xref: /dflybsd-src/contrib/binutils-2.27/gas/hash.c (revision e656dc90e3d65d744d534af2f5ea88cf8101ebcf)
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