Andreas Krennmair:
[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 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "mutt.h"
24
25 #define SOMEPRIME 149711
26
27 int hash_string (const unsigned char *s, int n)
28 {
29   int h = 0;
30
31 #if 0
32   while (*s)
33     h += *s++;
34 #else
35   while (*s)
36     h += (h << 7) + *s++;
37   h = (h * SOMEPRIME) % n;
38   h = (h >= 0) ? h : h + n;
39 #endif
40
41   return (h % n);
42 }
43
44 HASH *hash_create (int nelem)
45 {
46   HASH *table = safe_malloc (sizeof (HASH));
47   if (nelem == 0)
48     nelem = 2;
49   table->nelem = nelem;
50   table->curnelem = 0;
51   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
52   return table;
53 }
54
55 HASH *hash_resize (HASH *ptr, int nelem)
56 {
57   HASH *table;
58   struct hash_elem *elem, *tmp;
59   int i;
60
61   table = hash_create (nelem);
62
63   for (i = 0; i < ptr->nelem; i++)
64   {
65     for (elem = ptr->table[i]; elem; )
66     {
67       tmp = elem;
68       elem = elem->next;
69       hash_insert (table, tmp->key, tmp->data, 1);
70       FREE (&tmp);
71     }
72   }
73   FREE (&ptr->table);
74   FREE (&ptr);
75
76   return table;
77 }
78
79 /* table        hash table to update
80  * key          key to hash on
81  * data         data to associate with `key'
82  * allow_dup    if nonzero, duplicate keys are allowed in the table 
83  */
84 int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
85 {
86   struct hash_elem *ptr;
87   int h;
88
89   ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
90   h = hash_string ((unsigned char *) key, table->nelem);
91   ptr->key = key;
92   ptr->data = data;
93
94   if (allow_dup)
95   {
96     ptr->next = table->table[h];
97     table->table[h] = ptr;
98     table->curnelem++;
99   }
100   else
101   {
102     struct hash_elem *tmp, *last;
103     int r;
104
105     for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next)
106     {
107       r = mutt_strcmp (tmp->key, key);
108       if (r == 0)
109       {
110         FREE (&ptr);
111         return (-1);
112       }
113       if (r > 0)
114         break;
115     }
116     if (last)
117       last->next = ptr;
118     else
119       table->table[h] = ptr;
120     ptr->next = tmp;
121     table->curnelem++;
122   }
123   return h;
124 }
125
126 void *hash_find_hash (const HASH * table, int hash, const char *key)
127 {
128   struct hash_elem *ptr = table->table[hash];
129   for (; ptr; ptr = ptr->next)
130   {
131     if (mutt_strcmp (key, ptr->key) == 0)
132       return (ptr->data);
133   }
134   return NULL;
135 }
136
137 void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
138                        void (*destroy) (void *))
139 {
140   struct hash_elem *ptr = table->table[hash];
141   struct hash_elem **last = &table->table[hash];
142
143   for (; ptr; last = &ptr->next, ptr = ptr->next)
144   {
145     /* if `data' is given, look for a matching ->data member.  this is
146      * required for the case where we have multiple entries with the same
147      * key
148      */
149     if ((data == ptr->data) || (!data && mutt_strcmp (ptr->key, key) == 0))
150     {
151       *last = ptr->next;
152       if (destroy) destroy (ptr->data);
153       FREE (&ptr);
154       table->curnelem--;
155       return;
156     }
157   }
158 }
159
160 /* ptr          pointer to the hash table to be freed
161  * destroy()    function to call to free the ->data member (optional) 
162  */
163 void hash_destroy (HASH **ptr, void (*destroy) (void *))
164 {
165   int i;
166   HASH *pptr = *ptr;
167   struct hash_elem *elem, *tmp;
168
169   for (i = 0 ; i < pptr->nelem; i++)
170   {
171     for (elem = pptr->table[i]; elem; )
172     {
173       tmp = elem;
174       elem = elem->next;
175       if (destroy)
176         destroy (tmp->data);
177       FREE (&tmp);
178     }
179   }
180   FREE (&pptr->table);
181   FREE (ptr);
182 }