diff options
Diffstat (limited to 'src/utility.c')
-rw-r--r-- | src/utility.c | 978 |
1 files changed, 703 insertions, 275 deletions
diff --git a/src/utility.c b/src/utility.c index ec0373d..951fac5 100644 --- a/src/utility.c +++ b/src/utility.c @@ -1,7 +1,7 @@ /*******************************************************/ /* "C" Language Integrated Production System */ /* */ - /* CLIPS Version 6.24 06/05/06 */ + /* CLIPS Version 6.30 02/03/15 */ /* */ /* UTILITY MODULE */ /*******************************************************/ @@ -16,12 +16,36 @@ /* Gary D. Riley */ /* */ /* Contributing Programmer(s): */ -/* Brian Donnell */ +/* Brian Dantes */ +/* Jeff Bezanson */ +/* www.cprogramming.com/tutorial/unicode.html */ /* */ /* Revision History: */ /* */ /* 6.24: Renamed BOOLEAN macro type to intBool. */ /* */ +/* 6.30: Changed integer type/precision. */ +/* */ +/* Changed garbage collection algorithm. */ +/* */ +/* Added CopyString, DeleteString, */ +/* InsertInString,and EnlargeString functions. */ +/* */ +/* Used genstrncpy function instead of strncpy */ +/* function. */ +/* */ +/* Support for typed EXTERNAL_ADDRESS. */ +/* */ +/* Support for tracked memory (allows memory to */ +/* be freed if CLIPS is exited while executing). */ +/* */ +/* Added UTF-8 routines. */ +/* */ +/* Added const qualifiers to remove C++ */ +/* deprecation warnings. */ +/* */ +/* Converted API macros to function calls. */ +/* */ /*************************************************************/ #define _UTILITY_SOURCE_ @@ -35,12 +59,14 @@ #define _STDIO_INCLUDED_ #include <string.h> +#include "commline.h" #include "envrnmnt.h" #include "evaluatn.h" #include "facthsh.h" #include "memalloc.h" #include "multifld.h" #include "prntutil.h" +#include "sysdep.h" #include "utility.h" @@ -53,9 +79,6 @@ /* LOCAL INTERNAL FUNCTION DEFINITIONS */ /***************************************/ - static intBool AddCPFunction(void *,char *,void (*)(void *), - int,struct cleanupFunction **,intBool); - static intBool RemoveCPFunction(void *,char *,struct cleanupFunction **); static void DeallocateUtilityData(void *); /************************************************/ @@ -67,14 +90,12 @@ globle void InitializeUtilityData( { AllocateEnvironmentData(theEnv,UTILITY_DATA,sizeof(struct utilityData),DeallocateUtilityData); + UtilityData(theEnv)->CurrentGarbageFrame = &UtilityData(theEnv)->MasterGarbageFrame; + UtilityData(theEnv)->CurrentGarbageFrame->topLevel = TRUE; + UtilityData(theEnv)->GarbageCollectionLocks = 0; - UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled = TRUE; UtilityData(theEnv)->PeriodicFunctionsEnabled = TRUE; UtilityData(theEnv)->YieldFunctionEnabled = TRUE; - - UtilityData(theEnv)->CurrentEphemeralCountMax = MAX_EPHEMERAL_COUNT; - UtilityData(theEnv)->CurrentEphemeralSizeMax = MAX_EPHEMERAL_SIZE; - UtilityData(theEnv)->LastEvaluationDepth = -1; } /**************************************************/ @@ -84,13 +105,34 @@ globle void InitializeUtilityData( static void DeallocateUtilityData( void *theEnv) { - struct cleanupFunction *tmpPtr, *nextPtr; + struct callFunctionItem *tmpPtr, *nextPtr; + struct trackedMemory *tmpTM, *nextTM; + struct garbageFrame *theGarbageFrame; + struct ephemeron *edPtr, *nextEDPtr; + struct multifield *tmpMFPtr, *nextMFPtr; + + /*======================*/ + /* Free tracked memory. */ + /*======================*/ + + tmpTM = UtilityData(theEnv)->trackList; + while (tmpTM != NULL) + { + nextTM = tmpTM->next; + genfree(theEnv,tmpTM->theMemory,tmpTM->memSize); + rtn_struct(theEnv,trackedMemory,tmpTM); + tmpTM = nextTM; + } + + /*==========================*/ + /* Free callback functions. */ + /*==========================*/ tmpPtr = UtilityData(theEnv)->ListOfPeriodicFunctions; while (tmpPtr != NULL) { nextPtr = tmpPtr->next; - rtn_struct(theEnv,cleanupFunction,tmpPtr); + rtn_struct(theEnv,callFunctionItem,tmpPtr); tmpPtr = nextPtr; } @@ -98,147 +140,191 @@ static void DeallocateUtilityData( while (tmpPtr != NULL) { nextPtr = tmpPtr->next; - rtn_struct(theEnv,cleanupFunction,tmpPtr); + rtn_struct(theEnv,callFunctionItem,tmpPtr); tmpPtr = nextPtr; } - } -/*************************************************************/ -/* PeriodicCleanup: Returns garbage created during execution */ -/* that has not been returned to the memory pool yet. The */ -/* cleanup is normally deferred so that an executing rule */ -/* can still access these data structures. Always calls a */ -/* series of functions that should be called periodically. */ -/* Usually used by interfaces to update displays. */ -/*************************************************************/ -globle void PeriodicCleanup( - void *theEnv, - intBool cleanupAllDepths, - intBool useHeuristics) - { - int oldDepth = -1; - struct cleanupFunction *cleanupPtr,*periodPtr; + /*=========================================*/ + /* Free the ephemerons tracking data which */ + /* needs to be garbage collected. */ + /*=========================================*/ - /*===================================*/ - /* Don't use heuristics if disabled. */ - /*===================================*/ + while (UtilityData(theEnv)->CurrentGarbageFrame != NULL) + { + theGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame; - if (! UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled) - { useHeuristics = FALSE; } + edPtr = theGarbageFrame->ephemeralSymbolList; - /*=============================================*/ - /* Call functions for handling periodic tasks. */ - /*=============================================*/ + while (edPtr != NULL) + { + nextEDPtr = edPtr->next; + rtn_struct(theEnv,ephemeron,edPtr); + edPtr = nextEDPtr; + } - if (UtilityData(theEnv)->PeriodicFunctionsEnabled) - { - for (periodPtr = UtilityData(theEnv)->ListOfPeriodicFunctions; - periodPtr != NULL; - periodPtr = periodPtr->next) + edPtr = theGarbageFrame->ephemeralFloatList; + + while (edPtr != NULL) { - if (periodPtr->environmentAware) - { (*periodPtr->ip)(theEnv); } - else - { (* (void (*)(void)) periodPtr->ip)(); } + nextEDPtr = edPtr->next; + rtn_struct(theEnv,ephemeron,edPtr); + edPtr = nextEDPtr; } - } - /*===================================================*/ - /* If the last level we performed cleanup was deeper */ - /* than the current level, reset the values used by */ - /* the heuristics to determine if garbage collection */ - /* should be performed. If the heuristic values had */ - /* to be incremented because there was no garbage */ - /* that could be cleaned up, we don't want to keep */ - /* those same high values permanently so we reset */ - /* them when we go back to a lower evaluation depth. */ - /*===================================================*/ - - if (UtilityData(theEnv)->LastEvaluationDepth > EvaluationData(theEnv)->CurrentEvaluationDepth) - { - UtilityData(theEnv)->LastEvaluationDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; - UtilityData(theEnv)->CurrentEphemeralCountMax = MAX_EPHEMERAL_COUNT; - UtilityData(theEnv)->CurrentEphemeralSizeMax = MAX_EPHEMERAL_SIZE; - } + edPtr = theGarbageFrame->ephemeralIntegerList; - /*======================================================*/ - /* If we're using heuristics to determine if garbage */ - /* collection to occur, then check to see if enough */ - /* garbage has been created to make cleanup worthwhile. */ - /*======================================================*/ + while (edPtr != NULL) + { + nextEDPtr = edPtr->next; + rtn_struct(theEnv,ephemeron,edPtr); + edPtr = nextEDPtr; + } - if (UtilityData(theEnv)->GarbageCollectionLocks > 0) return; + edPtr = theGarbageFrame->ephemeralBitMapList; - if (useHeuristics && - (UtilityData(theEnv)->EphemeralItemCount < UtilityData(theEnv)->CurrentEphemeralCountMax) && - (UtilityData(theEnv)->EphemeralItemSize < UtilityData(theEnv)->CurrentEphemeralSizeMax)) - { return; } + while (edPtr != NULL) + { + nextEDPtr = edPtr->next; + rtn_struct(theEnv,ephemeron,edPtr); + edPtr = nextEDPtr; + } - /*==========================================================*/ - /* If cleanup is being performed at all depths, rather than */ - /* just the current evaluation depth, then temporarily set */ - /* the evaluation depth to a level that will force cleanup */ - /* at all depths. */ - /*==========================================================*/ + edPtr = theGarbageFrame->ephemeralExternalAddressList; - if (cleanupAllDepths) - { - oldDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; - EvaluationData(theEnv)->CurrentEvaluationDepth = -1; + while (edPtr != NULL) + { + nextEDPtr = edPtr->next; + rtn_struct(theEnv,ephemeron,edPtr); + edPtr = nextEDPtr; + } + + /*==========================*/ + /* Free up multifield data. */ + /*==========================*/ + + tmpMFPtr = theGarbageFrame->ListOfMultifields; + while (tmpMFPtr != NULL) + { + nextMFPtr = tmpMFPtr->next; + ReturnMultifield(theEnv,tmpMFPtr); + tmpMFPtr = nextMFPtr; + } + + UtilityData(theEnv)->CurrentGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame->priorFrame; } + } + +/*****************************/ +/* CleanCurrentGarbageFrame: */ +/*****************************/ +globle void CleanCurrentGarbageFrame( + void *theEnv, + DATA_OBJECT *returnValue) + { + struct garbageFrame *currentGarbageFrame; + + currentGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame; + + if (! currentGarbageFrame->dirty) return; - /*=============================================*/ - /* Free up multifield values no longer in use. */ - /*=============================================*/ + if (returnValue != NULL) + { ValueInstall(theEnv,returnValue); } + CallCleanupFunctions(theEnv); + RemoveEphemeralAtoms(theEnv); FlushMultifields(theEnv); - /*=====================================*/ - /* Call the list of cleanup functions. */ - /*=====================================*/ + if (returnValue != NULL) + { ValueDeinstall(theEnv,returnValue); } - for (cleanupPtr = UtilityData(theEnv)->ListOfCleanupFunctions; - cleanupPtr != NULL; - cleanupPtr = cleanupPtr->next) + if ((currentGarbageFrame->ephemeralFloatList == NULL) && + (currentGarbageFrame->ephemeralIntegerList == NULL) && + (currentGarbageFrame->ephemeralSymbolList == NULL) && + (currentGarbageFrame->ephemeralBitMapList == NULL) && + (currentGarbageFrame->ephemeralExternalAddressList == NULL) && + (currentGarbageFrame->LastMultifield == NULL)) + { currentGarbageFrame->dirty = FALSE; } + } + +/*****************************/ +/* RestorePriorGarbageFrame: */ +/*****************************/ +globle void RestorePriorGarbageFrame( + void *theEnv, + struct garbageFrame *newGarbageFrame, + struct garbageFrame *oldGarbageFrame, + DATA_OBJECT *returnValue) + { + if (newGarbageFrame->dirty) { - if (cleanupPtr->environmentAware) - { (*cleanupPtr->ip)(theEnv); } - else - { (* (void (*)(void)) cleanupPtr->ip)(); } - } + if (returnValue != NULL) ValueInstall(theEnv,returnValue); + CallCleanupFunctions(theEnv); + RemoveEphemeralAtoms(theEnv); + FlushMultifields(theEnv); + } - /*================================================*/ - /* Free up atomic values that are no longer used. */ - /*================================================*/ + UtilityData(theEnv)->CurrentGarbageFrame = oldGarbageFrame; - RemoveEphemeralAtoms(theEnv); + if (newGarbageFrame->dirty) + { + if (newGarbageFrame->ListOfMultifields != NULL) + { + if (oldGarbageFrame->ListOfMultifields == NULL) + { oldGarbageFrame->ListOfMultifields = newGarbageFrame->ListOfMultifields; } + else + { oldGarbageFrame->LastMultifield->next = newGarbageFrame->ListOfMultifields; } - /*=========================================*/ - /* Restore the evaluation depth if cleanup */ - /* was performed on all depths. */ - /*=========================================*/ + oldGarbageFrame->LastMultifield = newGarbageFrame->LastMultifield; + oldGarbageFrame->dirty = TRUE; + } - if (cleanupAllDepths) EvaluationData(theEnv)->CurrentEvaluationDepth = oldDepth; + if (returnValue != NULL) ValueDeinstall(theEnv,returnValue); + } - /*============================================================*/ - /* If very little memory was freed up, then increment the */ - /* values used by the heuristics so that we don't continually */ - /* try to free up memory that isn't being released. */ - /*============================================================*/ + if (returnValue != NULL) + { EphemerateValue(theEnv,returnValue->type,returnValue->value); } + } - if ((UtilityData(theEnv)->EphemeralItemCount + COUNT_INCREMENT) > UtilityData(theEnv)->CurrentEphemeralCountMax) - { UtilityData(theEnv)->CurrentEphemeralCountMax = UtilityData(theEnv)->EphemeralItemCount + COUNT_INCREMENT; } +/*************************/ +/* CallCleanupFunctions: */ +/*************************/ +globle void CallCleanupFunctions( + void *theEnv) + { + struct callFunctionItem *cleanupPtr; - if ((UtilityData(theEnv)->EphemeralItemSize + SIZE_INCREMENT) > UtilityData(theEnv)->CurrentEphemeralSizeMax) - { UtilityData(theEnv)->CurrentEphemeralSizeMax = UtilityData(theEnv)->EphemeralItemSize + SIZE_INCREMENT; } + for (cleanupPtr = UtilityData(theEnv)->ListOfCleanupFunctions; + cleanupPtr != NULL; + cleanupPtr = cleanupPtr->next) + { + if (cleanupPtr->environmentAware) + { (*cleanupPtr->func)(theEnv); } + else + { (* (void (*)(void)) cleanupPtr->func)(); } + } + } - /*===============================================================*/ - /* Remember the evaluation depth at which garbage collection was */ - /* last performed. This information is used for resetting the */ - /* ephemeral count and size numbers used by the heuristics. */ - /*===============================================================*/ +/**************************************************/ +/* CallPeriodicTasks: Calls the list of functions */ +/* for handling periodic tasks. */ +/**************************************************/ +globle void CallPeriodicTasks( + void *theEnv) + { + struct callFunctionItem *periodPtr; - UtilityData(theEnv)->LastEvaluationDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; + if (UtilityData(theEnv)->PeriodicFunctionsEnabled) + { + for (periodPtr = UtilityData(theEnv)->ListOfPeriodicFunctions; + periodPtr != NULL; + periodPtr = periodPtr->next) + { + if (periodPtr->environmentAware) + { (*periodPtr->func)(theEnv); } + else + { (* (void (*)(void)) periodPtr->func)(); } + } + } } /***************************************************/ @@ -248,20 +334,24 @@ globle void PeriodicCleanup( /***************************************************/ globle intBool AddCleanupFunction( void *theEnv, - char *name, + const char *name, void (*theFunction)(void *), int priority) { - return(AddCPFunction(theEnv,name,theFunction,priority,&UtilityData(theEnv)->ListOfCleanupFunctions,TRUE)); + UtilityData(theEnv)->ListOfCleanupFunctions = + AddFunctionToCallList(theEnv,name,priority, + (void (*)(void *)) theFunction, + UtilityData(theEnv)->ListOfCleanupFunctions,TRUE); + return(1); } -#if (! ENVIRONMENT_API_ONLY) && ALLOW_ENVIRONMENT_GLOBALS +#if ALLOW_ENVIRONMENT_GLOBALS /****************************************************/ /* AddPeriodicFunction: Adds a function to the list */ /* of functions called to handle periodic tasks. */ /****************************************************/ globle intBool AddPeriodicFunction( - char *name, + const char *name, void (*theFunction)(void), int priority) { @@ -269,8 +359,12 @@ globle intBool AddPeriodicFunction( theEnv = GetCurrentEnvironment(); - return(AddCPFunction(theEnv,name,(void (*)(void *)) theFunction,priority, - &UtilityData(theEnv)->ListOfPeriodicFunctions,FALSE)); + UtilityData(theEnv)->ListOfPeriodicFunctions = + AddFunctionToCallList(theEnv,name,priority, + (void (*)(void *)) theFunction, + UtilityData(theEnv)->ListOfPeriodicFunctions,FALSE); + + return(1); } #endif @@ -280,59 +374,14 @@ globle intBool AddPeriodicFunction( /*******************************************************/ globle intBool EnvAddPeriodicFunction( void *theEnv, - char *name, + const char *name, void (*theFunction)(void *), int priority) { - return(AddCPFunction(theEnv,name,theFunction,priority,&UtilityData(theEnv)->ListOfPeriodicFunctions,TRUE)); - } - -/**********************************/ -/* AddCPFunction: Adds a function */ -/* to a list of functions. */ -/**********************************/ -static intBool AddCPFunction( - void *theEnv, - char *name, - void (*theFunction)(void *), - int priority, - struct cleanupFunction **head, - intBool environmentAware) - { - struct cleanupFunction *newPtr, *currentPtr, *lastPtr = NULL; - - newPtr = get_struct(theEnv,cleanupFunction); - - newPtr->name = name; - newPtr->ip = theFunction; - newPtr->priority = priority; - newPtr->environmentAware = (short) environmentAware; - - if (*head == NULL) - { - newPtr->next = NULL; - *head = newPtr; - return(1); - } - - currentPtr = *head; - while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE) - { - lastPtr = currentPtr; - currentPtr = currentPtr->next; - } - - if (lastPtr == NULL) - { - newPtr->next = *head; - *head = newPtr; - } - else - { - newPtr->next = currentPtr; - lastPtr->next = newPtr; - } - + UtilityData(theEnv)->ListOfPeriodicFunctions = + AddFunctionToCallList(theEnv,name,priority, + (void (*)(void *)) theFunction, + UtilityData(theEnv)->ListOfPeriodicFunctions,TRUE); return(1); } @@ -343,9 +392,14 @@ static intBool AddCPFunction( /*******************************************************/ globle intBool RemoveCleanupFunction( void *theEnv, - char *name) + const char *name) { - return(RemoveCPFunction(theEnv,name,&UtilityData(theEnv)->ListOfCleanupFunctions)); + intBool found; + + UtilityData(theEnv)->ListOfCleanupFunctions = + RemoveFunctionFromCallList(theEnv,name,UtilityData(theEnv)->ListOfCleanupFunctions,&found); + + return found; } /**********************************************************/ @@ -354,53 +408,27 @@ globle intBool RemoveCleanupFunction( /**********************************************************/ globle intBool EnvRemovePeriodicFunction( void *theEnv, - char *name) - { - return(RemoveCPFunction(theEnv,name,&UtilityData(theEnv)->ListOfPeriodicFunctions)); - } - -/****************************************/ -/* RemoveCPFunction: Removes a function */ -/* from a list of functions. */ -/****************************************/ -static intBool RemoveCPFunction( - void *theEnv, - char *name, - struct cleanupFunction **head) + const char *name) { - struct cleanupFunction *currentPtr, *lastPtr; - - lastPtr = NULL; - currentPtr = *head; + intBool found; - while (currentPtr != NULL) - { - if (strcmp(name,currentPtr->name) == 0) - { - if (lastPtr == NULL) - { *head = currentPtr->next; } - else - { lastPtr->next = currentPtr->next; } - rtn_struct(theEnv,cleanupFunction,currentPtr); - return(TRUE); - } - lastPtr = currentPtr; - currentPtr = currentPtr->next; - } + UtilityData(theEnv)->ListOfPeriodicFunctions = + RemoveFunctionFromCallList(theEnv,name,UtilityData(theEnv)->ListOfPeriodicFunctions,&found); - return(FALSE); + return found; } /*****************************************************/ /* StringPrintForm: Generates printed representation */ /* of a string. Replaces / with // and " with /". */ /*****************************************************/ -globle char *StringPrintForm( +globle const char *StringPrintForm( void *theEnv, - char *str) + const char *str) { - int i = 0, pos = 0; - unsigned max = 0; + int i = 0; + size_t pos = 0; + size_t max = 0; char *theString = NULL; void *thePtr; @@ -424,18 +452,47 @@ globle char *StringPrintForm( return(ValueToString(thePtr)); } +/**************************************************************/ +/* CopyString: Copies a string using CLIPS memory management. */ +/**************************************************************/ +globle char *CopyString( + void *theEnv, + const char *theString) + { + char *stringCopy = NULL; + + if (theString != NULL) + { + stringCopy = (char *) genalloc(theEnv,strlen(theString) + 1); + genstrcpy(stringCopy,theString); + } + + return stringCopy; + } + +/*****************************************************************/ +/* DeleteString: Deletes a string using CLIPS memory management. */ +/*****************************************************************/ +globle void DeleteString( + void *theEnv, + char *theString) + { + if (theString != NULL) + { genfree(theEnv,theString,strlen(theString) + 1); } + } + /***********************************************************/ /* AppendStrings: Appends two strings together. The string */ /* created is added to the SymbolTable, so it is not */ /* necessary to deallocate the string returned. */ /***********************************************************/ -globle char *AppendStrings( +globle const char *AppendStrings( void *theEnv, - char *str1, - char *str2) + const char *str1, + const char *str2) { - int pos = 0; - unsigned max = 0; + size_t pos = 0; + size_t max = 0; char *theString = NULL; void *thePtr; @@ -453,10 +510,10 @@ globle char *AppendStrings( /******************************************************/ globle char *AppendToString( void *theEnv, - char *appendStr, + const char *appendStr, char *oldStr, - int *oldPos, - unsigned *oldMax) + size_t *oldPos, + size_t *oldMax) { size_t length; @@ -466,23 +523,66 @@ globle char *AppendToString( /*=========================================*/ length = strlen(appendStr); - if (length + *oldPos + 1 > *oldMax) - { - oldStr = (char *) genrealloc(theEnv,oldStr,(unsigned) *oldMax,(unsigned) length + *oldPos + 1); - *oldMax = length + *oldPos + 1; - } /*==============================================================*/ /* Return NULL if the old string was not successfully expanded. */ /*==============================================================*/ - if (oldStr == NULL) { return(NULL); } + if ((oldStr = EnlargeString(theEnv,length,oldStr,oldPos,oldMax)) == NULL) { return(NULL); } /*===============================================*/ /* Append the new string to the expanded string. */ /*===============================================*/ - strcpy(&oldStr[*oldPos],appendStr); + genstrcpy(&oldStr[*oldPos],appendStr); + *oldPos += (int) length; + + /*============================================================*/ + /* Return the expanded string containing the appended string. */ + /*============================================================*/ + + return(oldStr); + } + +/**********************************************************/ +/* InsertInString: Inserts a string within another string */ +/* (expanding the other string if necessary). */ +/**********************************************************/ +globle char *InsertInString( + void *theEnv, + const char *insertStr, + size_t position, + char *oldStr, + size_t *oldPos, + size_t *oldMax) + { + size_t length; + + /*=========================================*/ + /* Expand the old string so it can contain */ + /* the new string (if necessary). */ + /*=========================================*/ + + length = strlen(insertStr); + + /*==============================================================*/ + /* Return NULL if the old string was not successfully expanded. */ + /*==============================================================*/ + + if ((oldStr = EnlargeString(theEnv,length,oldStr,oldPos,oldMax)) == NULL) { return(NULL); } + + /*================================================================*/ + /* Shift the contents to the right of insertion point so that the */ + /* new text does not overwrite what is currently in the string. */ + /*================================================================*/ + + memmove(&oldStr[position],&oldStr[position+length],*oldPos - position); + + /*===============================================*/ + /* Insert the new string in the expanded string. */ + /*===============================================*/ + + genstrncpy(&oldStr[*oldPos],insertStr,length); *oldPos += (int) length; /*============================================================*/ @@ -492,6 +592,36 @@ globle char *AppendToString( return(oldStr); } +/*******************************************************************/ +/* EnlargeString: Enlarges a string by the specified amount. */ +/*******************************************************************/ +globle char *EnlargeString( + void *theEnv, + size_t length, + char *oldStr, + size_t *oldPos, + size_t *oldMax) + { + /*=========================================*/ + /* Expand the old string so it can contain */ + /* the new string (if necessary). */ + /*=========================================*/ + + if (length + *oldPos + 1 > *oldMax) + { + oldStr = (char *) genrealloc(theEnv,oldStr,*oldMax,length + *oldPos + 1); + *oldMax = length + *oldPos + 1; + } + + /*==============================================================*/ + /* Return NULL if the old string was not successfully expanded. */ + /*==============================================================*/ + + if (oldStr == NULL) { return(NULL); } + + return(oldStr); + } + /*******************************************************/ /* AppendNToString: Appends a string to another string */ /* (expanding the other string if necessary). Only a */ @@ -500,13 +630,13 @@ globle char *AppendToString( /*******************************************************/ globle char *AppendNToString( void *theEnv, - char *appendStr, + const char *appendStr, char *oldStr, - unsigned length, - int *oldPos, - unsigned *oldMax) + size_t length, + size_t *oldPos, + size_t *oldMax) { - unsigned lengthWithEOS; + size_t lengthWithEOS; /*====================================*/ /* Determine the number of characters */ @@ -523,8 +653,8 @@ globle char *AppendNToString( if (lengthWithEOS + *oldPos > *oldMax) { - oldStr = (char *) genrealloc(theEnv,oldStr,(unsigned) *oldMax,(unsigned) *oldPos + lengthWithEOS); - *oldMax = (unsigned) *oldPos + lengthWithEOS; + oldStr = (char *) genrealloc(theEnv,oldStr,*oldMax,*oldPos + lengthWithEOS); + *oldMax = *oldPos + lengthWithEOS; } /*==============================================================*/ @@ -538,8 +668,8 @@ globle char *AppendNToString( /* string to the expanded string. */ /*==================================*/ - strncpy(&oldStr[*oldPos],appendStr,(STD_SIZE) length); - *oldPos += (int) (lengthWithEOS - 1); + genstrncpy(&oldStr[*oldPos],appendStr,length); + *oldPos += (lengthWithEOS - 1); oldStr[*oldPos] = '\0'; /*============================================================*/ @@ -560,11 +690,11 @@ globle char *ExpandStringWithChar( void *theEnv, int inchar, char *str, - int *pos, - unsigned *max, - unsigned newSize) + size_t *pos, + size_t *max, + size_t newSize) { - if ((*pos + 1) >= (int) *max) + if ((*pos + 1) >= *max) { str = (char *) genrealloc(theEnv,str,*max,newSize); *max = newSize; @@ -578,6 +708,17 @@ globle char *ExpandStringWithChar( } else { + /*===========================================================*/ + /* First delete any UTF-8 multibyte continuation characters. */ + /*===========================================================*/ + + while ((*pos > 1) && IsUTF8MultiByteContinuation(str[*pos - 1])) + { (*pos)--; } + + /*===================================================*/ + /* Now delete the first byte of the UTF-8 character. */ + /*===================================================*/ + if (*pos > 0) (*pos)--; str[*pos] = '\0'; } @@ -592,12 +733,29 @@ globle char *ExpandStringWithChar( /*****************************************************************/ globle struct callFunctionItem *AddFunctionToCallList( void *theEnv, - char *name, + const char *name, int priority, void (*func)(void *), struct callFunctionItem *head, intBool environmentAware) { + return AddFunctionToCallListWithContext(theEnv,name,priority,func,head,environmentAware,NULL); + } + +/***********************************************************/ +/* AddFunctionToCallListWithContext: Adds a function to a */ +/* list of functions which are called to perform certain */ +/* operations (e.g. clear, reset, and bload functions). */ +/***********************************************************/ +globle struct callFunctionItem *AddFunctionToCallListWithContext( + void *theEnv, + const char *name, + int priority, + void (*func)(void *), + struct callFunctionItem *head, + intBool environmentAware, + void *context) + { struct callFunctionItem *newPtr, *currentPtr, *lastPtr = NULL; newPtr = get_struct(theEnv,callFunctionItem); @@ -606,6 +764,7 @@ globle struct callFunctionItem *AddFunctionToCallList( newPtr->func = func; newPtr->priority = priority; newPtr->environmentAware = (short) environmentAware; + newPtr->context = context; if (head == NULL) { @@ -641,7 +800,7 @@ globle struct callFunctionItem *AddFunctionToCallList( /*****************************************************************/ globle struct callFunctionItem *RemoveFunctionFromCallList( void *theEnv, - char *name, + const char *name, struct callFunctionItem *head, int *found) { @@ -692,16 +851,147 @@ globle void DeallocateCallList( } } +/***************************************************************/ +/* AddFunctionToCallListWithArg: Adds a function to a list of */ +/* functions which are called to perform certain operations */ +/* (e.g. clear,reset, and bload functions). */ +/***************************************************************/ +globle struct callFunctionItemWithArg *AddFunctionToCallListWithArg( + void *theEnv, + const char *name, + int priority, + void (*func)(void *, void *), + struct callFunctionItemWithArg *head, + intBool environmentAware) + { + return AddFunctionToCallListWithArgWithContext(theEnv,name,priority,func,head,environmentAware,NULL); + } + +/***************************************************************/ +/* AddFunctionToCallListWithArgWithContext: Adds a function to */ +/* a list of functions which are called to perform certain */ +/* operations (e.g. clear, reset, and bload functions). */ +/***************************************************************/ +globle struct callFunctionItemWithArg *AddFunctionToCallListWithArgWithContext( + void *theEnv, + const char *name, + int priority, + void (*func)(void *, void *), + struct callFunctionItemWithArg *head, + intBool environmentAware, + void *context) + { + struct callFunctionItemWithArg *newPtr, *currentPtr, *lastPtr = NULL; + + newPtr = get_struct(theEnv,callFunctionItemWithArg); + + newPtr->name = name; + newPtr->func = func; + newPtr->priority = priority; + newPtr->environmentAware = (short) environmentAware; + newPtr->context = context; + + if (head == NULL) + { + newPtr->next = NULL; + return(newPtr); + } + + currentPtr = head; + while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE) + { + lastPtr = currentPtr; + currentPtr = currentPtr->next; + } + + if (lastPtr == NULL) + { + newPtr->next = head; + head = newPtr; + } + else + { + newPtr->next = currentPtr; + lastPtr->next = newPtr; + } + + return(head); + } + +/**************************************************************/ +/* RemoveFunctionFromCallListWithArg: Removes a function from */ +/* a list of functions which are called to perform certain */ +/* operations (e.g. clear, reset, and bload functions). */ +/**************************************************************/ +globle struct callFunctionItemWithArg *RemoveFunctionFromCallListWithArg( + void *theEnv, + const char *name, + struct callFunctionItemWithArg *head, + int *found) + { + struct callFunctionItemWithArg *currentPtr, *lastPtr; + + *found = FALSE; + lastPtr = NULL; + currentPtr = head; + + while (currentPtr != NULL) + { + if (strcmp(name,currentPtr->name) == 0) + { + *found = TRUE; + if (lastPtr == NULL) + { head = currentPtr->next; } + else + { lastPtr->next = currentPtr->next; } + + rtn_struct(theEnv,callFunctionItemWithArg,currentPtr); + return(head); + } + + lastPtr = currentPtr; + currentPtr = currentPtr->next; + } + + return(head); + } + +/**************************************************************/ +/* DeallocateCallListWithArg: Removes all functions from a list of */ +/* functions which are called to perform certain operations */ +/* (e.g. clear, reset, and bload functions). */ +/**************************************************************/ +globle void DeallocateCallListWithArg( + void *theEnv, + struct callFunctionItemWithArg *theList) + { + struct callFunctionItemWithArg *tmpPtr, *nextPtr; + + tmpPtr = theList; + while (tmpPtr != NULL) + { + nextPtr = tmpPtr->next; + rtn_struct(theEnv,callFunctionItemWithArg,tmpPtr); + tmpPtr = nextPtr; + } + } + /*****************************************/ /* ItemHashValue: Returns the hash value */ /* for the specified value. */ /*****************************************/ -globle unsigned ItemHashValue( +globle unsigned long ItemHashValue( void *theEnv, unsigned short theType, void *theValue, - unsigned theRange) + unsigned long theRange) { + union + { + void *vv; + unsigned uv; + } fis; + switch(theType) { case FLOAT: @@ -722,17 +1012,18 @@ globle unsigned ItemHashValue( #if DEFTEMPLATE_CONSTRUCT case FACT_ADDRESS: - return(HashFact((struct fact *) theValue) % theRange); + return(((struct fact *) theValue)->hashValue % theRange); #endif case EXTERNAL_ADDRESS: + return(HashExternalAddress(ValueToExternalAddress(theValue),theRange)); + #if OBJECT_SYSTEM case INSTANCE_ADDRESS: #endif - return(((unsigned) theValue) % theRange); - - default: - break; + fis.uv = 0; + fis.vv = theValue; + return(fis.uv % theRange); } SystemError(theEnv,"UTILITY",1); @@ -745,29 +1036,13 @@ globle unsigned ItemHashValue( /* application responsiveness when CLIPS */ /* is running in the background. */ /********************************************/ -void YieldTime( +globle void YieldTime( void *theEnv) { if ((UtilityData(theEnv)->YieldTimeFunction != NULL) && UtilityData(theEnv)->YieldFunctionEnabled) { (*UtilityData(theEnv)->YieldTimeFunction)(); } } -/********************************************/ -/* SetGarbageCollectionHeuristics: */ -/********************************************/ -short SetGarbageCollectionHeuristics( - void *theEnv, - short newValue) - { - short oldValue; - - oldValue = UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled; - - UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled = newValue; - - return(oldValue); - } - /**********************************************/ /* EnvIncrementGCLocks: Increments the number */ /* of garbage collection locks. */ @@ -787,12 +1062,19 @@ globle void EnvDecrementGCLocks( { if (UtilityData(theEnv)->GarbageCollectionLocks > 0) { UtilityData(theEnv)->GarbageCollectionLocks--; } + + if ((UtilityData(theEnv)->CurrentGarbageFrame->topLevel) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) && + (EvaluationData(theEnv)->CurrentExpression == NULL) && (UtilityData(theEnv)->GarbageCollectionLocks == 0)) + { + CleanCurrentGarbageFrame(theEnv,NULL); + CallPeriodicTasks(theEnv); + } } /********************************************/ /* EnablePeriodicFunctions: */ /********************************************/ -short EnablePeriodicFunctions( +globle short EnablePeriodicFunctions( void *theEnv, short value) { @@ -805,10 +1087,10 @@ short EnablePeriodicFunctions( return(oldValue); } -/********************************************/ -/* EnableYieldFunction: */ -/********************************************/ -short EnableYieldFunction( +/************************/ +/* EnableYieldFunction: */ +/************************/ +globle short EnableYieldFunction( void *theEnv, short value) { @@ -820,3 +1102,149 @@ short EnableYieldFunction( return(oldValue); } + +/*************************************************************************/ +/* AddTrackedMemory: Tracked memory is memory allocated by CLIPS that's */ +/* referenced by a variable on the stack, but not by any environment */ +/* data structure. An example would be the storage for local variables */ +/* allocated when a deffunction is executed. Tracking this memory */ +/* allows it to be removed later when using longjmp as the code that */ +/* would normally deallocate the memory would be bypassed. */ +/*************************************************************************/ +globle struct trackedMemory *AddTrackedMemory( + void *theEnv, + void *theMemory, + size_t theSize) + { + struct trackedMemory *newPtr; + + newPtr = get_struct(theEnv,trackedMemory); + + newPtr->prev = NULL; + newPtr->theMemory = theMemory; + newPtr->memSize = theSize; + newPtr->next = UtilityData(theEnv)->trackList; + UtilityData(theEnv)->trackList = newPtr; + + return newPtr; + } + +/************************/ +/* RemoveTrackedMemory: */ +/************************/ +globle void RemoveTrackedMemory( + void *theEnv, + struct trackedMemory *theTracker) + { + if (theTracker->prev == NULL) + { UtilityData(theEnv)->trackList = theTracker->next; } + else + { theTracker->prev->next = theTracker->next; } + + if (theTracker->next != NULL) + { theTracker->next->prev = theTracker->prev; } + + rtn_struct(theEnv,trackedMemory,theTracker); + } + +/******************************************/ +/* UTF8Length: Returns the logical number */ +/* of characters in a UTF8 string. */ +/******************************************/ +globle size_t UTF8Length( + const char *s) + { + size_t i = 0, length = 0; + + while (s[i] != '\0') + { + UTF8Increment(s,&i); + length++; + } + + return(length); + } + +/*********************************************/ +/* UTF8Increment: Finds the beginning of the */ +/* next character in a UTF8 string. */ +/*********************************************/ +globle void UTF8Increment( + const char *s, + size_t *i) + { + (void) (IsUTF8Start(s[++(*i)]) || + IsUTF8Start(s[++(*i)]) || + IsUTF8Start(s[++(*i)]) || + ++(*i)); + } + +/****************************************************/ +/* UTF8Offset: Converts the logical character index */ +/* in a UTF8 string to the actual byte offset. */ +/****************************************************/ +globle size_t UTF8Offset( + const char *str, + size_t charnum) + { + size_t offs = 0; + + while ((charnum > 0) && (str[offs])) + { + (void) (IsUTF8Start(str[++offs]) || + IsUTF8Start(str[++offs]) || + IsUTF8Start(str[++offs]) || + ++offs); + + charnum--; + } + + return offs; + } + +/*************************************************/ +/* UTF8CharNum: Converts the UTF8 character byte */ +/* offset to the logical character index. */ +/*************************************************/ +globle size_t UTF8CharNum( + const char *s, + size_t offset) + { + size_t charnum = 0, offs=0; + + while ((offs < offset) && (s[offs])) + { + (void) (IsUTF8Start(s[++offs]) || + IsUTF8Start(s[++offs]) || + IsUTF8Start(s[++offs]) || + ++offs); + + charnum++; + } + + return charnum; + } + +/*#####################################*/ +/* ALLOW_ENVIRONMENT_GLOBALS Functions */ +/*#####################################*/ + +#if ALLOW_ENVIRONMENT_GLOBALS + +globle void IncrementGCLocks() + { + EnvIncrementGCLocks(GetCurrentEnvironment()); + } + +globle void DecrementGCLocks() + { + EnvDecrementGCLocks(GetCurrentEnvironment()); + } + +globle intBool RemovePeriodicFunction( + const char *name) + { + return EnvRemovePeriodicFunction(GetCurrentEnvironment(),name); + } + +#endif /* ALLOW_ENVIRONMENT_GLOBALS */ |