4 * Copyright 2012 Hans Leidekker for CodeWeavers
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.
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.
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
27 #include "wbemprox_private.h"
29 #include "wine/list.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 #define YYLEX_PARAM ctx
34 #define YYPARSE_PARAM ctx
35 #define YYERROR_DEBUG 1
36 #define YYERROR_VERBOSE 1
38 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
56 static void *alloc_mem( struct parser *parser, UINT size )
58 struct list *mem = heap_alloc( sizeof(struct list) + size );
59 list_add_tail( parser->mem, mem );
63 static struct property *alloc_property( struct parser *parser, const WCHAR *class, const WCHAR *name )
65 struct property *prop = alloc_mem( parser, sizeof(*prop) );
75 static WCHAR *get_string( struct parser *parser, const struct string *str )
77 const WCHAR *p = str->data;
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] == '\''))
89 if (!(ret = alloc_mem( parser, (len + 1) * sizeof(WCHAR) ))) return NULL;
90 memcpy( ret, p, len * sizeof(WCHAR) );
95 static int get_int( struct parser *parser )
97 const WCHAR *p = &parser->cmd[parser->idx];
100 for (i = 0; i < parser->len; i++)
102 if (p[i] < '0' || p[i] > '9')
104 ERR("should only be numbers here!\n");
107 ret = (p[i] - '0') + ret * 10;
112 static struct expr *expr_complex( struct parser *parser, struct expr *l, UINT op, struct expr *r )
114 struct expr *e = alloc_mem( parser, sizeof(*e) );
117 e->type = EXPR_COMPLEX;
125 static struct expr *expr_unary( struct parser *parser, struct expr *l, UINT op )
127 struct expr *e = alloc_mem( parser, sizeof(*e) );
130 e->type = EXPR_UNARY;
133 e->u.expr.right = NULL;
138 static struct expr *expr_ival( struct parser *parser, int val )
140 struct expr *e = alloc_mem( parser, sizeof *e );
149 static struct expr *expr_sval( struct parser *parser, const struct string *str )
151 struct expr *e = alloc_mem( parser, sizeof *e );
155 e->u.sval = get_string( parser, str );
157 return NULL; /* e will be freed by query destructor */
162 static struct expr *expr_bval( struct parser *parser, int val )
164 struct expr *e = alloc_mem( parser, sizeof *e );
173 static struct expr *expr_propval( struct parser *parser, const struct property *prop )
175 struct expr *e = alloc_mem( parser, sizeof *e );
178 e->type = EXPR_PROPVAL;
184 static int wql_error( const char *str );
185 static int wql_lex( void *val, struct parser *parser );
187 #define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \
188 *parser->view = current_view; \
189 result = current_view
199 struct property *proplist;
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
210 %type <proplist> prop proplist
212 %type <expr> expr prop_val const_val string_val
213 %type <integer> number
218 %left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
226 struct parser *parser = ctx;
229 hr = create_view( NULL, $3, NULL, &view );
233 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
235 | TK_SELECT proplist TK_FROM id
238 struct parser *parser = ctx;
241 hr = create_view( $2, $4, NULL, &view );
245 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
247 | TK_SELECT proplist TK_FROM id TK_WHERE expr
250 struct parser *parser = ctx;
253 hr = create_view( $2, $4, $6, &view );
257 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
263 | prop TK_COMMA proplist
276 $$ = alloc_property( ctx, $1, $3 );
282 $$ = alloc_property( ctx, NULL, $1 );
291 $$ = get_string( ctx, &$1 );
313 $$ = expr_complex( ctx, $1, OP_AND, $3 );
319 $$ = expr_complex( ctx, $1, OP_OR, $3 );
323 | prop_val TK_EQ const_val
325 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
329 | prop_val TK_GT const_val
331 $$ = expr_complex( ctx, $1, OP_GT, $3 );
335 | prop_val TK_LT const_val
337 $$ = expr_complex( ctx, $1, OP_LT, $3 );
341 | prop_val TK_LE const_val
343 $$ = expr_complex( ctx, $1, OP_LE, $3 );
347 | prop_val TK_GE const_val
349 $$ = expr_complex( ctx, $1, OP_GE, $3 );
353 | prop_val TK_NE const_val
355 $$ = expr_complex( ctx, $1, OP_NE, $3 );
359 | const_val TK_EQ prop_val
361 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
365 | const_val TK_GT prop_val
367 $$ = expr_complex( ctx, $1, OP_GT, $3 );
371 | const_val TK_LT prop_val
373 $$ = expr_complex( ctx, $1, OP_LT, $3 );
377 | const_val TK_LE prop_val
379 $$ = expr_complex( ctx, $1, OP_LE, $3 );
383 | const_val TK_GE prop_val
385 $$ = expr_complex( ctx, $1, OP_GE, $3 );
389 | const_val TK_NE prop_val
391 $$ = expr_complex( ctx, $1, OP_NE, $3 );
395 | prop_val TK_LIKE string_val
397 $$ = expr_complex( ctx, $1, OP_LIKE, $3 );
401 | prop_val TK_IS TK_NULL
403 $$ = expr_unary( ctx, $1, OP_ISNULL );
407 | prop_val TK_IS TK_NOT TK_NULL
409 $$ = expr_unary( ctx, $1, OP_NOTNULL );
418 $$ = expr_sval( ctx, &$1 );
427 $$ = expr_propval( ctx, $1 );
436 $$ = expr_ival( ctx, $1 );
442 $$ = expr_sval( ctx, &$1 );
448 $$ = expr_bval( ctx, -1 );
454 $$ = expr_bval( ctx, 0 );
462 HRESULT parse_query( const WCHAR *str, struct view **view, struct list *mem )
464 struct parser parser;
472 parser.error = WBEM_E_INVALID_QUERY;
476 ret = wql_parse( &parser );
477 TRACE("wql_parse returned %d\n", ret);
482 destroy_view( *parser.view );
490 static const char id_char[] =
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,
517 #define MAX_TOKEN_LEN 6
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'};
532 static const struct keyword keyword_table[] =
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 }
548 static int cmp_keyword( const void *arg1, const void *arg2 )
550 const struct keyword *key1 = arg1, *key2 = arg2;
551 int len = min( key1->len, key2->len );
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;
560 static int keyword_type( const WCHAR *str, unsigned int len )
562 struct keyword key, *ret;
564 if (len > MAX_TOKEN_LEN) return TK_ID;
569 ret = bsearch( &key, keyword_table, SIZEOF(keyword_table), sizeof(struct keyword), cmp_keyword );
570 if (ret) return ret->type;
574 static int get_token( const WCHAR *s, int *token )
583 for (i = 1; isspaceW( s[i] ); i++) {}
587 if (!s[1]) return -1;
608 else if (s[1] == '>')
646 for (i = 1; s[i]; i++)
648 if (s[i] == s[0]) break;
655 if (!isdigitW( s[1] ))
661 case '0': case '1': case '2': case '3': case '4':
662 case '5': case '6': case '7': case '8': case '9':
664 for (i = 1; isdigitW( s[i] ); i++) {}
667 if (!id_char[*s]) break;
669 for (i = 1; id_char[s[i]]; i++) {}
670 *token = keyword_type( s, i );
677 static int wql_lex( void *p, struct parser *parser )
679 struct string *str = p;
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;
688 str->data = &parser->cmd[parser->idx];
689 str->len = parser->len;
690 } while (token == TK_SPACE);
694 static int wql_error( const char *str )