hash.c revision 87aef7c3
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
2387aef7c3Smrg#include "config.h"
2487aef7c3Smrg
25ea6ae205Smrg#include <stdlib.h>
26ea6ae205Smrg#include <stdio.h>
27ea6ae205Smrg#include <string.h>
28ea6ae205Smrg#include <ctype.h>
29ea6ae205Smrg#include "hash.h"
30ea6ae205Smrg#include "list.h"
31ea6ae205Smrg
32ea6ae205Smrg#define LOG2_NUMBUCKETS 10
33ea6ae205Smrg#define NUMBUCKETS (1 << LOG2_NUMBUCKETS)
34ea6ae205Smrg
35ea6ae205Smrgstatic unsigned
36663cdc11Smrghash(const char *string)
37ea6ae205Smrg{
38ea6ae205Smrg    int i;
39ea6ae205Smrg    unsigned u = 0;
40ea6ae205Smrg    for(i = 0; string[i] != '\0'; i++)
41ea6ae205Smrg        u = (u<<5) + (u >> (LOG2_NUMBUCKETS - 5)) + (unsigned char)string[i];
42ea6ae205Smrg    return (u & (NUMBUCKETS - 1));
43ea6ae205Smrg}
44ea6ae205Smrg
45ea6ae205Smrgstatic void
4687aef7c3Smrgstr_tolower(char *s)
47ea6ae205Smrg{
4887aef7c3Smrg    while(*s != '\0') {
4987aef7c3Smrg        *s = tolower(*s);
5087aef7c3Smrg        s++;
51ea6ae205Smrg    }
52ea6ae205Smrg}
53ea6ae205Smrg
54ea6ae205SmrgHashTablePtr
55ea6ae205SmrgmakeHashTable(void)
56ea6ae205Smrg{
57ea6ae205Smrg    return calloc(NUMBUCKETS, sizeof(HashBucketPtr));
58ea6ae205Smrg}
59ea6ae205Smrg
60ea6ae205Smrgvoid
61ea6ae205SmrgdestroyHashTable(HashTablePtr table)
62ea6ae205Smrg{
63ea6ae205Smrg    int i;
64ea6ae205Smrg    HashBucketPtr bp;
65ea6ae205Smrg
66ea6ae205Smrg    for(i = 0; i < NUMBUCKETS; i++) {
67ea6ae205Smrg        while(table[i]) {
68ea6ae205Smrg            bp = table[i];
69ea6ae205Smrg            table[i] = table[i]->next;
70ea6ae205Smrg            free(bp->key);
71ea6ae205Smrg            free(bp->value);
72ea6ae205Smrg            free(bp);
73ea6ae205Smrg        }
74ea6ae205Smrg    }
75ea6ae205Smrg    free(table);
76ea6ae205Smrg}
77ea6ae205Smrg
78ea6ae205Smrgchar *
79663cdc11SmrggetHash(HashTablePtr table, const char *key)
80ea6ae205Smrg{
8187aef7c3Smrg    unsigned int i = hash(key);
82ea6ae205Smrg    HashBucketPtr bp;
83ea6ae205Smrg    for(bp = table[i]; bp; bp = bp->next) {
84ea6ae205Smrg        if(strcasecmp(bp->key, key) == 0)
85ea6ae205Smrg            return bp->value;
86ea6ae205Smrg    }
87ea6ae205Smrg    return NULL;
88ea6ae205Smrg}
89ea6ae205Smrg
90ea6ae205Smrgint
91ea6ae205SmrgputHash(HashTablePtr table, char *key, char *value, int prio)
92ea6ae205Smrg{
9387aef7c3Smrg    unsigned int i = hash(key);
94ea6ae205Smrg    char *keycopy = NULL, *valuecopy = NULL;
95ea6ae205Smrg    HashBucketPtr bp;
96ea6ae205Smrg    for(bp = table[i]; bp; bp = bp->next) {
97ea6ae205Smrg        if(strcasecmp(bp->key, key) == 0) {
98ea6ae205Smrg            if(prio > bp->prio) {
9987aef7c3Smrg                keycopy = strdup(key);
100ea6ae205Smrg                if(keycopy == NULL) goto fail;
10187aef7c3Smrg                str_tolower(keycopy);
10287aef7c3Smrg                valuecopy = strdup(value);
103ea6ae205Smrg                if(valuecopy == NULL) goto fail;
104ea6ae205Smrg                free(bp->key);
105ea6ae205Smrg                free(bp->value);
106ea6ae205Smrg                bp->key = keycopy;
107ea6ae205Smrg                bp->value = valuecopy;
108ea6ae205Smrg            }
109ea6ae205Smrg            return 1;
110ea6ae205Smrg        }
111ea6ae205Smrg    }
11287aef7c3Smrg    keycopy = strdup(key);
113ea6ae205Smrg    if(keycopy == NULL)
114ea6ae205Smrg        goto fail;
11587aef7c3Smrg    str_tolower(keycopy);
11687aef7c3Smrg    valuecopy = strdup(value);
117ea6ae205Smrg    if(valuecopy == NULL)
118ea6ae205Smrg        goto fail;
119ea6ae205Smrg    bp = malloc(sizeof(HashBucketRec));
120ea6ae205Smrg    if(bp == NULL)
121ea6ae205Smrg        goto fail;
122ea6ae205Smrg    bp->key = keycopy;
123ea6ae205Smrg    bp->value = valuecopy;
124ea6ae205Smrg    bp->prio = prio;
125ea6ae205Smrg    bp->next = table[i];
126ea6ae205Smrg    table[i] = bp;
127ea6ae205Smrg    return 1;
128ea6ae205Smrg
129ea6ae205Smrg fail:
130ea6ae205Smrg    if(keycopy) free(keycopy);
131ea6ae205Smrg    if(valuecopy) free(valuecopy);
132ea6ae205Smrg    return -1;
133ea6ae205Smrg}
134ea6ae205Smrg
135ea6ae205Smrgint
136ea6ae205SmrghashElements(HashTablePtr table)
137ea6ae205Smrg{
138ea6ae205Smrg    int i, n;
139ea6ae205Smrg    HashBucketPtr bp;
140ea6ae205Smrg
141ea6ae205Smrg    n = 0;
142ea6ae205Smrg    for(i = 0; i < NUMBUCKETS; i++) {
143ea6ae205Smrg        for(bp = table[i]; bp; bp = bp->next) {
144ea6ae205Smrg            n++;
145ea6ae205Smrg        }
146ea6ae205Smrg    }
147ea6ae205Smrg    return n;
148ea6ae205Smrg}
149ea6ae205Smrg
150ea6ae205Smrgstatic int
151ea6ae205Smrgkey_first_cmp(const void *v1, const void *v2)
152ea6ae205Smrg{
153ea6ae205Smrg    const HashBucketPtr *b1 = v1, *b2 = v2;
154ea6ae205Smrg    int c1 = strcasecmp((*b1)->key, (*b2)->key);
155ea6ae205Smrg    if(c1 != 0) return c1;
156ea6ae205Smrg    return strcmp((*b1)->value, (*b2)->value);
157ea6ae205Smrg}
158ea6ae205Smrg
159ea6ae205Smrgstatic int
160ea6ae205Smrgvalue_first_cmp(const void *v1, const void *v2)
161ea6ae205Smrg{
162ea6ae205Smrg    const HashBucketPtr *b1 = v1, *b2 = v2;
163ea6ae205Smrg    int c1 = strcmp((*b1)->value, (*b2)->value);
164ea6ae205Smrg    if(c1 != 0) return c1;
165ea6ae205Smrg    return strcasecmp((*b1)->key, (*b2)->key);
166ea6ae205Smrg}
167ea6ae205Smrg
168ea6ae205SmrgHashBucketPtr *
169ea6ae205SmrghashArray(HashTablePtr table, int value_first)
170ea6ae205Smrg{
171ea6ae205Smrg    int i, j, n;
172ea6ae205Smrg    HashBucketPtr *dst;
173663cdc11Smrg
174ea6ae205Smrg    n = hashElements(table);
175ea6ae205Smrg    dst = malloc((n + 1) * sizeof(HashBucketPtr));
176ea6ae205Smrg    if(dst == NULL)
177ea6ae205Smrg        return NULL;
178ea6ae205Smrg
179ea6ae205Smrg    j = 0;
180ea6ae205Smrg    for(i = 0; i < NUMBUCKETS; i++) {
181ea6ae205Smrg        while(table[i]) {
182ea6ae205Smrg            dst[j++] = table[i];
183ea6ae205Smrg            table[i] = table[i]->next;
184ea6ae205Smrg        }
185ea6ae205Smrg    }
186ea6ae205Smrg    qsort(dst, j, sizeof(HashBucketPtr),
187ea6ae205Smrg          value_first ? value_first_cmp : key_first_cmp);
188ea6ae205Smrg    dst[j++] = NULL;
189ea6ae205Smrg    free(table);
190ea6ae205Smrg
191ea6ae205Smrg    return dst;
192ea6ae205Smrg}
193ea6ae205Smrg
194ea6ae205Smrgvoid
195ea6ae205SmrgdestroyHashArray(HashBucketPtr *array)
196ea6ae205Smrg{
197ea6ae205Smrg    int i = 0;
198ea6ae205Smrg    while(array[i]) {
199ea6ae205Smrg        free(array[i]->key);
200ea6ae205Smrg        free(array[i]->value);
201ea6ae205Smrg        free(array[i]);
202ea6ae205Smrg        i++;
203ea6ae205Smrg    }
204ea6ae205Smrg    free(array);
205ea6ae205Smrg}
206