1ea6ae205Smrg/* 2ea6ae205Smrg Copyright (c) 2003 by Juliusz Chroboczek 3ea6ae205Smrg 4ea6ae205Smrg Permission is hereby granted, free of charge, to any person obtaining a copy 5ea6ae205Smrg of this software and associated documentation files (the "Software"), to deal 6ea6ae205Smrg in the Software without restriction, including without limitation the rights 7ea6ae205Smrg to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8ea6ae205Smrg copies of the Software, and to permit persons to whom the Software is 9ea6ae205Smrg furnished to do so, subject to the following conditions: 10ea6ae205Smrg 11ea6ae205Smrg The above copyright notice and this permission notice shall be included in 12ea6ae205Smrg all copies or substantial portions of the Software. 13ea6ae205Smrg 14ea6ae205Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15ea6ae205Smrg IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16ea6ae205Smrg FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17ea6ae205Smrg AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18ea6ae205Smrg LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19ea6ae205Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20ea6ae205Smrg THE SOFTWARE. 21ea6ae205Smrg*/ 22ea6ae205Smrg 2340cc5db4Smrg#ifdef HAVE_CONFIG_H 2487aef7c3Smrg#include "config.h" 2540cc5db4Smrg#endif 2687aef7c3Smrg 27ea6ae205Smrg#include <stdlib.h> 28ea6ae205Smrg#include <stdio.h> 29ea6ae205Smrg#include <string.h> 30ea6ae205Smrg#include <ctype.h> 31ea6ae205Smrg#include "hash.h" 32ea6ae205Smrg#include "list.h" 33ea6ae205Smrg 34ea6ae205Smrg#define LOG2_NUMBUCKETS 10 35ea6ae205Smrg#define NUMBUCKETS (1 << LOG2_NUMBUCKETS) 36ea6ae205Smrg 37ea6ae205Smrgstatic unsigned 38663cdc11Smrghash(const char *string) 39ea6ae205Smrg{ 40ea6ae205Smrg unsigned u = 0; 416ae2c069Smrg 426ae2c069Smrg for (int i = 0; string[i] != '\0'; i++) 436ae2c069Smrg u = (u << 5) + (u >> (LOG2_NUMBUCKETS - 5)) + (unsigned char) string[i]; 44ea6ae205Smrg return (u & (NUMBUCKETS - 1)); 45ea6ae205Smrg} 46ea6ae205Smrg 47ea6ae205Smrgstatic void 4887aef7c3Smrgstr_tolower(char *s) 49ea6ae205Smrg{ 506ae2c069Smrg while (*s != '\0') { 5187aef7c3Smrg *s = tolower(*s); 5287aef7c3Smrg s++; 53ea6ae205Smrg } 54ea6ae205Smrg} 55ea6ae205Smrg 56ea6ae205SmrgHashTablePtr 57ea6ae205SmrgmakeHashTable(void) 58ea6ae205Smrg{ 59ea6ae205Smrg return calloc(NUMBUCKETS, sizeof(HashBucketPtr)); 60ea6ae205Smrg} 61ea6ae205Smrg 62ea6ae205Smrgvoid 63ea6ae205SmrgdestroyHashTable(HashTablePtr table) 64ea6ae205Smrg{ 656ae2c069Smrg for (int i = 0; i < NUMBUCKETS; i++) { 666ae2c069Smrg while (table[i]) { 676ae2c069Smrg HashBucketPtr bp = table[i]; 68ea6ae205Smrg table[i] = table[i]->next; 69ea6ae205Smrg free(bp->key); 70ea6ae205Smrg free(bp->value); 71ea6ae205Smrg free(bp); 72ea6ae205Smrg } 73ea6ae205Smrg } 74ea6ae205Smrg free(table); 75ea6ae205Smrg} 76ea6ae205Smrg 77ea6ae205Smrgchar * 78663cdc11SmrggetHash(HashTablePtr table, const char *key) 79ea6ae205Smrg{ 8087aef7c3Smrg unsigned int i = hash(key); 816ae2c069Smrg 826ae2c069Smrg for (HashBucketPtr bp = table[i]; bp; bp = bp->next) { 836ae2c069Smrg if (strcasecmp(bp->key, key) == 0) 84ea6ae205Smrg return bp->value; 85ea6ae205Smrg } 86ea6ae205Smrg return NULL; 87ea6ae205Smrg} 88ea6ae205Smrg 89ea6ae205Smrgint 90ea6ae205SmrgputHash(HashTablePtr table, char *key, char *value, int prio) 91ea6ae205Smrg{ 9287aef7c3Smrg unsigned int i = hash(key); 93ea6ae205Smrg char *keycopy = NULL, *valuecopy = NULL; 94ea6ae205Smrg HashBucketPtr bp; 956ae2c069Smrg 966ae2c069Smrg for (bp = table[i]; bp; bp = bp->next) { 976ae2c069Smrg if (strcasecmp(bp->key, key) == 0) { 986ae2c069Smrg if (prio > bp->prio) { 9987aef7c3Smrg keycopy = strdup(key); 1006ae2c069Smrg if (keycopy == NULL) 1016ae2c069Smrg goto fail; 10287aef7c3Smrg str_tolower(keycopy); 10387aef7c3Smrg valuecopy = strdup(value); 1046ae2c069Smrg if (valuecopy == NULL) 1056ae2c069Smrg goto fail; 106ea6ae205Smrg free(bp->key); 107ea6ae205Smrg free(bp->value); 108ea6ae205Smrg bp->key = keycopy; 109ea6ae205Smrg bp->value = valuecopy; 110ea6ae205Smrg } 111ea6ae205Smrg return 1; 112ea6ae205Smrg } 113ea6ae205Smrg } 11487aef7c3Smrg keycopy = strdup(key); 1156ae2c069Smrg if (keycopy == NULL) 116ea6ae205Smrg goto fail; 11787aef7c3Smrg str_tolower(keycopy); 11887aef7c3Smrg valuecopy = strdup(value); 1196ae2c069Smrg if (valuecopy == NULL) 120ea6ae205Smrg goto fail; 121ea6ae205Smrg bp = malloc(sizeof(HashBucketRec)); 1226ae2c069Smrg if (bp == NULL) 123ea6ae205Smrg goto fail; 124ea6ae205Smrg bp->key = keycopy; 125ea6ae205Smrg bp->value = valuecopy; 126ea6ae205Smrg bp->prio = prio; 127ea6ae205Smrg bp->next = table[i]; 128ea6ae205Smrg table[i] = bp; 129ea6ae205Smrg return 1; 130ea6ae205Smrg 131ea6ae205Smrg fail: 1326ae2c069Smrg if (keycopy) 1336ae2c069Smrg free(keycopy); 1346ae2c069Smrg if (valuecopy) 1356ae2c069Smrg free(valuecopy); 136ea6ae205Smrg return -1; 137ea6ae205Smrg} 138ea6ae205Smrg 139ea6ae205Smrgint 140ea6ae205SmrghashElements(HashTablePtr table) 141ea6ae205Smrg{ 1426ae2c069Smrg int n = 0; 143ea6ae205Smrg 1446ae2c069Smrg for (int i = 0; i < NUMBUCKETS; i++) { 1456ae2c069Smrg for (HashBucketPtr bp = table[i]; bp; bp = bp->next) { 146ea6ae205Smrg n++; 147ea6ae205Smrg } 148ea6ae205Smrg } 149ea6ae205Smrg return n; 150ea6ae205Smrg} 151ea6ae205Smrg 152ea6ae205Smrgstatic int 153ea6ae205Smrgkey_first_cmp(const void *v1, const void *v2) 154ea6ae205Smrg{ 155ea6ae205Smrg const HashBucketPtr *b1 = v1, *b2 = v2; 156ea6ae205Smrg int c1 = strcasecmp((*b1)->key, (*b2)->key); 1576ae2c069Smrg 1586ae2c069Smrg if (c1 != 0) 1596ae2c069Smrg return c1; 160ea6ae205Smrg return strcmp((*b1)->value, (*b2)->value); 161ea6ae205Smrg} 162ea6ae205Smrg 163ea6ae205Smrgstatic int 164ea6ae205Smrgvalue_first_cmp(const void *v1, const void *v2) 165ea6ae205Smrg{ 166ea6ae205Smrg const HashBucketPtr *b1 = v1, *b2 = v2; 167ea6ae205Smrg int c1 = strcmp((*b1)->value, (*b2)->value); 1686ae2c069Smrg 1696ae2c069Smrg if (c1 != 0) 1706ae2c069Smrg return c1; 171ea6ae205Smrg return strcasecmp((*b1)->key, (*b2)->key); 172ea6ae205Smrg} 173ea6ae205Smrg 174ea6ae205SmrgHashBucketPtr * 175ea6ae205SmrghashArray(HashTablePtr table, int value_first) 176ea6ae205Smrg{ 1776ae2c069Smrg unsigned int j; 1786ae2c069Smrg int n = hashElements(table); 1796ae2c069Smrg HashBucketPtr *dst = malloc((n + 1) * sizeof(HashBucketPtr)); 1806ae2c069Smrg if (dst == NULL) 181ea6ae205Smrg return NULL; 182ea6ae205Smrg 183ea6ae205Smrg j = 0; 1846ae2c069Smrg for (unsigned int i = 0; i < NUMBUCKETS; i++) { 1856ae2c069Smrg while (table[i]) { 186ea6ae205Smrg dst[j++] = table[i]; 187ea6ae205Smrg table[i] = table[i]->next; 188ea6ae205Smrg } 189ea6ae205Smrg } 190ea6ae205Smrg qsort(dst, j, sizeof(HashBucketPtr), 191ea6ae205Smrg value_first ? value_first_cmp : key_first_cmp); 192ea6ae205Smrg dst[j++] = NULL; 193ea6ae205Smrg free(table); 194ea6ae205Smrg 195ea6ae205Smrg return dst; 196ea6ae205Smrg} 197ea6ae205Smrg 198ea6ae205Smrgvoid 199ea6ae205SmrgdestroyHashArray(HashBucketPtr *array) 200ea6ae205Smrg{ 2016ae2c069Smrg unsigned int i = 0; 2026ae2c069Smrg 2036ae2c069Smrg while (array[i]) { 204ea6ae205Smrg free(array[i]->key); 205ea6ae205Smrg free(array[i]->value); 206ea6ae205Smrg free(array[i]); 207ea6ae205Smrg i++; 208ea6ae205Smrg } 209ea6ae205Smrg free(array); 210ea6ae205Smrg} 211