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