diff --git a/.gitignore b/.gitignore index c70b20a5f02..6c333a57cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -135,6 +135,8 @@ dlls/vbscript/parser.tab.c dlls/vbscript/parser.tab.h dlls/vbscript/vbscript_classes.h dlls/vbscript/vbsglobal.h +dlls/wbemprox/wql.tab.c +dlls/wbemprox/wql.tab.h dlls/windowscodecs/windowscodecs_wincodec.h dlls/windowscodecs/windowscodecs_wincodec_p.c dlls/wshom.ocx/tests/wshom.h diff --git a/dlls/wbemprox/Makefile.in b/dlls/wbemprox/Makefile.in index 69274379ec9..8c6c31393bf 100644 --- a/dlls/wbemprox/Makefile.in +++ b/dlls/wbemprox/Makefile.in @@ -4,9 +4,12 @@ IMPORTS = ole32 advapi32 C_SRCS = \ class.c \ main.c \ + query.c \ services.c \ wbemlocator.c IDL_R_SRCS = wbemprox.idl +BISON_SRCS = wql.y + @MAKE_DLL_RULES@ diff --git a/dlls/wbemprox/class.c b/dlls/wbemprox/class.c index e696d0369a2..d40520653bd 100644 --- a/dlls/wbemprox/class.c +++ b/dlls/wbemprox/class.c @@ -35,6 +35,7 @@ struct enum_class_object { IEnumWbemClassObject IEnumWbemClassObject_iface; LONG refs; + struct query *query; }; static inline struct enum_class_object *impl_from_IEnumWbemClassObject( @@ -58,6 +59,7 @@ static ULONG WINAPI enum_class_object_Release( if (!refs) { TRACE("destroying %p\n", ec); + free_query( ec->query ); heap_free( ec ); } return refs; @@ -143,7 +145,7 @@ static const IEnumWbemClassObjectVtbl enum_class_object_vtbl = }; HRESULT EnumWbemClassObject_create( - IUnknown *pUnkOuter, LPVOID *ppObj ) + IUnknown *pUnkOuter, struct query *query, LPVOID *ppObj ) { struct enum_class_object *ec; @@ -154,6 +156,7 @@ HRESULT EnumWbemClassObject_create( ec->IEnumWbemClassObject_iface.lpVtbl = &enum_class_object_vtbl; ec->refs = 1; + ec->query = query; *ppObj = &ec->IEnumWbemClassObject_iface; diff --git a/dlls/wbemprox/query.c b/dlls/wbemprox/query.c new file mode 100644 index 00000000000..d40d7f102b3 --- /dev/null +++ b/dlls/wbemprox/query.c @@ -0,0 +1,87 @@ +/* + * Copyright 2012 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "config.h" +#include + +#include "windef.h" +#include "winbase.h" +#include "wbemcli.h" + +#include "wine/debug.h" +#include "wbemprox_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wbemprox); + +HRESULT create_view( const struct property *proplist, const WCHAR *class, + const struct expr *cond, struct view **ret ) +{ + struct view *view = heap_alloc( sizeof(struct view) ); + + if (!view) return E_OUTOFMEMORY; + view->proplist = proplist; + view->cond = cond; + *ret = view; + return S_OK; +} + +void destroy_view( struct view *view ) +{ + heap_free( view ); +} + +static struct query *alloc_query(void) +{ + struct query *query; + + if (!(query = heap_alloc( sizeof(*query) ))) return NULL; + list_init( &query->mem ); + return query; +} + +void free_query( struct query *query ) +{ + struct list *mem, *next; + + destroy_view( query->view ); + LIST_FOR_EACH_SAFE( mem, next, &query->mem ) + { + heap_free( mem ); + } + heap_free( query ); +} + +HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result ) +{ + HRESULT hr; + struct query *query; + + *result = NULL; + if (!(query = alloc_query())) return E_OUTOFMEMORY; + hr = parse_query( str, &query->view, &query->mem ); + if (hr != S_OK) + { + free_query( query ); + return hr; + } + hr = EnumWbemClassObject_create( NULL, query, (void **)result ); + if (hr != S_OK) free_query( query ); + return hr; +} diff --git a/dlls/wbemprox/services.c b/dlls/wbemprox/services.c index cc88790f912..c2aaa3aaa51 100644 --- a/dlls/wbemprox/services.c +++ b/dlls/wbemprox/services.c @@ -158,7 +158,7 @@ static ULONG WINAPI wbem_services_Release( if (!refs) { TRACE("destroying %p\n", ws); - HeapFree( GetProcessHeap(), 0, ws ); + heap_free( ws ); } return refs; } @@ -383,9 +383,14 @@ static HRESULT WINAPI wbem_services_ExecQuery( IWbemContext *pCtx, IEnumWbemClassObject **ppEnum ) { - FIXME("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), + static const WCHAR wqlW[] = {'W','Q','L',0}; + + TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery), lFlags, pCtx, ppEnum); - return WBEM_E_FAILED; + + if (!strQueryLanguage || !strQuery) return WBEM_E_INVALID_PARAMETER; + if (strcmpiW( strQueryLanguage, wqlW )) return WBEM_E_INVALID_QUERY_TYPE; + return exec_query( strQuery, ppEnum ); } static HRESULT WINAPI wbem_services_ExecQueryAsync( @@ -487,7 +492,7 @@ HRESULT WbemServices_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - ws = HeapAlloc( GetProcessHeap(), 0, sizeof(*ws) ); + ws = heap_alloc( sizeof(*ws) ); if (!ws) return E_OUTOFMEMORY; ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl; diff --git a/dlls/wbemprox/wbemprox_private.h b/dlls/wbemprox/wbemprox_private.h index 86d2f3c1b0e..7e129f0624c 100644 --- a/dlls/wbemprox/wbemprox_private.h +++ b/dlls/wbemprox/wbemprox_private.h @@ -16,8 +16,84 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "wine/list.h" + +#define SIZEOF(array) (sizeof(array)/sizeof((array)[0])) + +struct property +{ + const WCHAR *name; + const WCHAR *class; + const struct property *next; +}; + +enum operator +{ + OP_EQ = 1, + OP_AND = 2, + OP_OR = 3, + OP_GT = 4, + OP_LT = 5, + OP_LE = 6, + OP_GE = 7, + OP_NE = 8, + OP_ISNULL = 9, + OP_NOTNULL = 10, + OP_LIKE = 11 +}; + +struct expr; +struct complex_expr +{ + enum operator op; + struct expr *left; + struct expr *right; +}; + +enum expr_type +{ + EXPR_COMPLEX = 1, + EXPR_UNARY = 2, + EXPR_PROPVAL = 3, + EXPR_SVAL = 4, + EXPR_IVAL = 5, + EXPR_BVAL = 6 +}; + +struct expr +{ + enum expr_type type; + union + { + struct complex_expr expr; + const struct property *propval; + const WCHAR *sval; + int ival; + } u; +}; + +struct view +{ + const struct property *proplist; + const struct expr *cond; +}; + +struct query +{ + struct view *view; + struct list mem; +}; + +void free_query( struct query * ) DECLSPEC_HIDDEN; +HRESULT exec_query( const WCHAR *, IEnumWbemClassObject ** ) DECLSPEC_HIDDEN; +HRESULT parse_query( const WCHAR *, struct view **, struct list * ) DECLSPEC_HIDDEN; +HRESULT create_view( const struct property *, const WCHAR *, const struct expr *, + struct view ** ) DECLSPEC_HIDDEN; +void destroy_view( struct view * ) DECLSPEC_HIDDEN; + HRESULT WbemLocator_create(IUnknown *, LPVOID *) DECLSPEC_HIDDEN; HRESULT WbemServices_create(IUnknown *, LPVOID *) DECLSPEC_HIDDEN; +HRESULT EnumWbemClassObject_create(IUnknown *, struct query *, LPVOID *) DECLSPEC_HIDDEN; static void *heap_alloc( size_t len ) __WINE_ALLOC_SIZE(1); static inline void *heap_alloc( size_t len ) diff --git a/dlls/wbemprox/wql.y b/dlls/wbemprox/wql.y new file mode 100644 index 00000000000..8e347c22e5b --- /dev/null +++ b/dlls/wbemprox/wql.y @@ -0,0 +1,698 @@ +%{ + +/* + * Copyright 2012 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include + +#include "windef.h" +#include "winbase.h" +#include "wbemcli.h" +#include "wbemprox_private.h" + +#include "wine/list.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define YYLEX_PARAM ctx +#define YYPARSE_PARAM ctx +#define YYERROR_DEBUG 1 +#define YYERROR_VERBOSE 1 + +WINE_DEFAULT_DEBUG_CHANNEL(wbemprox); + +struct parser +{ + const WCHAR *cmd; + UINT idx; + UINT len; + HRESULT error; + struct view **view; + struct list *mem; +}; + +struct string +{ + const WCHAR *data; + int len; +}; + +static void *alloc_mem( struct parser *parser, UINT size ) +{ + struct list *mem = heap_alloc( sizeof(struct list) + size ); + list_add_tail( parser->mem, mem ); + return &mem[1]; +} + +static struct property *alloc_property( struct parser *parser, const WCHAR *class, const WCHAR *name ) +{ + struct property *prop = alloc_mem( parser, sizeof(*prop) ); + if (prop) + { + prop->name = name; + prop->class = class; + prop->next = NULL; + } + return prop; +} + +static WCHAR *get_string( struct parser *parser, const struct string *str ) +{ + const WCHAR *p = str->data; + int len = str->len; + WCHAR *ret; + + if ((p[0] == '\"' && p[len - 1] != '\"') || + (p[0] == '\'' && p[len - 1] != '\'')) return NULL; + if ((p[0] == '\"' && p[len - 1] == '\"') || + (p[0] == '\'' && p[len - 1] == '\'')) + { + p++; + len -= 2; + } + if (!(ret = alloc_mem( parser, (len + 1) * sizeof(WCHAR) ))) return NULL; + memcpy( ret, p, len * sizeof(WCHAR) ); + ret[len] = 0; + return ret; +} + +static int get_int( struct parser *parser ) +{ + const WCHAR *p = &parser->cmd[parser->idx]; + int i, ret = 0; + + for (i = 0; i < parser->len; i++) + { + if (p[i] < '0' || p[i] > '9') + { + ERR("should only be numbers here!\n"); + break; + } + ret = (p[i] - '0') + ret * 10; + } + return ret; +} + +static struct expr *expr_complex( struct parser *parser, struct expr *l, UINT op, struct expr *r ) +{ + struct expr *e = alloc_mem( parser, sizeof(*e) ); + if (e) + { + e->type = EXPR_COMPLEX; + e->u.expr.left = l; + e->u.expr.op = op; + e->u.expr.right = r; + } + return e; +} + +static struct expr *expr_unary( struct parser *parser, struct expr *l, UINT op ) +{ + struct expr *e = alloc_mem( parser, sizeof(*e) ); + if (e) + { + e->type = EXPR_UNARY; + e->u.expr.left = l; + e->u.expr.op = op; + e->u.expr.right = NULL; + } + return e; +} + +static struct expr *expr_ival( struct parser *parser, int val ) +{ + struct expr *e = alloc_mem( parser, sizeof *e ); + if (e) + { + e->type = EXPR_IVAL; + e->u.ival = val; + } + return e; +} + +static struct expr *expr_sval( struct parser *parser, const struct string *str ) +{ + struct expr *e = alloc_mem( parser, sizeof *e ); + if (e) + { + e->type = EXPR_SVAL; + e->u.sval = get_string( parser, str ); + if (!e->u.sval) + return NULL; /* e will be freed by query destructor */ + } + return e; +} + +static struct expr *expr_bval( struct parser *parser, int val ) +{ + struct expr *e = alloc_mem( parser, sizeof *e ); + if (e) + { + e->type = EXPR_BVAL; + e->u.ival = val; + } + return e; +} + +static struct expr *expr_propval( struct parser *parser, const struct property *prop ) +{ + struct expr *e = alloc_mem( parser, sizeof *e ); + if (e) + { + e->type = EXPR_PROPVAL; + e->u.propval = prop; + } + return e; +} + +static int wql_error( const char *str ); +static int wql_lex( void *val, struct parser *parser ); + +#define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \ + *parser->view = current_view; \ + result = current_view + +%} + +%pure-parser + +%union +{ + struct string str; + WCHAR *string; + struct property *proplist; + struct view *view; + struct expr *expr; + int integer; +} + +%token TK_SELECT TK_FROM TK_STAR TK_COMMA TK_DOT TK_IS TK_LP TK_RP TK_NULL TK_FALSE TK_TRUE +%token TK_INTEGER TK_WHERE TK_SPACE TK_MINUS TK_ILLEGAL TK_BY +%token TK_STRING TK_ID + +%type id +%type prop proplist +%type select +%type expr prop_val const_val string_val +%type number + +%left TK_OR +%left TK_AND +%left TK_NOT +%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE + +%% + +select: + TK_SELECT TK_FROM id + { + HRESULT hr; + struct parser *parser = ctx; + struct view *view; + + hr = create_view( NULL, $3, NULL, &view ); + if (hr != S_OK) + YYABORT; + + PARSER_BUBBLE_UP_VIEW( parser, $$, view ); + } + | TK_SELECT proplist TK_FROM id + { + HRESULT hr; + struct parser *parser = ctx; + struct view *view; + + hr = create_view( $2, $4, NULL, &view ); + if (hr != S_OK) + YYABORT; + + PARSER_BUBBLE_UP_VIEW( parser, $$, view ); + } + | TK_SELECT proplist TK_FROM id TK_WHERE expr + { + HRESULT hr; + struct parser *parser = ctx; + struct view *view; + + hr = create_view( $2, $4, $6, &view ); + if (hr != S_OK) + YYABORT; + + PARSER_BUBBLE_UP_VIEW( parser, $$, view ); + } + ; + +proplist: + prop + | prop TK_COMMA proplist + { + $1->next = $3; + } + | TK_STAR + { + $$ = NULL; + } + ; + +prop: + id TK_DOT id + { + $$ = alloc_property( ctx, $1, $3 ); + if (!$$) + YYABORT; + } + | id + { + $$ = alloc_property( ctx, NULL, $1 ); + if (!$$) + YYABORT; + } + ; + +id: + TK_ID + { + $$ = get_string( ctx, &$1 ); + if (!$$) + YYABORT; + } + ; + +number: + TK_INTEGER + { + $$ = get_int( ctx ); + } + ; + +expr: + TK_LP expr TK_RP + { + $$ = $2; + if (!$$) + YYABORT; + } + | expr TK_AND expr + { + $$ = expr_complex( ctx, $1, OP_AND, $3 ); + if (!$$) + YYABORT; + } + | expr TK_OR expr + { + $$ = expr_complex( ctx, $1, OP_OR, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_EQ const_val + { + $$ = expr_complex( ctx, $1, OP_EQ, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_GT const_val + { + $$ = expr_complex( ctx, $1, OP_GT, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_LT const_val + { + $$ = expr_complex( ctx, $1, OP_LT, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_LE const_val + { + $$ = expr_complex( ctx, $1, OP_LE, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_GE const_val + { + $$ = expr_complex( ctx, $1, OP_GE, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_NE const_val + { + $$ = expr_complex( ctx, $1, OP_NE, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_EQ prop_val + { + $$ = expr_complex( ctx, $1, OP_EQ, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_GT prop_val + { + $$ = expr_complex( ctx, $1, OP_GT, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_LT prop_val + { + $$ = expr_complex( ctx, $1, OP_LT, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_LE prop_val + { + $$ = expr_complex( ctx, $1, OP_LE, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_GE prop_val + { + $$ = expr_complex( ctx, $1, OP_GE, $3 ); + if (!$$) + YYABORT; + } + | const_val TK_NE prop_val + { + $$ = expr_complex( ctx, $1, OP_NE, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_LIKE string_val + { + $$ = expr_complex( ctx, $1, OP_LIKE, $3 ); + if (!$$) + YYABORT; + } + | prop_val TK_IS TK_NULL + { + $$ = expr_unary( ctx, $1, OP_ISNULL ); + if (!$$) + YYABORT; + } + | prop_val TK_IS TK_NOT TK_NULL + { + $$ = expr_unary( ctx, $1, OP_NOTNULL ); + if (!$$) + YYABORT; + } + ; + +string_val: + TK_STRING + { + $$ = expr_sval( ctx, &$1 ); + if (!$$) + YYABORT; + } + ; + +prop_val: + prop + { + $$ = expr_propval( ctx, $1 ); + if (!$$) + YYABORT; + } + ; + +const_val: + number + { + $$ = expr_ival( ctx, $1 ); + if (!$$) + YYABORT; + } + | TK_STRING + { + $$ = expr_sval( ctx, &$1 ); + if (!$$) + YYABORT; + } + | TK_TRUE + { + $$ = expr_bval( ctx, -1 ); + if (!$$) + YYABORT; + } + | TK_FALSE + { + $$ = expr_bval( ctx, 0 ); + if (!$$) + YYABORT; + } + ; + +%% + +HRESULT parse_query( const WCHAR *str, struct view **view, struct list *mem ) +{ + struct parser parser; + int ret; + + *view = NULL; + + parser.cmd = str; + parser.idx = 0; + parser.len = 0; + parser.error = WBEM_E_INVALID_QUERY; + parser.view = view; + parser.mem = mem; + + ret = wql_parse( &parser ); + TRACE("wql_parse returned %d\n", ret); + if (ret) + { + if (*parser.view) + { + destroy_view( *parser.view ); + *parser.view = NULL; + } + return parser.error; + } + return S_OK; +} + +static const char id_char[] = +{ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +struct keyword +{ + const WCHAR *name; + unsigned int len; + int type; +}; + +#define MAX_TOKEN_LEN 6 + +static const WCHAR andW[] = {'A','N','D'}; +static const WCHAR byW[] = {'B','Y'}; +static const WCHAR falseW[] = {'F','A','L','S','E'}; +static const WCHAR fromW[] = {'F','R','O','M'}; +static const WCHAR isW[] = {'I','S'}; +static const WCHAR likeW[] = {'L','I','K','E'}; +static const WCHAR notW[] = {'N','O','T'}; +static const WCHAR nullW[] = {'N','U','L','L'}; +static const WCHAR orW[] = {'O','R'}; +static const WCHAR selectW[] = {'S','E','L','E','C','T'}; +static const WCHAR trueW[] = {'T','R','U','E'}; +static const WCHAR whereW[] = {'W','H','E','R','E'}; + +static const struct keyword keyword_table[] = +{ + { andW, SIZEOF(andW), TK_AND }, + { byW, SIZEOF(byW), TK_BY }, + { falseW, SIZEOF(falseW), TK_FALSE }, + { fromW, SIZEOF(fromW), TK_FROM }, + { isW, SIZEOF(isW), TK_IS }, + { likeW, SIZEOF(likeW), TK_LIKE }, + { notW, SIZEOF(notW), TK_NOT }, + { nullW, SIZEOF(nullW), TK_NULL }, + { orW, SIZEOF(orW), TK_OR }, + { selectW, SIZEOF(selectW), TK_SELECT }, + { trueW, SIZEOF(trueW), TK_TRUE }, + { whereW, SIZEOF(whereW), TK_WHERE } +}; + +static int cmp_keyword( const void *arg1, const void *arg2 ) +{ + const struct keyword *key1 = arg1, *key2 = arg2; + int len = min( key1->len, key2->len ); + int ret; + + if ((ret = memicmpW( key1->name, key2->name, len ))) return ret; + if (key1->len < key2->len) return -1; + else if (key1->len > key2->len) return 1; + return 0; +} + +static int keyword_type( const WCHAR *str, unsigned int len ) +{ + struct keyword key, *ret; + + if (len > MAX_TOKEN_LEN) return TK_ID; + + key.name = str; + key.len = len; + key.type = 0; + ret = bsearch( &key, keyword_table, SIZEOF(keyword_table), sizeof(struct keyword), cmp_keyword ); + if (ret) return ret->type; + return TK_ID; +} + +static int get_token( const WCHAR *s, int *token ) +{ + int i; + + switch (*s) + { + case ' ': + case '\t': + case '\n': + for (i = 1; isspaceW( s[i] ); i++) {} + *token = TK_SPACE; + return i; + case '-': + if (!s[1]) return -1; + *token = TK_MINUS; + return 1; + case '(': + *token = TK_LP; + return 1; + case ')': + *token = TK_RP; + return 1; + case '*': + *token = TK_STAR; + return 1; + case '=': + *token = TK_EQ; + return 1; + case '<': + if (s[1] == '=' ) + { + *token = TK_LE; + return 2; + } + else if (s[1] == '>') + { + *token = TK_NE; + return 2; + } + else + { + *token = TK_LT; + return 1; + } + case '>': + if (s[1] == '=') + { + *token = TK_GE; + return 2; + } + else + { + *token = TK_GT; + return 1; + } + case '!': + if (s[1] != '=') + { + *token = TK_ILLEGAL; + return 2; + } + else + { + *token = TK_NE; + return 2; + } + case ',': + *token = TK_COMMA; + return 1; + case '\"': + case '\'': + { + for (i = 1; s[i]; i++) + { + if (s[i] == s[0]) break; + } + if (s[i]) i++; + *token = TK_STRING; + return i; + } + case '.': + if (!isdigitW( s[1] )) + { + *token = TK_DOT; + return 1; + } + /* fall through */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *token = TK_INTEGER; + for (i = 1; isdigitW( s[i] ); i++) {} + return i; + default: + if (!id_char[*s]) break; + + for (i = 1; id_char[s[i]]; i++) {} + *token = keyword_type( s, i ); + return i; + } + *token = TK_ILLEGAL; + return 1; +} + +static int wql_lex( void *p, struct parser *parser ) +{ + struct string *str = p; + int token = -1; + do + { + parser->idx += parser->len; + if (!parser->cmd[parser->idx]) return 0; + parser->len = get_token( &parser->cmd[parser->idx], &token ); + if (!parser->len) break; + + str->data = &parser->cmd[parser->idx]; + str->len = parser->len; + } while (token == TK_SPACE); + return token; +} + +static int wql_error( const char *str ) +{ + ERR("%s\n", str); + return 0; +}