Initial revision
[become] / src / sym.c
1 /* -*-c-*-
2 *
3 * $Id: sym.c,v 1.1 1997/07/21 13:47:44 mdw Exp $
4 *
5 * Symbol table management
6 *
7 * (c) 1996 Straylight
8 */
9
10 /*----- Licencing notice --------------------------------------------------*
11 *
12 * This file is part of `become'
13 *
14 * `Become' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * `Become' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*----- Revision history --------------------------------------------------*
30 *
31 * $Log: sym.c,v $
32 * Revision 1.1 1997/07/21 13:47:44 mdw
33 * Initial revision
34 *
35 */
36
37 /*----- Header files ------------------------------------------------------*/
38
39 /* --- ANSI headers --- */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 /* --- Local headers --- */
46
47 #include "sym.h"
48 #include "utils.h"
49
50 /*----- Tuning parameters -------------------------------------------------*/
51
52 /* --- Initial hash table size --- *
53 *
54 * This is the initial @mask@ value. It must be of the form %$2^n - 1$%,
55 * so that it can be used to mask of the bottom bits of a hash value.
56 */
57
58 #define sym__iSize 255 /* Size of a new hash table */
59
60 /* --- Maximum load factor --- *
61 *
62 * This parameter controls how much the table has to be loaded before the
63 * table is extended. The number of elements %$n$%, the number of bins %$b$%
64 * and the limit %$l$% satisfy the relation %$n < bl$%; if a new item is
65 * added to the table and this relation is found to be false, the table is
66 * doubled in size.
67 *
68 * The parameter @sym__limFactor@ is the value of %$l$% multiplied by 256;
69 * fixed point arithmetic is used to calculate the allowable load. Note
70 * that the exact calculation of this criterion isn't important; what's more
71 * significant is that the parameter allows tuning of the rehashing process.
72 *
73 * The current value is %$3 \over 4$%, which appears to be reasonable on the
74 * face of things.
75 */
76
77 #define sym__limFactor 0x0C0 /* Load factor for growing table */
78
79 /*----- CRC table ---------------------------------------------------------*/
80
81 /*****************************************************************/
82 /* */
83 /* CRC LOOKUP TABLE */
84 /* ================ */
85 /* */
86 /* The following CRC lookup table was generated automagically */
87 /* by `crcgen', which is based on the Rocksoft^tm Model CRC */
88 /* Algorithm Table Generation Program. The model parameters */
89 /* supplied to `crcgen' were: */
90 /* */
91 /* Width : 32 bits */
92 /* Poly : 0x04C11DB7 */
93 /* Init : 0xFFFFFFFF */
94 /* XorOut : 0xFFFFFFFF */
95 /* Reverse : Yes */
96 /* Check : 0xCBF43926 */
97 /* */
98 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
99 /* see the document titled `A Painless Guide to CRC Error */
100 /* Detection Algorithms' by Ross Williams */
101 /* (ross@@guest.adelaide.edu.au.). This document is likely to be */
102 /* in the FTP archive `ftp.adelaide.edu.au/pub/rocksoft'. */
103 /* */
104 /*****************************************************************/
105
106 static unsigned long sym__crcTable[256] = {
107 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
108 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
109 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
110 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
111 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
112 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
113 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
114 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
115 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
116 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
117 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
118 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
119 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
120 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
121 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
122 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
123 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
124 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
125 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
126 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
127 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
128 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
129 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
130 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
131 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
132 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
133 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
134 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
135 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
136 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
137 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
138 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
139 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
140 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
141 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
142 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
143 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
144 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
145 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
146 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
147 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
148 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
149 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
150 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
151 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
152 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
153 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
154 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
155 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
156 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
157 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
158 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
159 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
160 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
161 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
162 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
163 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
164 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
165 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
166 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
167 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
168 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
169 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
170 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL,
171 };
172
173 /*****************************************************************/
174 /* End of CRC Lookup Table */
175 /*****************************************************************/
176
177 /* --- Work out the CRC of a bytestring --- */
178
179 #define sym__crc(s_, l_, hv_) do { \
180 unsigned long h_ = 0xFFFFFFFFL; \
181 const char *p_ = s_; \
182 const char *e_ = (s_) + (l_); \
183 \
184 while (p_ < e_) \
185 h_ = (h_ >> 8) ^ (sym__crcTable[(*p_++ ^ h_) & 0xFF]); \
186 hv_ = ~h_ & 0xFFFFFFFFL; \
187 } while (0)
188
189 /*----- Main code ---------------------------------------------------------*/
190
191 #ifndef DEBUG_CRC
192
193 /* --- @sym_createTable@ --- *
194 *
195 * Arguments: @sym_table *t@ = symbol table to initialise
196 *
197 * Returns: ---
198 *
199 * Use: Initialises the given symbol table.
200 */
201
202 void sym_createTable(sym_table *t)
203 {
204 size_t i;
205
206 t->mask = sym__iSize;
207 t->c = (sym__iSize * sym__limFactor) >> 8;
208 t->a = xmalloc((t->mask + 1) * sizeof(sym_base *));
209
210 for (i = 0; i < sym__iSize + 1; i++)
211 t->a[i] = 0;
212 }
213
214 /* --- @sym_destroyTable@ --- *
215 *
216 * Arguments: @sym_table *t@ = pointer to symbol table in question
217 *
218 * Returns: ---
219 *
220 * Use: Destroys a symbol table, freeing all the memory it used to
221 * occupy.
222 */
223
224 void sym_destroyTable(sym_table *t)
225 {
226 size_t i;
227 sym_base *p, *q;
228
229 for (i = 0; i <= t->mask; i++) {
230 p = t->a[i];
231 while (p) {
232 q = p->next;
233 free(p);
234 p = q;
235 }
236 }
237 }
238
239 /* --- @sym_find@ --- *
240 *
241 * Arguments: @sym_table *t@ = pointer to symbol table in question
242 * @const char *n@ = pointer to symbol table to look up
243 * @long l@ = length of the name string or negative to measure
244 * @size_t sz@ = size of desired symbol object, or zero
245 * @unsigned *f@ = pointer to a flag, or null.
246 *
247 * Returns: The address of a @sym_base@ structure, or null if not found
248 * and @sz@ is zero.
249 *
250 * Use: Looks up a symbol in a given symbol table. The name is
251 * passed by the address of its first character. The length
252 * may be given, in which case the name may contain arbitrary
253 * binary data, or it may be given as a negative number, in
254 * which case the length of the name is calculated as
255 * @strlen(n)@.
256 *
257 * The return value is the address of a pointer to a @sym_base@
258 * block (which may have other things on the end, as above). If
259 * the symbol could be found, the return value points to the
260 * symbol block. If the symbol wasn't there, then if @sz@ is
261 * nonzero, a new symbol is created and its address is returned;
262 * otherwise a null pointer is returned.
263 *
264 * The value of @*f@ indicates whether a new symbol entry was
265 * created: a nonzero value indicates that an old value was
266 * found.
267 */
268
269 void *sym_find(sym_table *t, const char *n, long l, size_t sz, unsigned *f)
270 {
271 unsigned long hash; /* Hash value for user's name */
272 size_t len = l < 0 ? strlen(n) + 1 : l; /* Find length of user's name */
273 sym_base *bin; /* Bin containing our item */
274 sym_base *p, *q; /* Pointer wandering through list */
275
276 /* --- Find the correct bin --- */
277
278 sym__crc(n, len, hash); /* Find hash value for this name */
279 bin = p = (sym_base *)(t->a + (hash & t->mask));
280
281 /* --- Search the bin list --- */
282
283 while (p->next) {
284 if (hash == p->next->hash && /* Check hash values first */
285 len == p->next->len && /* Then compare string lengths */
286 !memcmp(n, p->next->name, len)) /* And finally compare the strings */
287 {
288 /* --- Found a match --- *
289 *
290 * As a minor, and probably pointless, tweak, move the item to the
291 * front of its bin list.
292 */
293
294 q = p->next; /* Find the actual symbol block */
295 p->next = q->next; /* Extract block from bin list */
296 q->next = bin->next; /* Set up symbol's next pointer */
297 bin->next = q; /* And reinsert the block */
298
299 /* --- Return the block --- */
300
301 if (f) *f = 1; /* Didn't fail to find the item */
302 return (q); /* And return the block */
303 }
304
305 p = p->next; /* Move onto the next item */
306 }
307
308 /* --- Couldn't find the item there --- */
309
310 if (f) *f = 0; /* Failed to find the block */
311 if (!sz) return (0); /* Return zero if not creating */
312
313 /* --- Create a new symbol block and initialise it --- */
314
315 p = xmalloc(sz); /* Create a new symbol block */
316 p->next = bin->next; /* Set up the next pointer */
317 p->hash = hash; /* Set up the hash value too */
318 p->name = xmalloc(len); /* Allocate a block for the name */
319 p->len = len; /* And set up the string length */
320 memcpy(p->name, n, len); /* And copy the string over */
321
322 bin->next = p; /* Put the pointer into the bin */
323
324 /* --- Consider growing the array --- */
325
326 if (!--t->c) {
327 unsigned long m = t->mask + 1; /* Next set bit in has word */
328 sym_base *p, *q, *r; /* More useful pointers */
329 size_t i, lim; /* Loop counter and limit */
330
331 /* --- Update values in the anchor block --- */
332
333 t->c = ((t->mask + 1) * sym__limFactor) >> 8; /* Set load value */
334 t->mask = (t->mask + 1) * 2 - 1; /* Set the new mask value */
335 t->a = xrealloc(t->a, (t->mask + 1) * sizeof(sym_base *));
336
337 /* --- Now wander through the table rehashing things --- *
338 *
339 * This loop is very careful to avoid problems with aliasing. The items
340 * are dealt with from the end backwards to avoid overwriting bins before
341 * they've been processed.
342 */
343
344 lim = (t->mask + 1) >> 1;
345 for (i = 0; i < lim; i++) {
346 /* --- Some initialisation --- */
347
348 r = t->a[i]; /* Find the list we're dissecting */
349 p = (sym_base *)(t->a + i); /* Find bit-clear list */
350 q = (sym_base *)(t->a + i + lim); /* And the bit-set lsit */
351
352 /* --- Now go through the @r@ list --- */
353
354 while (r) {
355 if (r->hash & m) /* Is the next bit set? */
356 q = q->next = r; /* Yes, so fit up previous link */
357 else
358 p = p->next = r; /* No, so fit up previous link */
359 r = r->next; /* Move onto the next item */
360 }
361 p->next = q->next = 0; /* Null terminate the new lists */
362 }
363 }
364
365 /* --- Finished that, so return the new symbol block --- */
366
367 return (p);
368 }
369
370 /* --- @sym_remove@ --- *
371 *
372 * Arguments: @sym_table *i@ = pointer to a symbol table object
373 * @void *b@ = pointer to symbol table entry
374 *
375 * Returns: ---
376 *
377 * Use: Removes the object from the symbol table. The space occupied
378 * by the object and its name is freed; anything else attached
379 * to the entry should already be gone by this point.
380 */
381
382 void sym_remove(sym_table *t, void *b)
383 {
384 /* --- A quick comment --- *
385 *
386 * Since the @sym_base@ block contains the hash, finding the element in the
387 * bin list is really quick -- it's not worth bothering with things like
388 * doubly linked lists.
389 */
390
391 sym_base *p = b;
392 sym_base *bin = (sym_base *)(t->a + (p->hash & t->mask));
393
394 /* --- Find the item in the bin list --- */
395
396 while (bin->next) {
397 if (bin->next == p)
398 break;
399 bin = bin->next;
400 }
401 if (!bin->next)
402 return;
403
404 /* --- Now just remove the item from the list and free it --- *
405 *
406 * Oh, and bump the load counter.
407 */
408
409 bin->next = p->next;
410 free(p->name);
411 free(p);
412 t->c++;
413 }
414
415 /* --- @sym_createIter@ --- *
416 *
417 * Arguments: @sym_iter *i@ = pointer to an iterator object
418 * @sym_table *t@ = pointer to a symbol table object
419 *
420 * Returns: ---
421 *
422 * Use: Creates a new symbol table iterator which may be used to
423 * iterate through a symbol table.
424 */
425
426 void sym_createIter(sym_iter *i, sym_table *t)
427 {
428 i->t = t;
429 i->i = 0;
430 i->n = 0;
431 }
432
433 /* --- @sym_next@ --- *
434 *
435 * Arguments: @sym_iter *i@ = pointer to iterator object
436 *
437 * Returns: Pointer to the next symbol found, or null when finished.
438 *
439 * Use: Returns the next symbol from the table. Symbols are not
440 * returned in any particular order.
441 */
442
443 void *sym_next(sym_iter *i)
444 {
445 sym_base *p;
446
447 /* --- Find the next item --- */
448
449 while (!i->n) {
450 if (i->i > i->t->mask)
451 return (0);
452 i->n = i->t->a[i->i++];
453 }
454
455 /* --- Update the iterator block --- */
456
457 p = i->n;
458 i->n = p->next;
459
460 /* --- Done --- */
461
462 return (p);
463 }
464
465 #endif
466
467 /*----- CRC test code -----------------------------------------------------*/
468
469 #ifdef DEBUG_CRC
470
471 int main(void)
472 {
473 unsigned long h;
474 sym__crc("123456789", 9, h);
475 printf("crc check == %04x\n", h);
476 return (0);
477 }
478
479 #endif
480
481 /*----- Symbol table test code --------------------------------------------*/
482
483 #ifdef TEST_RIG
484
485 #include <errno.h>
486 #include <time.h>
487
488 #include "dbutils.h"
489
490 typedef struct sym_word {
491 sym_base base;
492 size_t i;
493 } sym_word;
494
495
496 /* --- What it does --- *
497 *
498 * Reads the file /usr/dict/words (change to some other file full of
499 * interesting and appropriate bits of text to taste) into a big buffer and
500 * picks apart into lines. Then picks lines at random and enters them into
501 * the symbol table.
502 */
503
504 int main(void)
505 {
506 char *buff, *p, *lim;
507 size_t sz, done;
508 FILE *fp;
509 int i;
510 char **line;
511 sym_word **flag;
512 sym_table tbl;
513 int entries;
514
515 /* --- Initialise for reading the file --- */
516
517 sz = BUFSIZ;
518 buff = xmalloc(sz + 1);
519 done = 0;
520
521 if ((fp = fopen("/usr/dict/words", "r")) == 0)
522 fprintf(stderr, "buggered ;-( (%s)\n", strerror(errno));
523
524 /* --- Read buffers of text --- *
525 *
526 * Read a buffer. If more to come, double the buffer size and try again.
527 * This is the method I recommended to comp.lang.c, so I may as well try
528 * it.
529 */
530
531 for (;;) {
532 i = fread(buff + done, 1, sz - done, fp);
533 done += i;
534 if (done != sz)
535 break;
536 sz <<= 1;
537 buff = xrealloc(buff, sz + 1);
538 }
539
540 /* --- Count the lines --- */
541
542 lim = buff + done;
543
544 sz = 1;
545 for (p = buff; p < lim; p++)
546 if (*p == '\n') sz++;
547
548 /* --- Build a table of line starts --- */
549
550 line = xmalloc(sz * sizeof(char *));
551 i = 0;
552 line[i++] = buff;
553 for (p = buff; p < lim; p++)
554 if (*p == '\n') *p = 0, line[i++] = p + 1;
555 *lim = 0;
556
557 /* --- Build a table of lines --- *
558 *
559 * This reverses the mapping which the symbol table performs, so that its
560 * accuracy can be tested.
561 */
562
563 flag = xmalloc(sz * sizeof(sym_word *));
564 for (i = 0; i < sz; i++)
565 flag[i] = 0;
566 entries = 0;
567
568 sym_createTable(&tbl);
569
570 for (;;) {
571 i = (unsigned)rand() % sz;
572
573 switch (rand() % 5)
574 {
575 case 0: {
576 sym_word *w;
577
578 printf("find `%s'\n", line[i]);
579
580 w = sym_find(&tbl, line[i], -1, 0, 0);
581 if (w != flag[i])
582 printf("*** error: find `%s' gave %p not %p\n",
583 line[i], (void *)w, (void *)flag[i]);
584 else if (w && w->i != i)
585 printf("*** error: find sym for `%s' gives index %i not %i\n",
586 line[i], w->i, i);
587 } break;
588
589 case 1: {
590 unsigned f;
591 sym_word *w;
592
593 printf("create `%s'\n", line[i]);
594
595 w = sym_find(&tbl, line[i], -1, sizeof(sym_word), &f);
596 if (f)
597 {
598 if (w != flag[i])
599 printf("*** error: create `%s' gave %p not %p\n",
600 line[i], (void *)w, (void *)flag[i]);
601 else if (w && w->i != i)
602 printf("*** error: create sym for `%s' gives index %i not %i\n",
603 line[i], w->i, i);
604 }
605 else
606 {
607 if (flag[i])
608 printf("*** error: create `%s' gave new block, should be %p\n",
609 line[i], (void *)flag[i]);
610 else {
611 flag[i] = w;
612 w->i = i;
613 entries++;
614 }
615 }
616 } break;
617
618 case 2: {
619 sym_iter it;
620 sym_word *w, **ntbl;
621
622 printf("iterate\n");
623
624 ntbl = xmalloc(sz * sizeof(sym_word *));
625 memcpy(ntbl, flag, sz * sizeof(sym_word *));
626 sym_createIter(&it, &tbl);
627
628 while ((w = sym_next(&it)) != 0) {
629 if (ntbl[w->i] == 0)
630 printf("*** error: iterate returned duff item %i\n", w->i);
631 else
632 ntbl[w->i] = 0;
633 }
634
635 for (i = 0; i < sz; i++)
636 if (ntbl[i]) printf("*** error: iterate didn't return item %i\n",
637 i);
638 free(ntbl);
639 } break;
640
641 case 3: {
642 sym_base *b;
643 int v = rand() & 255 ? 0 : 1;
644
645 printf("dump\n");
646
647 for (i = 0; i <= tbl.mask; i++) {
648 if (!tbl.a[i]) continue;
649 if (v) printf(" %i: ", i);
650 b = tbl.a[i];
651 while (b) {
652 if ((b->hash & tbl.mask) != i)
653 printf("*** error: bad hash value found");
654 if (v) printf("`%s'(%08lx:%lu) ",
655 line[((sym_word *)b)->i],
656 b->hash,
657 b->hash & tbl.mask);
658 b = b->next;
659 }
660 if (v) putchar('\n');
661 }
662 } break;
663
664 case 4: {
665 if (flag[i]) {
666 printf("remove `%s'\n", flag[i]->base.name);
667 sym_remove(&tbl, flag[i]);
668 flag[i] = 0;
669 entries--;
670 }
671 } break;
672 }
673
674 }
675
676 return (0);
677 }
678
679 #endif
680
681 /*----- That's all, folks -------------------------------------------------*/