1b305b0f1Sespie /* hash.c -- gas hash table code
2b55d4692Sfgsch Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
3c074d1c9Sdrahn 2000, 2001, 2002
40c6d0228Sniklas Free Software Foundation, Inc.
52159047fSniklas
62159047fSniklas This file is part of GAS, the GNU Assembler.
72159047fSniklas
82159047fSniklas GAS is free software; you can redistribute it and/or modify
92159047fSniklas it under the terms of the GNU General Public License as published by
102159047fSniklas the Free Software Foundation; either version 2, or (at your option)
112159047fSniklas any later version.
122159047fSniklas
132159047fSniklas GAS is distributed in the hope that it will be useful,
142159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
152159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
162159047fSniklas GNU General Public License for more details.
172159047fSniklas
182159047fSniklas You should have received a copy of the GNU General Public License
19b305b0f1Sespie along with GAS; see the file COPYING. If not, write to the Free
20b305b0f1Sespie Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21b305b0f1Sespie 02111-1307, USA. */
222159047fSniklas
23b305b0f1Sespie /* This version of the hash table code is a wholescale replacement of
24b305b0f1Sespie the old hash table code, which was fairly bad. This is based on
25b305b0f1Sespie the hash table code in BFD, but optimized slightly for the
26*007c2a45Smiod assembler. The assembler does not need to derive structures that
27b305b0f1Sespie are stored in the hash table. Instead, it always stores a pointer.
28b305b0f1Sespie The assembler uses the hash table mostly to store symbols, and we
29b305b0f1Sespie don't need to confuse the symbol structure with a hash table
30b305b0f1Sespie structure. */
312159047fSniklas
322159047fSniklas #include "as.h"
33c074d1c9Sdrahn #include "safe-ctype.h"
34b305b0f1Sespie #include "obstack.h"
352159047fSniklas
36b305b0f1Sespie /* The default number of entries to use when creating a hash table. */
372159047fSniklas
38b305b0f1Sespie #define DEFAULT_SIZE (4051)
392159047fSniklas
40b305b0f1Sespie /* An entry in a hash table. */
412159047fSniklas
42b55d4692Sfgsch struct hash_entry {
43b305b0f1Sespie /* Next entry for this hash code. */
44b305b0f1Sespie struct hash_entry *next;
45b305b0f1Sespie /* String being hashed. */
46b305b0f1Sespie const char *string;
47b305b0f1Sespie /* Hash code. This is the full hash code, not the index into the
48b305b0f1Sespie table. */
49b305b0f1Sespie unsigned long hash;
50b305b0f1Sespie /* Pointer being stored in the hash table. */
51b305b0f1Sespie PTR data;
52191aa565Sniklas };
53191aa565Sniklas
54b305b0f1Sespie /* A hash table. */
55b305b0f1Sespie
56b55d4692Sfgsch struct hash_control {
57b305b0f1Sespie /* The hash array. */
58b305b0f1Sespie struct hash_entry **table;
59b305b0f1Sespie /* The number of slots in the hash table. */
60b305b0f1Sespie unsigned int size;
61b305b0f1Sespie /* An obstack for this hash table. */
62b305b0f1Sespie struct obstack memory;
63b305b0f1Sespie
64b305b0f1Sespie #ifdef HASH_STATISTICS
65b305b0f1Sespie /* Statistics. */
66b305b0f1Sespie unsigned long lookups;
67b305b0f1Sespie unsigned long hash_compares;
68b305b0f1Sespie unsigned long string_compares;
69b305b0f1Sespie unsigned long insertions;
70b305b0f1Sespie unsigned long replacements;
71b305b0f1Sespie unsigned long deletions;
72b305b0f1Sespie #endif /* HASH_STATISTICS */
73191aa565Sniklas };
742159047fSniklas
75b305b0f1Sespie /* Create a hash table. This return a control block. */
762159047fSniklas
772159047fSniklas struct hash_control *
hash_new(void)78*007c2a45Smiod hash_new (void)
792159047fSniklas {
80b305b0f1Sespie unsigned int size;
81b305b0f1Sespie struct hash_control *ret;
82b305b0f1Sespie unsigned int alloc;
832159047fSniklas
84b305b0f1Sespie size = DEFAULT_SIZE;
852159047fSniklas
86b305b0f1Sespie ret = (struct hash_control *) xmalloc (sizeof *ret);
87b305b0f1Sespie obstack_begin (&ret->memory, chunksize);
88b305b0f1Sespie alloc = size * sizeof (struct hash_entry *);
89b305b0f1Sespie ret->table = (struct hash_entry **) obstack_alloc (&ret->memory, alloc);
90b305b0f1Sespie memset (ret->table, 0, alloc);
91b305b0f1Sespie ret->size = size;
922159047fSniklas
93b305b0f1Sespie #ifdef HASH_STATISTICS
94b305b0f1Sespie ret->lookups = 0;
95b305b0f1Sespie ret->hash_compares = 0;
96b305b0f1Sespie ret->string_compares = 0;
97b305b0f1Sespie ret->insertions = 0;
98b305b0f1Sespie ret->replacements = 0;
99b305b0f1Sespie ret->deletions = 0;
100b305b0f1Sespie #endif
101b305b0f1Sespie
102b305b0f1Sespie return ret;
1032159047fSniklas }
1042159047fSniklas
105b305b0f1Sespie /* Delete a hash table, freeing all allocated memory. */
106b305b0f1Sespie
1072159047fSniklas void
hash_die(struct hash_control * table)108*007c2a45Smiod hash_die (struct hash_control *table)
1092159047fSniklas {
110b305b0f1Sespie obstack_free (&table->memory, 0);
111b305b0f1Sespie free (table);
1122159047fSniklas }
1132159047fSniklas
114b305b0f1Sespie /* Look up a string in a hash table. This returns a pointer to the
115b305b0f1Sespie hash_entry, or NULL if the string is not in the table. If PLIST is
116b305b0f1Sespie not NULL, this sets *PLIST to point to the start of the list which
117b305b0f1Sespie would hold this hash entry. If PHASH is not NULL, this sets *PHASH
118b305b0f1Sespie to the hash code for KEY.
119b305b0f1Sespie
120b305b0f1Sespie Each time we look up a string, we move it to the start of the list
121b305b0f1Sespie for its hash code, to take advantage of referential locality. */
122b305b0f1Sespie
123*007c2a45Smiod static struct hash_entry *hash_lookup (struct hash_control *,
124b305b0f1Sespie const char *,
125b305b0f1Sespie struct hash_entry ***,
126*007c2a45Smiod unsigned long *);
127b305b0f1Sespie
128b305b0f1Sespie static struct hash_entry *
hash_lookup(struct hash_control * table,const char * key,struct hash_entry *** plist,unsigned long * phash)129*007c2a45Smiod hash_lookup (struct hash_control *table, const char *key,
130*007c2a45Smiod struct hash_entry ***plist, unsigned long *phash)
1312159047fSniklas {
132b305b0f1Sespie register unsigned long hash;
133b305b0f1Sespie unsigned int len;
134b305b0f1Sespie register const unsigned char *s;
135b305b0f1Sespie register unsigned int c;
136b305b0f1Sespie unsigned int index;
137b305b0f1Sespie struct hash_entry **list;
138b305b0f1Sespie struct hash_entry *p;
139b305b0f1Sespie struct hash_entry *prev;
140b305b0f1Sespie
141b305b0f1Sespie #ifdef HASH_STATISTICS
142b305b0f1Sespie ++table->lookups;
1432159047fSniklas #endif
1442159047fSniklas
145b305b0f1Sespie hash = 0;
146b305b0f1Sespie len = 0;
147b305b0f1Sespie s = (const unsigned char *) key;
148b305b0f1Sespie while ((c = *s++) != '\0')
1492159047fSniklas {
150b305b0f1Sespie hash += c + (c << 17);
151b305b0f1Sespie hash ^= hash >> 2;
1522159047fSniklas ++len;
1532159047fSniklas }
154b305b0f1Sespie hash += len + (len << 17);
155b305b0f1Sespie hash ^= hash >> 2;
156b305b0f1Sespie
157b305b0f1Sespie if (phash != NULL)
158b305b0f1Sespie *phash = hash;
159b305b0f1Sespie
160b305b0f1Sespie index = hash % table->size;
161b305b0f1Sespie list = table->table + index;
162b305b0f1Sespie
163b305b0f1Sespie if (plist != NULL)
164b305b0f1Sespie *plist = list;
165b305b0f1Sespie
166b305b0f1Sespie prev = NULL;
167b305b0f1Sespie for (p = *list; p != NULL; p = p->next)
168b305b0f1Sespie {
169b305b0f1Sespie #ifdef HASH_STATISTICS
170b305b0f1Sespie ++table->hash_compares;
171b305b0f1Sespie #endif
172b305b0f1Sespie
173b305b0f1Sespie if (p->hash == hash)
174b305b0f1Sespie {
175b305b0f1Sespie #ifdef HASH_STATISTICS
176b305b0f1Sespie ++table->string_compares;
177b305b0f1Sespie #endif
178b305b0f1Sespie
179b305b0f1Sespie if (strcmp (p->string, key) == 0)
180b305b0f1Sespie {
181b305b0f1Sespie if (prev != NULL)
182b305b0f1Sespie {
183b305b0f1Sespie prev->next = p->next;
184b305b0f1Sespie p->next = *list;
185b305b0f1Sespie *list = p;
186b305b0f1Sespie }
187b305b0f1Sespie
188b305b0f1Sespie return p;
189b305b0f1Sespie }
190b305b0f1Sespie }
191b305b0f1Sespie
192b305b0f1Sespie prev = p;
193b305b0f1Sespie }
194b305b0f1Sespie
195b305b0f1Sespie return NULL;
196b305b0f1Sespie }
197b305b0f1Sespie
198b305b0f1Sespie /* Insert an entry into a hash table. This returns NULL on success.
199b305b0f1Sespie On error, it returns a printable string indicating the error. It
200b305b0f1Sespie is considered to be an error if the entry already exists in the
201b305b0f1Sespie hash table. */
202b305b0f1Sespie
203b305b0f1Sespie const char *
hash_insert(struct hash_control * table,const char * key,PTR value)204*007c2a45Smiod hash_insert (struct hash_control *table, const char *key, PTR value)
205b305b0f1Sespie {
206b305b0f1Sespie struct hash_entry *p;
207b305b0f1Sespie struct hash_entry **list;
208b305b0f1Sespie unsigned long hash;
209b305b0f1Sespie
210b305b0f1Sespie p = hash_lookup (table, key, &list, &hash);
211b305b0f1Sespie if (p != NULL)
212b305b0f1Sespie return "exists";
213b305b0f1Sespie
214b305b0f1Sespie #ifdef HASH_STATISTICS
215b305b0f1Sespie ++table->insertions;
216b305b0f1Sespie #endif
217b305b0f1Sespie
218b55d4692Sfgsch p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
219b305b0f1Sespie p->string = key;
220b305b0f1Sespie p->hash = hash;
221b305b0f1Sespie p->data = value;
222b305b0f1Sespie
223b305b0f1Sespie p->next = *list;
224b305b0f1Sespie *list = p;
225b305b0f1Sespie
226b305b0f1Sespie return NULL;
227b305b0f1Sespie }
228b305b0f1Sespie
229b305b0f1Sespie /* Insert or replace an entry in a hash table. This returns NULL on
230b305b0f1Sespie success. On error, it returns a printable string indicating the
231b305b0f1Sespie error. If an entry already exists, its value is replaced. */
232b305b0f1Sespie
233b305b0f1Sespie const char *
hash_jam(struct hash_control * table,const char * key,PTR value)234*007c2a45Smiod hash_jam (struct hash_control *table, const char *key, PTR value)
235b305b0f1Sespie {
236b305b0f1Sespie struct hash_entry *p;
237b305b0f1Sespie struct hash_entry **list;
238b305b0f1Sespie unsigned long hash;
239b305b0f1Sespie
240b305b0f1Sespie p = hash_lookup (table, key, &list, &hash);
241b305b0f1Sespie if (p != NULL)
242b305b0f1Sespie {
243b305b0f1Sespie #ifdef HASH_STATISTICS
244b305b0f1Sespie ++table->replacements;
245b305b0f1Sespie #endif
246b305b0f1Sespie
247b305b0f1Sespie p->data = value;
248b305b0f1Sespie }
249b305b0f1Sespie else
250b305b0f1Sespie {
251b305b0f1Sespie #ifdef HASH_STATISTICS
252b305b0f1Sespie ++table->insertions;
253b305b0f1Sespie #endif
254b305b0f1Sespie
255b55d4692Sfgsch p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
256b305b0f1Sespie p->string = key;
257b305b0f1Sespie p->hash = hash;
258b305b0f1Sespie p->data = value;
259b305b0f1Sespie
260b305b0f1Sespie p->next = *list;
261b305b0f1Sespie *list = p;
262b305b0f1Sespie }
263b305b0f1Sespie
264b305b0f1Sespie return NULL;
265b305b0f1Sespie }
266b305b0f1Sespie
267b305b0f1Sespie /* Replace an existing entry in a hash table. This returns the old
268b305b0f1Sespie value stored for the entry. If the entry is not found in the hash
269b305b0f1Sespie table, this does nothing and returns NULL. */
270b305b0f1Sespie
271b305b0f1Sespie PTR
hash_replace(struct hash_control * table,const char * key,PTR value)272*007c2a45Smiod hash_replace (struct hash_control *table, const char *key, PTR value)
273b305b0f1Sespie {
274b305b0f1Sespie struct hash_entry *p;
275b305b0f1Sespie PTR ret;
276b305b0f1Sespie
277b305b0f1Sespie p = hash_lookup (table, key, NULL, NULL);
278b305b0f1Sespie if (p == NULL)
279b305b0f1Sespie return NULL;
280b305b0f1Sespie
281b305b0f1Sespie #ifdef HASH_STATISTICS
282b305b0f1Sespie ++table->replacements;
283b305b0f1Sespie #endif
284b305b0f1Sespie
285b305b0f1Sespie ret = p->data;
286b305b0f1Sespie
287b305b0f1Sespie p->data = value;
288b305b0f1Sespie
289b305b0f1Sespie return ret;
290b305b0f1Sespie }
291b305b0f1Sespie
292b305b0f1Sespie /* Find an entry in a hash table, returning its value. Returns NULL
293b305b0f1Sespie if the entry is not found. */
294b305b0f1Sespie
295b305b0f1Sespie PTR
hash_find(struct hash_control * table,const char * key)296*007c2a45Smiod hash_find (struct hash_control *table, const char *key)
297b305b0f1Sespie {
298b305b0f1Sespie struct hash_entry *p;
299b305b0f1Sespie
300b305b0f1Sespie p = hash_lookup (table, key, NULL, NULL);
301b305b0f1Sespie if (p == NULL)
302b305b0f1Sespie return NULL;
303b305b0f1Sespie
304b305b0f1Sespie return p->data;
305b305b0f1Sespie }
306b305b0f1Sespie
307b305b0f1Sespie /* Delete an entry from a hash table. This returns the value stored
308b305b0f1Sespie for that entry, or NULL if there is no such entry. */
309b305b0f1Sespie
310b305b0f1Sespie PTR
hash_delete(struct hash_control * table,const char * key)311*007c2a45Smiod hash_delete (struct hash_control *table, const char *key)
312b305b0f1Sespie {
313b305b0f1Sespie struct hash_entry *p;
314b305b0f1Sespie struct hash_entry **list;
315b305b0f1Sespie
316b305b0f1Sespie p = hash_lookup (table, key, &list, NULL);
317b305b0f1Sespie if (p == NULL)
318b305b0f1Sespie return NULL;
319b305b0f1Sespie
320b305b0f1Sespie if (p != *list)
321b305b0f1Sespie abort ();
322b305b0f1Sespie
323b305b0f1Sespie #ifdef HASH_STATISTICS
324b305b0f1Sespie ++table->deletions;
325b305b0f1Sespie #endif
326b305b0f1Sespie
327b305b0f1Sespie *list = p->next;
328b305b0f1Sespie
329b305b0f1Sespie /* Note that we never reclaim the memory for this entry. If gas
330b305b0f1Sespie ever starts deleting hash table entries in a big way, this will
331b305b0f1Sespie have to change. */
332b305b0f1Sespie
333b305b0f1Sespie return p->data;
334b305b0f1Sespie }
335b305b0f1Sespie
336b305b0f1Sespie /* Traverse a hash table. Call the function on every entry in the
337b305b0f1Sespie hash table. */
338b305b0f1Sespie
339b305b0f1Sespie void
hash_traverse(struct hash_control * table,void (* pfn)(const char * key,PTR value))340*007c2a45Smiod hash_traverse (struct hash_control *table,
341*007c2a45Smiod void (*pfn) (const char *key, PTR value))
342b305b0f1Sespie {
343b305b0f1Sespie unsigned int i;
344b305b0f1Sespie
345b305b0f1Sespie for (i = 0; i < table->size; ++i)
346b305b0f1Sespie {
347b305b0f1Sespie struct hash_entry *p;
348b305b0f1Sespie
349b305b0f1Sespie for (p = table->table[i]; p != NULL; p = p->next)
350b305b0f1Sespie (*pfn) (p->string, p->data);
351b305b0f1Sespie }
352b305b0f1Sespie }
353b305b0f1Sespie
354b305b0f1Sespie /* Print hash table statistics on the specified file. NAME is the
355b305b0f1Sespie name of the hash table, used for printing a header. */
356b305b0f1Sespie
357b305b0f1Sespie void
hash_print_statistics(FILE * f ATTRIBUTE_UNUSED,const char * name ATTRIBUTE_UNUSED,struct hash_control * table ATTRIBUTE_UNUSED)358*007c2a45Smiod hash_print_statistics (FILE *f ATTRIBUTE_UNUSED,
359*007c2a45Smiod const char *name ATTRIBUTE_UNUSED,
360*007c2a45Smiod struct hash_control *table ATTRIBUTE_UNUSED)
361b305b0f1Sespie {
362b305b0f1Sespie #ifdef HASH_STATISTICS
363b305b0f1Sespie unsigned int i;
364b305b0f1Sespie unsigned long total;
365b305b0f1Sespie unsigned long empty;
366b305b0f1Sespie
367b305b0f1Sespie fprintf (f, "%s hash statistics:\n", name);
368b305b0f1Sespie fprintf (f, "\t%lu lookups\n", table->lookups);
369b305b0f1Sespie fprintf (f, "\t%lu hash comparisons\n", table->hash_compares);
370b305b0f1Sespie fprintf (f, "\t%lu string comparisons\n", table->string_compares);
371b305b0f1Sespie fprintf (f, "\t%lu insertions\n", table->insertions);
372b305b0f1Sespie fprintf (f, "\t%lu replacements\n", table->replacements);
373b305b0f1Sespie fprintf (f, "\t%lu deletions\n", table->deletions);
374b305b0f1Sespie
375b305b0f1Sespie total = 0;
376b305b0f1Sespie empty = 0;
377b305b0f1Sespie for (i = 0; i < table->size; ++i)
378b305b0f1Sespie {
379b305b0f1Sespie struct hash_entry *p;
380b305b0f1Sespie
381b305b0f1Sespie if (table->table[i] == NULL)
382b305b0f1Sespie ++empty;
383b305b0f1Sespie else
384b305b0f1Sespie {
385b305b0f1Sespie for (p = table->table[i]; p != NULL; p = p->next)
386b305b0f1Sespie ++total;
387b305b0f1Sespie }
388b305b0f1Sespie }
389b305b0f1Sespie
390b305b0f1Sespie fprintf (f, "\t%g average chain length\n", (double) total / table->size);
391b305b0f1Sespie fprintf (f, "\t%lu empty slots\n", empty);
3922159047fSniklas #endif
3932159047fSniklas }
3942159047fSniklas
3952159047fSniklas #ifdef TEST
3962159047fSniklas
397b305b0f1Sespie /* This test program is left over from the old hash table code. */
398b305b0f1Sespie
399b55d4692Sfgsch /* Number of hash tables to maintain (at once) in any testing. */
400b55d4692Sfgsch #define TABLES (6)
4012159047fSniklas
402b55d4692Sfgsch /* We can have 12 statistics. */
403b55d4692Sfgsch #define STATBUFSIZE (12)
404b55d4692Sfgsch
405b55d4692Sfgsch /* Display statistics here. */
406b55d4692Sfgsch int statbuf[STATBUFSIZE];
407b55d4692Sfgsch
408b55d4692Sfgsch /* Human farts here. */
409b55d4692Sfgsch char answer[100];
410b55d4692Sfgsch
411b55d4692Sfgsch /* We test many hash tables at once. */
412b55d4692Sfgsch char *hashtable[TABLES];
413b55d4692Sfgsch
414*007c2a45Smiod /* Points to current hash_control. */
415b55d4692Sfgsch char *h;
4162159047fSniklas char **pp;
4172159047fSniklas char *p;
4182159047fSniklas char *name;
4192159047fSniklas char *value;
4202159047fSniklas int size;
4212159047fSniklas int used;
4222159047fSniklas char command;
423b55d4692Sfgsch
424b55d4692Sfgsch /* Number 0:TABLES-1 of current hashed symbol table. */
425b55d4692Sfgsch int number;
4262159047fSniklas
427b305b0f1Sespie int
main()4282159047fSniklas main ()
4292159047fSniklas {
430191aa565Sniklas void applicatee ();
431191aa565Sniklas void destroy ();
4322159047fSniklas char *what ();
4332159047fSniklas int *ip;
4342159047fSniklas
4352159047fSniklas number = 0;
4362159047fSniklas h = 0;
4372159047fSniklas printf ("type h <RETURN> for help\n");
4382159047fSniklas for (;;)
4392159047fSniklas {
4402159047fSniklas printf ("hash_test command: ");
4412159047fSniklas gets (answer);
4422159047fSniklas command = answer[0];
443c074d1c9Sdrahn command = TOLOWER (command); /* Ecch! */
4442159047fSniklas switch (command)
4452159047fSniklas {
4462159047fSniklas case '#':
4472159047fSniklas printf ("old hash table #=%d.\n", number);
4482159047fSniklas whattable ();
4492159047fSniklas break;
4502159047fSniklas case '?':
4512159047fSniklas for (pp = hashtable; pp < hashtable + TABLES; pp++)
4522159047fSniklas {
453b55d4692Sfgsch printf ("address of hash table #%d control block is %xx\n",
454b55d4692Sfgsch pp - hashtable, *pp);
4552159047fSniklas }
4562159047fSniklas break;
4572159047fSniklas case 'a':
458b305b0f1Sespie hash_traverse (h, applicatee);
4592159047fSniklas break;
4602159047fSniklas case 'd':
461b305b0f1Sespie hash_traverse (h, destroy);
4622159047fSniklas hash_die (h);
4632159047fSniklas break;
4642159047fSniklas case 'f':
4652159047fSniklas p = hash_find (h, name = what ("symbol"));
4662159047fSniklas printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
4672159047fSniklas break;
4682159047fSniklas case 'h':
4692159047fSniklas printf ("# show old, select new default hash table number\n");
4702159047fSniklas printf ("? display all hashtable control block addresses\n");
4712159047fSniklas printf ("a apply a simple display-er to each symbol in table\n");
4722159047fSniklas printf ("d die: destroy hashtable\n");
4732159047fSniklas printf ("f find value of nominated symbol\n");
4742159047fSniklas printf ("h this help\n");
4752159047fSniklas printf ("i insert value into symbol\n");
4762159047fSniklas printf ("j jam value into symbol\n");
4772159047fSniklas printf ("n new hashtable\n");
4782159047fSniklas printf ("r replace a value with another\n");
4792159047fSniklas printf ("s say what %% of table is used\n");
4802159047fSniklas printf ("q exit this program\n");
4812159047fSniklas printf ("x delete a symbol from table, report its value\n");
4822159047fSniklas break;
4832159047fSniklas case 'i':
4842159047fSniklas p = hash_insert (h, name = what ("symbol"), value = what ("value"));
4852159047fSniklas if (p)
4862159047fSniklas {
4872159047fSniklas printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value,
4882159047fSniklas p);
4892159047fSniklas }
4902159047fSniklas break;
4912159047fSniklas case 'j':
4922159047fSniklas p = hash_jam (h, name = what ("symbol"), value = what ("value"));
4932159047fSniklas if (p)
4942159047fSniklas {
4952159047fSniklas printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
4962159047fSniklas }
4972159047fSniklas break;
4982159047fSniklas case 'n':
4992159047fSniklas h = hashtable[number] = (char *) hash_new ();
5002159047fSniklas break;
5012159047fSniklas case 'q':
5022159047fSniklas exit (EXIT_SUCCESS);
5032159047fSniklas case 'r':
5042159047fSniklas p = hash_replace (h, name = what ("symbol"), value = what ("value"));
5052159047fSniklas printf ("old value was \"%s\"\n", p ? p : "{}");
5062159047fSniklas break;
5072159047fSniklas case 's':
5082159047fSniklas hash_say (h, statbuf, STATBUFSIZE);
5092159047fSniklas for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
5102159047fSniklas {
5112159047fSniklas printf ("%d ", *ip);
5122159047fSniklas }
5132159047fSniklas printf ("\n");
5142159047fSniklas break;
5152159047fSniklas case 'x':
5162159047fSniklas p = hash_delete (h, name = what ("symbol"));
5172159047fSniklas printf ("old value was \"%s\"\n", p ? p : "{}");
5182159047fSniklas break;
5192159047fSniklas default:
5202159047fSniklas printf ("I can't understand command \"%c\"\n", command);
5212159047fSniklas break;
5222159047fSniklas }
5232159047fSniklas }
5242159047fSniklas }
5252159047fSniklas
5262159047fSniklas char *
what(description)5272159047fSniklas what (description)
5282159047fSniklas char *description;
5292159047fSniklas {
5302159047fSniklas printf (" %s : ", description);
5312159047fSniklas gets (answer);
532c074d1c9Sdrahn return xstrdup (answer);
5332159047fSniklas }
5342159047fSniklas
535191aa565Sniklas void
destroy(string,value)5362159047fSniklas destroy (string, value)
5372159047fSniklas char *string;
5382159047fSniklas char *value;
5392159047fSniklas {
5402159047fSniklas free (string);
5412159047fSniklas free (value);
5422159047fSniklas }
5432159047fSniklas
544191aa565Sniklas void
applicatee(string,value)5452159047fSniklas applicatee (string, value)
5462159047fSniklas char *string;
5472159047fSniklas char *value;
5482159047fSniklas {
5492159047fSniklas printf ("%.20s-%.20s\n", string, value);
5502159047fSniklas }
5512159047fSniklas
552b55d4692Sfgsch /* Determine number: what hash table to use.
553b55d4692Sfgsch Also determine h: points to hash_control. */
5542159047fSniklas
555b55d4692Sfgsch void
whattable()556b55d4692Sfgsch whattable ()
557b55d4692Sfgsch {
5582159047fSniklas for (;;)
5592159047fSniklas {
5602159047fSniklas printf (" what hash table (%d:%d) ? ", 0, TABLES - 1);
5612159047fSniklas gets (answer);
5622159047fSniklas sscanf (answer, "%d", &number);
5632159047fSniklas if (number >= 0 && number < TABLES)
5642159047fSniklas {
5652159047fSniklas h = hashtable[number];
5662159047fSniklas if (!h)
5672159047fSniklas {
5682159047fSniklas printf ("warning: current hash-table-#%d. has no hash-control\n", number);
5692159047fSniklas }
5702159047fSniklas return;
5712159047fSniklas }
5722159047fSniklas else
5732159047fSniklas {
5742159047fSniklas printf ("invalid hash table number: %d\n", number);
5752159047fSniklas }
5762159047fSniklas }
5772159047fSniklas }
5782159047fSniklas
579b55d4692Sfgsch #endif /* TEST */
580