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 12:13:41 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          48 : norm_fmt(const char *fmt, int fmtlen)
      49             : {
      50             :         char *newfmt;
      51             :         char *cp;
      52          48 :         char skip = 0;
      53             : 
      54          48 :         if (fmtlen == TDS_NULLTERM) {
      55          48 :                 fmtlen = strlen(fmt);
      56             :         }
      57          48 :         if ((newfmt = tds_new(char, fmtlen + 1)) == NULL)
      58             :                 return NULL;
      59             : 
      60         232 :         for (cp = newfmt; fmtlen > 0; fmtlen--, fmt++) {
      61         232 :                 switch (*fmt) {
      62          72 :                 case ',':
      63             :                 case ' ':
      64          72 :                         if (!skip) {
      65          40 :                                 *cp++ = '\377';
      66          40 :                                 skip = 1;
      67             :                         }
      68             :                         break;
      69         160 :                 default:
      70         160 :                         skip = 0;
      71         160 :                         *cp++ = *fmt;
      72         160 :                         break;
      73             :                 }
      74             :         }
      75          48 :         *cp = '\0';
      76          48 :         return newfmt;
      77             : }
      78             : 
      79             : TDSRET
      80          48 : 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          48 :         const char *sep = "\377";
      86             :         char *lasts;
      87          48 :         int tokcount = 0;
      88          48 :         struct string_linked_list *head = NULL;
      89          48 :         struct string_linked_list *item = NULL;
      90          48 :         struct string_linked_list **tail = &head;
      91             :         int i;
      92             :         int state;
      93          48 :         char **string_array = NULL;
      94          48 :         int pnum = 0;
      95             :         int pdigit;
      96          48 :         char *paramp = NULL;
      97          48 :         TDSRET rc = TDS_FAIL;
      98             : 
      99          48 :         *resultlen = 0;
     100          48 :         if (textlen == TDS_NULLTERM) {
     101          48 :                 textlen = (int)strlen(text);
     102             :         }
     103          48 :         if ((newformat = norm_fmt(formats, formatlen)) == NULL) {
     104             :                 return TDS_FAIL;
     105             :         }
     106          48 :         if (vasprintf(&params, newformat, ap) < 0) {
     107           0 :                 free(newformat);
     108           0 :                 return TDS_FAIL;
     109             :         }
     110          48 :         free(newformat);
     111         128 :         for (token = strtok_r(params, sep, &lasts); token != NULL; token = strtok_r(NULL, sep, &lasts)) {
     112          80 :                 if ((*tail = tds_new(struct string_linked_list, 1)) == NULL) {
     113             :                         goto out;
     114             :                 }
     115          80 :                 (*tail)->str = token;
     116          80 :                 (*tail)->next = NULL;
     117          80 :                 tail = &((*tail)->next);
     118          80 :                 tokcount++;
     119             :         }
     120          48 :         if ((string_array = tds_new(char *, tokcount + 1)) == NULL) {
     121             :                 goto out;
     122             :         }
     123         128 :         for (item = head, i = 0; i < tokcount; item = item->next, i++) {
     124          80 :                 if (item == NULL) {
     125             :                         goto out;
     126             :                 }
     127          80 :                 string_array[i] = item->str;
     128         160 :                 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        5728 :         while ((buflen > 0) && (textlen > 0)) {
     139        5680 :                 switch (state) {
     140        5320 :                 case COPYING:
     141        5320 :                         switch (*text) {
     142          80 :                         case '%':
     143          80 :                                 state = CALCPARAM;
     144          80 :                                 text++;
     145          80 :                                 textlen--;
     146          80 :                                 pnum = 0;
     147          80 :                                 break;
     148        5240 :                         default:
     149        5240 :                                 *buffer++ = *text++;
     150        5240 :                                 buflen--;
     151        5240 :                                 textlen--;
     152        5240 :                                 (*resultlen)++;
     153        5240 :                                 break;
     154             :                         }
     155             :                         break;
     156         160 :                 case CALCPARAM:
     157         160 :                         switch (*text) {
     158          80 :                         case '!':
     159          80 :                                 if (pnum <= tokcount) {
     160          80 :                                         paramp = string_array[pnum - 1];
     161          80 :                                         state = OUTPARAM;
     162             :                                 }
     163          80 :                                 text++;
     164          80 :                                 textlen--;
     165          80 :                                 break;
     166          80 :                         default:
     167          80 :                                 pdigit = *text++ - '0';
     168          80 :                                 if ((pdigit >= 0) && (pdigit <= 9)) {
     169          80 :                                         pnum *= 10;
     170          80 :                                         pnum += pdigit;
     171             :                                 }
     172          80 :                                 textlen--;
     173          80 :                                 break;
     174             :                         }
     175             :                         break;
     176         200 :                 case OUTPARAM:
     177         200 :                         switch (*paramp) {
     178             :                         case 0:
     179             :                                 state = COPYING;
     180             :                                 break;
     181         120 :                         default:
     182         120 :                                 *buffer++ = *paramp++;
     183         120 :                                 buflen--;
     184         120 :                                 (*resultlen)++;
     185             :                         }
     186             :                         break;
     187             :                 default:
     188             :                         /* unknown state */
     189             :                         goto out;
     190             :                         break;
     191             : 
     192             :                 }
     193             :         }
     194             : 
     195             :         rc = TDS_SUCCESS;
     196             : 
     197          48 :       out:
     198          48 :         free(string_array);
     199         128 :         for (item = head; item != NULL; item = head) {
     200          80 :                 head = head->next;
     201          80 :                 free(item);
     202             :         }
     203          48 :         free(params);
     204             : 
     205          48 :         return rc;
     206             : }

Generated by: LCOV version 1.13