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)
34 /* Zero the buckets in TABLE. */
36 initialize_hash_table (table)
40 for (i = 0; i < table->nbuckets; i++)
41 table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
44 /* Make a new hash table with BUCKETS number of buckets. Initialize
45 each slot in the table to NULL. */
47 make_hash_table (buckets)
50 HASH_TABLE *new_table;
52 new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE));
54 buckets = DEFAULT_HASH_BUCKETS;
56 new_table->bucket_array =
57 (BUCKET_CONTENTS **)xmalloc (buckets * sizeof (BUCKET_CONTENTS *));
58 new_table->nbuckets = buckets;
59 new_table->nentries = 0;
60 initialize_hash_table (new_table);
64 /* Return the location of the bucket which should contain the data
65 for STRING. TABLE is a pointer to a HASH_TABLE. */
67 #define ALL_ONES (~((unsigned long) 0))
68 #define BITS(h, n) ((unsigned long)(h) & ~(ALL_ONES << (n)))
71 hash_string (string, table)
75 register unsigned int i = 0;
78 i = (i << 2) + *string++;
80 return (BITS (i, 31) % table->nbuckets);
83 /* Return a pointer to the hashed item, or NULL if the item
86 find_hash_item (string, table)
90 BUCKET_CONTENTS *list;
94 return (BUCKET_CONTENTS *)NULL;
96 which_bucket = hash_string (string, table);
98 for (list = table->bucket_array[which_bucket]; list; list = list->next)
100 if (STREQ (list->key, string))
106 return (BUCKET_CONTENTS *)NULL;
109 /* Remove the item specified by STRING from the hash table TABLE.
110 The item removed is returned, so you can free its contents. If
111 the item isn't in this table NULL is returned. */
113 remove_hash_item (string, table)
118 BUCKET_CONTENTS *prev, *temp;
121 return (BUCKET_CONTENTS *)NULL;
123 the_bucket = hash_string (string, table);
124 prev = (BUCKET_CONTENTS *)NULL;
125 for (temp = table->bucket_array[the_bucket]; temp; temp = temp->next)
127 if (STREQ (temp->key, string))
130 prev->next = temp->next;
132 table->bucket_array[the_bucket] = temp->next;
139 return ((BUCKET_CONTENTS *) NULL);
142 /* Create an entry for STRING, in TABLE. If the entry already
143 exists, then return it. */
145 add_hash_item (string, table)
149 BUCKET_CONTENTS *item;
153 table = make_hash_table (0);
155 if ((item = find_hash_item (string, table)) == 0)
157 bucket = hash_string (string, table);
158 item = table->bucket_array[bucket];
160 while (item && item->next)
165 item->next = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
170 table->bucket_array[bucket] =
171 (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
172 item = table->bucket_array[bucket];
175 item->data = (char *)NULL;
176 item->next = (BUCKET_CONTENTS *)NULL;
179 item->times_found = 0;
185 /* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it
186 is a function to call to dispose of a hash item's data. Otherwise,
189 flush_hash_table (table, free_data)
191 VFunction *free_data;
194 register BUCKET_CONTENTS *bucket, *item;
199 for (i = 0; i < table->nbuckets; i++)
201 bucket = table->bucket_array[i];
206 bucket = bucket->next;
209 (*free_data) (item->data);
215 table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
219 /* Free the hash table pointed to by TABLE. */
221 dispose_hash_table (table)
224 free (table->bucket_array);
228 /* Return the bucket_contents list of bucket BUCKET in TABLE. If
229 TABLE doesn't have BUCKET buckets, return NULL. */
230 #undef get_hash_bucket
232 get_hash_bucket (bucket, table)
236 if (table && bucket < table->nbuckets)
237 return (table->bucket_array[bucket]);
239 return (BUCKET_CONTENTS *)NULL;
243 print_table_stats (table, name)
247 register int slot, bcount;
248 register BUCKET_CONTENTS *bc;
251 name = "unknown hash table";
253 fprintf (stderr, "%s: %d buckets; %d items\n", name, table->nbuckets, table->nentries);
255 /* Print out a count of how many strings hashed to each bucket, so we can
256 see how even the distribution is. */
257 for (slot = 0; slot < table->nbuckets; slot++)
259 bc = get_hash_bucket (slot, table);
261 fprintf (stderr, "\tslot %3d: ", slot);
262 for (bcount = 0; bc; bc = bc->next)
265 fprintf (stderr, "%d\n", bcount);
282 char *result = (char *)malloc (bytes);
285 fprintf (stderr, "hash: out of virtual memory\n");
297 table = make_hash_table (NBUCKETS);
302 if (fgets (string, sizeof (string), stdin) == 0)
306 temp_string = savestring (string);
307 tt = add_hash_item (temp_string, table);
310 fprintf (stderr, "You have already added item `%s'\n", string);
319 print_table_stats (table, "hash test");
323 #endif /* TEST_HASHING */