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