mutt stable branch with some hacks
at master 293 lines 6.4 kB view raw
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 32static unsigned int gen_string_hash (union hash_key key, unsigned int n) 33{ 34 unsigned int h = 0; 35 unsigned char *s = (unsigned char *)key.strkey; 36 37 while (*s) 38 h += (h << 7) + *s++; 39 h = (h * SOMEPRIME) % n; 40 41 return h; 42} 43 44static int cmp_string_key (union hash_key a, union hash_key b) 45{ 46 return mutt_strcmp (a.strkey, b.strkey); 47} 48 49static unsigned int gen_case_string_hash (union hash_key key, unsigned int n) 50{ 51 unsigned int h = 0; 52 unsigned char *s = (unsigned char *)key.strkey; 53 54 while (*s) 55 h += (h << 7) + tolower (*s++); 56 h = (h * SOMEPRIME) % n; 57 58 return h; 59} 60 61static int cmp_case_string_key (union hash_key a, union hash_key b) 62{ 63 return mutt_strcasecmp (a.strkey, b.strkey); 64} 65 66static unsigned int gen_int_hash (union hash_key key, unsigned int n) 67{ 68 return key.intkey % n; 69} 70 71static int cmp_int_key (union hash_key a, union hash_key b) 72{ 73 if (a.intkey == b.intkey) 74 return 0; 75 if (a.intkey < b.intkey) 76 return -1; 77 return 1; 78} 79 80static HASH *new_hash (int nelem) 81{ 82 HASH *table = safe_malloc (sizeof (HASH)); 83 if (nelem == 0) 84 nelem = 2; 85 table->nelem = nelem; 86 table->table = safe_calloc (nelem, sizeof (struct hash_elem *)); 87 return table; 88} 89 90HASH *hash_create (int nelem, int lower) 91{ 92 HASH *table = new_hash (nelem); 93 if (lower) 94 { 95 table->gen_hash = gen_case_string_hash; 96 table->cmp_key = cmp_case_string_key; 97 } 98 else 99 { 100 table->gen_hash = gen_string_hash; 101 table->cmp_key = cmp_string_key; 102 } 103 return table; 104} 105 106HASH *int_hash_create (int nelem) 107{ 108 HASH *table = new_hash (nelem); 109 table->gen_hash = gen_int_hash; 110 table->cmp_key = cmp_int_key; 111 return table; 112} 113 114/* table hash table to update 115 * key key to hash on 116 * data data to associate with `key' 117 * allow_dup if nonzero, duplicate keys are allowed in the table 118 */ 119static int union_hash_insert (HASH * table, union hash_key key, void *data, int allow_dup) 120{ 121 struct hash_elem *ptr; 122 unsigned int h; 123 124 ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem)); 125 h = table->gen_hash (key, table->nelem); 126 ptr->key = key; 127 ptr->data = data; 128 129 if (allow_dup) 130 { 131 ptr->next = table->table[h]; 132 table->table[h] = ptr; 133 } 134 else 135 { 136 struct hash_elem *tmp, *last; 137 int r; 138 139 for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next) 140 { 141 r = table->cmp_key (tmp->key, key); 142 if (r == 0) 143 { 144 FREE (&ptr); 145 return (-1); 146 } 147 if (r > 0) 148 break; 149 } 150 if (last) 151 last->next = ptr; 152 else 153 table->table[h] = ptr; 154 ptr->next = tmp; 155 } 156 return h; 157} 158 159int hash_insert (HASH * table, const char *strkey, void *data, int allow_dup) 160{ 161 union hash_key key; 162 key.strkey = strkey; 163 return union_hash_insert (table, key, data, allow_dup); 164} 165 166int int_hash_insert (HASH * table, unsigned int intkey, void *data, int allow_dup) 167{ 168 union hash_key key; 169 key.intkey = intkey; 170 return union_hash_insert (table, key, data, allow_dup); 171} 172 173static void *union_hash_find (const HASH *table, union hash_key key) 174{ 175 int hash; 176 struct hash_elem *ptr; 177 178 if (!table) 179 return NULL; 180 181 hash = table->gen_hash (key, table->nelem); 182 ptr = table->table[hash]; 183 for (; ptr; ptr = ptr->next) 184 { 185 if (table->cmp_key (key, ptr->key) == 0) 186 return (ptr->data); 187 } 188 return NULL; 189} 190 191void *hash_find (const HASH *table, const char *strkey) 192{ 193 union hash_key key; 194 key.strkey = strkey; 195 return union_hash_find (table, key); 196} 197 198void *int_hash_find (const HASH *table, unsigned int intkey) 199{ 200 union hash_key key; 201 key.intkey = intkey; 202 return union_hash_find (table, key); 203} 204 205struct hash_elem *hash_find_bucket (const HASH *table, const char *strkey) 206{ 207 union hash_key key; 208 int hash; 209 210 if (!table) 211 return NULL; 212 213 key.strkey = strkey; 214 hash = table->gen_hash (key, table->nelem); 215 return table->table[hash]; 216} 217 218static void union_hash_delete (HASH *table, union hash_key key, const void *data, 219 void (*destroy) (void *)) 220{ 221 int hash; 222 struct hash_elem *ptr, **last; 223 224 if (!table) 225 return; 226 227 hash = table->gen_hash (key, table->nelem); 228 ptr = table->table[hash]; 229 last = &table->table[hash]; 230 231 while (ptr) 232 { 233 if ((data == ptr->data || !data) 234 && table->cmp_key (ptr->key, key) == 0) 235 { 236 *last = ptr->next; 237 if (destroy) 238 destroy (ptr->data); 239 FREE (&ptr); 240 241 ptr = *last; 242 } 243 else 244 { 245 last = &ptr->next; 246 ptr = ptr->next; 247 } 248 } 249} 250 251void hash_delete (HASH *table, const char *strkey, const void *data, 252 void (*destroy) (void *)) 253{ 254 union hash_key key; 255 key.strkey = strkey; 256 union_hash_delete (table, key, data, destroy); 257} 258 259void int_hash_delete (HASH *table, unsigned int intkey, const void *data, 260 void (*destroy) (void *)) 261{ 262 union hash_key key; 263 key.intkey = intkey; 264 union_hash_delete (table, key, data, destroy); 265} 266 267/* ptr pointer to the hash table to be freed 268 * destroy() function to call to free the ->data member (optional) 269 */ 270void hash_destroy (HASH **ptr, void (*destroy) (void *)) 271{ 272 int i; 273 HASH *pptr; 274 struct hash_elem *elem, *tmp; 275 276 if (!ptr || !*ptr) 277 return; 278 279 pptr = *ptr; 280 for (i = 0 ; i < pptr->nelem; i++) 281 { 282 for (elem = pptr->table[i]; elem; ) 283 { 284 tmp = elem; 285 elem = elem->next; 286 if (destroy) 287 destroy (tmp->data); 288 FREE (&tmp); 289 } 290 } 291 FREE (&pptr->table); 292 FREE (ptr); /* __FREE_CHECKED__ */ 293}