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