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