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 : unsigned int odbc_line_num;
10 :
11 : void
12 0 : odbc_fatal(const char *msg, ...)
13 : {
14 : va_list ap;
15 :
16 0 : va_start(ap, msg);
17 0 : if (msg[0] == ':')
18 0 : fprintf(stderr, "Line %u", odbc_line_num);
19 0 : vfprintf(stderr, msg, ap);
20 0 : va_end(ap);
21 :
22 0 : exit(1);
23 : }
24 :
25 : #define SEP " \t\n"
26 :
27 : const char *
28 22430 : odbc_get_tok(char **p)
29 : {
30 22430 : char *s = *p, *end;
31 22430 : s += strspn(s, SEP);
32 22430 : if (!*s) return NULL;
33 21326 : end = s + strcspn(s, SEP);
34 21326 : *end = 0;
35 21326 : *p = end+1;
36 21326 : return s;
37 : }
38 :
39 : static void
40 2056 : parse_cstr(char *s)
41 : {
42 : char hexbuf[4];
43 2056 : char *d = s;
44 :
45 39600 : while (*s) {
46 35488 : if (*s != '\\') {
47 35440 : *d++ = *s++;
48 35440 : continue;
49 : }
50 :
51 48 : switch (*++s) {
52 0 : case '\"':
53 0 : *d++ = *s++;
54 0 : break;
55 0 : case '\\':
56 0 : *d++ = *s++;
57 0 : break;
58 48 : case 'x':
59 48 : if (strlen(s) < 3)
60 0 : odbc_fatal(": wrong string format\n");
61 48 : memcpy(hexbuf, ++s, 2);
62 48 : hexbuf[2] = 0;
63 48 : *d++ = (char) strtoul(hexbuf, NULL, 16);
64 48 : s += 2;
65 48 : break;
66 0 : default:
67 0 : odbc_fatal(": wrong string format\n");
68 : }
69 : }
70 2056 : *d = 0;
71 2056 : }
72 :
73 : const char *
74 9368 : odbc_get_str(char **p)
75 : {
76 9368 : char *s = *p, *end;
77 9368 : s += strspn(s, SEP);
78 9368 : if (!*s) odbc_fatal(": unable to get string\n");
79 :
80 9368 : if (strncmp(s, "\"\"\"", 3) == 0) {
81 80 : s += 3;
82 80 : end = strstr(s, "\"\"\"");
83 80 : if (!end) odbc_fatal(": string not terminated\n");
84 80 : *end = 0;
85 80 : *p = end+3;
86 9288 : } else if (s[0] == '\"') {
87 2056 : ++s;
88 2056 : end = strchr(s, '\"');
89 2056 : if (!end) odbc_fatal(": string not terminated\n");
90 2056 : *end = 0;
91 2056 : parse_cstr(s);
92 2056 : *p = end+1;
93 : } else {
94 7232 : return odbc_get_tok(p);
95 : }
96 : return s;
97 : }
98 :
99 : enum { MAX_BOOLS = 64 };
100 : typedef struct {
101 : char *name;
102 : int value;
103 : } bool_t;
104 : static bool_t bools[MAX_BOOLS];
105 :
106 : void
107 156 : odbc_set_bool(const char *name, int value)
108 : {
109 : unsigned n;
110 156 : value = !!value;
111 678 : for (n = 0; n < MAX_BOOLS && bools[n].name; ++n)
112 566 : if (!strcmp(bools[n].name, name)) {
113 44 : bools[n].value = value;
114 44 : return;
115 : }
116 :
117 112 : if (n == MAX_BOOLS)
118 0 : odbc_fatal(": no more boolean variable free\n");
119 112 : bools[n].name = strdup(name);
120 112 : if (!bools[n].name) odbc_fatal(": out of memory\n");
121 112 : bools[n].value = value;
122 : }
123 :
124 : static int
125 228 : get_bool(const char *name)
126 : {
127 : unsigned n;
128 228 : if (!name)
129 0 : odbc_fatal(": boolean variable not provided\n");
130 670 : for (n = 0; n < MAX_BOOLS && bools[n].name; ++n)
131 898 : if (!strcmp(bools[n].name, name))
132 228 : return bools[n].value;
133 :
134 0 : odbc_fatal(": boolean variable %s not found\n", name);
135 : return 0;
136 : }
137 :
138 : /** initialize booleans, call after connection */
139 : void
140 16 : odbc_init_bools(void)
141 : {
142 16 : int big_endian = 1;
143 :
144 : if (((char *) &big_endian)[0] == 1)
145 16 : big_endian = 0;
146 16 : odbc_set_bool("bigendian", big_endian);
147 :
148 16 : odbc_set_bool("msdb", odbc_db_is_microsoft());
149 16 : odbc_set_bool("freetds", odbc_driver_is_freetds());
150 16 : }
151 :
152 : void
153 16 : odbc_clear_bools(void)
154 : {
155 : unsigned n;
156 128 : for (n = 0; n < MAX_BOOLS && bools[n].name; ++n) {
157 112 : free(bools[n].name);
158 112 : bools[n].name = NULL;
159 : }
160 16 : }
161 :
162 : enum { MAX_CONDITIONS = 32 };
163 : static char conds[MAX_CONDITIONS];
164 : static unsigned cond_level = 0;
165 :
166 : static int
167 : pop_condition(void)
168 : {
169 272 : if (cond_level == 0) odbc_fatal(": no related if\n");
170 272 : return conds[--cond_level];
171 : }
172 :
173 : static void
174 272 : push_condition(int cond)
175 : {
176 272 : if (cond != 0 && cond != 1) odbc_fatal(": invalid cond value %d\n", cond);
177 272 : if (cond_level >= MAX_CONDITIONS) odbc_fatal(": too much nested conditions\n");
178 272 : conds[cond_level++] = cond;
179 272 : }
180 :
181 : static int
182 228 : get_not_cond(char **p)
183 : {
184 : int cond;
185 228 : const char *tok = odbc_get_tok(p);
186 228 : if (!tok) odbc_fatal(": wrong condition syntax\n");
187 :
188 228 : if (!strcmp(tok, "not"))
189 70 : cond = !get_bool(odbc_get_tok(p));
190 : else
191 158 : cond = get_bool(tok);
192 :
193 228 : return cond;
194 : }
195 :
196 : static int
197 200 : get_condition(char **p)
198 : {
199 200 : int cond1 = get_not_cond(p), cond2;
200 : const char *tok;
201 :
202 428 : while ((tok=odbc_get_tok(p)) != NULL) {
203 :
204 28 : cond2 = get_not_cond(p);
205 :
206 28 : if (!strcmp(tok, "or"))
207 0 : cond1 = cond1 || cond2;
208 28 : else if (!strcmp(tok, "and"))
209 28 : cond1 = cond1 && cond2;
210 0 : else odbc_fatal(": wrong condition syntax\n");
211 : }
212 200 : return cond1;
213 : }
214 :
215 : static FILE *parse_file;
216 : static char line_buf[1024];
217 :
218 : void
219 16 : odbc_init_parser(FILE *f)
220 : {
221 16 : if (parse_file)
222 0 : odbc_fatal("parser file already setup\n");
223 16 : parse_file = f;
224 16 : odbc_line_num = 0;
225 16 : odbc_tds_version();
226 16 : }
227 :
228 : const char *
229 6656 : odbc_get_cmd_line(char **p_s, int *cond)
230 : {
231 15080 : while (fgets(line_buf, sizeof(line_buf), parse_file)) {
232 8408 : char *p = line_buf;
233 : const char *cmd;
234 :
235 8408 : ++odbc_line_num;
236 :
237 8408 : cmd = odbc_get_tok(&p);
238 :
239 : /* skip comments */
240 8408 : if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
241 2960 : continue;
242 :
243 : /* conditional statement */
244 7216 : if (!strcmp(cmd, "else")) {
245 16 : int c = pop_condition();
246 16 : push_condition(c);
247 16 : *cond = c && !*cond;
248 16 : continue;
249 : }
250 7200 : if (!strcmp(cmd, "endif")) {
251 256 : *cond = pop_condition();
252 256 : continue;
253 : }
254 6944 : if (!strcmp(cmd, "if")) {
255 256 : push_condition(*cond);
256 256 : if (*cond)
257 200 : *cond = get_condition(&p);
258 256 : continue;
259 : }
260 :
261 6688 : if (strcmp(cmd, "tds_version_cmp") == 0) {
262 48 : const char *bool_name = odbc_get_tok(&p);
263 48 : const char *cmp = odbc_get_tok(&p);
264 48 : const char *s_ver = odbc_get_tok(&p);
265 48 : int ver = odbc_tds_version();
266 : int expected;
267 : int res;
268 : unsigned M, m;
269 :
270 48 : if (!cmp || !s_ver)
271 0 : odbc_fatal(": missing parameters\n");
272 48 : if (sscanf(s_ver, "%u.%u", &M, &m) != 2)
273 0 : odbc_fatal(": invalid version %s\n", s_ver);
274 48 : expected = M * 0x100u + m;
275 :
276 48 : if (strcmp(cmp, ">") == 0)
277 0 : res = ver > expected;
278 48 : else if (strcmp(cmp, ">=") == 0)
279 32 : res = ver >= expected;
280 16 : else if (strcmp(cmp, "<") == 0)
281 0 : res = ver < expected;
282 16 : else if (strcmp(cmp, "<=") == 0)
283 0 : res = ver <= expected;
284 16 : else if (strcmp(cmp, "==") == 0)
285 16 : res = ver == expected;
286 0 : else if (strcmp(cmp, "!=") == 0)
287 0 : res = ver != expected;
288 : else
289 0 : odbc_fatal(": invalid operator %s\n", cmp);
290 :
291 48 : if (*cond)
292 42 : odbc_set_bool(bool_name, res);
293 48 : continue;
294 : }
295 :
296 6640 : *p_s = p;
297 6640 : return cmd;
298 : }
299 : return NULL;
300 : }
301 :
|