/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998, Microsoft Corp. All rights reserved. // // FILE // // xprparse.cpp // // SYNOPSIS // // This file implements the function IASParseExpression. // // MODIFICATION HISTORY // // 02/06/1998 Original version. // 05/21/1999 Remove old style trace. // 03/23/2000 Use two quotes to escape a quote. // /////////////////////////////////////////////////////////////////////////////// #include #include #include #include ////////// // Struct for converting an identifier to a logical token. ////////// struct KeyWord { PCWSTR identifier; IAS_LOGICAL_TOKEN token; }; ////////// // Table of keywords. These must be sorted alphabetically. ////////// const KeyWord KEYWORDS[] = { { L"AND", IAS_LOGICAL_AND }, { L"FALSE", IAS_LOGICAL_FALSE }, { L"NOT", IAS_LOGICAL_NOT }, { L"OR", IAS_LOGICAL_OR }, { L"TRUE", IAS_LOGICAL_TRUE }, { L"XOR", IAS_LOGICAL_XOR }, { NULL, IAS_LOGICAL_NUM_TOKENS } }; ////////// // Returns the IAS_LOGICAL_TOKEN equivalent for 'key' or IAS_LOGICAL_NUM_TOKENS // if no such equivalent exists. ////////// IAS_LOGICAL_TOKEN findKeyWord(PCWSTR key) throw () { // We'll use a linear search since the table is so small. for (const KeyWord* i = KEYWORDS; i->identifier; ++i) { int cmp = _wcsicmp(key, i->identifier); // Did we find it ? if (cmp == 0) { return i->token; } // Did we we go past it ? if (cmp < 0) { break; } } return IAS_LOGICAL_NUM_TOKENS; } ////////// // Special characters for parsing. ////////// const WCHAR WHITESPACE[] = L" \t\n"; const WCHAR TOKEN_DELIMITERS[] = L" \t\n()"; ////////// // Parse a chunk of expression text and add it to the ExpressionBuilder. ////////// void addExpressionString(ExpressionBuilder& expression, PCWSTR szExpression) { ////////// // Make a local copy because parser can temporarily modify the string. ////////// size_t len = sizeof(WCHAR) * (wcslen(szExpression) + 1); Parser p((PWSTR)memcpy(_alloca(len), szExpression, len)); ////////// // Loop through the expression until we hit the null-terminator. ////////// while (*p.skip(WHITESPACE) != L'\0') { ////////// // Parentheses are handled separately since they don't have to be // delimited by whitespace. ////////// if (*p == L'(') { expression.addToken(IAS_LOGICAL_LEFT_PAREN); ++p; } else if (*p == L')') { expression.addToken(IAS_LOGICAL_RIGHT_PAREN); ++p; } else { // Get the next token. const wchar_t* token = p.findToken(TOKEN_DELIMITERS); // Check if it's a keyword. IAS_LOGICAL_TOKEN keyWord = findKeyWord(token); if (keyWord != IAS_LOGICAL_NUM_TOKENS) { // If it is a keyword, add it to the expression ... expression.addToken(keyWord); p.releaseToken(); } else { // If it's not a keyword, it must be a condition object. expression.addCondition(token); p.releaseToken(); // Skip the leading parenthesis. p.skip(WHITESPACE); p.ignore(L'('); // Skip the leading quote. p.skip(WHITESPACE); p.ignore(L'\"'); // We're now at the beginning of the condition text. p.beginToken(); // Find the trailing quote, skipping any escaped characters. while (p.findNext(L'\"')[1] == L'\"') { ++p; p.erase(1); } // Add the condition text. expression.addConditionText(p.endToken()); p.releaseToken(); // Skip the trailing quote p.ignore(L'\"'); // Skip the trailing parenthesis. p.skip(WHITESPACE); p.ignore(L')'); } } } } HRESULT WINAPI IASParseExpression( PCWSTR szExpression, VARIANT* pVal ) { if (szExpression == NULL || pVal == NULL) { return E_INVALIDARG; } VariantInit(pVal); try { ExpressionBuilder expression; addExpressionString(expression, szExpression); expression.detach(pVal); } catch (Parser::ParseError) { return E_INVALIDARG; } CATCH_AND_RETURN() return S_OK; } HRESULT WINAPI IASParseExpressionEx( IN VARIANT* pvExpression, OUT VARIANT* pVal ) { if (pvExpression == NULL || pVal == NULL) { return E_INVALIDARG; } // If the VARIANT contains a single BSTR, we can just use the method // defined above. if (V_VT(pvExpression) == VT_BSTR) { return IASParseExpression(V_BSTR(pvExpression), pVal); } VariantInit(pVal); try { ExpressionBuilder expression; if (V_VT(pvExpression) == VT_EMPTY) { // If the variant is empty, the expression is always false. expression.addToken(IAS_LOGICAL_FALSE); } else { CVariantVector values(pvExpression); for (size_t i = 0; i < values.size(); ++i) { // If we have more than one value, join them by AND's. if (i != 0) { expression.addToken(IAS_LOGICAL_AND); } if (V_VT(&values[i]) != VT_BSTR) { _com_issue_error(DISP_E_TYPEMISMATCH); } addExpressionString(expression, V_BSTR(&values[i])); } } expression.detach(pVal); } catch (Parser::ParseError) { return E_INVALIDARG; } CATCH_AND_RETURN() return S_OK; }