1 /* hashlib.c -- functions to manage and access hash tables for bash. */
3 /* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 1, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
25 #if defined (HAVE_UNISTD_H)
27 # include <sys/types.h>
37 /* Zero the buckets in TABLE. */
39 initialize_hash_table (table)
43 for (i = 0; i < table->nbuckets; i++)
44 table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
47 /* Make a new hash table with BUCKETS number of buckets. Initialize
48 each slot in the table to NULL. */
50 make_hash_table (buckets)
53 HASH_TABLE *new_table;
55 new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE));
57 buckets = DEFAULT_HASH_BUCKETS;
59 new_table->bucket_array =
60 (BUCKET_CONTENTS **)xmalloc (buckets * sizeof (BUCKET_CONTENTS *));
61 new_table->nbuckets = buckets;
62 new_table->nentries = 0;
63 initialize_hash_table (new_table);
67 /* Return the location of the bucket which should contain the data
68 for STRING. TABLE is a pointer to a HASH_TABLE. */
70 #define ALL_ONES (~((unsigned long) 0))
71 #define BITS(h, n) ((unsigned long)(h) & ~(ALL_ONES << (n)))
74 hash_string (string, table)
78 register unsigned int i = 0;
81 i = (i << 2) + *string++;
83 return (BITS (i, 31) % table->nbuckets);
86 /* Return a pointer to the hashed item, or NULL if the item
89 find_hash_item (string, table)
93 BUCKET_CONTENTS *list;
97 return (BUCKET_CONTENTS *)NULL;
99 which_bucket = hash_string (string, table);
101 for (list = table->bucket_array[which_bucket]; list; list = list->next)
103 if (STREQ (list->key, string))
109 return (BUCKET_CONTENTS *)NULL;
112 /* Remove the item specified by STRING from the hash table TABLE.
113 The item removed is returned, so you can free its contents. If
114 the item isn't in this table NULL is returned. */
116 remove_hash_item (string, table)
121 BUCKET_CONTENTS *prev, *temp;
124 return (BUCKET_CONTENTS *)NULL;
126 the_bucket = hash_string (string, table);
127 prev = (BUCKET_CONTENTS *)NULL;
128 for (temp = table->bucket_array[the_bucket]; temp; temp = temp->next)
130 if (STREQ (temp->key, string))
133 prev->next = temp->next;
135 table->bucket_array[the_bucket] = temp->next;
142 return ((BUCKET_CONTENTS *) NULL);
145 /* Create an entry for STRING, in TABLE. If the entry already
146 exists, then return it. */
148 add_hash_item (string, table)
152 BUCKET_CONTENTS *item;
156 table = make_hash_table (0);
158 if ((item = find_hash_item (string, table)) == 0)
160 bucket = hash_string (string, table);
161 item = table->bucket_array[bucket];
163 while (item && item->next)
168 item->next = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
173 table->bucket_array[bucket] =
174 (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
175 item = table->bucket_array[bucket];
178 item->data = (char *)NULL;
179 item->next = (BUCKET_CONTENTS *)NULL;
182 item->times_found = 0;
188 /* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it
189 is a function to call to dispose of a hash item's data. Otherwise,
192 flush_hash_table (table, free_data)
194 VFunction *free_data;
197 register BUCKET_CONTENTS *bucket, *item;
202 for (i = 0; i < table->nbuckets; i++)
204 bucket = table->bucket_array[i];
209 bucket = bucket->next;
212 (*free_data) (item->data);
218 table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
222 /* Free the hash table pointed to by TABLE. */
224 dispose_hash_table (table)
227 free (table->bucket_array);
231 /* No longer necessary; everything uses the macro */
233 /* Return the bucket_contents list of bucket BUCKET in TABLE. If
234 TABLE doesn't have BUCKET buckets, return NULL. */
235 #undef get_hash_bucket
237 get_hash_bucket (bucket, table)
241 if (table && bucket < table->nbuckets)
242 return (table->bucket_array[bucket]);
244 return (BUCKET_CONTENTS *)NULL;
250 print_table_stats (table, name)
254 register int slot, bcount;
255 register BUCKET_CONTENTS *bc;
258 name = "unknown hash table";
260 fprintf (stderr, "%s: %d buckets; %d items\n", name, table->nbuckets, table->nentries);
262 /* Print out a count of how many strings hashed to each bucket, so we can
263 see how even the distribution is. */
264 for (slot = 0; slot < table->nbuckets; slot++)
266 bc = get_hash_bucket (slot, table);
268 fprintf (stderr, "\tslot %3d: ", slot);
269 for (bcount = 0; bc; bc = bc->next)
272 fprintf (stderr, "%d\n", bcount);
289 char *result = (char *)malloc (bytes);
292 fprintf (stderr, "hash: out of virtual memory\n");
304 table = make_hash_table (NBUCKETS);
309 if (fgets (string, sizeof (string), stdin) == 0)
313 temp_string = savestring (string);
314 tt = add_hash_item (temp_string, table);
317 fprintf (stderr, "You have already added item `%s'\n", string);
326 print_table_stats (table, "hash test");
330 #endif /* TEST_HASHING */