Nico Golde:
[apps/madmutt.git] / hash.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */ 
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "mutt.h"
28
29 #define SOMEPRIME 149711
30
31 int hash_string (const unsigned char *s, int n)
32 {
33   int h = 0;
34
35 #if 0
36   while (*s)
37     h += *s++;
38 #else
39   while (*s)
40     h += (h << 7) + *s++;
41   h = (h * SOMEPRIME) % n;
42   h = (h >= 0) ? h : h + n;
43 #endif
44
45   return (h % n);
46 }
47
48 HASH *hash_create (int nelem)
49 {
50   HASH *table = safe_malloc (sizeof (HASH));
51   if (nelem == 0)
52     nelem = 2;
53   table->nelem = nelem;
54   table->curnelem = 0;
55   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
56   return table;
57 }
58
59 HASH *hash_resize (HASH *ptr, int nelem)
60 {
61   HASH *table;
62   struct hash_elem *elem, *tmp;
63   int i;
64
65   table = hash_create (nelem);
66
67   for (i = 0; i < ptr->nelem; i++)
68   {
69     for (elem = ptr->table[i]; elem; )
70     {
71       tmp = elem;
72       elem = elem->next;
73       hash_insert (table, tmp->key, tmp->data, 1);
74       FREE (&tmp);
75     }
76   }
77   FREE (&ptr->table);
78   FREE (&ptr);
79
80   return table;
81 }
82
83 /* table        hash table to update
84  * key          key to hash on
85  * data         data to associate with `key'
86  * allow_dup    if nonzero, duplicate keys are allowed in the table 
87  */
88 int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
89 {
90   struct hash_elem *ptr;
91   int h;
92
93   ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
94   h = hash_string ((unsigned char *) key, table->nelem);
95   ptr->key = key;
96   ptr->data = data;
97
98   if (allow_dup)
99   {
100     ptr->next = table->table[h];
101     table->table[h] = ptr;
102     table->curnelem++;
103   }
104   else
105   {
106     struct hash_elem *tmp, *last;
107     int r;
108
109     for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next)
110     {
111       r = mutt_strcmp (tmp->key, key);
112       if (r == 0)
113       {
114         FREE (&ptr);
115         return (-1);
116       }
117       if (r > 0)
118         break;
119     }
120     if (last)
121       last->next = ptr;
122     else
123       table->table[h] = ptr;
124     ptr->next = tmp;
125     table->curnelem++;
126   }
127   return h;
128 }
129
130 void *hash_find_hash (const HASH * table, int hash, const char *key)
131 {
132   struct hash_elem *ptr = table->table[hash];
133   for (; ptr; ptr = ptr->next)
134   {
135     if (mutt_strcmp (key, ptr->key) == 0)
136       return (ptr->data);
137   }
138   return NULL;
139 }
140
141 void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
142                        void (*destroy) (void *))
143 {
144   struct hash_elem *ptr = table->table[hash];
145   struct hash_elem **last = &table->table[hash];
146
147   for (; ptr; last = &ptr->next, ptr = ptr->next)
148   {
149     /* if `data' is given, look for a matching ->data member.  this is
150      * required for the case where we have multiple entries with the same
151      * key
152      */
153     if ((data == ptr->data) || (!data && mutt_strcmp (ptr->key, key) == 0))
154     {
155       *last = ptr->next;
156       if (destroy) destroy (ptr->data);
157       FREE (&ptr);
158       table->curnelem--;
159       return;
160     }
161   }
162 }
163
164 /* ptr          pointer to the hash table to be freed
165  * destroy()    function to call to free the ->data member (optional) 
166  */
167 void hash_destroy (HASH **ptr, void (*destroy) (void *))
168 {
169   int i;
170   HASH *pptr = *ptr;
171   struct hash_elem *elem, *tmp;
172
173   for (i = 0 ; i < pptr->nelem; i++)
174   {
175     for (elem = pptr->table[i]; elem; )
176     {
177       tmp = elem;
178       elem = elem->next;
179       if (destroy)
180         destroy (tmp->data);
181       FREE (&tmp);
182     }
183   }
184   FREE (&pptr->table);
185   FREE (ptr);
186 }