1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  02/04/15            */
5    /*                                                     */
6    /*                 FACT MANAGER MODULE                 */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Provides core routines for maintaining the fact  */
11 /*   list including assert/retract operations, data          */
12 /*   structure creation/deletion, printing, slot access,     */
13 /*   and other utility functions.                            */
14 /*                                                           */
15 /* Principal Programmer(s):                                  */
16 /*      Gary D. Riley                                        */
17 /*                                                           */
18 /* Contributing Programmer(s):                               */
19 /*      Brian L. Dantes                                      */
20 /*                                                           */
21 /* Revision History:                                         */
22 /*                                                           */
23 /*      6.23: Added support for templates maintaining their  */
24 /*            own list of facts.                             */
25 /*                                                           */
26 /*      6.24: Removed LOGICAL_DEPENDENCIES compilation flag. */
27 /*                                                           */
28 /*            Renamed BOOLEAN macro type to intBool.         */
29 /*                                                           */
30 /*            AssignFactSlotDefaults function does not       */
31 /*            properly handle defaults for multifield slots. */
32 /*            DR0869                                         */
33 /*                                                           */
34 /*            Support for ppfact command.                    */
35 /*                                                           */
36 /*      6.30: Callback function support for assertion,       */
37 /*            retraction, and modification of facts.         */
38 /*                                                           */
39 /*            Updates to fact pattern entity record.         */
40 /*                                                           */
41 /*            Changed integer type/precision.                */
42 /*                                                           */
43 /*            Changed garbage collection algorithm.          */
44 /*                                                           */
45 /*            Removed conditional code for unsupported       */
46 /*            compilers/operating systems (IBM_MCW,          */
47 /*            MAC_MCW, and IBM_TBC).                         */
48 /*                                                           */
49 /*            Added const qualifiers to remove C++           */
50 /*            deprecation warnings.                          */
51 /*                                                           */
52 /*            Converted API macros to function calls.        */
53 /*                                                           */
54 /*            Removed unused global variables.               */
55 /*                                                           */
56 /*            Added code to prevent a clear command from     */
57 /*            being executed during fact assertions via      */
58 /*            JoinOperationInProgress mechanism.             */
59 /*                                                           */
60 /*            Added code to keep track of pointers to        */
61 /*            constructs that are contained externally to    */
62 /*            to constructs, DanglingConstructs.             */
63 /*                                                           */
64 /*************************************************************/
65 
66 
67 #define _FACTMNGR_SOURCE_
68 
69 #include <stdio.h>
70 #define _STDIO_INCLUDED_
71 
72 #include "setup.h"
73 
74 #if DEFTEMPLATE_CONSTRUCT && DEFRULE_CONSTRUCT
75 
76 #include "constant.h"
77 #include "symbol.h"
78 #include "memalloc.h"
79 #include "exprnpsr.h"
80 #include "argacces.h"
81 #include "scanner.h"
82 #include "router.h"
83 #include "strngrtr.h"
84 #include "match.h"
85 #include "factbld.h"
86 #include "factqury.h"
87 #include "reteutil.h"
88 #include "retract.h"
89 #include "factcmp.h"
90 #include "filecom.h"
91 #include "factfun.h"
92 #include "factcom.h"
93 #include "constrct.h"
94 #include "factrhs.h"
95 #include "factmch.h"
96 #include "watch.h"
97 #include "utility.h"
98 #include "factbin.h"
99 #include "factmngr.h"
100 #include "facthsh.h"
101 #include "default.h"
102 #include "commline.h"
103 #include "envrnmnt.h"
104 #include "sysdep.h"
105 
106 #include "engine.h"
107 #include "lgcldpnd.h"
108 #include "drive.h"
109 #include "ruledlt.h"
110 
111 #include "tmpltbsc.h"
112 #include "tmpltdef.h"
113 #include "tmpltutl.h"
114 #include "tmpltfun.h"
115 
116 /***************************************/
117 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
118 /***************************************/
119 
120    static void                    ResetFacts(void *);
121    static int                     ClearFactsReady(void *);
122    static void                    RemoveGarbageFacts(void *);
123    static void                    DeallocateFactData(void *);
124 
125 /**************************************************************/
126 /* InitializeFacts: Initializes the fact data representation. */
127 /*   Facts are only available when both the defrule and       */
128 /*   deftemplate constructs are available.                    */
129 /**************************************************************/
InitializeFacts(void * theEnv)130 globle void InitializeFacts(
131   void *theEnv)
132   {
133    struct patternEntityRecord factInfo = { { "FACT_ADDRESS", FACT_ADDRESS,1,0,0,
134                                                      PrintFactIdentifier,
135                                                      PrintFactIdentifierInLongForm,
136                                                      EnvRetract,
137                                                      NULL,
138                                                      EnvGetNextFact,
139                                                      EnvDecrementFactCount,
140                                                      EnvIncrementFactCount,NULL,NULL,NULL,NULL,NULL
141                                                    },
142                                                    DecrementFactBasisCount,
143                                                    IncrementFactBasisCount,
144                                                    MatchFactFunction,
145                                                    NULL,
146                                                    FactIsDeleted
147                                                  };
148 
149    struct fact dummyFact = { { NULL, NULL, 0, 0L }, NULL, NULL, -1L, 0, 1,
150                                   NULL, NULL, NULL, NULL, { 1, 0UL, NULL, { { 0, NULL } } } };
151 
152    AllocateEnvironmentData(theEnv,FACTS_DATA,sizeof(struct factsData),DeallocateFactData);
153 
154    memcpy(&FactData(theEnv)->FactInfo,&factInfo,sizeof(struct patternEntityRecord));
155    dummyFact.factHeader.theInfo = &FactData(theEnv)->FactInfo;
156    memcpy(&FactData(theEnv)->DummyFact,&dummyFact,sizeof(struct fact));
157    FactData(theEnv)->LastModuleIndex = -1;
158 
159    /*=========================================*/
160    /* Initialize the fact hash table (used to */
161    /* quickly determine if a fact exists).    */
162    /*=========================================*/
163 
164    InitializeFactHashTable(theEnv);
165 
166    /*============================================*/
167    /* Initialize the fact callback functions for */
168    /* use with the reset and clear commands.     */
169    /*============================================*/
170 
171    EnvAddResetFunction(theEnv,"facts",ResetFacts,60);
172    AddClearReadyFunction(theEnv,"facts",ClearFactsReady,0);
173 
174    /*=============================*/
175    /* Initialize periodic garbage */
176    /* collection for facts.       */
177    /*=============================*/
178 
179    AddCleanupFunction(theEnv,"facts",RemoveGarbageFacts,0);
180 
181    /*===================================*/
182    /* Initialize fact pattern matching. */
183    /*===================================*/
184 
185    InitializeFactPatterns(theEnv);
186 
187    /*==================================*/
188    /* Initialize the facts keyword for */
189    /* use with the watch command.      */
190    /*==================================*/
191 
192 #if DEBUGGING_FUNCTIONS
193    AddWatchItem(theEnv,"facts",0,&FactData(theEnv)->WatchFacts,80,DeftemplateWatchAccess,DeftemplateWatchPrint);
194 #endif
195 
196    /*=========================================*/
197    /* Initialize fact commands and functions. */
198    /*=========================================*/
199 
200    FactCommandDefinitions(theEnv);
201    FactFunctionDefinitions(theEnv);
202 
203    /*==============================*/
204    /* Initialize fact set queries. */
205    /*==============================*/
206 
207 #if FACT_SET_QUERIES
208    SetupFactQuery(theEnv);
209 #endif
210 
211    /*==================================*/
212    /* Initialize fact patterns for use */
213    /* with the bload/bsave commands.   */
214    /*==================================*/
215 
216 #if (BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE) && (! RUN_TIME)
217    FactBinarySetup(theEnv);
218 #endif
219 
220    /*===================================*/
221    /* Initialize fact patterns for use  */
222    /* with the constructs-to-c command. */
223    /*===================================*/
224 
225 #if CONSTRUCT_COMPILER && (! RUN_TIME)
226    FactPatternsCompilerSetup(theEnv);
227 #endif
228   }
229 
230 /***********************************/
231 /* DeallocateFactData: Deallocates */
232 /*   environment data for facts.   */
233 /***********************************/
DeallocateFactData(void * theEnv)234 static void DeallocateFactData(
235   void *theEnv)
236   {
237    struct factHashEntry *tmpFHEPtr, *nextFHEPtr;
238    struct fact *tmpFactPtr, *nextFactPtr;
239    unsigned long i;
240    struct patternMatch *theMatch, *tmpMatch;
241 
242    for (i = 0; i < FactData(theEnv)->FactHashTableSize; i++)
243      {
244       tmpFHEPtr = FactData(theEnv)->FactHashTable[i];
245 
246       while (tmpFHEPtr != NULL)
247         {
248          nextFHEPtr = tmpFHEPtr->next;
249          rtn_struct(theEnv,factHashEntry,tmpFHEPtr);
250          tmpFHEPtr = nextFHEPtr;
251         }
252      }
253 
254    rm3(theEnv,FactData(theEnv)->FactHashTable,
255        sizeof(struct factHashEntry *) * FactData(theEnv)->FactHashTableSize);
256 
257    tmpFactPtr = FactData(theEnv)->FactList;
258    while (tmpFactPtr != NULL)
259      {
260       nextFactPtr = tmpFactPtr->nextFact;
261 
262       theMatch = (struct patternMatch *) tmpFactPtr->list;
263       while (theMatch != NULL)
264         {
265          tmpMatch = theMatch->next;
266          rtn_struct(theEnv,patternMatch,theMatch);
267          theMatch = tmpMatch;
268         }
269 
270       ReturnEntityDependencies(theEnv,(struct patternEntity *) tmpFactPtr);
271 
272       ReturnFact(theEnv,tmpFactPtr);
273       tmpFactPtr = nextFactPtr;
274      }
275 
276    tmpFactPtr = FactData(theEnv)->GarbageFacts;
277    while (tmpFactPtr != NULL)
278      {
279       nextFactPtr = tmpFactPtr->nextFact;
280 
281       ReturnFact(theEnv,tmpFactPtr);
282       tmpFactPtr = nextFactPtr;
283      }
284 
285    DeallocateCallListWithArg(theEnv,FactData(theEnv)->ListOfAssertFunctions);
286    DeallocateCallListWithArg(theEnv,FactData(theEnv)->ListOfRetractFunctions);
287    DeallocateCallListWithArg(theEnv,FactData(theEnv)->ListOfModifyFunctions);
288   }
289 
290 /**********************************************/
291 /* PrintFactWithIdentifier: Displays a single */
292 /*   fact preceded by its fact identifier.    */
293 /**********************************************/
PrintFactWithIdentifier(void * theEnv,const char * logicalName,struct fact * factPtr)294 globle void PrintFactWithIdentifier(
295   void *theEnv,
296   const char *logicalName,
297   struct fact *factPtr)
298   {
299    char printSpace[20];
300 
301    gensprintf(printSpace,"f-%-5lld ",factPtr->factIndex);
302    EnvPrintRouter(theEnv,logicalName,printSpace);
303    PrintFact(theEnv,logicalName,factPtr,FALSE,FALSE);
304   }
305 
306 /****************************************************/
307 /* PrintFactIdentifier: Displays a fact identifier. */
308 /****************************************************/
PrintFactIdentifier(void * theEnv,const char * logicalName,void * factPtr)309 globle void PrintFactIdentifier(
310   void *theEnv,
311   const char *logicalName,
312   void *factPtr)
313   {
314    char printSpace[20];
315 
316    gensprintf(printSpace,"f-%lld",((struct fact *) factPtr)->factIndex);
317    EnvPrintRouter(theEnv,logicalName,printSpace);
318   }
319 
320 /********************************************/
321 /* PrintFactIdentifierInLongForm: Display a */
322 /*   fact identifier in a longer format.    */
323 /********************************************/
PrintFactIdentifierInLongForm(void * theEnv,const char * logicalName,void * factPtr)324 globle void PrintFactIdentifierInLongForm(
325   void *theEnv,
326   const char *logicalName,
327   void *factPtr)
328   {
329    if (PrintUtilityData(theEnv)->AddressesToStrings) EnvPrintRouter(theEnv,logicalName,"\"");
330    if (factPtr != (void *) &FactData(theEnv)->DummyFact)
331      {
332       EnvPrintRouter(theEnv,logicalName,"<Fact-");
333       PrintLongInteger(theEnv,logicalName,((struct fact *) factPtr)->factIndex);
334       EnvPrintRouter(theEnv,logicalName,">");
335      }
336    else
337      { EnvPrintRouter(theEnv,logicalName,"<Dummy Fact>"); }
338 
339    if (PrintUtilityData(theEnv)->AddressesToStrings) EnvPrintRouter(theEnv,logicalName,"\"");
340   }
341 
342 /*******************************************/
343 /* DecrementFactBasisCount: Decrements the */
344 /*   partial match busy count of a fact    */
345 /*******************************************/
DecrementFactBasisCount(void * theEnv,void * vFactPtr)346 globle void DecrementFactBasisCount(
347   void *theEnv,
348   void *vFactPtr)
349   {
350    struct fact *factPtr = (struct fact *) vFactPtr;
351    struct multifield *theSegment;
352    int i;
353 
354    EnvDecrementFactCount(theEnv,factPtr);
355 
356    theSegment = &factPtr->theProposition;
357 
358    for (i = 0 ; i < (int) theSegment->multifieldLength ; i++)
359      {
360       AtomDeinstall(theEnv,theSegment->theFields[i].type,theSegment->theFields[i].value);
361      }
362   }
363 
364 /*******************************************/
365 /* IncrementFactBasisCount: Increments the */
366 /*   partial match busy count of a fact.   */
367 /*******************************************/
IncrementFactBasisCount(void * theEnv,void * vFactPtr)368 globle void IncrementFactBasisCount(
369   void *theEnv,
370   void *vFactPtr)
371   {
372    struct fact *factPtr = (struct fact *) vFactPtr;
373    struct multifield *theSegment;
374    int i;
375 
376    EnvIncrementFactCount(theEnv,factPtr);
377 
378    theSegment = &factPtr->theProposition;
379 
380    for (i = 0 ; i < (int) theSegment->multifieldLength ; i++)
381      {
382       AtomInstall(theEnv,theSegment->theFields[i].type,theSegment->theFields[i].value);
383      }
384   }
385 
386 /******************/
387 /* FactIsDeleted: */
388 /******************/
FactIsDeleted(void * theEnv,void * theFact)389 globle intBool FactIsDeleted(
390   void *theEnv,
391   void *theFact)
392   {
393 #if MAC_XCD
394 #pragma unused(theEnv)
395 #endif
396 
397    return(((struct fact *) theFact)->garbage);
398   }
399 
400 /**************************************************/
401 /* PrintFact: Displays the printed representation */
402 /*   of a fact containing the relation name and   */
403 /*   all of the fact's slots or fields.           */
404 /**************************************************/
PrintFact(void * theEnv,const char * logicalName,struct fact * factPtr,int seperateLines,int ignoreDefaults)405 globle void PrintFact(
406   void *theEnv,
407   const char *logicalName,
408   struct fact *factPtr,
409   int seperateLines,
410   int ignoreDefaults)
411   {
412    struct multifield *theMultifield;
413 
414    /*=========================================*/
415    /* Print a deftemplate (non-ordered) fact. */
416    /*=========================================*/
417 
418    if (factPtr->whichDeftemplate->implied == FALSE)
419      {
420       PrintTemplateFact(theEnv,logicalName,factPtr,seperateLines,ignoreDefaults);
421       return;
422      }
423 
424    /*==============================*/
425    /* Print an ordered fact (which */
426    /* has an implied deftemplate). */
427    /*==============================*/
428 
429    EnvPrintRouter(theEnv,logicalName,"(");
430 
431    EnvPrintRouter(theEnv,logicalName,factPtr->whichDeftemplate->header.name->contents);
432 
433    theMultifield = (struct multifield *) factPtr->theProposition.theFields[0].value;
434    if (theMultifield->multifieldLength != 0)
435      {
436       EnvPrintRouter(theEnv,logicalName," ");
437       PrintMultifield(theEnv,logicalName,theMultifield,0,
438                       (long) (theMultifield->multifieldLength - 1),
439                       FALSE);
440      }
441 
442    EnvPrintRouter(theEnv,logicalName,")");
443   }
444 
445 /*********************************************/
446 /* MatchFactFunction: Filters a fact through */
447 /*   the appropriate fact pattern network.   */
448 /*********************************************/
MatchFactFunction(void * theEnv,void * vTheFact)449 globle void MatchFactFunction(
450   void *theEnv,
451   void *vTheFact)
452   {
453    struct fact *theFact = (struct fact *) vTheFact;
454 
455    FactPatternMatch(theEnv,theFact,theFact->whichDeftemplate->patternNetwork,0,NULL,NULL);
456   }
457 
458 /*********************************************************/
459 /* EnvRetract: C access routine for the retract command. */
460 /*********************************************************/
EnvRetract(void * theEnv,void * vTheFact)461 globle intBool EnvRetract(
462   void *theEnv,
463   void *vTheFact)
464   {
465    struct fact *theFact = (struct fact *) vTheFact;
466    struct deftemplate *theTemplate = theFact->whichDeftemplate;
467    struct callFunctionItemWithArg *theRetractFunction;
468 
469    /*===========================================*/
470    /* A fact can not be retracted while another */
471    /* fact is being asserted or retracted.      */
472    /*===========================================*/
473 
474    if (EngineData(theEnv)->JoinOperationInProgress)
475      {
476       PrintErrorID(theEnv,"FACTMNGR",1,TRUE);
477       EnvPrintRouter(theEnv,WERROR,"Facts may not be retracted during pattern-matching\n");
478       return(FALSE);
479      }
480 
481    /*====================================*/
482    /* A NULL fact pointer indicates that */
483    /* all facts should be retracted.     */
484    /*====================================*/
485 
486    if (theFact == NULL)
487      {
488       RemoveAllFacts(theEnv);
489       return(TRUE);
490      }
491 
492    /*======================================================*/
493    /* Check to see if the fact has already been retracted. */
494    /*======================================================*/
495 
496    if (theFact->garbage) return(FALSE);
497 
498    /*==========================================*/
499    /* Execute the list of functions that are   */
500    /* to be called before each fact assertion. */
501    /*==========================================*/
502 
503    for (theRetractFunction = FactData(theEnv)->ListOfRetractFunctions;
504         theRetractFunction != NULL;
505         theRetractFunction = theRetractFunction->next)
506      {
507       SetEnvironmentCallbackContext(theEnv,theRetractFunction->context);
508       if (theRetractFunction->environmentAware)
509         { (*theRetractFunction->func)(theEnv,theFact); }
510       else
511         { ((void (*)(void *))(*theRetractFunction->func))(theFact); }
512      }
513 
514    /*============================*/
515    /* Print retraction output if */
516    /* facts are being watched.   */
517    /*============================*/
518 
519 #if DEBUGGING_FUNCTIONS
520    if (theFact->whichDeftemplate->watch)
521      {
522       EnvPrintRouter(theEnv,WTRACE,"<== ");
523       PrintFactWithIdentifier(theEnv,WTRACE,theFact);
524       EnvPrintRouter(theEnv,WTRACE,"\n");
525      }
526 #endif
527 
528    /*==================================*/
529    /* Set the change flag to indicate  */
530    /* the fact-list has been modified. */
531    /*==================================*/
532 
533    FactData(theEnv)->ChangeToFactList = TRUE;
534 
535    /*===============================================*/
536    /* Remove any links between the fact and partial */
537    /* matches in the join network. These links are  */
538    /* used to keep track of logical dependencies.   */
539    /*===============================================*/
540 
541    RemoveEntityDependencies(theEnv,(struct patternEntity *) theFact);
542 
543    /*===========================================*/
544    /* Remove the fact from the fact hash table. */
545    /*===========================================*/
546 
547    RemoveHashedFact(theEnv,theFact);
548 
549    /*=========================================*/
550    /* Remove the fact from its template list. */
551    /*=========================================*/
552 
553    if (theFact == theTemplate->lastFact)
554      { theTemplate->lastFact = theFact->previousTemplateFact; }
555 
556    if (theFact->previousTemplateFact == NULL)
557      {
558       theTemplate->factList = theTemplate->factList->nextTemplateFact;
559       if (theTemplate->factList != NULL)
560         { theTemplate->factList->previousTemplateFact = NULL; }
561      }
562    else
563      {
564       theFact->previousTemplateFact->nextTemplateFact = theFact->nextTemplateFact;
565       if (theFact->nextTemplateFact != NULL)
566         { theFact->nextTemplateFact->previousTemplateFact = theFact->previousTemplateFact; }
567      }
568 
569    /*=====================================*/
570    /* Remove the fact from the fact list. */
571    /*=====================================*/
572 
573    if (theFact == FactData(theEnv)->LastFact)
574      { FactData(theEnv)->LastFact = theFact->previousFact; }
575 
576    if (theFact->previousFact == NULL)
577      {
578       FactData(theEnv)->FactList = FactData(theEnv)->FactList->nextFact;
579       if (FactData(theEnv)->FactList != NULL)
580         { FactData(theEnv)->FactList->previousFact = NULL; }
581      }
582    else
583      {
584       theFact->previousFact->nextFact = theFact->nextFact;
585       if (theFact->nextFact != NULL)
586         { theFact->nextFact->previousFact = theFact->previousFact; }
587      }
588 
589    /*========================================*/
590    /* Add the fact to the fact garbage list. */
591    /*========================================*/
592 
593    theFact->nextFact = FactData(theEnv)->GarbageFacts;
594    FactData(theEnv)->GarbageFacts = theFact;
595    theFact->garbage = TRUE;
596    UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
597 
598    /*===================================================*/
599    /* Reset the evaluation error flag since expressions */
600    /* will be evaluated as part of the retract.         */
601    /*===================================================*/
602 
603    SetEvaluationError(theEnv,FALSE);
604 
605    /*===========================================*/
606    /* Loop through the list of all the patterns */
607    /* that matched the fact and process the     */
608    /* retract operation for each one.           */
609    /*===========================================*/
610 
611    EngineData(theEnv)->JoinOperationInProgress = TRUE;
612    NetworkRetract(theEnv,(struct patternMatch *) theFact->list);
613    EngineData(theEnv)->JoinOperationInProgress = FALSE;
614 
615    /*=========================================*/
616    /* Free partial matches that were released */
617    /* by the retraction of the fact.          */
618    /*=========================================*/
619 
620    if (EngineData(theEnv)->ExecutingRule == NULL)
621      { FlushGarbagePartialMatches(theEnv); }
622 
623    /*=========================================*/
624    /* Retract other facts that were logically */
625    /* dependent on the fact just retracted.   */
626    /*=========================================*/
627 
628    ForceLogicalRetractions(theEnv);
629 
630    /*===========================================*/
631    /* Force periodic cleanup if the retract was */
632    /* executed from an embedded application.    */
633    /*===========================================*/
634 
635    if ((UtilityData(theEnv)->CurrentGarbageFrame->topLevel) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
636        (EvaluationData(theEnv)->CurrentExpression == NULL) && (UtilityData(theEnv)->GarbageCollectionLocks == 0))
637      { CleanCurrentGarbageFrame(theEnv,NULL); }
638 
639    /*==================================*/
640    /* Update busy counts and ephemeral */
641    /* garbage information.             */
642    /*==================================*/
643 
644    FactDeinstall(theEnv,theFact);
645 
646    /*==================================*/
647    /* Return TRUE to indicate the fact */
648    /* was successfully retracted.      */
649    /*==================================*/
650 
651    return(TRUE);
652   }
653 
654 /*******************************************************************/
655 /* RemoveGarbageFacts: Returns facts that have been retracted to   */
656 /*   the pool of available memory. It is necessary to postpone     */
657 /*   returning the facts to memory because RHS actions retrieve    */
658 /*   their variable bindings directly from the fact data structure */
659 /*   and the facts may be in use in other data structures.         */
660 /*******************************************************************/
RemoveGarbageFacts(void * theEnv)661 static void RemoveGarbageFacts(
662   void *theEnv)
663   {
664    struct fact *factPtr, *nextPtr, *lastPtr = NULL;
665 
666    factPtr = FactData(theEnv)->GarbageFacts;
667 
668    while (factPtr != NULL)
669      {
670       nextPtr = factPtr->nextFact;
671       if (factPtr->factHeader.busyCount == 0)
672         {
673          ReturnFact(theEnv,factPtr);
674          if (lastPtr == NULL) FactData(theEnv)->GarbageFacts = nextPtr;
675          else lastPtr->nextFact = nextPtr;
676         }
677       else
678         { lastPtr = factPtr; }
679 
680       factPtr = nextPtr;
681      }
682   }
683 
684 /********************************************************/
685 /* EnvAssert: C access routine for the assert function. */
686 /********************************************************/
EnvAssert(void * theEnv,void * vTheFact)687 globle void *EnvAssert(
688   void *theEnv,
689   void *vTheFact)
690   {
691    unsigned long hashValue;
692    unsigned long length, i;
693    struct field *theField;
694    struct fact *theFact = (struct fact *) vTheFact;
695    intBool duplicate;
696    struct callFunctionItemWithArg *theAssertFunction;
697 
698    /*==========================================*/
699    /* A fact can not be asserted while another */
700    /* fact is being asserted or retracted.     */
701    /*==========================================*/
702 
703    if (EngineData(theEnv)->JoinOperationInProgress)
704      {
705       ReturnFact(theEnv,theFact);
706       PrintErrorID(theEnv,"FACTMNGR",2,TRUE);
707       EnvPrintRouter(theEnv,WERROR,"Facts may not be asserted during pattern-matching\n");
708       return(NULL);
709      }
710 
711    /*=============================================================*/
712    /* Replace invalid data types in the fact with the symbol nil. */
713    /*=============================================================*/
714 
715    length = theFact->theProposition.multifieldLength;
716    theField = theFact->theProposition.theFields;
717 
718    for (i = 0; i < length; i++)
719      {
720       if (theField[i].type == RVOID)
721         {
722          theField[i].type = SYMBOL;
723          theField[i].value = (void *) EnvAddSymbol(theEnv,"nil");
724         }
725      }
726 
727    /*========================================================*/
728    /* If fact assertions are being checked for duplications, */
729    /* then search the fact list for a duplicate fact.        */
730    /*========================================================*/
731 
732    hashValue = HandleFactDuplication(theEnv,theFact,&duplicate);
733    if (duplicate) return(NULL);
734 
735    /*==========================================================*/
736    /* If necessary, add logical dependency links between the   */
737    /* fact and the partial match which is its logical support. */
738    /*==========================================================*/
739 
740    if (AddLogicalDependencies(theEnv,(struct patternEntity *) theFact,FALSE) == FALSE)
741      {
742       ReturnFact(theEnv,theFact);
743       return(NULL);
744      }
745 
746    /*======================================*/
747    /* Add the fact to the fact hash table. */
748    /*======================================*/
749 
750    AddHashedFact(theEnv,theFact,hashValue);
751 
752    /*================================*/
753    /* Add the fact to the fact list. */
754    /*================================*/
755 
756    theFact->nextFact = NULL;
757    theFact->list = NULL;
758    theFact->previousFact = FactData(theEnv)->LastFact;
759    if (FactData(theEnv)->LastFact == NULL)
760      { FactData(theEnv)->FactList = theFact; }
761    else
762      { FactData(theEnv)->LastFact->nextFact = theFact; }
763    FactData(theEnv)->LastFact = theFact;
764 
765    /*====================================*/
766    /* Add the fact to its template list. */
767    /*====================================*/
768 
769    theFact->previousTemplateFact = theFact->whichDeftemplate->lastFact;
770    theFact->nextTemplateFact = NULL;
771 
772    if (theFact->whichDeftemplate->lastFact == NULL)
773      { theFact->whichDeftemplate->factList = theFact; }
774    else
775      { theFact->whichDeftemplate->lastFact->nextTemplateFact = theFact; }
776 
777    theFact->whichDeftemplate->lastFact = theFact;
778 
779    /*==================================*/
780    /* Set the fact index and time tag. */
781    /*==================================*/
782 
783    theFact->factIndex = FactData(theEnv)->NextFactIndex++;
784    theFact->factHeader.timeTag = DefruleData(theEnv)->CurrentEntityTimeTag++;
785 
786    /*=====================*/
787    /* Update busy counts. */
788    /*=====================*/
789 
790    FactInstall(theEnv,theFact);
791 
792    /*==========================================*/
793    /* Execute the list of functions that are   */
794    /* to be called before each fact assertion. */
795    /*==========================================*/
796 
797    for (theAssertFunction = FactData(theEnv)->ListOfAssertFunctions;
798         theAssertFunction != NULL;
799         theAssertFunction = theAssertFunction->next)
800      {
801       SetEnvironmentCallbackContext(theEnv,theAssertFunction->context);
802       if (theAssertFunction->environmentAware)
803         { (*theAssertFunction->func)(theEnv,theFact); }
804       else
805         { ((void (*)(void *))(*theAssertFunction->func))(theFact); }
806      }
807 
808    /*==========================*/
809    /* Print assert output if   */
810    /* facts are being watched. */
811    /*==========================*/
812 
813 #if DEBUGGING_FUNCTIONS
814    if (theFact->whichDeftemplate->watch)
815      {
816       EnvPrintRouter(theEnv,WTRACE,"==> ");
817       PrintFactWithIdentifier(theEnv,WTRACE,theFact);
818       EnvPrintRouter(theEnv,WTRACE,"\n");
819      }
820 #endif
821 
822    /*==================================*/
823    /* Set the change flag to indicate  */
824    /* the fact-list has been modified. */
825    /*==================================*/
826 
827    FactData(theEnv)->ChangeToFactList = TRUE;
828 
829    /*==========================================*/
830    /* Check for constraint errors in the fact. */
831    /*==========================================*/
832 
833    CheckTemplateFact(theEnv,theFact);
834 
835    /*===================================================*/
836    /* Reset the evaluation error flag since expressions */
837    /* will be evaluated as part of the assert .         */
838    /*===================================================*/
839 
840    SetEvaluationError(theEnv,FALSE);
841 
842    /*=============================================*/
843    /* Pattern match the fact using the associated */
844    /* deftemplate's pattern network.              */
845    /*=============================================*/
846 
847    EngineData(theEnv)->JoinOperationInProgress = TRUE;
848    FactPatternMatch(theEnv,theFact,theFact->whichDeftemplate->patternNetwork,0,NULL,NULL);
849    EngineData(theEnv)->JoinOperationInProgress = FALSE;
850 
851    /*===================================================*/
852    /* Retract other facts that were logically dependent */
853    /* on the non-existence of the fact just asserted.   */
854    /*===================================================*/
855 
856    ForceLogicalRetractions(theEnv);
857 
858    /*=========================================*/
859    /* Free partial matches that were released */
860    /* by the assertion of the fact.           */
861    /*=========================================*/
862 
863    if (EngineData(theEnv)->ExecutingRule == NULL) FlushGarbagePartialMatches(theEnv);
864 
865    /*==========================================*/
866    /* Force periodic cleanup if the assert was */
867    /* executed from an embedded application.   */
868    /*==========================================*/
869 
870    if ((UtilityData(theEnv)->CurrentGarbageFrame->topLevel) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
871        (EvaluationData(theEnv)->CurrentExpression == NULL) && (UtilityData(theEnv)->GarbageCollectionLocks == 0))
872      {
873       CleanCurrentGarbageFrame(theEnv,NULL);
874       CallPeriodicTasks(theEnv);
875      }
876 
877    /*===============================*/
878    /* Return a pointer to the fact. */
879    /*===============================*/
880 
881    return((void *) theFact);
882   }
883 
884 /**************************************/
885 /* RemoveAllFacts: Loops through the  */
886 /*   fact-list and removes each fact. */
887 /**************************************/
RemoveAllFacts(void * theEnv)888 globle void RemoveAllFacts(
889   void *theEnv)
890   {
891    while (FactData(theEnv)->FactList != NULL)
892      { EnvRetract(theEnv,(void *) FactData(theEnv)->FactList); }
893   }
894 
895 /************************************************/
896 /* EnvCreateFact: Creates a fact data structure */
897 /*   of the specified deftemplate.              */
898 /************************************************/
EnvCreateFact(void * theEnv,void * vTheDeftemplate)899 globle struct fact *EnvCreateFact(
900   void *theEnv,
901   void *vTheDeftemplate)
902   {
903    struct deftemplate *theDeftemplate = (struct deftemplate *) vTheDeftemplate;
904    struct fact *newFact;
905    int i;
906 
907    /*=================================*/
908    /* A deftemplate must be specified */
909    /* in order to create a fact.      */
910    /*=================================*/
911 
912    if (theDeftemplate == NULL) return(NULL);
913 
914    /*============================================*/
915    /* Create a fact for an explicit deftemplate. */
916    /*============================================*/
917 
918    if (theDeftemplate->implied == FALSE)
919      {
920       newFact = CreateFactBySize(theEnv,theDeftemplate->numberOfSlots);
921       for (i = 0;
922            i < (int) theDeftemplate->numberOfSlots;
923            i++)
924         { newFact->theProposition.theFields[i].type = RVOID; }
925      }
926 
927    /*===========================================*/
928    /* Create a fact for an implied deftemplate. */
929    /*===========================================*/
930 
931    else
932      {
933       newFact = CreateFactBySize(theEnv,1);
934       newFact->theProposition.theFields[0].type = MULTIFIELD;
935       newFact->theProposition.theFields[0].value = CreateMultifield2(theEnv,0L);
936      }
937 
938    /*===============================*/
939    /* Return a pointer to the fact. */
940    /*===============================*/
941 
942    newFact->whichDeftemplate = theDeftemplate;
943 
944    return(newFact);
945   }
946 
947 /******************************************/
948 /* EnvGetFactSlot: Returns the slot value */
949 /*   from the specified slot of a fact.   */
950 /******************************************/
EnvGetFactSlot(void * theEnv,void * vTheFact,const char * slotName,DATA_OBJECT * theValue)951 globle intBool EnvGetFactSlot(
952   void *theEnv,
953   void *vTheFact,
954   const char *slotName,
955   DATA_OBJECT *theValue)
956   {
957    struct fact *theFact = (struct fact *) vTheFact;
958    struct deftemplate *theDeftemplate;
959    short whichSlot;
960 
961    /*===============================================*/
962    /* Get the deftemplate associated with the fact. */
963    /*===============================================*/
964 
965    theDeftemplate = theFact->whichDeftemplate;
966 
967    /*==============================================*/
968    /* Handle retrieving the slot value from a fact */
969    /* having an implied deftemplate. An implied    */
970    /* facts has a single multifield slot.          */
971    /*==============================================*/
972 
973    if (theDeftemplate->implied)
974      {
975       if (slotName != NULL) return(FALSE);
976       theValue->type = theFact->theProposition.theFields[0].type;
977       theValue->value = theFact->theProposition.theFields[0].value;
978       SetpDOBegin(theValue,1);
979       SetpDOEnd(theValue,((struct multifield *) theValue->value)->multifieldLength);
980       return(TRUE);
981      }
982 
983    /*===================================*/
984    /* Make sure the slot name requested */
985    /* corresponds to a valid slot name. */
986    /*===================================*/
987 
988    if (FindSlot(theDeftemplate,(SYMBOL_HN *) EnvAddSymbol(theEnv,slotName),&whichSlot) == NULL)
989      { return(FALSE); }
990 
991    /*======================================================*/
992    /* Return the slot value. If the slot value wasn't set, */
993    /* then return FALSE to indicate that an appropriate    */
994    /* slot value wasn't available.                         */
995    /*======================================================*/
996 
997    theValue->type = theFact->theProposition.theFields[whichSlot-1].type;
998    theValue->value = theFact->theProposition.theFields[whichSlot-1].value;
999    if (theValue->type == MULTIFIELD)
1000      {
1001       SetpDOBegin(theValue,1);
1002       SetpDOEnd(theValue,((struct multifield *) theValue->value)->multifieldLength);
1003      }
1004 
1005    if (theValue->type == RVOID) return(FALSE);
1006 
1007    return(TRUE);
1008   }
1009 
1010 /***************************************/
1011 /* EnvPutFactSlot: Sets the slot value */
1012 /*   of the specified slot of a fact.  */
1013 /***************************************/
EnvPutFactSlot(void * theEnv,void * vTheFact,const char * slotName,DATA_OBJECT * theValue)1014 globle intBool EnvPutFactSlot(
1015   void *theEnv,
1016   void *vTheFact,
1017   const char *slotName,
1018   DATA_OBJECT *theValue)
1019   {
1020    struct fact *theFact = (struct fact *) vTheFact;
1021    struct deftemplate *theDeftemplate;
1022    struct templateSlot *theSlot;
1023    short whichSlot;
1024 
1025    /*===============================================*/
1026    /* Get the deftemplate associated with the fact. */
1027    /*===============================================*/
1028 
1029    theDeftemplate = theFact->whichDeftemplate;
1030 
1031    /*============================================*/
1032    /* Handle setting the slot value of a fact    */
1033    /* having an implied deftemplate. An implied  */
1034    /* facts has a single multifield slot.        */
1035    /*============================================*/
1036 
1037    if (theDeftemplate->implied)
1038      {
1039       if ((slotName != NULL) || (theValue->type != MULTIFIELD))
1040         { return(FALSE); }
1041 
1042       if (theFact->theProposition.theFields[0].type == MULTIFIELD)
1043         { ReturnMultifield(theEnv,(struct multifield *) theFact->theProposition.theFields[0].value); }
1044 
1045       theFact->theProposition.theFields[0].type = theValue->type;
1046       theFact->theProposition.theFields[0].value = DOToMultifield(theEnv,theValue);
1047 
1048       return(TRUE);
1049      }
1050 
1051    /*===================================*/
1052    /* Make sure the slot name requested */
1053    /* corresponds to a valid slot name. */
1054    /*===================================*/
1055 
1056    if ((theSlot = FindSlot(theDeftemplate,(SYMBOL_HN *) EnvAddSymbol(theEnv,slotName),&whichSlot)) == NULL)
1057      { return(FALSE); }
1058 
1059    /*=============================================*/
1060    /* Make sure a single field value is not being */
1061    /* stored in a multifield slot or vice versa.  */
1062    /*=============================================*/
1063 
1064    if (((theSlot->multislot == 0) && (theValue->type == MULTIFIELD)) ||
1065        ((theSlot->multislot == 1) && (theValue->type != MULTIFIELD)))
1066      { return(FALSE); }
1067 
1068    /*=====================*/
1069    /* Set the slot value. */
1070    /*=====================*/
1071 
1072    if (theFact->theProposition.theFields[whichSlot-1].type == MULTIFIELD)
1073      { ReturnMultifield(theEnv,(struct multifield *) theFact->theProposition.theFields[whichSlot-1].value); }
1074 
1075    theFact->theProposition.theFields[whichSlot-1].type = theValue->type;
1076 
1077    if (theValue->type == MULTIFIELD)
1078      { theFact->theProposition.theFields[whichSlot-1].value = DOToMultifield(theEnv,theValue); }
1079    else
1080      { theFact->theProposition.theFields[whichSlot-1].value = theValue->value; }
1081 
1082    return(TRUE);
1083   }
1084 
1085 /********************************************************/
1086 /* EnvAssignFactSlotDefaults: Sets a fact's slot values */
1087 /*   to its default value if the value of the slot has  */
1088 /*   not yet been set.                                  */
1089 /********************************************************/
EnvAssignFactSlotDefaults(void * theEnv,void * vTheFact)1090 globle intBool EnvAssignFactSlotDefaults(
1091   void *theEnv,
1092   void *vTheFact)
1093   {
1094    struct fact *theFact = (struct fact *) vTheFact;
1095    struct deftemplate *theDeftemplate;
1096    struct templateSlot *slotPtr;
1097    int i;
1098    DATA_OBJECT theResult;
1099 
1100    /*===============================================*/
1101    /* Get the deftemplate associated with the fact. */
1102    /*===============================================*/
1103 
1104    theDeftemplate = theFact->whichDeftemplate;
1105 
1106    /*================================================*/
1107    /* The value for the implied multifield slot of   */
1108    /* an implied deftemplate is set to a multifield  */
1109    /* of length zero when the fact is created.       */
1110    /*================================================*/
1111 
1112    if (theDeftemplate->implied) return(TRUE);
1113 
1114    /*============================================*/
1115    /* Loop through each slot of the deftemplate. */
1116    /*============================================*/
1117 
1118    for (i = 0, slotPtr = theDeftemplate->slotList;
1119         i < (int) theDeftemplate->numberOfSlots;
1120         i++, slotPtr = slotPtr->next)
1121      {
1122       /*===================================*/
1123       /* If the slot's value has been set, */
1124       /* then move on to the next slot.    */
1125       /*===================================*/
1126 
1127       if (theFact->theProposition.theFields[i].type != RVOID) continue;
1128 
1129       /*======================================================*/
1130       /* Assign the default value for the slot if one exists. */
1131       /*======================================================*/
1132 
1133       if (DeftemplateSlotDefault(theEnv,theDeftemplate,slotPtr,&theResult,FALSE))
1134         {
1135          theFact->theProposition.theFields[i].type = theResult.type;
1136          theFact->theProposition.theFields[i].value = theResult.value;
1137         }
1138      }
1139 
1140    /*==========================================*/
1141    /* Return TRUE to indicate that the default */
1142    /* values have been successfully set.       */
1143    /*==========================================*/
1144 
1145    return(TRUE);
1146   }
1147 
1148 /********************************************************/
1149 /* DeftemplateSlotDefault: Determines the default value */
1150 /*   for the specified slot of a deftemplate.           */
1151 /********************************************************/
DeftemplateSlotDefault(void * theEnv,struct deftemplate * theDeftemplate,struct templateSlot * slotPtr,DATA_OBJECT * theResult,int garbageMultifield)1152 globle intBool DeftemplateSlotDefault(
1153   void *theEnv,
1154   struct deftemplate *theDeftemplate,
1155   struct templateSlot *slotPtr,
1156   DATA_OBJECT *theResult,
1157   int garbageMultifield)
1158   {
1159    /*================================================*/
1160    /* The value for the implied multifield slot of an */
1161    /* implied deftemplate does not have a default.    */
1162    /*=================================================*/
1163 
1164    if (theDeftemplate->implied) return(FALSE);
1165 
1166    /*===============================================*/
1167    /* If the (default ?NONE) attribute was declared */
1168    /* for the slot, then return FALSE to indicate   */
1169    /* the default values for the fact couldn't be   */
1170    /* supplied since this attribute requires that a */
1171    /* default value can't be used for the slot.     */
1172    /*===============================================*/
1173 
1174    if (slotPtr->noDefault) return(FALSE);
1175 
1176    /*==============================================*/
1177    /* Otherwise if a static default was specified, */
1178    /* use this as the default value.               */
1179    /*==============================================*/
1180 
1181    else if (slotPtr->defaultPresent)
1182      {
1183       if (slotPtr->multislot)
1184         {
1185          StoreInMultifield(theEnv,theResult,slotPtr->defaultList,garbageMultifield);
1186         }
1187       else
1188         {
1189          theResult->type = slotPtr->defaultList->type;
1190          theResult->value = slotPtr->defaultList->value;
1191         }
1192      }
1193 
1194    /*================================================*/
1195    /* Otherwise if a dynamic-default was specified,  */
1196    /* evaluate it and use this as the default value. */
1197    /*================================================*/
1198 
1199    else if (slotPtr->defaultDynamic)
1200      {
1201       if (! EvaluateAndStoreInDataObject(theEnv,(int) slotPtr->multislot,
1202                                          (EXPRESSION *) slotPtr->defaultList,
1203                                          theResult,garbageMultifield))
1204         { return(FALSE); }
1205      }
1206 
1207    /*====================================*/
1208    /* Otherwise derive the default value */
1209    /* from the slot's constraints.       */
1210    /*====================================*/
1211 
1212    else
1213      {
1214       DeriveDefaultFromConstraints(theEnv,slotPtr->constraints,theResult,
1215                                   (int) slotPtr->multislot,garbageMultifield);
1216      }
1217 
1218    /*==========================================*/
1219    /* Return TRUE to indicate that the default */
1220    /* values have been successfully set.       */
1221    /*==========================================*/
1222 
1223    return(TRUE);
1224   }
1225 
1226 /***************************************************************/
1227 /* CopyFactSlotValues: Copies the slot values from one fact to */
1228 /*   another. Both facts must have the same relation name.     */
1229 /***************************************************************/
CopyFactSlotValues(void * theEnv,void * vTheDestFact,void * vTheSourceFact)1230 globle intBool CopyFactSlotValues(
1231   void *theEnv,
1232   void *vTheDestFact,
1233   void *vTheSourceFact)
1234   {
1235    struct fact *theDestFact = (struct fact *) vTheDestFact;
1236    struct fact *theSourceFact = (struct fact *) vTheSourceFact;
1237    struct deftemplate *theDeftemplate;
1238    struct templateSlot *slotPtr;
1239    int i;
1240 
1241    /*===================================*/
1242    /* Both facts must be the same type. */
1243    /*===================================*/
1244 
1245    theDeftemplate = theSourceFact->whichDeftemplate;
1246    if (theDestFact->whichDeftemplate != theDeftemplate)
1247      { return(FALSE); }
1248 
1249    /*===================================================*/
1250    /* Loop through each slot of the deftemplate copying */
1251    /* the source fact value to the destination fact.    */
1252    /*===================================================*/
1253 
1254    for (i = 0, slotPtr = theDeftemplate->slotList;
1255         i < (int) theDeftemplate->numberOfSlots;
1256         i++, slotPtr = slotPtr->next)
1257      {
1258       theDestFact->theProposition.theFields[i].type =
1259          theSourceFact->theProposition.theFields[i].type;
1260       if (theSourceFact->theProposition.theFields[i].type != MULTIFIELD)
1261         {
1262          theDestFact->theProposition.theFields[i].value =
1263            theSourceFact->theProposition.theFields[i].value;
1264         }
1265       else
1266         {
1267          theDestFact->theProposition.theFields[i].value =
1268            CopyMultifield(theEnv,(struct multifield *) theSourceFact->theProposition.theFields[i].value);
1269         }
1270      }
1271 
1272    /*========================================*/
1273    /* Return TRUE to indicate that fact slot */
1274    /* values were successfully copied.       */
1275    /*========================================*/
1276 
1277    return(TRUE);
1278   }
1279 
1280 /*********************************************/
1281 /* CreateFactBySize: Allocates a fact data   */
1282 /*   structure based on the number of slots. */
1283 /*********************************************/
CreateFactBySize(void * theEnv,unsigned size)1284 globle struct fact *CreateFactBySize(
1285   void *theEnv,
1286   unsigned size)
1287   {
1288    struct fact *theFact;
1289    unsigned newSize;
1290 
1291    if (size <= 0) newSize = 1;
1292    else newSize = size;
1293 
1294    theFact = get_var_struct(theEnv,fact,sizeof(struct field) * (newSize - 1));
1295 
1296    theFact->garbage = FALSE;
1297    theFact->factIndex = 0LL;
1298    theFact->factHeader.busyCount = 0;
1299    theFact->factHeader.theInfo = &FactData(theEnv)->FactInfo;
1300    theFact->factHeader.dependents = NULL;
1301    theFact->whichDeftemplate = NULL;
1302    theFact->nextFact = NULL;
1303    theFact->previousFact = NULL;
1304    theFact->previousTemplateFact = NULL;
1305    theFact->nextTemplateFact = NULL;
1306    theFact->list = NULL;
1307 
1308    theFact->theProposition.multifieldLength = size;
1309    theFact->theProposition.busyCount = 0;
1310 
1311    return(theFact);
1312   }
1313 
1314 /*********************************************/
1315 /* ReturnFact: Returns a fact data structure */
1316 /*   to the pool of free memory.             */
1317 /*********************************************/
ReturnFact(void * theEnv,struct fact * theFact)1318 globle void ReturnFact(
1319   void *theEnv,
1320   struct fact *theFact)
1321   {
1322    struct multifield *theSegment, *subSegment;
1323    long newSize, i;
1324 
1325    theSegment = &theFact->theProposition;
1326 
1327    for (i = 0; i < theSegment->multifieldLength; i++)
1328      {
1329       if (theSegment->theFields[i].type == MULTIFIELD)
1330         {
1331          subSegment = (struct multifield *) theSegment->theFields[i].value;
1332          if (subSegment->busyCount == 0)
1333            { ReturnMultifield(theEnv,subSegment); }
1334          else
1335            { AddToMultifieldList(theEnv,subSegment); }
1336         }
1337      }
1338 
1339    if (theFact->theProposition.multifieldLength == 0) newSize = 1;
1340    else newSize = theFact->theProposition.multifieldLength;
1341 
1342    rtn_var_struct(theEnv,fact,sizeof(struct field) * (newSize - 1),theFact);
1343   }
1344 
1345 /*************************************************************/
1346 /* FactInstall: Increments the fact, deftemplate, and atomic */
1347 /*   data value busy counts associated with the fact.        */
1348 /*************************************************************/
FactInstall(void * theEnv,struct fact * newFact)1349 globle void FactInstall(
1350   void *theEnv,
1351   struct fact *newFact)
1352   {
1353    struct multifield *theSegment;
1354    int i;
1355 
1356    FactData(theEnv)->NumberOfFacts++;
1357    newFact->whichDeftemplate->busyCount++;
1358    theSegment = &newFact->theProposition;
1359 
1360    for (i = 0 ; i < (int) theSegment->multifieldLength ; i++)
1361      {
1362       AtomInstall(theEnv,theSegment->theFields[i].type,theSegment->theFields[i].value);
1363      }
1364 
1365    newFact->factHeader.busyCount++;
1366   }
1367 
1368 /***************************************************************/
1369 /* FactDeinstall: Decrements the fact, deftemplate, and atomic */
1370 /*   data value busy counts associated with the fact.          */
1371 /***************************************************************/
FactDeinstall(void * theEnv,struct fact * newFact)1372 globle void FactDeinstall(
1373   void *theEnv,
1374   struct fact *newFact)
1375   {
1376    struct multifield *theSegment;
1377    int i;
1378 
1379    FactData(theEnv)->NumberOfFacts--;
1380    theSegment = &newFact->theProposition;
1381    newFact->whichDeftemplate->busyCount--;
1382 
1383    for (i = 0 ; i < (int) theSegment->multifieldLength ; i++)
1384      {
1385       AtomDeinstall(theEnv,theSegment->theFields[i].type,theSegment->theFields[i].value);
1386      }
1387 
1388    newFact->factHeader.busyCount--;
1389   }
1390 
1391 /************************************************/
1392 /* EnvIncrementFactCount: Increments the number */
1393 /*   of references to a specified fact.         */
1394 /************************************************/
EnvIncrementFactCount(void * theEnv,void * factPtr)1395 globle void EnvIncrementFactCount(
1396   void *theEnv,
1397   void *factPtr)
1398   {
1399 #if MAC_XCD
1400 #pragma unused(theEnv)
1401 #endif
1402 
1403    ((struct fact *) factPtr)->factHeader.busyCount++;
1404   }
1405 
1406 /************************************************/
1407 /* EnvDecrementFactCount: Decrements the number */
1408 /*   of references to a specified fact.         */
1409 /************************************************/
EnvDecrementFactCount(void * theEnv,void * factPtr)1410 globle void EnvDecrementFactCount(
1411   void *theEnv,
1412   void *factPtr)
1413   {
1414 #if MAC_XCD
1415 #pragma unused(theEnv)
1416 #endif
1417 
1418    ((struct fact *) factPtr)->factHeader.busyCount--;
1419   }
1420 
1421 /*********************************************************/
1422 /* EnvGetNextFact: If passed a NULL pointer, returns the */
1423 /*   first fact in the fact-list. Otherwise returns the  */
1424 /*   next fact following the fact passed as an argument. */
1425 /*********************************************************/
EnvGetNextFact(void * theEnv,void * factPtr)1426 globle void *EnvGetNextFact(
1427   void *theEnv,
1428   void *factPtr)
1429   {
1430    if (factPtr == NULL)
1431      { return((void *) FactData(theEnv)->FactList); }
1432 
1433    if (((struct fact *) factPtr)->garbage) return(NULL);
1434 
1435    return((void *) ((struct fact *) factPtr)->nextFact);
1436   }
1437 
1438 /**************************************************/
1439 /* GetNextFactInScope: Returns the next fact that */
1440 /*   is in scope of the current module. Works in  */
1441 /*   a similar fashion to GetNextFact, but skips  */
1442 /*   facts that are out of scope.                 */
1443 /**************************************************/
GetNextFactInScope(void * theEnv,void * vTheFact)1444 globle void *GetNextFactInScope(
1445   void *theEnv,
1446   void *vTheFact)
1447   {
1448    struct fact *theFact = (struct fact *) vTheFact;
1449 
1450    /*=======================================================*/
1451    /* If fact passed as an argument is a NULL pointer, then */
1452    /* we're just beginning a traversal of the fact list. If */
1453    /* the module index has changed since that last time the */
1454    /* fact list was traversed by this routine, then         */
1455    /* determine all of the deftemplates that are in scope   */
1456    /* of the current module.                                */
1457    /*=======================================================*/
1458 
1459    if (theFact == NULL)
1460      {
1461       theFact = FactData(theEnv)->FactList;
1462       if (FactData(theEnv)->LastModuleIndex != DefmoduleData(theEnv)->ModuleChangeIndex)
1463         {
1464          UpdateDeftemplateScope(theEnv);
1465          FactData(theEnv)->LastModuleIndex = DefmoduleData(theEnv)->ModuleChangeIndex;
1466         }
1467      }
1468 
1469    /*==================================================*/
1470    /* Otherwise, if the fact passed as an argument has */
1471    /* been retracted, then there's no way to determine */
1472    /* the next fact, so return a NULL pointer.         */
1473    /*==================================================*/
1474 
1475    else if (((struct fact *) theFact)->garbage)
1476      { return(NULL); }
1477 
1478    /*==================================================*/
1479    /* Otherwise, start the search for the next fact in */
1480    /* scope with the fact immediately following the    */
1481    /* fact passed as an argument.                      */
1482    /*==================================================*/
1483 
1484    else
1485      { theFact = theFact->nextFact; }
1486 
1487    /*================================================*/
1488    /* Continue traversing the fact-list until a fact */
1489    /* is found that's associated with a deftemplate  */
1490    /* that's in scope.                               */
1491    /*================================================*/
1492 
1493    while (theFact != NULL)
1494      {
1495       if (theFact->whichDeftemplate->inScope) return((void *) theFact);
1496 
1497       theFact = theFact->nextFact;
1498      }
1499 
1500    return(NULL);
1501   }
1502 
1503 /****************************************/
1504 /* EnvGetFactPPForm: Returns the pretty */
1505 /*   print representation of a fact.    */
1506 /****************************************/
EnvGetFactPPForm(void * theEnv,char * buffer,size_t bufferLength,void * theFact)1507 globle void EnvGetFactPPForm(
1508   void *theEnv,
1509   char *buffer,
1510   size_t bufferLength,
1511   void *theFact)
1512   {
1513    OpenStringDestination(theEnv,"FactPPForm",buffer,bufferLength);
1514    PrintFactWithIdentifier(theEnv,"FactPPForm",(struct fact *) theFact);
1515    CloseStringDestination(theEnv,"FactPPForm");
1516   }
1517 
1518 /**********************************/
1519 /* EnvFactIndex: C access routine */
1520 /*   for the fact-index function. */
1521 /**********************************/
EnvFactIndex(void * theEnv,void * factPtr)1522 globle long long EnvFactIndex(
1523   void *theEnv,
1524   void *factPtr)
1525   {
1526 #if MAC_XCD
1527 #pragma unused(theEnv)
1528 #endif
1529 
1530    return(((struct fact *) factPtr)->factIndex);
1531   }
1532 
1533 /*************************************/
1534 /* EnvAssertString: C access routine */
1535 /*   for the assert-string function. */
1536 /*************************************/
EnvAssertString(void * theEnv,const char * theString)1537 globle void *EnvAssertString(
1538   void *theEnv,
1539   const char *theString)
1540   {
1541    struct fact *theFact;
1542    int danglingConstructs;
1543    danglingConstructs = ConstructData(theEnv)->DanglingConstructs;
1544 
1545    if ((theFact = StringToFact(theEnv,theString)) == NULL) return(NULL);
1546 
1547    if ((! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
1548        (EvaluationData(theEnv)->CurrentExpression == NULL))
1549      { ConstructData(theEnv)->DanglingConstructs = danglingConstructs; }
1550 
1551    return((void *) EnvAssert(theEnv,(void *) theFact));
1552   }
1553 
1554 /******************************************************/
1555 /* EnvGetFactListChanged: Returns the flag indicating */
1556 /*   whether a change to the fact-list has been made. */
1557 /******************************************************/
EnvGetFactListChanged(void * theEnv)1558 globle int EnvGetFactListChanged(
1559   void *theEnv)
1560   {
1561    return(FactData(theEnv)->ChangeToFactList);
1562   }
1563 
1564 /***********************************************************/
1565 /* EnvSetFactListChanged: Sets the flag indicating whether */
1566 /*   a change to the fact-list has been made.              */
1567 /***********************************************************/
EnvSetFactListChanged(void * theEnv,int value)1568 globle void EnvSetFactListChanged(
1569   void *theEnv,
1570   int value)
1571   {
1572    FactData(theEnv)->ChangeToFactList = value;
1573   }
1574 
1575 /****************************************/
1576 /* GetNumberOfFacts: Returns the number */
1577 /* of facts in the fact-list.           */
1578 /****************************************/
GetNumberOfFacts(void * theEnv)1579 globle unsigned long GetNumberOfFacts(
1580   void *theEnv)
1581   {
1582    return(FactData(theEnv)->NumberOfFacts);
1583   }
1584 
1585 /***********************************************************/
1586 /* ResetFacts: Reset function for facts. Sets the starting */
1587 /*   fact index to zero and removes all facts.             */
1588 /***********************************************************/
ResetFacts(void * theEnv)1589 static void ResetFacts(
1590   void *theEnv)
1591   {
1592    /*====================================*/
1593    /* Initialize the fact index to zero. */
1594    /*====================================*/
1595 
1596    FactData(theEnv)->NextFactIndex = 0L;
1597 
1598    /*======================================*/
1599    /* Remove all facts from the fact list. */
1600    /*======================================*/
1601 
1602    RemoveAllFacts(theEnv);
1603   }
1604 
1605 /************************************************************/
1606 /* ClearFactsReady: Clear ready function for facts. Returns */
1607 /*   TRUE if facts were successfully removed and the clear  */
1608 /*   command can continue, otherwise FALSE.                 */
1609 /************************************************************/
ClearFactsReady(void * theEnv)1610 static int ClearFactsReady(
1611   void *theEnv)
1612   {
1613    /*======================================*/
1614    /* Facts can not be deleted when a join */
1615    /* operation is already in progress.    */
1616    /*======================================*/
1617 
1618    if (EngineData(theEnv)->JoinOperationInProgress) return(FALSE);
1619 
1620    /*====================================*/
1621    /* Initialize the fact index to zero. */
1622    /*====================================*/
1623 
1624    FactData(theEnv)->NextFactIndex = 0L;
1625 
1626    /*======================================*/
1627    /* Remove all facts from the fact list. */
1628    /*======================================*/
1629 
1630    RemoveAllFacts(theEnv);
1631 
1632    /*==============================================*/
1633    /* If for some reason there are any facts still */
1634    /* remaining, don't continue with the clear.    */
1635    /*==============================================*/
1636 
1637    if (EnvGetNextFact(theEnv,NULL) != NULL) return(FALSE);
1638 
1639    /*=============================*/
1640    /* Return TRUE to indicate the */
1641    /* clear command can continue. */
1642    /*=============================*/
1643 
1644    return(TRUE);
1645   }
1646 
1647 /***************************************************/
1648 /* FindIndexedFact: Returns a pointer to a fact in */
1649 /*   the fact list with the specified fact index.  */
1650 /***************************************************/
FindIndexedFact(void * theEnv,long long factIndexSought)1651 globle struct fact *FindIndexedFact(
1652   void *theEnv,
1653   long long factIndexSought)
1654   {
1655    struct fact *theFact;
1656 
1657    for (theFact = (struct fact *) EnvGetNextFact(theEnv,NULL);
1658         theFact != NULL;
1659         theFact = (struct fact *) EnvGetNextFact(theEnv,theFact))
1660      {
1661       if (theFact->factIndex == factIndexSought)
1662         { return(theFact); }
1663      }
1664 
1665    return(NULL);
1666   }
1667 
1668 /*****************************************/
1669 /* EnvAddAssertFunction: Adds a function */
1670 /*   to the ListOfAssertFunctions.       */
1671 /*****************************************/
EnvAddAssertFunction(void * theEnv,const char * name,void (* functionPtr)(void *,void *),int priority)1672 globle intBool EnvAddAssertFunction(
1673   void *theEnv,
1674   const char *name,
1675   void (*functionPtr)(void *, void *),
1676   int priority)
1677   {
1678    FactData(theEnv)->ListOfAssertFunctions =
1679       AddFunctionToCallListWithArg(theEnv,name,priority,
1680                                               functionPtr,
1681                                               FactData(theEnv)->ListOfAssertFunctions,TRUE);
1682    return(1);
1683   }
1684 
1685 /********************************************/
1686 /* EnvAddAssertFunctionWithContext: Adds a  */
1687 /*   function to the ListOfAssertFunctions. */
1688 /********************************************/
EnvAddAssertFunctionWithContext(void * theEnv,const char * name,void (* functionPtr)(void *,void *),int priority,void * context)1689 globle intBool EnvAddAssertFunctionWithContext(
1690   void *theEnv,
1691   const char *name,
1692   void (*functionPtr)(void *, void *),
1693   int priority,
1694   void *context)
1695   {
1696    FactData(theEnv)->ListOfAssertFunctions =
1697       AddFunctionToCallListWithArgWithContext(theEnv,name,priority,functionPtr,
1698                                        FactData(theEnv)->ListOfAssertFunctions,
1699                                        TRUE,context);
1700    return(1);
1701   }
1702 
1703 /***********************************************/
1704 /* EnvRemoveAssertFunction: Removes a function */
1705 /*   from the ListOfAssertFunctions.           */
1706 /***********************************************/
EnvRemoveAssertFunction(void * theEnv,const char * name)1707 globle intBool EnvRemoveAssertFunction(
1708   void *theEnv,
1709   const char *name)
1710   {
1711    int found;
1712 
1713    FactData(theEnv)->ListOfAssertFunctions =
1714       RemoveFunctionFromCallListWithArg(theEnv,name,FactData(theEnv)->ListOfAssertFunctions,&found);
1715 
1716    if (found) return(TRUE);
1717 
1718    return(FALSE);
1719   }
1720 
1721 /******************************************/
1722 /* EnvAddRetractFunction: Adds a function */
1723 /*   to the ListOfRetractFunctions.       */
1724 /******************************************/
EnvAddRetractFunction(void * theEnv,const char * name,void (* functionPtr)(void *,void *),int priority)1725 globle intBool EnvAddRetractFunction(
1726   void *theEnv,
1727   const char *name,
1728   void (*functionPtr)(void *, void *),
1729   int priority)
1730   {
1731    FactData(theEnv)->ListOfRetractFunctions =
1732       AddFunctionToCallListWithArg(theEnv,name,priority,
1733                                               functionPtr,
1734                                               FactData(theEnv)->ListOfRetractFunctions,TRUE);
1735    return(1);
1736   }
1737 
1738 /*********************************************/
1739 /* EnvAddRetractFunctionWithContext: Adds a  */
1740 /*   function to the ListOfRetractFunctions. */
1741 /*********************************************/
EnvAddRetractFunctionWithContext(void * theEnv,const char * name,void (* functionPtr)(void *,void *),int priority,void * context)1742 globle intBool EnvAddRetractFunctionWithContext(
1743   void *theEnv,
1744   const char *name,
1745   void (*functionPtr)(void *, void *),
1746   int priority,
1747   void *context)
1748   {
1749    FactData(theEnv)->ListOfRetractFunctions =
1750       AddFunctionToCallListWithArgWithContext(theEnv,name,priority,functionPtr,
1751                                        FactData(theEnv)->ListOfRetractFunctions,
1752                                        TRUE,context);
1753    return(1);
1754   }
1755 
1756 /************************************************/
1757 /* EnvRemoveRetractFunction: Removes a function */
1758 /*   from the ListOfRetractFunctions.           */
1759 /************************************************/
EnvRemoveRetractFunction(void * theEnv,const char * name)1760 globle intBool EnvRemoveRetractFunction(
1761   void *theEnv,
1762   const char *name)
1763   {
1764    int found;
1765 
1766    FactData(theEnv)->ListOfRetractFunctions =
1767       RemoveFunctionFromCallListWithArg(theEnv,name,FactData(theEnv)->ListOfRetractFunctions,&found);
1768 
1769    if (found) return(TRUE);
1770 
1771    return(FALSE);
1772   }
1773 
1774 /*****************************************/
1775 /* EnvAddModifyFunction: Adds a function */
1776 /*   to the ListOfModifyFunctions.       */
1777 /*****************************************/
EnvAddModifyFunction(void * theEnv,const char * name,void (* functionPtr)(void *,void *,void *),int priority)1778 globle intBool EnvAddModifyFunction(
1779   void *theEnv,
1780   const char *name,
1781   void (*functionPtr)(void *, void *, void *),
1782   int priority)
1783   {
1784    FactData(theEnv)->ListOfModifyFunctions =
1785       AddFunctionToCallListWithArg(theEnv,name,priority,
1786                                               (void (*)(void *, void *)) functionPtr,
1787                                               FactData(theEnv)->ListOfModifyFunctions,TRUE);
1788    return(1);
1789   }
1790 
1791 /********************************************/
1792 /* EnvAddModifyFunctionWithContext: Adds a  */
1793 /*   function to the ListOfModifyFunctions. */
1794 /********************************************/
EnvAddModifyFunctionWithContext(void * theEnv,const char * name,void (* functionPtr)(void *,void *,void *),int priority,void * context)1795 globle intBool EnvAddModifyFunctionWithContext(
1796   void *theEnv,
1797   const char *name,
1798   void (*functionPtr)(void *, void *, void *),
1799   int priority,
1800   void *context)
1801   {
1802    FactData(theEnv)->ListOfModifyFunctions =
1803       AddFunctionToCallListWithArgWithContext(theEnv,name,priority,
1804                                        (void (*)(void *, void *)) functionPtr,
1805                                        FactData(theEnv)->ListOfModifyFunctions,
1806                                        TRUE,context);
1807    return(1);
1808   }
1809 
1810 /***********************************************/
1811 /* EnvRemoveModifyFunction: Removes a function */
1812 /*   from the ListOfModifyFunctions.           */
1813 /***********************************************/
EnvRemoveModifyFunction(void * theEnv,const char * name)1814 globle intBool EnvRemoveModifyFunction(
1815   void *theEnv,
1816   const char *name)
1817   {
1818    int found;
1819 
1820    FactData(theEnv)->ListOfModifyFunctions =
1821       RemoveFunctionFromCallListWithArg(theEnv,name,FactData(theEnv)->ListOfModifyFunctions,&found);
1822 
1823    if (found) return(TRUE);
1824 
1825    return(FALSE);
1826   }
1827 
1828 /*#####################################*/
1829 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
1830 /*#####################################*/
1831 
1832 #if ALLOW_ENVIRONMENT_GLOBALS
1833 
AddAssertFunction(const char * name,void (* functionPtr)(void *,void *),int priority)1834 globle intBool AddAssertFunction(
1835   const char *name,
1836   void (*functionPtr)(void *,void *),
1837   int priority)
1838   {
1839    void *theEnv;
1840 
1841    theEnv = GetCurrentEnvironment();
1842 
1843    FactData(theEnv)->ListOfAssertFunctions =
1844        AddFunctionToCallListWithArg(theEnv,name,priority,(void (*)(void *, void *)) functionPtr,
1845                              FactData(theEnv)->ListOfAssertFunctions,TRUE);
1846    return(1);
1847   }
1848 
AddModifyFunction(const char * name,void (* functionPtr)(void *,void *,void *),int priority)1849 globle intBool AddModifyFunction(
1850   const char *name,
1851   void (*functionPtr)(void *,void *,void *),
1852   int priority)
1853   {
1854    void *theEnv;
1855 
1856    theEnv = GetCurrentEnvironment();
1857 
1858    FactData(theEnv)->ListOfModifyFunctions =
1859        AddFunctionToCallListWithArg(theEnv,name,priority,(void (*)(void *, void *)) functionPtr,
1860                              FactData(theEnv)->ListOfModifyFunctions,TRUE);
1861    return(1);
1862   }
1863 
AddRetractFunction(const char * name,void (* functionPtr)(void *,void *),int priority)1864 globle intBool AddRetractFunction(
1865   const char *name,
1866   void (*functionPtr)(void *,void *),
1867   int priority)
1868   {
1869    void *theEnv;
1870 
1871    theEnv = GetCurrentEnvironment();
1872 
1873    FactData(theEnv)->ListOfRetractFunctions =
1874        AddFunctionToCallListWithArg(theEnv,name,priority,(void (*)(void *, void *)) functionPtr,
1875                              FactData(theEnv)->ListOfRetractFunctions,TRUE);
1876    return(1);
1877   }
1878 
Assert(void * vTheFact)1879 globle void *Assert(
1880   void *vTheFact)
1881   {
1882    return EnvAssert(GetCurrentEnvironment(),vTheFact);
1883   }
1884 
AssertString(const char * theString)1885 globle void *AssertString(
1886   const char *theString)
1887   {
1888    return EnvAssertString(GetCurrentEnvironment(),theString);
1889   }
1890 
AssignFactSlotDefaults(void * vTheFact)1891 globle intBool AssignFactSlotDefaults(
1892   void *vTheFact)
1893   {
1894    return EnvAssignFactSlotDefaults(GetCurrentEnvironment(),vTheFact);
1895   }
1896 
CreateFact(void * vTheDeftemplate)1897 globle struct fact *CreateFact(
1898   void *vTheDeftemplate)
1899   {
1900    return EnvCreateFact(GetCurrentEnvironment(),vTheDeftemplate);
1901   }
1902 
DecrementFactCount(void * factPtr)1903 globle void DecrementFactCount(
1904   void *factPtr)
1905   {
1906    EnvDecrementFactCount(GetCurrentEnvironment(),factPtr);
1907   }
1908 
FactIndex(void * factPtr)1909 globle long long FactIndex(
1910   void *factPtr)
1911   {
1912    return(EnvFactIndex(GetCurrentEnvironment(),factPtr));
1913   }
1914 
GetFactListChanged()1915 globle int GetFactListChanged()
1916   {
1917    return EnvGetFactListChanged(GetCurrentEnvironment());
1918   }
1919 
GetFactPPForm(char * buffer,unsigned bufferLength,void * theFact)1920 globle void GetFactPPForm(
1921   char *buffer,
1922   unsigned bufferLength,
1923   void *theFact)
1924   {
1925    EnvGetFactPPForm(GetCurrentEnvironment(),buffer,bufferLength,theFact);
1926   }
1927 
GetFactSlot(void * vTheFact,const char * slotName,DATA_OBJECT * theValue)1928 globle intBool GetFactSlot(
1929   void *vTheFact,
1930   const char *slotName,
1931   DATA_OBJECT *theValue)
1932   {
1933    return(EnvGetFactSlot(GetCurrentEnvironment(),vTheFact,slotName,theValue));
1934   }
1935 
GetNextFact(void * factPtr)1936 globle void *GetNextFact(
1937   void *factPtr)
1938   {
1939    return EnvGetNextFact(GetCurrentEnvironment(),factPtr);
1940   }
1941 
IncrementFactCount(void * factPtr)1942 globle void IncrementFactCount(
1943   void *factPtr)
1944   {
1945    EnvIncrementFactCount(GetCurrentEnvironment(),factPtr);
1946   }
1947 
PutFactSlot(void * vTheFact,const char * slotName,DATA_OBJECT * theValue)1948 globle intBool PutFactSlot(
1949   void *vTheFact,
1950   const char *slotName,
1951   DATA_OBJECT *theValue)
1952   {
1953    return EnvPutFactSlot(GetCurrentEnvironment(),vTheFact,slotName,theValue);
1954   }
1955 
RemoveAssertFunction(const char * name)1956 globle intBool RemoveAssertFunction(
1957   const char *name)
1958   {
1959    return EnvRemoveAssertFunction(GetCurrentEnvironment(),name);
1960   }
1961 
RemoveModifyFunction(const char * name)1962 globle intBool RemoveModifyFunction(
1963   const char *name)
1964   {
1965    return EnvRemoveModifyFunction(GetCurrentEnvironment(),name);
1966   }
1967 
RemoveRetractFunction(const char * name)1968 globle intBool RemoveRetractFunction(
1969   const char *name)
1970   {
1971    return EnvRemoveRetractFunction(GetCurrentEnvironment(),name);
1972   }
1973 
Retract(void * vTheFact)1974 globle intBool Retract(
1975   void *vTheFact)
1976   {
1977    return EnvRetract(GetCurrentEnvironment(),vTheFact);
1978   }
1979 
SetFactListChanged(int value)1980 globle void SetFactListChanged(
1981   int value)
1982   {
1983    EnvSetFactListChanged(GetCurrentEnvironment(),value);
1984   }
1985 
1986 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
1987 
1988 #endif /* DEFTEMPLATE_CONSTRUCT && DEFRULE_CONSTRUCT */
1989 
1990