1 %{
2
3 /*
4 * Copyright 2012 Hans Leidekker for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wbemcli.h"
26 #include "wbemprox_private.h"
27
28 #include "wine/list.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 struct parser
34 {
35 const WCHAR *cmd;
36 UINT idx;
37 UINT len;
38 HRESULT error;
39 struct view **view;
40 struct list *mem;
41 };
42
43 struct string
44 {
45 const WCHAR *data;
46 int len;
47 };
48
alloc_mem(struct parser * parser,UINT size)49 static void *alloc_mem( struct parser *parser, UINT size )
50 {
51 struct list *mem = heap_alloc( sizeof(struct list) + size );
52 list_add_tail( parser->mem, mem );
53 return &mem[1];
54 }
55
alloc_property(struct parser * parser,const WCHAR * class,const WCHAR * name)56 static struct property *alloc_property( struct parser *parser, const WCHAR *class, const WCHAR *name )
57 {
58 struct property *prop = alloc_mem( parser, sizeof(*prop) );
59 if (prop)
60 {
61 prop->name = name;
62 prop->class = class;
63 prop->next = NULL;
64 }
65 return prop;
66 }
67
alloc_keyword(struct parser * parser,const WCHAR * name,const WCHAR * value)68 static struct keyword *alloc_keyword( struct parser *parser, const WCHAR *name, const WCHAR *value )
69 {
70 struct keyword *keyword = alloc_mem( parser, sizeof(*keyword) );
71 if (keyword)
72 {
73 keyword->name = name;
74 keyword->value = value;
75 keyword->next = NULL;
76 }
77 return keyword;
78 }
79
get_string(struct parser * parser,const struct string * str)80 static WCHAR *get_string( struct parser *parser, const struct string *str )
81 {
82 const WCHAR *p = str->data;
83 int len = str->len;
84 WCHAR *ret;
85
86 if ((p[0] == '\"' && p[len - 1] != '\"') ||
87 (p[0] == '\'' && p[len - 1] != '\'')) return NULL;
88 if ((p[0] == '\"' && p[len - 1] == '\"') ||
89 (p[0] == '\'' && p[len - 1] == '\''))
90 {
91 p++;
92 len -= 2;
93 }
94 if (!(ret = alloc_mem( parser, (len + 1) * sizeof(WCHAR) ))) return NULL;
95 memcpy( ret, p, len * sizeof(WCHAR) );
96 ret[len] = 0;
97 return ret;
98 }
99
get_path(struct parser * parser,const struct string * str)100 static WCHAR *get_path( struct parser *parser, const struct string *str )
101 {
102 const WCHAR *p = str->data;
103 int len = str->len;
104 WCHAR *ret;
105
106 if (p[0] == '{' && p[len - 1] == '}')
107 {
108 p++;
109 len -= 2;
110 }
111
112 if (!(ret = alloc_mem( parser, (len + 1) * sizeof(WCHAR) ))) return NULL;
113 memcpy( ret, p, len * sizeof(WCHAR) );
114 ret[len] = 0;
115 return ret;
116 }
117
get_int(struct parser * parser)118 static int get_int( struct parser *parser )
119 {
120 const WCHAR *p = &parser->cmd[parser->idx];
121 int i, ret = 0;
122
123 for (i = 0; i < parser->len; i++)
124 {
125 if (p[i] < '0' || p[i] > '9')
126 {
127 ERR("should only be numbers here!\n");
128 break;
129 }
130 ret = (p[i] - '0') + ret * 10;
131 }
132 return ret;
133 }
134
expr_complex(struct parser * parser,struct expr * l,UINT op,struct expr * r)135 static struct expr *expr_complex( struct parser *parser, struct expr *l, UINT op, struct expr *r )
136 {
137 struct expr *e = alloc_mem( parser, sizeof(*e) );
138 if (e)
139 {
140 e->type = EXPR_COMPLEX;
141 e->u.expr.left = l;
142 e->u.expr.op = op;
143 e->u.expr.right = r;
144 }
145 return e;
146 }
147
expr_unary(struct parser * parser,struct expr * l,UINT op)148 static struct expr *expr_unary( struct parser *parser, struct expr *l, UINT op )
149 {
150 struct expr *e = alloc_mem( parser, sizeof(*e) );
151 if (e)
152 {
153 e->type = EXPR_UNARY;
154 e->u.expr.left = l;
155 e->u.expr.op = op;
156 e->u.expr.right = NULL;
157 }
158 return e;
159 }
160
expr_ival(struct parser * parser,int val)161 static struct expr *expr_ival( struct parser *parser, int val )
162 {
163 struct expr *e = alloc_mem( parser, sizeof *e );
164 if (e)
165 {
166 e->type = EXPR_IVAL;
167 e->u.ival = val;
168 }
169 return e;
170 }
171
expr_sval(struct parser * parser,const struct string * str)172 static struct expr *expr_sval( struct parser *parser, const struct string *str )
173 {
174 struct expr *e = alloc_mem( parser, sizeof *e );
175 if (e)
176 {
177 e->type = EXPR_SVAL;
178 e->u.sval = get_string( parser, str );
179 if (!e->u.sval)
180 return NULL; /* e will be freed by query destructor */
181 }
182 return e;
183 }
184
expr_bval(struct parser * parser,int val)185 static struct expr *expr_bval( struct parser *parser, int val )
186 {
187 struct expr *e = alloc_mem( parser, sizeof *e );
188 if (e)
189 {
190 e->type = EXPR_BVAL;
191 e->u.ival = val;
192 }
193 return e;
194 }
195
expr_propval(struct parser * parser,const struct property * prop)196 static struct expr *expr_propval( struct parser *parser, const struct property *prop )
197 {
198 struct expr *e = alloc_mem( parser, sizeof *e );
199 if (e)
200 {
201 e->type = EXPR_PROPVAL;
202 e->u.propval = prop;
203 }
204 return e;
205 }
206
207 static int wql_error( struct parser *parser, const char *str );
208 static int wql_lex( void *val, struct parser *parser );
209
210 #define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \
211 *parser->view = current_view; \
212 result = current_view
213
214 %}
215
216 %lex-param { struct parser *ctx }
217 %parse-param { struct parser *ctx }
218 %define parse.error verbose
219 %pure-parser
220
221 %union
222 {
223 struct string str;
224 WCHAR *string;
225 struct property *proplist;
226 struct keyword *keywordlist;
227 struct view *view;
228 struct expr *expr;
229 int integer;
230 }
231
232 %token TK_SELECT TK_FROM TK_STAR TK_COMMA TK_DOT TK_IS TK_LP TK_RP TK_NULL TK_FALSE TK_TRUE
233 %token TK_INTEGER TK_WHERE TK_SPACE TK_MINUS TK_ILLEGAL TK_BY TK_ASSOCIATORS TK_OF
234 %token <str> TK_STRING TK_ID TK_PATH
235
236 %type <string> id path
237 %type <proplist> prop proplist
238 %type <keywordlist> keyword keywordlist
239 %type <view> query select associatorsof
240 %type <expr> expr prop_val const_val string_val
241 %type <integer> number
242
243 %left TK_OR TK_AND TK_NOT TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
244
245 %%
246
247 query:
248 select
249 |
250 associatorsof
251 ;
252
253 path:
254 TK_PATH
255 {
256 $$ = get_path( ctx, &$1 );
257 if (!$$)
258 YYABORT;
259 }
260 ;
261
262 keyword:
263 id
264 {
265 $$ = alloc_keyword( ctx, $1, NULL );
266 if (!$$)
267 YYABORT;
268 }
269 | id TK_EQ id
270 {
271 $$ = alloc_keyword( ctx, $1, $3 );
272 if (!$$)
273 YYABORT;
274 }
275 ;
276
277 keywordlist:
278 keyword
279 | keyword keywordlist
280 {
281 $1->next = $2;
282 }
283 ;
284
285 associatorsof:
286 TK_ASSOCIATORS TK_OF path
287 {
288 HRESULT hr;
289 struct parser *parser = ctx;
290 struct view *view;
291
292 hr = create_view( VIEW_TYPE_ASSOCIATORS, $3, NULL, NULL, NULL, NULL, &view );
293 if (hr != S_OK)
294 YYABORT;
295
296 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
297 }
298 | TK_ASSOCIATORS TK_OF path TK_WHERE keywordlist
299 {
300 HRESULT hr;
301 struct parser *parser = ctx;
302 struct view *view;
303
304 hr = create_view( VIEW_TYPE_ASSOCIATORS, $3, $5, NULL, NULL, NULL, &view );
305 if (hr != S_OK)
306 YYABORT;
307
308 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
309 }
310 ;
311
312 select:
313 TK_SELECT TK_FROM id
314 {
315 HRESULT hr;
316 struct parser *parser = ctx;
317 struct view *view;
318
319 hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $3, NULL, NULL, &view );
320 if (hr != S_OK)
321 YYABORT;
322
323 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
324 }
325 | TK_SELECT proplist TK_FROM id
326 {
327 HRESULT hr;
328 struct parser *parser = ctx;
329 struct view *view;
330
331 hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $4, $2, NULL, &view );
332 if (hr != S_OK)
333 YYABORT;
334
335 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
336 }
337 | TK_SELECT proplist TK_FROM id TK_WHERE expr
338 {
339 HRESULT hr;
340 struct parser *parser = ctx;
341 struct view *view;
342
343 hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $4, $2, $6, &view );
344 if (hr != S_OK)
345 YYABORT;
346
347 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
348 }
349 ;
350
351 proplist:
352 prop
353 | prop TK_COMMA proplist
354 {
355 $1->next = $3;
356 }
357 | TK_STAR
358 {
359 $$ = NULL;
360 }
361 ;
362
363 prop:
364 id TK_DOT id
365 {
366 $$ = alloc_property( ctx, $1, $3 );
367 if (!$$)
368 YYABORT;
369 }
370 | id
371 {
372 $$ = alloc_property( ctx, NULL, $1 );
373 if (!$$)
374 YYABORT;
375 }
376 ;
377
378 id:
379 TK_ID
380 {
381 $$ = get_string( ctx, &$1 );
382 if (!$$)
383 YYABORT;
384 }
385 ;
386
387 number:
388 TK_INTEGER
389 {
390 $$ = get_int( ctx );
391 }
392 ;
393
394 expr:
395 TK_LP expr TK_RP
396 {
397 $$ = $2;
398 if (!$$)
399 YYABORT;
400 }
401 | expr TK_AND expr
402 {
403 $$ = expr_complex( ctx, $1, OP_AND, $3 );
404 if (!$$)
405 YYABORT;
406 }
407 | expr TK_OR expr
408 {
409 $$ = expr_complex( ctx, $1, OP_OR, $3 );
410 if (!$$)
411 YYABORT;
412 }
413 | TK_NOT expr
414 {
415 $$ = expr_unary( ctx, $2, OP_NOT );
416 if (!$$)
417 YYABORT;
418 }
419 | prop_val TK_EQ const_val
420 {
421 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
422 if (!$$)
423 YYABORT;
424 }
425 | prop_val TK_GT const_val
426 {
427 $$ = expr_complex( ctx, $1, OP_GT, $3 );
428 if (!$$)
429 YYABORT;
430 }
431 | prop_val TK_LT const_val
432 {
433 $$ = expr_complex( ctx, $1, OP_LT, $3 );
434 if (!$$)
435 YYABORT;
436 }
437 | prop_val TK_LE const_val
438 {
439 $$ = expr_complex( ctx, $1, OP_LE, $3 );
440 if (!$$)
441 YYABORT;
442 }
443 | prop_val TK_GE const_val
444 {
445 $$ = expr_complex( ctx, $1, OP_GE, $3 );
446 if (!$$)
447 YYABORT;
448 }
449 | prop_val TK_NE const_val
450 {
451 $$ = expr_complex( ctx, $1, OP_NE, $3 );
452 if (!$$)
453 YYABORT;
454 }
455 | const_val TK_EQ prop_val
456 {
457 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
458 if (!$$)
459 YYABORT;
460 }
461 | const_val TK_GT prop_val
462 {
463 $$ = expr_complex( ctx, $1, OP_GT, $3 );
464 if (!$$)
465 YYABORT;
466 }
467 | const_val TK_LT prop_val
468 {
469 $$ = expr_complex( ctx, $1, OP_LT, $3 );
470 if (!$$)
471 YYABORT;
472 }
473 | const_val TK_LE prop_val
474 {
475 $$ = expr_complex( ctx, $1, OP_LE, $3 );
476 if (!$$)
477 YYABORT;
478 }
479 | const_val TK_GE prop_val
480 {
481 $$ = expr_complex( ctx, $1, OP_GE, $3 );
482 if (!$$)
483 YYABORT;
484 }
485 | const_val TK_NE prop_val
486 {
487 $$ = expr_complex( ctx, $1, OP_NE, $3 );
488 if (!$$)
489 YYABORT;
490 }
491 | prop_val TK_LIKE string_val
492 {
493 $$ = expr_complex( ctx, $1, OP_LIKE, $3 );
494 if (!$$)
495 YYABORT;
496 }
497 | prop_val TK_IS TK_NULL
498 {
499 $$ = expr_unary( ctx, $1, OP_ISNULL );
500 if (!$$)
501 YYABORT;
502 }
503 | prop_val TK_IS TK_NOT TK_NULL
504 {
505 $$ = expr_unary( ctx, $1, OP_NOTNULL );
506 if (!$$)
507 YYABORT;
508 }
509 | prop_val TK_EQ TK_NULL
510 {
511 $$ = expr_unary( ctx, $1, OP_ISNULL );
512 if (!$$)
513 YYABORT;
514 }
515 | TK_NULL TK_EQ prop_val
516 {
517 $$ = expr_unary( ctx, $3, OP_ISNULL );
518 if (!$$)
519 YYABORT;
520 }
521 | prop_val TK_NE TK_NULL
522 {
523 $$ = expr_unary( ctx, $1, OP_NOTNULL );
524 if (!$$)
525 YYABORT;
526 }
527 | TK_NULL TK_NE prop_val
528 {
529 $$ = expr_unary( ctx, $3, OP_NOTNULL );
530 if (!$$)
531 YYABORT;
532 }
533 ;
534
535 string_val:
536 TK_STRING
537 {
538 $$ = expr_sval( ctx, &$1 );
539 if (!$$)
540 YYABORT;
541 }
542 ;
543
544 prop_val:
545 prop
546 {
547 $$ = expr_propval( ctx, $1 );
548 if (!$$)
549 YYABORT;
550 }
551 ;
552
553 const_val:
554 number
555 {
556 $$ = expr_ival( ctx, $1 );
557 if (!$$)
558 YYABORT;
559 }
560 | TK_STRING
561 {
562 $$ = expr_sval( ctx, &$1 );
563 if (!$$)
564 YYABORT;
565 }
566 | TK_TRUE
567 {
568 $$ = expr_bval( ctx, -1 );
569 if (!$$)
570 YYABORT;
571 }
572 | TK_FALSE
573 {
574 $$ = expr_bval( ctx, 0 );
575 if (!$$)
576 YYABORT;
577 }
578 ;
579
580 %%
581
582 HRESULT parse_query( const WCHAR *str, struct view **view, struct list *mem )
583 {
584 struct parser parser;
585 int ret;
586
587 *view = NULL;
588
589 parser.cmd = str;
590 parser.idx = 0;
591 parser.len = 0;
592 parser.error = WBEM_E_INVALID_QUERY;
593 parser.view = view;
594 parser.mem = mem;
595
596 ret = wql_parse( &parser );
597 TRACE("wql_parse returned %d\n", ret);
598 if (ret)
599 {
600 if (*parser.view)
601 {
602 destroy_view( *parser.view );
603 *parser.view = NULL;
604 }
605 return parser.error;
606 }
607 return S_OK;
608 }
609
610 static const char id_char[] =
611 {
612 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
615 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
616 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
617 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
618 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
619 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
620 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
621 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
622 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
623 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
624 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
625 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
626 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
627 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
628 };
629
630 struct wql_keyword
631 {
632 const WCHAR *name;
633 unsigned int len;
634 int type;
635 };
636
637 #define MIN_TOKEN_LEN 2
638 #define MAX_TOKEN_LEN 11
639
640 static const WCHAR andW[] = {'A','N','D'};
641 static const WCHAR associatorsW[] = {'A','S','S','O','C','I','A','T','O','R','S'};
642 static const WCHAR byW[] = {'B','Y'};
643 static const WCHAR falseW[] = {'F','A','L','S','E'};
644 static const WCHAR fromW[] = {'F','R','O','M'};
645 static const WCHAR isW[] = {'I','S'};
646 static const WCHAR likeW[] = {'L','I','K','E'};
647 static const WCHAR notW[] = {'N','O','T'};
648 static const WCHAR nullW[] = {'N','U','L','L'};
649 static const WCHAR ofW[] = {'O','F'};
650 static const WCHAR orW[] = {'O','R'};
651 static const WCHAR selectW[] = {'S','E','L','E','C','T'};
652 static const WCHAR trueW[] = {'T','R','U','E'};
653 static const WCHAR whereW[] = {'W','H','E','R','E'};
654
655 static const struct wql_keyword keyword_table[] =
656 {
657 { andW, ARRAY_SIZE(andW), TK_AND },
658 { associatorsW, ARRAY_SIZE(associatorsW), TK_ASSOCIATORS },
659 { byW, ARRAY_SIZE(byW), TK_BY },
660 { falseW, ARRAY_SIZE(falseW), TK_FALSE },
661 { fromW, ARRAY_SIZE(fromW), TK_FROM },
662 { isW, ARRAY_SIZE(isW), TK_IS },
663 { likeW, ARRAY_SIZE(likeW), TK_LIKE },
664 { notW, ARRAY_SIZE(notW), TK_NOT },
665 { nullW, ARRAY_SIZE(nullW), TK_NULL },
666 { ofW, ARRAY_SIZE(ofW), TK_OF },
667 { orW, ARRAY_SIZE(orW), TK_OR },
668 { selectW, ARRAY_SIZE(selectW), TK_SELECT },
669 { trueW, ARRAY_SIZE(trueW), TK_TRUE },
670 { whereW, ARRAY_SIZE(whereW), TK_WHERE }
671 };
672
673 static int __cdecl cmp_keyword( const void *arg1, const void *arg2 )
674 {
675 const struct wql_keyword *key1 = arg1, *key2 = arg2;
676 int len = min( key1->len, key2->len );
677 int ret;
678
679 if ((ret = _wcsnicmp( key1->name, key2->name, len ))) return ret;
680 if (key1->len < key2->len) return -1;
681 else if (key1->len > key2->len) return 1;
682 return 0;
683 }
684
685 static int keyword_type( const WCHAR *str, unsigned int len )
686 {
687 struct wql_keyword key, *ret;
688
689 if (len < MIN_TOKEN_LEN || len > MAX_TOKEN_LEN) return TK_ID;
690
691 key.name = str;
692 key.len = len;
693 key.type = 0;
694 ret = bsearch( &key, keyword_table, ARRAY_SIZE(keyword_table), sizeof(struct wql_keyword), cmp_keyword );
695 if (ret) return ret->type;
696 return TK_ID;
697 }
698
699 static int get_token( const WCHAR *s, int *token )
700 {
701 int i;
702
703 switch (*s)
704 {
705 case ' ':
706 case '\t':
707 case '\r':
708 case '\n':
709 for (i = 1; iswspace( s[i] ); i++) {}
710 *token = TK_SPACE;
711 return i;
712 case '-':
713 if (!s[1]) return -1;
714 *token = TK_MINUS;
715 return 1;
716 case '(':
717 *token = TK_LP;
718 return 1;
719 case ')':
720 *token = TK_RP;
721 return 1;
722 case '{':
723 for (i = 1; s[i] && s[i] != '}'; i++) {}
724 if (s[i] != '}')
725 {
726 *token = TK_ILLEGAL;
727 return i;
728 }
729 *token = TK_PATH;
730 return i + 1;
731 case '*':
732 *token = TK_STAR;
733 return 1;
734 case '=':
735 *token = TK_EQ;
736 return 1;
737 case '<':
738 if (s[1] == '=' )
739 {
740 *token = TK_LE;
741 return 2;
742 }
743 else if (s[1] == '>')
744 {
745 *token = TK_NE;
746 return 2;
747 }
748 else
749 {
750 *token = TK_LT;
751 return 1;
752 }
753 case '>':
754 if (s[1] == '=')
755 {
756 *token = TK_GE;
757 return 2;
758 }
759 else
760 {
761 *token = TK_GT;
762 return 1;
763 }
764 case '!':
765 if (s[1] != '=')
766 {
767 *token = TK_ILLEGAL;
768 return 2;
769 }
770 else
771 {
772 *token = TK_NE;
773 return 2;
774 }
775 case ',':
776 *token = TK_COMMA;
777 return 1;
778 case '\"':
779 case '\'':
780 for (i = 1; s[i]; i++)
781 {
782 if (s[i] == s[0]) break;
783 }
784 if (s[i]) i++;
785 *token = TK_STRING;
786 return i;
787 case '.':
788 if (!iswdigit( s[1] ))
789 {
790 *token = TK_DOT;
791 return 1;
792 }
793 /* fall through */
794 case '0': case '1': case '2': case '3': case '4':
795 case '5': case '6': case '7': case '8': case '9':
796 *token = TK_INTEGER;
797 for (i = 1; iswdigit( s[i] ); i++) {}
798 return i;
799 default:
800 if (!id_char[*s]) break;
801
802 for (i = 1; id_char[s[i]]; i++) {}
803 *token = keyword_type( s, i );
804 return i;
805 }
806 *token = TK_ILLEGAL;
807 return 1;
808 }
809
810 static int wql_lex( void *p, struct parser *parser )
811 {
812 struct string *str = p;
813 int token = -1;
814 do
815 {
816 parser->idx += parser->len;
817 if (!parser->cmd[parser->idx]) return 0;
818 parser->len = get_token( &parser->cmd[parser->idx], &token );
819 if (!parser->len) break;
820
821 str->data = &parser->cmd[parser->idx];
822 str->len = parser->len;
823 } while (token == TK_SPACE);
824 return token;
825 }
826
827 static int wql_error( struct parser *parser, const char *str )
828 {
829 ERR("%s\n", str);
830 return 0;
831 }
832