1 /*******************************************************/
2 /* "C" Language Integrated Production System */
4 /* CLIPS Version 6.30 02/03/15 */
7 /*******************************************************/
9 /*************************************************************/
10 /* Purpose: Provides a set of utility functions useful to */
11 /* other modules. Primarily these are the functions for */
12 /* handling periodic garbage collection and appending */
15 /* Principal Programmer(s): */
18 /* Contributing Programmer(s): */
21 /* www.cprogramming.com/tutorial/unicode.html */
23 /* Revision History: */
25 /* 6.24: Renamed BOOLEAN macro type to intBool. */
27 /* 6.30: Changed integer type/precision. */
29 /* Changed garbage collection algorithm. */
31 /* Added CopyString, DeleteString, */
32 /* InsertInString,and EnlargeString functions. */
34 /* Used genstrncpy function instead of strncpy */
37 /* Support for typed EXTERNAL_ADDRESS. */
39 /* Support for tracked memory (allows memory to */
40 /* be freed if CLIPS is exited while executing). */
42 /* Added UTF-8 routines. */
44 /* Added const qualifiers to remove C++ */
45 /* deprecation warnings. */
47 /* Converted API macros to function calls. */
49 /*************************************************************/
51 #define _UTILITY_SOURCE_
59 #define _STDIO_INCLUDED_
73 #define MAX_EPHEMERAL_COUNT 1000L
74 #define MAX_EPHEMERAL_SIZE 10240L
75 #define COUNT_INCREMENT 1000L
76 #define SIZE_INCREMENT 10240L
78 /***************************************/
79 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
80 /***************************************/
82 static void DeallocateUtilityData(void *);
84 /************************************************/
85 /* InitializeUtilityData: Allocates environment */
86 /* data for utility routines. */
87 /************************************************/
88 globle void InitializeUtilityData(
91 AllocateEnvironmentData(theEnv,UTILITY_DATA,sizeof(struct utilityData),DeallocateUtilityData);
93 UtilityData(theEnv)->CurrentGarbageFrame = &UtilityData(theEnv)->MasterGarbageFrame;
94 UtilityData(theEnv)->CurrentGarbageFrame->topLevel = TRUE;
96 UtilityData(theEnv)->GarbageCollectionLocks = 0;
97 UtilityData(theEnv)->PeriodicFunctionsEnabled = TRUE;
98 UtilityData(theEnv)->YieldFunctionEnabled = TRUE;
101 /**************************************************/
102 /* DeallocateUtilityData: Deallocates environment */
103 /* data for utility routines. */
104 /**************************************************/
105 static void DeallocateUtilityData(
108 struct callFunctionItem *tmpPtr, *nextPtr;
109 struct trackedMemory *tmpTM, *nextTM;
110 struct garbageFrame *theGarbageFrame;
111 struct ephemeron *edPtr, *nextEDPtr;
112 struct multifield *tmpMFPtr, *nextMFPtr;
114 /*======================*/
115 /* Free tracked memory. */
116 /*======================*/
118 tmpTM = UtilityData(theEnv)->trackList;
119 while (tmpTM != NULL)
121 nextTM = tmpTM->next;
122 genfree(theEnv,tmpTM->theMemory,tmpTM->memSize);
123 rtn_struct(theEnv,trackedMemory,tmpTM);
127 /*==========================*/
128 /* Free callback functions. */
129 /*==========================*/
131 tmpPtr = UtilityData(theEnv)->ListOfPeriodicFunctions;
132 while (tmpPtr != NULL)
134 nextPtr = tmpPtr->next;
135 rtn_struct(theEnv,callFunctionItem,tmpPtr);
139 tmpPtr = UtilityData(theEnv)->ListOfCleanupFunctions;
140 while (tmpPtr != NULL)
142 nextPtr = tmpPtr->next;
143 rtn_struct(theEnv,callFunctionItem,tmpPtr);
147 /*=========================================*/
148 /* Free the ephemerons tracking data which */
149 /* needs to be garbage collected. */
150 /*=========================================*/
152 while (UtilityData(theEnv)->CurrentGarbageFrame != NULL)
154 theGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame;
156 edPtr = theGarbageFrame->ephemeralSymbolList;
158 while (edPtr != NULL)
160 nextEDPtr = edPtr->next;
161 rtn_struct(theEnv,ephemeron,edPtr);
165 edPtr = theGarbageFrame->ephemeralFloatList;
167 while (edPtr != NULL)
169 nextEDPtr = edPtr->next;
170 rtn_struct(theEnv,ephemeron,edPtr);
174 edPtr = theGarbageFrame->ephemeralIntegerList;
176 while (edPtr != NULL)
178 nextEDPtr = edPtr->next;
179 rtn_struct(theEnv,ephemeron,edPtr);
183 edPtr = theGarbageFrame->ephemeralBitMapList;
185 while (edPtr != NULL)
187 nextEDPtr = edPtr->next;
188 rtn_struct(theEnv,ephemeron,edPtr);
192 edPtr = theGarbageFrame->ephemeralExternalAddressList;
194 while (edPtr != NULL)
196 nextEDPtr = edPtr->next;
197 rtn_struct(theEnv,ephemeron,edPtr);
201 /*==========================*/
202 /* Free up multifield data. */
203 /*==========================*/
205 tmpMFPtr = theGarbageFrame->ListOfMultifields;
206 while (tmpMFPtr != NULL)
208 nextMFPtr = tmpMFPtr->next;
209 ReturnMultifield(theEnv,tmpMFPtr);
210 tmpMFPtr = nextMFPtr;
213 UtilityData(theEnv)->CurrentGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame->priorFrame;
217 /*****************************/
218 /* CleanCurrentGarbageFrame: */
219 /*****************************/
220 globle void CleanCurrentGarbageFrame(
222 DATA_OBJECT *returnValue)
224 struct garbageFrame *currentGarbageFrame;
226 currentGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame;
228 if (! currentGarbageFrame->dirty) return;
230 if (returnValue != NULL)
231 { ValueInstall(theEnv,returnValue); }
233 CallCleanupFunctions(theEnv);
234 RemoveEphemeralAtoms(theEnv);
235 FlushMultifields(theEnv);
237 if (returnValue != NULL)
238 { ValueDeinstall(theEnv,returnValue); }
240 if ((currentGarbageFrame->ephemeralFloatList == NULL) &&
241 (currentGarbageFrame->ephemeralIntegerList == NULL) &&
242 (currentGarbageFrame->ephemeralSymbolList == NULL) &&
243 (currentGarbageFrame->ephemeralBitMapList == NULL) &&
244 (currentGarbageFrame->ephemeralExternalAddressList == NULL) &&
245 (currentGarbageFrame->LastMultifield == NULL))
246 { currentGarbageFrame->dirty = FALSE; }
249 /*****************************/
250 /* RestorePriorGarbageFrame: */
251 /*****************************/
252 globle void RestorePriorGarbageFrame(
254 struct garbageFrame *newGarbageFrame,
255 struct garbageFrame *oldGarbageFrame,
256 DATA_OBJECT *returnValue)
258 if (newGarbageFrame->dirty)
260 if (returnValue != NULL) ValueInstall(theEnv,returnValue);
261 CallCleanupFunctions(theEnv);
262 RemoveEphemeralAtoms(theEnv);
263 FlushMultifields(theEnv);
266 UtilityData(theEnv)->CurrentGarbageFrame = oldGarbageFrame;
268 if (newGarbageFrame->dirty)
270 if (newGarbageFrame->ListOfMultifields != NULL)
272 if (oldGarbageFrame->ListOfMultifields == NULL)
273 { oldGarbageFrame->ListOfMultifields = newGarbageFrame->ListOfMultifields; }
275 { oldGarbageFrame->LastMultifield->next = newGarbageFrame->ListOfMultifields; }
277 oldGarbageFrame->LastMultifield = newGarbageFrame->LastMultifield;
278 oldGarbageFrame->dirty = TRUE;
281 if (returnValue != NULL) ValueDeinstall(theEnv,returnValue);
284 if (returnValue != NULL)
285 { EphemerateValue(theEnv,returnValue->type,returnValue->value); }
288 /*************************/
289 /* CallCleanupFunctions: */
290 /*************************/
291 globle void CallCleanupFunctions(
294 struct callFunctionItem *cleanupPtr;
296 for (cleanupPtr = UtilityData(theEnv)->ListOfCleanupFunctions;
298 cleanupPtr = cleanupPtr->next)
300 if (cleanupPtr->environmentAware)
301 { (*cleanupPtr->func)(theEnv); }
303 { (* (void (*)(void)) cleanupPtr->func)(); }
307 /**************************************************/
308 /* CallPeriodicTasks: Calls the list of functions */
309 /* for handling periodic tasks. */
310 /**************************************************/
311 globle void CallPeriodicTasks(
314 struct callFunctionItem *periodPtr;
316 if (UtilityData(theEnv)->PeriodicFunctionsEnabled)
318 for (periodPtr = UtilityData(theEnv)->ListOfPeriodicFunctions;
320 periodPtr = periodPtr->next)
322 if (periodPtr->environmentAware)
323 { (*periodPtr->func)(theEnv); }
325 { (* (void (*)(void)) periodPtr->func)(); }
330 /***************************************************/
331 /* AddCleanupFunction: Adds a function to the list */
332 /* of functions called to perform cleanup such */
333 /* as returning free memory to the memory pool. */
334 /***************************************************/
335 globle intBool AddCleanupFunction(
338 void (*theFunction)(void *),
341 UtilityData(theEnv)->ListOfCleanupFunctions =
342 AddFunctionToCallList(theEnv,name,priority,
343 (void (*)(void *)) theFunction,
344 UtilityData(theEnv)->ListOfCleanupFunctions,TRUE);
348 #if ALLOW_ENVIRONMENT_GLOBALS
349 /****************************************************/
350 /* AddPeriodicFunction: Adds a function to the list */
351 /* of functions called to handle periodic tasks. */
352 /****************************************************/
353 globle intBool AddPeriodicFunction(
355 void (*theFunction)(void),
360 theEnv = GetCurrentEnvironment();
362 UtilityData(theEnv)->ListOfPeriodicFunctions =
363 AddFunctionToCallList(theEnv,name,priority,
364 (void (*)(void *)) theFunction,
365 UtilityData(theEnv)->ListOfPeriodicFunctions,FALSE);
371 /*******************************************************/
372 /* EnvAddPeriodicFunction: Adds a function to the list */
373 /* of functions called to handle periodic tasks. */
374 /*******************************************************/
375 globle intBool EnvAddPeriodicFunction(
378 void (*theFunction)(void *),
381 UtilityData(theEnv)->ListOfPeriodicFunctions =
382 AddFunctionToCallList(theEnv,name,priority,
383 (void (*)(void *)) theFunction,
384 UtilityData(theEnv)->ListOfPeriodicFunctions,TRUE);
388 /*******************************************************/
389 /* RemoveCleanupFunction: Removes a function from the */
390 /* list of functions called to perform cleanup such */
391 /* as returning free memory to the memory pool. */
392 /*******************************************************/
393 globle intBool RemoveCleanupFunction(
399 UtilityData(theEnv)->ListOfCleanupFunctions =
400 RemoveFunctionFromCallList(theEnv,name,UtilityData(theEnv)->ListOfCleanupFunctions,&found);
405 /**********************************************************/
406 /* EnvRemovePeriodicFunction: Removes a function from the */
407 /* list of functions called to handle periodic tasks. */
408 /**********************************************************/
409 globle intBool EnvRemovePeriodicFunction(
415 UtilityData(theEnv)->ListOfPeriodicFunctions =
416 RemoveFunctionFromCallList(theEnv,name,UtilityData(theEnv)->ListOfPeriodicFunctions,&found);
421 /*****************************************************/
422 /* StringPrintForm: Generates printed representation */
423 /* of a string. Replaces / with // and " with /". */
424 /*****************************************************/
425 globle const char *StringPrintForm(
432 char *theString = NULL;
435 theString = ExpandStringWithChar(theEnv,'"',theString,&pos,&max,max+80);
436 while (str[i] != EOS)
438 if ((str[i] == '"') || (str[i] == '\\'))
440 theString = ExpandStringWithChar(theEnv,'\\',theString,&pos,&max,max+80);
441 theString = ExpandStringWithChar(theEnv,str[i],theString,&pos,&max,max+80);
444 { theString = ExpandStringWithChar(theEnv,str[i],theString,&pos,&max,max+80); }
448 theString = ExpandStringWithChar(theEnv,'"',theString,&pos,&max,max+80);
450 thePtr = EnvAddSymbol(theEnv,theString);
451 rm(theEnv,theString,max);
452 return(ValueToString(thePtr));
455 /**************************************************************/
456 /* CopyString: Copies a string using CLIPS memory management. */
457 /**************************************************************/
458 globle char *CopyString(
460 const char *theString)
462 char *stringCopy = NULL;
464 if (theString != NULL)
466 stringCopy = (char *) genalloc(theEnv,strlen(theString) + 1);
467 genstrcpy(stringCopy,theString);
473 /*****************************************************************/
474 /* DeleteString: Deletes a string using CLIPS memory management. */
475 /*****************************************************************/
476 globle void DeleteString(
480 if (theString != NULL)
481 { genfree(theEnv,theString,strlen(theString) + 1); }
484 /***********************************************************/
485 /* AppendStrings: Appends two strings together. The string */
486 /* created is added to the SymbolTable, so it is not */
487 /* necessary to deallocate the string returned. */
488 /***********************************************************/
489 globle const char *AppendStrings(
496 char *theString = NULL;
499 theString = AppendToString(theEnv,str1,theString,&pos,&max);
500 theString = AppendToString(theEnv,str2,theString,&pos,&max);
502 thePtr = EnvAddSymbol(theEnv,theString);
503 rm(theEnv,theString,max);
504 return(ValueToString(thePtr));
507 /******************************************************/
508 /* AppendToString: Appends a string to another string */
509 /* (expanding the other string if necessary). */
510 /******************************************************/
511 globle char *AppendToString(
513 const char *appendStr,
520 /*=========================================*/
521 /* Expand the old string so it can contain */
522 /* the new string (if necessary). */
523 /*=========================================*/
525 length = strlen(appendStr);
527 /*==============================================================*/
528 /* Return NULL if the old string was not successfully expanded. */
529 /*==============================================================*/
531 if ((oldStr = EnlargeString(theEnv,length,oldStr,oldPos,oldMax)) == NULL) { return(NULL); }
533 /*===============================================*/
534 /* Append the new string to the expanded string. */
535 /*===============================================*/
537 genstrcpy(&oldStr[*oldPos],appendStr);
538 *oldPos += (int) length;
540 /*============================================================*/
541 /* Return the expanded string containing the appended string. */
542 /*============================================================*/
547 /**********************************************************/
548 /* InsertInString: Inserts a string within another string */
549 /* (expanding the other string if necessary). */
550 /**********************************************************/
551 globle char *InsertInString(
553 const char *insertStr,
561 /*=========================================*/
562 /* Expand the old string so it can contain */
563 /* the new string (if necessary). */
564 /*=========================================*/
566 length = strlen(insertStr);
568 /*==============================================================*/
569 /* Return NULL if the old string was not successfully expanded. */
570 /*==============================================================*/
572 if ((oldStr = EnlargeString(theEnv,length,oldStr,oldPos,oldMax)) == NULL) { return(NULL); }
574 /*================================================================*/
575 /* Shift the contents to the right of insertion point so that the */
576 /* new text does not overwrite what is currently in the string. */
577 /*================================================================*/
579 memmove(&oldStr[position],&oldStr[position+length],*oldPos - position);
581 /*===============================================*/
582 /* Insert the new string in the expanded string. */
583 /*===============================================*/
585 genstrncpy(&oldStr[*oldPos],insertStr,length);
586 *oldPos += (int) length;
588 /*============================================================*/
589 /* Return the expanded string containing the appended string. */
590 /*============================================================*/
595 /*******************************************************************/
596 /* EnlargeString: Enlarges a string by the specified amount. */
597 /*******************************************************************/
598 globle char *EnlargeString(
605 /*=========================================*/
606 /* Expand the old string so it can contain */
607 /* the new string (if necessary). */
608 /*=========================================*/
610 if (length + *oldPos + 1 > *oldMax)
612 oldStr = (char *) genrealloc(theEnv,oldStr,*oldMax,length + *oldPos + 1);
613 *oldMax = length + *oldPos + 1;
616 /*==============================================================*/
617 /* Return NULL if the old string was not successfully expanded. */
618 /*==============================================================*/
620 if (oldStr == NULL) { return(NULL); }
625 /*******************************************************/
626 /* AppendNToString: Appends a string to another string */
627 /* (expanding the other string if necessary). Only a */
628 /* specified number of characters are appended from */
630 /*******************************************************/
631 globle char *AppendNToString(
633 const char *appendStr,
639 size_t lengthWithEOS;
641 /*====================================*/
642 /* Determine the number of characters */
643 /* to be appended from the string. */
644 /*====================================*/
646 if (appendStr[length-1] != '\0') lengthWithEOS = length + 1;
647 else lengthWithEOS = length;
649 /*=========================================*/
650 /* Expand the old string so it can contain */
651 /* the new string (if necessary). */
652 /*=========================================*/
654 if (lengthWithEOS + *oldPos > *oldMax)
656 oldStr = (char *) genrealloc(theEnv,oldStr,*oldMax,*oldPos + lengthWithEOS);
657 *oldMax = *oldPos + lengthWithEOS;
660 /*==============================================================*/
661 /* Return NULL if the old string was not successfully expanded. */
662 /*==============================================================*/
664 if (oldStr == NULL) { return(NULL); }
666 /*==================================*/
667 /* Append N characters from the new */
668 /* string to the expanded string. */
669 /*==================================*/
671 genstrncpy(&oldStr[*oldPos],appendStr,length);
672 *oldPos += (lengthWithEOS - 1);
673 oldStr[*oldPos] = '\0';
675 /*============================================================*/
676 /* Return the expanded string containing the appended string. */
677 /*============================================================*/
682 /*******************************************************/
683 /* ExpandStringWithChar: Adds a character to a string, */
684 /* reallocating space for the string if it needs to */
685 /* be enlarged. The backspace character causes the */
686 /* size of the string to reduced if it is "added" to */
688 /*******************************************************/
689 globle char *ExpandStringWithChar(
697 if ((*pos + 1) >= *max)
699 str = (char *) genrealloc(theEnv,str,*max,newSize);
705 str[*pos] = (char) inchar;
711 /*===========================================================*/
712 /* First delete any UTF-8 multibyte continuation characters. */
713 /*===========================================================*/
715 while ((*pos > 1) && IsUTF8MultiByteContinuation(str[*pos - 1]))
718 /*===================================================*/
719 /* Now delete the first byte of the UTF-8 character. */
720 /*===================================================*/
722 if (*pos > 0) (*pos)--;
729 /*****************************************************************/
730 /* AddFunctionToCallList: Adds a function to a list of functions */
731 /* which are called to perform certain operations (e.g. clear, */
732 /* reset, and bload functions). */
733 /*****************************************************************/
734 globle struct callFunctionItem *AddFunctionToCallList(
738 void (*func)(void *),
739 struct callFunctionItem *head,
740 intBool environmentAware)
742 return AddFunctionToCallListWithContext(theEnv,name,priority,func,head,environmentAware,NULL);
745 /***********************************************************/
746 /* AddFunctionToCallListWithContext: Adds a function to a */
747 /* list of functions which are called to perform certain */
748 /* operations (e.g. clear, reset, and bload functions). */
749 /***********************************************************/
750 globle struct callFunctionItem *AddFunctionToCallListWithContext(
754 void (*func)(void *),
755 struct callFunctionItem *head,
756 intBool environmentAware,
759 struct callFunctionItem *newPtr, *currentPtr, *lastPtr = NULL;
761 newPtr = get_struct(theEnv,callFunctionItem);
765 newPtr->priority = priority;
766 newPtr->environmentAware = (short) environmentAware;
767 newPtr->context = context;
776 while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE)
778 lastPtr = currentPtr;
779 currentPtr = currentPtr->next;
789 newPtr->next = currentPtr;
790 lastPtr->next = newPtr;
796 /*****************************************************************/
797 /* RemoveFunctionFromCallList: Removes a function from a list of */
798 /* functions which are called to perform certain operations */
799 /* (e.g. clear, reset, and bload functions). */
800 /*****************************************************************/
801 globle struct callFunctionItem *RemoveFunctionFromCallList(
804 struct callFunctionItem *head,
807 struct callFunctionItem *currentPtr, *lastPtr;
813 while (currentPtr != NULL)
815 if (strcmp(name,currentPtr->name) == 0)
819 { head = currentPtr->next; }
821 { lastPtr->next = currentPtr->next; }
823 rtn_struct(theEnv,callFunctionItem,currentPtr);
827 lastPtr = currentPtr;
828 currentPtr = currentPtr->next;
834 /**************************************************************/
835 /* DeallocateCallList: Removes all functions from a list of */
836 /* functions which are called to perform certain operations */
837 /* (e.g. clear, reset, and bload functions). */
838 /**************************************************************/
839 globle void DeallocateCallList(
841 struct callFunctionItem *theList)
843 struct callFunctionItem *tmpPtr, *nextPtr;
846 while (tmpPtr != NULL)
848 nextPtr = tmpPtr->next;
849 rtn_struct(theEnv,callFunctionItem,tmpPtr);
854 /***************************************************************/
855 /* AddFunctionToCallListWithArg: Adds a function to a list of */
856 /* functions which are called to perform certain operations */
857 /* (e.g. clear,reset, and bload functions). */
858 /***************************************************************/
859 globle struct callFunctionItemWithArg *AddFunctionToCallListWithArg(
863 void (*func)(void *, void *),
864 struct callFunctionItemWithArg *head,
865 intBool environmentAware)
867 return AddFunctionToCallListWithArgWithContext(theEnv,name,priority,func,head,environmentAware,NULL);
870 /***************************************************************/
871 /* AddFunctionToCallListWithArgWithContext: Adds a function to */
872 /* a list of functions which are called to perform certain */
873 /* operations (e.g. clear, reset, and bload functions). */
874 /***************************************************************/
875 globle struct callFunctionItemWithArg *AddFunctionToCallListWithArgWithContext(
879 void (*func)(void *, void *),
880 struct callFunctionItemWithArg *head,
881 intBool environmentAware,
884 struct callFunctionItemWithArg *newPtr, *currentPtr, *lastPtr = NULL;
886 newPtr = get_struct(theEnv,callFunctionItemWithArg);
890 newPtr->priority = priority;
891 newPtr->environmentAware = (short) environmentAware;
892 newPtr->context = context;
901 while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE)
903 lastPtr = currentPtr;
904 currentPtr = currentPtr->next;
914 newPtr->next = currentPtr;
915 lastPtr->next = newPtr;
921 /**************************************************************/
922 /* RemoveFunctionFromCallListWithArg: Removes a function from */
923 /* a list of functions which are called to perform certain */
924 /* operations (e.g. clear, reset, and bload functions). */
925 /**************************************************************/
926 globle struct callFunctionItemWithArg *RemoveFunctionFromCallListWithArg(
929 struct callFunctionItemWithArg *head,
932 struct callFunctionItemWithArg *currentPtr, *lastPtr;
938 while (currentPtr != NULL)
940 if (strcmp(name,currentPtr->name) == 0)
944 { head = currentPtr->next; }
946 { lastPtr->next = currentPtr->next; }
948 rtn_struct(theEnv,callFunctionItemWithArg,currentPtr);
952 lastPtr = currentPtr;
953 currentPtr = currentPtr->next;
959 /**************************************************************/
960 /* DeallocateCallListWithArg: Removes all functions from a list of */
961 /* functions which are called to perform certain operations */
962 /* (e.g. clear, reset, and bload functions). */
963 /**************************************************************/
964 globle void DeallocateCallListWithArg(
966 struct callFunctionItemWithArg *theList)
968 struct callFunctionItemWithArg *tmpPtr, *nextPtr;
971 while (tmpPtr != NULL)
973 nextPtr = tmpPtr->next;
974 rtn_struct(theEnv,callFunctionItemWithArg,tmpPtr);
979 /*****************************************/
980 /* ItemHashValue: Returns the hash value */
981 /* for the specified value. */
982 /*****************************************/
983 globle unsigned long ItemHashValue(
985 unsigned short theType,
987 unsigned long theRange)
998 return(HashFloat(ValueToDouble(theValue),theRange));
1001 return(HashInteger(ValueToLong(theValue),theRange));
1008 return(HashSymbol(ValueToString(theValue),theRange));
1011 return(HashMultifield((struct multifield *) theValue,theRange));
1013 #if DEFTEMPLATE_CONSTRUCT
1015 return(((struct fact *) theValue)->hashValue % theRange);
1018 case EXTERNAL_ADDRESS:
1019 return(HashExternalAddress(ValueToExternalAddress(theValue),theRange));
1022 case INSTANCE_ADDRESS:
1026 return(fis.uv % theRange);
1029 SystemError(theEnv,"UTILITY",1);
1033 /********************************************/
1034 /* YieldTime: Yields time to a user-defined */
1035 /* function. Intended to allow foreground */
1036 /* application responsiveness when CLIPS */
1037 /* is running in the background. */
1038 /********************************************/
1039 globle void YieldTime(
1042 if ((UtilityData(theEnv)->YieldTimeFunction != NULL) && UtilityData(theEnv)->YieldFunctionEnabled)
1043 { (*UtilityData(theEnv)->YieldTimeFunction)(); }
1046 /**********************************************/
1047 /* EnvIncrementGCLocks: Increments the number */
1048 /* of garbage collection locks. */
1049 /**********************************************/
1050 globle void EnvIncrementGCLocks(
1053 UtilityData(theEnv)->GarbageCollectionLocks++;
1056 /**********************************************/
1057 /* EnvDecrementGCLocks: Decrements the number */
1058 /* of garbage collection locks. */
1059 /**********************************************/
1060 globle void EnvDecrementGCLocks(
1063 if (UtilityData(theEnv)->GarbageCollectionLocks > 0)
1064 { UtilityData(theEnv)->GarbageCollectionLocks--; }
1066 if ((UtilityData(theEnv)->CurrentGarbageFrame->topLevel) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
1067 (EvaluationData(theEnv)->CurrentExpression == NULL) && (UtilityData(theEnv)->GarbageCollectionLocks == 0))
1069 CleanCurrentGarbageFrame(theEnv,NULL);
1070 CallPeriodicTasks(theEnv);
1074 /********************************************/
1075 /* EnablePeriodicFunctions: */
1076 /********************************************/
1077 globle short EnablePeriodicFunctions(
1083 oldValue = UtilityData(theEnv)->PeriodicFunctionsEnabled;
1085 UtilityData(theEnv)->PeriodicFunctionsEnabled = value;
1090 /************************/
1091 /* EnableYieldFunction: */
1092 /************************/
1093 globle short EnableYieldFunction(
1099 oldValue = UtilityData(theEnv)->YieldFunctionEnabled;
1101 UtilityData(theEnv)->YieldFunctionEnabled = value;
1106 /*************************************************************************/
1107 /* AddTrackedMemory: Tracked memory is memory allocated by CLIPS that's */
1108 /* referenced by a variable on the stack, but not by any environment */
1109 /* data structure. An example would be the storage for local variables */
1110 /* allocated when a deffunction is executed. Tracking this memory */
1111 /* allows it to be removed later when using longjmp as the code that */
1112 /* would normally deallocate the memory would be bypassed. */
1113 /*************************************************************************/
1114 globle struct trackedMemory *AddTrackedMemory(
1119 struct trackedMemory *newPtr;
1121 newPtr = get_struct(theEnv,trackedMemory);
1123 newPtr->prev = NULL;
1124 newPtr->theMemory = theMemory;
1125 newPtr->memSize = theSize;
1126 newPtr->next = UtilityData(theEnv)->trackList;
1127 UtilityData(theEnv)->trackList = newPtr;
1132 /************************/
1133 /* RemoveTrackedMemory: */
1134 /************************/
1135 globle void RemoveTrackedMemory(
1137 struct trackedMemory *theTracker)
1139 if (theTracker->prev == NULL)
1140 { UtilityData(theEnv)->trackList = theTracker->next; }
1142 { theTracker->prev->next = theTracker->next; }
1144 if (theTracker->next != NULL)
1145 { theTracker->next->prev = theTracker->prev; }
1147 rtn_struct(theEnv,trackedMemory,theTracker);
1150 /******************************************/
1151 /* UTF8Length: Returns the logical number */
1152 /* of characters in a UTF8 string. */
1153 /******************************************/
1154 globle size_t UTF8Length(
1157 size_t i = 0, length = 0;
1159 while (s[i] != '\0')
1161 UTF8Increment(s,&i);
1168 /*********************************************/
1169 /* UTF8Increment: Finds the beginning of the */
1170 /* next character in a UTF8 string. */
1171 /*********************************************/
1172 globle void UTF8Increment(
1176 (void) (IsUTF8Start(s[++(*i)]) ||
1177 IsUTF8Start(s[++(*i)]) ||
1178 IsUTF8Start(s[++(*i)]) ||
1182 /****************************************************/
1183 /* UTF8Offset: Converts the logical character index */
1184 /* in a UTF8 string to the actual byte offset. */
1185 /****************************************************/
1186 globle size_t UTF8Offset(
1192 while ((charnum > 0) && (str[offs]))
1194 (void) (IsUTF8Start(str[++offs]) ||
1195 IsUTF8Start(str[++offs]) ||
1196 IsUTF8Start(str[++offs]) ||
1205 /*************************************************/
1206 /* UTF8CharNum: Converts the UTF8 character byte */
1207 /* offset to the logical character index. */
1208 /*************************************************/
1209 globle size_t UTF8CharNum(
1213 size_t charnum = 0, offs=0;
1215 while ((offs < offset) && (s[offs]))
1217 (void) (IsUTF8Start(s[++offs]) ||
1218 IsUTF8Start(s[++offs]) ||
1219 IsUTF8Start(s[++offs]) ||
1228 /*#####################################*/
1229 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
1230 /*#####################################*/
1232 #if ALLOW_ENVIRONMENT_GLOBALS
1234 globle void IncrementGCLocks()
1236 EnvIncrementGCLocks(GetCurrentEnvironment());
1239 globle void DecrementGCLocks()
1241 EnvDecrementGCLocks(GetCurrentEnvironment());
1244 globle intBool RemovePeriodicFunction(
1247 return EnvRemovePeriodicFunction(GetCurrentEnvironment(),name);
1250 #endif /* ALLOW_ENVIRONMENT_GLOBALS */