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