1*a9fa9459Szrj /* hash.c -- gas hash table code
2*a9fa9459Szrj Copyright (C) 1987-2016 Free Software Foundation, Inc.
3*a9fa9459Szrj
4*a9fa9459Szrj This file is part of GAS, the GNU Assembler.
5*a9fa9459Szrj
6*a9fa9459Szrj GAS is free software; you can redistribute it and/or modify
7*a9fa9459Szrj it under the terms of the GNU General Public License as published by
8*a9fa9459Szrj the Free Software Foundation; either version 3, or (at your option)
9*a9fa9459Szrj any later version.
10*a9fa9459Szrj
11*a9fa9459Szrj GAS is distributed in the hope that it will be useful,
12*a9fa9459Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
13*a9fa9459Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*a9fa9459Szrj GNU General Public License for more details.
15*a9fa9459Szrj
16*a9fa9459Szrj You should have received a copy of the GNU General Public License
17*a9fa9459Szrj along with GAS; see the file COPYING. If not, write to the Free
18*a9fa9459Szrj Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19*a9fa9459Szrj 02110-1301, USA. */
20*a9fa9459Szrj
21*a9fa9459Szrj /* This version of the hash table code is a wholescale replacement of
22*a9fa9459Szrj the old hash table code, which was fairly bad. This is based on
23*a9fa9459Szrj the hash table code in BFD, but optimized slightly for the
24*a9fa9459Szrj assembler. The assembler does not need to derive structures that
25*a9fa9459Szrj are stored in the hash table. Instead, it always stores a pointer.
26*a9fa9459Szrj The assembler uses the hash table mostly to store symbols, and we
27*a9fa9459Szrj don't need to confuse the symbol structure with a hash table
28*a9fa9459Szrj structure. */
29*a9fa9459Szrj
30*a9fa9459Szrj #include "as.h"
31*a9fa9459Szrj #include "safe-ctype.h"
32*a9fa9459Szrj #include "obstack.h"
33*a9fa9459Szrj
34*a9fa9459Szrj /* An entry in a hash table. */
35*a9fa9459Szrj
36*a9fa9459Szrj struct hash_entry {
37*a9fa9459Szrj /* Next entry for this hash code. */
38*a9fa9459Szrj struct hash_entry *next;
39*a9fa9459Szrj /* String being hashed. */
40*a9fa9459Szrj const char *string;
41*a9fa9459Szrj /* Hash code. This is the full hash code, not the index into the
42*a9fa9459Szrj table. */
43*a9fa9459Szrj unsigned long hash;
44*a9fa9459Szrj /* Pointer being stored in the hash table. */
45*a9fa9459Szrj void *data;
46*a9fa9459Szrj };
47*a9fa9459Szrj
48*a9fa9459Szrj /* A hash table. */
49*a9fa9459Szrj
50*a9fa9459Szrj struct hash_control {
51*a9fa9459Szrj /* The hash array. */
52*a9fa9459Szrj struct hash_entry **table;
53*a9fa9459Szrj /* The number of slots in the hash table. */
54*a9fa9459Szrj unsigned int size;
55*a9fa9459Szrj /* An obstack for this hash table. */
56*a9fa9459Szrj struct obstack memory;
57*a9fa9459Szrj
58*a9fa9459Szrj #ifdef HASH_STATISTICS
59*a9fa9459Szrj /* Statistics. */
60*a9fa9459Szrj unsigned long lookups;
61*a9fa9459Szrj unsigned long hash_compares;
62*a9fa9459Szrj unsigned long string_compares;
63*a9fa9459Szrj unsigned long insertions;
64*a9fa9459Szrj unsigned long replacements;
65*a9fa9459Szrj unsigned long deletions;
66*a9fa9459Szrj #endif /* HASH_STATISTICS */
67*a9fa9459Szrj };
68*a9fa9459Szrj
69*a9fa9459Szrj /* The default number of entries to use when creating a hash table.
70*a9fa9459Szrj Note this value can be reduced to 4051 by using the command line
71*a9fa9459Szrj switch --reduce-memory-overheads, or set to other values by using
72*a9fa9459Szrj the --hash-size=<NUMBER> switch. */
73*a9fa9459Szrj
74*a9fa9459Szrj static unsigned long gas_hash_table_size = 65537;
75*a9fa9459Szrj
76*a9fa9459Szrj void
set_gas_hash_table_size(unsigned long size)77*a9fa9459Szrj set_gas_hash_table_size (unsigned long size)
78*a9fa9459Szrj {
79*a9fa9459Szrj gas_hash_table_size = bfd_hash_set_default_size (size);
80*a9fa9459Szrj }
81*a9fa9459Szrj
82*a9fa9459Szrj /* Create a hash table. This return a control block. */
83*a9fa9459Szrj
84*a9fa9459Szrj struct hash_control *
hash_new_sized(unsigned long size)85*a9fa9459Szrj hash_new_sized (unsigned long size)
86*a9fa9459Szrj {
87*a9fa9459Szrj unsigned long alloc;
88*a9fa9459Szrj struct hash_control *ret;
89*a9fa9459Szrj
90*a9fa9459Szrj ret = XNEW (struct hash_control);
91*a9fa9459Szrj obstack_begin (&ret->memory, chunksize);
92*a9fa9459Szrj alloc = size * sizeof (struct hash_entry *);
93*a9fa9459Szrj ret->table = (struct hash_entry **) obstack_alloc (&ret->memory, alloc);
94*a9fa9459Szrj memset (ret->table, 0, alloc);
95*a9fa9459Szrj ret->size = size;
96*a9fa9459Szrj
97*a9fa9459Szrj #ifdef HASH_STATISTICS
98*a9fa9459Szrj ret->lookups = 0;
99*a9fa9459Szrj ret->hash_compares = 0;
100*a9fa9459Szrj ret->string_compares = 0;
101*a9fa9459Szrj ret->insertions = 0;
102*a9fa9459Szrj ret->replacements = 0;
103*a9fa9459Szrj ret->deletions = 0;
104*a9fa9459Szrj #endif
105*a9fa9459Szrj
106*a9fa9459Szrj return ret;
107*a9fa9459Szrj }
108*a9fa9459Szrj
109*a9fa9459Szrj struct hash_control *
hash_new(void)110*a9fa9459Szrj hash_new (void)
111*a9fa9459Szrj {
112*a9fa9459Szrj return hash_new_sized (gas_hash_table_size);
113*a9fa9459Szrj }
114*a9fa9459Szrj
115*a9fa9459Szrj /* Delete a hash table, freeing all allocated memory. */
116*a9fa9459Szrj
117*a9fa9459Szrj void
hash_die(struct hash_control * table)118*a9fa9459Szrj hash_die (struct hash_control *table)
119*a9fa9459Szrj {
120*a9fa9459Szrj obstack_free (&table->memory, 0);
121*a9fa9459Szrj free (table);
122*a9fa9459Szrj }
123*a9fa9459Szrj
124*a9fa9459Szrj /* Look up a string in a hash table. This returns a pointer to the
125*a9fa9459Szrj hash_entry, or NULL if the string is not in the table. If PLIST is
126*a9fa9459Szrj not NULL, this sets *PLIST to point to the start of the list which
127*a9fa9459Szrj would hold this hash entry. If PHASH is not NULL, this sets *PHASH
128*a9fa9459Szrj to the hash code for KEY.
129*a9fa9459Szrj
130*a9fa9459Szrj Each time we look up a string, we move it to the start of the list
131*a9fa9459Szrj for its hash code, to take advantage of referential locality. */
132*a9fa9459Szrj
133*a9fa9459Szrj static struct hash_entry *
hash_lookup(struct hash_control * table,const char * key,size_t len,struct hash_entry *** plist,unsigned long * phash)134*a9fa9459Szrj hash_lookup (struct hash_control *table, const char *key, size_t len,
135*a9fa9459Szrj struct hash_entry ***plist, unsigned long *phash)
136*a9fa9459Szrj {
137*a9fa9459Szrj unsigned long hash;
138*a9fa9459Szrj size_t n;
139*a9fa9459Szrj unsigned int c;
140*a9fa9459Szrj unsigned int hindex;
141*a9fa9459Szrj struct hash_entry **list;
142*a9fa9459Szrj struct hash_entry *p;
143*a9fa9459Szrj struct hash_entry *prev;
144*a9fa9459Szrj
145*a9fa9459Szrj #ifdef HASH_STATISTICS
146*a9fa9459Szrj ++table->lookups;
147*a9fa9459Szrj #endif
148*a9fa9459Szrj
149*a9fa9459Szrj hash = 0;
150*a9fa9459Szrj for (n = 0; n < len; n++)
151*a9fa9459Szrj {
152*a9fa9459Szrj c = key[n];
153*a9fa9459Szrj hash += c + (c << 17);
154*a9fa9459Szrj hash ^= hash >> 2;
155*a9fa9459Szrj }
156*a9fa9459Szrj hash += len + (len << 17);
157*a9fa9459Szrj hash ^= hash >> 2;
158*a9fa9459Szrj
159*a9fa9459Szrj if (phash != NULL)
160*a9fa9459Szrj *phash = hash;
161*a9fa9459Szrj
162*a9fa9459Szrj hindex = hash % table->size;
163*a9fa9459Szrj list = table->table + hindex;
164*a9fa9459Szrj
165*a9fa9459Szrj if (plist != NULL)
166*a9fa9459Szrj *plist = list;
167*a9fa9459Szrj
168*a9fa9459Szrj prev = NULL;
169*a9fa9459Szrj for (p = *list; p != NULL; p = p->next)
170*a9fa9459Szrj {
171*a9fa9459Szrj #ifdef HASH_STATISTICS
172*a9fa9459Szrj ++table->hash_compares;
173*a9fa9459Szrj #endif
174*a9fa9459Szrj
175*a9fa9459Szrj if (p->hash == hash)
176*a9fa9459Szrj {
177*a9fa9459Szrj #ifdef HASH_STATISTICS
178*a9fa9459Szrj ++table->string_compares;
179*a9fa9459Szrj #endif
180*a9fa9459Szrj
181*a9fa9459Szrj if (strncmp (p->string, key, len) == 0 && p->string[len] == '\0')
182*a9fa9459Szrj {
183*a9fa9459Szrj if (prev != NULL)
184*a9fa9459Szrj {
185*a9fa9459Szrj prev->next = p->next;
186*a9fa9459Szrj p->next = *list;
187*a9fa9459Szrj *list = p;
188*a9fa9459Szrj }
189*a9fa9459Szrj
190*a9fa9459Szrj return p;
191*a9fa9459Szrj }
192*a9fa9459Szrj }
193*a9fa9459Szrj
194*a9fa9459Szrj prev = p;
195*a9fa9459Szrj }
196*a9fa9459Szrj
197*a9fa9459Szrj return NULL;
198*a9fa9459Szrj }
199*a9fa9459Szrj
200*a9fa9459Szrj /* Insert an entry into a hash table. This returns NULL on success.
201*a9fa9459Szrj On error, it returns a printable string indicating the error. It
202*a9fa9459Szrj is considered to be an error if the entry already exists in the
203*a9fa9459Szrj hash table. */
204*a9fa9459Szrj
205*a9fa9459Szrj const char *
hash_insert(struct hash_control * table,const char * key,void * val)206*a9fa9459Szrj hash_insert (struct hash_control *table, const char *key, void *val)
207*a9fa9459Szrj {
208*a9fa9459Szrj struct hash_entry *p;
209*a9fa9459Szrj struct hash_entry **list;
210*a9fa9459Szrj unsigned long hash;
211*a9fa9459Szrj
212*a9fa9459Szrj p = hash_lookup (table, key, strlen (key), &list, &hash);
213*a9fa9459Szrj if (p != NULL)
214*a9fa9459Szrj return "exists";
215*a9fa9459Szrj
216*a9fa9459Szrj #ifdef HASH_STATISTICS
217*a9fa9459Szrj ++table->insertions;
218*a9fa9459Szrj #endif
219*a9fa9459Szrj
220*a9fa9459Szrj p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
221*a9fa9459Szrj p->string = key;
222*a9fa9459Szrj p->hash = hash;
223*a9fa9459Szrj p->data = val;
224*a9fa9459Szrj
225*a9fa9459Szrj p->next = *list;
226*a9fa9459Szrj *list = p;
227*a9fa9459Szrj
228*a9fa9459Szrj return NULL;
229*a9fa9459Szrj }
230*a9fa9459Szrj
231*a9fa9459Szrj /* Insert or replace an entry in a hash table. This returns NULL on
232*a9fa9459Szrj success. On error, it returns a printable string indicating the
233*a9fa9459Szrj error. If an entry already exists, its value is replaced. */
234*a9fa9459Szrj
235*a9fa9459Szrj const char *
hash_jam(struct hash_control * table,const char * key,void * val)236*a9fa9459Szrj hash_jam (struct hash_control *table, const char *key, void *val)
237*a9fa9459Szrj {
238*a9fa9459Szrj struct hash_entry *p;
239*a9fa9459Szrj struct hash_entry **list;
240*a9fa9459Szrj unsigned long hash;
241*a9fa9459Szrj
242*a9fa9459Szrj p = hash_lookup (table, key, strlen (key), &list, &hash);
243*a9fa9459Szrj if (p != NULL)
244*a9fa9459Szrj {
245*a9fa9459Szrj #ifdef HASH_STATISTICS
246*a9fa9459Szrj ++table->replacements;
247*a9fa9459Szrj #endif
248*a9fa9459Szrj
249*a9fa9459Szrj p->data = val;
250*a9fa9459Szrj }
251*a9fa9459Szrj else
252*a9fa9459Szrj {
253*a9fa9459Szrj #ifdef HASH_STATISTICS
254*a9fa9459Szrj ++table->insertions;
255*a9fa9459Szrj #endif
256*a9fa9459Szrj
257*a9fa9459Szrj p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
258*a9fa9459Szrj p->string = key;
259*a9fa9459Szrj p->hash = hash;
260*a9fa9459Szrj p->data = val;
261*a9fa9459Szrj
262*a9fa9459Szrj p->next = *list;
263*a9fa9459Szrj *list = p;
264*a9fa9459Szrj }
265*a9fa9459Szrj
266*a9fa9459Szrj return NULL;
267*a9fa9459Szrj }
268*a9fa9459Szrj
269*a9fa9459Szrj /* Replace an existing entry in a hash table. This returns the old
270*a9fa9459Szrj value stored for the entry. If the entry is not found in the hash
271*a9fa9459Szrj table, this does nothing and returns NULL. */
272*a9fa9459Szrj
273*a9fa9459Szrj void *
hash_replace(struct hash_control * table,const char * key,void * value)274*a9fa9459Szrj hash_replace (struct hash_control *table, const char *key, void *value)
275*a9fa9459Szrj {
276*a9fa9459Szrj struct hash_entry *p;
277*a9fa9459Szrj void *ret;
278*a9fa9459Szrj
279*a9fa9459Szrj p = hash_lookup (table, key, strlen (key), NULL, NULL);
280*a9fa9459Szrj if (p == NULL)
281*a9fa9459Szrj return NULL;
282*a9fa9459Szrj
283*a9fa9459Szrj #ifdef HASH_STATISTICS
284*a9fa9459Szrj ++table->replacements;
285*a9fa9459Szrj #endif
286*a9fa9459Szrj
287*a9fa9459Szrj ret = p->data;
288*a9fa9459Szrj
289*a9fa9459Szrj p->data = value;
290*a9fa9459Szrj
291*a9fa9459Szrj return ret;
292*a9fa9459Szrj }
293*a9fa9459Szrj
294*a9fa9459Szrj /* Find an entry in a hash table, returning its value. Returns NULL
295*a9fa9459Szrj if the entry is not found. */
296*a9fa9459Szrj
297*a9fa9459Szrj void *
hash_find(struct hash_control * table,const char * key)298*a9fa9459Szrj hash_find (struct hash_control *table, const char *key)
299*a9fa9459Szrj {
300*a9fa9459Szrj struct hash_entry *p;
301*a9fa9459Szrj
302*a9fa9459Szrj p = hash_lookup (table, key, strlen (key), NULL, NULL);
303*a9fa9459Szrj if (p == NULL)
304*a9fa9459Szrj return NULL;
305*a9fa9459Szrj
306*a9fa9459Szrj return p->data;
307*a9fa9459Szrj }
308*a9fa9459Szrj
309*a9fa9459Szrj /* As hash_find, but KEY is of length LEN and is not guaranteed to be
310*a9fa9459Szrj NUL-terminated. */
311*a9fa9459Szrj
312*a9fa9459Szrj void *
hash_find_n(struct hash_control * table,const char * key,size_t len)313*a9fa9459Szrj hash_find_n (struct hash_control *table, const char *key, size_t len)
314*a9fa9459Szrj {
315*a9fa9459Szrj struct hash_entry *p;
316*a9fa9459Szrj
317*a9fa9459Szrj p = hash_lookup (table, key, len, NULL, NULL);
318*a9fa9459Szrj if (p == NULL)
319*a9fa9459Szrj return NULL;
320*a9fa9459Szrj
321*a9fa9459Szrj return p->data;
322*a9fa9459Szrj }
323*a9fa9459Szrj
324*a9fa9459Szrj /* Delete an entry from a hash table. This returns the value stored
325*a9fa9459Szrj for that entry, or NULL if there is no such entry. */
326*a9fa9459Szrj
327*a9fa9459Szrj void *
hash_delete(struct hash_control * table,const char * key,int freeme)328*a9fa9459Szrj hash_delete (struct hash_control *table, const char *key, int freeme)
329*a9fa9459Szrj {
330*a9fa9459Szrj struct hash_entry *p;
331*a9fa9459Szrj struct hash_entry **list;
332*a9fa9459Szrj
333*a9fa9459Szrj p = hash_lookup (table, key, strlen (key), &list, NULL);
334*a9fa9459Szrj if (p == NULL)
335*a9fa9459Szrj return NULL;
336*a9fa9459Szrj
337*a9fa9459Szrj if (p != *list)
338*a9fa9459Szrj abort ();
339*a9fa9459Szrj
340*a9fa9459Szrj #ifdef HASH_STATISTICS
341*a9fa9459Szrj ++table->deletions;
342*a9fa9459Szrj #endif
343*a9fa9459Szrj
344*a9fa9459Szrj *list = p->next;
345*a9fa9459Szrj
346*a9fa9459Szrj if (freeme)
347*a9fa9459Szrj obstack_free (&table->memory, p);
348*a9fa9459Szrj
349*a9fa9459Szrj return p->data;
350*a9fa9459Szrj }
351*a9fa9459Szrj
352*a9fa9459Szrj /* Traverse a hash table. Call the function on every entry in the
353*a9fa9459Szrj hash table. */
354*a9fa9459Szrj
355*a9fa9459Szrj void
hash_traverse(struct hash_control * table,void (* pfn)(const char * key,void * value))356*a9fa9459Szrj hash_traverse (struct hash_control *table,
357*a9fa9459Szrj void (*pfn) (const char *key, void *value))
358*a9fa9459Szrj {
359*a9fa9459Szrj unsigned int i;
360*a9fa9459Szrj
361*a9fa9459Szrj for (i = 0; i < table->size; ++i)
362*a9fa9459Szrj {
363*a9fa9459Szrj struct hash_entry *p;
364*a9fa9459Szrj
365*a9fa9459Szrj for (p = table->table[i]; p != NULL; p = p->next)
366*a9fa9459Szrj (*pfn) (p->string, p->data);
367*a9fa9459Szrj }
368*a9fa9459Szrj }
369*a9fa9459Szrj
370*a9fa9459Szrj /* Print hash table statistics on the specified file. NAME is the
371*a9fa9459Szrj name of the hash table, used for printing a header. */
372*a9fa9459Szrj
373*a9fa9459Szrj void
hash_print_statistics(FILE * f ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,struct hash_control * table ATTRIBUTE_UNUSED)374*a9fa9459Szrj hash_print_statistics (FILE *f ATTRIBUTE_UNUSED,
375*a9fa9459Szrj const char *name ATTRIBUTE_UNUSED,
376*a9fa9459Szrj struct hash_control *table ATTRIBUTE_UNUSED)
377*a9fa9459Szrj {
378*a9fa9459Szrj #ifdef HASH_STATISTICS
379*a9fa9459Szrj unsigned int i;
380*a9fa9459Szrj unsigned long total;
381*a9fa9459Szrj unsigned long empty;
382*a9fa9459Szrj
383*a9fa9459Szrj fprintf (f, "%s hash statistics:\n", name);
384*a9fa9459Szrj fprintf (f, "\t%lu lookups\n", table->lookups);
385*a9fa9459Szrj fprintf (f, "\t%lu hash comparisons\n", table->hash_compares);
386*a9fa9459Szrj fprintf (f, "\t%lu string comparisons\n", table->string_compares);
387*a9fa9459Szrj fprintf (f, "\t%lu insertions\n", table->insertions);
388*a9fa9459Szrj fprintf (f, "\t%lu replacements\n", table->replacements);
389*a9fa9459Szrj fprintf (f, "\t%lu deletions\n", table->deletions);
390*a9fa9459Szrj
391*a9fa9459Szrj total = 0;
392*a9fa9459Szrj empty = 0;
393*a9fa9459Szrj for (i = 0; i < table->size; ++i)
394*a9fa9459Szrj {
395*a9fa9459Szrj struct hash_entry *p;
396*a9fa9459Szrj
397*a9fa9459Szrj if (table->table[i] == NULL)
398*a9fa9459Szrj ++empty;
399*a9fa9459Szrj else
400*a9fa9459Szrj {
401*a9fa9459Szrj for (p = table->table[i]; p != NULL; p = p->next)
402*a9fa9459Szrj ++total;
403*a9fa9459Szrj }
404*a9fa9459Szrj }
405*a9fa9459Szrj
406*a9fa9459Szrj fprintf (f, "\t%g average chain length\n", (double) total / table->size);
407*a9fa9459Szrj fprintf (f, "\t%lu empty slots\n", empty);
408*a9fa9459Szrj #endif
409*a9fa9459Szrj }
410*a9fa9459Szrj
411*a9fa9459Szrj #ifdef TEST
412*a9fa9459Szrj
413*a9fa9459Szrj /* This test program is left over from the old hash table code. */
414*a9fa9459Szrj
415*a9fa9459Szrj /* Number of hash tables to maintain (at once) in any testing. */
416*a9fa9459Szrj #define TABLES (6)
417*a9fa9459Szrj
418*a9fa9459Szrj /* We can have 12 statistics. */
419*a9fa9459Szrj #define STATBUFSIZE (12)
420*a9fa9459Szrj
421*a9fa9459Szrj /* Display statistics here. */
422*a9fa9459Szrj int statbuf[STATBUFSIZE];
423*a9fa9459Szrj
424*a9fa9459Szrj /* Human farts here. */
425*a9fa9459Szrj char answer[100];
426*a9fa9459Szrj
427*a9fa9459Szrj /* We test many hash tables at once. */
428*a9fa9459Szrj char *hashtable[TABLES];
429*a9fa9459Szrj
430*a9fa9459Szrj /* Points to current hash_control. */
431*a9fa9459Szrj char *h;
432*a9fa9459Szrj char **pp;
433*a9fa9459Szrj char *p;
434*a9fa9459Szrj char *name;
435*a9fa9459Szrj char *value;
436*a9fa9459Szrj int size;
437*a9fa9459Szrj int used;
438*a9fa9459Szrj char command;
439*a9fa9459Szrj
440*a9fa9459Szrj /* Number 0:TABLES-1 of current hashed symbol table. */
441*a9fa9459Szrj int number;
442*a9fa9459Szrj
443*a9fa9459Szrj int
main()444*a9fa9459Szrj main ()
445*a9fa9459Szrj {
446*a9fa9459Szrj void applicatee ();
447*a9fa9459Szrj void destroy ();
448*a9fa9459Szrj char *what ();
449*a9fa9459Szrj int *ip;
450*a9fa9459Szrj
451*a9fa9459Szrj number = 0;
452*a9fa9459Szrj h = 0;
453*a9fa9459Szrj printf ("type h <RETURN> for help\n");
454*a9fa9459Szrj for (;;)
455*a9fa9459Szrj {
456*a9fa9459Szrj printf ("hash_test command: ");
457*a9fa9459Szrj gets (answer);
458*a9fa9459Szrj command = answer[0];
459*a9fa9459Szrj command = TOLOWER (command); /* Ecch! */
460*a9fa9459Szrj switch (command)
461*a9fa9459Szrj {
462*a9fa9459Szrj case '#':
463*a9fa9459Szrj printf ("old hash table #=%d.\n", number);
464*a9fa9459Szrj whattable ();
465*a9fa9459Szrj break;
466*a9fa9459Szrj case '?':
467*a9fa9459Szrj for (pp = hashtable; pp < hashtable + TABLES; pp++)
468*a9fa9459Szrj {
469*a9fa9459Szrj printf ("address of hash table #%d control block is %xx\n",
470*a9fa9459Szrj pp - hashtable, *pp);
471*a9fa9459Szrj }
472*a9fa9459Szrj break;
473*a9fa9459Szrj case 'a':
474*a9fa9459Szrj hash_traverse (h, applicatee);
475*a9fa9459Szrj break;
476*a9fa9459Szrj case 'd':
477*a9fa9459Szrj hash_traverse (h, destroy);
478*a9fa9459Szrj hash_die (h);
479*a9fa9459Szrj break;
480*a9fa9459Szrj case 'f':
481*a9fa9459Szrj p = hash_find (h, name = what ("symbol"));
482*a9fa9459Szrj printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
483*a9fa9459Szrj break;
484*a9fa9459Szrj case 'h':
485*a9fa9459Szrj printf ("# show old, select new default hash table number\n");
486*a9fa9459Szrj printf ("? display all hashtable control block addresses\n");
487*a9fa9459Szrj printf ("a apply a simple display-er to each symbol in table\n");
488*a9fa9459Szrj printf ("d die: destroy hashtable\n");
489*a9fa9459Szrj printf ("f find value of nominated symbol\n");
490*a9fa9459Szrj printf ("h this help\n");
491*a9fa9459Szrj printf ("i insert value into symbol\n");
492*a9fa9459Szrj printf ("j jam value into symbol\n");
493*a9fa9459Szrj printf ("n new hashtable\n");
494*a9fa9459Szrj printf ("r replace a value with another\n");
495*a9fa9459Szrj printf ("s say what %% of table is used\n");
496*a9fa9459Szrj printf ("q exit this program\n");
497*a9fa9459Szrj printf ("x delete a symbol from table, report its value\n");
498*a9fa9459Szrj break;
499*a9fa9459Szrj case 'i':
500*a9fa9459Szrj p = hash_insert (h, name = what ("symbol"), value = what ("value"));
501*a9fa9459Szrj if (p)
502*a9fa9459Szrj {
503*a9fa9459Szrj printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value,
504*a9fa9459Szrj p);
505*a9fa9459Szrj }
506*a9fa9459Szrj break;
507*a9fa9459Szrj case 'j':
508*a9fa9459Szrj p = hash_jam (h, name = what ("symbol"), value = what ("value"));
509*a9fa9459Szrj if (p)
510*a9fa9459Szrj {
511*a9fa9459Szrj printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
512*a9fa9459Szrj }
513*a9fa9459Szrj break;
514*a9fa9459Szrj case 'n':
515*a9fa9459Szrj h = hashtable[number] = (char *) hash_new ();
516*a9fa9459Szrj break;
517*a9fa9459Szrj case 'q':
518*a9fa9459Szrj exit (EXIT_SUCCESS);
519*a9fa9459Szrj case 'r':
520*a9fa9459Szrj p = hash_replace (h, name = what ("symbol"), value = what ("value"));
521*a9fa9459Szrj printf ("old value was \"%s\"\n", p ? p : "{}");
522*a9fa9459Szrj break;
523*a9fa9459Szrj case 's':
524*a9fa9459Szrj hash_say (h, statbuf, STATBUFSIZE);
525*a9fa9459Szrj for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
526*a9fa9459Szrj {
527*a9fa9459Szrj printf ("%d ", *ip);
528*a9fa9459Szrj }
529*a9fa9459Szrj printf ("\n");
530*a9fa9459Szrj break;
531*a9fa9459Szrj case 'x':
532*a9fa9459Szrj p = hash_delete (h, name = what ("symbol"));
533*a9fa9459Szrj printf ("old value was \"%s\"\n", p ? p : "{}");
534*a9fa9459Szrj break;
535*a9fa9459Szrj default:
536*a9fa9459Szrj printf ("I can't understand command \"%c\"\n", command);
537*a9fa9459Szrj break;
538*a9fa9459Szrj }
539*a9fa9459Szrj }
540*a9fa9459Szrj }
541*a9fa9459Szrj
542*a9fa9459Szrj char *
what(description)543*a9fa9459Szrj what (description)
544*a9fa9459Szrj char *description;
545*a9fa9459Szrj {
546*a9fa9459Szrj printf (" %s : ", description);
547*a9fa9459Szrj gets (answer);
548*a9fa9459Szrj return xstrdup (answer);
549*a9fa9459Szrj }
550*a9fa9459Szrj
551*a9fa9459Szrj void
destroy(string,value)552*a9fa9459Szrj destroy (string, value)
553*a9fa9459Szrj char *string;
554*a9fa9459Szrj char *value;
555*a9fa9459Szrj {
556*a9fa9459Szrj free (string);
557*a9fa9459Szrj free (value);
558*a9fa9459Szrj }
559*a9fa9459Szrj
560*a9fa9459Szrj void
applicatee(string,value)561*a9fa9459Szrj applicatee (string, value)
562*a9fa9459Szrj char *string;
563*a9fa9459Szrj char *value;
564*a9fa9459Szrj {
565*a9fa9459Szrj printf ("%.20s-%.20s\n", string, value);
566*a9fa9459Szrj }
567*a9fa9459Szrj
568*a9fa9459Szrj /* Determine number: what hash table to use.
569*a9fa9459Szrj Also determine h: points to hash_control. */
570*a9fa9459Szrj
571*a9fa9459Szrj void
whattable()572*a9fa9459Szrj whattable ()
573*a9fa9459Szrj {
574*a9fa9459Szrj for (;;)
575*a9fa9459Szrj {
576*a9fa9459Szrj printf (" what hash table (%d:%d) ? ", 0, TABLES - 1);
577*a9fa9459Szrj gets (answer);
578*a9fa9459Szrj sscanf (answer, "%d", &number);
579*a9fa9459Szrj if (number >= 0 && number < TABLES)
580*a9fa9459Szrj {
581*a9fa9459Szrj h = hashtable[number];
582*a9fa9459Szrj if (!h)
583*a9fa9459Szrj {
584*a9fa9459Szrj printf ("warning: current hash-table-#%d. has no hash-control\n", number);
585*a9fa9459Szrj }
586*a9fa9459Szrj return;
587*a9fa9459Szrj }
588*a9fa9459Szrj else
589*a9fa9459Szrj {
590*a9fa9459Szrj printf ("invalid hash table number: %d\n", number);
591*a9fa9459Szrj }
592*a9fa9459Szrj }
593*a9fa9459Szrj }
594*a9fa9459Szrj
595*a9fa9459Szrj #endif /* TEST */
596