LCOV - code coverage report
Current view: top level - src/tds - vstrbuild.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 89 92 96.7 %
Date: 2025-01-18 11:50:39 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-1999  Brian Bruns
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <stdarg.h>
      23             : #include <stdio.h>
      24             : 
      25             : #if HAVE_STDLIB_H
      26             : #include <stdlib.h>
      27             : #endif /* HAVE_STDLIB_H */
      28             : 
      29             : #if HAVE_STRING_H
      30             : #include <string.h>
      31             : #endif /* HAVE_STRING_H */
      32             : 
      33             : #include <freetds/tds.h>
      34             : #include <freetds/replacements.h>
      35             : 
      36             : struct string_linked_list
      37             : {
      38             :         char *str;
      39             :         struct string_linked_list *next;
      40             : };
      41             : 
      42             : /*
      43             :  * XXX The magic use of \xFF is bletcherous, but I can't think of anything
      44             :  *     better right now.
      45             :  */
      46             : 
      47             : static char *
      48         464 : norm_fmt(const char *fmt, int fmtlen)
      49             : {
      50             :         char *newfmt;
      51             :         char *cp;
      52         464 :         bool skip = false;
      53             : 
      54         464 :         if (fmtlen == TDS_NULLTERM) {
      55         464 :                 fmtlen = strlen(fmt);
      56             :         }
      57         464 :         if ((newfmt = tds_new(char, fmtlen + 1)) == NULL)
      58             :                 return NULL;
      59             : 
      60        2768 :         for (cp = newfmt; fmtlen > 0; fmtlen--, fmt++) {
      61        2768 :                 switch (*fmt) {
      62         664 :                 case ',':
      63             :                 case ' ':
      64         664 :                         if (!skip) {
      65         336 :                                 *cp++ = '\377';
      66         336 :                                 skip = true;
      67             :                         }
      68             :                         break;
      69        2104 :                 default:
      70        2104 :                         skip = false;
      71        2104 :                         *cp++ = *fmt;
      72        2104 :                         break;
      73             :                 }
      74             :         }
      75         464 :         *cp = '\0';
      76         464 :         return newfmt;
      77             : }
      78             : 
      79             : TDSRET
      80         464 : tds_vstrbuild(char *buffer, int buflen, int *resultlen, const char *text, int textlen, const char *formats, int formatlen, va_list ap)
      81             : {
      82             :         char *newformat;
      83             :         char *params;
      84             :         char *token;
      85         464 :         const char *sep = "\377";
      86             :         char *lasts;
      87         464 :         int tokcount = 0;
      88         464 :         struct string_linked_list *head = NULL;
      89         464 :         struct string_linked_list *item = NULL;
      90         464 :         struct string_linked_list **tail = &head;
      91             :         int i;
      92             :         int state;
      93         464 :         char **string_array = NULL;
      94         464 :         int pnum = 0;
      95             :         int pdigit;
      96         464 :         char *paramp = NULL;
      97         464 :         TDSRET rc = TDS_FAIL;
      98             : 
      99         464 :         *resultlen = 0;
     100         464 :         if (textlen == TDS_NULLTERM) {
     101         464 :                 textlen = (int)strlen(text);
     102             :         }
     103         464 :         if ((newformat = norm_fmt(formats, formatlen)) == NULL) {
     104             :                 return TDS_FAIL;
     105             :         }
     106         464 :         if (vasprintf(&params, newformat, ap) < 0) {
     107           0 :                 free(newformat);
     108           0 :                 return TDS_FAIL;
     109             :         }
     110         464 :         free(newformat);
     111        1216 :         for (token = strtok_r(params, sep, &lasts); token != NULL; token = strtok_r(NULL, sep, &lasts)) {
     112         752 :                 if ((*tail = tds_new(struct string_linked_list, 1)) == NULL) {
     113             :                         goto out;
     114             :                 }
     115         752 :                 (*tail)->str = token;
     116         752 :                 (*tail)->next = NULL;
     117         752 :                 tail = &((*tail)->next);
     118         752 :                 tokcount++;
     119             :         }
     120         464 :         if ((string_array = tds_new(char *, tokcount + 1)) == NULL) {
     121             :                 goto out;
     122             :         }
     123        1216 :         for (item = head, i = 0; i < tokcount; item = item->next, i++) {
     124         752 :                 if (item == NULL) {
     125             :                         goto out;
     126             :                 }
     127         752 :                 string_array[i] = item->str;
     128        1504 :                 while (*(string_array[i]) == ' ') {
     129           0 :                         string_array[i]++;
     130             :                 }
     131             :         }
     132             : 
     133             : #define COPYING 1
     134             : #define CALCPARAM 2
     135             : #define OUTPARAM 3
     136             : 
     137             :         state = COPYING;
     138       50064 :         while ((buflen > 0) && (textlen > 0)) {
     139       49600 :                 switch (state) {
     140       44168 :                 case COPYING:
     141       44168 :                         switch (*text) {
     142         752 :                         case '%':
     143         752 :                                 state = CALCPARAM;
     144         752 :                                 text++;
     145         752 :                                 textlen--;
     146         752 :                                 pnum = 0;
     147         752 :                                 break;
     148       43416 :                         default:
     149       43416 :                                 *buffer++ = *text++;
     150       43416 :                                 buflen--;
     151       43416 :                                 textlen--;
     152       43416 :                                 (*resultlen)++;
     153       43416 :                                 break;
     154             :                         }
     155             :                         break;
     156        1504 :                 case CALCPARAM:
     157        1504 :                         switch (*text) {
     158         752 :                         case '!':
     159         752 :                                 if (pnum <= tokcount) {
     160         752 :                                         paramp = string_array[pnum - 1];
     161         752 :                                         state = OUTPARAM;
     162             :                                 }
     163         752 :                                 text++;
     164         752 :                                 textlen--;
     165         752 :                                 break;
     166         752 :                         default:
     167         752 :                                 pdigit = *text++ - '0';
     168         752 :                                 if ((pdigit >= 0) && (pdigit <= 9)) {
     169         752 :                                         pnum *= 10;
     170         752 :                                         pnum += pdigit;
     171             :                                 }
     172         752 :                                 textlen--;
     173         752 :                                 break;
     174             :                         }
     175             :                         break;
     176        3928 :                 case OUTPARAM:
     177        3928 :                         switch (*paramp) {
     178             :                         case 0:
     179             :                                 state = COPYING;
     180             :                                 break;
     181        3176 :                         default:
     182        3176 :                                 *buffer++ = *paramp++;
     183        3176 :                                 buflen--;
     184        3176 :                                 (*resultlen)++;
     185             :                         }
     186             :                         break;
     187             :                 default:
     188             :                         /* unknown state */
     189             :                         goto out;
     190             :                         break;
     191             : 
     192             :                 }
     193             :         }
     194             : 
     195             :         rc = TDS_SUCCESS;
     196             : 
     197         464 :       out:
     198         464 :         free(string_array);
     199        1216 :         for (item = head; item != NULL; item = head) {
     200         752 :                 head = head->next;
     201         752 :                 free(item);
     202             :         }
     203         464 :         free(params);
     204             : 
     205         464 :         return rc;
     206             : }

Generated by: LCOV version 1.13