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