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