[1/4] wbemprox: Add support for parsing WQL queries.

Hans Leidekker hans at codeweavers.com
Fri Jun 15 08:46:51 CDT 2012


---
 dlls/wbemprox/Makefile.in        |    3 +
 dlls/wbemprox/class.c            |    5 +-
 dlls/wbemprox/query.c            |   87 +++++
 dlls/wbemprox/services.c         |   13 +-
 dlls/wbemprox/wbemprox_private.h |   76 +++++
 dlls/wbemprox/wql.y              |  698 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 877 insertions(+), 5 deletions(-)
 create mode 100644 dlls/wbemprox/query.c
 create mode 100644 dlls/wbemprox/wql.y

diff --git a/dlls/wbemprox/Makefile.in b/dlls/wbemprox/Makefile.in
index 6927437..8c6c313 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 e696d03..d405206 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 0000000..d40d7f1
--- /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 <stdarg.h>
+
+#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 cc88790..c2aaa3a 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 86d2f3c..7e129f0 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 0000000..8e347c2
--- /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 <stdarg.h>
+
+#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 <str> TK_STRING TK_ID
+
+%type <string> id
+%type <proplist> prop proplist
+%type <view> select
+%type <expr> expr prop_val const_val string_val
+%type <integer> 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;
+}
-- 
1.7.10







More information about the wine-patches mailing list