#include <stdio.h>
#include <string.h>
#include <time.h>
#include "setup.h"
#include "argacces.h"
#include "envrnmnt.h"
#include "exprnpsr.h"
#include "memalloc.h"
#include "multifld.h"
#include "prntutil.h"
#include "router.h"
#include "sysdep.h"
#include "utility.h"
#if DEFFUNCTION_CONSTRUCT
#include "dffnxfun.h"
#endif
#if DEFTEMPLATE_CONSTRUCT
#include "factfun.h"
#include "tmpltutl.h"
#endif
#include "miscfun.h"
#define MISCFUN_DATA 9
struct miscFunctionData
{
long long GensymNumber;
CLIPSValue errorCode;
};
#define MiscFunctionData(theEnv) ((struct miscFunctionData *) GetEnvironmentData(theEnv,MISCFUN_DATA))
static void ExpandFuncMultifield(Environment *,UDFValue *,Expression *,
Expression **,void *);
static int FindLanguageType(Environment *,const char *);
static void ConvertTime(Environment *,UDFValue *,struct tm *);
void MiscFunctionDefinitions(
Environment *theEnv)
{
AllocateEnvironmentData(theEnv,MISCFUN_DATA,sizeof(struct miscFunctionData),NULL);
MiscFunctionData(theEnv)->GensymNumber = 1;
MiscFunctionData(theEnv)->errorCode.lexemeValue = FalseSymbol(theEnv);
Retain(theEnv,MiscFunctionData(theEnv)->errorCode.header);
#if ! RUN_TIME
AddUDF(theEnv,"exit","v",0,1,"l",ExitCommand,"ExitCommand",NULL);
AddUDF(theEnv,"gensym","y",0,0,NULL,GensymFunction,"GensymFunction",NULL);
AddUDF(theEnv,"gensym*","y",0,0,NULL,GensymStarFunction,"GensymStarFunction",NULL);
AddUDF(theEnv,"setgen","l",1,1,"l",SetgenFunction,"SetgenFunction",NULL);
AddUDF(theEnv,"system","ly",0,UNBOUNDED,"sy",SystemCommand,"SystemCommand",NULL);
AddUDF(theEnv,"length$","l",1,1,"m",LengthFunction,"LengthFunction",NULL);
AddUDF(theEnv,"time","d",0,0,NULL,TimeFunction,"TimeFunction",NULL);
AddUDF(theEnv,"local-time","m",0,0,NULL,LocalTimeFunction,"LocalTimeFunction",NULL);
AddUDF(theEnv,"gm-time","m",0,0,NULL,GMTimeFunction,"GMTimeFunction",NULL);
AddUDF(theEnv,"random","l",0,2,"l",RandomFunction,"RandomFunction",NULL);
AddUDF(theEnv,"seed","v",1,1,"l",SeedFunction,"SeedFunction",NULL);
AddUDF(theEnv,"conserve-mem","v",1,1,"y",ConserveMemCommand,"ConserveMemCommand",NULL);
AddUDF(theEnv,"release-mem","l",0,0,NULL,ReleaseMemCommand,"ReleaseMemCommand",NULL);
#if DEBUGGING_FUNCTIONS
AddUDF(theEnv,"mem-used","l",0,0,NULL,MemUsedCommand,"MemUsedCommand",NULL);
AddUDF(theEnv,"mem-requests","l",0,0,NULL,MemRequestsCommand,"MemRequestsCommand",NULL);
#endif
AddUDF(theEnv,"options","v",0,0,NULL,OptionsCommand,"OptionsCommand",NULL);
AddUDF(theEnv,"operating-system","y",0,0,NULL,OperatingSystemFunction,"OperatingSystemFunction",NULL);
AddUDF(theEnv,"(expansion-call)","*",0,UNBOUNDED,NULL,ExpandFuncCall,"ExpandFuncCall",NULL);
AddUDF(theEnv,"expand$","*",1,1,"m",DummyExpandFuncMultifield,"DummyExpandFuncMultifield",NULL);
FuncSeqOvlFlags(theEnv,"expand$",false,false);
AddUDF(theEnv,"(set-evaluation-error)","y",0,0,NULL,CauseEvaluationError,"CauseEvaluationError",NULL);
AddUDF(theEnv,"set-sequence-operator-recognition","b",1,1,"y",SetSORCommand,"SetSORCommand",NULL);
AddUDF(theEnv,"get-sequence-operator-recognition","b",0,0,NULL,GetSORCommand,"GetSORCommand",NULL);
AddUDF(theEnv,"get-function-restrictions","s",1,1,"y",GetFunctionRestrictions,"GetFunctionRestrictions",NULL);
AddUDF(theEnv,"create$","m",0,UNBOUNDED,NULL,CreateFunction,"CreateFunction",NULL);
AddUDF(theEnv,"apropos","v",1,1,"y",AproposCommand,"AproposCommand",NULL);
AddUDF(theEnv,"get-function-list","m",0,0,NULL,GetFunctionListFunction,"GetFunctionListFunction",NULL);
AddUDF(theEnv,"funcall","*",1,UNBOUNDED,"*;sy",FuncallFunction,"FuncallFunction",NULL);
AddUDF(theEnv,"new","*",1,UNBOUNDED,"*;y",NewFunction,"NewFunction",NULL);
AddUDF(theEnv,"call","*",1,UNBOUNDED,"*",CallFunction,"CallFunction",NULL);
AddUDF(theEnv,"timer","d",0,UNBOUNDED,NULL,TimerFunction,"TimerFunction",NULL);
AddUDF(theEnv,"get-error","*",0,0,NULL,GetErrorFunction,"GetErrorFunction",NULL);
AddUDF(theEnv,"clear-error","*",0,0,NULL,ClearErrorFunction,"ClearErrorFunction",NULL);
AddUDF(theEnv,"set-error","v",1,1,NULL,SetErrorFunction,"SetErrorFunction",NULL);
AddUDF(theEnv,"void","v",0,0,NULL,VoidFunction,"VoidFunction",NULL);
#endif
}
void ExitCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
unsigned int argCnt;
int status;
UDFValue theArg;
argCnt = UDFArgumentCount(context);
if (argCnt == 0)
{ ExitRouter(theEnv,EXIT_SUCCESS); }
else
{
if (! UDFFirstArgument(context,INTEGER_BIT,&theArg))
{ ExitRouter(theEnv,EXIT_SUCCESS); }
status = (int) theArg.integerValue->contents;
if (GetEvaluationError(theEnv)) return;
ExitRouter(theEnv,status);
}
return;
}
void CreateFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
StoreInMultifield(theEnv,returnValue,GetFirstArgument(),true);
}
void SetgenFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
long long theLong;
if (! UDFNthArgument(context,1,INTEGER_BIT,returnValue))
{ return; }
theLong = returnValue->integerValue->contents;
if (theLong < 1LL)
{
UDFInvalidArgumentMessage(context,"integer (greater than or equal to 1)");
returnValue->integerValue = CreateInteger(theEnv,MiscFunctionData(theEnv)->GensymNumber);
return;
}
MiscFunctionData(theEnv)->GensymNumber = theLong;
}
void GensymFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
char genstring[128];
gensprintf(genstring,"gen%lld",MiscFunctionData(theEnv)->GensymNumber);
MiscFunctionData(theEnv)->GensymNumber++;
returnValue->lexemeValue = CreateSymbol(theEnv,genstring);
}
void GensymStarFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
GensymStar(theEnv,returnValue);
}
void GensymStar(
Environment *theEnv,
UDFValue *returnValue)
{
char genstring[128];
do
{
gensprintf(genstring,"gen%lld",MiscFunctionData(theEnv)->GensymNumber);
MiscFunctionData(theEnv)->GensymNumber++;
}
while (FindSymbolHN(theEnv,genstring,SYMBOL_BIT) != NULL);
returnValue->lexemeValue = CreateSymbol(theEnv,genstring);
}
void RandomFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
unsigned int argCount;
long long rv;
UDFValue theArg;
long long begin, end;
argCount = UDFArgumentCount(context);
if ((argCount != 0) && (argCount != 2))
{
PrintErrorID(theEnv,"MISCFUN",2,false);
WriteString(theEnv,STDERR,"Function random expected either 0 or 2 arguments\n");
}
rv = genrand();
if (argCount == 2)
{
if (! UDFFirstArgument(context,INTEGER_BIT,&theArg))
{ return; }
begin = theArg.integerValue->contents;
if (! UDFNextArgument(context,INTEGER_BIT,&theArg))
{ return; }
end = theArg.integerValue->contents;
if (end < begin)
{
PrintErrorID(theEnv,"MISCFUN",3,false);
WriteString(theEnv,STDERR,"Function random expected argument #1 to be less than argument #2\n");
returnValue->integerValue = CreateInteger(theEnv,rv);
return;
}
rv = begin + (rv % ((end - begin) + 1));
}
returnValue->integerValue = CreateInteger(theEnv,rv);
}
void SeedFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UDFValue theValue;
if (! UDFFirstArgument(context,INTEGER_BIT,&theValue))
{ return; }
genseed((unsigned int) theValue.integerValue->contents);
}
void LengthFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UDFValue theArg;
if (! UDFFirstArgument(context, MULTIFIELD_BIT, &theArg))
{ return; }
returnValue->value = CreateInteger(theEnv,(long long) theArg.range);
}
void ReleaseMemCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->integerValue = CreateInteger(theEnv,ReleaseMem(theEnv,-1));
}
void ConserveMemCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
const char *argument;
UDFValue theValue;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theValue))
{ return; }
argument = theValue.lexemeValue->contents;
if (strcmp(argument,"on") == 0)
{ SetConserveMemory(theEnv,true); }
else if (strcmp(argument,"off") == 0)
{ SetConserveMemory(theEnv,false); }
else
{
UDFInvalidArgumentMessage(context,"symbol with value on or off");
return;
}
return;
}
#if DEBUGGING_FUNCTIONS
void MemUsedCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->integerValue = CreateInteger(theEnv,MemUsed(theEnv));
}
void MemRequestsCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->integerValue = CreateInteger(theEnv,MemRequests(theEnv));
}
#endif
void AproposCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
const char *argument;
UDFValue theArg;
CLIPSLexeme *hashPtr = NULL;
size_t theLength;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg))
{ return; }
argument = theArg.lexemeValue->contents;
theLength = strlen(argument);
while ((hashPtr = GetNextSymbolMatch(theEnv,argument,theLength,hashPtr,true,NULL)) != NULL)
{
WriteString(theEnv,STDOUT,hashPtr->contents);
WriteString(theEnv,STDOUT,"\n");
}
}
void OptionsCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->voidValue = VoidConstant(theEnv);
WriteString(theEnv,STDOUT,"Machine type: ");
#if GENERIC
WriteString(theEnv,STDOUT,"Generic ");
#endif
#if UNIX_V
WriteString(theEnv,STDOUT,"UNIX System V or 4.2BSD ");
#endif
#if DARWIN
WriteString(theEnv,STDOUT,"Darwin ");
#endif
#if LINUX
WriteString(theEnv,STDOUT,"Linux ");
#endif
#if UNIX_7
WriteString(theEnv,STDOUT,"UNIX System III Version 7 or Sun Unix ");
#endif
#if MAC_XCD
WriteString(theEnv,STDOUT,"Apple Macintosh with Xcode");
#endif
#if WIN_MVC
WriteString(theEnv,STDOUT,"Microsoft Windows with Microsoft Visual C++");
#endif
#if WIN_GCC
WriteString(theEnv,STDOUT,"Microsoft Windows with DJGPP");
#endif
WriteString(theEnv,STDOUT,"\n");
WriteString(theEnv,STDOUT,"Defrule construct is ");
#if DEFRULE_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Defmodule construct is ");
#if DEFMODULE_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Deftemplate construct is ");
#if DEFTEMPLATE_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT," Fact-set queries are ");
#if FACT_SET_QUERIES
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
#if DEFTEMPLATE_CONSTRUCT
WriteString(theEnv,STDOUT," Deffacts construct is ");
#if DEFFACTS_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
#endif
WriteString(theEnv,STDOUT,"Defglobal construct is ");
#if DEFGLOBAL_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Deffunction construct is ");
#if DEFFUNCTION_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Defgeneric/Defmethod constructs are ");
#if DEFGENERIC_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Object System is ");
#if OBJECT_SYSTEM
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
#if OBJECT_SYSTEM
WriteString(theEnv,STDOUT," Definstances construct is ");
#if DEFINSTANCES_CONSTRUCT
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT," Instance-set queries are ");
#if INSTANCE_SET_QUERIES
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT," Binary loading of instances is ");
#if BLOAD_INSTANCES
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT," Binary saving of instances is ");
#if BSAVE_INSTANCES
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
#endif
WriteString(theEnv,STDOUT,"Extended math function package is ");
#if EXTENDED_MATH_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Text processing function package is ");
#if TEXTPRO_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Bload capability is ");
#if BLOAD_ONLY
WriteString(theEnv,STDOUT,"BLOAD ONLY");
#endif
#if BLOAD
WriteString(theEnv,STDOUT,"BLOAD");
#endif
#if BLOAD_AND_BSAVE
WriteString(theEnv,STDOUT,"BLOAD AND BSAVE");
#endif
#if (! BLOAD_ONLY) && (! BLOAD) && (! BLOAD_AND_BSAVE)
WriteString(theEnv,STDOUT,"OFF ");
#endif
WriteString(theEnv,STDOUT,"\n");
WriteString(theEnv,STDOUT,"Construct compiler is ");
#if CONSTRUCT_COMPILER
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"I/O function package is ");
#if IO_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"String function package is ");
#if STRING_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Multifield function package is ");
#if MULTIFIELD_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Debugging function package is ");
#if DEBUGGING_FUNCTIONS
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Window Interface flag is ");
#if WINDOW_INTERFACE
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Developer flag is ");
#if DEVELOPER
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
WriteString(theEnv,STDOUT,"Run time module is ");
#if RUN_TIME
WriteString(theEnv,STDOUT,"ON\n");
#else
WriteString(theEnv,STDOUT,"OFF\n");
#endif
}
void OperatingSystemFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
#if GENERIC
returnValue->lexemeValue = CreateSymbol(theEnv,"UNKNOWN");
#elif UNIX_V
returnValue->lexemeValue = CreateSymbol(theEnv,"UNIX-V");
#elif UNIX_7
returnValue->lexemeValue = CreateSymbol(theEnv,"UNIX-7");
#elif LINUX
returnValue->lexemeValue = CreateSymbol(theEnv,"LINUX");
#elif DARWIN
returnValue->lexemeValue = CreateSymbol(theEnv,"DARWIN");
#elif MAC_XCD
returnValue->lexemeValue = CreateSymbol(theEnv,"MAC-OS");
#elif IBM && (! WINDOW_INTERFACE)
returnValue->lexemeValue = CreateSymbol(theEnv,"DOS");
#elif IBM && WINDOW_INTERFACE
returnValue->lexemeValue = CreateSymbol(theEnv,"WINDOWS");
#else
returnValue->lexemeValue = CreateSymbol(theEnv,"UNKNOWN");
#endif
}
void ExpandFuncCall(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
Expression *newargexp,*fcallexp;
struct functionDefinition *func;
newargexp = CopyExpression(theEnv,GetFirstArgument()->argList);
ExpandFuncMultifield(theEnv,returnValue,newargexp,&newargexp,
FindFunction(theEnv,"expand$"));
fcallexp = get_struct(theEnv,expr);
fcallexp->type = GetFirstArgument()->type;
fcallexp->value = GetFirstArgument()->value;
fcallexp->nextArg = NULL;
fcallexp->argList = newargexp;
if (fcallexp->type == FCALL)
{
func = fcallexp->functionValue;
if (CheckFunctionArgCount(theEnv,func,CountArguments(newargexp)) == false)
{
returnValue->lexemeValue = FalseSymbol(theEnv);
ReturnExpression(theEnv,fcallexp);
return;
}
}
#if DEFFUNCTION_CONSTRUCT
else if (fcallexp->type == PCALL)
{
if (CheckDeffunctionCall(theEnv,(Deffunction *) fcallexp->value,
CountArguments(fcallexp->argList)) == false)
{
returnValue->lexemeValue = FalseSymbol(theEnv);
ReturnExpression(theEnv,fcallexp);
SetEvaluationError(theEnv,true);
return;
}
}
#endif
EvaluateExpression(theEnv,fcallexp,returnValue);
ReturnExpression(theEnv,fcallexp);
}
void DummyExpandFuncMultifield(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->lexemeValue = FalseSymbol(theEnv);
SetEvaluationError(theEnv,true);
PrintErrorID(theEnv,"MISCFUN",1,false);
WriteString(theEnv,STDERR,"The function 'expand$' must be used in the argument list of a function call.\n");
}
static void ExpandFuncMultifield(
Environment *theEnv,
UDFValue *returnValue,
Expression *theExp,
Expression **sto,
void *expmult)
{
Expression *newexp,*top,*bot;
size_t i;
while (theExp != NULL)
{
if (theExp->value == expmult)
{
EvaluateExpression(theEnv,theExp->argList,returnValue);
ReturnExpression(theEnv,theExp->argList);
if ((EvaluationData(theEnv)->EvaluationError) ||
(returnValue->header->type != MULTIFIELD_TYPE))
{
theExp->argList = NULL;
if ((EvaluationData(theEnv)->EvaluationError == false) &&
(returnValue->header->type != MULTIFIELD_TYPE))
ExpectedTypeError2(theEnv,"expand$",1);
theExp->value = FindFunction(theEnv,"(set-evaluation-error)");
EvaluationData(theEnv)->EvaluationError = false;
EvaluationData(theEnv)->HaltExecution = false;
return;
}
top = bot = NULL;
for (i = returnValue->begin ; i < (returnValue->begin + returnValue->range) ; i++)
{
newexp = get_struct(theEnv,expr);
newexp->type = returnValue->multifieldValue->contents[i].header->type;
newexp->value = returnValue->multifieldValue->contents[i].value;
newexp->argList = NULL;
newexp->nextArg = NULL;
if (top == NULL)
top = newexp;
else
bot->nextArg = newexp;
bot = newexp;
}
if (top == NULL)
{
*sto = theExp->nextArg;
rtn_struct(theEnv,expr,theExp);
theExp = *sto;
}
else
{
bot->nextArg = theExp->nextArg;
*sto = top;
rtn_struct(theEnv,expr,theExp);
sto = &bot->nextArg;
theExp = bot->nextArg;
}
}
else
{
if (theExp->argList != NULL)
ExpandFuncMultifield(theEnv,returnValue,theExp->argList,&theExp->argList,expmult);
sto = &theExp->nextArg;
theExp = theExp->nextArg;
}
}
}
void CauseEvaluationError(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
SetEvaluationError(theEnv,true);
returnValue->lexemeValue = FalseSymbol(theEnv);
}
void GetSORCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->lexemeValue = CreateBoolean(theEnv,GetSequenceOperatorRecognition(theEnv));
}
void SetSORCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
#if (! RUN_TIME) && (! BLOAD_ONLY)
UDFValue theArg;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg))
{ return; }
returnValue->lexemeValue = CreateBoolean(theEnv,SetSequenceOperatorRecognition(theEnv,theArg.value != FalseSymbol(theEnv)));
#else
returnValue->lexemeValue = CreateBoolean(theEnv,ExpressionData(theEnv)->SequenceOpMode);
#endif
}
void GetFunctionRestrictions(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UDFValue theArg;
struct functionDefinition *fptr;
char *stringBuffer = NULL;
size_t bufferPosition = 0;
size_t bufferMaximum = 0;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg))
{ return; }
fptr = FindFunction(theEnv,theArg.lexemeValue->contents);
if (fptr == NULL)
{
CantFindItemErrorMessage(theEnv,"function",theArg.lexemeValue->contents,true);
SetEvaluationError(theEnv,true);
returnValue->lexemeValue = CreateString(theEnv,"");
return;
}
if (fptr->minArgs == UNBOUNDED)
{
stringBuffer = AppendToString(theEnv,"0",
stringBuffer,&bufferPosition,&bufferMaximum);
}
else
{
stringBuffer = AppendToString(theEnv,LongIntegerToString(theEnv,fptr->minArgs),
stringBuffer,&bufferPosition,&bufferMaximum);
}
stringBuffer = AppendToString(theEnv,";",
stringBuffer,&bufferPosition,&bufferMaximum);
if (fptr->maxArgs == UNBOUNDED)
{
stringBuffer = AppendToString(theEnv,"*",
stringBuffer,&bufferPosition,&bufferMaximum);
}
else
{
stringBuffer = AppendToString(theEnv,LongIntegerToString(theEnv,fptr->maxArgs),
stringBuffer,&bufferPosition,&bufferMaximum);
}
stringBuffer = AppendToString(theEnv,";",
stringBuffer,&bufferPosition,&bufferMaximum);
if (fptr->restrictions == NULL)
{
stringBuffer = AppendToString(theEnv,"*",
stringBuffer,&bufferPosition,&bufferMaximum);
}
else
{
stringBuffer = AppendToString(theEnv,fptr->restrictions->contents,
stringBuffer,&bufferPosition,&bufferMaximum);
}
returnValue->lexemeValue = CreateString(theEnv,stringBuffer);
rm(theEnv,stringBuffer,bufferMaximum);
}
void GetFunctionListFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
struct functionDefinition *theFunction;
Multifield *theList;
unsigned long functionCount = 0;
for (theFunction = GetFunctionList(theEnv);
theFunction != NULL;
theFunction = theFunction->next)
{ functionCount++; }
returnValue->begin = 0;
returnValue->range = functionCount;
theList = CreateMultifield(theEnv,functionCount);
returnValue->value = theList;
for (theFunction = GetFunctionList(theEnv), functionCount = 0;
theFunction != NULL;
theFunction = theFunction->next, functionCount++)
{
theList->contents[functionCount].lexemeValue = theFunction->callFunctionName;
}
}
void FuncallFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
size_t j;
UDFValue theArg;
Expression theReference;
const char *name;
Multifield *theMultifield;
struct expr *lastAdd = NULL, *nextAdd, *multiAdd;
struct functionDefinition *theFunction = NULL;
returnValue->lexemeValue = FalseSymbol(theEnv);
if (! UDFFirstArgument(context,LEXEME_BITS,&theArg))
{ return; }
name = theArg.lexemeValue->contents;
if (! GetFunctionReference(theEnv,name,&theReference))
{
ExpectedTypeError1(theEnv,"funcall",1,"function, deffunction, or generic function name");
return;
}
if (theReference.type == FCALL)
{
theFunction = FindFunction(theEnv,name);
if (theFunction->parser != NULL)
{
ExpectedTypeError1(theEnv,"funcall",1,"function without specialized parser");
return;
}
}
ExpressionInstall(theEnv,&theReference);
while (UDFHasNextArgument(context))
{
if (! UDFNextArgument(context,ANY_TYPE_BITS,&theArg))
{
ExpressionDeinstall(theEnv,&theReference);
return;
}
switch(theArg.header->type)
{
case MULTIFIELD_TYPE:
nextAdd = GenConstant(theEnv,FCALL,FindFunction(theEnv,"create$"));
if (lastAdd == NULL)
{ theReference.argList = nextAdd; }
else
{ lastAdd->nextArg = nextAdd; }
lastAdd = nextAdd;
multiAdd = NULL;
theMultifield = theArg.multifieldValue;
for (j = theArg.begin; j < (theArg.begin + theArg.range); j++)
{
nextAdd = GenConstant(theEnv,theMultifield->contents[j].header->type,
theMultifield->contents[j].value);
if (multiAdd == NULL)
{ lastAdd->argList = nextAdd; }
else
{ multiAdd->nextArg = nextAdd; }
multiAdd = nextAdd;
}
ExpressionInstall(theEnv,lastAdd);
break;
default:
nextAdd = GenConstant(theEnv,theArg.header->type,theArg.value);
if (lastAdd == NULL)
{ theReference.argList = nextAdd; }
else
{ lastAdd->nextArg = nextAdd; }
lastAdd = nextAdd;
ExpressionInstall(theEnv,lastAdd);
break;
}
}
#if DEFFUNCTION_CONSTRUCT
if (theReference.type == PCALL)
{
if (CheckDeffunctionCall(theEnv,(Deffunction *) theReference.value,CountArguments(theReference.argList)) == false)
{
PrintErrorID(theEnv,"MISCFUN",4,false);
WriteString(theEnv,STDERR,"Function 'funcall' called with the wrong number of arguments for deffunction '");
WriteString(theEnv,STDERR,DeffunctionName((Deffunction *) theReference.value));
WriteString(theEnv,STDERR,"'.\n");
ExpressionDeinstall(theEnv,&theReference);
ReturnExpression(theEnv,theReference.argList);
return;
}
}
#endif
#if ! RUN_TIME
if (theReference.type == FCALL)
{
if (CheckExpressionAgainstRestrictions(theEnv,&theReference,theFunction,name))
{
ExpressionDeinstall(theEnv,&theReference);
ReturnExpression(theEnv,theReference.argList);
return;
}
}
#endif
EvaluateExpression(theEnv,&theReference,returnValue);
ExpressionDeinstall(theEnv,&theReference);
ReturnExpression(theEnv,theReference.argList);
}
void NewFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
int theType;
UDFValue theValue;
const char *name;
returnValue->lexemeValue = FalseSymbol(theEnv);
if (! UDFFirstArgument(context,SYMBOL_BIT,&theValue))
{ return; }
name = theValue.lexemeValue->contents;
theType = FindLanguageType(theEnv,name);
if (theType == -1)
{
ExpectedTypeError1(theEnv,"new",1,"external language");
return;
}
if ((EvaluationData(theEnv)->ExternalAddressTypes[theType] != NULL) &&
(EvaluationData(theEnv)->ExternalAddressTypes[theType]->newFunction != NULL))
{ (*EvaluationData(theEnv)->ExternalAddressTypes[theType]->newFunction)(context,returnValue); }
}
void CallFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
int theType;
UDFValue theValue;
const char *name;
CLIPSExternalAddress *theEA;
returnValue->lexemeValue = FalseSymbol(theEnv);
if (! UDFFirstArgument(context,SYMBOL_BIT | EXTERNAL_ADDRESS_BIT,&theValue))
{ return; }
if (theValue.header->type == SYMBOL_TYPE)
{
name = theValue.lexemeValue->contents;
theType = FindLanguageType(theEnv,name);
if (theType == -1)
{
ExpectedTypeError1(theEnv,"call",1,"external language symbol or external address");
return;
}
if ((EvaluationData(theEnv)->ExternalAddressTypes[theType] != NULL) &&
(EvaluationData(theEnv)->ExternalAddressTypes[theType]->callFunction != NULL))
{ (*EvaluationData(theEnv)->ExternalAddressTypes[theType]->callFunction)(context,&theValue,returnValue); }
return;
}
if (theValue.header->type == EXTERNAL_ADDRESS_TYPE)
{
theEA = theValue.externalAddressValue;
theType = theEA->type;
if ((EvaluationData(theEnv)->ExternalAddressTypes[theType] != NULL) &&
(EvaluationData(theEnv)->ExternalAddressTypes[theType]->callFunction != NULL))
{ (*EvaluationData(theEnv)->ExternalAddressTypes[theType]->callFunction)(context,&theValue,returnValue); }
return;
}
}
static int FindLanguageType(
Environment *theEnv,
const char *languageName)
{
int theType;
for (theType = 0; theType < EvaluationData(theEnv)->numberOfAddressTypes; theType++)
{
if (strcmp(EvaluationData(theEnv)->ExternalAddressTypes[theType]->name,languageName) == 0)
{ return(theType); }
}
return -1;
}
void TimeFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->floatValue = CreateFloat(theEnv,gentime());
}
static void ConvertTime(
Environment *theEnv,
UDFValue *returnValue,
struct tm *info)
{
returnValue->begin = 0;
returnValue->range = 9;
returnValue->value = CreateMultifield(theEnv,9L);
returnValue->multifieldValue->contents[0].integerValue = CreateInteger(theEnv,info->tm_year + 1900);
returnValue->multifieldValue->contents[1].integerValue = CreateInteger(theEnv,info->tm_mon + 1);
returnValue->multifieldValue->contents[2].integerValue = CreateInteger(theEnv,info->tm_mday);
returnValue->multifieldValue->contents[3].integerValue = CreateInteger(theEnv,info->tm_hour);
returnValue->multifieldValue->contents[4].integerValue = CreateInteger(theEnv,info->tm_min);
returnValue->multifieldValue->contents[5].integerValue = CreateInteger(theEnv,info->tm_sec);
switch (info->tm_wday)
{
case 0:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Sunday");
break;
case 1:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Monday");
break;
case 2:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Tuesday");
break;
case 3:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Wednesday");
break;
case 4:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Thursday");
break;
case 5:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Friday");
break;
case 6:
returnValue->multifieldValue->contents[6].lexemeValue = CreateSymbol(theEnv,"Saturday");
break;
}
returnValue->multifieldValue->contents[7].integerValue = CreateInteger(theEnv,info->tm_yday);
if (info->tm_isdst > 0)
{ returnValue->multifieldValue->contents[8].lexemeValue = TrueSymbol(theEnv); }
else if (info->tm_isdst == 0)
{ returnValue->multifieldValue->contents[8].lexemeValue = FalseSymbol(theEnv); }
else
{ returnValue->multifieldValue->contents[8].lexemeValue = CreateSymbol(theEnv,"UNKNOWN"); }
}
void LocalTimeFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
time_t rawtime;
struct tm *info;
time(&rawtime);
info = localtime(&rawtime);
ConvertTime(theEnv,returnValue,info);
}
void GMTimeFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
time_t rawtime;
struct tm *info;
time(&rawtime);
info = gmtime(&rawtime);
ConvertTime(theEnv,returnValue,info);
}
void TimerFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
double startTime;
UDFValue theArg;
startTime = gentime();
while (UDFHasNextArgument(context) &&
(! GetHaltExecution(theEnv)))
{ UDFNextArgument(context,ANY_TYPE_BITS,&theArg); }
returnValue->floatValue = CreateFloat(theEnv,gentime() - startTime);
}
void SystemCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
char *commandBuffer = NULL;
size_t bufferPosition = 0;
size_t bufferMaximum = 0;
UDFValue tempValue;
const char *theString;
while (UDFHasNextArgument(context))
{
if (! UDFNextArgument(context,LEXEME_BITS,&tempValue))
{
returnValue->lexemeValue = FalseSymbol(theEnv);
return;
}
theString = tempValue.lexemeValue->contents;
commandBuffer = AppendToString(theEnv,theString,commandBuffer,&bufferPosition,&bufferMaximum);
}
returnValue->integerValue = CreateInteger(theEnv,gensystem(theEnv,commandBuffer));
if (commandBuffer != NULL)
{ rm(theEnv,commandBuffer,bufferMaximum); }
}
void GetErrorFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
CLIPSToUDFValue(&MiscFunctionData(theEnv)->errorCode,returnValue);
}
void SetErrorValue(
Environment *theEnv,
TypeHeader *theValue)
{
Release(theEnv,MiscFunctionData(theEnv)->errorCode.header);
if (theValue == NULL)
{ MiscFunctionData(theEnv)->errorCode.lexemeValue = FalseSymbol(theEnv); }
else
{ MiscFunctionData(theEnv)->errorCode.header = theValue; }
Retain(theEnv,MiscFunctionData(theEnv)->errorCode.header);
}
void ClearErrorValue(
Environment *theEnv)
{
Release(theEnv,MiscFunctionData(theEnv)->errorCode.header);
MiscFunctionData(theEnv)->errorCode.lexemeValue = FalseSymbol(theEnv);
Retain(theEnv,MiscFunctionData(theEnv)->errorCode.header);
}
void ClearErrorFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
CLIPSToUDFValue(&MiscFunctionData(theEnv)->errorCode,returnValue);
ClearErrorValue(theEnv);
}
void SetErrorFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
CLIPSValue cv;
UDFValue theArg;
if (! UDFFirstArgument(context,ANY_TYPE_BITS,&theArg))
{ return; }
NormalizeMultifield(theEnv,&theArg);
cv.value = theArg.value;
SetErrorValue(theEnv,cv.header);
}
void VoidFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->voidValue = VoidConstant(theEnv);
}