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