Nico Golde:
[apps/madmutt.git] / hash.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #include "mutt.h"
19
20 #include "lib/mem.h"
21
22 #define SOMEPRIME 149711
23
24 int hash_string (const unsigned char *s, int n)
25 {
26   int h = 0;
27
28 #if 0
29   while (*s)
30     h += *s++;
31 #else
32   while (*s)
33     h += (h << 7) + *s++;
34   h = (h * SOMEPRIME) % n;
35   h = (h >= 0) ? h : h + n;
36 #endif
37
38   return (h % n);
39 }
40
41 HASH *hash_create (int nelem)
42 {
43   HASH *table = safe_malloc (sizeof (HASH));
44
45   if (nelem == 0)
46     nelem = 2;
47   table->nelem = nelem;
48   table->curnelem = 0;
49   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
50   return table;
51 }
52
53 HASH *hash_resize (HASH * ptr, int nelem)
54 {
55   HASH *table;
56   struct hash_elem *elem, *tmp;
57   int i;
58
59   table = hash_create (nelem);
60
61   for (i = 0; i < ptr->nelem; i++) {
62     for (elem = ptr->table[i]; elem;) {
63       tmp = elem;
64       elem = elem->next;
65       hash_insert (table, tmp->key, tmp->data, 1);
66       FREE (&tmp);
67     }
68   }
69   FREE (&ptr->table);
70   FREE (&ptr);
71
72   return table;
73 }
74
75 /* table        hash table to update
76  * key          key to hash on
77  * data         data to associate with `key'
78  * allow_dup    if nonzero, duplicate keys are allowed in the table 
79  */
80 int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
81 {
82   struct hash_elem *ptr;
83   int h;
84
85   ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
86   h = hash_string ((unsigned char *) key, table->nelem);
87   ptr->key = key;
88   ptr->data = data;
89
90   if (allow_dup) {
91     ptr->next = table->table[h];
92     table->table[h] = ptr;
93     table->curnelem++;
94   }
95   else {
96     struct hash_elem *tmp, *last;
97     int r;
98
99     for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next) {
100       r = mutt_strcmp (tmp->key, key);
101       if (r == 0) {
102         FREE (&ptr);
103         return (-1);
104       }
105       if (r > 0)
106         break;
107     }
108     if (last)
109       last->next = ptr;
110     else
111       table->table[h] = ptr;
112     ptr->next = tmp;
113     table->curnelem++;
114   }
115   return h;
116 }
117
118 void *hash_find_hash (const HASH * table, int hash, const char *key)
119 {
120   struct hash_elem *ptr = table->table[hash];
121
122   for (; ptr; ptr = ptr->next) {
123     if (mutt_strcmp (key, ptr->key) == 0)
124       return (ptr->data);
125   }
126   return NULL;
127 }
128
129 void hash_delete_hash (HASH * table, int hash, const char *key,
130                        const void *data, void (*destroy) (void *))
131 {
132   struct hash_elem *ptr = table->table[hash];
133   struct hash_elem **last = &table->table[hash];
134
135   for (; ptr; last = &ptr->next, ptr = ptr->next) {
136     /* if `data' is given, look for a matching ->data member.  this is
137      * required for the case where we have multiple entries with the same
138      * key
139      */
140     if ((data == ptr->data) || (!data && mutt_strcmp (ptr->key, key) == 0)) {
141       *last = ptr->next;
142       if (destroy)
143         destroy (ptr->data);
144       FREE (&ptr);
145       table->curnelem--;
146       return;
147     }
148   }
149 }
150
151 /* ptr          pointer to the hash table to be freed
152  * destroy()    function to call to free the ->data member (optional) 
153  */
154 void hash_destroy (HASH ** ptr, void (*destroy) (void *))
155 {
156   int i;
157   HASH *pptr = *ptr;
158   struct hash_elem *elem, *tmp;
159
160   for (i = 0; i < pptr->nelem; i++) {
161     for (elem = pptr->table[i]; elem;) {
162       tmp = elem;
163       elem = elem->next;
164       if (destroy)
165         destroy (tmp->data);
166       FREE (&tmp);
167     }
168   }
169   FREE (&pptr->table);
170   FREE (ptr);
171 }