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 1580 : norm_fmt(const char *fmt, ptrdiff_t fmtlen, size_t *p_tokcount)
44 : {
45 : char *newfmt;
46 : char *cp;
47 1580 : bool skip = true;
48 1580 : size_t tokcount = 1;
49 :
50 1580 : if (fmtlen == TDS_NULLTERM) {
51 1580 : fmtlen = strlen(fmt);
52 : }
53 1580 : if ((newfmt = tds_new(char, fmtlen + 1)) == NULL)
54 : return NULL;
55 :
56 6830 : for (cp = newfmt; fmtlen > 0; fmtlen--, fmt++) {
57 6830 : switch (*fmt) {
58 1716 : case ',':
59 : case ' ':
60 1716 : if (!skip) {
61 858 : tokcount++;
62 858 : *cp++ = CHARSEP;
63 858 : skip = true;
64 : }
65 : break;
66 5114 : default:
67 5114 : skip = false;
68 5114 : *cp++ = *fmt;
69 5114 : break;
70 : }
71 : }
72 1580 : *cp = '\0';
73 1580 : *p_tokcount = tokcount;
74 1580 : return newfmt;
75 : }
76 :
77 : TDSRET
78 1580 : 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 1580 : const char *sep = strsep;
86 : char *lasts;
87 : size_t tokcount, i;
88 : int state;
89 1580 : char **string_array = NULL;
90 1580 : unsigned int pnum = 0;
91 1580 : char *paramp = NULL;
92 1580 : char *const orig_buffer = buffer;
93 1580 : TDSRET rc = TDS_FAIL;
94 :
95 1580 : *resultlen = 0;
96 1580 : if (textlen == TDS_NULLTERM)
97 1580 : textlen = (int) strlen(text);
98 :
99 1580 : newformat = norm_fmt(formats, formatlen, &tokcount);
100 1580 : if (newformat == NULL)
101 : return TDS_FAIL;
102 :
103 1580 : if (vasprintf(¶ms, newformat, ap) < 0) {
104 0 : free(newformat);
105 0 : return TDS_FAIL;
106 : }
107 1580 : free(newformat);
108 1580 : if ((string_array = tds_new(char *, tokcount + 1)) == NULL) {
109 : goto out;
110 : }
111 3662 : for (token = strtok_r(params, sep, &lasts), i = 0; token != NULL && i < tokcount; token = strtok_r(NULL, sep, &lasts)) {
112 2082 : string_array[i] = token;
113 2082 : i++;
114 : }
115 1580 : tokcount = i;
116 :
117 : #define COPYING 1
118 : #define CALCPARAM 2
119 : #define OUTPARAM 3
120 :
121 1580 : state = COPYING;
122 178108 : while ((buflen > 0) && (textlen > 0 || state == OUTPARAM)) {
123 174958 : switch (state) {
124 160228 : case COPYING:
125 160228 : if (*text == '%') {
126 : state = CALCPARAM;
127 : pnum = 0;
128 : } else {
129 158136 : *buffer++ = *text;
130 158136 : buflen--;
131 : }
132 160228 : text++;
133 160228 : textlen--;
134 160228 : break;
135 4184 : case CALCPARAM:
136 4184 : if (*text == '!') {
137 4184 : if (pnum <= 0 || pnum > tokcount)
138 : goto out;
139 2082 : paramp = string_array[pnum - 1];
140 2082 : state = OUTPARAM;
141 : } else {
142 2092 : int pdigit = *text - '0';
143 :
144 2092 : if ((pdigit >= 0) && (pdigit <= 9)) {
145 2092 : pnum *= 10;
146 2092 : pnum += pdigit;
147 : }
148 : }
149 4174 : text++;
150 4174 : textlen--;
151 4174 : break;
152 10546 : case OUTPARAM:
153 10546 : if (*paramp == 0) {
154 : state = COPYING;
155 : } else {
156 8464 : *buffer++ = *paramp++;
157 8464 : buflen--;
158 : }
159 : break;
160 : default:
161 : /* unknown state */
162 : goto out;
163 : }
164 : }
165 :
166 : rc = TDS_SUCCESS;
167 :
168 1590 : out:
169 1580 : *resultlen = (int) (buffer - orig_buffer);
170 1580 : free(string_array);
171 1580 : free(params);
172 :
173 1580 : return rc;
174 : }
|