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 30570 : odbc_get_tok(char **p)
60 : {
61 30570 : char *s = *p, *end;
62 :
63 30570 : s += strspn(s, SEP);
64 30570 : if (!*s)
65 : return NULL;
66 28684 : end = s + strcspn(s, SEP);
67 28684 : *end = 0;
68 28684 : *p = end + 1;
69 28684 : return s;
70 : }
71 :
72 : static void
73 2570 : parse_cstr(odbc_parser *parser, char *s)
74 : {
75 : char hexbuf[4];
76 2570 : char *d = s;
77 :
78 49500 : while (*s) {
79 44360 : if (*s != '\\') {
80 44300 : *d++ = *s++;
81 44300 : continue;
82 : }
83 :
84 60 : switch (*++s) {
85 0 : case '\"':
86 0 : *d++ = *s++;
87 0 : break;
88 0 : case '\\':
89 0 : *d++ = *s++;
90 0 : break;
91 60 : case 'x':
92 60 : if (strlen(s) < 3)
93 0 : odbc_fatal(parser, ": wrong string format\n");
94 60 : memcpy(hexbuf, ++s, 2);
95 60 : hexbuf[2] = 0;
96 60 : *d++ = (char) strtoul(hexbuf, NULL, 16);
97 60 : s += 2;
98 60 : break;
99 0 : default:
100 0 : odbc_fatal(parser, ": wrong string format\n");
101 : }
102 : }
103 2570 : *d = 0;
104 2570 : }
105 :
106 : const char *
107 11710 : odbc_get_str(odbc_parser *parser, char **p)
108 : {
109 11710 : char *s = *p, *end;
110 :
111 11710 : s += strspn(s, SEP);
112 11710 : if (!*s)
113 0 : odbc_fatal(parser, ": unable to get string\n");
114 :
115 11710 : if (strncmp(s, "\"\"\"", 3) == 0) {
116 100 : s += 3;
117 100 : end = strstr(s, "\"\"\"");
118 100 : if (!end)
119 0 : odbc_fatal(parser, ": string not terminated\n");
120 100 : *end = 0;
121 100 : *p = end + 3;
122 11610 : } else if (s[0] == '\"') {
123 2570 : ++s;
124 2570 : end = strchr(s, '\"');
125 2570 : if (!end)
126 0 : odbc_fatal(parser, ": string not terminated\n");
127 2570 : *end = 0;
128 2570 : parse_cstr(parser, s);
129 2570 : *p = end + 1;
130 : } else {
131 9040 : return odbc_get_tok(p);
132 : }
133 : return s;
134 : }
135 :
136 : void
137 860 : odbc_set_bool(odbc_parser *parser, const char *name, bool value)
138 : {
139 : unsigned n;
140 :
141 2196 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n)
142 1394 : if (!strcmp(parser->bools[n].name, name)) {
143 58 : parser->bools[n].value = value;
144 58 : return;
145 : }
146 :
147 802 : if (n == MAX_BOOLS)
148 0 : odbc_fatal(parser, ": no more boolean variable free\n");
149 802 : parser->bools[n].name = strdup(name);
150 802 : if (!parser->bools[n].name)
151 0 : odbc_fatal(parser, ": out of memory\n");
152 802 : parser->bools[n].value = value;
153 : }
154 :
155 : static bool
156 294 : get_bool(odbc_parser *parser, const char *name)
157 : {
158 : unsigned n;
159 :
160 294 : if (!name)
161 0 : odbc_fatal(parser, ": boolean variable not provided\n");
162 868 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n)
163 1162 : if (!strcmp(parser->bools[n].name, name))
164 294 : 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 240 : init_bools(odbc_parser *parser)
173 : {
174 240 : int big_endian = 1;
175 :
176 : if (((char *) &big_endian)[0] == 1)
177 240 : big_endian = 0;
178 240 : odbc_set_bool(parser, "bigendian", !!big_endian);
179 :
180 240 : odbc_set_bool(parser, "msdb", odbc_db_is_microsoft());
181 240 : odbc_set_bool(parser, "freetds", odbc_driver_is_freetds());
182 240 : }
183 :
184 : static void
185 : clear_bools(odbc_parser *parser)
186 : {
187 : unsigned n;
188 :
189 1042 : for (n = 0; n < MAX_BOOLS && parser->bools[n].name; ++n) {
190 802 : free(parser->bools[n].name);
191 802 : parser->bools[n].name = NULL;
192 : }
193 : }
194 :
195 : static bool
196 : pop_condition(odbc_parser *parser)
197 : {
198 340 : if (parser->cond_level == 0)
199 0 : odbc_fatal(parser, ": no related if\n");
200 340 : return parser->conds[--parser->cond_level];
201 : }
202 :
203 : static void
204 : push_condition(odbc_parser *parser, bool cond)
205 : {
206 340 : if (parser->cond_level >= MAX_CONDITIONS)
207 0 : odbc_fatal(parser, ": too much nested conditions\n");
208 340 : parser->conds[parser->cond_level++] = cond;
209 : }
210 :
211 : static bool
212 294 : get_not_cond(odbc_parser *parser, char **p)
213 : {
214 : bool cond;
215 294 : const char *tok = odbc_get_tok(p);
216 :
217 294 : if (!tok)
218 0 : odbc_fatal(parser, ": wrong condition syntax\n");
219 :
220 294 : if (!strcmp(tok, "not"))
221 92 : cond = !get_bool(parser, odbc_get_tok(p));
222 : else
223 202 : cond = get_bool(parser, tok);
224 :
225 294 : return cond;
226 : }
227 :
228 : static bool
229 256 : get_condition(odbc_parser *parser, char **p)
230 : {
231 256 : bool cond1 = get_not_cond(parser, p), cond2;
232 : const char *tok;
233 :
234 550 : while ((tok = odbc_get_tok(p)) != NULL) {
235 :
236 38 : cond2 = get_not_cond(parser, p);
237 :
238 38 : if (!strcmp(tok, "or"))
239 0 : cond1 = cond1 || cond2;
240 38 : else if (!strcmp(tok, "and"))
241 38 : cond1 = cond1 && cond2;
242 : else
243 0 : odbc_fatal(parser, ": wrong condition syntax\n");
244 : }
245 256 : return cond1;
246 : }
247 :
248 : odbc_parser *
249 240 : odbc_init_parser_func(odbc_read_line_p read_func, void *param)
250 : {
251 : odbc_parser *parser;
252 :
253 240 : if (!read_func) {
254 0 : fprintf(stderr, "Missing reading function\n");
255 0 : exit(1);
256 : }
257 :
258 240 : parser = tds_new0(odbc_parser, 1);
259 240 : if (!parser) {
260 0 : fprintf(stderr, "out of memory\n");
261 0 : exit(1);
262 : }
263 240 : parser->read_param = param;
264 240 : parser->read_func = read_func;
265 240 : init_bools(parser);
266 :
267 240 : return parser;
268 : }
269 :
270 : static char *
271 10530 : read_file(void *param, char *s, size_t size)
272 : {
273 : /* we don't expect "size" to be huge, cast is fine */
274 10530 : return fgets(s, (int) size, (FILE *) param);
275 : }
276 :
277 : odbc_parser *
278 20 : odbc_init_parser(FILE *f)
279 : {
280 20 : return odbc_init_parser_func(read_file, f);
281 : }
282 :
283 : void
284 240 : odbc_free_parser(odbc_parser *parser)
285 : {
286 240 : clear_bools(parser);
287 240 : free(parser);
288 240 : }
289 :
290 : const char *
291 9810 : odbc_get_cmd_line(odbc_parser *parser, char **p_s, bool *cond)
292 : {
293 21830 : while (parser->read_func(parser->read_param, parser->line_buf, sizeof(parser->line_buf))) {
294 11780 : char *p = parser->line_buf;
295 : const char *cmd;
296 :
297 11780 : ++parser->line_num;
298 :
299 11780 : cmd = odbc_get_tok(&p);
300 :
301 : /* skip comments */
302 11780 : if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
303 3700 : continue;
304 :
305 : /* conditional statement */
306 10290 : if (!strcmp(cmd, "else")) {
307 20 : bool c = pop_condition(parser);
308 :
309 40 : push_condition(parser, c);
310 20 : *cond = c && !*cond;
311 20 : continue;
312 : }
313 10270 : if (!strcmp(cmd, "endif")) {
314 320 : *cond = pop_condition(parser);
315 320 : continue;
316 : }
317 9950 : if (!strcmp(cmd, "if")) {
318 640 : push_condition(parser, *cond);
319 320 : if (*cond)
320 256 : *cond = get_condition(parser, &p);
321 320 : continue;
322 : }
323 :
324 9630 : if (strcmp(cmd, "tds_version_cmp") == 0) {
325 60 : const char *bool_name = odbc_get_tok(&p);
326 60 : const char *cmp = odbc_get_tok(&p);
327 60 : const char *s_ver = odbc_get_tok(&p);
328 60 : int ver = odbc_tds_version();
329 : int expected;
330 : bool res;
331 : unsigned M, m;
332 :
333 60 : if (!cmp || !s_ver)
334 0 : odbc_fatal(parser, ": missing parameters\n");
335 60 : if (sscanf(s_ver, "%u.%u", &M, &m) != 2)
336 0 : odbc_fatal(parser, ": invalid version %s\n", s_ver);
337 60 : expected = M * 0x100u + m;
338 :
339 60 : if (strcmp(cmp, ">") == 0)
340 0 : res = ver > expected;
341 60 : else if (strcmp(cmp, ">=") == 0)
342 40 : res = ver >= expected;
343 20 : else if (strcmp(cmp, "<") == 0)
344 0 : res = ver < expected;
345 20 : else if (strcmp(cmp, "<=") == 0)
346 0 : res = ver <= expected;
347 20 : else if (strcmp(cmp, "==") == 0)
348 20 : res = ver == expected;
349 0 : else if (strcmp(cmp, "!=") == 0)
350 0 : res = ver != expected;
351 : else
352 0 : odbc_fatal(parser, ": invalid operator %s\n", cmp);
353 :
354 60 : if (*cond)
355 54 : odbc_set_bool(parser, bool_name, res);
356 60 : continue;
357 : }
358 :
359 9570 : *p_s = p;
360 9570 : return cmd;
361 : }
362 : return NULL;
363 : }
|