Line data Source code
1 : /*
2 : * Test reading data with SQLBindCol
3 : */
4 : #include "common.h"
5 : #include <assert.h>
6 : #include <ctype.h>
7 : #include "parser.h"
8 :
9 : enum
10 : {
11 : MAX_BOOLS = 64,
12 : MAX_CONDITIONS = 32
13 : };
14 :
15 : typedef struct
16 : {
17 : char *name;
18 : bool value;
19 : } bool_t;
20 :
21 : struct odbc_parser
22 : {
23 : unsigned int line_num;
24 :
25 : bool_t bools[MAX_BOOLS];
26 :
27 : bool conds[MAX_CONDITIONS];
28 : unsigned cond_level;
29 :
30 : void *read_param;
31 : odbc_read_line_p read_func;
32 :
33 : char line_buf[1024];
34 : };
35 :
36 : unsigned int
37 0 : odbc_line_num(odbc_parser *parser)
38 : {
39 0 : return parser->line_num;
40 : }
41 :
42 : void
43 0 : odbc_fatal(odbc_parser *parser, const char *msg, ...)
44 : {
45 : va_list ap;
46 :
47 0 : va_start(ap, msg);
48 0 : if (msg[0] == ':')
49 0 : fprintf(stderr, "Line %u", parser->line_num);
50 0 : vfprintf(stderr, msg, ap);
51 0 : va_end(ap);
52 :
53 0 : exit(1);
54 : }
55 :
56 : #define SEP " \t\n"
57 :
58 : const char *
59 24438 : odbc_get_tok(char **p)
60 : {
61 24438 : char *s = *p, *end;
62 :
63 24438 : s += strspn(s, SEP);
64 24438 : if (!*s)
65 : return NULL;
66 22934 : end = s + strcspn(s, SEP);
67 22934 : *end = 0;
68 22934 : *p = end + 1;
69 22934 : return s;
70 : }
71 :
72 : static void
73 2056 : parse_cstr(odbc_parser *parser, char *s)
74 : {
75 : char hexbuf[4];
76 2056 : char *d = s;
77 :
78 39600 : while (*s) {
79 35488 : if (*s != '\\') {
80 35440 : *d++ = *s++;
81 35440 : continue;
82 : }
83 :
84 48 : switch (*++s) {
85 0 : case '\"':
86 0 : *d++ = *s++;
87 0 : break;
88 0 : case '\\':
89 0 : *d++ = *s++;
90 0 : break;
91 48 : case 'x':
92 48 : if (strlen(s) < 3)
93 0 : odbc_fatal(parser, ": wrong string format\n");
94 48 : memcpy(hexbuf, ++s, 2);
95 48 : hexbuf[2] = 0;
96 48 : *d++ = (char) strtoul(hexbuf, NULL, 16);
97 48 : s += 2;
98 48 : break;
99 0 : default:
100 0 : odbc_fatal(parser, ": wrong string format\n");
101 : }
102 : }
103 2056 : *d = 0;
104 2056 : }
105 :
106 : const char *
107 9368 : odbc_get_str(odbc_parser *parser, char **p)
108 : {
109 9368 : char *s = *p, *end;
110 :
111 9368 : s += strspn(s, SEP);
112 9368 : if (!*s)
113 0 : odbc_fatal(parser, ": unable to get string\n");
114 :
115 9368 : if (strncmp(s, "\"\"\"", 3) == 0) {
116 80 : s += 3;
117 80 : end = strstr(s, "\"\"\"");
118 80 : if (!end)
119 0 : odbc_fatal(parser, ": string not terminated\n");
120 80 : *end = 0;
121 80 : *p = end + 3;
122 9288 : } else if (s[0] == '\"') {
123 2056 : ++s;
124 2056 : end = strchr(s, '\"');
125 2056 : if (!end)
126 0 : odbc_fatal(parser, ": string not terminated\n");
127 2056 : *end = 0;
128 2056 : parse_cstr(parser, s);
129 2056 : *p = end + 1;
130 : } else {
131 7232 : return odbc_get_tok(p);
132 : }
133 : return s;
134 : }
135 :
136 : void
137 684 : odbc_set_bool(odbc_parser *parser, const char *name, bool value)
138 : {
139 : unsigned n;
140 :
141 1734 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n)
142 1094 : if (!strcmp(parser->bools[n].name, name)) {
143 44 : parser->bools[n].value = value;
144 44 : return;
145 : }
146 :
147 640 : if (n == MAX_BOOLS)
148 0 : odbc_fatal(parser, ": no more boolean variable free\n");
149 640 : parser->bools[n].name = strdup(name);
150 640 : if (!parser->bools[n].name)
151 0 : odbc_fatal(parser, ": out of memory\n");
152 640 : parser->bools[n].value = value;
153 : }
154 :
155 : static bool
156 228 : get_bool(odbc_parser *parser, const char *name)
157 : {
158 : unsigned n;
159 :
160 228 : if (!name)
161 0 : odbc_fatal(parser, ": boolean variable not provided\n");
162 670 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n)
163 898 : if (!strcmp(parser->bools[n].name, name))
164 228 : return parser->bools[n].value;
165 :
166 0 : odbc_fatal(parser, ": boolean variable %s not found\n", name);
167 : return false;
168 : }
169 :
170 : /** initialize booleans, call after connection */
171 : static void
172 192 : init_bools(odbc_parser *parser)
173 : {
174 192 : int big_endian = 1;
175 :
176 : if (((char *) &big_endian)[0] == 1)
177 192 : big_endian = 0;
178 192 : odbc_set_bool(parser, "bigendian", !!big_endian);
179 :
180 192 : odbc_set_bool(parser, "msdb", odbc_db_is_microsoft());
181 192 : odbc_set_bool(parser, "freetds", odbc_driver_is_freetds());
182 192 : }
183 :
184 : static void
185 : clear_bools(odbc_parser *parser)
186 : {
187 : unsigned n;
188 :
189 832 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n) {
190 640 : free(parser->bools[n].name);
191 640 : parser->bools[n].name = NULL;
192 : }
193 : }
194 :
195 : static bool
196 : pop_condition(odbc_parser *parser)
197 : {
198 272 : if (parser->cond_level == 0)
199 0 : odbc_fatal(parser, ": no related if\n");
200 272 : return parser->conds[--parser->cond_level];
201 : }
202 :
203 : static void
204 : push_condition(odbc_parser *parser, bool cond)
205 : {
206 272 : if (parser->cond_level >= MAX_CONDITIONS)
207 0 : odbc_fatal(parser, ": too much nested conditions\n");
208 272 : parser->conds[parser->cond_level++] = cond;
209 : }
210 :
211 : static bool
212 228 : get_not_cond(odbc_parser *parser, char **p)
213 : {
214 : bool cond;
215 228 : const char *tok = odbc_get_tok(p);
216 :
217 228 : if (!tok)
218 0 : odbc_fatal(parser, ": wrong condition syntax\n");
219 :
220 228 : if (!strcmp(tok, "not"))
221 70 : cond = !get_bool(parser, odbc_get_tok(p));
222 : else
223 158 : cond = get_bool(parser, tok);
224 :
225 228 : return cond;
226 : }
227 :
228 : static bool
229 200 : get_condition(odbc_parser *parser, char **p)
230 : {
231 200 : bool cond1 = get_not_cond(parser, p), cond2;
232 : const char *tok;
233 :
234 428 : while ((tok = odbc_get_tok(p)) != NULL) {
235 :
236 28 : cond2 = get_not_cond(parser, p);
237 :
238 28 : if (!strcmp(tok, "or"))
239 0 : cond1 = cond1 || cond2;
240 28 : else if (!strcmp(tok, "and"))
241 28 : cond1 = cond1 && cond2;
242 : else
243 0 : odbc_fatal(parser, ": wrong condition syntax\n");
244 : }
245 200 : return cond1;
246 : }
247 :
248 : odbc_parser *
249 192 : odbc_init_parser_func(odbc_read_line_p read_func, void *param)
250 : {
251 : odbc_parser *parser;
252 :
253 192 : if (!read_func) {
254 0 : fprintf(stderr, "Missing reading function\n");
255 0 : exit(1);
256 : }
257 :
258 192 : parser = tds_new0(odbc_parser, 1);
259 192 : if (!parser) {
260 0 : fprintf(stderr, "out of memory\n");
261 0 : exit(1);
262 : }
263 192 : parser->read_param = param;
264 192 : parser->read_func = read_func;
265 192 : init_bools(parser);
266 :
267 192 : return parser;
268 : }
269 :
270 : static char *
271 8424 : read_file(void *param, char *s, size_t size)
272 : {
273 8424 : return fgets(s, size, (FILE *) param);
274 : }
275 :
276 : odbc_parser *
277 16 : odbc_init_parser(FILE *f)
278 : {
279 16 : return odbc_init_parser_func(read_file, f);
280 : }
281 :
282 : void
283 192 : odbc_free_parser(odbc_parser *parser)
284 : {
285 192 : clear_bools(parser);
286 192 : free(parser);
287 192 : }
288 :
289 : const char *
290 7848 : odbc_get_cmd_line(odbc_parser *parser, char **p_s, bool *cond)
291 : {
292 17464 : while (parser->read_func(parser->read_param, parser->line_buf, sizeof(parser->line_buf))) {
293 9424 : char *p = parser->line_buf;
294 : const char *cmd;
295 :
296 9424 : ++parser->line_num;
297 :
298 9424 : cmd = odbc_get_tok(&p);
299 :
300 : /* skip comments */
301 9424 : if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
302 2960 : continue;
303 :
304 : /* conditional statement */
305 8232 : if (!strcmp(cmd, "else")) {
306 16 : bool c = pop_condition(parser);
307 :
308 32 : push_condition(parser, c);
309 16 : *cond = c && !*cond;
310 16 : continue;
311 : }
312 8216 : if (!strcmp(cmd, "endif")) {
313 256 : *cond = pop_condition(parser);
314 256 : continue;
315 : }
316 7960 : if (!strcmp(cmd, "if")) {
317 512 : push_condition(parser, *cond);
318 256 : if (*cond)
319 200 : *cond = get_condition(parser, &p);
320 256 : continue;
321 : }
322 :
323 7704 : if (strcmp(cmd, "tds_version_cmp") == 0) {
324 48 : const char *bool_name = odbc_get_tok(&p);
325 48 : const char *cmp = odbc_get_tok(&p);
326 48 : const char *s_ver = odbc_get_tok(&p);
327 48 : int ver = odbc_tds_version();
328 : int expected;
329 : bool res;
330 : unsigned M, m;
331 :
332 48 : if (!cmp || !s_ver)
333 0 : odbc_fatal(parser, ": missing parameters\n");
334 48 : if (sscanf(s_ver, "%u.%u", &M, &m) != 2)
335 0 : odbc_fatal(parser, ": invalid version %s\n", s_ver);
336 48 : expected = M * 0x100u + m;
337 :
338 48 : if (strcmp(cmp, ">") == 0)
339 0 : res = ver > expected;
340 48 : else if (strcmp(cmp, ">=") == 0)
341 32 : res = ver >= expected;
342 16 : else if (strcmp(cmp, "<") == 0)
343 0 : res = ver < expected;
344 16 : else if (strcmp(cmp, "<=") == 0)
345 0 : res = ver <= expected;
346 16 : else if (strcmp(cmp, "==") == 0)
347 16 : res = ver == expected;
348 0 : else if (strcmp(cmp, "!=") == 0)
349 0 : res = ver != expected;
350 : else
351 0 : odbc_fatal(parser, ": invalid operator %s\n", cmp);
352 :
353 48 : if (*cond)
354 42 : odbc_set_bool(parser, bool_name, res);
355 48 : continue;
356 : }
357 :
358 7656 : *p_s = p;
359 7656 : return cmd;
360 : }
361 : return NULL;
362 : }
|