/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: QL.CPP Abstract: Level 1 Syntax QL Parser Implements the syntax described in QL_1.BNF. This translates the input into an RPN stream of tokens. History: a-raymcc 21-Jun-96 Created. mdavis 23-Apr-99 Changed to allow 'group' as a property name for Raid 47767. Also fixed GetText() for property comparisons and improved Dump(). --*/ #include "precomp.h" #include #include #include #include #include #include #include //#include #include #include #include #include #define trace(x) //printf x WBEM_WSTR WbemStringAlloc(unsigned long lNumChars) { return (WBEM_WSTR)CoTaskMemAlloc(lNumChars+1); } void WbemStringFree(WBEM_WSTR String) { CoTaskMemFree(String); } unsigned long WbemStringLen(const WCHAR* String) { return wcslen(String); } WBEM_WSTR WbemStringCopy(const WCHAR* String) { if(String == NULL) return NULL; WBEM_WSTR NewString = (WBEM_WSTR)CoTaskMemAlloc(2*(wcslen(String)+1)); if(NewString == NULL) return NULL; wcscpy(NewString, String); return NewString; } //*************************************************************************** // // WCHARToDOUBLE // // Converts a wchar to a double, but does it using the english locale rather // than whatever local the process is running in. This allows us to support // all english queries even on German machines. // //*************************************************************************** DOUBLE WCHARToDOUBLE(WCHAR * pConv, bool & bSuccess) { bSuccess = false; if(pConv == NULL) return 0.0; VARIANT varTo, varFrom; VariantInit(&varTo); varFrom.vt = VT_BSTR; varFrom.bstrVal = SysAllocString(pConv); if ( varFrom.bstrVal == NULL ) { return 0.0; } SCODE sc = VariantChangeTypeEx(&varTo, &varFrom, 0x409, 0, VT_R8); SysFreeString(varFrom.bstrVal); if ( FAILED(sc) ) { return 0.0; } bSuccess = true; return varTo.dblVal; } CPropertyName::CPropertyName(const CPropertyName& Other) { Init(); *this = Other; } void CPropertyName::Init() { m_lNumElements = 0; m_lAllocated = 0; m_aElements = NULL; m_pvHandle = NULL; } void CPropertyName::operator=(const CPropertyName& Other) { *this = (const WBEM_PROPERTY_NAME&)Other; m_pvHandle = Other.m_pvHandle; } void CPropertyName::operator=(const WBEM_PROPERTY_NAME& Other) { Empty(); if ( Other.m_lNumElements > 0) { m_aElements = new WBEM_NAME_ELEMENT[Other.m_lNumElements]; if ( m_aElements == NULL ) { throw CX_MemoryException(); } } m_lAllocated = Other.m_lNumElements; for( long l=0 ; l < Other.m_lNumElements; l++ ) { if(Other.m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY) { m_aElements[l].Element.m_wszPropertyName = WbemStringCopy(Other.m_aElements[l].Element.m_wszPropertyName); if ( m_aElements[l].Element.m_wszPropertyName == NULL ) { break; } } else { m_aElements[l].Element.m_lArrayIndex = Other.m_aElements[l].Element.m_lArrayIndex; } m_aElements[l].m_nType = Other.m_aElements[l].m_nType; } m_lNumElements = l; if ( m_lNumElements != Other.m_lNumElements ) { throw CX_MemoryException(); } } BOOL CPropertyName::operator==(const WBEM_PROPERTY_NAME& Other) { if(m_lNumElements != Other.m_lNumElements) return FALSE; for(long l = 0; l < m_lNumElements; l++) { if(m_aElements[l].m_nType != Other.m_aElements[l].m_nType) return FALSE; if(m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY) { if(wbem_wcsicmp(m_aElements[l].Element.m_wszPropertyName, Other.m_aElements[l].Element.m_wszPropertyName)) { return FALSE; } } else { if(m_aElements[l].Element.m_lArrayIndex != Other.m_aElements[l].Element.m_lArrayIndex) { return FALSE; } } } return TRUE; } void CPropertyName::Empty() { if ( m_aElements!=NULL ) { for(long l = 0; l < m_lNumElements; l++) { if(m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY) { WbemStringFree(m_aElements[l].Element.m_wszPropertyName); } } delete [] m_aElements; m_aElements = NULL; } m_lNumElements = 0; m_lAllocated = 0; m_pvHandle = NULL; } LPCWSTR CPropertyName::GetStringAt(long lIndex) const { if(m_aElements[lIndex].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY) { return m_aElements[lIndex].Element.m_wszPropertyName; } else return NULL; } void CPropertyName::AddElement(LPCWSTR wszElement) { EnsureAllocated(m_lNumElements+1); LPWSTR wszTemp = WbemStringCopy(wszElement); if ( wszTemp == NULL ) { throw CX_MemoryException(); } m_aElements[m_lNumElements].m_nType = WBEM_NAME_ELEMENT_TYPE_PROPERTY; m_aElements[m_lNumElements].Element.m_wszPropertyName = wszTemp; m_lNumElements++; } void CPropertyName::EnsureAllocated(long lElements) { if(m_lAllocated < lElements) { m_lAllocated = lElements+5; WBEM_NAME_ELEMENT* pTemp = new WBEM_NAME_ELEMENT[m_lAllocated]; if (!pTemp) throw CX_MemoryException(); memcpy(pTemp, m_aElements, sizeof(WBEM_NAME_ELEMENT) * m_lNumElements); delete [] m_aElements; m_aElements = pTemp; } } DELETE_ME LPWSTR CPropertyName::GetText() { WString wsText; for(int i = 0; i < m_lNumElements; i++) { if(m_aElements[i].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY) return NULL; if(i > 0) wsText += L"."; wsText += m_aElements[i].Element.m_wszPropertyName; } return wsText.UnbindPtr(); } //*************************************************************************** //*************************************************************************** DWORD CAbstractQl1Parser::TranslateIntrinsic(LPCWSTR pFuncName) { if (wbem_wcsicmp(pFuncName, L"UPPER") == 0) return QL1_FUNCTION_UPPER; if (wbem_wcsicmp(pFuncName, L"LOWER") == 0) return QL1_FUNCTION_LOWER; return QL1_FUNCTION_NONE; } void CAbstractQl1Parser::InitToken(WBEM_QL1_TOKEN* pToken) { pToken->m_lTokenType = QL1_NONE; pToken->m_PropertyName.m_lNumElements = 0; pToken->m_PropertyName.m_aElements = NULL; pToken->m_PropertyName2.m_lNumElements = 0; pToken->m_PropertyName2.m_aElements = NULL; VariantInit(&pToken->m_vConstValue); } CAbstractQl1Parser::CAbstractQl1Parser(CGenLexSource *pSrc) { m_pLexer = new CGenLexer(Ql_1_LexTable, pSrc); if ( m_pLexer == NULL ) { throw CX_MemoryException(); } m_nLine = 0; m_pTokenText = 0; m_nCurrentToken = 0; // Semantic transfer variables. // ============================ m_nRelOp = 0; VariantInit(&m_vTypedConst); m_dwPropFunction = 0; m_dwConstFunction = 0; m_PropertyName.m_lNumElements = 0; m_PropertyName.m_aElements = NULL; m_PropertyName2.m_lNumElements = 0; m_PropertyName2.m_aElements = NULL; m_bPropComp = FALSE; } CAbstractQl1Parser::~CAbstractQl1Parser() { VariantClear(&m_vTypedConst); DeletePropertyName(); delete m_pLexer; } int CAbstractQl1Parser::Parse(CQl1ParseSink* pSink, int nFlags) { m_pSink = pSink; int nRes = parse(nFlags); m_pSink = NULL; return nRes; } //*************************************************************************** // // Next() // // Advances to the next token and recognizes keywords, etc. // //*************************************************************************** BOOL CAbstractQl1Parser::Next(int nFlags) { m_nCurrentToken = m_pLexer->NextToken(); if (m_nCurrentToken == QL_1_TOK_ERROR) return FALSE; m_nLine = m_pLexer->GetLineNum(); m_pTokenText = m_pLexer->GetTokenText(); if (m_nCurrentToken == QL_1_TOK_EOF) m_pTokenText = L""; // Keyword check. // ============== if (m_nCurrentToken == QL_1_TOK_IDENT && nFlags != NO_KEYWORDS) { if (wbem_wcsicmp(m_pTokenText, L"select") == 0) m_nCurrentToken = QL_1_TOK_SELECT; else if (wbem_wcsicmp(m_pTokenText, L"from") == 0) m_nCurrentToken = QL_1_TOK_FROM; else if (wbem_wcsicmp(m_pTokenText, L"where") == 0) m_nCurrentToken = QL_1_TOK_WHERE; else if (wbem_wcsicmp(m_pTokenText, L"like") == 0) m_nCurrentToken = QL_1_TOK_LIKE; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"or") == 0) m_nCurrentToken = QL_1_TOK_OR; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"and") == 0) m_nCurrentToken = QL_1_TOK_AND; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"not") == 0) m_nCurrentToken = QL_1_TOK_NOT; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"IS") == 0) m_nCurrentToken = QL_1_TOK_IS; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"NULL") == 0) m_nCurrentToken = QL_1_TOK_NULL; else if (wbem_wcsicmp(m_pTokenText, L"WITHIN") == 0) m_nCurrentToken = QL_1_TOK_WITHIN; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"ISA") == 0) m_nCurrentToken = QL_1_TOK_ISA; else if (nFlags != EXCLUDE_GROUP_KEYWORD && wbem_wcsicmp(m_pTokenText, L"GROUP") == 0) m_nCurrentToken = QL_1_TOK_GROUP; else if (wbem_wcsicmp(m_pTokenText, L"BY") == 0) m_nCurrentToken = QL_1_TOK_BY; else if (wbem_wcsicmp(m_pTokenText, L"HAVING") == 0) m_nCurrentToken = QL_1_TOK_HAVING; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"TRUE") == 0) m_nCurrentToken = QL_1_TOK_TRUE; else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"FALSE") == 0) m_nCurrentToken = QL_1_TOK_FALSE; } return TRUE; } LPCWSTR CAbstractQl1Parser::GetSinglePropertyName() { if(m_PropertyName.m_lNumElements < 1) return NULL; if(m_PropertyName.m_aElements[0].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY) return NULL; return m_PropertyName.m_aElements[0].Element.m_wszPropertyName; } void CAbstractQl1Parser::DeletePropertyName() { for(long l = 0; l < m_PropertyName.m_lNumElements; l++) { if(m_PropertyName.m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY) { WbemStringFree(m_PropertyName.m_aElements[l]. Element.m_wszPropertyName); } } delete [] m_PropertyName.m_aElements; m_PropertyName.m_lNumElements = 0; m_PropertyName.m_aElements = NULL; } int CAbstractQl1Parser::FlipOperator(int nOp) { switch(nOp) { case QL1_OPERATOR_EQUALS: return QL1_OPERATOR_EQUALS; case QL1_OPERATOR_NOTEQUALS: return QL1_OPERATOR_NOTEQUALS; case QL1_OPERATOR_GREATER: return QL1_OPERATOR_LESS; case QL1_OPERATOR_LESS: return QL1_OPERATOR_GREATER; case QL1_OPERATOR_LESSOREQUALS: return QL1_OPERATOR_GREATEROREQUALS; case QL1_OPERATOR_GREATEROREQUALS: return QL1_OPERATOR_LESSOREQUALS; case QL1_OPERATOR_LIKE: return QL1_OPERATOR_LIKE; case QL1_OPERATOR_UNLIKE: return QL1_OPERATOR_UNLIKE; case QL1_OPERATOR_ISA: return QL1_OPERATOR_INV_ISA; case QL1_OPERATOR_ISNOTA: return QL1_OPERATOR_INV_ISNOTA; case QL1_OPERATOR_INV_ISA: return QL1_OPERATOR_ISA; case QL1_OPERATOR_INV_ISNOTA: return QL1_OPERATOR_ISNOTA; default: return nOp; } } void CAbstractQl1Parser::AddAppropriateToken(const WBEM_QL1_TOKEN& Token) { if(m_bInAggregation) m_pSink->AddHavingToken(Token); else m_pSink->AddToken(Token); } //*************************************************************************** // // ::= SELECT FROM WHERE ; // //*************************************************************************** // ok int CAbstractQl1Parser::parse(int nFlags) { int nRes; m_bInAggregation = FALSE; if(nFlags != JUST_WHERE) { m_pLexer->Reset(); // SELECT // ====== if (!Next()) return LEXICAL_ERROR; if (m_nCurrentToken != QL_1_TOK_SELECT) return SYNTAX_ERROR; if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; // // =========== if (nRes = prop_list()) return nRes; // FROM // ==== if (m_nCurrentToken != QL_1_TOK_FROM) return SYNTAX_ERROR; if (!Next()) return LEXICAL_ERROR; // // =========== if (nRes = class_name()) return nRes; // // =========== if(nRes = tolerance()) return nRes; } if(nFlags != NO_WHERE) { // WHERE clause. // ============= if(nRes = opt_where()) return nRes; // GROUP BY clause // =============== if(nRes = opt_aggregation()) return nRes; } return SUCCESS; } //*************************************************************************** // // ::= WHERE ; // ::= <>; // //*************************************************************************** int CAbstractQl1Parser::opt_where() { int nRes; if (m_nCurrentToken == QL_1_TOK_EOF || m_nCurrentToken == QL_1_TOK_GROUP) { trace(("No WHERE clause\n")); return SUCCESS; } if (m_nCurrentToken != QL_1_TOK_WHERE) return SYNTAX_ERROR; if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; // // ====== if (nRes = expr()) return nRes; // Verify that the current token is QL_1_TOK_EOF. // =============================================== if (m_nCurrentToken != QL_1_TOK_EOF && m_nCurrentToken != QL_1_TOK_GROUP) return SYNTAX_ERROR; return SUCCESS; } //*************************************************************************** // // ::= ; // //*************************************************************************** int CAbstractQl1Parser::prop_list() { int nRes; if (m_nCurrentToken != QL_1_TOK_ASTERISK && m_nCurrentToken != QL_1_TOK_IDENT) return SYNTAX_ERROR; if (nRes = property_name()) return nRes; return prop_list_2(); } //*************************************************************************** // // ::= COMMA ; // ::= <>; // //*************************************************************************** int CAbstractQl1Parser::prop_list_2() { if (m_nCurrentToken == QL_1_TOK_COMMA) { if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; return prop_list(); } return SUCCESS; } int CAbstractQl1Parser::parse_property_name(CPropertyName& Prop) { int nCount = 0; Prop.Empty(); try { while(m_nCurrentToken == QL_1_TOK_IDENT) { // VERY TEMPORARY: See if this is a count query // that should be forwarded to the repository. BOOL bSkipNext = FALSE; if (!_wcsicmp(L"count", m_pTokenText)) { if (Next() && m_nCurrentToken == QL_1_TOK_OPEN_PAREN) { if (!Next() || m_nCurrentToken != QL_1_TOK_ASTERISK) return LEXICAL_ERROR; if (!Next() || m_nCurrentToken != QL_1_TOK_CLOSE_PAREN) return LEXICAL_ERROR; Prop.AddElement(L"count(*)"); m_pSink->SetCountQuery(); } else { bSkipNext = TRUE; Prop.AddElement(L"count"); } } else Prop.AddElement(m_pTokenText); nCount++; if (!bSkipNext) { if(!Next()) return LEXICAL_ERROR; } if(m_nCurrentToken != QL_1_TOK_DOT) break; if(!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; } } catch (CX_MemoryException) { return OUT_OF_MEMORY; } catch (...) { return FAILED; } if (nCount) return SUCCESS; else return SYNTAX_ERROR; } //*************************************************************************** // // ::= PROPERTY_NAME_STRING; // ::= ASTERISK; // //*************************************************************************** int CAbstractQl1Parser::property_name() { try { if (m_nCurrentToken == QL_1_TOK_ASTERISK) { trace(("Asterisk\n")); if(m_bInAggregation) m_pSink->AddAllAggregationProperties(); else m_pSink->AddAllProperties(); if(!Next()) return LEXICAL_ERROR; return SUCCESS; } // Else a list of property names // ============================= CPropertyName Prop; int nRes = parse_property_name(Prop); if(nRes != SUCCESS) return nRes; if(m_bInAggregation) m_pSink->AddAggregationProperty(Prop); else m_pSink->AddProperty(Prop); } catch (CX_MemoryException) { return OUT_OF_MEMORY; } catch (...) { return FAILED; } return SUCCESS; } //*************************************************************************** // // ::= CLASS_NAME_STRING; // //*************************************************************************** int CAbstractQl1Parser::class_name() { if (m_nCurrentToken != QL_1_TOK_IDENT) return SYNTAX_ERROR; trace(("Class name is %S\n", m_pTokenText)); m_pSink->SetClassName(m_pTokenText); if (!Next()) return LEXICAL_ERROR; return SUCCESS; } //*************************************************************************** // // ::= <>; // ::= WITHIN duration; // //*************************************************************************** int CAbstractQl1Parser::tolerance() { LPWSTR wszGarbage; WBEM_QL1_TOLERANCE Tolerance; if(m_nCurrentToken != QL_1_TOK_WITHIN) { Tolerance.m_bExact = TRUE; m_pSink->SetTolerance(Tolerance); return SUCCESS; } if(!Next()) return LEXICAL_ERROR; if (m_nCurrentToken == QL_1_TOK_REAL) { Tolerance.m_bExact = FALSE; bool bSuccess; Tolerance.m_fTolerance = WCHARToDOUBLE(m_pTokenText, bSuccess); if(Tolerance.m_fTolerance <= 0 || bSuccess == false) { return SYNTAX_ERROR; } m_pSink->SetTolerance(Tolerance); Next(); return SUCCESS; } else if (m_nCurrentToken == QL_1_TOK_INT) { Tolerance.m_bExact = FALSE; Tolerance.m_fTolerance = wcstol(m_pTokenText, &wszGarbage, 10); if(Tolerance.m_fTolerance < 0) { return SYNTAX_ERROR; } m_pSink->SetTolerance(Tolerance); Next(); return SUCCESS; } else { return SYNTAX_ERROR; } } //*************************************************************************** // // ::= ; // //*************************************************************************** int CAbstractQl1Parser::expr() { int nRes; if (nRes = term()) return nRes; if (nRes = expr2()) return nRes; return SUCCESS; } //*************************************************************************** // // ::= OR ; // ::= <>; // // Entry: Assumes token OR already current. // Exit: Advances a token // //*************************************************************************** int CAbstractQl1Parser::expr2() { int nRes; while (1) { if (m_nCurrentToken == QL_1_TOK_OR) { trace(("Token OR\n")); m_pSink->InOrder(QL1_OR); if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if (nRes = term()) return nRes; WBEM_QL1_TOKEN NewTok; InitToken(&NewTok); NewTok.m_lTokenType = QL1_OR; AddAppropriateToken(NewTok); } else break; } return SUCCESS; } //*************************************************************************** // // ::= ; // //*************************************************************************** int CAbstractQl1Parser::term() { int nRes; if (nRes = simple_expr()) return nRes; if (nRes = term2()) return nRes; return SUCCESS; } //*************************************************************************** // // ::= AND ; // ::= <>; // //*************************************************************************** int CAbstractQl1Parser::term2() { int nRes; while (1) { if (m_nCurrentToken == QL_1_TOK_AND) { trace(("Token AND\n")); m_pSink->InOrder(QL1_AND); if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if (nRes = simple_expr()) return nRes; // Add the AND token. // ================== WBEM_QL1_TOKEN NewTok; InitToken(&NewTok); NewTok.m_lTokenType = QL1_AND; AddAppropriateToken(NewTok); } else break; } return SUCCESS; } //*************************************************************************** // // ::= NOT ; // ::= OPEN_PAREN CLOSE_PAREN; // ::= IDENTIFIER ; // ::= VARIANT ; // //*************************************************************************** // ok int CAbstractQl1Parser::simple_expr() { int nRes; // NOT // ========== if (m_nCurrentToken == QL_1_TOK_NOT) { trace(("Operator NOT\n")); if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if (nRes = simple_expr()) return nRes; WBEM_QL1_TOKEN NewTok; InitToken(&NewTok); NewTok.m_lTokenType = QL1_NOT; AddAppropriateToken(NewTok); return SUCCESS; } // OPEN_PAREN CLOSE_PAREN // ============================= else if (m_nCurrentToken == QL_1_TOK_OPEN_PAREN) { trace(("Open Paren: Entering subexpression\n")); if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if (expr()) return SYNTAX_ERROR; if (m_nCurrentToken != QL_1_TOK_CLOSE_PAREN) return SYNTAX_ERROR; trace(("Close paren: Exiting subexpression\n")); if (!Next()) return LEXICAL_ERROR; return SUCCESS; } // IDENTIFIER // ========================================== else if (m_nCurrentToken == QL_1_TOK_IDENT) { trace((" Identifier <%S>\n", m_pTokenText)); if(nRes = parse_property_name(m_PropertyName)) return nRes; if (nRes = leading_ident_expr()) return SYNTAX_ERROR; return finalize(); } // // ====================================================== else if (m_nCurrentToken == QL_1_TOK_INT || m_nCurrentToken == QL_1_TOK_REAL || m_nCurrentToken == QL_1_TOK_TRUE || m_nCurrentToken == QL_1_TOK_FALSE || m_nCurrentToken == QL_1_TOK_NULL || m_nCurrentToken == QL_1_TOK_QSTRING ) { if (nRes = typed_constant()) return nRes; if (nRes = rel_operator()) return nRes; // dont allow const followed by isa! if(m_nRelOp == QL1_OPERATOR_ISA) return SYNTAX_ERROR; // Since we always view the token as IDENT constant, we need // to invert this operator, e.g. replace > with < // ================================================================ m_nRelOp = FlipOperator(m_nRelOp); if (nRes = trailing_prop_expr()) return nRes; return finalize(); } return SYNTAX_ERROR; } //*************************************************************************** // // ::= IDENTIFIER // //*************************************************************************** // ok int CAbstractQl1Parser::trailing_prop_expr() { if (m_nCurrentToken != QL_1_TOK_IDENT) return SYNTAX_ERROR; int nRes = parse_property_name(m_PropertyName); return nRes; } //*************************************************************************** // // ::= ; // ::= ; // ::= NULL; // //*************************************************************************** // ok int CAbstractQl1Parser::leading_ident_expr() { int nRes; if (SUCCESS == comp_operator()) { return trailing_const_expr(); } else if(SUCCESS == equiv_operator()) return trailing_or_null(); nRes = is_operator(); if(nRes != SUCCESS) return nRes; if (m_nCurrentToken != QL_1_TOK_NULL) return LEXICAL_ERROR; if (Next()) { V_VT(&m_vTypedConst) = VT_NULL; return SUCCESS; } else return LEXICAL_ERROR; } //*************************************************************************** // // ::= NULL; // ::= ; // //*************************************************************************** int CAbstractQl1Parser::trailing_or_null() { if (m_nCurrentToken == QL_1_TOK_NULL) { if (!Next()) return LEXICAL_ERROR; else { V_VT(&m_vTypedConst) = VT_NULL; return SUCCESS; } } return trailing_const_expr(); } //*************************************************************************** // // ::= IDENTIFIER OPEN_PAREN // CLOSE_PAREN; // ::= ; // ::= // //*************************************************************************** // ok int CAbstractQl1Parser::trailing_const_expr() { int nRes; nRes = typed_constant(); if (nRes != SUCCESS) nRes = trailing_ident_expr(); return nRes; } //*************************************************************************** // // ::= // //*************************************************************************** // ok int CAbstractQl1Parser::trailing_ident_expr() { int nRes = parse_property_name(m_PropertyName2) ; if (nRes == SUCCESS) m_bPropComp = TRUE; return nRes; } //*************************************************************************** // // ::= <>; // // This composes the QL_LEVEL_1_TOKEN for a simple relational expression, // complete with any associated intrinsic functions. All of the other // parse functions help isolate the terms of the expression, but only // this function builds the token. // // To build the token, the following member variables are used: // m_pPropName // m_vTypedConst // m_dwPropFunction // m_dwConstFunction // m_nRelOp; // // After the token is built, these are cleared/deallocated as appropriate. // No tokens are consumed and the input is not advanced. // //*************************************************************************** int CAbstractQl1Parser::finalize() { // At this point, we have all the info needed for a token. // ======================================================= WBEM_QL1_TOKEN NewTok; InitToken(&NewTok); NewTok.m_lTokenType = QL1_OP_EXPRESSION; VariantInit(&NewTok.m_vConstValue); memcpy((void*)&NewTok.m_PropertyName, (void*)(WBEM_PROPERTY_NAME*)&m_PropertyName, sizeof(WBEM_PROPERTY_NAME)); if (m_bPropComp) { NewTok.m_bPropComp = true; memcpy((void*)&NewTok.m_PropertyName2, (void*)(WBEM_PROPERTY_NAME*)&m_PropertyName2, sizeof(WBEM_PROPERTY_NAME)); } else { NewTok.m_bPropComp = false; if ( FAILED(VariantCopy(&NewTok.m_vConstValue, &m_vTypedConst) )) { return OUT_OF_MEMORY; } } NewTok.m_lOperator = m_nRelOp; NewTok.m_lPropertyFunction = m_dwPropFunction; NewTok.m_lConstFunction = m_dwConstFunction; NewTok.m_bQuoted = m_bQuoted; AddAppropriateToken(NewTok); // m_PropertyName.m_lNumElements = 0; // m_PropertyName.m_aElements = NULL; m_PropertyName.Empty(); m_PropertyName2.Empty(); // Cleanup. // ======== VariantClear(&m_vTypedConst); VariantClear(&NewTok.m_vConstValue); m_nRelOp = 0; m_dwPropFunction = 0; m_dwConstFunction = 0; m_bPropComp = FALSE; return SUCCESS; } //*************************************************************************** // // ::= VARIANT; // // Ouput: m_vTypedConst is set to the value of the constant. The only // supported types are VT_I4, VT_R8 and VT_BSTR. // //*************************************************************************** int CAbstractQl1Parser::typed_constant() { trace((" Typed constant <%S> ", m_pTokenText)); VariantClear(&m_vTypedConst); m_bQuoted = FALSE; if (m_nCurrentToken == QL_1_TOK_INT) { trace((" Integer\n")); // Read it in as a 64-bit one // ========================== __int64 i64; unsigned __int64 ui64; BOOL b32bits = FALSE; if(ReadI64(m_pTokenText, i64)) { // Check if it is within range of I4 // ================================= if(i64 >= - (__int64)0x80000000 && i64 <= 0x7FFFFFFF) { V_VT(&m_vTypedConst) = VT_I4; V_I4(&m_vTypedConst) = (long)i64; b32bits = TRUE; } } else if(!ReadUI64(m_pTokenText, ui64)) { // Not a valid number // ================== return LEXICAL_ERROR; } if(!b32bits) { // Valid 64-bit number but not 32-bit // ================================== BSTR bstr = SysAllocString(m_pTokenText); if ( bstr == NULL ) { return OUT_OF_MEMORY; } V_VT(&m_vTypedConst) = VT_BSTR; V_BSTR(&m_vTypedConst) = bstr; m_bQuoted = FALSE; } } else if (m_nCurrentToken == QL_1_TOK_QSTRING) { trace((" String\n")); BSTR bstr = SysAllocString(m_pTokenText); if ( bstr == NULL ) { return OUT_OF_MEMORY; } V_VT(&m_vTypedConst) = VT_BSTR; V_BSTR(&m_vTypedConst) = bstr; m_bQuoted = TRUE; } else if (m_nCurrentToken == QL_1_TOK_REAL) { trace((" Real\n")); V_VT(&m_vTypedConst) = VT_R8; bool bSuccess; V_R8(&m_vTypedConst) = WCHARToDOUBLE(m_pTokenText, bSuccess); if(bSuccess == false) return LEXICAL_ERROR; } else if(m_nCurrentToken == QL_1_TOK_TRUE) { V_VT(&m_vTypedConst) = VT_BOOL; V_BOOL(&m_vTypedConst) = VARIANT_TRUE; } else if(m_nCurrentToken == QL_1_TOK_FALSE) { V_VT(&m_vTypedConst) = VT_BOOL; V_BOOL(&m_vTypedConst) = VARIANT_FALSE; } else if (m_nCurrentToken == QL_1_TOK_NULL) V_VT(&m_vTypedConst) = VT_NULL; // Else, not a typed constant. else return SYNTAX_ERROR; if (!Next()) return LEXICAL_ERROR; return SUCCESS; } //*************************************************************************** // // ::= ; // ::= ; // //*************************************************************************** int CAbstractQl1Parser::rel_operator() { if(SUCCESS == equiv_operator()) return SUCCESS; else if (SUCCESS == comp_operator()) return SUCCESS; else return LEXICAL_ERROR; } //*************************************************************************** // // ::= EQUIV_OPERATOR; // =, != // // Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN. // //*************************************************************************** int CAbstractQl1Parser::equiv_operator() { m_nRelOp = 0; if (m_nCurrentToken == QL_1_TOK_EQ) { trace((" REL OP =\n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUAL; } else if (m_nCurrentToken == QL_1_TOK_NE) { trace((" REL OP <> (!=) \n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL; } else return SYNTAX_ERROR; if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; return SUCCESS; } //*************************************************************************** // // ::= IS_OPERATOR; // is, isnot // // Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN. // //*************************************************************************** int CAbstractQl1Parser::is_operator() { m_nRelOp = 0; if (m_nCurrentToken != QL_1_TOK_IS) return SYNTAX_ERROR; if (!Next()) return LEXICAL_ERROR; if (m_nCurrentToken == QL_1_TOK_NOT) { m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL; if (!Next()) return LEXICAL_ERROR; trace((" REL OP IS NOT \n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL; return SUCCESS; } else { trace((" REL OP IS \n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUAL; return SUCCESS; } return SUCCESS; } //*************************************************************************** // // ::= COMP_OPERATOR; // <=, >=, <, >, like // // Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN. // //*************************************************************************** int CAbstractQl1Parser::comp_operator() { m_nRelOp = 0; if (m_nCurrentToken == QL_1_TOK_LE) { trace((" REL OP <=\n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN; } else if (m_nCurrentToken == QL_1_TOK_LT) { trace((" REL OP <\n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_LESSTHAN; } else if (m_nCurrentToken == QL_1_TOK_GE) { trace((" REL OP >=\n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN; } else if (m_nCurrentToken == QL_1_TOK_GT) { trace((" REL OP >\n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_GREATERTHAN; } else if (m_nCurrentToken == QL_1_TOK_LIKE) { trace((" REL OP 'like' \n")); m_nRelOp = QL_LEVEL_1_TOKEN::OP_LIKE; } else if (m_nCurrentToken == QL_1_TOK_ISA) { trace((" REL OP 'isa' \n")); m_nRelOp = QL1_OPERATOR_ISA; } else return SYNTAX_ERROR; if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; return SUCCESS; } int CAbstractQl1Parser::opt_aggregation() { if(m_nCurrentToken == QL_1_TOK_EOF) return SUCCESS; if(m_nCurrentToken != QL_1_TOK_GROUP) return SYNTAX_ERROR; if (!Next()) return LEXICAL_ERROR; m_pSink->SetAggregated(); int nRes = aggregation_params(); if(nRes) return nRes; if(nRes = opt_having()) return nRes; // Make sure we've reached the end // =============================== if(m_nCurrentToken != QL_1_TOK_EOF) return SYNTAX_ERROR; return SUCCESS; } int CAbstractQl1Parser::aggregation_params() { int nRes; WBEM_QL1_TOLERANCE Exact; Exact.m_bExact = TRUE; if(m_nCurrentToken == QL_1_TOK_BY) { if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if(nRes = aggregate_by()) return nRes; if(m_nCurrentToken == QL_1_TOK_WITHIN) { if (!Next()) return LEXICAL_ERROR; if(nRes = aggregate_within()) return nRes; } else { m_pSink->SetAggregationTolerance(Exact); } } else if(m_nCurrentToken == QL_1_TOK_WITHIN) { if (!Next()) return LEXICAL_ERROR; if(nRes = aggregate_within()) return nRes; if(m_nCurrentToken == QL_1_TOK_BY) { if (!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; if(nRes = aggregate_by()) return nRes; } } else { return SYNTAX_ERROR; } return SUCCESS; } int CAbstractQl1Parser::aggregate_within() { WBEM_QL1_TOLERANCE Tolerance; Tolerance.m_bExact = FALSE; LPWSTR wszGarbage; if (m_nCurrentToken == QL_1_TOK_REAL) { bool bSuccess; Tolerance.m_fTolerance = WCHARToDOUBLE(m_pTokenText, bSuccess); if(!bSuccess) return SYNTAX_ERROR; m_pSink->SetAggregationTolerance(Tolerance); Next(); return SUCCESS; } else if (m_nCurrentToken == QL_1_TOK_INT) { Tolerance.m_fTolerance = (double)wcstol(m_pTokenText, &wszGarbage, 10); m_pSink->SetAggregationTolerance(Tolerance); Next(); return SUCCESS; } else { return SYNTAX_ERROR; } } int CAbstractQl1Parser::aggregate_by() { m_bInAggregation = TRUE; int nRes = prop_list(); m_bInAggregation = FALSE; return nRes; } int CAbstractQl1Parser::opt_having() { if(m_nCurrentToken == QL_1_TOK_HAVING) { if(!Next(EXCLUDE_GROUP_KEYWORD)) return LEXICAL_ERROR; m_bInAggregation = TRUE; int nRes = expr(); m_bInAggregation = FALSE; return nRes; } else return SUCCESS; } //*************************************************************************** //*************************************************************************** // // class QL1_Parser // // A derivative of CAbstractQlParser for backward compatibility // //*************************************************************************** // // QL1_Parser::QL1_Parser(CGenLexSource *pSrc) : m_pExpression(NULL), CAbstractQl1Parser(pSrc), m_bPartiallyParsed(FALSE) { m_pExpression = new QL_LEVEL_1_RPN_EXPRESSION; if ( m_pExpression == NULL ) { throw CX_MemoryException(); } } QL1_Parser::~QL1_Parser() { delete m_pExpression; } int QL1_Parser::GetQueryClass( LPWSTR pDestBuf, int nBufLen ) { // Get the underlying parser to parse the first part of the query // ============================================================== if(!m_bPartiallyParsed) { int nRes = CAbstractQl1Parser::Parse(m_pExpression, NO_WHERE); if(nRes != SUCCESS) return nRes; } if (!m_pExpression->bsClassName) return SYNTAX_ERROR; m_bPartiallyParsed = TRUE; if(wcslen(m_pExpression->bsClassName) >= (unsigned int)nBufLen) return BUFFER_TOO_SMALL; wcscpy(pDestBuf, m_pExpression->bsClassName); return WBEM_S_NO_ERROR; } int QL1_Parser::Parse(QL_LEVEL_1_RPN_EXPRESSION **pOutput) { *pOutput = NULL; // Get the underying parser to completely parse the query. If // GetQueryClass was called in the past, no sense in duplcating // the work // ============================================================ QL_LEVEL_1_RPN_EXPRESSION* pTemp = NULL; try { pTemp = new QL_LEVEL_1_RPN_EXPRESSION; } catch (CX_MemoryException) { return OUT_OF_MEMORY; } if ( pTemp == NULL ) { return OUT_OF_MEMORY; } int nRes = CAbstractQl1Parser::Parse(m_pExpression, m_bPartiallyParsed?JUST_WHERE:FULL_PARSE); if ( nRes == SUCCESS ) { *pOutput = m_pExpression; m_pExpression = pTemp; m_bPartiallyParsed = FALSE; } else { delete pTemp; } return nRes; } DELETE_ME LPWSTR QL1_Parser::ReplaceClassName(QL_LEVEL_1_RPN_EXPRESSION* pExpr, LPCWSTR wszClassName) { QL_LEVEL_1_RPN_EXPRESSION NewExpr(*pExpr); if (NewExpr.bsClassName) SysFreeString(NewExpr.bsClassName); NewExpr.bsClassName = SysAllocString(wszClassName); if ( NewExpr.bsClassName == NULL ) { return NULL; } LPWSTR wszNewQuery = NewExpr.GetText(); return wszNewQuery; } //*************************************************************************** // // Expression and token structure methods. // //*************************************************************************** QL_LEVEL_1_RPN_EXPRESSION::QL_LEVEL_1_RPN_EXPRESSION() { nNumTokens = 0; bsClassName = 0; bCount = FALSE; nNumberOfProperties = 0; bStar = FALSE; pRequestedPropertyNames = 0; nCurSize = 1; nCurPropSize = 1; pArrayOfTokens = new QL_LEVEL_1_TOKEN[nCurSize]; pRequestedPropertyNames = new CPropertyName[nCurPropSize]; bAggregated = FALSE; bAggregateAll = FALSE; nNumAggregatedProperties = 0; nCurAggPropSize = 1; pAggregatedPropertyNames = new CPropertyName[nCurAggPropSize]; nNumHavingTokens = 0; nCurHavingSize = 1; pArrayOfHavingTokens = new QL_LEVEL_1_TOKEN[nCurHavingSize]; if ( pArrayOfTokens == NULL || pRequestedPropertyNames == NULL || pAggregatedPropertyNames == NULL || pArrayOfHavingTokens == NULL ) { delete [] pArrayOfTokens; delete [] pRequestedPropertyNames; delete [] pAggregatedPropertyNames; delete [] pArrayOfHavingTokens; throw CX_MemoryException(); } lRefCount = 0; } QL_LEVEL_1_RPN_EXPRESSION::QL_LEVEL_1_RPN_EXPRESSION( const QL_LEVEL_1_RPN_EXPRESSION& Other) { nNumTokens = Other.nNumTokens; nNumberOfProperties = Other.nNumberOfProperties; bStar = Other.bStar; bCount = Other.bCount; pRequestedPropertyNames = 0; nCurSize = Other.nCurSize; nCurPropSize = Other.nCurPropSize; bAggregated = Other.bAggregated; bAggregateAll = Other.bAggregateAll; nNumAggregatedProperties = Other.nNumAggregatedProperties; nCurAggPropSize = Other.nCurAggPropSize; nNumHavingTokens = Other.nNumHavingTokens; nCurHavingSize = Other.nCurHavingSize; bsClassName = SysAllocString(Other.bsClassName); pArrayOfTokens = new QL_LEVEL_1_TOKEN[nCurSize]; pRequestedPropertyNames = new CPropertyName[nCurPropSize]; pAggregatedPropertyNames = new CPropertyName[nCurAggPropSize]; pArrayOfHavingTokens = new QL_LEVEL_1_TOKEN[nCurHavingSize]; if ( pArrayOfTokens == NULL || pRequestedPropertyNames == NULL || pAggregatedPropertyNames == NULL || pArrayOfHavingTokens == NULL || bsClassName == NULL ) { delete [] pArrayOfTokens; delete [] pRequestedPropertyNames; delete [] pAggregatedPropertyNames; delete [] pArrayOfHavingTokens; if ( bsClassName != NULL ) SysFreeString( bsClassName ); throw CX_MemoryException(); } int i; for(i = 0; i < nNumTokens; i++) pArrayOfTokens[i] = Other.pArrayOfTokens[i]; for(i = 0; i < nNumberOfProperties; i++) pRequestedPropertyNames[i] = Other.pRequestedPropertyNames[i]; for(i = 0; i < nNumAggregatedProperties; i++) pAggregatedPropertyNames[i] = Other.pAggregatedPropertyNames[i]; for(i = 0; i < nNumHavingTokens; i++) pArrayOfHavingTokens[i] = Other.pArrayOfHavingTokens[i]; lRefCount = 0; } void QL_LEVEL_1_RPN_EXPRESSION::AddRef() { InterlockedIncrement(&lRefCount); } void QL_LEVEL_1_RPN_EXPRESSION::Release() { if(InterlockedDecrement(&lRefCount) == 0) delete this; } QL_LEVEL_1_RPN_EXPRESSION::~QL_LEVEL_1_RPN_EXPRESSION() { delete [] pArrayOfTokens; if (bsClassName) SysFreeString(bsClassName); delete [] pAggregatedPropertyNames; delete [] pArrayOfHavingTokens; delete [] pRequestedPropertyNames; } void QL_LEVEL_1_RPN_EXPRESSION::SetClassName(LPCWSTR wszClassName) { if ( bsClassName != NULL ) { SysFreeString( bsClassName ); } bsClassName = SysAllocString(wszClassName); if ( bsClassName == NULL ) { throw CX_MemoryException(); } } void QL_LEVEL_1_RPN_EXPRESSION::SetTolerance( const WBEM_QL1_TOLERANCE& _Tolerance) { Tolerance = _Tolerance; } void QL_LEVEL_1_RPN_EXPRESSION::SetAggregationTolerance( const WBEM_QL1_TOLERANCE& _Tolerance) { AggregationTolerance = _Tolerance; } void QL_LEVEL_1_RPN_EXPRESSION::AddToken(const WBEM_QL1_TOKEN& Tok) { if (nCurSize == nNumTokens) { nCurSize += 1; nCurSize *= 2; QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurSize]; if ( pTemp == NULL ) { throw CX_MemoryException(); } for (int i = 0; i < nNumTokens; i++) pTemp[i] = pArrayOfTokens[i]; delete [] pArrayOfTokens; pArrayOfTokens = pTemp; } pArrayOfTokens[nNumTokens++] = Tok; } void QL_LEVEL_1_RPN_EXPRESSION::AddToken(const QL_LEVEL_1_TOKEN& Tok) { if (nCurSize == nNumTokens) { nCurSize += 1; nCurSize *= 2; QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurSize]; if ( pTemp == NULL ) { throw CX_MemoryException(); } for (int i = 0; i < nNumTokens; i++) pTemp[i] = pArrayOfTokens[i]; delete [] pArrayOfTokens; pArrayOfTokens = pTemp; } pArrayOfTokens[nNumTokens++] = Tok; } void QL_LEVEL_1_RPN_EXPRESSION::AddHavingToken( const WBEM_QL1_TOKEN& Tok) { if (nCurHavingSize == nNumHavingTokens) { nCurHavingSize += 1; nCurHavingSize *= 2; QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurHavingSize]; if ( pTemp == NULL ) { throw CX_MemoryException(); } for (int i = 0; i < nNumHavingTokens; i++) pTemp[i] = pArrayOfHavingTokens[i]; delete [] pArrayOfHavingTokens; pArrayOfHavingTokens = pTemp; } pArrayOfHavingTokens[nNumHavingTokens++] = Tok; } void QL_LEVEL_1_RPN_EXPRESSION::AddProperty(const CPropertyName& Prop) { if (nCurPropSize == nNumberOfProperties) { nCurPropSize += 1; nCurPropSize *= 2; CPropertyName *pTemp = new CPropertyName[nCurPropSize]; if (!pTemp) throw CX_MemoryException(); for(int i = 0; i < nNumberOfProperties; i++) pTemp[i] = pRequestedPropertyNames[i]; delete [] pRequestedPropertyNames; pRequestedPropertyNames = pTemp; } pRequestedPropertyNames[nNumberOfProperties++] = Prop; } void QL_LEVEL_1_RPN_EXPRESSION::AddAllProperties() { bStar = TRUE; } void QL_LEVEL_1_RPN_EXPRESSION::SetCountQuery() { bCount = TRUE; } void QL_LEVEL_1_RPN_EXPRESSION::SetAggregated() { bAggregated = TRUE; } void QL_LEVEL_1_RPN_EXPRESSION::AddAggregationProperty( const CPropertyName& Property) { if(pAggregatedPropertyNames == NULL) { // '*' requested return; } if (nCurAggPropSize == nNumAggregatedProperties) { nCurAggPropSize += 1; nCurAggPropSize *= 2; CPropertyName *pTemp = new CPropertyName[nCurAggPropSize]; if ( pTemp == NULL ) { throw CX_MemoryException(); } for(int i = 0; i < nNumAggregatedProperties; i++) pTemp[i] = pAggregatedPropertyNames[i]; delete [] pAggregatedPropertyNames; pAggregatedPropertyNames = pTemp; } pAggregatedPropertyNames[nNumAggregatedProperties++] = Property; } void QL_LEVEL_1_RPN_EXPRESSION::AddAllAggregationProperties() { bAggregateAll = TRUE; } DELETE_ME LPWSTR QL_LEVEL_1_RPN_EXPRESSION::GetText() { WString wsText; wsText += L"select "; for(int i = 0; i < nNumberOfProperties; i++) { if(i != 0) wsText += L", "; wsText += (LPWSTR)pRequestedPropertyNames[i].GetStringAt(0); } if(bStar) { if(nNumberOfProperties > 0) wsText += L", "; wsText += L"*"; } wsText += L" from "; if (bsClassName) wsText += bsClassName; if(nNumTokens > 0) { wsText += L" where "; CWStringArray awsStack; for(int i = 0; i < nNumTokens; i++) { QL_LEVEL_1_TOKEN& Token = pArrayOfTokens[i]; LPWSTR wszTokenText = Token.GetText(); if(wszTokenText == NULL) return NULL; if(Token.nTokenType == QL1_OP_EXPRESSION) { awsStack.Add(wszTokenText); delete [] wszTokenText; } else if(Token.nTokenType == QL1_NOT) { LPWSTR wszLast = awsStack[awsStack.Size()-1]; WString wsNew; wsNew += wszTokenText; delete [] wszTokenText; wsNew += L" ("; wsNew += wszLast; wsNew += L")"; awsStack.RemoveAt(awsStack.Size()-1); //pop awsStack.Add(wsNew); } else { if(awsStack.Size() < 2) return NULL; LPWSTR wszLast = awsStack[awsStack.Size()-1]; LPWSTR wszPrev = awsStack[awsStack.Size()-2]; WString wsNew; wsNew += L"("; wsNew += wszPrev; wsNew += L" "; wsNew += wszTokenText; delete [] wszTokenText; wsNew += L" "; wsNew += wszLast; wsNew += L")"; awsStack.RemoveAt(awsStack.Size()-1); //pop awsStack.RemoveAt(awsStack.Size()-1); //pop awsStack.Add(wsNew); } } if(awsStack.Size() != 1) return NULL; wsText += awsStack[0]; } return wsText.UnbindPtr(); } void QL_LEVEL_1_RPN_EXPRESSION::Dump(const char *pszTextFile) { FILE *f = fopen(pszTextFile, "wt"); if (!f) return; fprintf(f, "----RPN Expression----\n"); fprintf(f, "Class name = %S\n", bsClassName); fprintf(f, "Properties selected: "); if (!nNumberOfProperties) { fprintf(f, "* = all properties selected\n"); } else for (int i = 0; i < nNumberOfProperties; i++) { fprintf(f, "%S ", pRequestedPropertyNames[i].GetStringAt(0)); } fprintf(f, "\n------------------\n"); fprintf(f, "Tokens:\n"); for (int i = 0; i < nNumTokens; i++) pArrayOfTokens[i].Dump(f); fprintf(f, "---end of expression---\n"); fclose(f); } QL_LEVEL_1_TOKEN::QL_LEVEL_1_TOKEN() { nTokenType = 0; nOperator = 0; VariantInit(&vConstValue); dwPropertyFunction = 0; dwConstFunction = 0; bQuoted = TRUE; m_bPropComp = FALSE; } QL_LEVEL_1_TOKEN::QL_LEVEL_1_TOKEN(const QL_LEVEL_1_TOKEN &Src) { nTokenType = 0; nOperator = 0; VariantInit(&vConstValue); dwPropertyFunction = 0; dwConstFunction = 0; bQuoted = TRUE; m_bPropComp = FALSE; *this = Src; } QL_LEVEL_1_TOKEN& QL_LEVEL_1_TOKEN::operator =(const QL_LEVEL_1_TOKEN &Src) { if ( FAILED(VariantCopy(&vConstValue, (VARIANT*)&Src.vConstValue)) ) { throw CX_MemoryException(); } nTokenType = Src.nTokenType; PropertyName = Src.PropertyName; if (Src.m_bPropComp) PropertyName2 = Src.PropertyName2; nOperator = Src.nOperator; dwPropertyFunction = Src.dwPropertyFunction; dwConstFunction = Src.dwConstFunction; bQuoted = Src.bQuoted; m_bPropComp = Src.m_bPropComp; return *this; } QL_LEVEL_1_TOKEN& QL_LEVEL_1_TOKEN::operator =(const WBEM_QL1_TOKEN &Src) { if ( FAILED(VariantCopy(&vConstValue, (VARIANT*)&Src.m_vConstValue) ) ) { throw CX_MemoryException(); } nTokenType = Src.m_lTokenType; PropertyName = Src.m_PropertyName; if (Src.m_bPropComp) PropertyName2 = Src.m_PropertyName2; nOperator = Src.m_lOperator; dwPropertyFunction = Src.m_lPropertyFunction; dwConstFunction = Src.m_lConstFunction; bQuoted = Src.m_bQuoted; m_bPropComp = Src.m_bPropComp; return *this; } QL_LEVEL_1_TOKEN::~QL_LEVEL_1_TOKEN() { nTokenType = 0; nOperator = 0; VariantClear(&vConstValue); } DELETE_ME LPWSTR QL_LEVEL_1_TOKEN::GetText() { WString wsText; LPWSTR wszPropName; switch (nTokenType) { case OP_EXPRESSION: wszPropName = PropertyName.GetText(); if(wszPropName == NULL) return NULL; wsText += wszPropName; delete [] wszPropName; wsText += L" "; WCHAR* wszOp; switch (nOperator) { case OP_EQUAL: wszOp = L"="; break; case OP_NOT_EQUAL: wszOp = L"<>"; break; case OP_EQUALorGREATERTHAN: wszOp = L">="; break; case OP_EQUALorLESSTHAN: wszOp = L"<="; break; case OP_LESSTHAN: wszOp = L"<"; break; case OP_GREATERTHAN: wszOp = L">"; break; case OP_LIKE: wszOp = L"LIKE"; break; case QL1_OPERATOR_ISA: wszOp = L"ISA"; break; default: wszOp = NULL; } if(wszOp) wsText += wszOp; wsText += L" "; if (m_bPropComp) { // property comparison (e.g., prop1 > prop2) wszPropName = PropertyName2.GetText(); if(wszPropName == NULL) return NULL; wsText += wszPropName; delete [] wszPropName; } else { // expression with constant (e.g., prop1 > 5) WCHAR wszConst[100]; switch (V_VT(&vConstValue)) { case VT_NULL: wsText += L"NULL"; break; case VT_I4: swprintf(wszConst, L"%d", V_I4(&vConstValue)); wsText += wszConst; break; case VT_I2: swprintf(wszConst, L"%d", (int)V_I2(&vConstValue)); wsText += wszConst; break; case VT_UI1: swprintf(wszConst, L"%d", (int)V_UI1(&vConstValue)); wsText += wszConst; break; case VT_BSTR: { if(bQuoted) wsText += L"\""; //If we need to parse the string we do it the hard way WCHAR* pwc = V_BSTR(&vConstValue); BOOL bLongMethod = FALSE; for (int tmp = 0; pwc[tmp]; tmp++) if ((pwc[tmp] == L'\\') || (pwc[tmp] == L'"')) bLongMethod = TRUE; if (bLongMethod) { for(pwc; *pwc; pwc++) { if(*pwc == L'\\' || *pwc == L'"') wsText += L'\\'; wsText += *pwc; } } else { //otherwise we do it the fast way... wsText += pwc; } if(bQuoted) wsText += L"\""; } break; case VT_R4: swprintf(wszConst, L"%G", V_R4(&vConstValue)); wsText += wszConst; break; case VT_R8: swprintf(wszConst, L"%lG", V_R8(&vConstValue)); wsText += wszConst; break; case VT_BOOL: wsText += (V_BOOL(&vConstValue)?L"TRUE":L"FALSE"); break; } } break; case TOKEN_AND: wsText = "AND"; break; case TOKEN_OR: wsText = "OR"; break; case TOKEN_NOT: wsText = "NOT"; break; } return wsText.UnbindPtr(); } void QL_LEVEL_1_TOKEN::Dump(FILE *f) { switch (nTokenType) { case OP_EXPRESSION: fprintf(f, "OP_EXPRESSION "); break; case TOKEN_AND: fprintf(f, "TOKEN_AND "); break; case TOKEN_OR: fprintf(f, "TOKEN_OR "); break; case TOKEN_NOT: fprintf(f, "TOKEN_NOT "); break; default: fprintf(f, "Error: no token type specified\n"); } if (nTokenType == OP_EXPRESSION) { char *pOp = ""; switch (nOperator) { case OP_EQUAL: pOp = "OP_EQUAL"; break; case OP_NOT_EQUAL: pOp = "OP_NOT_EQUAL"; break; case OP_EQUALorGREATERTHAN: pOp = "OP_EQUALorGREATERTHAN"; break; case OP_EQUALorLESSTHAN: pOp = "OP_EQUALorLESSTHAN"; break; case OP_LESSTHAN: pOp = "OP_LESSTHAN"; break; case OP_GREATERTHAN: pOp = "OP_GREATERTHAN"; break; case OP_LIKE: pOp = "OP_LIKE"; break; } LPWSTR wszPropName = PropertyName.GetText(); if(wszPropName == NULL) return; fprintf(f, " Property = %S\n", wszPropName); delete [] wszPropName; fprintf(f, " Operator = %s\n", pOp); fprintf(f, " Value = "); if (m_bPropComp) { wszPropName = PropertyName2.GetText(); if(wszPropName == NULL) return; fprintf(f, " \n", wszPropName); delete [] wszPropName; } else { switch (V_VT(&vConstValue)) { case VT_I4: fprintf(f, "VT_I4 = %d\n", V_I4(&vConstValue)); break; case VT_I2: fprintf(f, "VT_I2 = %d\n", (int)V_I2(&vConstValue)); break; case VT_UI1: fprintf(f, "VT_UI1 = %d\n", (int)V_UI1(&vConstValue)); break; case VT_BSTR: fprintf(f, "VT_BSTR = %S\n", V_BSTR(&vConstValue)); break; case VT_R4: fprintf(f, "VT_R4 = %f\n", V_R4(&vConstValue)); break; case VT_R8: fprintf(f, "VT_R8 = %f\n", V_R8(&vConstValue)); break; case VT_BOOL: fprintf(f, "%S\n", V_BOOL(&vConstValue)?L"TRUE":L"FALSE"); break; case VT_NULL: fprintf(f, "%S\n", L"NULL"); break; default: fprintf(f, "\n"); } switch (dwPropertyFunction) { case IFUNC_NONE: break; case IFUNC_LOWER: fprintf(f, "Intrinsic function LOWER() applied to property\n"); break; case IFUNC_UPPER: fprintf(f, "Intrinsic function UPPER() applied to property\n"); break; } switch (dwConstFunction) { case IFUNC_NONE: break; case IFUNC_LOWER: fprintf(f, "Intrinsic function LOWER() applied to const value\n"); break; case IFUNC_UPPER: fprintf(f, "Intrinsic function UPPER() applied to const value\n"); break; } } } fprintf(f, " \n"); } ///////////////////////////////////////////////////////////////////////////// // // Algorithm for evaluating the expression, assuming that it has been // tokenized and translated to Reverse Polish. // // Starting point: (a) An array of QL tokens. // (b) An empty boolean token stack. // // 1. Read Next Token // // 2. If a SIMPLE EXPRESSION, evaluate it to TRUE or FALSE, and // place this boolean result on the stack. Go to 1. // // 3. If an OR operator, then pop a boolean token into A, // pop another boolean token into B. If either A or B are TRUE, // stack TRUE. Else stack FALSE. // Go to 1. // // 4. If an AND operator, then pop a boolean token into A, // and pop another into B. If both are TRUE, stack TRUE. // Else stack FALSE. // Go to 1. // // 5. If a NOT operator, reverse the value of the top-of-stack boolean. // Go to 1. // // At end-of-input, the result is at top-of-stack. // /////////////////////////////////////////////////////////////////////////////