1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  02/03/15            */
5    /*                                                     */
6    /*                    SYMBOL MODULE                    */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Manages the atomic data value hash tables for    */
11 /*   storing symbols, integers, floats, and bit maps.        */
12 /*   Contains routines for adding entries, examining the     */
13 /*   hash tables, and performing garbage collection to       */
14 /*   remove entries no longer in use.                        */
15 /*                                                           */
16 /* Principal Programmer(s):                                  */
17 /*      Gary D. Riley                                        */
18 /*                                                           */
19 /* Contributing Programmer(s):                               */
20 /*      Brian L. Dantes                                      */
21 /*                                                           */
22 /* Revision History:                                         */
23 /*                                                           */
24 /*      6.23: Correction for FalseSymbol/TrueSymbol. DR0859  */
25 /*                                                           */
26 /*      6.24: CLIPS crashing on AMD64 processor in the       */
27 /*            function used to generate a hash value for     */
28 /*            integers. DR0871                               */
29 /*                                                           */
30 /*            Support for run-time programs directly passing */
31 /*            the hash tables for initialization.            */
32 /*                                                           */
33 /*            Corrected code generating compilation          */
34 /*            warnings.                                      */
35 /*                                                           */
36 /*      6.30: Changed integer type/precision.                */
37 /*                                                           */
38 /*            Removed conditional code for unsupported       */
39 /*            compilers/operating systems (IBM_MCW,          */
40 /*            MAC_MCW, and IBM_TBC).                         */
41 /*                                                           */
42 /*            Support for hashing EXTERNAL_ADDRESS data      */
43 /*            type.                                          */
44 /*                                                           */
45 /*            Support for long long integers.                */
46 /*                                                           */
47 /*            Changed garbage collection algorithm.          */
48 /*                                                           */
49 /*            Used genstrcpy instead of strcpy.              */
50 /*                                                           */
51 /*            Added support for external address hash table  */
52 /*            and subtyping.                                 */
53 /*                                                           */
54 /*            Added const qualifiers to remove C++           */
55 /*            deprecation warnings.                          */
56 /*                                                           */
57 /*            Converted API macros to function calls.        */
58 /*                                                           */
59 /*************************************************************/
60 
61 #define _SYMBOL_SOURCE_
62 
63 #include <stdio.h>
64 #define _STDIO_INCLUDED_
65 #include <stdlib.h>
66 #include <string.h>
67 
68 #include "setup.h"
69 
70 #include "constant.h"
71 #include "envrnmnt.h"
72 #include "memalloc.h"
73 #include "router.h"
74 #include "utility.h"
75 #include "argacces.h"
76 #include "sysdep.h"
77 
78 #include "symbol.h"
79 
80 /***************/
81 /* DEFINITIONS */
82 /***************/
83 
84 #define FALSE_STRING "FALSE"
85 #define TRUE_STRING  "TRUE"
86 #define POSITIVE_INFINITY_STRING "+oo"
87 #define NEGATIVE_INFINITY_STRING "-oo"
88 
89 #define AVERAGE_STRING_SIZE 10
90 #define AVERAGE_BITMAP_SIZE sizeof(long)
91 #define NUMBER_OF_LONGS_FOR_HASH 25
92 
93 /***************************************/
94 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
95 /***************************************/
96 
97    static void                    RemoveHashNode(void *,GENERIC_HN *,GENERIC_HN **,int,int);
98    static void                    AddEphemeralHashNode(void *,GENERIC_HN *,struct ephemeron **,
99                                                        int,int,int);
100    static void                    RemoveEphemeralHashNodes(void *,struct ephemeron **,
101                                                            GENERIC_HN **,
102                                                            int,int,int);
103    static const char             *StringWithinString(const char *,const char *);
104    static size_t                  CommonPrefixLength(const char *,const char *);
105    static void                    DeallocateSymbolData(void *);
106 
107 /*******************************************************/
108 /* InitializeAtomTables: Initializes the SymbolTable,  */
109 /*   IntegerTable, and FloatTable. It also initializes */
110 /*   the TrueSymbol and FalseSymbol.                   */
111 /*******************************************************/
InitializeAtomTables(void * theEnv,struct symbolHashNode ** symbolTable,struct floatHashNode ** floatTable,struct integerHashNode ** integerTable,struct bitMapHashNode ** bitmapTable,struct externalAddressHashNode ** externalAddressTable)112 globle void InitializeAtomTables(
113   void *theEnv,
114   struct symbolHashNode **symbolTable,
115   struct floatHashNode **floatTable,
116   struct integerHashNode **integerTable,
117   struct bitMapHashNode **bitmapTable,
118   struct externalAddressHashNode **externalAddressTable)
119   {
120 #if MAC_XCD
121 #pragma unused(symbolTable)
122 #pragma unused(floatTable)
123 #pragma unused(integerTable)
124 #pragma unused(bitmapTable)
125 #pragma unused(externalAddressTable)
126 #endif
127    unsigned long i;
128 
129    AllocateEnvironmentData(theEnv,SYMBOL_DATA,sizeof(struct symbolData),DeallocateSymbolData);
130 
131 #if ! RUN_TIME
132    /*=========================*/
133    /* Create the hash tables. */
134    /*=========================*/
135 
136    SymbolData(theEnv)->SymbolTable = (SYMBOL_HN **)
137                   gm3(theEnv,sizeof (SYMBOL_HN *) * SYMBOL_HASH_SIZE);
138 
139    SymbolData(theEnv)->FloatTable = (FLOAT_HN **)
140                   gm2(theEnv,(int) sizeof (FLOAT_HN *) * FLOAT_HASH_SIZE);
141 
142    SymbolData(theEnv)->IntegerTable = (INTEGER_HN **)
143                    gm2(theEnv,(int) sizeof (INTEGER_HN *) * INTEGER_HASH_SIZE);
144 
145    SymbolData(theEnv)->BitMapTable = (BITMAP_HN **)
146                    gm2(theEnv,(int) sizeof (BITMAP_HN *) * BITMAP_HASH_SIZE);
147 
148    SymbolData(theEnv)->ExternalAddressTable = (EXTERNAL_ADDRESS_HN **)
149                    gm2(theEnv,(int) sizeof (EXTERNAL_ADDRESS_HN *) * EXTERNAL_ADDRESS_HASH_SIZE);
150 
151    /*===================================================*/
152    /* Initialize all of the hash table entries to NULL. */
153    /*===================================================*/
154 
155    for (i = 0; i < SYMBOL_HASH_SIZE; i++) SymbolData(theEnv)->SymbolTable[i] = NULL;
156    for (i = 0; i < FLOAT_HASH_SIZE; i++) SymbolData(theEnv)->FloatTable[i] = NULL;
157    for (i = 0; i < INTEGER_HASH_SIZE; i++) SymbolData(theEnv)->IntegerTable[i] = NULL;
158    for (i = 0; i < BITMAP_HASH_SIZE; i++) SymbolData(theEnv)->BitMapTable[i] = NULL;
159    for (i = 0; i < EXTERNAL_ADDRESS_HASH_SIZE; i++) SymbolData(theEnv)->ExternalAddressTable[i] = NULL;
160 
161    /*========================*/
162    /* Predefine some values. */
163    /*========================*/
164 
165    SymbolData(theEnv)->TrueSymbolHN = EnvAddSymbol(theEnv,TRUE_STRING);
166    IncrementSymbolCount(SymbolData(theEnv)->TrueSymbolHN);
167    SymbolData(theEnv)->FalseSymbolHN = EnvAddSymbol(theEnv,FALSE_STRING);
168    IncrementSymbolCount(SymbolData(theEnv)->FalseSymbolHN);
169    SymbolData(theEnv)->PositiveInfinity = EnvAddSymbol(theEnv,POSITIVE_INFINITY_STRING);
170    IncrementSymbolCount(SymbolData(theEnv)->PositiveInfinity);
171    SymbolData(theEnv)->NegativeInfinity = EnvAddSymbol(theEnv,NEGATIVE_INFINITY_STRING);
172    IncrementSymbolCount(SymbolData(theEnv)->NegativeInfinity);
173    SymbolData(theEnv)->Zero = EnvAddLong(theEnv,0LL);
174    IncrementIntegerCount(SymbolData(theEnv)->Zero);
175 #else
176    SetSymbolTable(theEnv,symbolTable);
177    SetFloatTable(theEnv,floatTable);
178    SetIntegerTable(theEnv,integerTable);
179    SetBitMapTable(theEnv,bitmapTable);
180 
181    SymbolData(theEnv)->ExternalAddressTable = (EXTERNAL_ADDRESS_HN **)
182                 gm2(theEnv,(int) sizeof (EXTERNAL_ADDRESS_HN *) * EXTERNAL_ADDRESS_HASH_SIZE);
183 
184    for (i = 0; i < EXTERNAL_ADDRESS_HASH_SIZE; i++) SymbolData(theEnv)->ExternalAddressTable[i] = NULL;
185 #endif
186   }
187 
188 /*************************************************/
189 /* DeallocateSymbolData: Deallocates environment */
190 /*    data for symbols.                          */
191 /*************************************************/
DeallocateSymbolData(void * theEnv)192 static void DeallocateSymbolData(
193   void *theEnv)
194   {
195    int i;
196    SYMBOL_HN *shPtr, *nextSHPtr;
197    INTEGER_HN *ihPtr, *nextIHPtr;
198    FLOAT_HN *fhPtr, *nextFHPtr;
199    BITMAP_HN *bmhPtr, *nextBMHPtr;
200    EXTERNAL_ADDRESS_HN *eahPtr, *nextEAHPtr;
201 
202    if ((SymbolData(theEnv)->SymbolTable == NULL) ||
203        (SymbolData(theEnv)->FloatTable == NULL) ||
204        (SymbolData(theEnv)->IntegerTable == NULL) ||
205        (SymbolData(theEnv)->BitMapTable == NULL) ||
206        (SymbolData(theEnv)->ExternalAddressTable == NULL))
207      { return; }
208 
209    for (i = 0; i < SYMBOL_HASH_SIZE; i++)
210      {
211       shPtr = SymbolData(theEnv)->SymbolTable[i];
212 
213       while (shPtr != NULL)
214         {
215          nextSHPtr = shPtr->next;
216          if (! shPtr->permanent)
217            {
218             rm(theEnv,(void *) shPtr->contents,strlen(shPtr->contents)+1);
219             rtn_struct(theEnv,symbolHashNode,shPtr);
220            }
221          shPtr = nextSHPtr;
222         }
223      }
224 
225    for (i = 0; i < FLOAT_HASH_SIZE; i++)
226      {
227       fhPtr = SymbolData(theEnv)->FloatTable[i];
228 
229       while (fhPtr != NULL)
230         {
231          nextFHPtr = fhPtr->next;
232          if (! fhPtr->permanent)
233            { rtn_struct(theEnv,floatHashNode,fhPtr); }
234          fhPtr = nextFHPtr;
235         }
236      }
237 
238    for (i = 0; i < INTEGER_HASH_SIZE; i++)
239      {
240       ihPtr = SymbolData(theEnv)->IntegerTable[i];
241 
242       while (ihPtr != NULL)
243         {
244          nextIHPtr = ihPtr->next;
245          if (! ihPtr->permanent)
246            { rtn_struct(theEnv,integerHashNode,ihPtr); }
247          ihPtr = nextIHPtr;
248         }
249      }
250 
251    for (i = 0; i < BITMAP_HASH_SIZE; i++)
252      {
253       bmhPtr = SymbolData(theEnv)->BitMapTable[i];
254 
255       while (bmhPtr != NULL)
256         {
257          nextBMHPtr = bmhPtr->next;
258          if (! bmhPtr->permanent)
259            {
260             rm(theEnv,(void *) bmhPtr->contents,bmhPtr->size);
261             rtn_struct(theEnv,bitMapHashNode,bmhPtr);
262            }
263          bmhPtr = nextBMHPtr;
264         }
265      }
266 
267    for (i = 0; i < EXTERNAL_ADDRESS_HASH_SIZE; i++)
268      {
269       eahPtr = SymbolData(theEnv)->ExternalAddressTable[i];
270 
271       while (eahPtr != NULL)
272         {
273          nextEAHPtr = eahPtr->next;
274          if (! eahPtr->permanent)
275            {
276             rtn_struct(theEnv,externalAddressHashNode,eahPtr);
277            }
278          eahPtr = nextEAHPtr;
279         }
280      }
281 
282    /*================================*/
283    /* Remove the symbol hash tables. */
284    /*================================*/
285 
286  #if ! RUN_TIME
287    rm3(theEnv,SymbolData(theEnv)->SymbolTable,sizeof (SYMBOL_HN *) * SYMBOL_HASH_SIZE);
288 
289    genfree(theEnv,SymbolData(theEnv)->FloatTable,(int) sizeof (FLOAT_HN *) * FLOAT_HASH_SIZE);
290 
291    genfree(theEnv,SymbolData(theEnv)->IntegerTable,(int) sizeof (INTEGER_HN *) * INTEGER_HASH_SIZE);
292 
293    genfree(theEnv,SymbolData(theEnv)->BitMapTable,(int) sizeof (BITMAP_HN *) * BITMAP_HASH_SIZE);
294 #endif
295 
296    genfree(theEnv,SymbolData(theEnv)->ExternalAddressTable,(int) sizeof (EXTERNAL_ADDRESS_HN *) * EXTERNAL_ADDRESS_HASH_SIZE);
297 
298    /*==============================*/
299    /* Remove binary symbol tables. */
300    /*==============================*/
301 
302 #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE || BLOAD_INSTANCES || BSAVE_INSTANCES
303    if (SymbolData(theEnv)->SymbolArray != NULL)
304      rm3(theEnv,(void *) SymbolData(theEnv)->SymbolArray,(long) sizeof(SYMBOL_HN *) * SymbolData(theEnv)->NumberOfSymbols);
305    if (SymbolData(theEnv)->FloatArray != NULL)
306      rm3(theEnv,(void *) SymbolData(theEnv)->FloatArray,(long) sizeof(FLOAT_HN *) * SymbolData(theEnv)->NumberOfFloats);
307    if (SymbolData(theEnv)->IntegerArray != NULL)
308      rm3(theEnv,(void *) SymbolData(theEnv)->IntegerArray,(long) sizeof(INTEGER_HN *) * SymbolData(theEnv)->NumberOfIntegers);
309    if (SymbolData(theEnv)->BitMapArray != NULL)
310      rm3(theEnv,(void *) SymbolData(theEnv)->BitMapArray,(long) sizeof(BITMAP_HN *) * SymbolData(theEnv)->NumberOfBitMaps);
311 #endif
312   }
313 
314 /*********************************************************************/
315 /* EnvAddSymbol: Searches for the string in the symbol table. If the */
316 /*   string is already in the symbol table, then the address of the  */
317 /*   string's location in the symbol table is returned. Otherwise,   */
318 /*   the string is added to the symbol table and then the address    */
319 /*   of the string's location in the symbol table is returned.       */
320 /*********************************************************************/
EnvAddSymbol(void * theEnv,const char * str)321 globle void *EnvAddSymbol(
322   void *theEnv,
323   const char *str)
324   {
325    unsigned long tally;
326    size_t length;
327    SYMBOL_HN *past = NULL, *peek;
328    char *buffer;
329 
330     /*====================================*/
331     /* Get the hash value for the string. */
332     /*====================================*/
333 
334     if (str == NULL)
335       {
336        SystemError(theEnv,"SYMBOL",1);
337        EnvExitRouter(theEnv,EXIT_FAILURE);
338       }
339 
340     tally = HashSymbol(str,SYMBOL_HASH_SIZE);
341     peek = SymbolData(theEnv)->SymbolTable[tally];
342 
343     /*==================================================*/
344     /* Search for the string in the list of entries for */
345     /* this symbol table location.  If the string is    */
346     /* found, then return the address of the string.    */
347     /*==================================================*/
348 
349     while (peek != NULL)
350       {
351        if (strcmp(str,peek->contents) == 0)
352          { return((void *) peek); }
353        past = peek;
354        peek = peek->next;
355       }
356 
357     /*==================================================*/
358     /* Add the string at the end of the list of entries */
359     /* for this symbol table location.                  */
360     /*==================================================*/
361 
362     peek = get_struct(theEnv,symbolHashNode);
363 
364     if (past == NULL) SymbolData(theEnv)->SymbolTable[tally] = peek;
365     else past->next = peek;
366 
367     length = strlen(str) + 1;
368     buffer = (char *) gm2(theEnv,length);
369     genstrcpy(buffer,str);
370     peek->contents = buffer;
371     peek->next = NULL;
372     peek->bucket = tally;
373     peek->count = 0;
374     peek->permanent = FALSE;
375 
376     /*================================================*/
377     /* Add the string to the list of ephemeral items. */
378     /*================================================*/
379 
380     AddEphemeralHashNode(theEnv,(GENERIC_HN *) peek,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralSymbolList,
381                          sizeof(SYMBOL_HN),AVERAGE_STRING_SIZE,TRUE);
382     UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
383 
384     /*===================================*/
385     /* Return the address of the symbol. */
386     /*===================================*/
387 
388     return((void *) peek);
389    }
390 
391 /*****************************************************************/
392 /* FindSymbolHN: Searches for the string in the symbol table and */
393 /*   returns a pointer to it if found, otherwise returns NULL.   */
394 /*****************************************************************/
FindSymbolHN(void * theEnv,const char * str)395 globle SYMBOL_HN *FindSymbolHN(
396   void *theEnv,
397   const char *str)
398   {
399    unsigned long tally;
400    SYMBOL_HN *peek;
401 
402     tally = HashSymbol(str,SYMBOL_HASH_SIZE);
403 
404     for (peek = SymbolData(theEnv)->SymbolTable[tally];
405          peek != NULL;
406          peek = peek->next)
407       {
408        if (strcmp(str,peek->contents) == 0)
409          { return(peek); }
410       }
411 
412     return(NULL);
413    }
414 
415 /*******************************************************************/
416 /* EnvAddDouble: Searches for the double in the hash table. If the */
417 /*   double is already in the hash table, then the address of the  */
418 /*   double is returned. Otherwise, the double is hashed into the  */
419 /*   table and the address of the double is also returned.         */
420 /*******************************************************************/
EnvAddDouble(void * theEnv,double number)421 globle void *EnvAddDouble(
422   void *theEnv,
423   double number)
424   {
425    unsigned long tally;
426    FLOAT_HN *past = NULL, *peek;
427 
428     /*====================================*/
429     /* Get the hash value for the double. */
430     /*====================================*/
431 
432     tally = HashFloat(number,FLOAT_HASH_SIZE);
433     peek = SymbolData(theEnv)->FloatTable[tally];
434 
435     /*==================================================*/
436     /* Search for the double in the list of entries for */
437     /* this hash location.  If the double is found,     */
438     /* then return the address of the double.           */
439     /*==================================================*/
440 
441     while (peek != NULL)
442       {
443        if (number == peek->contents)
444          { return((void *) peek); }
445        past = peek;
446        peek = peek->next;
447       }
448 
449     /*=================================================*/
450     /* Add the float at the end of the list of entries */
451     /* for this hash location.                         */
452     /*=================================================*/
453 
454     peek = get_struct(theEnv,floatHashNode);
455 
456     if (past == NULL) SymbolData(theEnv)->FloatTable[tally] = peek;
457     else past->next = peek;
458 
459     peek->contents = number;
460     peek->next = NULL;
461     peek->bucket = tally;
462     peek->count = 0;
463     peek->permanent = FALSE;
464 
465     /*===============================================*/
466     /* Add the float to the list of ephemeral items. */
467     /*===============================================*/
468 
469     AddEphemeralHashNode(theEnv,(GENERIC_HN *) peek,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralFloatList,
470                          sizeof(FLOAT_HN),0,TRUE);
471     UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
472 
473     /*==================================*/
474     /* Return the address of the float. */
475     /*==================================*/
476 
477     return((void *) peek);
478    }
479 
480 /***************************************************************/
481 /* EnvAddLong: Searches for the long in the hash table. If the */
482 /*   long is already in the hash table, then the address of    */
483 /*   the long is returned. Otherwise, the long is hashed into  */
484 /*   the table and the address of the long is also returned.   */
485 /***************************************************************/
EnvAddLong(void * theEnv,long long number)486 globle void *EnvAddLong(
487   void *theEnv,
488   long long number)
489   {
490    unsigned long tally;
491    INTEGER_HN *past = NULL, *peek;
492 
493     /*==================================*/
494     /* Get the hash value for the long. */
495     /*==================================*/
496 
497     tally = HashInteger(number,INTEGER_HASH_SIZE);
498     peek = SymbolData(theEnv)->IntegerTable[tally];
499 
500     /*================================================*/
501     /* Search for the long in the list of entries for */
502     /* this hash location. If the long is found, then */
503     /* return the address of the long.                */
504     /*================================================*/
505 
506     while (peek != NULL)
507       {
508        if (number == peek->contents)
509          { return((void *) peek); }
510        past = peek;
511        peek = peek->next;
512       }
513 
514     /*================================================*/
515     /* Add the long at the end of the list of entries */
516     /* for this hash location.                        */
517     /*================================================*/
518 
519     peek = get_struct(theEnv,integerHashNode);
520     if (past == NULL) SymbolData(theEnv)->IntegerTable[tally] = peek;
521     else past->next = peek;
522 
523     peek->contents = number;
524     peek->next = NULL;
525     peek->bucket = tally;
526     peek->count = 0;
527     peek->permanent = FALSE;
528 
529     /*=================================================*/
530     /* Add the integer to the list of ephemeral items. */
531     /*=================================================*/
532 
533     AddEphemeralHashNode(theEnv,(GENERIC_HN *) peek,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralIntegerList,
534                          sizeof(INTEGER_HN),0,TRUE);
535     UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
536 
537     /*====================================*/
538     /* Return the address of the integer. */
539     /*====================================*/
540 
541     return((void *) peek);
542    }
543 
544 /*****************************************************************/
545 /* FindLongHN: Searches for the integer in the integer table and */
546 /*   returns a pointer to it if found, otherwise returns NULL.   */
547 /*****************************************************************/
FindLongHN(void * theEnv,long long theLong)548 globle INTEGER_HN *FindLongHN(
549   void *theEnv,
550   long long theLong)
551   {
552    unsigned long tally;
553    INTEGER_HN *peek;
554 
555    tally = HashInteger(theLong,INTEGER_HASH_SIZE);
556 
557    for (peek = SymbolData(theEnv)->IntegerTable[tally];
558         peek != NULL;
559         peek = peek->next)
560      { if (peek->contents == theLong) return(peek); }
561 
562    return(NULL);
563   }
564 
565 /*******************************************************************/
566 /* EnvAddBitMap: Searches for the bitmap in the hash table. If the */
567 /*   bitmap is already in the hash table, then the address of the  */
568 /*   bitmap is returned. Otherwise, the bitmap is hashed into the  */
569 /*   table and the address of the bitmap is also returned.         */
570 /*******************************************************************/
EnvAddBitMap(void * theEnv,void * vTheBitMap,unsigned size)571 globle void *EnvAddBitMap(
572   void *theEnv,
573   void *vTheBitMap,
574   unsigned size)
575   {
576    char *theBitMap = (char *) vTheBitMap;
577    unsigned long tally;
578    unsigned i;
579    BITMAP_HN *past = NULL, *peek;
580    char *buffer;
581 
582     /*====================================*/
583     /* Get the hash value for the bitmap. */
584     /*====================================*/
585 
586     if (theBitMap == NULL)
587       {
588        SystemError(theEnv,"SYMBOL",2);
589        EnvExitRouter(theEnv,EXIT_FAILURE);
590       }
591 
592     tally = HashBitMap(theBitMap,BITMAP_HASH_SIZE,size);
593     peek = SymbolData(theEnv)->BitMapTable[tally];
594 
595     /*==================================================*/
596     /* Search for the bitmap in the list of entries for */
597     /* this hash table location.  If the bitmap is      */
598     /* found, then return the address of the bitmap.    */
599     /*==================================================*/
600 
601     while (peek != NULL)
602       {
603 	   if (peek->size == (unsigned short) size)
604          {
605           for (i = 0; i < size ; i++)
606             { if (peek->contents[i] != theBitMap[i]) break; }
607 
608           if (i == size) return((void *) peek);
609          }
610 
611        past = peek;
612        peek = peek->next;
613       }
614 
615     /*==================================================*/
616     /* Add the bitmap at the end of the list of entries */
617     /* for this hash table location.  Return the        */
618     /*==================================================*/
619 
620     peek = get_struct(theEnv,bitMapHashNode);
621     if (past == NULL) SymbolData(theEnv)->BitMapTable[tally] = peek;
622     else past->next = peek;
623 
624     buffer = (char *) gm2(theEnv,size);
625     for (i = 0; i < size ; i++) buffer[i] = theBitMap[i];
626     peek->contents = buffer;
627     peek->next = NULL;
628     peek->bucket = tally;
629     peek->count = 0;
630     peek->permanent = FALSE;
631     peek->size = (unsigned short) size;
632 
633     /*================================================*/
634     /* Add the bitmap to the list of ephemeral items. */
635     /*================================================*/
636 
637     AddEphemeralHashNode(theEnv,(GENERIC_HN *) peek,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralBitMapList,
638                          sizeof(BITMAP_HN),sizeof(long),TRUE);
639     UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
640 
641     /*===================================*/
642     /* Return the address of the bitmap. */
643     /*===================================*/
644 
645     return((void *) peek);
646    }
647 
648 /*******************************************************************/
649 /* EnvAddExternalAddress: Searches for the external address in the */
650 /*   hash table. If the external address is already in the hash    */
651 /*   table, then the address of the external address is returned.  */
652 /*   Otherwise, the external address is hashed into the table and  */
653 /*   the address of the external address is also returned.         */
654 /*******************************************************************/
EnvAddExternalAddress(void * theEnv,void * theExternalAddress,unsigned theType)655 globle void *EnvAddExternalAddress(
656   void *theEnv,
657   void *theExternalAddress,
658   unsigned theType)
659   {
660    unsigned long tally;
661    EXTERNAL_ADDRESS_HN *past = NULL, *peek;
662 
663     /*====================================*/
664     /* Get the hash value for the bitmap. */
665     /*====================================*/
666 
667     tally = HashExternalAddress(theExternalAddress,EXTERNAL_ADDRESS_HASH_SIZE);
668 
669     peek = SymbolData(theEnv)->ExternalAddressTable[tally];
670 
671     /*=============================================================*/
672     /* Search for the external address in the list of entries for  */
673     /* this hash table location.  If the external addressis found, */
674     /* then return the address of the external address.            */
675     /*=============================================================*/
676 
677     while (peek != NULL)
678       {
679        if ((peek->type == (unsigned short) theType) &&
680            (peek->externalAddress == theExternalAddress))
681          { return((void *) peek); }
682 
683        past = peek;
684        peek = peek->next;
685       }
686 
687     /*=================================================*/
688     /* Add the external address at the end of the list */
689     /* of entries for this hash table location.        */
690     /*=================================================*/
691 
692     peek = get_struct(theEnv,externalAddressHashNode);
693     if (past == NULL) SymbolData(theEnv)->ExternalAddressTable[tally] = peek;
694     else past->next = peek;
695 
696     peek->externalAddress = theExternalAddress;
697     peek->type = (unsigned short) theType;
698     peek->next = NULL;
699     peek->bucket = tally;
700     peek->count = 0;
701     peek->permanent = FALSE;
702 
703     /*================================================*/
704     /* Add the bitmap to the list of ephemeral items. */
705     /*================================================*/
706 
707     AddEphemeralHashNode(theEnv,(GENERIC_HN *) peek,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralExternalAddressList,
708                          sizeof(EXTERNAL_ADDRESS_HN),sizeof(long),TRUE);
709     UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
710 
711     /*=============================================*/
712     /* Return the address of the external address. */
713     /*=============================================*/
714 
715     return((void *) peek);
716    }
717 
718 /***************************************************/
719 /* HashSymbol: Computes a hash value for a symbol. */
720 /***************************************************/
HashSymbol(const char * word,unsigned long range)721 globle unsigned long HashSymbol(
722   const char *word,
723   unsigned long range)
724   {
725    register int i;
726    unsigned long tally = 0;
727 
728    for (i = 0; word[i]; i++)
729      { tally = tally * 127 + word[i]; }
730 
731    if (range == 0)
732      { return tally; }
733 
734    return(tally % range);
735   }
736 
737 /*************************************************/
738 /* HashFloat: Computes a hash value for a float. */
739 /*************************************************/
HashFloat(double number,unsigned long range)740 globle unsigned long HashFloat(
741   double number,
742   unsigned long range)
743   {
744    unsigned long tally = 0;
745    char *word;
746    unsigned i;
747 
748    word = (char *) &number;
749 
750    for (i = 0; i < sizeof(double); i++)
751      { tally = tally * 127 + word[i]; }
752 
753    if (range == 0)
754      { return tally; }
755 
756    return(tally % range);
757   }
758 
759 /******************************************************/
760 /* HashInteger: Computes a hash value for an integer. */
761 /******************************************************/
HashInteger(long long number,unsigned long range)762 globle unsigned long HashInteger(
763   long long number,
764   unsigned long range)
765   {
766    unsigned long tally;
767 
768 #if WIN_MVC
769    if (number < 0)
770      { number = - number; }
771    tally = (((unsigned) number) % range);
772 #else
773    tally = (((unsigned) llabs(number)) % range);
774 #endif
775 
776    if (range == 0)
777      { return tally; }
778 
779    return(tally);
780   }
781 
782 /****************************************/
783 /* HashExternalAddress: Computes a hash */
784 /*   value for an external address.     */
785 /****************************************/
HashExternalAddress(void * theExternalAddress,unsigned long range)786 globle unsigned long HashExternalAddress(
787   void *theExternalAddress,
788   unsigned long range)
789   {
790    unsigned long tally;
791    union
792      {
793       void *vv;
794       unsigned uv;
795      } fis;
796 
797    fis.uv = 0;
798    fis.vv = theExternalAddress;
799    tally = (fis.uv / 256);
800 
801    if (range == 0)
802      { return tally; }
803 
804    return(tally % range);
805   }
806 
807 /***************************************************/
808 /* HashBitMap: Computes a hash value for a bitmap. */
809 /***************************************************/
HashBitMap(const char * word,unsigned long range,unsigned length)810 globle unsigned long HashBitMap(
811   const char *word,
812   unsigned long range,
813   unsigned length)
814   {
815    register unsigned k,j,i;
816    unsigned long tally;
817    unsigned longLength;
818    unsigned long count = 0L,tmpLong;
819    char *tmpPtr;
820 
821    tmpPtr = (char *) &tmpLong;
822 
823    /*================================================================ */
824    /* Add up the first part of the word as unsigned long int values.  */
825    /*================================================================ */
826 
827    longLength = length / sizeof(unsigned long);
828    for (i = 0 , j = 0 ; i < longLength; i++)
829      {
830       for (k = 0 ; k < sizeof(unsigned long) ; k++ , j++)
831         tmpPtr[k] = word[j];
832       count += tmpLong;
833      }
834 
835    /*============================================*/
836    /* Add the remaining characters to the count. */
837    /*============================================*/
838 
839    for (; j < length; j++) count += (unsigned long) word[j];
840 
841    /*========================*/
842    /* Return the hash value. */
843    /*========================*/
844 
845    if (range == 0)
846      { return count; }
847 
848    tally = (count % range);
849 
850    return(tally);
851   }
852 
853 /*****************************************************/
854 /* DecrementSymbolCount: Decrements the count value  */
855 /*   for a SymbolTable entry. Adds the symbol to the */
856 /*   EphemeralSymbolList if the count becomes zero.  */
857 /*****************************************************/
DecrementSymbolCount(void * theEnv,SYMBOL_HN * theValue)858 globle void DecrementSymbolCount(
859   void *theEnv,
860   SYMBOL_HN *theValue)
861   {
862    if (theValue->count < 0)
863      {
864       SystemError(theEnv,"SYMBOL",3);
865       EnvExitRouter(theEnv,EXIT_FAILURE);
866      }
867 
868    if (theValue->count == 0)
869      {
870       SystemError(theEnv,"SYMBOL",4);
871       EnvExitRouter(theEnv,EXIT_FAILURE);
872      }
873 
874    theValue->count--;
875 
876    if (theValue->count != 0) return;
877 
878    if (theValue->markedEphemeral == FALSE)
879      {
880       AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralSymbolList,
881                            sizeof(SYMBOL_HN),AVERAGE_STRING_SIZE,TRUE);
882       UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
883      }
884 
885    return;
886   }
887 
888 /***************************************************/
889 /* DecrementFloatCount: Decrements the count value */
890 /*   for a FloatTable entry. Adds the float to the */
891 /*   EphemeralFloatList if the count becomes zero. */
892 /***************************************************/
DecrementFloatCount(void * theEnv,FLOAT_HN * theValue)893 globle void DecrementFloatCount(
894   void *theEnv,
895   FLOAT_HN *theValue)
896   {
897    if (theValue->count <= 0)
898      {
899       SystemError(theEnv,"SYMBOL",5);
900       EnvExitRouter(theEnv,EXIT_FAILURE);
901      }
902 
903    theValue->count--;
904 
905    if (theValue->count != 0) return;
906 
907    if (theValue->markedEphemeral == FALSE)
908      {
909       AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralFloatList,
910                            sizeof(FLOAT_HN),0,TRUE);
911       UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
912      }
913 
914    return;
915   }
916 
917 /*********************************************************/
918 /* DecrementIntegerCount: Decrements the count value for */
919 /*   an IntegerTable entry. Adds the integer to the      */
920 /*   EphemeralIntegerList if the count becomes zero.     */
921 /*********************************************************/
DecrementIntegerCount(void * theEnv,INTEGER_HN * theValue)922 globle void DecrementIntegerCount(
923   void *theEnv,
924   INTEGER_HN *theValue)
925   {
926    if (theValue->count <= 0)
927      {
928       SystemError(theEnv,"SYMBOL",6);
929       EnvExitRouter(theEnv,EXIT_FAILURE);
930      }
931 
932    theValue->count--;
933 
934    if (theValue->count != 0) return;
935 
936    if (theValue->markedEphemeral == FALSE)
937      {
938       AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralIntegerList,
939                            sizeof(INTEGER_HN),0,TRUE);
940       UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
941      }
942 
943    return;
944   }
945 
946 /*****************************************************/
947 /* DecrementBitMapCount: Decrements the count value  */
948 /*   for a BitmapTable entry. Adds the bitmap to the */
949 /*   EphemeralBitMapList if the count becomes zero.  */
950 /*****************************************************/
DecrementBitMapCount(void * theEnv,BITMAP_HN * theValue)951 globle void DecrementBitMapCount(
952   void *theEnv,
953   BITMAP_HN *theValue)
954   {
955    if (theValue->count < 0)
956      {
957       SystemError(theEnv,"SYMBOL",7);
958       EnvExitRouter(theEnv,EXIT_FAILURE);
959      }
960 
961    if (theValue->count == 0)
962      {
963       SystemError(theEnv,"SYMBOL",8);
964       EnvExitRouter(theEnv,EXIT_FAILURE);
965      }
966 
967    theValue->count--;
968 
969    if (theValue->count != 0) return;
970 
971    if (theValue->markedEphemeral == FALSE)
972      {
973       AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralBitMapList,
974                            sizeof(BITMAP_HN),sizeof(long),TRUE);
975       UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
976      }
977 
978    return;
979   }
980 
981 /*************************************************************/
982 /* DecrementExternalAddressCount: Decrements the count value */
983 /*   for an ExternAddressTable entry. Adds the bitmap to the */
984 /*   EphemeralExternalAddressList if the count becomes zero. */
985 /*************************************************************/
DecrementExternalAddressCount(void * theEnv,EXTERNAL_ADDRESS_HN * theValue)986 globle void DecrementExternalAddressCount(
987   void *theEnv,
988   EXTERNAL_ADDRESS_HN *theValue)
989   {
990    if (theValue->count < 0)
991      {
992       SystemError(theEnv,"SYMBOL",9);
993       EnvExitRouter(theEnv,EXIT_FAILURE);
994      }
995 
996    if (theValue->count == 0)
997      {
998       SystemError(theEnv,"SYMBOL",10);
999       EnvExitRouter(theEnv,EXIT_FAILURE);
1000      }
1001 
1002    theValue->count--;
1003 
1004    if (theValue->count != 0) return;
1005 
1006    if (theValue->markedEphemeral == FALSE)
1007      {
1008       AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,&UtilityData(theEnv)->CurrentGarbageFrame->ephemeralExternalAddressList,
1009                            sizeof(EXTERNAL_ADDRESS_HN),sizeof(long),TRUE);
1010       UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
1011      }
1012 
1013    return;
1014   }
1015 
1016 /************************************************/
1017 /* RemoveHashNode: Removes a hash node from the */
1018 /*   SymbolTable, FloatTable, IntegerTable,     */
1019 /*   BitMapTable, or ExternalAddressTable.      */
1020 /************************************************/
RemoveHashNode(void * theEnv,GENERIC_HN * theValue,GENERIC_HN ** theTable,int size,int type)1021 static void RemoveHashNode(
1022   void *theEnv,
1023   GENERIC_HN *theValue,
1024   GENERIC_HN **theTable,
1025   int size,
1026   int type)
1027   {
1028    GENERIC_HN *previousNode, *currentNode;
1029    struct externalAddressHashNode *theAddress;
1030 
1031    /*=============================================*/
1032    /* Find the entry in the specified hash table. */
1033    /*=============================================*/
1034 
1035    previousNode = NULL;
1036    currentNode = theTable[theValue->bucket];
1037 
1038    while (currentNode != theValue)
1039      {
1040       previousNode = currentNode;
1041       currentNode = currentNode->next;
1042 
1043       if (currentNode == NULL)
1044         {
1045          SystemError(theEnv,"SYMBOL",11);
1046          EnvExitRouter(theEnv,EXIT_FAILURE);
1047         }
1048      }
1049 
1050    /*===========================================*/
1051    /* Remove the entry from the list of entries */
1052    /* stored in the hash table bucket.          */
1053    /*===========================================*/
1054 
1055    if (previousNode == NULL)
1056      { theTable[theValue->bucket] = theValue->next; }
1057    else
1058      { previousNode->next = currentNode->next; }
1059 
1060    /*=================================================*/
1061    /* Symbol and bit map nodes have additional memory */
1062    /* use to store the character or bitmap string.    */
1063    /*=================================================*/
1064 
1065    if (type == SYMBOL)
1066      {
1067       rm(theEnv,(void *) ((SYMBOL_HN *) theValue)->contents,
1068          strlen(((SYMBOL_HN *) theValue)->contents) + 1);
1069      }
1070    else if (type == BITMAPARRAY)
1071      {
1072       rm(theEnv,(void *) ((BITMAP_HN *) theValue)->contents,
1073          ((BITMAP_HN *) theValue)->size);
1074      }
1075    else if (type == EXTERNAL_ADDRESS)
1076      {
1077       theAddress = (struct externalAddressHashNode *) theValue;
1078 
1079       if ((EvaluationData(theEnv)->ExternalAddressTypes[theAddress->type] != NULL) &&
1080           (EvaluationData(theEnv)->ExternalAddressTypes[theAddress->type]->discardFunction != NULL))
1081         { (*EvaluationData(theEnv)->ExternalAddressTypes[theAddress->type]->discardFunction)(theEnv,theAddress->externalAddress); }
1082      }
1083 
1084    /*===========================*/
1085    /* Return the table entry to */
1086    /* the pool of free memory.  */
1087    /*===========================*/
1088 
1089    rtn_sized_struct(theEnv,size,theValue);
1090   }
1091 
1092 /***********************************************************/
1093 /* AddEphemeralHashNode: Adds a symbol, integer, float, or */
1094 /*   bit map table entry to the list of ephemeral atomic   */
1095 /*   values. These entries have a zero count indicating    */
1096 /*   that no structure is using the data value.            */
1097 /***********************************************************/
AddEphemeralHashNode(void * theEnv,GENERIC_HN * theHashNode,struct ephemeron ** theEphemeralList,int hashNodeSize,int averageContentsSize,int checkCount)1098 static void AddEphemeralHashNode(
1099   void *theEnv,
1100   GENERIC_HN *theHashNode,
1101   struct ephemeron **theEphemeralList,
1102   int hashNodeSize,
1103   int averageContentsSize,
1104   int checkCount)
1105   {
1106    struct ephemeron *temp;
1107 
1108    /*===========================================*/
1109    /* If the count isn't zero then this routine */
1110    /* should never have been called.            */
1111    /*===========================================*/
1112 
1113    if (checkCount && (theHashNode->count != 0))
1114      {
1115       SystemError(theEnv,"SYMBOL",12);
1116       EnvExitRouter(theEnv,EXIT_FAILURE);
1117      }
1118 
1119    /*=====================================*/
1120    /* Mark the atomic value as ephemeral. */
1121    /*=====================================*/
1122 
1123    theHashNode->markedEphemeral = TRUE;
1124 
1125    /*=============================*/
1126    /* Add the atomic value to the */
1127    /* list of ephemeral values.   */
1128    /*=============================*/
1129 
1130    temp = get_struct(theEnv,ephemeron);
1131    temp->associatedValue = theHashNode;
1132    temp->next = *theEphemeralList;
1133    *theEphemeralList = temp;
1134   }
1135 
1136 /***************************************************/
1137 /* RemoveEphemeralAtoms: Causes the removal of all */
1138 /*   ephemeral symbols, integers, floats, and bit  */
1139 /*   maps that still have a count value of zero,   */
1140 /*   from their respective storage tables.         */
1141 /***************************************************/
RemoveEphemeralAtoms(void * theEnv)1142 globle void RemoveEphemeralAtoms(
1143   void *theEnv)
1144   {
1145    struct garbageFrame *theGarbageFrame;
1146 
1147    theGarbageFrame = UtilityData(theEnv)->CurrentGarbageFrame;
1148    if (! theGarbageFrame->dirty) return;
1149 
1150    RemoveEphemeralHashNodes(theEnv,&theGarbageFrame->ephemeralSymbolList,(GENERIC_HN **) SymbolData(theEnv)->SymbolTable,
1151                             sizeof(SYMBOL_HN),SYMBOL,AVERAGE_STRING_SIZE);
1152    RemoveEphemeralHashNodes(theEnv,&theGarbageFrame->ephemeralFloatList,(GENERIC_HN **) SymbolData(theEnv)->FloatTable,
1153                             sizeof(FLOAT_HN),FLOAT,0);
1154    RemoveEphemeralHashNodes(theEnv,&theGarbageFrame->ephemeralIntegerList,(GENERIC_HN **) SymbolData(theEnv)->IntegerTable,
1155                             sizeof(INTEGER_HN),INTEGER,0);
1156    RemoveEphemeralHashNodes(theEnv,&theGarbageFrame->ephemeralBitMapList,(GENERIC_HN **) SymbolData(theEnv)->BitMapTable,
1157                             sizeof(BITMAP_HN),BITMAPARRAY,AVERAGE_BITMAP_SIZE);
1158    RemoveEphemeralHashNodes(theEnv,&theGarbageFrame->ephemeralExternalAddressList,(GENERIC_HN **) SymbolData(theEnv)->ExternalAddressTable,
1159                             sizeof(EXTERNAL_ADDRESS_HN),EXTERNAL_ADDRESS,0);
1160   }
1161 
1162 /**********************************************************/
1163 /* EphemerateMultifield: Marks the values of a multifield */
1164 /*   as ephemeral if they have not already been marker.   */
1165 /**********************************************************/
EphemerateMultifield(void * theEnv,struct multifield * theSegment)1166 globle void EphemerateMultifield(
1167   void *theEnv,
1168   struct multifield *theSegment)
1169   {
1170    unsigned long length, i;
1171    struct field *theFields;
1172 
1173    if (theSegment == NULL) return;
1174 
1175    length = theSegment->multifieldLength;
1176 
1177    theFields = theSegment->theFields;
1178 
1179    for (i = 0 ; i < length ; i++)
1180      { EphemerateValue(theEnv,theFields[i].type,theFields[i].value); }
1181   }
1182 
1183 /***********************************************/
1184 /* EphemerateValue: Marks a value as ephemeral */
1185 /*   if it is not already marked.              */
1186 /***********************************************/
EphemerateValue(void * theEnv,int theType,void * theValue)1187 globle void EphemerateValue(
1188    void *theEnv,
1189    int theType,
1190    void *theValue)
1191    {
1192     SYMBOL_HN *theSymbol;
1193     FLOAT_HN *theFloat;
1194     INTEGER_HN *theInteger;
1195     EXTERNAL_ADDRESS_HN *theExternalAddress;
1196 
1197     switch (theType)
1198       {
1199       case SYMBOL:
1200       case STRING:
1201 #if OBJECT_SYSTEM
1202       case INSTANCE_NAME:
1203 #endif
1204         theSymbol = (SYMBOL_HN *) theValue;
1205         if (theSymbol->markedEphemeral) return;
1206         AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,
1207                              &UtilityData(theEnv)->CurrentGarbageFrame->ephemeralSymbolList,
1208                              sizeof(SYMBOL_HN),AVERAGE_STRING_SIZE,FALSE);
1209         UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
1210         break;
1211 
1212       case FLOAT:
1213         theFloat = (FLOAT_HN *) theValue;
1214         if (theFloat->markedEphemeral) return;
1215         AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,
1216                              &UtilityData(theEnv)->CurrentGarbageFrame->ephemeralFloatList,
1217                              sizeof(FLOAT_HN),0,FALSE);
1218         UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
1219         break;
1220 
1221       case INTEGER:
1222         theInteger = (INTEGER_HN *) theValue;
1223         if (theInteger->markedEphemeral) return;
1224         AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,
1225                              &UtilityData(theEnv)->CurrentGarbageFrame->ephemeralIntegerList,
1226                              sizeof(INTEGER_HN),0,FALSE);
1227         UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
1228         break;
1229 
1230       case EXTERNAL_ADDRESS:
1231         theExternalAddress = (EXTERNAL_ADDRESS_HN *) theValue;
1232         if (theExternalAddress->markedEphemeral) return;
1233         AddEphemeralHashNode(theEnv,(GENERIC_HN *) theValue,
1234                              &UtilityData(theEnv)->CurrentGarbageFrame->ephemeralExternalAddressList,
1235                              sizeof(EXTERNAL_ADDRESS_HN),sizeof(long),FALSE);
1236         UtilityData(theEnv)->CurrentGarbageFrame->dirty = TRUE;
1237         break;
1238 
1239       case MULTIFIELD:
1240         EphemerateMultifield(theEnv,(struct multifield *) theValue);
1241         break;
1242 
1243       }
1244    }
1245 
1246 /****************************************************************/
1247 /* RemoveEphemeralHashNodes: Removes symbols from the ephemeral */
1248 /*   symbol list that have a count of zero and were placed on   */
1249 /*   the list at a higher level than the current evaluation     */
1250 /*   depth. Since symbols are ordered in the list in descending */
1251 /*   order, the removal process can end when a depth is reached */
1252 /*   less than the current evaluation depth. Because ephemeral  */
1253 /*   symbols can be "pulled" up through an evaluation depth,    */
1254 /*   this routine needs to check through both the previous and  */
1255 /*   current evaluation depth.                                  */
1256 /****************************************************************/
RemoveEphemeralHashNodes(void * theEnv,struct ephemeron ** theEphemeralList,GENERIC_HN ** theTable,int hashNodeSize,int hashNodeType,int averageContentsSize)1257 static void RemoveEphemeralHashNodes(
1258   void *theEnv,
1259   struct ephemeron **theEphemeralList,
1260   GENERIC_HN **theTable,
1261   int hashNodeSize,
1262   int hashNodeType,
1263   int averageContentsSize)
1264   {
1265    struct ephemeron *edPtr, *lastPtr = NULL, *nextPtr;
1266 
1267    edPtr = *theEphemeralList;
1268 
1269    while (edPtr != NULL)
1270      {
1271       /*======================================================*/
1272       /* Check through previous and current evaluation depth  */
1273       /* because these symbols can be interspersed, otherwise */
1274       /* symbols are stored in descending evaluation depth.   */
1275       /*======================================================*/
1276 
1277       nextPtr = edPtr->next;
1278 
1279       /*==================================================*/
1280       /* Remove any symbols that have a count of zero and */
1281       /* were added to the ephemeral list at a higher     */
1282       /* evaluation depth.                                */
1283       /*==================================================*/
1284 
1285       if (edPtr->associatedValue->count == 0)
1286         {
1287          RemoveHashNode(theEnv,edPtr->associatedValue,theTable,hashNodeSize,hashNodeType);
1288          rtn_struct(theEnv,ephemeron,edPtr);
1289          if (lastPtr == NULL) *theEphemeralList = nextPtr;
1290          else lastPtr->next = nextPtr;
1291         }
1292 
1293       /*=======================================*/
1294       /* Remove ephemeral status of any symbol */
1295       /* with a count greater than zero.       */
1296       /*=======================================*/
1297 
1298       else if (edPtr->associatedValue->count > 0)
1299         {
1300          edPtr->associatedValue->markedEphemeral = FALSE;
1301 
1302          rtn_struct(theEnv,ephemeron,edPtr);
1303 
1304          if (lastPtr == NULL) *theEphemeralList = nextPtr;
1305          else lastPtr->next = nextPtr;
1306         }
1307 
1308       /*==================================================*/
1309       /* Otherwise keep the symbol in the ephemeral list. */
1310       /*==================================================*/
1311 
1312       else
1313         { lastPtr = edPtr; }
1314 
1315       edPtr = nextPtr;
1316      }
1317   }
1318 
1319 /*********************************************************/
1320 /* GetSymbolTable: Returns a pointer to the SymbolTable. */
1321 /*********************************************************/
GetSymbolTable(void * theEnv)1322 globle SYMBOL_HN **GetSymbolTable(
1323   void *theEnv)
1324   {
1325    return(SymbolData(theEnv)->SymbolTable);
1326   }
1327 
1328 /******************************************************/
1329 /* SetSymbolTable: Sets the value of the SymbolTable. */
1330 /******************************************************/
SetSymbolTable(void * theEnv,SYMBOL_HN ** value)1331 globle void SetSymbolTable(
1332   void *theEnv,
1333   SYMBOL_HN **value)
1334   {
1335    SymbolData(theEnv)->SymbolTable = value;
1336   }
1337 
1338 /*******************************************************/
1339 /* GetFloatTable: Returns a pointer to the FloatTable. */
1340 /*******************************************************/
GetFloatTable(void * theEnv)1341 globle FLOAT_HN **GetFloatTable(
1342   void *theEnv)
1343   {
1344    return(SymbolData(theEnv)->FloatTable);
1345   }
1346 
1347 /****************************************************/
1348 /* SetFloatTable: Sets the value of the FloatTable. */
1349 /****************************************************/
SetFloatTable(void * theEnv,FLOAT_HN ** value)1350 globle void SetFloatTable(
1351   void *theEnv,
1352   FLOAT_HN **value)
1353   {
1354    SymbolData(theEnv)->FloatTable = value;
1355   }
1356 
1357 /***********************************************************/
1358 /* GetIntegerTable: Returns a pointer to the IntegerTable. */
1359 /***********************************************************/
GetIntegerTable(void * theEnv)1360 globle INTEGER_HN **GetIntegerTable(
1361   void *theEnv)
1362   {
1363    return(SymbolData(theEnv)->IntegerTable);
1364   }
1365 
1366 /********************************************************/
1367 /* SetIntegerTable: Sets the value of the IntegerTable. */
1368 /********************************************************/
SetIntegerTable(void * theEnv,INTEGER_HN ** value)1369 globle void SetIntegerTable(
1370   void *theEnv,
1371   INTEGER_HN **value)
1372   {
1373    SymbolData(theEnv)->IntegerTable = value;
1374   }
1375 
1376 /*********************************************************/
1377 /* GetBitMapTable: Returns a pointer to the BitMapTable. */
1378 /*********************************************************/
GetBitMapTable(void * theEnv)1379 globle BITMAP_HN **GetBitMapTable(
1380   void *theEnv)
1381   {
1382    return(SymbolData(theEnv)->BitMapTable);
1383   }
1384 
1385 /******************************************************/
1386 /* SetBitMapTable: Sets the value of the BitMapTable. */
1387 /******************************************************/
SetBitMapTable(void * theEnv,BITMAP_HN ** value)1388 globle void SetBitMapTable(
1389   void *theEnv,
1390   BITMAP_HN **value)
1391   {
1392    SymbolData(theEnv)->BitMapTable = value;
1393   }
1394 
1395 /***************************************************************************/
1396 /* GetExternalAddressTable: Returns a pointer to the ExternalAddressTable. */
1397 /***************************************************************************/
GetExternalAddressTable(void * theEnv)1398 globle EXTERNAL_ADDRESS_HN **GetExternalAddressTable(
1399   void *theEnv)
1400   {
1401    return(SymbolData(theEnv)->ExternalAddressTable);
1402   }
1403 
1404 /************************************************************************/
1405 /* SetExternalAddressTable: Sets the value of the ExternalAddressTable. */
1406 /************************************************************************/
SetExternalAddressTable(void * theEnv,EXTERNAL_ADDRESS_HN ** value)1407 globle void SetExternalAddressTable(
1408   void *theEnv,
1409   EXTERNAL_ADDRESS_HN **value)
1410   {
1411    SymbolData(theEnv)->ExternalAddressTable = value;
1412   }
1413 
1414 /******************************************************/
1415 /* RefreshSpecialSymbols: Resets the values of the    */
1416 /*   TrueSymbol, FalseSymbol, Zero, PositiveInfinity, */
1417 /*   and NegativeInfinity symbols.                    */
1418 /******************************************************/
RefreshSpecialSymbols(void * theEnv)1419 globle void RefreshSpecialSymbols(
1420   void *theEnv)
1421   {
1422    SymbolData(theEnv)->TrueSymbolHN = (void *) FindSymbolHN(theEnv,TRUE_STRING);
1423    SymbolData(theEnv)->FalseSymbolHN = (void *) FindSymbolHN(theEnv,FALSE_STRING);
1424    SymbolData(theEnv)->PositiveInfinity = (void *) FindSymbolHN(theEnv,POSITIVE_INFINITY_STRING);
1425    SymbolData(theEnv)->NegativeInfinity = (void *) FindSymbolHN(theEnv,NEGATIVE_INFINITY_STRING);
1426    SymbolData(theEnv)->Zero = (void *) FindLongHN(theEnv,0L);
1427   }
1428 
1429 /***********************************************************/
1430 /* FindSymbolMatches: Finds all symbols in the SymbolTable */
1431 /*   which begin with a specified symbol. This function is */
1432 /*   used to implement the command completion feature      */
1433 /*   found in some of the machine specific interfaces.     */
1434 /***********************************************************/
FindSymbolMatches(void * theEnv,const char * searchString,unsigned * numberOfMatches,size_t * commonPrefixLength)1435 globle struct symbolMatch *FindSymbolMatches(
1436   void *theEnv,
1437   const char *searchString,
1438   unsigned *numberOfMatches,
1439   size_t *commonPrefixLength)
1440   {
1441    struct symbolMatch *reply = NULL, *temp;
1442    struct symbolHashNode *hashPtr = NULL;
1443    size_t searchLength;
1444 
1445    searchLength = strlen(searchString);
1446    *numberOfMatches = 0;
1447 
1448    while ((hashPtr = GetNextSymbolMatch(theEnv,searchString,searchLength,hashPtr,
1449                                         FALSE,commonPrefixLength)) != NULL)
1450      {
1451       *numberOfMatches = *numberOfMatches + 1;
1452       temp = get_struct(theEnv,symbolMatch);
1453       temp->match = hashPtr;
1454       temp->next = reply;
1455       reply = temp;
1456      }
1457 
1458    return(reply);
1459   }
1460 
1461 /*********************************************************/
1462 /* ReturnSymbolMatches: Returns a set of symbol matches. */
1463 /*********************************************************/
ReturnSymbolMatches(void * theEnv,struct symbolMatch * listOfMatches)1464 globle void ReturnSymbolMatches(
1465   void *theEnv,
1466   struct symbolMatch *listOfMatches)
1467   {
1468    struct symbolMatch *temp;
1469 
1470    while (listOfMatches != NULL)
1471      {
1472       temp = listOfMatches->next;
1473       rtn_struct(theEnv,symbolMatch,listOfMatches);
1474       listOfMatches = temp;
1475      }
1476   }
1477 
1478 /***************************************************************/
1479 /* ClearBitString: Initializes the values of a bitmap to zero. */
1480 /***************************************************************/
ClearBitString(void * vTheBitMap,unsigned length)1481 globle void ClearBitString(
1482   void *vTheBitMap,
1483   unsigned length)
1484   {
1485    char *theBitMap = (char *) vTheBitMap;
1486    unsigned i;
1487 
1488    for (i = 0; i < length; i++) theBitMap[i] = '\0';
1489   }
1490 
1491 /*****************************************************************/
1492 /* GetNextSymbolMatch: Finds the next symbol in the SymbolTable  */
1493 /*   which begins with a specified symbol. This function is used */
1494 /*   to implement the command completion feature found in some   */
1495 /*   of the machine specific interfaces.                         */
1496 /*****************************************************************/
GetNextSymbolMatch(void * theEnv,const char * searchString,size_t searchLength,SYMBOL_HN * prevSymbol,int anywhere,size_t * commonPrefixLength)1497 globle SYMBOL_HN *GetNextSymbolMatch(
1498   void *theEnv,
1499   const char *searchString,
1500   size_t searchLength,
1501   SYMBOL_HN *prevSymbol,
1502   int anywhere,
1503   size_t *commonPrefixLength)
1504   {
1505    register unsigned long i;
1506    SYMBOL_HN *hashPtr;
1507    int flag = TRUE;
1508    size_t prefixLength;
1509 
1510    /*==========================================*/
1511    /* If we're looking anywhere in the string, */
1512    /* then there's no common prefix length.    */
1513    /*==========================================*/
1514 
1515    if (anywhere && (commonPrefixLength != NULL))
1516      *commonPrefixLength = 0;
1517 
1518    /*========================================================*/
1519    /* If we're starting the search from the beginning of the */
1520    /* symbol table, the previous symbol argument is NULL.    */
1521    /*========================================================*/
1522 
1523    if (prevSymbol == NULL)
1524      {
1525       i = 0;
1526       hashPtr = SymbolData(theEnv)->SymbolTable[0];
1527      }
1528 
1529    /*==========================================*/
1530    /* Otherwise start the search at the symbol */
1531    /* after the last symbol found.             */
1532    /*==========================================*/
1533 
1534    else
1535      {
1536       i = prevSymbol->bucket;
1537       hashPtr = prevSymbol->next;
1538      }
1539 
1540    /*==============================================*/
1541    /* Search through all the symbol table buckets. */
1542    /*==============================================*/
1543 
1544    while (flag)
1545      {
1546       /*===================================*/
1547       /* Search through all of the entries */
1548       /* in the bucket being examined.     */
1549       /*===================================*/
1550 
1551       for (; hashPtr != NULL; hashPtr = hashPtr->next)
1552         {
1553          /*================================================*/
1554          /* Skip symbols that being with ( since these are */
1555          /* typically symbols for internal use. Also skip  */
1556          /* any symbols that are marked ephemeral since    */
1557          /* these aren't in use.                           */
1558          /*================================================*/
1559 
1560          if ((hashPtr->contents[0] == '(') ||
1561              (hashPtr->markedEphemeral))
1562            { continue; }
1563 
1564          /*==================================================*/
1565          /* Two types of matching can be performed: the type */
1566          /* comparing just to the beginning of the string    */
1567          /* and the type which looks for the substring       */
1568          /* anywhere within the string being examined.       */
1569          /*==================================================*/
1570 
1571          if (! anywhere)
1572            {
1573             /*=============================================*/
1574             /* Determine the common prefix length between  */
1575             /* the previously found match (if available or */
1576             /* the search string if not) and the symbol    */
1577             /* table entry.                                */
1578             /*=============================================*/
1579 
1580             if (prevSymbol != NULL)
1581               prefixLength = CommonPrefixLength(prevSymbol->contents,hashPtr->contents);
1582             else
1583               prefixLength = CommonPrefixLength(searchString,hashPtr->contents);
1584 
1585             /*===================================================*/
1586             /* If the prefix length is greater than or equal to  */
1587             /* the length of the search string, then we've found */
1588             /* a match. If this is the first match, the common   */
1589             /* prefix length is set to the length of the first   */
1590             /* match, otherwise the common prefix length is the  */
1591             /* smallest prefix length found among all matches.   */
1592             /*===================================================*/
1593 
1594             if (prefixLength >= searchLength)
1595               {
1596                if (commonPrefixLength != NULL)
1597                  {
1598                   if (prevSymbol == NULL)
1599                     *commonPrefixLength = strlen(hashPtr->contents);
1600                   else if (prefixLength < *commonPrefixLength)
1601                     *commonPrefixLength = prefixLength;
1602                  }
1603                return(hashPtr);
1604               }
1605            }
1606          else
1607            {
1608             if (StringWithinString(hashPtr->contents,searchString) != NULL)
1609               { return(hashPtr); }
1610            }
1611         }
1612 
1613       /*=================================================*/
1614       /* Move on to the next bucket in the symbol table. */
1615       /*=================================================*/
1616 
1617       if (++i >= SYMBOL_HASH_SIZE) flag = FALSE;
1618       else hashPtr = SymbolData(theEnv)->SymbolTable[i];
1619      }
1620 
1621    /*=====================================*/
1622    /* There are no more matching symbols. */
1623    /*=====================================*/
1624 
1625    return(NULL);
1626   }
1627 
1628 /**********************************************/
1629 /* StringWithinString: Determines if a string */
1630 /*   is contained within another string.      */
1631 /**********************************************/
StringWithinString(const char * cs,const char * ct)1632 static const char *StringWithinString(
1633   const char *cs,
1634   const char *ct)
1635   {
1636    register unsigned i,j,k;
1637 
1638    for (i = 0 ; cs[i] != '\0' ; i++)
1639      {
1640       for (j = i , k = 0 ; ct[k] != '\0' && cs[j] == ct[k] ; j++, k++) ;
1641       if ((ct[k] == '\0') && (k != 0))
1642         return(cs + i);
1643      }
1644    return(NULL);
1645   }
1646 
1647 /************************************************/
1648 /* CommonPrefixLength: Determines the length of */
1649 /*    the maximumcommon prefix of two strings   */
1650 /************************************************/
CommonPrefixLength(const char * cs,const char * ct)1651 static size_t CommonPrefixLength(
1652   const char *cs,
1653   const char *ct)
1654   {
1655    register unsigned i;
1656 
1657    for (i = 0 ; (cs[i] != '\0') && (ct[i] != '\0') ; i++)
1658      if (cs[i] != ct[i])
1659        break;
1660    return(i);
1661   }
1662 
1663 #if BLOAD_AND_BSAVE || CONSTRUCT_COMPILER || BSAVE_INSTANCES
1664 
1665 /****************************************************************/
1666 /* SetAtomicValueIndices: Sets the bucket values for hash table */
1667 /*   entries with an index value that indicates the position of */
1668 /*   the hash table in a hash table traversal (e.g. this is the */
1669 /*   fifth entry in the  hash table.                            */
1670 /****************************************************************/
SetAtomicValueIndices(void * theEnv,int setAll)1671 globle void SetAtomicValueIndices(
1672   void *theEnv,
1673   int setAll)
1674   {
1675    unsigned long count;
1676    unsigned long i;
1677    SYMBOL_HN *symbolPtr, **symbolArray;
1678    FLOAT_HN *floatPtr, **floatArray;
1679    INTEGER_HN *integerPtr, **integerArray;
1680    BITMAP_HN *bitMapPtr, **bitMapArray;
1681 
1682    /*===================================*/
1683    /* Set indices for the symbol table. */
1684    /*===================================*/
1685 
1686    count = 0;
1687    symbolArray = GetSymbolTable(theEnv);
1688 
1689    for (i = 0; i < SYMBOL_HASH_SIZE; i++)
1690      {
1691       for (symbolPtr = symbolArray[i];
1692            symbolPtr != NULL;
1693            symbolPtr = symbolPtr->next)
1694         {
1695          if ((symbolPtr->neededSymbol == TRUE) || setAll)
1696            {
1697             symbolPtr->bucket = count++;
1698             if (symbolPtr->bucket != (count - 1))
1699               { SystemError(theEnv,"SYMBOL",13); }
1700            }
1701         }
1702      }
1703 
1704    /*==================================*/
1705    /* Set indices for the float table. */
1706    /*==================================*/
1707 
1708    count = 0;
1709    floatArray = GetFloatTable(theEnv);
1710 
1711    for (i = 0; i < FLOAT_HASH_SIZE; i++)
1712      {
1713       for (floatPtr = floatArray[i];
1714            floatPtr != NULL;
1715            floatPtr = floatPtr->next)
1716         {
1717          if ((floatPtr->neededFloat == TRUE) || setAll)
1718            {
1719             floatPtr->bucket = count++;
1720             if (floatPtr->bucket != (count - 1))
1721               { SystemError(theEnv,"SYMBOL",14); }
1722            }
1723         }
1724      }
1725 
1726    /*====================================*/
1727    /* Set indices for the integer table. */
1728    /*====================================*/
1729 
1730    count = 0;
1731    integerArray = GetIntegerTable(theEnv);
1732 
1733    for (i = 0; i < INTEGER_HASH_SIZE; i++)
1734      {
1735       for (integerPtr = integerArray[i];
1736            integerPtr != NULL;
1737            integerPtr = integerPtr->next)
1738         {
1739          if ((integerPtr->neededInteger == TRUE) || setAll)
1740            {
1741             integerPtr->bucket = count++;
1742             if (integerPtr->bucket != (count - 1))
1743               { SystemError(theEnv,"SYMBOL",15); }
1744            }
1745         }
1746      }
1747 
1748    /*===================================*/
1749    /* Set indices for the bitmap table. */
1750    /*===================================*/
1751 
1752    count = 0;
1753    bitMapArray = GetBitMapTable(theEnv);
1754 
1755    for (i = 0; i < BITMAP_HASH_SIZE; i++)
1756      {
1757       for (bitMapPtr = bitMapArray[i];
1758            bitMapPtr != NULL;
1759            bitMapPtr = bitMapPtr->next)
1760         {
1761          if ((bitMapPtr->neededBitMap == TRUE) || setAll)
1762            {
1763             bitMapPtr->bucket = count++;
1764             if (bitMapPtr->bucket != (count - 1))
1765               { SystemError(theEnv,"SYMBOL",16); }
1766            }
1767         }
1768      }
1769   }
1770 
1771 /***********************************************************************/
1772 /* RestoreAtomicValueBuckets: Restores the bucket values of hash table */
1773 /*   entries to the appropriate values. Normally called to undo the    */
1774 /*   effects of a call to the SetAtomicValueIndices function.          */
1775 /***********************************************************************/
RestoreAtomicValueBuckets(void * theEnv)1776 globle void RestoreAtomicValueBuckets(
1777   void *theEnv)
1778   {
1779    unsigned long i;
1780    SYMBOL_HN *symbolPtr, **symbolArray;
1781    FLOAT_HN *floatPtr, **floatArray;
1782    INTEGER_HN *integerPtr, **integerArray;
1783    BITMAP_HN *bitMapPtr, **bitMapArray;
1784 
1785    /*================================================*/
1786    /* Restore the bucket values in the symbol table. */
1787    /*================================================*/
1788 
1789    symbolArray = GetSymbolTable(theEnv);
1790 
1791    for (i = 0; i < SYMBOL_HASH_SIZE; i++)
1792      {
1793       for (symbolPtr = symbolArray[i];
1794            symbolPtr != NULL;
1795            symbolPtr = symbolPtr->next)
1796         { symbolPtr->bucket = i; }
1797      }
1798 
1799    /*===============================================*/
1800    /* Restore the bucket values in the float table. */
1801    /*===============================================*/
1802 
1803    floatArray = GetFloatTable(theEnv);
1804 
1805    for (i = 0; i < FLOAT_HASH_SIZE; i++)
1806      {
1807       for (floatPtr = floatArray[i];
1808            floatPtr != NULL;
1809            floatPtr = floatPtr->next)
1810         { floatPtr->bucket = i; }
1811      }
1812 
1813    /*=================================================*/
1814    /* Restore the bucket values in the integer table. */
1815    /*=================================================*/
1816 
1817    integerArray = GetIntegerTable(theEnv);
1818 
1819    for (i = 0; i < INTEGER_HASH_SIZE; i++)
1820      {
1821       for (integerPtr = integerArray[i];
1822            integerPtr != NULL;
1823            integerPtr = integerPtr->next)
1824         { integerPtr->bucket = i; }
1825      }
1826 
1827    /*================================================*/
1828    /* Restore the bucket values in the bitmap table. */
1829    /*================================================*/
1830 
1831    bitMapArray = GetBitMapTable(theEnv);
1832 
1833    for (i = 0; i < BITMAP_HASH_SIZE; i++)
1834      {
1835       for (bitMapPtr = bitMapArray[i];
1836            bitMapPtr != NULL;
1837            bitMapPtr = bitMapPtr->next)
1838         { bitMapPtr->bucket = i; }
1839      }
1840   }
1841 
1842 #endif /* BLOAD_AND_BSAVE || CONSTRUCT_COMPILER || BSAVE_INSTANCES */
1843 
1844 /*##################################*/
1845 /* Additional Environment Functions */
1846 /*##################################*/
1847 
EnvFalseSymbol(void * theEnv)1848 globle void *EnvFalseSymbol(
1849   void *theEnv)
1850   {
1851    return SymbolData(theEnv)->FalseSymbolHN;
1852   }
1853 
EnvTrueSymbol(void * theEnv)1854 globle void *EnvTrueSymbol(
1855   void *theEnv)
1856   {
1857    return SymbolData(theEnv)->TrueSymbolHN;
1858   }
1859 
1860 /*#####################################*/
1861 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
1862 /*#####################################*/
1863 
1864 #if ALLOW_ENVIRONMENT_GLOBALS
1865 
AddSymbol(const char * str)1866 globle void *AddSymbol(
1867   const char *str)
1868   {
1869    return EnvAddSymbol(GetCurrentEnvironment(),str);
1870   }
1871 
AddLong(long long number)1872 globle void *AddLong(
1873   long long number)
1874   {
1875    return EnvAddLong(GetCurrentEnvironment(),number);
1876   }
1877 
AddDouble(double number)1878 globle void *AddDouble(
1879   double number)
1880   {
1881    return EnvAddDouble(GetCurrentEnvironment(),number);
1882   }
1883 
FalseSymbol()1884 globle void *FalseSymbol()
1885   {
1886    return SymbolData(GetCurrentEnvironment())->FalseSymbolHN;
1887   }
1888 
TrueSymbol()1889 globle void *TrueSymbol()
1890   {
1891    return SymbolData(GetCurrentEnvironment())->TrueSymbolHN;
1892   }
1893 
1894 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
1895 
1896