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
26 #include "wbemprox_private.h"
28 #include "wine/list.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL
(wbemprox
);
41 enum wbm_namespace ns
;
50 static void *alloc_mem
( struct parser
*parser
, UINT size
)
52 struct list
*mem
= malloc
( sizeof
(struct list
) + size
);
53 list_add_tail
( parser
->mem
, mem
);
57 static struct property
*alloc_property
( struct parser
*parser
, const WCHAR
*class
, const WCHAR
*name
)
59 struct property
*prop
= alloc_mem
( parser
, sizeof
(*prop
) );
69 static struct keyword
*alloc_keyword
( struct parser
*parser
, const WCHAR
*name
, const WCHAR
*value
)
71 struct keyword
*keyword
= alloc_mem
( parser
, sizeof
(*keyword
) );
75 keyword
->value
= value
;
81 static WCHAR
*get_string
( struct parser
*parser
, const struct string *str
)
83 const WCHAR
*p
= str
->data
;
87 if
((p
[0] == '\"' && p
[len
- 1] != '\"') ||
88 (p
[0] == '\'' && p
[len
- 1] != '\'')) return NULL
;
89 if
((p
[0] == '\"' && p
[len
- 1] == '\"') ||
90 (p
[0] == '\'' && p
[len
- 1] == '\''))
95 if
(!(ret
= alloc_mem
( parser
, (len
+ 1) * sizeof
(WCHAR
) ))) return NULL
;
96 memcpy
( ret
, p
, len
* sizeof
(WCHAR
) );
101 static WCHAR
*get_path
( struct parser
*parser
, const struct string *str
)
103 const WCHAR
*p
= str
->data
;
107 if
(p
[0] == '{' && p
[len
- 1] == '}')
113 if
(!(ret
= alloc_mem
( parser
, (len
+ 1) * sizeof
(WCHAR
) ))) return NULL
;
114 memcpy
( ret
, p
, len
* sizeof
(WCHAR
) );
119 static int get_int
( struct parser
*parser
)
121 const WCHAR
*p
= &parser
->cmd
[parser
->idx
];
124 for
(i
= 0; i
< parser
->len
; i
++)
126 if
(p
[i
] < '0' || p
[i
] > '9')
128 ERR
("should only be numbers here!\n");
131 ret
= (p
[i
] - '0') + ret
* 10;
136 static struct expr
*expr_complex
( struct parser
*parser
, struct expr
*l
, UINT op
, struct expr
*r
)
138 struct expr
*e
= alloc_mem
( parser
, sizeof
(*e
) );
141 e
->type
= EXPR_COMPLEX
;
149 static struct expr
*expr_unary
( struct parser
*parser
, struct expr
*l
, UINT op
)
151 struct expr
*e
= alloc_mem
( parser
, sizeof
(*e
) );
154 e
->type
= EXPR_UNARY
;
157 e
->u.expr.right
= NULL
;
162 static struct expr
*expr_ival
( struct parser
*parser
, int val
)
164 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
173 static struct expr
*expr_sval
( struct parser
*parser
, const struct string *str
)
175 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
179 e
->u.sval
= get_string
( parser
, str
);
181 return NULL
; /* e will be freed by query destructor */
186 static struct expr
*expr_bval
( struct parser
*parser
, int val
)
188 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
197 static struct expr
*expr_propval
( struct parser
*parser
, const struct property
*prop
)
199 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
202 e
->type
= EXPR_PROPVAL
;
208 static int wql_error
( struct parser
*parser
, const char *str
);
209 static int wql_lex
( void *val
, struct parser
*parser
);
211 #define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \
212 *parser
->view
= current_view
; \
213 result
= current_view
217 %lex
-param
{ struct parser
*ctx
}
218 %parse
-param
{ struct parser
*ctx
}
219 %define parse.
error verbose
220 %define api.prefix
{wql_
}
227 struct property
*proplist
;
228 struct keyword
*keywordlist
;
234 %token TK_SELECT TK_FROM TK_STAR TK_COMMA TK_DOT TK_IS TK_LP TK_RP TK_NULL TK_FALSE TK_TRUE
235 %token TK_INTEGER TK_WHERE TK_SPACE TK_MINUS TK_ILLEGAL TK_BY TK_ASSOCIATORS TK_OF
236 %token
<str
> TK_STRING TK_ID TK_PATH
238 %type
<string> id path
239 %type
<proplist
> prop proplist
240 %type
<keywordlist
> keyword keywordlist
241 %type
<view
> query select associatorsof
242 %type
<expr
> expr prop_val const_val string_val
243 %type
<integer
> number
245 %left TK_OR TK_AND TK_NOT TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
258 $$
= get_path
( ctx
, &$1 );
267 $$
= alloc_keyword
( ctx
, $1, NULL
);
273 $$
= alloc_keyword
( ctx
, $1, $3 );
281 | keyword keywordlist
288 TK_ASSOCIATORS TK_OF path
291 struct parser
*parser
= ctx
;
294 hr
= create_view
( VIEW_TYPE_ASSOCIATORS
, ctx
->ns
, $3, NULL
, NULL
, NULL
, NULL
, &view
);
301 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
303 | TK_ASSOCIATORS TK_OF path TK_WHERE keywordlist
306 struct parser
*parser
= ctx
;
309 hr
= create_view
( VIEW_TYPE_ASSOCIATORS
, ctx
->ns
, $3, $5, NULL
, NULL
, NULL
, &view
);
316 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
324 struct parser
*parser
= ctx
;
327 hr
= create_view
( VIEW_TYPE_SELECT
, ctx
->ns
, NULL
, NULL
, $3, NULL
, NULL
, &view
);
334 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
336 | TK_SELECT proplist TK_FROM id
339 struct parser
*parser
= ctx
;
342 hr
= create_view
( VIEW_TYPE_SELECT
, ctx
->ns
, NULL
, NULL
, $4, $2, NULL
, &view
);
349 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
351 | TK_SELECT proplist TK_FROM id TK_WHERE expr
354 struct parser
*parser
= ctx
;
357 hr
= create_view
( VIEW_TYPE_SELECT
, ctx
->ns
, NULL
, NULL
, $4, $2, $6, &view
);
364 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
370 | prop TK_COMMA proplist
383 $$
= alloc_property
( ctx
, $1, $3 );
389 $$
= alloc_property
( ctx
, NULL
, $1 );
398 $$
= get_string
( ctx
, &$1 );
420 $$
= expr_complex
( ctx
, $1, OP_AND
, $3 );
426 $$
= expr_complex
( ctx
, $1, OP_OR
, $3 );
432 $$
= expr_unary
( ctx
, $2, OP_NOT
);
436 | prop_val TK_EQ const_val
438 $$
= expr_complex
( ctx
, $1, OP_EQ
, $3 );
442 | prop_val TK_GT const_val
444 $$
= expr_complex
( ctx
, $1, OP_GT
, $3 );
448 | prop_val TK_LT const_val
450 $$
= expr_complex
( ctx
, $1, OP_LT
, $3 );
454 | prop_val TK_LE const_val
456 $$
= expr_complex
( ctx
, $1, OP_LE
, $3 );
460 | prop_val TK_GE const_val
462 $$
= expr_complex
( ctx
, $1, OP_GE
, $3 );
466 | prop_val TK_NE const_val
468 $$
= expr_complex
( ctx
, $1, OP_NE
, $3 );
472 | const_val TK_EQ prop_val
474 $$
= expr_complex
( ctx
, $1, OP_EQ
, $3 );
478 | const_val TK_GT prop_val
480 $$
= expr_complex
( ctx
, $1, OP_GT
, $3 );
484 | const_val TK_LT prop_val
486 $$
= expr_complex
( ctx
, $1, OP_LT
, $3 );
490 | const_val TK_LE prop_val
492 $$
= expr_complex
( ctx
, $1, OP_LE
, $3 );
496 | const_val TK_GE prop_val
498 $$
= expr_complex
( ctx
, $1, OP_GE
, $3 );
502 | const_val TK_NE prop_val
504 $$
= expr_complex
( ctx
, $1, OP_NE
, $3 );
508 | prop_val TK_LIKE string_val
510 $$
= expr_complex
( ctx
, $1, OP_LIKE
, $3 );
514 | prop_val TK_IS TK_NULL
516 $$
= expr_unary
( ctx
, $1, OP_ISNULL
);
520 | prop_val TK_IS TK_NOT TK_NULL
522 $$
= expr_unary
( ctx
, $1, OP_NOTNULL
);
526 | prop_val TK_EQ TK_NULL
528 $$
= expr_unary
( ctx
, $1, OP_ISNULL
);
532 | TK_NULL TK_EQ prop_val
534 $$
= expr_unary
( ctx
, $3, OP_ISNULL
);
538 | prop_val TK_NE TK_NULL
540 $$
= expr_unary
( ctx
, $1, OP_NOTNULL
);
544 | TK_NULL TK_NE prop_val
546 $$
= expr_unary
( ctx
, $3, OP_NOTNULL
);
555 $$
= expr_sval
( ctx
, &$1 );
564 $$
= expr_propval
( ctx
, $1 );
573 $$
= expr_ival
( ctx
, $1 );
579 $$
= expr_sval
( ctx
, &$1 );
585 $$
= expr_bval
( ctx
, -1 );
591 $$
= expr_bval
( ctx
, 0 );
599 HRESULT parse_query
( enum wbm_namespace ns
, const WCHAR
*str
, struct view
**view
, struct list
*mem
)
601 struct parser parser
;
609 parser.
error = WBEM_E_INVALID_QUERY
;
614 ret
= wql_parse
( &parser
);
615 TRACE
("wql_parse returned %d\n", ret
);
620 destroy_view
( *parser.view
);
628 static const char id_char
[] =
630 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
631 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
633 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
634 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
635 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
636 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
637 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
638 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
639 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
640 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
641 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
642 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
643 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
644 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
645 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
648 static int is_idchar
(WCHAR chr
)
650 return chr
>= ARRAY_SIZE
(id_char
) || id_char
[chr
];
660 #define MIN_TOKEN_LEN 2
661 #define MAX_TOKEN_LEN 11
663 #define X(str) str, ARRAY_SIZE(str) - 1
664 static const struct wql_keyword keyword_table
[] =
666 { X
(L
"AND"), TK_AND
},
667 { X
(L
"ASSOCIATORS"), TK_ASSOCIATORS
},
669 { X
(L
"FALSE"), TK_FALSE
},
670 { X
(L
"FROM"), TK_FROM
},
672 { X
(L
"LIKE"), TK_LIKE
},
673 { X
(L
"NOT"), TK_NOT
},
674 { X
(L
"NULL"), TK_NULL
},
677 { X
(L
"SELECT"), TK_SELECT
},
678 { X
(L
"TRUE"), TK_TRUE
},
679 { X
(L
"WHERE"), TK_WHERE
}
683 static int __cdecl cmp_keyword
( const void *arg1
, const void *arg2
)
685 const struct wql_keyword
*key1
= arg1
, *key2
= arg2
;
686 int len
= min
( key1
->len
, key2
->len
);
689 if
((ret
= wcsnicmp
( key1
->name
, key2
->name
, len
))) return ret
;
690 if
(key1
->len
< key2
->len
) return
-1;
691 else if
(key1
->len
> key2
->len
) return
1;
695 static int keyword_type
( const WCHAR
*str
, unsigned int len
)
697 struct wql_keyword key
, *ret
;
699 if
(len
< MIN_TOKEN_LEN || len
> MAX_TOKEN_LEN
) return TK_ID
;
704 ret
= bsearch
( &key
, keyword_table
, ARRAY_SIZE
(keyword_table
), sizeof
(struct wql_keyword
), cmp_keyword
);
705 if
(ret
) return ret
->type
;
709 static int get_token
( const WCHAR
*s
, int *token
)
719 for
(i
= 1; iswspace
( s
[i
] ); i
++) {}
723 if
(!s
[1]) return
-1;
733 for
(i
= 1; s
[i
] && s
[i
] != '}'; i
++) {}
753 else if
(s
[1] == '>')
790 for
(i
= 1; s
[i
]; i
++)
792 if
(s
[i
] == s
[0]) break
;
798 if
(!is_digit
( s
[1] ))
804 case
'0': case
'1': case
'2': case
'3': case
'4':
805 case
'5': case
'6': case
'7': case
'8': case
'9':
807 for
(i
= 1; is_digit
( s
[i
] ); i
++) {}
810 if
(!is_idchar
(*s
)) break
;
812 for
(i
= 1; is_idchar
(s
[i
]); i
++) {}
813 *token
= keyword_type
( s
, i
);
820 static int wql_lex
( void *p
, struct parser
*parser
)
822 struct string *str
= p
;
826 parser
->idx
+= parser
->len
;
827 if
(!parser
->cmd
[parser
->idx
]) return
0;
828 parser
->len
= get_token
( &parser
->cmd
[parser
->idx
], &token
);
829 if
(!parser
->len
) break
;
831 str
->data
= &parser
->cmd
[parser
->idx
];
832 str
->len
= parser
->len
;
833 } while
(token
== TK_SPACE
);
837 static int wql_error
( struct parser
*parser
, const char *str
)