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