/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.40 05/29/19 */ /* */ /* FACT FUNCTIONS MODULE */ /*******************************************************/ /*************************************************************/ /* Purpose: */ /* */ /* */ /* (fact-existp ) */ /* Returns TRUE if the fact exists, otherwise FALSE is */ /* returned. */ /* */ /* (fact-relation ) */ /* Returns the deftemplate name of the fact. Returns */ /* FALSE if the specified fact doesn't exist. */ /* */ /* (fact-slot-value ) */ /* Returns the contents of a slot (use the slot name */ /* implied for the implied multifield slot of an ordered */ /* fact). Returns the value FALSE if the slot name is */ /* invalid or the fact doesn't exist. */ /* */ /* (fact-slot-names ) */ /* Returns the slot names associated with a fact in a */ /* multifield value. Returns FALSE if the fact doesn't */ /* exist. */ /* */ /* (get-fact-list []) */ /* Returns the list of facts visible to the specified */ /* module or to the current module if none is specified. */ /* If * is specified then all facts are returned. */ /* */ /* Principal Programmer(s): */ /* Gary D. Riley */ /* */ /* Contributing Programmer(s): */ /* */ /* Revision History: */ /* */ /* 6.23: Correction for FalseSymbol/TrueSymbol. DR0859 */ /* */ /* Corrected compilation errors for files */ /* generated by constructs-to-c. DR0861 */ /* */ /* 6.24: Added ppfact function. */ /* */ /* 6.30: Support for long long integers. */ /* */ /* Removed conditional code for unsupported */ /* compilers/operating systems (IBM_MCW, */ /* MAC_MCW, and IBM_TBC). */ /* */ /* Added const qualifiers to remove C++ */ /* deprecation warnings. */ /* */ /* Converted API macros to function calls. */ /* */ /* Added STDOUT and STDIN logical name */ /* definitions. */ /* */ /* 6.31: Calling EnvFactExistp for a fact that has */ /* been created, but not asserted now returns */ /* FALSE. */ /* */ /* Error messages are now generated when the */ /* fact-relation, fact-slot-value, */ /* fact-slot-names, and ppfact functions are */ /* given a retracted fact. */ /* */ /* 6.40: Added Env prefix to GetEvaluationError and */ /* SetEvaluationError functions. */ /* */ /* Added Env prefix to GetHaltExecution and */ /* SetHaltExecution functions. */ /* */ /* Pragma once and other inclusion changes. */ /* */ /* Added support for booleans with . */ /* */ /* Removed use of void pointers for specific */ /* data structures. */ /* */ /* ALLOW_ENVIRONMENT_GLOBALS no longer supported. */ /* */ /* UDF redesign. */ /* */ /* Watch facts for modify command only prints */ /* changed slots. */ /* */ /* Pretty print functions accept optional logical */ /* name argument. */ /* */ /* Added fact-addressp function. */ /* */ /*************************************************************/ #include #include #include "setup.h" #if DEFTEMPLATE_CONSTRUCT #include "argacces.h" #include "envrnmnt.h" #include "extnfunc.h" #include "multifld.h" #include "prntutil.h" #include "router.h" #include "sysdep.h" #include "tmpltutl.h" #include "factfun.h" /****************************************************/ /* FactFunctionDefinitions: Defines fact functions. */ /****************************************************/ void FactFunctionDefinitions( Environment *theEnv) { #if ! RUN_TIME AddUDF(theEnv,"fact-existp","b",1,1,"lf",FactExistpFunction,"FactExistpFunction",NULL); AddUDF(theEnv,"fact-relation","y",1,1,"lf",FactRelationFunction,"FactRelationFunction",NULL); AddUDF(theEnv,"fact-slot-value","*",2,2,";lf;y",FactSlotValueFunction,"FactSlotValueFunction",NULL); AddUDF(theEnv,"fact-slot-names","*",1,1,"lf",FactSlotNamesFunction,"FactSlotNamesFunction",NULL); AddUDF(theEnv,"get-fact-list","m",0,1,"y",GetFactListFunction,"GetFactListFunction",NULL); AddUDF(theEnv,"ppfact","vs",1,3,"*;lf;ldsyn",PPFactFunction,"PPFactFunction",NULL); AddUDF(theEnv,"fact-addressp","b",1,1,NULL,FactAddresspFunction,"FactAddresspFunction",NULL); #else #if MAC_XCD #pragma unused(theEnv) #endif #endif } /**********************************************/ /* FactRelationFunction: H/L access routine */ /* for the fact-relation function. */ /**********************************************/ void FactRelationFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Fact *theFact; theFact = GetFactAddressOrIndexArgument(context,true); if (theFact == NULL) { returnValue->lexemeValue = FalseSymbol(theEnv); return; } returnValue->value = FactRelation(theFact); } /**************************************/ /* FactRelation: C access routine for */ /* the fact-relation function. */ /**************************************/ CLIPSLexeme *FactRelation( Fact *theFact) { return theFact->whichDeftemplate->header.name; } /***************************************/ /* FactDeftemplate: C access routine */ /* to retrieve a fact's deftemplate. */ /***************************************/ Deftemplate *FactDeftemplate( Fact *theFact) { return theFact->whichDeftemplate; } /********************************************/ /* FactExistpFunction: H/L access routine */ /* for the fact-existp function. */ /********************************************/ void FactExistpFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Fact *theFact; theFact = GetFactAddressOrIndexArgument(context,false); returnValue->lexemeValue = CreateBoolean(theEnv,FactExistp(theFact)); } /***********************************/ /* FactExistp: C access routine */ /* for the fact-existp function. */ /***********************************/ bool FactExistp( Fact *theFact) { if (theFact == NULL) return false; if (theFact->garbage) return false; if (theFact->factIndex == 0LL) return false; return true; } /********************************************/ /* FactAddresspFunction: H/L access routine */ /* for the fact-addressp function. */ /********************************************/ void FactAddresspFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { UDFValue item; if (! UDFFirstArgument(context,ANY_TYPE_BITS,&item)) { return; } if (CVIsType(&item,FACT_ADDRESS_BIT)) { returnValue->lexemeValue = TrueSymbol(theEnv); } else { returnValue->lexemeValue = FalseSymbol(theEnv); } } /***********************************************/ /* FactSlotValueFunction: H/L access routine */ /* for the fact-slot-value function. */ /***********************************************/ void FactSlotValueFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Fact *theFact; UDFValue theArg; CLIPSValue result; /*================================*/ /* Get the reference to the fact. */ /*================================*/ theFact = GetFactAddressOrIndexArgument(context,true); if (theFact == NULL) { returnValue->lexemeValue = FalseSymbol(theEnv); return; } /*===========================*/ /* Get the name of the slot. */ /*===========================*/ if (! UDFNextArgument(context,SYMBOL_BIT,&theArg)) { return; } /*=======================*/ /* Get the slot's value. */ /*=======================*/ FactSlotValue(theEnv,theFact,theArg.lexemeValue->contents,&result); CLIPSToUDFValue(&result,returnValue); } /***************************************/ /* FactSlotValue: C access routine for */ /* the fact-slot-value function. */ /***************************************/ void FactSlotValue( Environment *theEnv, Fact *theFact, const char *theSlotName, CLIPSValue *returnValue) { /*==================================================*/ /* Make sure the slot exists (the symbol implied is */ /* used for the implied slot of an ordered fact). */ /*==================================================*/ if (theFact->whichDeftemplate->implied) { if (strcmp(theSlotName,"implied") != 0) { SetEvaluationError(theEnv,true); InvalidDeftemplateSlotMessage(theEnv,theSlotName, theFact->whichDeftemplate->header.name->contents,false); returnValue->lexemeValue = FalseSymbol(theEnv); return; } } else if (FindSlot(theFact->whichDeftemplate,CreateSymbol(theEnv,theSlotName),NULL) == NULL) { SetEvaluationError(theEnv,true); InvalidDeftemplateSlotMessage(theEnv,theSlotName, theFact->whichDeftemplate->header.name->contents,false); returnValue->lexemeValue = FalseSymbol(theEnv); return; } /*==========================*/ /* Return the slot's value. */ /*==========================*/ if (theFact->whichDeftemplate->implied) { GetFactSlot(theFact,NULL,returnValue); } else { GetFactSlot(theFact,theSlotName,returnValue); } } /***********************************************/ /* FactSlotNamesFunction: H/L access routine */ /* for the fact-slot-names function. */ /***********************************************/ void FactSlotNamesFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Fact *theFact; CLIPSValue result; /*================================*/ /* Get the reference to the fact. */ /*================================*/ theFact = GetFactAddressOrIndexArgument(context,true); if (theFact == NULL) { returnValue->lexemeValue = FalseSymbol(theEnv); return; } /*=====================*/ /* Get the slot names. */ /*=====================*/ FactSlotNames(theFact,&result); CLIPSToUDFValue(&result,returnValue); } /***************************************/ /* FactSlotNames: C access routine */ /* for the fact-slot-names function. */ /***************************************/ void FactSlotNames( Fact *theFact, CLIPSValue *returnValue) { Multifield *theList; struct templateSlot *theSlot; unsigned long count; Environment *theEnv = theFact->whichDeftemplate->header.env; /*===============================================*/ /* If we're dealing with an implied deftemplate, */ /* then the only slot names is "implied." */ /*===============================================*/ if (theFact->whichDeftemplate->implied) { theList = CreateMultifield(theEnv,1); theList->contents[0].lexemeValue = CreateSymbol(theEnv,"implied"); returnValue->value = theList; return; } /*=================================*/ /* Count the number of slot names. */ /*=================================*/ for (count = 0, theSlot = theFact->whichDeftemplate->slotList; theSlot != NULL; count++, theSlot = theSlot->next) { /* Do Nothing */ } /*=============================================================*/ /* Create a multifield value in which to store the slot names. */ /*=============================================================*/ theList = CreateMultifield(theEnv,count); returnValue->value = theList; /*===============================================*/ /* Store the slot names in the multifield value. */ /*===============================================*/ for (count = 0, theSlot = theFact->whichDeftemplate->slotList; theSlot != NULL; count++, theSlot = theSlot->next) { theList->contents[count].lexemeValue = theSlot->slotName; } } /*********************************************/ /* GetFactListFunction: H/L access routine */ /* for the get-fact-list function. */ /*********************************************/ void GetFactListFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Defmodule *theModule; UDFValue theArg; CLIPSValue result; /*===========================================*/ /* Determine if a module name was specified. */ /*===========================================*/ if (UDFHasNextArgument(context)) { if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg)) { return; } if ((theModule = FindDefmodule(theEnv,theArg.lexemeValue->contents)) == NULL) { if (strcmp("*",theArg.lexemeValue->contents) != 0) { SetMultifieldErrorValue(theEnv,returnValue); UDFInvalidArgumentMessage(context,"defmodule name"); return; } theModule = NULL; } } else { theModule = GetCurrentModule(theEnv); } /*=====================*/ /* Get the constructs. */ /*=====================*/ GetFactList(theEnv,&result,theModule); CLIPSToUDFValue(&result,returnValue); } /*************************************/ /* GetFactList: C access routine */ /* for the get-fact-list function. */ /*************************************/ void GetFactList( Environment *theEnv, CLIPSValue *returnValue, Defmodule *theModule) { Fact *theFact; unsigned long count; Multifield *theList; /*==========================*/ /* Save the current module. */ /*==========================*/ SaveCurrentModule(theEnv); /*============================================*/ /* Count the number of facts to be retrieved. */ /*============================================*/ if (theModule == NULL) { for (theFact = GetNextFact(theEnv,NULL), count = 0; theFact != NULL; theFact = GetNextFact(theEnv,theFact), count++) { /* Do Nothing */ } } else { SetCurrentModule(theEnv,theModule); UpdateDeftemplateScope(theEnv); for (theFact = GetNextFactInScope(theEnv,NULL), count = 0; theFact != NULL; theFact = GetNextFactInScope(theEnv,theFact), count++) { /* Do Nothing */ } } /*===========================================================*/ /* Create the multifield value to store the construct names. */ /*===========================================================*/ theList = CreateMultifield(theEnv,count); returnValue->value = theList; /*==================================================*/ /* Store the fact pointers in the multifield value. */ /*==================================================*/ if (theModule == NULL) { for (theFact = GetNextFact(theEnv,NULL), count = 0; theFact != NULL; theFact = GetNextFact(theEnv,theFact), count++) { theList->contents[count].factValue = theFact; } } else { for (theFact = GetNextFactInScope(theEnv,NULL), count = 0; theFact != NULL; theFact = GetNextFactInScope(theEnv,theFact), count++) { theList->contents[count].factValue = theFact; } } /*=============================*/ /* Restore the current module. */ /*=============================*/ RestoreCurrentModule(theEnv); UpdateDeftemplateScope(theEnv); } /**************************************/ /* PPFactFunction: H/L access routine */ /* for the ppfact function. */ /**************************************/ void PPFactFunction( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Fact *theFact; const char *logicalName = NULL; /* Avoids warning */ bool ignoreDefaults = false; UDFValue theArg; theFact = GetFactAddressOrIndexArgument(context,true); if (theFact == NULL) return; /*===============================================================*/ /* Determine the logical name to which the fact will be printed. */ /*===============================================================*/ if (UDFHasNextArgument(context)) { logicalName = GetLogicalName(context,STDOUT); if (logicalName == NULL) { IllegalLogicalNameMessage(theEnv,"ppfact"); SetHaltExecution(theEnv,true); SetEvaluationError(theEnv,true); return; } } else { logicalName = STDOUT; } /*=========================================*/ /* Should slot values be printed if they */ /* are the same as the default slot value. */ /*=========================================*/ if (UDFHasNextArgument(context)) { UDFNextArgument(context,ANY_TYPE_BITS,&theArg); if (theArg.value == FalseSymbol(theEnv)) { ignoreDefaults = false; } else { ignoreDefaults = true; } } /*============================================================*/ /* Determine if any router recognizes the output destination. */ /*============================================================*/ if (strcmp(logicalName,"nil") == 0) { StringBuilder *theSB; theSB = CreateStringBuilder(theEnv,256); FactPPForm(theFact,theSB,ignoreDefaults); returnValue->lexemeValue = CreateString(theEnv,theSB->contents); SBDispose(theSB); return; } else if (QueryRouters(theEnv,logicalName) == false) { UnrecognizedRouterMessage(theEnv,logicalName); return; } PPFact(theFact,logicalName,ignoreDefaults); } /******************************/ /* PPFact: C access routine */ /* for the ppfact function. */ /******************************/ void PPFact( Fact *theFact, const char *logicalName, bool ignoreDefaults) { Environment *theEnv = theFact->whichDeftemplate->header.env; if (theFact == NULL) return; if (theFact->garbage) return; PrintFact(theEnv,logicalName,theFact,true,ignoreDefaults,NULL); WriteString(theEnv,logicalName,"\n"); } /**************************************************************/ /* GetFactAddressOrIndexArgument: Retrieves an argument for a */ /* function which should be a reference to a valid fact. */ /**************************************************************/ Fact *GetFactAddressOrIndexArgument( UDFContext *context, bool noFactError) { UDFValue theArg; long long factIndex; Fact *theFact; Environment *theEnv = context->environment; char tempBuffer[20]; if (! UDFNextArgument(context,ANY_TYPE_BITS,&theArg)) { return NULL; } if (theArg.header->type == FACT_ADDRESS_TYPE) { if (theArg.factValue->garbage) { if (noFactError) { FactRetractedErrorMessage(theEnv,theArg.factValue); SetEvaluationError(theEnv,true); } return NULL; } else return theArg.factValue; } else if (theArg.header->type == INTEGER_TYPE) { factIndex = theArg.integerValue->contents; if (factIndex < 0) { UDFInvalidArgumentMessage(context,"fact-address or fact-index"); return NULL; } theFact = FindIndexedFact(theEnv,factIndex); if ((theFact == NULL) && noFactError) { gensprintf(tempBuffer,"f-%lld",factIndex); CantFindItemErrorMessage(theEnv,"fact",tempBuffer,false); return NULL; } return theFact; } UDFInvalidArgumentMessage(context,"fact-address or fact-index"); return NULL; } #endif /* DEFTEMPLATE_CONSTRUCT */