1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*            DEFTEMPLATE UTILITIES MODULE             */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Provides utility routines for deftemplates.      */
11 /*                                                           */
12 /* Principal Programmer(s):                                  */
13 /*      Gary D. Riley                                        */
14 /*                                                           */
15 /* Contributing Programmer(s):                               */
16 /*      Brian L. Dantes                                      */
17 /*                                                           */
18 /* Revision History:                                         */
19 /*                                                           */
20 /*      6.23: Added support for templates maintaining their  */
21 /*            own list of facts.                             */
22 /*                                                           */
23 /*      6.24: Renamed BOOLEAN macro type to intBool.         */
24 /*                                                           */
25 /*            Added additional arguments to                  */
26 /*            InvalidDeftemplateSlotMessage function.        */
27 /*                                                           */
28 /*            Added additional arguments to                  */
29 /*            PrintTemplateFact function.                    */
30 /*                                                           */
31 /*      6.30: Support for long long integers.                */
32 /*                                                           */
33 /*            Used gensprintf instead of sprintf.            */
34 /*                                                           */
35 /*            Added const qualifiers to remove C++           */
36 /*            deprecation warnings.                          */
37 /*                                                           */
38 /*************************************************************/
39 
40 #define  _TMPLTUTL_SOURCE_
41 
42 #include "setup.h"
43 
44 #if DEFTEMPLATE_CONSTRUCT
45 
46 #include <stdio.h>
47 
48 #define _STDIO_INCLUDED_
49 
50 #include <string.h>
51 
52 #include "extnfunc.h"
53 #include "memalloc.h"
54 #include "constrct.h"
55 #include "router.h"
56 #include "argacces.h"
57 #include "cstrnchk.h"
58 #include "envrnmnt.h"
59 #include "tmpltfun.h"
60 #include "tmpltpsr.h"
61 #include "modulutl.h"
62 #include "watch.h"
63 #include "sysdep.h"
64 #include "tmpltbsc.h"
65 #include "tmpltdef.h"
66 
67 #include "tmpltutl.h"
68 
69 /********************************************************/
70 /* InvalidDeftemplateSlotMessage: Generic error message */
71 /*   for use when a specified slot name isn't defined   */
72 /*   in its corresponding deftemplate.                  */
73 /********************************************************/
InvalidDeftemplateSlotMessage(void * theEnv,const char * slotName,const char * deftemplateName,int printCR)74 globle void InvalidDeftemplateSlotMessage(
75   void *theEnv,
76   const char *slotName,
77   const char *deftemplateName,
78   int printCR)
79   {
80    PrintErrorID(theEnv,"TMPLTDEF",1,printCR);
81    EnvPrintRouter(theEnv,WERROR,"Invalid slot ");
82    EnvPrintRouter(theEnv,WERROR,slotName);
83    EnvPrintRouter(theEnv,WERROR," not defined in corresponding deftemplate ");
84    EnvPrintRouter(theEnv,WERROR,deftemplateName);
85    EnvPrintRouter(theEnv,WERROR,".\n");
86   }
87 
88 /**********************************************************/
89 /* SingleFieldSlotCardinalityError: Generic error message */
90 /*   used when an attempt is made to placed a multifield  */
91 /*   value into a single field slot.                      */
92 /**********************************************************/
SingleFieldSlotCardinalityError(void * theEnv,const char * slotName)93 globle void SingleFieldSlotCardinalityError(
94   void *theEnv,
95   const char *slotName)
96   {
97    PrintErrorID(theEnv,"TMPLTDEF",2,TRUE);
98    EnvPrintRouter(theEnv,WERROR,"The single field slot ");
99    EnvPrintRouter(theEnv,WERROR,slotName);
100    EnvPrintRouter(theEnv,WERROR," can only contain a single field value.\n");
101   }
102 
103 /**********************************************************************/
104 /* MultiIntoSingleFieldSlotError: Determines if a multifield value is */
105 /*   being placed into a single field slot of a deftemplate fact.     */
106 /**********************************************************************/
MultiIntoSingleFieldSlotError(void * theEnv,struct templateSlot * theSlot,struct deftemplate * theDeftemplate)107 globle void MultiIntoSingleFieldSlotError(
108   void *theEnv,
109   struct templateSlot *theSlot,
110   struct deftemplate *theDeftemplate)
111   {
112    PrintErrorID(theEnv,"TMPLTFUN",2,TRUE);
113    EnvPrintRouter(theEnv,WERROR,"Attempted to assert a multifield value \n");
114    EnvPrintRouter(theEnv,WERROR,"into the single field slot ");
115    if (theSlot != NULL) EnvPrintRouter(theEnv,WERROR,theSlot->slotName->contents);
116    else EnvPrintRouter(theEnv,WERROR,"<<unknown>>");
117    EnvPrintRouter(theEnv,WERROR," of deftemplate ");
118    if (theDeftemplate != NULL) EnvPrintRouter(theEnv,WERROR,theDeftemplate->header.name->contents);
119    else EnvPrintRouter(theEnv,WERROR,"<<unknown>>");
120    EnvPrintRouter(theEnv,WERROR,".\n");
121 
122    SetEvaluationError(theEnv,TRUE);
123   }
124 
125 /**************************************************************/
126 /* CheckTemplateFact: Checks a fact to see if it violates any */
127 /*   deftemplate type, allowed-..., or range specifications.  */
128 /**************************************************************/
CheckTemplateFact(void * theEnv,struct fact * theFact)129 globle void CheckTemplateFact(
130   void *theEnv,
131   struct fact *theFact)
132   {
133    struct field *sublist;
134    int i;
135    struct deftemplate *theDeftemplate;
136    struct templateSlot *slotPtr;
137    DATA_OBJECT theData;
138    char thePlace[20];
139    int rv;
140 
141    if (! EnvGetDynamicConstraintChecking(theEnv)) return;
142 
143    sublist = theFact->theProposition.theFields;
144 
145    /*========================================================*/
146    /* If the deftemplate corresponding to the first field of */
147    /* of the fact cannot be found, then the fact cannot be   */
148    /* checked against the deftemplate format.                */
149    /*========================================================*/
150 
151    theDeftemplate = theFact->whichDeftemplate;
152    if (theDeftemplate == NULL) return;
153    if (theDeftemplate->implied) return;
154 
155    /*=============================================*/
156    /* Check each of the slots of the deftemplate. */
157    /*=============================================*/
158 
159    i = 0;
160    for (slotPtr = theDeftemplate->slotList;
161         slotPtr != NULL;
162         slotPtr = slotPtr->next)
163      {
164       /*================================================*/
165       /* Store the slot value in the appropriate format */
166       /* for a call to the constraint checking routine. */
167       /*================================================*/
168 
169       if (slotPtr->multislot == FALSE)
170         {
171          theData.type = sublist[i].type;
172          theData.value = sublist[i].value;
173          i++;
174         }
175       else
176         {
177          theData.type = MULTIFIELD;
178          theData.value = (void *) sublist[i].value;
179          SetDOBegin(theData,1);
180          SetDOEnd(theData,((struct multifield *) sublist[i].value)->multifieldLength);
181          i++;
182         }
183 
184       /*=============================================*/
185       /* Call the constraint checking routine to see */
186       /* if a constraint violation occurred.         */
187       /*=============================================*/
188 
189       rv = ConstraintCheckDataObject(theEnv,&theData,slotPtr->constraints);
190       if (rv != NO_VIOLATION)
191         {
192          gensprintf(thePlace,"fact f-%-5lld ",theFact->factIndex);
193 
194          PrintErrorID(theEnv,"CSTRNCHK",1,TRUE);
195          EnvPrintRouter(theEnv,WERROR,"Slot value ");
196          PrintDataObject(theEnv,WERROR,&theData);
197          EnvPrintRouter(theEnv,WERROR," ");
198          ConstraintViolationErrorMessage(theEnv,NULL,thePlace,FALSE,0,slotPtr->slotName,
199                                          0,rv,slotPtr->constraints,TRUE);
200          SetHaltExecution(theEnv,TRUE);
201          return;
202         }
203      }
204 
205    return;
206   }
207 
208 /***********************************************************************/
209 /* CheckRHSSlotTypes: Checks the validity of a change to a slot as the */
210 /*   result of an assert, modify, or duplicate command. This checking  */
211 /*   is performed statically (i.e. when the command is being parsed).  */
212 /***********************************************************************/
CheckRHSSlotTypes(void * theEnv,struct expr * rhsSlots,struct templateSlot * slotPtr,const char * thePlace)213 globle intBool CheckRHSSlotTypes(
214   void *theEnv,
215   struct expr *rhsSlots,
216   struct templateSlot *slotPtr,
217   const char *thePlace)
218   {
219    int rv;
220    const char *theName;
221 
222    if (EnvGetStaticConstraintChecking(theEnv) == FALSE) return(TRUE);
223       rv = ConstraintCheckExpressionChain(theEnv,rhsSlots,slotPtr->constraints);
224       if (rv != NO_VIOLATION)
225         {
226          if (rv != CARDINALITY_VIOLATION) theName = "A literal slot value";
227          else theName = "Literal slot values";
228          ConstraintViolationErrorMessage(theEnv,theName,thePlace,TRUE,0,
229                                          slotPtr->slotName,0,rv,slotPtr->constraints,TRUE);
230          return(0);
231         }
232 
233    return(1);
234   }
235 
236 /*********************************************************/
237 /* GetNthSlot: Given a deftemplate and an integer index, */
238 /*   returns the nth slot of a deftemplate.              */
239 /*********************************************************/
GetNthSlot(struct deftemplate * theDeftemplate,int position)240 globle struct templateSlot *GetNthSlot(
241   struct deftemplate *theDeftemplate,
242   int position)
243   {
244    struct templateSlot *slotPtr;
245    int i = 0;
246 
247    slotPtr = theDeftemplate->slotList;
248    while (slotPtr != NULL)
249      {
250       if (i == position) return(slotPtr);
251       slotPtr = slotPtr->next;
252       i++;
253      }
254 
255    return(NULL);
256   }
257 
258 /*******************************************************/
259 /* FindSlotPosition: Finds the position of a specified */
260 /*   slot in a deftemplate structure.                  */
261 /*******************************************************/
FindSlotPosition(struct deftemplate * theDeftemplate,SYMBOL_HN * name)262 globle int FindSlotPosition(
263   struct deftemplate *theDeftemplate,
264   SYMBOL_HN *name)
265   {
266    struct templateSlot *slotPtr;
267    int position;
268 
269    for (slotPtr = theDeftemplate->slotList, position = 1;
270         slotPtr != NULL;
271         slotPtr = slotPtr->next, position++)
272      {
273       if (slotPtr->slotName == name)
274         { return(position); }
275      }
276 
277    return(0);
278   }
279 
280 /*******************************************************************/
281 /* PrintTemplateFact: Prints a fact using the deftemplate format.  */
282 /*   Returns TRUE if the fact was printed using this format, */
283 /*   otherwise FALSE.                                        */
284 /*******************************************************************/
PrintTemplateFact(void * theEnv,const char * logicalName,struct fact * theFact,int seperateLines,int ignoreDefaults)285 globle void PrintTemplateFact(
286   void *theEnv,
287   const char *logicalName,
288   struct fact *theFact,
289   int seperateLines,
290   int ignoreDefaults)
291   {
292    struct field *sublist;
293    int i;
294    struct deftemplate *theDeftemplate;
295    struct templateSlot *slotPtr;
296    DATA_OBJECT tempDO;
297    int slotPrinted = FALSE;
298 
299    /*==============================*/
300    /* Initialize some information. */
301    /*==============================*/
302 
303    theDeftemplate = theFact->whichDeftemplate;
304    sublist = theFact->theProposition.theFields;
305 
306    /*=============================================*/
307    /* Print the relation name of the deftemplate. */
308    /*=============================================*/
309 
310    EnvPrintRouter(theEnv,logicalName,"(");
311    EnvPrintRouter(theEnv,logicalName,theDeftemplate->header.name->contents);
312 
313    /*===================================================*/
314    /* Print each of the field slots of the deftemplate. */
315    /*===================================================*/
316 
317    slotPtr = theDeftemplate->slotList;
318 
319    i = 0;
320    while (slotPtr != NULL)
321      {
322       /*=================================================*/
323       /* If we're ignoring slots with their original     */
324       /* default value, check to see if the fact's slot  */
325       /* value differs from the deftemplate default.     */
326       /*=================================================*/
327 
328       if (ignoreDefaults && (slotPtr->defaultDynamic == FALSE))
329         {
330          DeftemplateSlotDefault(theEnv,theDeftemplate,slotPtr,&tempDO,TRUE);
331 
332          if (slotPtr->multislot == FALSE)
333            {
334             if ((GetType(tempDO) == sublist[i].type) &&
335                 (GetValue(tempDO) == sublist[i].value))
336               {
337                i++;
338                slotPtr = slotPtr->next;
339                continue;
340               }
341            }
342          else if (MultifieldsEqual((struct multifield*) GetValue(tempDO),
343                                    (struct multifield *) sublist[i].value))
344            {
345             i++;
346             slotPtr = slotPtr->next;
347             continue;
348            }
349         }
350 
351       /*===========================================*/
352       /* Print the opening parenthesis of the slot */
353       /* and the slot name.                        */
354       /*===========================================*/
355 
356       if (! slotPrinted)
357         {
358          slotPrinted = TRUE;
359          EnvPrintRouter(theEnv,logicalName," ");
360         }
361 
362       if (seperateLines)
363         { EnvPrintRouter(theEnv,logicalName,"\n   "); }
364 
365       EnvPrintRouter(theEnv,logicalName,"(");
366       EnvPrintRouter(theEnv,logicalName,slotPtr->slotName->contents);
367 
368       /*======================================================*/
369       /* Print the value of the slot for a single field slot. */
370       /*======================================================*/
371 
372       if (slotPtr->multislot == FALSE)
373         {
374          EnvPrintRouter(theEnv,logicalName," ");
375          PrintAtom(theEnv,logicalName,sublist[i].type,sublist[i].value);
376         }
377 
378       /*==========================================================*/
379       /* Else print the value of the slot for a multi field slot. */
380       /*==========================================================*/
381 
382       else
383         {
384          struct multifield *theSegment;
385 
386          theSegment = (struct multifield *) sublist[i].value;
387          if (theSegment->multifieldLength > 0)
388            {
389             EnvPrintRouter(theEnv,logicalName," ");
390             PrintMultifield(theEnv,logicalName,(struct multifield *) sublist[i].value,
391                             0,(long) theSegment->multifieldLength-1,FALSE);
392            }
393         }
394 
395       /*============================================*/
396       /* Print the closing parenthesis of the slot. */
397       /*============================================*/
398 
399       i++;
400       EnvPrintRouter(theEnv,logicalName,")");
401       slotPtr = slotPtr->next;
402       if (slotPtr != NULL) EnvPrintRouter(theEnv,logicalName," ");
403      }
404 
405    EnvPrintRouter(theEnv,logicalName,")");
406   }
407 
408 /***************************************************************************/
409 /* UpdateDeftemplateScope: Updates the scope flag of all the deftemplates. */
410 /***************************************************************************/
UpdateDeftemplateScope(void * theEnv)411 globle void UpdateDeftemplateScope(
412   void *theEnv)
413   {
414    struct deftemplate *theDeftemplate;
415    int moduleCount;
416    struct defmodule *theModule;
417    struct defmoduleItemHeader *theItem;
418 
419    /*==================================*/
420    /* Loop through all of the modules. */
421    /*==================================*/
422 
423    for (theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,NULL);
424         theModule != NULL;
425         theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,theModule))
426      {
427       /*======================================================*/
428       /* Loop through each of the deftemplates in the module. */
429       /*======================================================*/
430 
431       theItem = (struct defmoduleItemHeader *)
432                 GetModuleItem(theEnv,theModule,DeftemplateData(theEnv)->DeftemplateModuleIndex);
433 
434       for (theDeftemplate = (struct deftemplate *) theItem->firstItem;
435            theDeftemplate != NULL ;
436            theDeftemplate = (struct deftemplate *) EnvGetNextDeftemplate(theEnv,theDeftemplate))
437         {
438          /*=======================================*/
439          /* If the deftemplate can be seen by the */
440          /* current module, then it is in scope.  */
441          /*=======================================*/
442 
443          if (FindImportedConstruct(theEnv,"deftemplate",theModule,
444                                    ValueToString(theDeftemplate->header.name),
445                                    &moduleCount,TRUE,NULL) != NULL)
446            { theDeftemplate->inScope = TRUE; }
447          else
448            { theDeftemplate->inScope = FALSE; }
449         }
450      }
451   }
452 
453 /****************************************************************/
454 /* FindSlot: Finds a specified slot in a deftemplate structure. */
455 /****************************************************************/
FindSlot(struct deftemplate * theDeftemplate,SYMBOL_HN * name,short * whichOne)456 globle struct templateSlot *FindSlot(
457   struct deftemplate *theDeftemplate,
458   SYMBOL_HN *name,
459   short *whichOne)
460   {
461    struct templateSlot *slotPtr;
462 
463    *whichOne = 1;
464    slotPtr = theDeftemplate->slotList;
465    while (slotPtr != NULL)
466      {
467       if (slotPtr->slotName == name)
468         { return(slotPtr); }
469       (*whichOne)++;
470       slotPtr = slotPtr->next;
471      }
472 
473    *whichOne = -1;
474    return(NULL);
475   }
476 
477 #if (! RUN_TIME) && (! BLOAD_ONLY)
478 
479 /************************************************************/
480 /* CreateImpliedDeftemplate: Creates an implied deftemplate */
481 /*   and adds it to the list of deftemplates.               */
482 /************************************************************/
CreateImpliedDeftemplate(void * theEnv,SYMBOL_HN * deftemplateName,int setFlag)483 globle struct deftemplate *CreateImpliedDeftemplate(
484   void *theEnv,
485   SYMBOL_HN *deftemplateName,
486   int setFlag)
487   {
488    struct deftemplate *newDeftemplate;
489 
490    newDeftemplate = get_struct(theEnv,deftemplate);
491    newDeftemplate->header.name = deftemplateName;
492    newDeftemplate->header.ppForm = NULL;
493    newDeftemplate->header.usrData = NULL;
494    newDeftemplate->slotList = NULL;
495    newDeftemplate->implied = setFlag;
496    newDeftemplate->numberOfSlots = 0;
497    newDeftemplate->inScope = 1;
498    newDeftemplate->patternNetwork = NULL;
499    newDeftemplate->factList = NULL;
500    newDeftemplate->lastFact = NULL;
501    newDeftemplate->busyCount = 0;
502    newDeftemplate->watch = FALSE;
503    newDeftemplate->header.next = NULL;
504 
505 #if DEBUGGING_FUNCTIONS
506    if (EnvGetWatchItem(theEnv,"facts"))
507      { EnvSetDeftemplateWatch(theEnv,ON,(void *) newDeftemplate); }
508 #endif
509 
510    newDeftemplate->header.whichModule = (struct defmoduleItemHeader *)
511                                         GetModuleItem(theEnv,NULL,DeftemplateData(theEnv)->DeftemplateModuleIndex);
512 
513    AddConstructToModule(&newDeftemplate->header);
514    InstallDeftemplate(theEnv,newDeftemplate);
515 
516    return(newDeftemplate);
517   }
518 
519 #endif
520 
521 #endif /* DEFTEMPLATE_CONSTRUCT */
522 
523