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
);
49 static void *alloc_mem
( struct parser
*parser
, UINT size
)
51 struct list
*mem
= heap_alloc
( sizeof
(struct list
) + size
);
52 list_add_tail
( parser
->mem
, mem
);
56 static struct property
*alloc_property
( struct parser
*parser
, const WCHAR
*class
, const WCHAR
*name
)
58 struct property
*prop
= alloc_mem
( parser
, sizeof
(*prop
) );
68 static struct keyword
*alloc_keyword
( struct parser
*parser
, const WCHAR
*name
, const WCHAR
*value
)
70 struct keyword
*keyword
= alloc_mem
( parser
, sizeof
(*keyword
) );
74 keyword
->value
= value
;
80 static WCHAR
*get_string
( struct parser
*parser
, const struct string *str
)
82 const WCHAR
*p
= str
->data
;
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] == '\''))
94 if
(!(ret
= alloc_mem
( parser
, (len
+ 1) * sizeof
(WCHAR
) ))) return NULL
;
95 memcpy
( ret
, p
, len
* sizeof
(WCHAR
) );
100 static WCHAR
*get_path
( struct parser
*parser
, const struct string *str
)
102 const WCHAR
*p
= str
->data
;
106 if
(p
[0] == '{' && p
[len
- 1] == '}')
112 if
(!(ret
= alloc_mem
( parser
, (len
+ 1) * sizeof
(WCHAR
) ))) return NULL
;
113 memcpy
( ret
, p
, len
* sizeof
(WCHAR
) );
118 static int get_int
( struct parser
*parser
)
120 const WCHAR
*p
= &parser
->cmd
[parser
->idx
];
123 for
(i
= 0; i
< parser
->len
; i
++)
125 if
(p
[i
] < '0' || p
[i
] > '9')
127 ERR
("should only be numbers here!\n");
130 ret
= (p
[i
] - '0') + ret
* 10;
135 static struct expr
*expr_complex
( struct parser
*parser
, struct expr
*l
, UINT op
, struct expr
*r
)
137 struct expr
*e
= alloc_mem
( parser
, sizeof
(*e
) );
140 e
->type
= EXPR_COMPLEX
;
148 static struct expr
*expr_unary
( struct parser
*parser
, struct expr
*l
, UINT op
)
150 struct expr
*e
= alloc_mem
( parser
, sizeof
(*e
) );
153 e
->type
= EXPR_UNARY
;
156 e
->u.expr.right
= NULL
;
161 static struct expr
*expr_ival
( struct parser
*parser
, int val
)
163 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
172 static struct expr
*expr_sval
( struct parser
*parser
, const struct string *str
)
174 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
178 e
->u.sval
= get_string
( parser
, str
);
180 return NULL
; /* e will be freed by query destructor */
185 static struct expr
*expr_bval
( struct parser
*parser
, int val
)
187 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
196 static struct expr
*expr_propval
( struct parser
*parser
, const struct property
*prop
)
198 struct expr
*e
= alloc_mem
( parser
, sizeof
*e
);
201 e
->type
= EXPR_PROPVAL
;
207 static int wql_error
( struct parser
*parser
, const char *str
);
208 static int wql_lex
( void *val
, struct parser
*parser
);
210 #define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \
211 *parser
->view
= current_view
; \
212 result
= current_view
216 %lex
-param
{ struct parser
*ctx
}
217 %parse
-param
{ struct parser
*ctx
}
218 %define parse.
error verbose
225 struct property
*proplist
;
226 struct keyword
*keywordlist
;
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
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
243 %left TK_OR TK_AND TK_NOT TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
256 $$
= get_path
( ctx
, &$1 );
265 $$
= alloc_keyword
( ctx
, $1, NULL
);
271 $$
= alloc_keyword
( ctx
, $1, $3 );
279 | keyword keywordlist
286 TK_ASSOCIATORS TK_OF path
289 struct parser
*parser
= ctx
;
292 hr
= create_view
( VIEW_TYPE_ASSOCIATORS
, $3, NULL
, NULL
, NULL
, NULL
, &view
);
296 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
298 | TK_ASSOCIATORS TK_OF path TK_WHERE keywordlist
301 struct parser
*parser
= ctx
;
304 hr
= create_view
( VIEW_TYPE_ASSOCIATORS
, $3, $5, NULL
, NULL
, NULL
, &view
);
308 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
316 struct parser
*parser
= ctx
;
319 hr
= create_view
( VIEW_TYPE_SELECT
, NULL
, NULL
, $3, NULL
, NULL
, &view
);
323 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
325 | TK_SELECT proplist TK_FROM id
328 struct parser
*parser
= ctx
;
331 hr
= create_view
( VIEW_TYPE_SELECT
, NULL
, NULL
, $4, $2, NULL
, &view
);
335 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
337 | TK_SELECT proplist TK_FROM id TK_WHERE expr
340 struct parser
*parser
= ctx
;
343 hr
= create_view
( VIEW_TYPE_SELECT
, NULL
, NULL
, $4, $2, $6, &view
);
347 PARSER_BUBBLE_UP_VIEW
( parser
, $$
, view
);
353 | prop TK_COMMA proplist
366 $$
= alloc_property
( ctx
, $1, $3 );
372 $$
= alloc_property
( ctx
, NULL
, $1 );
381 $$
= get_string
( ctx
, &$1 );
403 $$
= expr_complex
( ctx
, $1, OP_AND
, $3 );
409 $$
= expr_complex
( ctx
, $1, OP_OR
, $3 );
415 $$
= expr_unary
( ctx
, $2, OP_NOT
);
419 | prop_val TK_EQ const_val
421 $$
= expr_complex
( ctx
, $1, OP_EQ
, $3 );
425 | prop_val TK_GT const_val
427 $$
= expr_complex
( ctx
, $1, OP_GT
, $3 );
431 | prop_val TK_LT const_val
433 $$
= expr_complex
( ctx
, $1, OP_LT
, $3 );
437 | prop_val TK_LE const_val
439 $$
= expr_complex
( ctx
, $1, OP_LE
, $3 );
443 | prop_val TK_GE const_val
445 $$
= expr_complex
( ctx
, $1, OP_GE
, $3 );
449 | prop_val TK_NE const_val
451 $$
= expr_complex
( ctx
, $1, OP_NE
, $3 );
455 | const_val TK_EQ prop_val
457 $$
= expr_complex
( ctx
, $1, OP_EQ
, $3 );
461 | const_val TK_GT prop_val
463 $$
= expr_complex
( ctx
, $1, OP_GT
, $3 );
467 | const_val TK_LT prop_val
469 $$
= expr_complex
( ctx
, $1, OP_LT
, $3 );
473 | const_val TK_LE prop_val
475 $$
= expr_complex
( ctx
, $1, OP_LE
, $3 );
479 | const_val TK_GE prop_val
481 $$
= expr_complex
( ctx
, $1, OP_GE
, $3 );
485 | const_val TK_NE prop_val
487 $$
= expr_complex
( ctx
, $1, OP_NE
, $3 );
491 | prop_val TK_LIKE string_val
493 $$
= expr_complex
( ctx
, $1, OP_LIKE
, $3 );
497 | prop_val TK_IS TK_NULL
499 $$
= expr_unary
( ctx
, $1, OP_ISNULL
);
503 | prop_val TK_IS TK_NOT TK_NULL
505 $$
= expr_unary
( ctx
, $1, OP_NOTNULL
);
509 | prop_val TK_EQ TK_NULL
511 $$
= expr_unary
( ctx
, $1, OP_ISNULL
);
515 | TK_NULL TK_EQ prop_val
517 $$
= expr_unary
( ctx
, $3, OP_ISNULL
);
521 | prop_val TK_NE TK_NULL
523 $$
= expr_unary
( ctx
, $1, OP_NOTNULL
);
527 | TK_NULL TK_NE prop_val
529 $$
= expr_unary
( ctx
, $3, OP_NOTNULL
);
538 $$
= expr_sval
( ctx
, &$1 );
547 $$
= expr_propval
( ctx
, $1 );
556 $$
= expr_ival
( ctx
, $1 );
562 $$
= expr_sval
( ctx
, &$1 );
568 $$
= expr_bval
( ctx
, -1 );
574 $$
= expr_bval
( ctx
, 0 );
582 HRESULT parse_query
( const WCHAR
*str
, struct view
**view
, struct list
*mem
)
584 struct parser parser
;
592 parser.
error = WBEM_E_INVALID_QUERY
;
596 ret
= wql_parse
( &parser
);
597 TRACE
("wql_parse returned %d\n", ret
);
602 destroy_view
( *parser.view
);
610 static const char id_char
[] =
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,
637 #define MIN_TOKEN_LEN 2
638 #define MAX_TOKEN_LEN 11
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'};
655 static const struct wql_keyword keyword_table
[] =
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
}
673 static int __cdecl cmp_keyword
( const void *arg1
, const void *arg2
)
675 const struct wql_keyword
*key1
= arg1
, *key2
= arg2
;
676 int len
= min
( key1
->len
, key2
->len
);
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;
685 static int keyword_type
( const WCHAR
*str
, unsigned int len
)
687 struct wql_keyword key
, *ret
;
689 if
(len
< MIN_TOKEN_LEN || len
> MAX_TOKEN_LEN
) return TK_ID
;
694 ret
= bsearch
( &key
, keyword_table
, ARRAY_SIZE
(keyword_table
), sizeof
(struct wql_keyword
), cmp_keyword
);
695 if
(ret
) return ret
->type
;
699 static int get_token
( const WCHAR
*s
, int *token
)
709 for
(i
= 1; iswspace
( s
[i
] ); i
++) {}
713 if
(!s
[1]) return
-1;
723 for
(i
= 1; s
[i
] && s
[i
] != '}'; i
++) {}
743 else if
(s
[1] == '>')
780 for
(i
= 1; s
[i
]; i
++)
782 if
(s
[i
] == s
[0]) break
;
788 if
(!iswdigit
( s
[1] ))
794 case
'0': case
'1': case
'2': case
'3': case
'4':
795 case
'5': case
'6': case
'7': case
'8': case
'9':
797 for
(i
= 1; iswdigit
( s
[i
] ); i
++) {}
800 if
(!id_char
[*s
]) break
;
802 for
(i
= 1; id_char
[s
[i
]]; i
++) {}
803 *token
= keyword_type
( s
, i
);
810 static int wql_lex
( void *p
, struct parser
*parser
)
812 struct string *str
= p
;
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
;
821 str
->data
= &parser
->cmd
[parser
->idx
];
822 str
->len
= parser
->len
;
823 } while
(token
== TK_SPACE
);
827 static int wql_error
( struct parser
*parser
, const char *str
)