version 1.2, 2015/04/20 18:10:35
|
version 1.3, 2015/04/20 18:20:37
|
|
|
*/ | */ |
| |
#include "wql.h" | #include "wql.h" |
|
#include <ctype.h> |
| |
#ifndef _MSC_VER | #ifndef _MSC_VER |
#include <pthread.h> | #include <pthread.h> |
|
|
#include <stdlib.h> | #include <stdlib.h> |
#include <stdio.h> | #include <stdio.h> |
#include <string.h> | #include <string.h> |
#include <base/strings.h> |
#include <pal/strings.h> |
#include <base/classdecl.h> | #include <base/classdecl.h> |
#include <base/helpers.h> | #include <base/helpers.h> |
#include <base/io.h> |
#include <pal/format.h> |
#include "wqlyacc.h" | #include "wqlyacc.h" |
#include "state.h" | #include "state.h" |
|
#include "like.h" |
| |
extern int wqlparse(); | extern int wqlparse(); |
|
extern void WQL_ResetParser(); |
| |
WQL_State wqlstate; | WQL_State wqlstate; |
| |
#ifndef _MSC_VER |
#ifdef _MSC_VER |
|
/* TODO: Fix this otherwise we are not thread safe */ |
|
static void _Lock() { } |
|
static void _Unlock() { } |
|
#else |
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; | static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; |
static void _Lock() { pthread_mutex_lock(&_mutex); } | static void _Lock() { pthread_mutex_lock(&_mutex); } |
static void _Unlock() { pthread_mutex_unlock(&_mutex); } | static void _Unlock() { pthread_mutex_unlock(&_mutex); } |
|
|
return Batch_Get(wqlstate.wql->batch, size); | return Batch_Get(wqlstate.wql->batch, size); |
} | } |
| |
MI_Char* wqlstrdup(const MI_Char * str) |
ZChar* wqlstrdup(const ZChar * str) |
{ | { |
return Batch_Zdup(wqlstate.wql->batch, str); |
return Batch_Tcsdup(wqlstate.wql->batch, str); |
} | } |
| |
WQL* WQL_Parse(const MI_Char* text, Batch* batch) |
WQL* WQL_Parse( |
|
const ZChar* text, |
|
Batch* batch, |
|
WQL_Dialect dialect) |
{ | { |
WQL* self = NULL; | WQL* self = NULL; |
int deleteBatch; | int deleteBatch; |
|
|
/* Create batch if none */ | /* Create batch if none */ |
if (!batch) | if (!batch) |
{ | { |
batch = Batch_New(64); |
batch = Batch_New(BATCH_MAX_PAGES); |
| |
if (!batch) | if (!batch) |
{ | { |
|
|
} | } |
} | } |
| |
|
/* Set the dialect */ |
|
self->dialect = dialect; |
|
|
/* Initialize WQL object */ | /* Initialize WQL object */ |
self->batch = batch; | self->batch = batch; |
self->deleteBatch = deleteBatch; | self->deleteBatch = deleteBatch; |
self->text = Batch_Zdup(batch, text); |
self->text = Batch_Tcsdup(batch, text); |
|
|
|
if (!self->text) |
|
{ |
|
if (deleteBatch) |
|
Batch_Delete(batch); |
|
|
|
_Unlock(); |
|
return NULL; |
|
} |
| |
/* Initialize global parser state */ | /* Initialize global parser state */ |
memset(&wqlstate, 0, sizeof(WQL_State)); | memset(&wqlstate, 0, sizeof(WQL_State)); |
wqlstate.text = self->text; | wqlstate.text = self->text; |
wqlstate.size = (int)Zlen(text); |
wqlstate.size = (int)Tcslen(text); |
wqlstate.wql = self; | wqlstate.wql = self; |
wqlstate.ptr = text; | wqlstate.ptr = text; |
| |
/* Parse the text */ | /* Parse the text */ |
wqlparse(); | wqlparse(); |
| |
|
/* Reset global parser states */ |
|
WQL_ResetParser(); |
|
|
/* Get return status */ | /* Get return status */ |
if (wqlstate.status != 0) | if (wqlstate.status != 0) |
{ | { |
|
|
/* Create batch if none */ | /* Create batch if none */ |
if (!batch) | if (!batch) |
{ | { |
batch = Batch_New(64); |
batch = Batch_New(BATCH_MAX_PAGES); |
| |
if (!batch) | if (!batch) |
return NULL; | return NULL; |
|
|
{ | { |
for (i = 0; i < self->nproperties; i++) | for (i = 0; i < self->nproperties; i++) |
{ | { |
result->properties[i] = Batch_Zdup(batch, self->properties[i]); |
result->properties[i] = Batch_Tcsdup(batch, self->properties[i]); |
| |
if (!result->properties[i]) | if (!result->properties[i]) |
goto failed; | goto failed; |
|
|
/* Clone classname */ | /* Clone classname */ |
if (self->className) | if (self->className) |
{ | { |
result->className = Batch_Zdup(batch, self->className); |
result->className = Batch_Tcsdup(batch, self->className); |
| |
if (!result->className) | if (!result->className) |
goto failed; | goto failed; |
|
|
if (self->symbols[i].value.string) | if (self->symbols[i].value.string) |
{ | { |
result->symbols[i].value.string = | result->symbols[i].value.string = |
Batch_Zdup(batch, self->symbols[i].value.string); |
Batch_Tcsdup(batch, self->symbols[i].value.string); |
| |
if (!result->symbols[i].value.string) | if (!result->symbols[i].value.string) |
goto failed; | goto failed; |
|
|
/* Clone text */ | /* Clone text */ |
if (self->text) | if (self->text) |
{ | { |
result->text = Batch_Zdup(batch, self->text); |
result->text = Batch_Tcsdup(batch, self->text); |
| |
if (!result->text) | if (!result->text) |
goto failed; | goto failed; |
|
|
| |
MI_Boolean WQL_ContainsProperty( | MI_Boolean WQL_ContainsProperty( |
const WQL* wql, | const WQL* wql, |
const MI_Char* propertyName) |
const ZChar* propertyName) |
{ | { |
size_t i; | size_t i; |
| |
|
|
| |
for (i = 0; i < wql->nproperties; i++) | for (i = 0; i < wql->nproperties; i++) |
{ | { |
if (Zcasecmp(propertyName, wql->properties[i]) == 0) |
if (Tcscmp(propertyName, wql->properties[i]) == 0) |
return MI_TRUE; | return MI_TRUE; |
} | } |
| |
|
|
} | } |
| |
int _ValidateLookup( | int _ValidateLookup( |
const MI_Char* name, |
const ZChar* name, |
|
const ZChar* embeddedClassName, |
|
const ZChar* embeddedPropertyName, |
WQL_Symbol* symbol, | WQL_Symbol* symbol, |
Batch* batch, | Batch* batch, |
void* data) | void* data) |
|
|
const MI_ClassDecl* cd = (const MI_ClassDecl*)data; | const MI_ClassDecl* cd = (const MI_ClassDecl*)data; |
const MI_PropertyDecl* pd; | const MI_PropertyDecl* pd; |
| |
|
#if 0 |
|
printf("_ValidateLookup(): {%s}{%s}{%s}\n", |
|
name, embeddedClassName, embeddedPropertyName); |
|
#endif |
|
|
MI_UNUSED(batch); | MI_UNUSED(batch); |
| |
/* Check for null parameters */ | /* Check for null parameters */ |
if (!name || !symbol || !data) | if (!name || !symbol || !data) |
return -1; | return -1; |
| |
|
/* Handle ISA operation */ |
|
if (name && embeddedClassName && !embeddedPropertyName) |
|
{ |
|
symbol->type = WQL_TYPE_BOOLEAN; |
|
symbol->value.boolean = MI_TRUE; |
|
return 0; |
|
} |
|
|
/* Lookup the property with this name */ | /* Lookup the property with this name */ |
{ | { |
pd = ClassDecl_FindPropertyDecl(cd, name); | pd = ClassDecl_FindPropertyDecl(cd, name); |
|
|
symbol->type = WQL_TYPE_STRING; | symbol->type = WQL_TYPE_STRING; |
symbol->value.string = MI_T(""); | symbol->value.string = MI_T(""); |
return 0; | return 0; |
|
case MI_INSTANCE: |
|
/* Use WQL_TYPE_ANY since the type of the embedded instance property |
|
* cannot be deterined. |
|
*/ |
|
symbol->type = WQL_TYPE_ANY; |
|
return 0; |
default: | default: |
break; | break; |
} | } |
|
|
* property-literal mismatches. | * property-literal mismatches. |
*/ | */ |
if (WQL_Eval(self, _ValidateLookup, (void*)cd) == -1) | if (WQL_Eval(self, _ValidateLookup, (void*)cd) == -1) |
|
{ |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int _FixupTypeAux(WQL_Symbol* sym, WQL_Type type) |
|
{ |
|
if (sym->type != WQL_TYPE_STRING) |
|
return -1; |
|
|
|
if (type == WQL_TYPE_REAL) |
|
{ |
|
ZChar* end = NULL; |
|
sym->value.real = Tcstod(sym->value.string, &end); |
|
|
|
if (end == sym->value.string) |
|
return -1; |
|
|
|
if (*end != '\0') |
|
return -1; |
|
|
|
sym->type = WQL_TYPE_REAL; |
|
return 0; |
|
} |
|
else if (type == WQL_TYPE_INTEGER) |
|
{ |
|
ZChar* end = NULL; |
|
sym->value.integer = Tcstoll(sym->value.string, &end, 10); |
|
|
|
if (end == sym->value.string) |
|
return -1; |
|
|
|
if (*end != '\0') |
|
return -1; |
|
|
|
sym->type = WQL_TYPE_INTEGER; |
|
return 0; |
|
} |
|
else if (type == WQL_TYPE_BOOLEAN) |
|
{ |
|
if (Tcscasecmp(sym->value.string, PAL_T("true")) == 0) |
|
sym->value.boolean = 1; |
|
else if (Tcscasecmp(sym->value.string, PAL_T("false")) == 0) |
|
sym->value.boolean = 0; |
|
else |
return -1; | return -1; |
| |
|
sym->type = WQL_TYPE_BOOLEAN; |
return 0; | return 0; |
} | } |
| |
|
return -1; |
|
} |
|
|
|
/* |
|
* If the types of the two symbols are incompatible, then if either symbol |
|
* is a string, attempt to convert it to the type of the other symbol. For |
|
* example, the string will be converted to a real, integer, or boolean. |
|
*/ |
|
static int _FixupType(WQL_Symbol* lhs, WQL_Symbol* rhs) |
|
{ |
|
if (lhs->type == rhs->type) |
|
return 0; |
|
|
|
if (lhs->type == WQL_TYPE_STRING) |
|
{ |
|
return _FixupTypeAux(lhs, rhs->type); |
|
} |
|
else if (rhs->type == WQL_TYPE_STRING) |
|
{ |
|
return _FixupTypeAux(rhs, lhs->type); |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
/* |
|
**----------------------------------------------------------------------------- |
|
** @brief See if a string matches a template string |
|
** |
|
** @param [in] s1 - one string |
|
** @param [in] s1 - another string |
|
** |
|
** @returns 0 for a match, > 0 for s1 > s2; < 0 for s1 < s2 |
|
**----------------------------------------------------------------------------- |
|
*/ |
|
|
static int _Compare(const WQL_Symbol* s1, const WQL_Symbol* s2) | static int _Compare(const WQL_Symbol* s1, const WQL_Symbol* s2) |
{ | { |
switch (s1->type) | switch (s1->type) |
|
|
} | } |
case WQL_TYPE_STRING: | case WQL_TYPE_STRING: |
{ | { |
return Zcmp(s1->value.string, s2->value.string); |
return Tcscasecmp(s1->value.string, s2->value.string); |
} | } |
default: | default: |
return -1; | return -1; |
} | } |
} | } |
| |
|
static int _CompareLike(const WQL_Symbol* s1, const WQL_Symbol* s2) |
|
{ |
|
const ZChar* pattern; |
|
const ZChar* string; |
|
|
|
if (s1->type != WQL_TYPE_STRING || s2->type != WQL_TYPE_STRING) |
|
return -1; |
|
|
|
string = s1->value.string; |
|
pattern = s2->value.string; |
|
|
|
if (WQL_MatchLike(pattern, string, '\0')) |
|
return 0; |
|
else |
|
return -1; |
|
} |
|
|
extern int WQL_Eval( | extern int WQL_Eval( |
const WQL* wql, | const WQL* wql, |
WQL_Lookup lookup, | WQL_Lookup lookup, |
|
|
const WQL_Symbol* sym = &wql->symbols[i]; | const WQL_Symbol* sym = &wql->symbols[i]; |
WQL_Type type = sym->type; | WQL_Type type = sym->type; |
| |
|
if (nsymbols >= WQL_MAX_SYMBOLS) |
|
return -1; |
|
|
switch (type) | switch (type) |
{ | { |
case WQL_TYPE_AND: | case WQL_TYPE_AND: |
|
|
WQL_Symbol s; | WQL_Symbol s; |
int f; | int f; |
| |
|
memset(&s, '\0', sizeof(s)); |
|
|
if (s1.type != WQL_TYPE_BOOLEAN) | if (s1.type != WQL_TYPE_BOOLEAN) |
return -1; | return -1; |
if (s2.type != WQL_TYPE_BOOLEAN) | if (s2.type != WQL_TYPE_BOOLEAN) |
|
|
{ | { |
if (nsymbols < 1) | if (nsymbols < 1) |
return -1; | return -1; |
|
|
{ | { |
WQL_Symbol s1 = symbols[--nsymbols]; | WQL_Symbol s1 = symbols[--nsymbols]; |
WQL_Symbol s; | WQL_Symbol s; |
| |
|
memset(&s, '\0', sizeof(s)); |
|
|
if (s1.type != WQL_TYPE_BOOLEAN) | if (s1.type != WQL_TYPE_BOOLEAN) |
return -1; | return -1; |
| |
|
|
case WQL_TYPE_LE: | case WQL_TYPE_LE: |
case WQL_TYPE_GT: | case WQL_TYPE_GT: |
case WQL_TYPE_GE: | case WQL_TYPE_GE: |
|
case WQL_TYPE_LIKE: |
{ | { |
if (nsymbols < 2) | if (nsymbols < 2) |
return -1; | return -1; |
|
|
{ | { |
WQL_Symbol s2 = symbols[--nsymbols]; | WQL_Symbol s2 = symbols[--nsymbols]; |
WQL_Symbol s1 = symbols[--nsymbols]; | WQL_Symbol s1 = symbols[--nsymbols]; |
|
|
int r; | int r; |
int f; | int f; |
| |
|
memset(&s, '\0', sizeof(s)); |
|
|
|
/* This type only returned by _ValidateLookup() */ |
|
if (s2.type == WQL_TYPE_ANY || s1.type == WQL_TYPE_ANY) |
|
{ |
|
return 0; |
|
} |
|
|
/* If either operand is null */ | /* If either operand is null */ |
if (s1.type == WQL_TYPE_NULL || s2.type == WQL_TYPE_NULL) | if (s1.type == WQL_TYPE_NULL || s2.type == WQL_TYPE_NULL) |
{ | { |
|
|
int bothNull = | int bothNull = |
(s1.type==WQL_TYPE_NULL && s2.type==WQL_TYPE_NULL); | (s1.type==WQL_TYPE_NULL && s2.type==WQL_TYPE_NULL); |
| |
if (type == WQL_TYPE_EQ) |
if (type == WQL_TYPE_EQ || type == WQL_TYPE_LIKE) |
{ | { |
s.type = WQL_TYPE_BOOLEAN; | s.type = WQL_TYPE_BOOLEAN; |
s.value.boolean = bothNull ? 1 : 0; | s.value.boolean = bothNull ? 1 : 0; |
|
|
} | } |
else | else |
{ | { |
/* Reject type mismatch */ |
|
if (s1.type != s2.type) |
if (type == WQL_TYPE_LIKE) |
|
r = _CompareLike(&s1, &s2); |
|
else |
|
{ |
|
WQL_Symbol lhs = s1; |
|
WQL_Symbol rhs = s2; |
|
|
|
if (lhs.type != rhs.type) |
|
{ |
|
if (_FixupType(&lhs, &rhs) != 0) |
return -1; | return -1; |
|
} |
| |
r = _Compare(&s1, &s2); |
r = _Compare(&lhs, &rhs); |
|
} |
| |
switch (type) | switch (type) |
{ | { |
case WQL_TYPE_EQ: | case WQL_TYPE_EQ: |
|
case WQL_TYPE_LIKE: |
f = (r == 0); | f = (r == 0); |
break; | break; |
case WQL_TYPE_NE: | case WQL_TYPE_NE: |
|
|
| |
memset(&tmp, 0, sizeof(WQL_Symbol)); | memset(&tmp, 0, sizeof(WQL_Symbol)); |
| |
if ((*lookup)(sym->value.string, &tmp, wql->batch, data) != 0) |
if ((*lookup)( |
|
sym->value.string, |
|
sym->value.embeddedClassName, |
|
sym->value.embeddedPropertyName, |
|
&tmp, |
|
wql->batch, |
|
data) != 0) |
|
{ |
return -1; | return -1; |
|
} |
| |
if (tmp.type != WQL_TYPE_BOOLEAN && | if (tmp.type != WQL_TYPE_BOOLEAN && |
tmp.type != WQL_TYPE_INTEGER && | tmp.type != WQL_TYPE_INTEGER && |
tmp.type != WQL_TYPE_REAL && | tmp.type != WQL_TYPE_REAL && |
tmp.type != WQL_TYPE_STRING && | tmp.type != WQL_TYPE_STRING && |
tmp.type != WQL_TYPE_NULL) |
tmp.type != WQL_TYPE_NULL && |
|
tmp.type != WQL_TYPE_ANY) |
{ | { |
return -1; | return -1; |
} | } |
|
|
symbols[nsymbols++] = tmp; | symbols[nsymbols++] = tmp; |
break; | break; |
} | } |
|
|
case WQL_TYPE_REAL: | case WQL_TYPE_REAL: |
case WQL_TYPE_STRING: | case WQL_TYPE_STRING: |
case WQL_TYPE_NULL: | case WQL_TYPE_NULL: |
|
case WQL_TYPE_ANY: |
symbols[nsymbols++] = *sym; | symbols[nsymbols++] = *sym; |
break; | break; |
|
|
|
case WQL_TYPE_ISA: |
|
{ |
|
WQL_Symbol s2; |
|
WQL_Symbol s1; |
|
|
|
if (nsymbols < 2) |
|
return -1; |
|
|
|
s2 = symbols[--nsymbols]; |
|
s1 = symbols[--nsymbols]; |
|
|
|
if (s1.type != WQL_TYPE_STRING) |
|
return -1; |
|
|
|
if (s2.type != WQL_TYPE_STRING) |
|
return -1; |
|
|
|
/* Ask lookup() to perform ISA operation */ |
|
{ |
|
WQL_Symbol tmp = s2; |
|
|
|
if ((*lookup)( |
|
s1.value.string, /* Embedded property name */ |
|
s2.value.string, /* Embedded class name */ |
|
NULL, |
|
&tmp, |
|
wql->batch, |
|
data) != 0) |
|
{ |
|
return -1; |
|
} |
|
|
|
symbols[nsymbols++] = tmp; |
|
} |
|
break; |
|
} |
} | } |
} | } |
| |
|
|
if (nsymbols != 1) | if (nsymbols != 1) |
return -1; | return -1; |
| |
|
/* There should be exactly 1 symbol left on stack */ |
/* Final token on stack should be boolean */ | /* Final token on stack should be boolean */ |
if (symbols[0].type != WQL_TYPE_BOOLEAN) | if (symbols[0].type != WQL_TYPE_BOOLEAN) |
return -1; | return -1; |
|
|
} | } |
| |
int WQL_LookupInstanceProperty( | int WQL_LookupInstanceProperty( |
const MI_Char* name, |
const ZChar* name, |
|
const ZChar* embeddedClassName, |
|
const ZChar* embeddedPropertyName, |
WQL_Symbol* symbol, | WQL_Symbol* symbol, |
Batch* batch, | Batch* batch, |
void* data) | void* data) |
|
|
MI_Type type; | MI_Type type; |
MI_Uint32 flags; | MI_Uint32 flags; |
| |
|
#if 0 |
|
printf("WQL_LookupInstanceProperty{%s}{%s}{%s}\n", |
|
name, embeddedClassName, embeddedPropertyName); |
|
#endif |
|
|
/* Check for null parameters */ | /* Check for null parameters */ |
if (!name || !symbol || !data) | if (!name || !symbol || !data) |
return -1; | return -1; |
|
|
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
return -1; | return -1; |
| |
|
/* Handle ISA opeartion and ISA check for gets on embedded properties: |
|
* For example: SourceInstance.CIM_StorageVolume.OperationalStatus |
|
*/ |
|
if (embeddedClassName) |
|
{ |
|
const MI_ClassDecl* cd; |
|
MI_Boolean isa = MI_FALSE; |
|
|
|
if (type != MI_INSTANCE || !value.instance) |
|
return -1; |
|
|
|
/* Perform ISA check */ |
|
|
|
for (cd = value.instance->classDecl; cd; cd = cd->superClassDecl) |
|
{ |
|
if (Tcscmp(cd->name, embeddedClassName) == 0) |
|
{ |
|
isa = MI_TRUE; |
|
break; |
|
} |
|
} |
|
|
|
/* If lookup was called just to perform an ISA check */ |
|
|
|
if (!embeddedPropertyName) |
|
{ |
|
symbol->type = WQL_TYPE_BOOLEAN; |
|
symbol->value.boolean = isa; |
|
return 0; |
|
} |
|
|
|
/* If lookup was called to get an embedded intance property */ |
|
|
|
if (embeddedPropertyName && !isa) |
|
{ |
|
/* Class was wrong type */ |
|
return -1; |
|
} |
|
} |
|
|
|
/* Handle get embedded instance property */ |
|
|
|
if (embeddedPropertyName) |
|
{ |
|
if (type != MI_INSTANCE || !value.instance) |
|
return -1; |
|
|
|
r = __MI_Instance_GetElement( |
|
value.instance, |
|
embeddedPropertyName, |
|
&value, |
|
&type, |
|
&flags, 0); |
|
|
|
if (r != MI_RESULT_OK) |
|
return -1; |
|
} |
|
|
/* Handle null case */ | /* Handle null case */ |
if (flags & MI_FLAG_NULL) | if (flags & MI_FLAG_NULL) |
{ | { |
|
|
} | } |
case MI_DATETIME: | case MI_DATETIME: |
{ | { |
MI_Char buf[26]; |
ZChar buf[26]; |
DatetimeToStr(&value.datetime, buf); | DatetimeToStr(&value.datetime, buf); |
symbol->type = WQL_TYPE_STRING; | symbol->type = WQL_TYPE_STRING; |
symbol->value.string = Batch_Zdup(batch, buf); |
symbol->value.string = Batch_Tcsdup(batch, buf); |
|
if (!symbol->value.string) |
|
return -1; |
|
else |
return 0; | return 0; |
} | } |
case MI_STRING: | case MI_STRING: |
{ | { |
symbol->type = WQL_TYPE_STRING; | symbol->type = WQL_TYPE_STRING; |
symbol->value.string = Batch_Zdup(batch, value.string); |
symbol->value.string = Batch_Tcsdup(batch, value.string); |
|
if (!symbol->value.string) |
|
return -1; |
|
else |
return 0; | return 0; |
} | } |
| |