]> git.llucax.com Git - software/mutt-debian.git/blob - hash.c
Imported Upstream version 1.5.20
[software/mutt-debian.git] / hash.c
1 /*
2  * Copyright (C) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 #include <ctype.h>
27
28 #include "mutt.h"
29
30 #define SOMEPRIME 149711
31
32 static unsigned int hash_string (const unsigned char *s, unsigned int n)
33 {
34   unsigned int h = 0;
35
36   while (*s)
37     h += (h << 7) + *s++;
38   h = (h * SOMEPRIME) % n;
39
40   return h;
41 }
42
43 static unsigned int hash_case_string (const unsigned char *s, unsigned int n)
44 {
45   unsigned int h = 0;
46
47   while (*s)
48     h += (h << 7) + tolower (*s++);
49   h = (h * SOMEPRIME) % n;
50
51   return h;
52 }
53
54 HASH *hash_create (int nelem, int lower)
55 {
56   HASH *table = safe_malloc (sizeof (HASH));
57   if (nelem == 0)
58     nelem = 2;
59   table->nelem = nelem;
60   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
61   if (lower)
62   {
63     table->hash_string = hash_case_string;
64     table->cmp_string = mutt_strcasecmp;
65   }
66   else
67   {
68     table->hash_string = hash_string;
69     table->cmp_string = mutt_strcmp;
70   }
71   return table;
72 }
73
74 /* table        hash table to update
75  * key          key to hash on
76  * data         data to associate with `key'
77  * allow_dup    if nonzero, duplicate keys are allowed in the table 
78  */
79 int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
80 {
81   struct hash_elem *ptr;
82   unsigned int h;
83
84   ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
85   h = table->hash_string ((unsigned char *) key, table->nelem);
86   ptr->key = key;
87   ptr->data = data;
88
89   if (allow_dup)
90   {
91     ptr->next = table->table[h];
92     table->table[h] = ptr;
93   }
94   else
95   {
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     {
101       r = table->cmp_string (tmp->key, key);
102       if (r == 0)
103       {
104         FREE (&ptr);
105         return (-1);
106       }
107       if (r > 0)
108         break;
109     }
110     if (last)
111       last->next = ptr;
112     else
113       table->table[h] = ptr;
114     ptr->next = tmp;
115   }
116   return h;
117 }
118
119 void *hash_find_hash (const HASH * table, int hash, const char *key)
120 {
121   struct hash_elem *ptr = table->table[hash];
122   for (; ptr; ptr = ptr->next)
123   {
124     if (table->cmp_string (key, ptr->key) == 0)
125       return (ptr->data);
126   }
127   return NULL;
128 }
129
130 void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
131                        void (*destroy) (void *))
132 {
133   struct hash_elem *ptr = table->table[hash];
134   struct hash_elem **last = &table->table[hash];
135
136   while (ptr) 
137   {
138     if ((data == ptr->data || !data)
139         && table->cmp_string (ptr->key, key) == 0)
140     {
141       *last = ptr->next;
142       if (destroy)
143         destroy (ptr->data);
144       FREE (&ptr);
145       
146       ptr = *last;
147     }
148     else
149     {
150       last = &ptr->next;
151       ptr = ptr->next;
152     }
153   }
154 }
155
156 /* ptr          pointer to the hash table to be freed
157  * destroy()    function to call to free the ->data member (optional) 
158  */
159 void hash_destroy (HASH **ptr, void (*destroy) (void *))
160 {
161   int i;
162   HASH *pptr = *ptr;
163   struct hash_elem *elem, *tmp;
164
165   for (i = 0 ; i < pptr->nelem; i++)
166   {
167     for (elem = pptr->table[i]; elem; )
168     {
169       tmp = elem;
170       elem = elem->next;
171       if (destroy)
172         destroy (tmp->data);
173       FREE (&tmp);
174     }
175   }
176   FREE (&pptr->table);
177   FREE (ptr);           /* __FREE_CHECKED__ */
178 }