//////////////////////////////////////////////////////////////////////////////// // / // 2012-2020 (c) Baical / // / // 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 3.0 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. / // / //////////////////////////////////////////////////////////////////////////////// #pragma once #define PR_USE_REGEXP #if defined(PR_USE_REGEXP) #pragma warning(disable : 4995 ) #include #include #endif //////////////////////////////////////////////////////////////////////////////// enum ePr_VType { EPR_VTYPE_UNK = -1, EPR_VTYPE_INT = 0, EPR_VTYPE_FLOAT , EPR_VTYPE_DATE , EPR_VTYPE_WTEXT , EPR_VTYPE_ENUM //user enumes +1, +2, +3, ... etc }; //////////////////////////////////////////////////////////////////////////////// enum ePr_Op { EPR_OP_UNK = -1, // EPR_OP_EQUAL = 0, //= EPR_OP_NOT_EQUAL , //!= EPR_OP_GREATER , //> EPR_OP_GREATER_OR_EQUAL , //>= EPR_OP_LESS , //< EPR_OP_LESS_OR_EQUAL , //<= EPR_OP_LEFT_INCLUDE , //<< EPR_OP_RIGHT_INCLUDE , //>> EPR_OP_LEFT_NOT_INCLUDE , // #if defined(PR_USE_REGEXP) EPR_OP_REG_EXP , //r= EPR_OP_WILD_CARD //w= #endif }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Op_Text { const tXCHAR *pText; tUINT32 dwLen; ePr_Op eType; ePr_Op eRevers; tBOOL bDigit; }; static const sPr_Op_Text g_pOperators[] = { { TM("<="), 2, EPR_OP_LESS_OR_EQUAL, EPR_OP_GREATER_OR_EQUAL, TRUE }, { TM("<<"), 2, EPR_OP_LEFT_INCLUDE, EPR_OP_RIGHT_INCLUDE, FALSE}, { TM(">>"), 2, EPR_OP_RIGHT_INCLUDE, EPR_OP_LEFT_INCLUDE, FALSE}, { TM(""), 2, EPR_OP_RIGHT_NOT_INCLUDE,EPR_OP_LEFT_NOT_INCLUDE, FALSE}, { TM("!="), 2, EPR_OP_NOT_EQUAL, EPR_OP_NOT_EQUAL, TRUE }, { TM(">="), 2, EPR_OP_GREATER_OR_EQUAL, EPR_OP_LESS_OR_EQUAL, TRUE }, { TM("="), 1, EPR_OP_EQUAL, EPR_OP_EQUAL, TRUE }, { TM(">"), 1, EPR_OP_GREATER, EPR_OP_LESS, TRUE }, { TM("<"), 1, EPR_OP_LESS, EPR_OP_GREATER, TRUE }, #if defined(PR_USE_REGEXP) { TM("r="), 2, EPR_OP_REG_EXP, EPR_OP_REG_EXP, FALSE}, { TM("w="), 2, EPR_OP_WILD_CARD, EPR_OP_WILD_CARD, FALSE}, #endif }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Var { tXCHAR *m_pName; ePr_VType m_eType; tUINT32 m_dwLength; //length of the text if it is tBOOL m_bUsed; union { tXCHAR *m_pValue; tUINT64 m_qwValue; double m_dbValue; }; sPr_Var(tXCHAR *i_pName, ePr_VType i_eType) : m_pName(NULL) , m_eType(i_eType) , m_dwLength(0) , m_bUsed(FALSE) , m_qwValue(0) //the largest value in union { tUINT32 l_dwLen = (i_pName) ? PStrLen(i_pName) : 0; if (l_dwLen) { m_pName = new tXCHAR[l_dwLen + 1]; if (m_pName) { PStrCpy(m_pName, l_dwLen + 1, i_pName); } } } ~sPr_Var() { if (m_pName) { delete [] m_pName; m_pName = NULL; } } }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Enum_Item { tXCHAR *m_pName; int m_iValue; sPr_Enum_Item(tXCHAR *i_pName, int i_iValue) : m_pName(NULL) , m_iValue(i_iValue) { tUINT32 l_dwLen = (i_pName) ? PStrLen(i_pName) : 0; if (l_dwLen) { m_pName = new tXCHAR[l_dwLen + 1]; if (m_pName) { PStrCpy(m_pName, l_dwLen + 1, i_pName); } } } ~sPr_Enum_Item() { if (m_pName) { delete [] m_pName; m_pName = NULL; } } }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Enum { tUINT32 m_dwID; CBList m_cItems; sPr_Enum(tUINT32 i_dwID) : m_dwID(i_dwID) {} ~sPr_Enum() { m_cItems.Clear(TRUE); } }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Group; struct sPr_Node { union { sPr_Group *m_pGroup; tXCHAR *m_pValue; tUINT64 m_qwValue; double m_dbValue; }; tBOOL m_bLink; //if TRUE we use m_pGroup, otherwise - values ePr_Op m_eOperator; tUINT32 m_dwLength; //length of the text if it is sPr_Var *m_pVariable; #if defined(PR_USE_REGEXP) QRegExp *m_pRE; #endif sPr_Node(); ~sPr_Node(); }; //////////////////////////////////////////////////////////////////////////////// struct sPr_OrGroup { CBList m_cNodes; ~sPr_OrGroup() { m_cNodes.Clear(TRUE); } }; //////////////////////////////////////////////////////////////////////////////// struct sPr_Group { CBList m_cOrGroups; ~sPr_Group() { m_cOrGroups.Clear(TRUE); } }; //////////////////////////////////////////////////////////////////////////////// //Normal class usage //1. Create child class with yours structure //2. Implement abstract function Set_Data() //3. Set variables list using Set_Variables() //4. If you are using enums - use Set_Enum() //5. Set predicate string - Set_Predicate() //6. Use Compare() to compare you structure using predicate // //See usage example at the end of this header file class CPredicate { protected: tXCHAR *m_pPr; tUINT32 m_dwPr_Max; tUINT32 m_dwPr_Len; CBList m_cVars; CBList m_cEnums; sPr_Group m_cGroup; tXCHAR m_cError[512]; public: CPredicate(); virtual ~CPredicate(); //////////////////////////////////////////////////////////////////////////// //Predicate (i_pPr) consist of next part //Variables - %MyVariable% //Constants - "0x20" possible values Int, Float, Date, String, Enum. Date // has simple format "DD.MM.YYYY HH:MM:SS.MS" //Atoms - atom is working block, you compare variable and constant. It // is not possible to compare 2 variables, only variable and // constant, next operators are available: "<=", "<<", ">>", "", "!=", ">=", "=", ">", "<". Operators "<<", ">>" used // only for text ("T1 << T2" - T1 contains T2) //Grouping - "(" and ")" //Operators - "&", "|" //Examples: //$Var1$ >="0x10" & "Text" >> $Var2$ //$Var1$ >="500" & ("Text" >> $Var2$ | "Text1" >> $Var2$) virtual tBOOL Set_Predicate(const tXCHAR *i_pPr); tXCHAR *Get_Error(); //////////////////////////////////////////////////////////////////////////// //Set_Variables() // i_dwCount - count of the variables, each variable has 2 values // tXCHAR - name of the variable, allowed any characters // ePr_VType - type of the variable // ... - variables (2 value: name & type) tBOOL Set_Variables(tUINT32 i_dwCount, ...); //////////////////////////////////////////////////////////////////////////// //Set_Enum() // i_dwEnum_ID - ID of the enum, EPR_VTYPE_ENUM, EPR_VTYPE_ENUM + 1, ... etc // i_dwCount - count of the enum values. Each value has 2 fields // tXCHAR - text value representation // int - int value representation // ... - enum values (2 fields: text & int) tBOOL Set_Enum(tUINT32 i_dwEnum_ID, tUINT32 i_dwCount, ...); tBOOL Check(const void *i_pData); protected: tBOOL Check(sPr_Group *i_pGroup); tBOOL Build(sPr_Group *i_pGroup, tUINT32 *io_pOffset); tBOOL Add_Node(CBList *i_pNodes, tUINT32 *io_pOffset); tBOOL Fill_Node(sPr_Node *i_pNode, tXCHAR *i_pVariable, tXCHAR *i_pConst ); tBOOL Is_True(sPr_Node *i_pNode); tBOOL Is_Sub(tXCHAR *i_pString, tUINT32 i_dwLenght, tXCHAR *i_pSearch, tUINT32 i_dwSub_Len ); //re-implement this function, you should get yours input structure and //every field put to the m_cVars list. virtual tBOOL Fill_Variables(const void *i_pData) = 0; }; //////////////////////////////////////////////////////////////////////////////// // Predicate Example //////////////////////////////////////////////////////////////////////////////// // // // enum eTest1 // { // ETEST1_ENUM0 = 0, // ETEST1_ENUM1 = 1, // ETEST1_ENUM2 = 2, // ETEST1_ENUM3 = 3 // }; // // struct sTest1 // { // tUINT32 m_dwInt; // eTest1 m_eEnum; // tXCHAR *m_pText; // }; // //////////////////////////////////////////////////////////////////////////////// // class CMy_Pred: // public CPredicate // { // public: // CMy_Pred(): // CPredicate() // { // Set_Variables(3, // TM("Int"), EPR_VTYPE_INT, //Index = 0; // TM("Enum"), EPR_VTYPE_ENUM + 0, //Index = 1; // TM("Text"), EPR_VTYPE_WTEXT //Index = 2; // ); // // Set_Enum(EPR_VTYPE_ENUM + 0, // 4, // TM("ENUM0"), 0, //ETEST1_ENUM0 = 0, // TM("ENUM1"), 1, //ETEST1_ENUM1 = 1, // TM("ENUM2"), 2, //ETEST1_ENUM2 = 2, // TM("ENUM3"), 3 //ETEST1_ENUM3 = 3 // ); // } // // protected: // BOOL Fill_Variables(void *i_pData) // { // sPr_Var *l_pVar = m_cVars[0];//Index = 0, first declared variable "Int" // if (l_pVar->m_bUsed) // { // l_pVar->m_qwValue = ((sTest1*)i_pData)->m_dwInt; // } // // l_pVar = m_cVars[1]; //Index = 1, second declared variable "Enum" // if (l_pVar->m_bUsed) // { // l_pVar->m_qwValue = ((sTest1*)i_pData)->m_eEnum; // } // // l_pVar = m_cVars[2]; //Index = 2, third declared variable "Text" // if (l_pVar->m_bUsed) // { // l_pVar->m_pValue = ((sTest1*)i_pData)->m_pText; // // //Very important to set Text length !!!! // if (l_pVar->m_pValue) // { // l_pVar->m_dwLength = PStrLen(l_pVar->m_pValue); // } // else // { // l_pVar->m_dwLength = 0; // } // } // return TRUE; // } // }; // //////////////////////////////////////////////////////////////////////////////// // int wmain(int i_iArgC, tXCHAR* i_pArgV[]) // { // CMy_Pred l_cPred; // sTest1 l_sTest = {10, ETEST1_ENUM2, TM("My Name")}; // // if (FALSE == l_cPred.Set_Predicate(TM("$Enum$ <= \"ENUM2\" & ($Int$ >= \"0x9\" | $Text$ >> \"Andrey is My Name\")"))) // { // wprintf(l_cPred.Get_Error()); // } // // if (l_cPred.Check(&l_sTest)) // { // wprintf(TM("TRUE\n")); // } // else // { // wprintf(TM("FALSE\n")); // } // // return 0; // }