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(¶ms, 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 : }
|