summaryrefslogtreecommitdiff
path: root/src/utility.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utility.c')
-rw-r--r--src/utility.c978
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 */