LCOV - code coverage report
Current view: top level - src/tds - vstrbuild.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 70 72 97.2 %
Date: 2026-02-12 04:50:10 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             : /*
      37             :  * XXX The magic use of \xFF is bletcherous, but I can't think of anything
      38             :  *     better right now.
      39             :  */
      40             : #define CHARSEP '\377'
      41             : 
      42             : static char *
      43         920 : norm_fmt(const char *fmt, ptrdiff_t fmtlen, size_t *p_tokcount)
      44             : {
      45             :         char *newfmt;
      46             :         char *cp;
      47         920 :         bool skip = true;
      48         920 :         size_t tokcount = 1;
      49             : 
      50         920 :         if (fmtlen == TDS_NULLTERM) {
      51         920 :                 fmtlen = strlen(fmt);
      52             :         }
      53         920 :         if ((newfmt = tds_new(char, fmtlen + 1)) == NULL)
      54             :                 return NULL;
      55             : 
      56        4530 :         for (cp = newfmt; fmtlen > 0; fmtlen--, fmt++) {
      57        4530 :                 switch (*fmt) {
      58         960 :                 case ',':
      59             :                 case ' ':
      60         960 :                         if (!skip) {
      61         480 :                                 tokcount++;
      62         480 :                                 *cp++ = CHARSEP;
      63         480 :                                 skip = true;
      64             :                         }
      65             :                         break;
      66        3570 :                 default:
      67        3570 :                         skip = false;
      68        3570 :                         *cp++ = *fmt;
      69        3570 :                         break;
      70             :                 }
      71             :         }
      72         920 :         *cp = '\0';
      73         920 :         *p_tokcount = tokcount;
      74         920 :         return newfmt;
      75             : }
      76             : 
      77             : TDSRET
      78         920 : tds_vstrbuild(char *buffer, int buflen, int *resultlen, const char *text, int textlen, const char *formats, int formatlen,
      79             :               va_list ap)
      80             : {
      81             :         char *newformat;
      82             :         char *params;
      83             :         char *token;
      84             :         static const char strsep[2] = { CHARSEP, 0 };
      85         920 :         const char *sep = strsep;
      86             :         char *lasts;
      87             :         size_t tokcount, i;
      88             :         int state;
      89         920 :         char **string_array = NULL;
      90         920 :         unsigned int pnum = 0;
      91         920 :         char *paramp = NULL;
      92         920 :         char *const orig_buffer = buffer;
      93         920 :         TDSRET rc = TDS_FAIL;
      94             : 
      95         920 :         *resultlen = 0;
      96         920 :         if (textlen == TDS_NULLTERM)
      97         920 :                 textlen = (int) strlen(text);
      98             : 
      99         920 :         newformat = norm_fmt(formats, formatlen, &tokcount);
     100         920 :         if (newformat == NULL)
     101             :                 return TDS_FAIL;
     102             : 
     103         920 :         if (vasprintf(&params, newformat, ap) < 0) {
     104           0 :                 free(newformat);
     105           0 :                 return TDS_FAIL;
     106             :         }
     107         920 :         free(newformat);
     108         920 :         if ((string_array = tds_new(char *, tokcount + 1)) == NULL) {
     109             :                 goto out;
     110             :         }
     111        2230 :         for (token = strtok_r(params, sep, &lasts), i = 0; token != NULL && i < tokcount; token = strtok_r(NULL, sep, &lasts)) {
     112        1310 :                 string_array[i] = token;
     113        1310 :                 i++;
     114             :         }
     115         920 :         tokcount = i;
     116             : 
     117             : #define COPYING 1
     118             : #define CALCPARAM 2
     119             : #define OUTPARAM 3
     120             : 
     121         920 :         state = COPYING;
     122       90690 :         while ((buflen > 0) && (textlen > 0 || state == OUTPARAM)) {
     123       88860 :                 switch (state) {
     124       79280 :                 case COPYING:
     125       79280 :                         if (*text == '%') {
     126             :                                 state = CALCPARAM;
     127             :                                 pnum = 0;
     128             :                         } else {
     129       77960 :                                 *buffer++ = *text;
     130       77960 :                                 buflen--;
     131             :                         }
     132       79280 :                         text++;
     133       79280 :                         textlen--;
     134       79280 :                         break;
     135        2640 :                 case CALCPARAM:
     136        2640 :                         if (*text == '!') {
     137        2640 :                                 if (pnum <= 0 || pnum > tokcount)
     138             :                                         goto out;
     139        1310 :                                 paramp = string_array[pnum - 1];
     140        1310 :                                 state = OUTPARAM;
     141             :                         } else {
     142        1320 :                                 int pdigit = *text - '0';
     143             : 
     144        1320 :                                 if ((pdigit >= 0) && (pdigit <= 9)) {
     145        1320 :                                         pnum *= 10;
     146        1320 :                                         pnum += pdigit;
     147             :                                 }
     148             :                         }
     149        2630 :                         text++;
     150        2630 :                         textlen--;
     151        2630 :                         break;
     152        6940 :                 case OUTPARAM:
     153        6940 :                         if (*paramp == 0) {
     154             :                                 state = COPYING;
     155             :                         } else {
     156        5630 :                                 *buffer++ = *paramp++;
     157        5630 :                                 buflen--;
     158             :                         }
     159             :                         break;
     160             :                 default:
     161             :                         /* unknown state */
     162             :                         goto out;
     163             :                 }
     164             :         }
     165             : 
     166             :         rc = TDS_SUCCESS;
     167             : 
     168         930 :       out:
     169         920 :         *resultlen = (int) (buffer - orig_buffer);
     170         920 :         free(string_array);
     171         920 :         free(params);
     172             : 
     173         920 :         return rc;
     174             : }

Generated by: LCOV version 1.13