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