/***************************************************************************** emrule.h Owner: DaleG Copyright (c) 1992-1997 Microsoft Corporation General Rule-Network Propagation Engine functions and prototypes ---------------------------------------------------------------------------- NOTE: 1. BAD CODE, but it works: FIsDelayFactor(),LpruldependFromCDelay() and CDelayFromLpruldepend() rely upon the fact (?) that pointers on the machines we support are never (?) small integers. But if this should ever prove false, it would be bad. We should rewrite this to either have a RULDEP structure (as does the rule compiler), or make the list of dependencies indexes to rules, rather than pointers. *****************************************************************************/ #ifndef EMRULE_H #include "msodbglg.h" #include "emkwd.h" #include "emrulini.h" #include "emrultk.h" MSOEXTERN_C_BEGIN // ***************** Begin extern "C" ******************** // REVIEW: configure this in makefile, so emtest (for example) can build // debug without dynamic rules #ifdef DEBUG #ifndef YY_NODYNRULES #define DYN_RULES 1 #endif #endif /*---------------------------------------------------------------------------- System limits ----------------------------------------------------------------------------*/ #define wDelayMax 100 // Maximum delay poss #define irultkRuleMax 256 // Max events cached #define iruldepAllocMax 256 // Max ruldeps alloced #define ichRulNameMax 128 // Max trace name len #define ichRulNameAllocMax 1024 // Max name alloc /************************************************************************* Types: irul Rule node ID. ruldep Rule node dependency link. ruldepblk Rule node dependency link allocation structure. sv Split Value structure. rul Rule node structure. ruls Rule state structure. *************************************************************************/ /* I R U L */ /*---------------------------------------------------------------------------- %%Structure: IRUL %%Contact: daleg Rule Index definition ----------------------------------------------------------------------------*/ typedef short IRUL; #define IrulFromTk(tk) ((IRUL) (tk)) #define TkFromIrul(irul) (irul) // Lexer tokens: hard-coded rule node IDs #define irulERROR tkERROR #ifdef tkNil #define irulNil tkNil #else /* !tkNil */ #define irulNil 0 #endif /* tkNil */ // Is rule ID valid (not irulNil and not irulERROR) #define FValidIrul(irul) \ ((irul) > 0) /* R U L D E P */ /*---------------------------------------------------------------------------- %%Structure: RULDEP %%Contact: daleg Rule node dependency structure. This structure holds the dependency information that links a rule node to its dependents. ----------------------------------------------------------------------------*/ typedef struct _RULDEP { struct _MSORUL *prul; // Node referenced struct _RULDEP *pruldepNext; // Next dependency // int cDelay; // Delay in eval } RULDEP; MSOAPI_(RULDEP *) _MsoPruldepNew( // Alloc blk of deps int cruldep, int fOnFreeList ); // Return a new ruldep record from the free list (requires local var pruldep) // Operates in either sequential mode (vlpruls->lpruldepNextFree) or free list #define LpruldepNew() \ (vlpruls->lpruldepNextFree != NULL \ ? (vlpruls->fSeqentialFreeRuldeps \ ? vlpruls->lpruldepNextFree++ \ : (pruldep = vlpruls->lpruldepNextFree, \ vlpruls->lpruldepNextFree \ = pruldep->pruldepNext, \ pruldep->pruldepNext = NULL, \ pruldep)) \ : _MsoPruldepNew(iruldepAllocMax, TRUE)) // Push a ruldep record onto the free list #define PushLpruldepOnFreeList(pruldep) \ ((pruldep)->pruldepNext = vlpruls->lpruldepNextFree, \ vlpruls->lpruldepNextFree = (pruldep)) /* R U L D E P B L K */ /*---------------------------------------------------------------------------- %%Structure: RULDEPBLK %%Contact: daleg Rule node dependency allocation block structure. This structure allows us to batch-allocate RULDEP records. ----------------------------------------------------------------------------*/ typedef struct _RULDEPBLK { struct _RULDEPBLK *lpruldepblkNext; // Next block RULDEP rgruldep[1]; // Array of ruldeps } RULDEPBLK; /* R U L C X T */ /*---------------------------------------------------------------------------- %%Structure: RULCXT %%Contact: daleg (Rul)e (C)onte(x)t-group (T)able structure. This structure allows the rule engine to support cheap sparse dependents lists for special contexts. The callback function allows us to perform any desired side effects during the propagation, as well as offering the chance to optimize the lookup algorithm. ----------------------------------------------------------------------------*/ typedef struct _RULCXT { struct _RULCXT *lprulcxtNext; // Next context LPFNRULCXT lpfnrulcxt; // Callback fn int iruldepMax; // Size of array struct _RULCXL *rglprulcxl[1]; // Hash table } RULCXT; /* R U L C X L */ /*---------------------------------------------------------------------------- %%Structure: RULCXL %%Contact: daleg (Rul)e (C)onte(x)t-group (L)ist item structure. This is the item used in the hash table of the RULCXT above. ----------------------------------------------------------------------------*/ typedef struct _RULCXL { IRUL irul; // Rule ID struct _RULDEP *pruldep; // Dependent list struct _RULCXL *lprulcxlNext; // Next in hash chain } RULCXL; #ifdef DEBUG /* R U L N B L K */ /*---------------------------------------------------------------------------- %%Structure: RULNBLK %%Contact: daleg (Rul)e (N)ame block Store dynamically constructed rule names. ----------------------------------------------------------------------------*/ typedef struct _RULNBLK { struct _RULNBLK *lprulnblkNext; // Next block char rgch[1]; // Block of text } RULNBLK; char *LszGenNameForLprul( // Gen dyn rule name struct _MSORUL *prul, int irulAssert ); char *SzSaveRulName(char *szName); // Save node name sz char *LpchRulNameNew(int dichNeeded); // Get new name lpch #endif /* DEBUG */ /* M S O R U L */ /*---------------------------------------------------------------------------- %%Structure: MSORUL %%Contact: daleg Rule node structure. This structure holds the state information for a rule within the propagation network. ASSUMPTIONS: 1. The wDelayMask field only applies to rules, but it is (currently) faster to not have to test for whether a node is a rule, by merely leaving the field empty for values. ----------------------------------------------------------------------------*/ typedef long RULV; typedef struct _MSORUL *MSOPRUL; #pragma pack(2) typedef struct _MSORUL { IRUL irul; // Rule ID char rultType; // Type: rule/event char ipfnrulscSeqCheck; // Fn to ensure contig short rulevl; // Evaluation level short birulDependsOn; // Depends on: nodes SVL svl; // 32-bit storage area #ifdef DEBUG char const *lpchName; // Name or rule text #endif /* DEBUG */ IRUL irulNextChanged; // Next changed value union { short ipociiInstrs; // Interp instrs short USEME_IN_EVENTS; // Unsed slot }; short wIntervalCount; // Ensure contig seqs short wDelayMask; // Delays as bit pos's struct _MSORUL *prulNext; // Next node in queue #ifdef DEBUG IRUL irulNextTrace; // Next traced rule short wDebugFlags; // Random debug flags #endif /* DEBUG */ } MSORUL; #pragma pack() // Allocate new nodes MSOAPI_(MSORUL *) MsoPrulNew(void); // Allocate new node MSOAPI_(int) MsoFEnsureIrulAllocated(int irulMax); // Pre-allocated nodes // Discard an existing rul node #define DiscardIrul(irul) \ (vlpruls->irulLim--) #define msoprulNil ((MSORUL *) -1) // NIL value for MSORUL #define msoprulInactive ((MSORUL *) -2) // Node is deactivated #define wRulTrue 1000 #define wRulFalse 0 // Rule node type flags: shared with emrulini.h and rulc.h #define rultNil 0 #define rultRule 0x00 // Rule #define rultEvent 0x01 // Event/Variable #define rultPrimaryRule 0x02 // Rule auto-scheduled #define rultImmediateRule 0x04 // Rule executes immed #define rultPersistentRule 0x20 // Rule not cleared #define rultAlwaysPersist 0x40 // Rule never cleared #define rultSpecialKwd 0x80 // Node is generic type // Debug check that rule is not marked as both NonTerminal and Seq #define rultRuleMask 0x19 #ifdef NEVER #define FRultRuleIs(rult, rultExpected) \ (((rult) & rultRuleMask) == ((rultExpected))) #endif /* NEVER */ #ifdef DEBUG #define rultDynActionRule 0x04 // Dyn DEBUG only #define rultNonTermRule 0x08 // Dyn DEBUG only #define rultSeqRule 0x10 // Dyn DEBUG only #endif /* DEBUG */ /* R U L S */ /*---------------------------------------------------------------------------- %%Structure: RULS %%Contact: daleg Rule state structure. This structure holds the state information for the rule engine. ----------------------------------------------------------------------------*/ typedef int (WIN_CALLBACK *LPFNRul)(IRUL irul); // Rule Eval function typedef short (WIN_CALLBACK *PFNRULSC)(void); // Interval seq chk fn typedef int (*PFNRULVT)(IRUL irul); // Rule V-Table typedef struct _RULS { // Rule base limits RULLIMS rullims; // Rule base limits int irulMax; // Num nodes allocated int irulLim; // Num nodes used // Rule base state information RULDEP ***rgrgpruldepDependents; // List of Dep lists RULDEP **rgpruldepDependents; // Active Dep lists MSORUL **lrglprulBlk; // Array of node arrays int ilprulNodesLim; // #arrays of arrays #ifdef DEBUG MSORUL **rgprulNodes; // Debug node array #endif /* DEBUG */ const short *prulgAppendTo; // Group linkages const short *prulgAppendedFrom; // Group linkages short const *rgrulevlRulevt; // Event_type eval lvls int *rgrulevlRulevtLast; // Highest Q of rulevts MSORUL **rgprulActiveQueues; // Active eval queues MSORUL **rgprulDelayedQueues; // Delayed eval queues MSORUL *lprulQPersistent; // Temp Q: persistent int *rgirulRulevtChanged; // Nodes changed in evt int *rgrulevtEval; // Pending rulevt eval MSORULTKH *prultkhRulevtHistory; // Ev history for type long *rgdtkiRulevt; // #times enter rulevt const int *rgrulevtFromRulevl; // Trans lvls to evts const short *lpgrpirulDependBack; // Back dependencies LPFNRul lpfnEvalRule; // Evaluate rule code PFNRULSC const *rgpfnrulscSeqCheck; // Interval seq chk fns MSOKWTB **rgpkwtbKeyTables; // Keyword tables // Allocation information WORD fDynamicInit : 1; // Structs alloced? WORD fDynAlloced : 1; // vlpruls alloced? WORD fDependBackDynAlloced : 1; // Back deps alloced? WORD fRgDependDynAlloced : 1; // Dep lists alloced? WORD fDynRulesAlloced : 1; // Dyn rulebase alloc? WORD fRgrulevlRulevtAlloced : 1; // Last lvl tbl alloc? WORD fRgprulQueuesAlloced : 1; // Eval queues alloc? WORD fRgrulevtFromRulevlAlloced : 1; // Lvl-evt tbl alloc? WORD fRgprulNodesAlloced : 1; // DEBUG nd arr alloc? int rulgCurr; // Current rule group IRUL irulSelf; // irulSelf under eval MSORUL *prulEvent; // Event causing eval IRUL irulPrimaryEvent; // Primary ev of intvl RULDEP *lpruldepNextFree; // Next free dep rec RULDEPBLK *lpruldepblkDependBlocks; // List of dep blocks RULCXT *lprulcxtActive; // Active context list RULCXT **lrglprulcxtContexts; // List of cntx groups int rulevtCurr; // Current event_type int *prulevtEvalLim; // Num Ev types to eval MSORUL *lprulQueue; // Current queue int rulevlRultevtMin; // 1st eval lvl in evt int rulevlRulevtLast; // Last eval lvl in evt void *pociiDynRules; // Dyn-loaded rulebase #ifdef DEBUG char *lpchNames; // Name/string buf char const * const *rgpchDynNames; // Interp: node names int irulQTrace; // Backtrace list int dichNameFree; // Num chars avail char *lpchNameNextFree; // Next free name rgch RULNBLK *lprulnblkNames; // Dyn name list #endif /* DEBUG */ // Run-time flags WORD fInited : 1; // Rule base inited? WORD fNew : 1; // Rule base new? WORD fSeqentialFreeRuldeps : 1; // Free ruldeps are seq WORD fEvaluatingDeferred : 1; // Evaling deferred nd? WORD fEvaluating: 1; // Eval recursion check // Multiple Rule base support struct _RULS *lprulsNext; // Next struct LIFO // Allocation info WORD fAllocedSpare1 : 1; WORD fAllocedSpare2 : 1; WORD fAllocedSpare3 : 1; WORD fAllocedSpare4 : 1; WORD fAllocedSpare5 : 1; WORD fAllocedSpare6 : 1; WORD fAllocedSpare7 : 1; WORD fAllocedSpare8 : 1; WORD fAllocedSpare9 : 1; WORD fAllocedSpare10 : 1; WORD fAllocedSpare11 : 1; int ilprulNodesAllocFirstLim; // Start alloc'd nds +1 long lReturn; // Return value LPV lpvSpare3; LPV lpvSpare4; LPV lpvSpare5; LPV lpvSpare6; LPV lpvSpare7; LPV lpvSpare8; LPV lpvSpare9; LPV lpvSpare10; LPV lpvSpare11; // Debug logging #ifdef DEBUG unsigned int grfDebugLogFilter; // DEBUG: how to log #endif /* DEBUG */ #ifdef DYN_RULES // Dynamically-loaded rulebase support struct _MSOOCIS *pocis; // Op-Code Interp State short irulRuleInterpLim; // #Interpreted rules short irulRuleInterpMac; // #Alloced inter ptrs void **rgpociiRules; // Rule instructions #endif /* DYN_RULES */ } RULS; extern RULS *vlpruls; // Global rule state //---------------------------------------------------- // If using debugger, an rulebase node's value is given by: // rulv_ == vlpruls->rgprulNodes[irul]->svl.lValue // // Or if the rulebase is statically initialized, and // DEBUG_RULE_POINTERS is #defined then // event FOO can be accessed as *prulFOO and // rule 126 can be accessed as *prul126 //---------------------------------------------------- // Return the number of rules in rule base #define IrulMax() (vlpruls->irulMax) // Return the number of compiled rules in rule base #define IrulCompiledMax() (vlpruls->rullims.irulRulesMax) // Return the number of event_types in rule base #define RulevtMax() RulevtMaxPruls(vlpruls) // Return the number of event_types in rule base #define RulevtMaxPruls(pruls) \ ((pruls)->rullims.rulevtMax) // Return the number of evaluation levels in rule base #define RulevlMax() RulevlMaxPruls(vlpruls) // Return the number of evaluation levels in rule base #define RulevlMaxPruls(pruls) \ ((pruls)->rullims.rulevlMax) #define irulMaxAlloc 128 // Max nodes/array #define cbfIrulShift 7 // #bits irulMaxAlloc #define wIrulMask 0x7F // Mask: irulMaxAlloc #define ilprulMaxAlloc 256L // Max arrays of arrys ///#define irulMaxAlloc 2048 // Max nodes/array ///#define cbfIrulShift 11 // #bits irulMaxAlloc ///#define wIrulMask 0x7FF // Mask: irulMaxAlloc ///#define ilprulMaxAlloc 100L // Max arrays of arrys ///#define irulMaxAlloc 1024 // Max nodes/array ///#define cbfIrulShift 10 // #bits irulMaxAlloc ///#define wIrulMask 0x3FF // Mask: irulMaxAlloc ///#define ilprulMaxAlloc 100L // Max arrays of arrys // Return the rule node structure pointer for the rule ID #define LprulFromIrul(irul) \ (&vlpruls->lrglprulBlk \ [(irul) >> cbfIrulShift] [(irul) & wIrulMask]) // Return the rule ID of the rule node structure pointer #define IrulFromLprul(prul) \ ((prul)->irul) // Return the Lim irul value for iruls that are contiguous with the irul #define IrulLimContig(irul) \ ((((irul) >> cbfIrulShift) << cbfIrulShift) + irulMaxAlloc) // Return whether rule node is a primary rule #define FPrimaryRule(prul) ((prul)->rultType & rultPrimaryRule) #ifdef NEVER // Return whether rule node is a action rule #define FActionRule(prul) ((prul)->wDebugFlags & rultActionRule) #endif /* NEVER */ #ifdef DEBUG // Return whether rule node is a non-terminal rule (then) #define FNonTermRule(prul) ((prul)->wDebugFlags & rultNonTermRule) // Return whether rule node is a sequence rule (...) #define FSeqRule(prul) ((prul)->wDebugFlags & rultSeqRule) #endif /* DEBUG */ // Return whether the node ID refers to an event node #define FIsEventIrul(irul) FIsEventPrul(LprulFromIrul(irul)) // Return whether the node is an event node #define FIsEventPrul(prul) ((prul)->rultType & rultEvent) // Return whether the node is a rule node #define FIsRulePrul(prul) (!FIsEventPrul(prul)) #define IMMEDIATE_RULES #ifdef IMMEDIATE_RULES // Return whether rule node is a sequence rule (...) #define FImmediateRulePrul(prul) ((prul)->rultType & rultImmediateRule) #endif /* IMMEDIATE_RULES */ // Return whether the node is an *undefined* event #define FSpecialKwdIrul(irul) \ FSpecialKwdLprul(LprulFromIrul(irul)) // Return whether the node is an *undefined* event #define SetFSpecialKwdIrul(irul) \ SetFSpecialKwdLprul(LprulFromIrul(irul)) // Return whether the node is an *undefined* event #define FSpecialKwdLprul(prul) ((prul)->rultType & rultSpecialKwd) // Return whether the node is an *undefined* event #define SetFSpecialKwdLprul(prul) \ ((prul)->rultType |= rultSpecialKwd) // Return whether rule node can persist in delayed queue in soft resets #define FPersistentLprul(prul) \ ((prul)->rultType & rultPersistentRule) // Mark that rule node can persist in delayed queue in soft resets #define SetFPersistentIrul(irul) \ SetFPersistentLprul(LprulFromIrul(irul)) // Mark that rule node can persist in delayed queue in soft resets #define SetFPersistentLprul(prul) \ ((prul)->rultType |= rultPersistentRule) // Return whether rule node can persist in delayed queue in all resets #define FAlwaysPersistLprul(prul) \ ((prul)->rultType & rultAlwaysPersist) // Mark that rule node can persist in delayed queue in all resets #define SetFAlwaysPersistIrul(irul) \ SetFAlwaysPersistLprul(LprulFromIrul(irul)) // Mark that rule node can persist in delayed queue in all resets #define SetFAlwaysPersistLprul(prul) \ ((prul)->rultType |= rultAlwaysPersist) // Return whether rule node can persist in delayed queue #define FPersistLprulGrf(prul, grf) \ ((prul)->rultType & (grf)) // Return the value for the current rule #define RulvSelf() \ RulvOfIrul(irulSelf) // Set the value for the current rule #define SetRulvSelf(rulv) \ SetRulvOfIrul(irulSelf, (rulv)) // Increment the value for the current rule #define IncrRulvSelf(drulv) \ IncrRulvOfIrul(irulSelf, (drulv)) // Return the value1 for the current rule #define Rulv1Self() \ Rulv1OfIrul(irulSelf) // Set the value1 for the current rule #define SetRulv1Self(rulv) \ SetRulv1OfIrul(irulSelf, (rulv)) // Increment the value1 for the current rule #define IncrRulv1Self(drulv) \ IncrRulv1OfIrul(irulSelf, (drulv)) // Return the value2 for the current rule #define Rulv2Self() \ Rulv2OfIrul(irulSelf) // Set the value2 for the current rule #define SetRulv2Self(rulv) \ SetRulv2OfIrul(irulSelf, (rulv)) // Increment the value2 for the current rule #define IncrRulv2Self(drulv) \ IncrRulv2OfIrul(irulSelf, (drulv)) // Return the value for the rule ID #define RulvOfIrul(irul) \ (LprulFromIrul(irul)->svl.lValue) // Set the value for the rule ID #define SetRulvOfIrul(irul, rulv) \ (LprulFromIrul(irul)->svl.lValue = (rulv)) // Increment the value1 field for the rule ID #define IncrRulvOfIrul(irul, drulv) \ IncrRulvOfLprul(LprulFromIrul(irul), (drulv)) // Return the lValue field for a rule node #define RulvOfLprul(prul) ((prul)->svl.lValue) // Set the lValue field for a rule node #define SetRulvOfLprul(prul, w) ((prul)->svl.lValue = (w)) // Increment the value1 field for a rule node #define IncrRulvOfLprul(prul, drulv) ((prul)->svl.lValue += (drulv)) // Set the value for the rule ID #define PlValueOfIrul(irul) \ (&LprulFromIrul(irul)->svl.lValue) // Return the value1 field for the rule ID #define Rulv1OfIrul(irul) \ Rulv1OfLprul(LprulFromIrul(irul)) // Set the value1 field for the rule ID #define SetRulv1OfIrul(irul, rulv) \ SetRulv1OfLprul(LprulFromIrul(irul), (rulv)) // Increment the value1 field for the rule ID #define IncrRulv1OfIrul(irul, drulv) \ IncrRulv1OfLprul(LprulFromIrul(irul), (drulv)) // Return the value2 field for the rule ID #define Rulv2OfIrul(irul) \ Rulv2OfLprul(LprulFromIrul(irul)) // Set the value2 field for the rule ID #define SetRulv2OfIrul(irul, rulv) \ SetRulv2OfLprul(LprulFromIrul(irul), (rulv)) // Increment the value2 field for the rule ID #define IncrRulv2OfIrul(irul, drulv) \ IncrRulv2OfLprul(LprulFromIrul(irul), (drulv)) // Return the value1 field for a rule node #define Rulv1OfLprul(prul) W1OfPsv(PsvOfLprul(prul)) // Set the value1 field for a rule node #define SetRulv1OfLprul(prul, w) SetW1OfPsv(PsvOfLprul(prul), (w)) // Increment the value1 field for a rule node #define IncrRulv1OfLprul(prul, dw) IncrW1OfPsv(PsvOfLprul(prul), (dw)) // Return the value2 field for a rule node #define Rulv2OfLprul(prul) W2OfPsv(PsvOfLprul(prul)) // Set the value2 field for a rule node #define SetRulv2OfLprul(prul, w) SetW2OfPsv(PsvOfLprul(prul), (w)) // Increment the value2 field for a rule node #define IncrRulv2OfLprul(prul, dw) IncrW2OfPsv(PsvOfLprul(prul), (dw)) // Return the Split Value pointer of a node #define PsvOfLprul(prul) (&(prul)->svl.sv) // Return the value1 field for an rule node #define Rulv1(rulv) W1OfPsv((SV *) &(rulv)) // Set the value1 field for a node #define SetRulv1(rulv, w) SetW1OfPsv(((SV *) &(rulv)), (w)) // Return the value2 field #define Rulv2(rulv) W2OfPsv((SV *) &(rulv)) // Set the value2 field for a node #define SetRulv2(rulv, w) SetW2OfPsv(((SV *) &(rulv)), (w)) // Return the confidence value of a node node #define WConfidence(prul) Rulv1OfLprul(prul) // Set the confidence value of a node node #define SetConfidence(prul, wValue) SetRulv1OfLprul((prul), (wValue)) // Return the doubt value of a node node #define WDoubt(prul) Rulv2OfLprul(prul) // Set the doubt value of a node node #define SetDoubt(prul, wValue) SetRulv2OfLprul((prul), (wValue)) // OBSOLETE FORMS OF MACROS #define WValueOfIrul(irul) RulvOfIrul(irul) #define SetWValueOfIrul(irul, rulv) SetRulvOfIrul(irul, rulv) #define WRulValue1(prul) Rulv1OfLprul(prul) #define SetWRulValue1(prul, w) SetRulv1OfLprul((prul), (w)) #define WRulValue2(prul) Rulv2OfLprul(prul) #define SetWRulValue2(prul, w) SetRulv2OfLprul((prul), (w)) // Return the rule node for the rule value #define LprulOfWValue(lplValue) \ ((MSORUL *) \ (((char *) lplValue) - CchStructOffset(MSORUL, svl.lValue))) #ifdef DEBUG // Return the value name or rule text of the rule node structure pointer #define LpchRulName(prul) ((prul)->lpchName) // Return the value name or rule text of the rule node structure pointer #define LpchIrulName(irul) LpchRulName(LprulFromIrul(irul)) // Return debug rule name for dynamic rule #define PszNameDynLprul(prul) \ (vlpruls->rgpchDynNames[(prul)->irul - IrulCompiledMax()]) #endif /* DEBUG */ // Return the node evaluation level for the node #define RulevlOfPrul(prul) \ (prul->rulevl) // Return the event_type for the node #define RulevtOfLprul(prul) \ RulevtOfRulevl(RulevlOfPrul(prul)) // Return the event_type for the evaluation level #define RulevtOfRulevl(rulevl) \ (vlpruls->rgrulevtFromRulevl[rulevl]) // Return the rule queue of the rule level #define LplprulQueueOf(rulevl) (&vlpruls->rgprulActiveQueues[rulevl]) // Return the delayed-evaluation rule queue of the event_type #define LplprulDelayedQueueOf(rulevt) \ (&vlpruls->rgprulDelayedQueues[rulevt]) // Return the minimum evaluation level of the event_type #define RulevlMinOfRulevt(rulevt) \ (vlpruls->rgrulevlRulevt[(rulevt)]) // Return the maximum evaluation level of the event_type #define RulevlMaxOfRulevt(rulevt) \ (vlpruls->rgrulevlRulevt[(rulevt) + 1]) // Return the list of dependent node references of node ID #define LpruldepFromIrul(irul) \ (vlpruls->rgpruldepDependents[irul]) // Return the list of dependent node references of node #define LpruldepGetDependents(prul) \ LpruldepFromIrul(IrulFromLprul(prul)) // Set the list of dependent node references of node ID #define SetLpruldepFromIrul(irul, pruldep) \ (vlpruls->rgpruldepDependents[irul] = (pruldep)) // Set the list of dependent node references of node #define LpruldepSetDependents(prul, pruldep) \ SetLpruldepFromIrul(IrulFromLprul(prul), (pruldep)) // Return the list of dependent node references of node ID for specific group #define LpruldepFromRulgIrul(rulg, irul) \ (*LplpruldepForRulgIrul(rulg, irul)) // Set the list of dependent node references of node ID for specific group #define SetLpruldepFromRulgIrul(rulg, irul, pruldep) \ (*LplpruldepForRulgIrul(rulg, irul) = (pruldep)) // Return the address of the start of a ruldep list for the irul and group #define LplpruldepForRulgIrul(rulg, irul) \ (&(vlpruls->rgrgpruldepDependents[rulg][irul])) // Return whether a dependent reference is in fact a delay specfication #define FIsDelayFactor(lprulDepend) \ ((unsigned long) (lprulDepend) < wDelayMax) // Return the delay value associated with the dependency record #define CDelayFromLpruldepend(lprulDepend) \ ((int) ((unsigned long) lprulDepend)) // Return a dependency record to represent the delay factor #define LpruldependFromCDelay(cDelay) \ ((MSORUL *) (cDelay)) // Add a delay to the delay field of a delayed rule #define AddCDelayToLprul(prul, cDelay) \ ((prul)->wDelayMask |= (cDelay)) // Return whether a rule has any delay factor #define FHaveCDelay(prul) \ ((prul)->wDelayMask) // Return whether a rule has a specific delay factor #define FHaveCDelayOf(prul, cDelay) \ ((prul)->wDelayMask & (cDelay)) // Decrement the node's delay counts (by shifting right) #define DecrementCDelaysOfLprul(prul) \ ((prul)->wDelayMask >>= 1) // Return whether the (event) node is marked for history recording #define FHistoryRecordLprul(prul) \ (TRUE) // First version // ((prul)->fRecordHistory) // Correct version // Return whether node must check interval counts to detect seq discontinuities #define FIntervalsSeqCheckedPrul(prul) \ ((prul)->ipfnrulscSeqCheck) // Return interval counts associated with node that has sequence checking #define WIntervalsSeqCheckedPrul(prul) \ ((*vlpruls->rgpfnrulscSeqCheck[(prul)->ipfnrulscSeqCheck])()) // Return whether the rule base is initialized #define FRulesInited(lpruls) (lpruls != NULL && lpruls->fInited) // Return the op-code instructions for an interpreted rule ID #define PociiForIrul(irul) \ PociiForPrul(LprulFromIrul(irul)) // Return the op-code instructions for an interpreted rule #define PociiForPrul(prul) \ ((MSOOCII *) vlpruls->rgpociiRules[((prul)->ipociiInstrs)]) // Return any group(s) that append(s) the current group #define RulgAppendedFrom(rulg) \ (vlpruls->prulgAppendedFrom[rulg]) // Return the list of groups that append from other groups #define PrulgAppendedFrom() \ (vlpruls->prulgAppendedFrom) // Return the group (if any) that the current group appends to #define RulgAppendTo(rulg) \ (vlpruls->prulgAppendTo[rulg]) // Return the list of groups that append to other groups #define PrulgAppendTo() \ (vlpruls->prulgAppendTo) #define rulgNil (-1) // "No" rule group #define rulevtNil (-1) // "No" event type #ifdef DEBUG // Return whether node is marked for automatic backtracing */ #define FTraceLprul(prul) \ ((prul)->irulNextTrace != 0) #endif /* DEBUG */ // Return the list of nodes that current node depends upon #define LpirulGetDependsOn(prul) \ (&vlpruls->lpgrpirulDependBack[(prul)->birulDependsOn]) /************************************************************************* Prototypes and macros for rule.c *************************************************************************/ #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif /* !max */ #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif /* !max */ // Push the node onto the queue #define PushLprul(prul, lplprulQ) \ ((prul)->prulNext = *(lplprulQ), \ *(lplprulQ) = (prul)) // Pop the node from the queue into the variable #define PopLprul(lplprul, lplprulQ) \ (*lplprul = *lplprulQ, \ *lplprulQ = (*lplprul)->prulNext, \ (*lplprul)->prulNext = 0) // Push event node into Auto-Clear (Changed) list #define PushLpRulChanged(prul) \ if ((prul)->irulNextChanged == 0) \ { \ int rulevt = RulevtOfLprul(prul); \ \ (prul)->irulNextChanged \ = vlpruls->rgirulRulevtChanged[rulevt]; \ vlpruls->rgirulRulevtChanged[rulevt] = IrulFromLprul(prul); \ } // Mark event as never Auto-Clearing #define SetNoAutoClearRulv(rulv) \ (LprulFromRulv(rulv)->irulNextChanged = irulNoAutoClear) #define SetNoAutoClearLprul(prul) \ ((prul)->irulNextChanged = irulNoAutoClear) #define irulChangedNil -1 #define irulNoAutoClear -2 // Return the offset of a field from the start of its typedef'd structure // NOTE: THIS IS TRICKY CODE, BUT COMPLETELY LEGAL C!! // To understand it, remember that 0 is a valid pointer for ALL types! #define CchStructOffset(type, field) \ (((char *) (&((type *) 0)->field)) - ((char *) 0)) // Call Rule Evaluation function provided by Application #define FEvalRule(irul) \ (*vlpruls->lpfnEvalRule)(irul) #ifndef STATIC_LINK_EM MSOAPI_(RULS **) MsoPvlprulsMirror(RULS **pvlprulsApp); // Exchange &vlpruls #else /* STATIC_LINK_EM */ #define MsoPvlprulsMirror(pvlprulsApp) pvlprulsApp #endif /* !STATIC_LINK_EM */ MSOAPI_(int) MsoFInitRules( // Init rule base LPFNRulinit lpfnRulInit, RULS *lpruls ); IRUL IrulDefineEvent(int rulevt, char *szName); // Define simple event MSOAPI_(MSOKWD *) MsoFDefineStringKwdEvent( // Define str kwd event int rulevt, char *szName, XCHAR *pxch, int cch, int ikwtb ); MSOAPI_(MSOKWDLH *) MsoFDefineIntegerKwdEvent( // Define int kwd event int rulevt, char *szName, long lValue, int ikwtb ); MSOAPI_(void) MsoClearRules(void); // Clear nodes & state MSOAPI_(void) MsoClearEventsForRulevts( // Clr rg of ev types int rulevtFirst, int drulevtCount, int fSavePersistentDelayed, int fClearChanged, int fClearIntervalCounts ); MSOAPI_(void) MsoRestorePersistentDelayedRules(void); // Restore delayed Q MSOAPI_(int) MsoFAddPruldepDependent( // Add dependent link IRUL irul, MSORUL *prulDependent, int cDelay, int rulg ); MSOAPI_(void) MsoFixUpPruldeps( // Fix up after insert IRUL irul, int rulg, int rulgBase, RULDEP *lpruldepOldList, RULDEP *lpruldepNewList ); MSOAPI_(int) MsoFDelPruldepDependent( // Del dependent link IRUL irul, MSORUL *prulDependent, int rulg, int fDiscard ); MSOAPI_(void) MsoSetActiveRuls(RULS *pruls); // Set curr vlpruls MSOAPI_(void) MsoFreeRuleMem(RULS *pruls); // Free rule memory #ifdef OFFICE_BUILD MSOAPI_(void) MsoMarkRuleMem(RULS *pruls); // Mark rule mem used #endif /* OFFICE_BUILD */ MSOAPI_(void) MsoSetEventTypeRulevt(int rulevt); // Change event_types MSOAPI_(void) MsoClearChangedEventsForRulevt(int rulevt);// Clr event_type vals void RemoveLprulChanged(MSORUL *prul); // Un-auto-clear event MSOAPI_(int) MsoEvaluateEvents(int rulevt); // Event evaluation MSOAPI_(int) MsoFEvalIrul(IRUL irul); // Eval single node MSOAPI_(void) MsoDelaySignalIrul( // Signal node w/delay IRUL irul, long lValue, int cDelay ); MSOAPI_(void) MsoDelaySignalIrulFrom( // Signal node w/delay IRUL irul, IRUL irulFrom, int cDelay ); MSOAPI_(void) MsoSignalIrul(IRUL irul, long lValue); // Cond schedule irul #define PushIrulToEval(irul, lValue) \ MsoSignalIrul(irul, lValue) MSOAPI_(void) MsoScheduleIrul(IRUL irul, long lValue); // Schedule rule to run #ifdef DEBUG MSOAPI_(void) MsoScheduleIrulDebug(IRUL irul, long lValue);// Log and schedule MSOAPI_(void) MsoScheduleIrulDebugMso(IRUL irul, long lValue);//Log &sched MSO #else #define MsoScheduleIrulDebug MsoScheduleIrul #define MsoScheduleIrulDebugMso MsoScheduleIrul #endif /* DEBUG */ MSOAPI_(void) MsoDelayScheduleIrul( // Schedule after delay IRUL irul, long lValue, int cDelay ); #ifdef DEBUG MSOAPI_(void) MsoDelayScheduleIrulDebug( // Log and schedule IRUL irul, long lValue, int cDelay ); #else #define MsoDelayScheduleIrulDebug MsoDelayScheduleIrul #endif /* DEBUG */ MSOAPI_(void) MsoDelayScheduleIrulFrom( // Sched, pass value IRUL irul, IRUL irulFrom, int cDelay ); MSOAPI_(int) MsoFEvalIrulImmediately( // Eval irul now IRUL irul, long lValue ); MSOAPI_(void) MsoPushLprulDependents(MSORUL *prul); // Push dependents MSOAPI_(void) MsoPushDelayedEvalForRulevt(int rulevt); // Push delayed nodes MSOAPI_(void) MsoAutoClearIrul(IRUL irul); // Mark node for clear MSOAPI_(int) MsoFAliasPrulPrul( // Ret if 2 are aliases MSORUL *prul, MSORUL *prulTarget ); void RecordLprulHistory(MSORUL *prul); // Push ev into hist #ifdef NEVER MSOAPI_(int) MsoFIrulHistoryValueWas( // Look 4 event in hist int dirultkBackwards, long *lpwVar ); #endif // NEVER #ifdef NEED_AS_FUNCTION void SetCurrRulg(int rulgGroup); // Set rule group #endif /* NEED_AS_FUNCTION */ MSOAPI_(void) MsoSignalEventIrul(IRUL irul, long lValue);// Signal an event MSOAPI_(void) MsoSignalEventIrulFrom( // Signal ev from node IRUL irul, IRUL irulFrom ); #ifdef NEVER MSOAPI_(void) MsoSetRuleConfid(IRUL irul, int wFactor); // Set confidence val #endif // NEVER // Schedule a node for deferred evaluation, based upon a decision rule // This macro gets invoked twice. See _MsoFDeferIrul() for details. #define FDeferIrul(irul) \ (vlpruls->fEvaluatingDeferred || _MsoFDeferIrul(irul)) #define FDeferIrulExpr(irul, lExpr) \ (vlpruls->fEvaluatingDeferred \ || (((int) lExpr) && _MsoFDeferIrul(irul))) #define FDeferIrulExprL(irul, lExpr, lValue) \ (vlpruls->fEvaluatingDeferred \ || (((int) lExpr) && _MsoFDeferIrulL((irul), (lValue)))) #define IrulPickDeferred(irulDecision) \ MsoIrulPickDeferred(irulDecision) MSOAPI_(int) _MsoFDeferIrul(IRUL irul); // Add to defer list MSOAPI_(int) _MsoFDeferIrulL(IRUL irul, long lValue); // Add to defer w/value MSOAPI_(IRUL) MsoIrulPickDeferred(IRUL irulDecision); // Pick from defer list MSOAPI_(void) MsoSetRulNotify( // Set up notification long lExprValue, // Really an int IRUL irulDecision, IRUL irulNotify ); MSOAPI_(int) MsoFRulNotify(long wNotify); // Notify on next eval MSOAPI_(int) MsoFRulNotifyImmediately(long wNotify); // Notify immediately MSOAPI_(long) MsoRulvElement(IRUL irulArray, IRUL iirul);// Get value of array MSOAPI_(void) MsoSetElementRulv( // Set value of array IRUL irulArray, IRUL iirul, long lValue ); MSOAPI_(void) MsoSetAllElementsToRulv( // Set all vals of arr IRUL irulArray, IRUL cirul, long lValue ); /* M S O F A C T I V A T E I R U L */ /*---------------------------------------------------------------------------- %%Function: MsoFActivateIrul %%Contact: daleg Activate a node in the rulebase ----------------------------------------------------------------------------*/ _inline int MsoFActivateIrul(IRUL irul) // Activate a node { MSOPRUL prul = LprulFromIrul(irul); if (prul->prulNext == msoprulInactive) { prul->prulNext = (MSOPRUL) NULL; return TRUE; } else return FALSE; } /* M S O F D E A C T I V A T E I R U L */ /*---------------------------------------------------------------------------- %%Function: MsoFDeactivateIrul %%Contact: daleg Deactivate a node in the rulebase ----------------------------------------------------------------------------*/ MSOAPI_(int) _MsoFDeactivateIrul(IRUL irul); // Deactivate a node _inline int MsoFDeactivateIrul(IRUL irul) { MSOPRUL prul = LprulFromIrul(irul); if (prul->prulNext == NULL) { prul->prulNext = msoprulInactive; return TRUE; } else return _MsoFDeactivateIrul(irul); } MSOAPI_(int) MsoFDeleteIrul(IRUL irul, int rulg); // Delete a node /************************************************************************* Prototypes and macros for rultest.c and rulconcl.c. These prototypes "Hungarianize" the rule code so that the rule authors do not have to know Hungarian, but it is preserved within the application code. *************************************************************************/ // Return the current interval number for the event_type #define CIntervalsRulevt(rulevt) \ (vlpruls->rgdtkiRulevt[rulevt]) // OBSOLETE: Return the current interval number for the event_type #define CIntervalsRsct(rulevt) CIntervalsRulevt(rulevt) // Increment the current interval number for the event_type #define IncrIntervalsRsct(rulevt, dc) \ (vlpruls->rgdtkiRulevt[rulevt] += (dc)) #ifdef NEVER // Set long value of a node and force propagation #define SetValue(wVar, lValue) \ SignalEvent(wVar, lValue) #endif /* NEVER */ // Convert a "variable" event reference to an node address #define LprulFromRulv(rulvVar) \ LprulOfWValue(&(rulvVar)) // Notify a node, on its next evaluation pass #define FNotify(rgwVar) \ MsoFRulNotify(rgwVar) // Notify an action rule, immediately #define FNotifyImmediately(rgwVar) \ MsoFRulNotifyImmediately(rgwVar) // Indicate the next event_type to enter when current event_type is exited #define SetNextEventType(rulevt) \ if (vlpruls->prulevtEvalLim \ < vlpruls->rgrulevtEval + RulevtMax()) \ (*vlpruls->prulevtEvalLim++ = (rulevt)); \ else \ AssertSz0(FALSE, "Exceeded max number of rulevts to eval"); // Force delayed evaluation of rule of given ID: GENERATED BY RULE COMPILER #define DelayEvalIrul(irul, cDelay) \ MsoDelayScheduleIrulFrom((irul), (irul), (cDelay)) // Return whether the dirultkBackwards'th previous value was the given event #define ValueWas(dirultkBackwards, wVar) \ MsoFIrulHistoryValueWas(dirultkBackwards, &(wVar)) // Find the given value in its event_type history, and return the (neg) offset #define FindPrevValueFrom(dirultkBackwards, wVar) \ DirultkFindPrevValueFrom(dirultkBackwards, &(wVar)) // Mark event/rule for automatic clearing on event_type exit #define AutoClear(irul) \ MsoAutoClearIrul(irul) // Mark expression as exempt from dependency linkage in rule if #define Value(expr) (expr) // Push all dependents of node of ID onto their evaluation queues #define Propagate(irul) \ MsoPushLprulDependents(LprulFromIrul((int) irul)) // Evaluate the rule at normal time #define GoToRule(irul) \ MsoDelayScheduleIrul((irul), TRUE, 0 /* cDelay */) // Evaluate the rule at normal time #define GoToIrul(irul) \ MsoDelayScheduleIrulFrom((IRUL) (irul), (irulSelf), 0 /* cDelay */) // Evaluate the rule after delay of 1, incrementing value #define GoToIrulNoValue(irul) \ MsoDelayScheduleIrulFrom \ ((IRUL) (irul), (IRUL) (irul), 1 /* cDelay */) // Evaluate the rule at normal time #define GoToDirul(dirul) \ MsoDelayScheduleIrulFrom \ ((IRUL) (irulSelf) + (dirul), (irulSelf), 0 /* cDelay */) // Evaluate the rule after delay of 1 #define DelayGoToRule(irul) \ DelayGoToIrulNoValue(irul) // Signal the event with the given value #define SignalIrul(irul, lValue) \ MsoSignalIrul(irul, lValue) // Signal the event with the given value #define SignalEvent(wVar, lValue) \ MsoSignalEventIrul(IrulFromLprul(LprulFromRulv(wVar)), (lValue)) // Signal the event with the given value #define SignalEventIrul(irul, lValue) \ MsoSignalEventIrul(irul, lValue) // Signal the node with the value from the current rule // REVIEW: THIS IS WRONG, NOT CONDITIONALLY SCHEDULING IF EVENT #define SignalIrulSelf(irul) \ MsoDelayScheduleIrulFrom((IRUL) (irul), (irulSelf), 0) // Signal the event with the value from the current rule #define SignalEventIrulSelf(irul) \ MsoSignalEventIrulFrom((IRUL) (irul), (irulSelf)) // Evaluate the event after delay of 1 #define DelaySignalEventIrul(irul, lValue) \ MsoDelayScheduleIrul((irul), (lValue), 1 /* cDelay */) // Evaluate the event after specified delay #define DelaySignalEventIrulAfter(irul, lValue, cDelay) \ MsoDelayScheduleIrul((irul), (lValue), 1 << ((cDelay) - 1)) // Evaluate the node after delay of 1, getting value from rule #define DelaySignalIrulSelf(irul) \ MsoDelayScheduleIrulFrom((irul), (irulSelf), 1 /* cDelay */) // Evaluate the event after delay of 1, getting value from rule #define DelaySignalEventIrulSelf(irul) \ MsoDelayScheduleIrulFrom((irul), (irulSelf), 1 /* cDelay */) // Evaluate the event after delay of 1 // REVIEW daleg: OBSOLETE: USE DelaySignalEventIrul or "then ... ()" #define DelaySignalIrul(irul) \ MsoDelayScheduleIrul((irul), TRUE, 1 /* cDelay */) // Evaluate the event after delay of 1 #define DelaySignal(rulvVar) \ DelaySignalRulv((rulvVar), TRUE) // Evaluate the event after delay of 1 #define DelaySignalRulv(rulvVar, lValue) \ CDelaySignalRulv((rulvVar), (lValue), 1 /* cDelay */) // Evaluate the event after delay of 1 #define CDelaySignalRulv(rulvVar, lValue, cDelay) \ MsoDelayScheduleIrul(LprulFromRulv(rulvVar)->irul, (lValue), \ (cDelay)) // Evaluate the rule after delay of 1 passing TRUE as the value #define DelayGoToIrul1(irul) \ MsoDelayScheduleIrul((irul), TRUE, 1 /* cDelay */) // Evaluate the rule after specified delay #define DelayGoToIrulAfter(irul, cDelay) \ MsoDelayScheduleIrul((irul), TRUE, 1 << ((cDelay) - 1)) // Evaluate the rule with value after specified delay #define DelayGoToIrulWithRulvAfter(irul, lValue, cDelay) \ MsoDelayScheduleIrul((irul), (lValue) - (cDelay) + 1, \ 1 << ((cDelay) - 1)) // Evaluate the rule after specified delay #define DelayGoToDirulAfter(dirul, cDelay) \ MsoDelayScheduleIrulFrom((IRUL) (irulSelf + (dirul)), (irulSelf), \ 1 << ((cDelay) - 1)) // Evaluate the rule after delay of 1, incrementing value #define DelayGoToIrulNoValue(irul) \ MsoDelayScheduleIrulFrom \ ((IRUL) (irul), (IRUL) (irul), 1 /* cDelay */) // Evaluate the rule after delay of 1, passing the value of the current node #define DelayGoToIrul(irul) \ MsoDelayScheduleIrulFrom((IRUL) (irul), (irulSelf), 1 /* cDelay */) // Evaluate the rule (via relative offset) after delay of 1 #define DelayGoToDirul(dirul) \ MsoDelayScheduleIrulFrom \ ((IRUL) (irulSelf + (dirul)), (irulSelf), 1) // Evaluate the rule (via relative offset) after delay of 1 #define DelayGoToDirulNoValue(dirul) \ MsoDelayScheduleIrulFrom((IRUL) (irulSelf + (dirul)), \ (IRUL) (irulSelf + (dirul)), 1) // Evaluate the rule (via relative offset) after delay of 1, with value rulv #define DelayGoToDirulWithRulv(dirul, rulv) \ (SetRulvOfIrul(irulSelf + (dirul), (rulv)), \ DelayGoToDirulNoValue(dirul)) // Evaluate the rule (via relative offset) after delay of 1, with value rulv2 #define DelayGoToDirulWithRulv2(dirul, rulv2) \ (SetRulv2OfIrul(irulSelf + (dirul), (short) (rulv2)), \ DelayGoToDirulNoValue(dirul)) // Evaluate the rule (via relative offset) after delay of 1, with value rulv2 #define DelayGoToDirulWithRulv1(dirul, rulv1) \ (SetRulv1OfIrul(irulSelf + (dirul), (short) (rulv1)), \ DelayGoToDirulNoValue(dirul)) // Evaluate the rule (via relative offset) after delay of 1, with values #define DelayGoToDirulWithRulvs(dirul, rulv1, rulv2) \ (SetRulv1OfIrul(irulSelf + (dirul), (short) (rulv1)), \ SetRulv2OfIrul(irulSelf + (dirul), (short) (rulv2)), \ DelayGoToDirulNoValue(dirul)) // Deactivate curr rule if the fTest value is FALSE: used in rule test clause #define FAutoDeactivateSelf(fTest) \ FAutoDeactivateIrul(irulSelf, (fTest)) // Deactivate the rule if the fTest value is FALSE: used in rule test clause #define FAutoDeactivateIrul(irul, fTest) \ ((fTest) ? FALSE : (_MsoFDeactivateIrul(irul), TRUE)) // Set the Rule Propagation Group to the given value #define SetCurrRulg(rulgGroup) \ (vlpruls->rgpruldepDependents \ = vlpruls->rgrgpruldepDependents[vlpruls->rulgCurr \ = rulgGroup]) // Return the current main Rule Propagation Group #define FCurrRulg(rulg) \ (vlpruls->rulgCurr == (rulg)) /************************************************************************* Prototypes and macros for Debugging and Error Handling *************************************************************************/ #ifdef DEBUG MSOAPI_(int) MsoFTraceIrul(IRUL irul, int fTraceOn); // Trace a node char *SzFromFixed3(long lValue, char *pchBuf); // Fixed to sz conv #define DebugDumpQueues(wTraceLvl, sz, lValue, wToLevel) \ { \ static const unsigned char _szDump[] = sz; \ \ _DumpQueues(wTraceLvl, _szDump, lValue, wToLevel); \ } #define DebugDumpQueue(wTraceLvl, rulevl) \ _DumpQueue(wTraceLvl, rulevl, LplprulQueueOf(rulevl)) #else /* !DEBUG */ #define DebugDumpQueues(wTraceLvl, sz, lValue, wToLevel) #define DebugDumpQueue(wTraceLvl, rulevl) #endif /* DEBUG */ MSOEXTERN_C_END // ****************** End extern "C" ********************* #define EMRULE_H #if !(defined(OFFICE_BUILD) || defined(XL)) #ifdef DYN_RULES int FLoadDynEmRules(void); // Load dyn rulebase #include "emruloci.h" #endif /* DYN_RULES */ #endif /* !OFFICE_BUILD */ #endif /* !EMRULE_H */