1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*             CONSTRAINT UTILITY MODULE               */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Utility routines for manipulating, initializing, */
11 /*   creating, copying, and comparing constraint records.    */
12 /*                                                           */
13 /* Principal Programmer(s):                                  */
14 /*      Gary D. Riley                                        */
15 /*                                                           */
16 /* Contributing Programmer(s):                               */
17 /*      Brian Dantes                                         */
18 /*                                                           */
19 /* Revision History:                                         */
20 /*                                                           */
21 /*      6.24: Added allowed-classes slot facet.              */
22 /*                                                           */
23 /*      6.30: Support for long long integers.                */
24 /*                                                           */
25 /*************************************************************/
26 
27 #define _CSTRNUTL_SOURCE_
28 
29 #include <stdio.h>
30 #define _STDIO_INCLUDED_
31 #include <stdlib.h>
32 
33 #include "setup.h"
34 
35 #include "constant.h"
36 #include "envrnmnt.h"
37 #include "memalloc.h"
38 #include "router.h"
39 #include "extnfunc.h"
40 #include "scanner.h"
41 #include "multifld.h"
42 #include "argacces.h"
43 
44 #include "cstrnutl.h"
45 
46 /************************************************/
47 /* GetConstraintRecord: Creates and initializes */
48 /*   the values of a constraint record.         */
49 /************************************************/
GetConstraintRecord(void * theEnv)50 globle struct constraintRecord *GetConstraintRecord(
51   void *theEnv)
52   {
53    CONSTRAINT_RECORD *constraints;
54    unsigned i;
55 
56    constraints = get_struct(theEnv,constraintRecord);
57 
58    for (i = 0 ; i < sizeof(CONSTRAINT_RECORD) ; i++)
59      { ((char *) constraints)[i] = '\0'; }
60 
61    SetAnyAllowedFlags(constraints,TRUE);
62 
63    constraints->multifieldsAllowed = FALSE;
64    constraints->singlefieldsAllowed = TRUE;
65 
66    constraints->anyRestriction = FALSE;
67    constraints->symbolRestriction = FALSE;
68    constraints->stringRestriction = FALSE;
69    constraints->floatRestriction = FALSE;
70    constraints->integerRestriction = FALSE;
71    constraints->classRestriction = FALSE;
72    constraints->instanceNameRestriction = FALSE;
73    constraints->classList = NULL;
74    constraints->restrictionList = NULL;
75    constraints->minValue = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->NegativeInfinity);
76    constraints->maxValue = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->PositiveInfinity);
77    constraints->minFields = GenConstant(theEnv,INTEGER,SymbolData(theEnv)->Zero);
78    constraints->maxFields = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->PositiveInfinity);
79    constraints->bucket = -1;
80    constraints->count = 0;
81    constraints->multifield = NULL;
82    constraints->next = NULL;
83 
84    return(constraints);
85   }
86 
87 /********************************************************/
88 /* SetAnyAllowedFlags: Sets the allowed type flags of a */
89 /*   constraint record to allow all types. If passed an */
90 /*   argument of TRUE, just the "any allowed" flag is   */
91 /*   set to TRUE. If passed an argument of FALSE, then  */
92 /*   all of the individual type flags are set to TRUE.  */
93 /********************************************************/
SetAnyAllowedFlags(CONSTRAINT_RECORD * theConstraint,int justOne)94 globle void SetAnyAllowedFlags(
95   CONSTRAINT_RECORD *theConstraint,
96   int justOne)
97   {
98    int flag1, flag2;
99 
100    if (justOne)
101      {
102       flag1 = TRUE;
103       flag2 = FALSE;
104      }
105    else
106      {
107       flag1 = FALSE;
108       flag2 = TRUE;
109      }
110 
111    theConstraint->anyAllowed = flag1;
112    theConstraint->symbolsAllowed = flag2;
113    theConstraint->stringsAllowed = flag2;
114    theConstraint->floatsAllowed = flag2;
115    theConstraint->integersAllowed = flag2;
116    theConstraint->instanceNamesAllowed = flag2;
117    theConstraint->instanceAddressesAllowed = flag2;
118    theConstraint->externalAddressesAllowed = flag2;
119    theConstraint->voidAllowed = flag2;
120    theConstraint->factAddressesAllowed = flag2;
121   }
122 
123 /*****************************************************/
124 /* CopyConstraintRecord: Copies a constraint record. */
125 /*****************************************************/
CopyConstraintRecord(void * theEnv,CONSTRAINT_RECORD * sourceConstraint)126 globle struct constraintRecord *CopyConstraintRecord(
127   void *theEnv,
128   CONSTRAINT_RECORD *sourceConstraint)
129   {
130    CONSTRAINT_RECORD *theConstraint;
131 
132    if (sourceConstraint == NULL) return(NULL);
133 
134    theConstraint = get_struct(theEnv,constraintRecord);
135 
136    theConstraint->anyAllowed = sourceConstraint->anyAllowed;
137    theConstraint->symbolsAllowed = sourceConstraint->symbolsAllowed;
138    theConstraint->stringsAllowed = sourceConstraint->stringsAllowed;
139    theConstraint->floatsAllowed = sourceConstraint->floatsAllowed;
140    theConstraint->integersAllowed = sourceConstraint->integersAllowed;
141    theConstraint->instanceNamesAllowed = sourceConstraint->instanceNamesAllowed;
142    theConstraint->instanceAddressesAllowed = sourceConstraint->instanceAddressesAllowed;
143    theConstraint->externalAddressesAllowed = sourceConstraint->externalAddressesAllowed;
144    theConstraint->voidAllowed = sourceConstraint->voidAllowed;
145    theConstraint->multifieldsAllowed = sourceConstraint->multifieldsAllowed;
146    theConstraint->singlefieldsAllowed = sourceConstraint->singlefieldsAllowed;
147    theConstraint->factAddressesAllowed = sourceConstraint->factAddressesAllowed;
148    theConstraint->anyRestriction = sourceConstraint->anyRestriction;
149    theConstraint->symbolRestriction = sourceConstraint->symbolRestriction;
150    theConstraint->stringRestriction = sourceConstraint->stringRestriction;
151    theConstraint->floatRestriction = sourceConstraint->floatRestriction;
152    theConstraint->integerRestriction = sourceConstraint->integerRestriction;
153    theConstraint->classRestriction = sourceConstraint->classRestriction;
154    theConstraint->instanceNameRestriction = sourceConstraint->instanceNameRestriction;
155    theConstraint->classList = CopyExpression(theEnv,sourceConstraint->classList);
156    theConstraint->restrictionList = CopyExpression(theEnv,sourceConstraint->restrictionList);
157    theConstraint->minValue = CopyExpression(theEnv,sourceConstraint->minValue);
158    theConstraint->maxValue = CopyExpression(theEnv,sourceConstraint->maxValue);
159    theConstraint->minFields = CopyExpression(theEnv,sourceConstraint->minFields);
160    theConstraint->maxFields = CopyExpression(theEnv,sourceConstraint->maxFields);
161    theConstraint->bucket = -1;
162    theConstraint->count = 0;
163    theConstraint->multifield = CopyConstraintRecord(theEnv,sourceConstraint->multifield);
164    theConstraint->next = NULL;
165 
166    return(theConstraint);
167   }
168 
169 #if (! RUN_TIME) && (! BLOAD_ONLY)
170 
171 /**************************************************************/
172 /* SetAnyRestrictionFlags: Sets the restriction type flags of */
173 /*   a constraint record to indicate there are restriction on */
174 /*   all types. If passed an argument of TRUE, just the       */
175 /*   "any restriction" flag is set to TRUE. If passed an      */
176 /*   argument of FALSE, then all of the individual type       */
177 /*   restriction flags are set to TRUE.                       */
178 /**************************************************************/
SetAnyRestrictionFlags(CONSTRAINT_RECORD * theConstraint,int justOne)179 globle void SetAnyRestrictionFlags(
180   CONSTRAINT_RECORD *theConstraint,
181   int justOne)
182   {
183    int flag1, flag2;
184 
185    if (justOne)
186      {
187       flag1 = TRUE;
188       flag2 = FALSE;
189      }
190    else
191      {
192       flag1 = FALSE;
193       flag2 = TRUE;
194      }
195 
196    theConstraint->anyRestriction = flag1;
197    theConstraint->symbolRestriction = flag2;
198    theConstraint->stringRestriction = flag2;
199    theConstraint->floatRestriction = flag2;
200    theConstraint->integerRestriction = flag2;
201    theConstraint->instanceNameRestriction = flag2;
202   }
203 
204 /*****************************************************/
205 /* SetConstraintType: Given a constraint type and a  */
206 /*   constraint, sets the allowed type flags for the */
207 /*   specified type in the constraint to TRUE.       */
208 /*****************************************************/
SetConstraintType(int theType,CONSTRAINT_RECORD * constraints)209 globle int SetConstraintType(
210   int theType,
211   CONSTRAINT_RECORD *constraints)
212   {
213    int rv = TRUE;
214 
215    switch(theType)
216      {
217       case UNKNOWN_VALUE:
218          rv = constraints->anyAllowed;
219          constraints->anyAllowed = TRUE;
220          break;
221 
222       case SYMBOL:
223          rv = constraints->symbolsAllowed;
224          constraints->symbolsAllowed = TRUE;
225          break;
226 
227       case STRING:
228          rv = constraints->stringsAllowed;
229          constraints->stringsAllowed = TRUE;
230          break;
231 
232       case SYMBOL_OR_STRING:
233          rv = (constraints->stringsAllowed | constraints->symbolsAllowed);
234          constraints->symbolsAllowed = TRUE;
235          constraints->stringsAllowed = TRUE;
236          break;
237 
238       case INTEGER:
239          rv = constraints->integersAllowed;
240          constraints->integersAllowed = TRUE;
241          break;
242 
243       case FLOAT:
244          rv = constraints->floatsAllowed;
245          constraints->floatsAllowed = TRUE;
246          break;
247 
248       case INTEGER_OR_FLOAT:
249          rv = (constraints->integersAllowed | constraints->floatsAllowed);
250          constraints->integersAllowed = TRUE;
251          constraints->floatsAllowed = TRUE;
252          break;
253 
254       case INSTANCE_ADDRESS:
255          rv = constraints->instanceAddressesAllowed;
256          constraints->instanceAddressesAllowed = TRUE;
257          break;
258 
259       case INSTANCE_NAME:
260          rv = constraints->instanceNamesAllowed;
261          constraints->instanceNamesAllowed = TRUE;
262          break;
263 
264       case INSTANCE_OR_INSTANCE_NAME:
265          rv = (constraints->instanceNamesAllowed | constraints->instanceAddressesAllowed);
266          constraints->instanceNamesAllowed = TRUE;
267          constraints->instanceAddressesAllowed = TRUE;
268          break;
269 
270       case EXTERNAL_ADDRESS:
271          rv = constraints->externalAddressesAllowed;
272          constraints->externalAddressesAllowed = TRUE;
273          break;
274 
275       case RVOID:
276          rv = constraints->voidAllowed;
277          constraints->voidAllowed = TRUE;
278          break;
279 
280       case FACT_ADDRESS:
281          rv = constraints->factAddressesAllowed;
282          constraints->factAddressesAllowed = TRUE;
283          break;
284 
285       case MULTIFIELD:
286          rv = constraints->multifieldsAllowed;
287          constraints->multifieldsAllowed = TRUE;
288          break;
289      }
290 
291    if (theType != UNKNOWN_VALUE) constraints->anyAllowed = FALSE;
292    return(rv);
293   }
294 
295 #endif /* (! RUN_TIME) && (! BLOAD_ONLY) */
296 
297 /*************************************************************/
298 /* CompareNumbers: Given two numbers (which can be integers, */
299 /*   floats, or the symbols for positive/negative infinity)  */
300 /*   returns the relationship between the numbers (greater   */
301 /*   than, less than or equal).                              */
302 /*************************************************************/
CompareNumbers(void * theEnv,int type1,void * vptr1,int type2,void * vptr2)303 globle int CompareNumbers(
304   void *theEnv,
305   int type1,
306   void *vptr1,
307   int type2,
308   void *vptr2)
309   {
310    /*============================================*/
311    /* Handle the situation in which the values   */
312    /* are exactly equal (same type, same value). */
313    /*============================================*/
314 
315    if (vptr1 == vptr2) return(EQUAL);
316 
317    /*=======================================*/
318    /* Handle the special cases for positive */
319    /* and negative infinity.                */
320    /*=======================================*/
321 
322    if (vptr1 == SymbolData(theEnv)->PositiveInfinity) return(GREATER_THAN);
323 
324    if (vptr1 == SymbolData(theEnv)->NegativeInfinity) return(LESS_THAN);
325 
326    if (vptr2 == SymbolData(theEnv)->PositiveInfinity) return(LESS_THAN);
327 
328    if (vptr2 == SymbolData(theEnv)->NegativeInfinity) return(GREATER_THAN);
329 
330    /*=======================*/
331    /* Compare two integers. */
332    /*=======================*/
333 
334    if ((type1 == INTEGER) && (type2 == INTEGER))
335      {
336       if (ValueToLong(vptr1) < ValueToLong(vptr2))
337         { return(LESS_THAN); }
338       else if (ValueToLong(vptr1) > ValueToLong(vptr2))
339         { return(GREATER_THAN); }
340 
341       return(EQUAL);
342      }
343 
344    /*=====================*/
345    /* Compare two floats. */
346    /*=====================*/
347 
348    if ((type1 == FLOAT) && (type2 == FLOAT))
349      {
350       if (ValueToDouble(vptr1) < ValueToDouble(vptr2))
351         { return(LESS_THAN); }
352       else if (ValueToDouble(vptr1) > ValueToDouble(vptr2))
353         { return(GREATER_THAN); }
354 
355       return(EQUAL);
356      }
357 
358    /*================================*/
359    /* Compare an integer to a float. */
360    /*================================*/
361 
362    if ((type1 == INTEGER) && (type2 == FLOAT))
363      {
364       if (((double) ValueToLong(vptr1)) < ValueToDouble(vptr2))
365         { return(LESS_THAN); }
366       else if (((double) ValueToLong(vptr1)) > ValueToDouble(vptr2))
367         { return(GREATER_THAN); }
368 
369       return(EQUAL);
370      }
371 
372    /*================================*/
373    /* Compare a float to an integer. */
374    /*================================*/
375 
376    if ((type1 == FLOAT) && (type2 == INTEGER))
377      {
378       if (ValueToDouble(vptr1) < ((double) ValueToLong(vptr2)))
379         { return(LESS_THAN); }
380       else if (ValueToDouble(vptr1) > ((double) ValueToLong(vptr2)))
381         { return(GREATER_THAN); }
382 
383       return(EQUAL);
384      }
385 
386    /*===================================*/
387    /* One of the arguments was invalid. */
388    /* Return -1 to indicate an error.   */
389    /*===================================*/
390 
391    return(-1);
392   }
393 
394 /****************************************************************/
395 /* ExpressionToConstraintRecord: Converts an expression into a  */
396 /*   constraint record. For example, an expression representing */
397 /*   the symbol BLUE would be converted to a  record with       */
398 /*   allowed types SYMBOL and allow-values BLUE.                */
399 /****************************************************************/
ExpressionToConstraintRecord(void * theEnv,struct expr * theExpression)400 globle CONSTRAINT_RECORD *ExpressionToConstraintRecord(
401   void *theEnv,
402   struct expr *theExpression)
403   {
404    CONSTRAINT_RECORD *rv;
405 
406    /*================================================*/
407    /* A NULL expression is converted to a constraint */
408    /* record with no values allowed.                 */
409    /*================================================*/
410 
411    if (theExpression == NULL)
412      {
413       rv = GetConstraintRecord(theEnv);
414       rv->anyAllowed = FALSE;
415       return(rv);
416      }
417 
418    /*=============================================================*/
419    /* Convert variables and function calls to constraint records. */
420    /*=============================================================*/
421 
422    if ((theExpression->type == SF_VARIABLE) ||
423        (theExpression->type == MF_VARIABLE) ||
424 #if DEFGENERIC_CONSTRUCT
425        (theExpression->type == GCALL) ||
426 #endif
427 #if DEFFUNCTION_CONSTRUCT
428        (theExpression->type == PCALL) ||
429 #endif
430        (theExpression->type == GBL_VARIABLE) ||
431        (theExpression->type == MF_GBL_VARIABLE))
432      {
433       rv = GetConstraintRecord(theEnv);
434       rv->multifieldsAllowed = TRUE;
435       return(rv);
436      }
437    else if (theExpression->type == FCALL)
438      { return(FunctionCallToConstraintRecord(theEnv,theExpression->value)); }
439 
440    /*============================================*/
441    /* Convert a constant to a constraint record. */
442    /*============================================*/
443 
444    rv = GetConstraintRecord(theEnv);
445    rv->anyAllowed = FALSE;
446 
447    if (theExpression->type == FLOAT)
448      {
449       rv->floatRestriction = TRUE;
450       rv->floatsAllowed = TRUE;
451      }
452    else if (theExpression->type == INTEGER)
453      {
454       rv->integerRestriction = TRUE;
455       rv->integersAllowed = TRUE;
456      }
457    else if (theExpression->type == SYMBOL)
458      {
459       rv->symbolRestriction = TRUE;
460       rv->symbolsAllowed = TRUE;
461      }
462    else if (theExpression->type == STRING)
463      {
464       rv->stringRestriction = TRUE;
465       rv->stringsAllowed = TRUE;
466      }
467    else if (theExpression->type == INSTANCE_NAME)
468      {
469       rv->instanceNameRestriction = TRUE;
470       rv->instanceNamesAllowed = TRUE;
471      }
472    else if (theExpression->type == INSTANCE_ADDRESS)
473      { rv->instanceAddressesAllowed = TRUE; }
474 
475    if (rv->floatsAllowed || rv->integersAllowed || rv->symbolsAllowed ||
476        rv->stringsAllowed || rv->instanceNamesAllowed)
477      { rv->restrictionList = GenConstant(theEnv,theExpression->type,theExpression->value); }
478 
479    return(rv);
480   }
481 
482 /*******************************************************/
483 /* FunctionCallToConstraintRecord: Converts a function */
484 /*   call to a constraint record. For example, the +   */
485 /*   function when converted would be a constraint     */
486 /*   record with allowed types INTEGER and FLOAT.      */
487 /*******************************************************/
FunctionCallToConstraintRecord(void * theEnv,void * theFunction)488 globle CONSTRAINT_RECORD *FunctionCallToConstraintRecord(
489   void *theEnv,
490   void *theFunction)
491   {
492    CONSTRAINT_RECORD *rv;
493 
494    rv = GetConstraintRecord(theEnv);
495    rv->anyAllowed = FALSE;
496 
497    switch ((char) ValueFunctionType(theFunction))
498      {
499       case 'a':
500         rv->externalAddressesAllowed = TRUE;
501         break;
502 
503       case 'f':
504       case 'd':
505         rv->floatsAllowed = TRUE;
506         break;
507 
508       case 'i':
509       case 'g':
510       case 'l':
511         rv->integersAllowed = TRUE;
512         break;
513 
514       case 'j':
515         rv->instanceNamesAllowed = TRUE;
516         rv->symbolsAllowed = TRUE;
517         rv->stringsAllowed = TRUE;
518         break;
519 
520       case 'k':
521         rv->symbolsAllowed = TRUE;
522         rv->stringsAllowed = TRUE;
523         break;
524 
525       case 'm':
526         rv->singlefieldsAllowed = FALSE;
527         rv->multifieldsAllowed = TRUE;
528         break;
529 
530       case 'n':
531         rv->floatsAllowed = TRUE;
532         rv->integersAllowed = TRUE;
533         break;
534 
535       case 'o':
536         rv->instanceNamesAllowed = TRUE;
537         break;
538 
539       case 's':
540         rv->stringsAllowed = TRUE;
541         break;
542 
543       case 'u':
544         rv->anyAllowed = TRUE;
545         rv->multifieldsAllowed = TRUE;
546         break;
547 
548       case 'w':
549       case 'c':
550       case 'b':
551         rv->symbolsAllowed = TRUE;
552         break;
553 
554       case 'x':
555         rv->instanceAddressesAllowed = TRUE;
556         break;
557 
558       case 'y':
559         rv->factAddressesAllowed = TRUE;
560         break;
561 
562       case 'v':
563         rv->voidAllowed = TRUE;
564         break;
565      }
566 
567    return(rv);
568   }
569 
570 /*******************************************************/
571 /* ArgumentTypeToConstraintRecord: Converts one of the */
572 /*   function argument types (used by DefineFunction2) */
573 /*   to a constraint record.                           */
574 /*******************************************************/
ArgumentTypeToConstraintRecord(void * theEnv,int theRestriction)575 globle CONSTRAINT_RECORD *ArgumentTypeToConstraintRecord(
576   void *theEnv,
577   int theRestriction)
578   {
579    CONSTRAINT_RECORD *rv;
580 
581    rv = GetConstraintRecord(theEnv);
582    rv->anyAllowed = FALSE;
583 
584    switch (theRestriction)
585      {
586       case 'a':
587         rv->externalAddressesAllowed = TRUE;
588         break;
589 
590       case 'e':
591         rv->symbolsAllowed = TRUE;
592         rv->instanceNamesAllowed = TRUE;
593         rv->instanceAddressesAllowed = TRUE;
594         break;
595 
596       case 'd':
597       case 'f':
598         rv->floatsAllowed = TRUE;
599         break;
600 
601       case 'g':
602         rv->integersAllowed = TRUE;
603         rv->floatsAllowed = TRUE;
604         rv->symbolsAllowed = TRUE;
605         break;
606 
607       case 'h':
608         rv->factAddressesAllowed = TRUE;
609         rv->integersAllowed = TRUE;
610         rv->symbolsAllowed = TRUE;
611         rv->instanceNamesAllowed = TRUE;
612         rv->instanceAddressesAllowed = TRUE;
613         break;
614 
615       case 'i':
616       case 'l':
617         rv->integersAllowed = TRUE;
618         break;
619 
620       case 'j':
621         rv->symbolsAllowed = TRUE;
622         rv->stringsAllowed = TRUE;
623         rv->instanceNamesAllowed = TRUE;
624         break;
625 
626       case 'k':
627         rv->symbolsAllowed = TRUE;
628         rv->stringsAllowed = TRUE;
629         break;
630 
631       case 'm':
632         rv->singlefieldsAllowed = FALSE;
633         rv->multifieldsAllowed = TRUE;
634         break;
635 
636       case 'n':
637         rv->floatsAllowed = TRUE;
638         rv->integersAllowed = TRUE;
639         break;
640 
641       case 'o':
642         rv->instanceNamesAllowed = TRUE;
643         break;
644 
645       case 'p':
646         rv->instanceNamesAllowed = TRUE;
647         rv->symbolsAllowed = TRUE;
648         break;
649 
650       case 'q':
651         rv->symbolsAllowed = TRUE;
652         rv->stringsAllowed = TRUE;
653         rv->multifieldsAllowed = TRUE;
654         break;
655 
656       case 's':
657         rv->stringsAllowed = TRUE;
658         break;
659 
660       case 'w':
661         rv->symbolsAllowed = TRUE;
662         break;
663 
664       case 'x':
665         rv->instanceAddressesAllowed = TRUE;
666         break;
667 
668       case 'y':
669         rv->factAddressesAllowed = TRUE;
670         break;
671 
672       case 'z':
673         rv->symbolsAllowed = TRUE;
674         rv->factAddressesAllowed = TRUE;
675         rv->integersAllowed = TRUE;
676         break;
677 
678       case 'u':
679         rv->anyAllowed = TRUE;
680         rv->multifieldsAllowed = TRUE;
681         break;
682 
683       case 'v':
684         rv->voidAllowed = TRUE;
685         break;
686      }
687 
688    return(rv);
689   }
690 
691 
692 
693 
694