3 * Copyright (c) 1995-1999 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
9 * Enscript is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * Enscript is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Enscript. If not, see <http://www.gnu.org/licenses/>.
27 * Types and definitions.
30 #define STRHASH_DEBUG 0
32 #define HASH_SIZE 8192
36 struct hash_list_st *next;
37 char *key; /* malloc()ated copy of key. */
42 typedef struct hash_list_st HashList;
44 typedef HashList *HashTable;
46 typedef struct stringhash_st
48 HashTable *hash_table;
51 unsigned int next_idx;
56 #endif /* STRHASH_DEBUG */
61 * Prototypes for static functions.
64 static int count_hash ___P ((const char *key, int keylen));
76 tmp = (StringHashPtr) calloc (1, sizeof (*tmp));
80 tmp->hash_table = (HashTable *) calloc (HASH_SIZE, sizeof (HashTable));
88 tmp->items_in_hash = 0;
89 #endif /* STRHASH_DEBUG */
95 strhash_free (StringHashPtr hash)
97 HashList *list, *list_next;
104 for (i = 0; i < HASH_SIZE; i++)
105 for (list = hash->hash_table[i]; list; list = list_next)
107 list_next = list->next;
113 free (hash->hash_table);
119 strhash_put (StringHashPtr hash, char *key, int keylen, void *data,
122 HashList *list, *prev = NULL;
125 if (!hash || !key || keylen <= 0)
130 pos = count_hash (key, keylen);
132 /* Is it already here? */
133 for (list = hash->hash_table[pos]; list; prev = list, list = list->next)
134 if (list->keylen == keylen)
136 cmp_val = memcmp (key, list->key, keylen);
139 /* We had an old occurence. */
141 *old_data = list->data;
145 else if (cmp_val < 0)
147 /* Run over. Correct position is prev->next. */
151 else if (list->keylen > keylen)
152 /* Lists are kept sorted so that smallest keys are at the head and
153 keys with equal length are in normal sorted order. */
157 list = (HashList *) calloc (1, sizeof (HashList));
160 list->key = (char *) malloc (keylen);
167 memcpy (list->key, key, keylen);
168 list->keylen = keylen;
171 /* Insert list to the correct position. */
174 list->next = hash->hash_table[pos];
175 hash->hash_table[pos] = list;
179 list->next = prev->next;
183 hash->items_in_hash++;
184 #endif /* STRHASH_DEBUG */
190 strhash_get (StringHashPtr hash, const char *key, int keylen, void **data)
195 if (!hash || !key || keylen <= 0 || !data)
199 pos = count_hash (key, keylen);
200 for (list = hash->hash_table[pos]; list; list = list->next)
201 if (list->keylen == keylen)
203 cmp_val = memcmp (key, list->key, keylen);
209 else if (cmp_val < 0)
213 else if (list->keylen > keylen)
222 strhash_delete (StringHashPtr hash, const char *key, int keylen, void **data)
224 HashList *list, *prev = NULL;
227 if (!hash || !key || keylen <= 0 || !data)
231 pos = count_hash (key, keylen);
232 for (list = hash->hash_table[pos]; list; prev = list, list = list->next)
233 if (list->keylen == keylen)
235 cmp_val = memcmp (key, list->key, keylen);
240 hash->hash_table[pos] = list->next;
242 prev->next = list->next;
250 hash->next_item = NULL;
253 hash->items_in_hash--;
254 #endif /* STRHASH_DEBUG */
257 else if (cmp_val < 0)
261 else if (list->keylen > keylen)
270 strhash_get_first (StringHashPtr hash, char **key_return,
271 int *keylen_return, void **data_return)
273 if (!hash || !key_return || !keylen_return || !data_return)
276 for (hash->next_idx = 0; hash->next_idx < HASH_SIZE; hash->next_idx++)
278 hash->next_item = hash->hash_table[hash->next_idx];
281 *key_return = hash->next_item->key;
282 *keylen_return = hash->next_item->keylen;
283 *data_return = hash->next_item->data;
292 strhash_get_next (StringHashPtr hash, char **key_return,
293 int *keylen_return, void **data_return)
295 if (!hash || !key_return || !keylen_return || !data_return)
298 for (; hash->next_idx < HASH_SIZE; hash->next_idx++)
300 if (hash->next_item == NULL)
301 hash->next_item = hash->hash_table[hash->next_idx];
303 hash->next_item = hash->next_item->next;
307 *key_return = hash->next_item->key;
308 *keylen_return = hash->next_item->keylen;
309 *data_return = hash->next_item->data;
319 strhash_debug (StringHashPtr hash)
321 int i, count = 0, max = 0;
326 fprintf (stderr, "Invalid hash handle!\n");
329 fprintf (stderr, "hash_size\t%d\n", HASH_SIZE);
330 fprintf (stderr, "items_in_hash\t%d\n", hash->items_in_hash);
332 for (i = 0; i < HASH_SIZE; i++)
333 if (hash->hash_table[i] == NULL)
335 fprintf (stderr, "empty entries\t%d\n", count);
338 for (i = 0; i < HASH_SIZE; i++)
340 for (tmp = hash->hash_table[i]; tmp; tmp = tmp->next)
342 max = count > max ? count : max;
345 fprintf (stderr, "longest list\t%d\n", max);
349 /* Print the first longest list. */
350 for (i = 0; i < HASH_SIZE; i++)
353 for (tmp = hash->hash_table[i]; tmp; tmp = tmp->next)
357 for (count = 0, tmp = hash->hash_table[i]; tmp;
358 tmp = tmp->next, count++)
360 fprintf (stderr, "%d\t", count);
361 for (i = 0; i < tmp->keylen; i++)
362 fprintf (stderr, "%c", tmp->key[i]);
369 #endif /* STRHASH_DEBUG */
377 count_hash (const char *key, int keylen)
379 unsigned int val = 0;
382 for (i = 0; i < keylen; i++)
383 val = (val << 5) ^ (unsigned char) key[i]
384 ^ (val >> 16) ^ (val >> 7);
385 return val % HASH_SIZE;