1*00b67f09SDavid van Moolenbroek /* $NetBSD: symtab.c,v 1.4 2014/12/10 04:38:01 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Portions Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Portions Copyright (C) 2001 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
12*00b67f09SDavid van Moolenbroek * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
13*00b67f09SDavid van Moolenbroek * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
14*00b67f09SDavid van Moolenbroek * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*00b67f09SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*00b67f09SDavid van Moolenbroek * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*00b67f09SDavid van Moolenbroek * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek *
19*00b67f09SDavid van Moolenbroek * Portions Copyright (C) 2001 Nominum, Inc.
20*00b67f09SDavid van Moolenbroek *
21*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
22*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
23*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
24*00b67f09SDavid van Moolenbroek *
25*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
26*00b67f09SDavid van Moolenbroek * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27*00b67f09SDavid van Moolenbroek * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
28*00b67f09SDavid van Moolenbroek * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29*00b67f09SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30*00b67f09SDavid van Moolenbroek * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31*00b67f09SDavid van Moolenbroek * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32*00b67f09SDavid van Moolenbroek */
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek /* Id: symtab.c,v 1.11 2007/09/13 04:45:18 each Exp */
35*00b67f09SDavid van Moolenbroek
36*00b67f09SDavid van Moolenbroek /*! \file */
37*00b67f09SDavid van Moolenbroek
38*00b67f09SDavid van Moolenbroek #include <config.h>
39*00b67f09SDavid van Moolenbroek
40*00b67f09SDavid van Moolenbroek #include <ctype.h>
41*00b67f09SDavid van Moolenbroek #include <stdlib.h>
42*00b67f09SDavid van Moolenbroek
43*00b67f09SDavid van Moolenbroek #include <isc/assertions.h>
44*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
45*00b67f09SDavid van Moolenbroek #include <isc/string.h>
46*00b67f09SDavid van Moolenbroek
47*00b67f09SDavid van Moolenbroek #include <isccc/result.h>
48*00b67f09SDavid van Moolenbroek #include <isccc/symtab.h>
49*00b67f09SDavid van Moolenbroek #include <isccc/util.h>
50*00b67f09SDavid van Moolenbroek
51*00b67f09SDavid van Moolenbroek typedef struct elt {
52*00b67f09SDavid van Moolenbroek char * key;
53*00b67f09SDavid van Moolenbroek unsigned int type;
54*00b67f09SDavid van Moolenbroek isccc_symvalue_t value;
55*00b67f09SDavid van Moolenbroek ISC_LINK(struct elt) link;
56*00b67f09SDavid van Moolenbroek } elt_t;
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek typedef ISC_LIST(elt_t) eltlist_t;
59*00b67f09SDavid van Moolenbroek
60*00b67f09SDavid van Moolenbroek #define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
61*00b67f09SDavid van Moolenbroek #define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
62*00b67f09SDavid van Moolenbroek
63*00b67f09SDavid van Moolenbroek struct isccc_symtab {
64*00b67f09SDavid van Moolenbroek unsigned int magic;
65*00b67f09SDavid van Moolenbroek unsigned int size;
66*00b67f09SDavid van Moolenbroek eltlist_t * table;
67*00b67f09SDavid van Moolenbroek isccc_symtabundefaction_t undefine_action;
68*00b67f09SDavid van Moolenbroek void * undefine_arg;
69*00b67f09SDavid van Moolenbroek isc_boolean_t case_sensitive;
70*00b67f09SDavid van Moolenbroek };
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek isc_result_t
isccc_symtab_create(unsigned int size,isccc_symtabundefaction_t undefine_action,void * undefine_arg,isc_boolean_t case_sensitive,isccc_symtab_t ** symtabp)73*00b67f09SDavid van Moolenbroek isccc_symtab_create(unsigned int size,
74*00b67f09SDavid van Moolenbroek isccc_symtabundefaction_t undefine_action,
75*00b67f09SDavid van Moolenbroek void *undefine_arg,
76*00b67f09SDavid van Moolenbroek isc_boolean_t case_sensitive,
77*00b67f09SDavid van Moolenbroek isccc_symtab_t **symtabp)
78*00b67f09SDavid van Moolenbroek {
79*00b67f09SDavid van Moolenbroek isccc_symtab_t *symtab;
80*00b67f09SDavid van Moolenbroek unsigned int i;
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek REQUIRE(symtabp != NULL && *symtabp == NULL);
83*00b67f09SDavid van Moolenbroek REQUIRE(size > 0); /* Should be prime. */
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek symtab = malloc(sizeof(*symtab));
86*00b67f09SDavid van Moolenbroek if (symtab == NULL)
87*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
88*00b67f09SDavid van Moolenbroek symtab->table = malloc(size * sizeof(eltlist_t));
89*00b67f09SDavid van Moolenbroek if (symtab->table == NULL) {
90*00b67f09SDavid van Moolenbroek free(symtab);
91*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
92*00b67f09SDavid van Moolenbroek }
93*00b67f09SDavid van Moolenbroek for (i = 0; i < size; i++)
94*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(symtab->table[i]);
95*00b67f09SDavid van Moolenbroek symtab->size = size;
96*00b67f09SDavid van Moolenbroek symtab->undefine_action = undefine_action;
97*00b67f09SDavid van Moolenbroek symtab->undefine_arg = undefine_arg;
98*00b67f09SDavid van Moolenbroek symtab->case_sensitive = case_sensitive;
99*00b67f09SDavid van Moolenbroek symtab->magic = SYMTAB_MAGIC;
100*00b67f09SDavid van Moolenbroek
101*00b67f09SDavid van Moolenbroek *symtabp = symtab;
102*00b67f09SDavid van Moolenbroek
103*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
104*00b67f09SDavid van Moolenbroek }
105*00b67f09SDavid van Moolenbroek
106*00b67f09SDavid van Moolenbroek static inline void
free_elt(isccc_symtab_t * symtab,unsigned int bucket,elt_t * elt)107*00b67f09SDavid van Moolenbroek free_elt(isccc_symtab_t *symtab, unsigned int bucket, elt_t *elt) {
108*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
109*00b67f09SDavid van Moolenbroek if (symtab->undefine_action != NULL)
110*00b67f09SDavid van Moolenbroek (symtab->undefine_action)(elt->key, elt->type, elt->value,
111*00b67f09SDavid van Moolenbroek symtab->undefine_arg);
112*00b67f09SDavid van Moolenbroek free(elt);
113*00b67f09SDavid van Moolenbroek }
114*00b67f09SDavid van Moolenbroek
115*00b67f09SDavid van Moolenbroek void
isccc_symtab_destroy(isccc_symtab_t ** symtabp)116*00b67f09SDavid van Moolenbroek isccc_symtab_destroy(isccc_symtab_t **symtabp) {
117*00b67f09SDavid van Moolenbroek isccc_symtab_t *symtab;
118*00b67f09SDavid van Moolenbroek unsigned int i;
119*00b67f09SDavid van Moolenbroek elt_t *elt, *nelt;
120*00b67f09SDavid van Moolenbroek
121*00b67f09SDavid van Moolenbroek REQUIRE(symtabp != NULL);
122*00b67f09SDavid van Moolenbroek symtab = *symtabp;
123*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SYMTAB(symtab));
124*00b67f09SDavid van Moolenbroek
125*00b67f09SDavid van Moolenbroek for (i = 0; i < symtab->size; i++) {
126*00b67f09SDavid van Moolenbroek for (elt = ISC_LIST_HEAD(symtab->table[i]);
127*00b67f09SDavid van Moolenbroek elt != NULL;
128*00b67f09SDavid van Moolenbroek elt = nelt) {
129*00b67f09SDavid van Moolenbroek nelt = ISC_LIST_NEXT(elt, link);
130*00b67f09SDavid van Moolenbroek free_elt(symtab, i, elt);
131*00b67f09SDavid van Moolenbroek }
132*00b67f09SDavid van Moolenbroek }
133*00b67f09SDavid van Moolenbroek free(symtab->table);
134*00b67f09SDavid van Moolenbroek symtab->magic = 0;
135*00b67f09SDavid van Moolenbroek free(symtab);
136*00b67f09SDavid van Moolenbroek
137*00b67f09SDavid van Moolenbroek *symtabp = NULL;
138*00b67f09SDavid van Moolenbroek }
139*00b67f09SDavid van Moolenbroek
140*00b67f09SDavid van Moolenbroek static inline unsigned int
hash(const char * key,isc_boolean_t case_sensitive)141*00b67f09SDavid van Moolenbroek hash(const char *key, isc_boolean_t case_sensitive) {
142*00b67f09SDavid van Moolenbroek const char *s;
143*00b67f09SDavid van Moolenbroek unsigned int h = 0;
144*00b67f09SDavid van Moolenbroek unsigned int g;
145*00b67f09SDavid van Moolenbroek int c;
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek /*
148*00b67f09SDavid van Moolenbroek * P. J. Weinberger's hash function, adapted from p. 436 of
149*00b67f09SDavid van Moolenbroek * _Compilers: Principles, Techniques, and Tools_, Aho, Sethi
150*00b67f09SDavid van Moolenbroek * and Ullman, Addison-Wesley, 1986, ISBN 0-201-10088-6.
151*00b67f09SDavid van Moolenbroek */
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek if (case_sensitive) {
154*00b67f09SDavid van Moolenbroek for (s = key; *s != '\0'; s++) {
155*00b67f09SDavid van Moolenbroek h = ( h << 4 ) + *s;
156*00b67f09SDavid van Moolenbroek if ((g = ( h & 0xf0000000 )) != 0) {
157*00b67f09SDavid van Moolenbroek h = h ^ (g >> 24);
158*00b67f09SDavid van Moolenbroek h = h ^ g;
159*00b67f09SDavid van Moolenbroek }
160*00b67f09SDavid van Moolenbroek }
161*00b67f09SDavid van Moolenbroek } else {
162*00b67f09SDavid van Moolenbroek for (s = key; *s != '\0'; s++) {
163*00b67f09SDavid van Moolenbroek c = *s;
164*00b67f09SDavid van Moolenbroek c = tolower((unsigned char)c);
165*00b67f09SDavid van Moolenbroek h = ( h << 4 ) + c;
166*00b67f09SDavid van Moolenbroek if ((g = ( h & 0xf0000000 )) != 0) {
167*00b67f09SDavid van Moolenbroek h = h ^ (g >> 24);
168*00b67f09SDavid van Moolenbroek h = h ^ g;
169*00b67f09SDavid van Moolenbroek }
170*00b67f09SDavid van Moolenbroek }
171*00b67f09SDavid van Moolenbroek }
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek return (h);
174*00b67f09SDavid van Moolenbroek }
175*00b67f09SDavid van Moolenbroek
176*00b67f09SDavid van Moolenbroek #define FIND(s, k, t, b, e) \
177*00b67f09SDavid van Moolenbroek b = hash((k), (s)->case_sensitive) % (s)->size; \
178*00b67f09SDavid van Moolenbroek if ((s)->case_sensitive) { \
179*00b67f09SDavid van Moolenbroek for (e = ISC_LIST_HEAD((s)->table[b]); \
180*00b67f09SDavid van Moolenbroek e != NULL; \
181*00b67f09SDavid van Moolenbroek e = ISC_LIST_NEXT(e, link)) { \
182*00b67f09SDavid van Moolenbroek if (((t) == 0 || e->type == (t)) && \
183*00b67f09SDavid van Moolenbroek strcmp(e->key, (k)) == 0) \
184*00b67f09SDavid van Moolenbroek break; \
185*00b67f09SDavid van Moolenbroek } \
186*00b67f09SDavid van Moolenbroek } else { \
187*00b67f09SDavid van Moolenbroek for (e = ISC_LIST_HEAD((s)->table[b]); \
188*00b67f09SDavid van Moolenbroek e != NULL; \
189*00b67f09SDavid van Moolenbroek e = ISC_LIST_NEXT(e, link)) { \
190*00b67f09SDavid van Moolenbroek if (((t) == 0 || e->type == (t)) && \
191*00b67f09SDavid van Moolenbroek strcasecmp(e->key, (k)) == 0) \
192*00b67f09SDavid van Moolenbroek break; \
193*00b67f09SDavid van Moolenbroek } \
194*00b67f09SDavid van Moolenbroek }
195*00b67f09SDavid van Moolenbroek
196*00b67f09SDavid van Moolenbroek isc_result_t
isccc_symtab_lookup(isccc_symtab_t * symtab,const char * key,unsigned int type,isccc_symvalue_t * value)197*00b67f09SDavid van Moolenbroek isccc_symtab_lookup(isccc_symtab_t *symtab, const char *key, unsigned int type,
198*00b67f09SDavid van Moolenbroek isccc_symvalue_t *value)
199*00b67f09SDavid van Moolenbroek {
200*00b67f09SDavid van Moolenbroek unsigned int bucket;
201*00b67f09SDavid van Moolenbroek elt_t *elt;
202*00b67f09SDavid van Moolenbroek
203*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SYMTAB(symtab));
204*00b67f09SDavid van Moolenbroek REQUIRE(key != NULL);
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek FIND(symtab, key, type, bucket, elt);
207*00b67f09SDavid van Moolenbroek
208*00b67f09SDavid van Moolenbroek if (elt == NULL)
209*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
210*00b67f09SDavid van Moolenbroek
211*00b67f09SDavid van Moolenbroek if (value != NULL)
212*00b67f09SDavid van Moolenbroek *value = elt->value;
213*00b67f09SDavid van Moolenbroek
214*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
215*00b67f09SDavid van Moolenbroek }
216*00b67f09SDavid van Moolenbroek
217*00b67f09SDavid van Moolenbroek isc_result_t
isccc_symtab_define(isccc_symtab_t * symtab,char * key,unsigned int type,isccc_symvalue_t value,isccc_symexists_t exists_policy)218*00b67f09SDavid van Moolenbroek isccc_symtab_define(isccc_symtab_t *symtab, char *key, unsigned int type,
219*00b67f09SDavid van Moolenbroek isccc_symvalue_t value, isccc_symexists_t exists_policy)
220*00b67f09SDavid van Moolenbroek {
221*00b67f09SDavid van Moolenbroek unsigned int bucket;
222*00b67f09SDavid van Moolenbroek elt_t *elt;
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SYMTAB(symtab));
225*00b67f09SDavid van Moolenbroek REQUIRE(key != NULL);
226*00b67f09SDavid van Moolenbroek REQUIRE(type != 0);
227*00b67f09SDavid van Moolenbroek
228*00b67f09SDavid van Moolenbroek FIND(symtab, key, type, bucket, elt);
229*00b67f09SDavid van Moolenbroek
230*00b67f09SDavid van Moolenbroek if (exists_policy != isccc_symexists_add && elt != NULL) {
231*00b67f09SDavid van Moolenbroek if (exists_policy == isccc_symexists_reject)
232*00b67f09SDavid van Moolenbroek return (ISC_R_EXISTS);
233*00b67f09SDavid van Moolenbroek INSIST(exists_policy == isccc_symexists_replace);
234*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
235*00b67f09SDavid van Moolenbroek if (symtab->undefine_action != NULL)
236*00b67f09SDavid van Moolenbroek (symtab->undefine_action)(elt->key, elt->type,
237*00b67f09SDavid van Moolenbroek elt->value,
238*00b67f09SDavid van Moolenbroek symtab->undefine_arg);
239*00b67f09SDavid van Moolenbroek } else {
240*00b67f09SDavid van Moolenbroek elt = malloc(sizeof(*elt));
241*00b67f09SDavid van Moolenbroek if (elt == NULL)
242*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
243*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(elt, link);
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek
246*00b67f09SDavid van Moolenbroek elt->key = key;
247*00b67f09SDavid van Moolenbroek elt->type = type;
248*00b67f09SDavid van Moolenbroek elt->value = value;
249*00b67f09SDavid van Moolenbroek
250*00b67f09SDavid van Moolenbroek /*
251*00b67f09SDavid van Moolenbroek * We prepend so that the most recent definition will be found.
252*00b67f09SDavid van Moolenbroek */
253*00b67f09SDavid van Moolenbroek ISC_LIST_PREPEND(symtab->table[bucket], elt, link);
254*00b67f09SDavid van Moolenbroek
255*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
256*00b67f09SDavid van Moolenbroek }
257*00b67f09SDavid van Moolenbroek
258*00b67f09SDavid van Moolenbroek isc_result_t
isccc_symtab_undefine(isccc_symtab_t * symtab,const char * key,unsigned int type)259*00b67f09SDavid van Moolenbroek isccc_symtab_undefine(isccc_symtab_t *symtab, const char *key, unsigned int type) {
260*00b67f09SDavid van Moolenbroek unsigned int bucket;
261*00b67f09SDavid van Moolenbroek elt_t *elt;
262*00b67f09SDavid van Moolenbroek
263*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SYMTAB(symtab));
264*00b67f09SDavid van Moolenbroek REQUIRE(key != NULL);
265*00b67f09SDavid van Moolenbroek
266*00b67f09SDavid van Moolenbroek FIND(symtab, key, type, bucket, elt);
267*00b67f09SDavid van Moolenbroek
268*00b67f09SDavid van Moolenbroek if (elt == NULL)
269*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
270*00b67f09SDavid van Moolenbroek
271*00b67f09SDavid van Moolenbroek free_elt(symtab, bucket, elt);
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
274*00b67f09SDavid van Moolenbroek }
275*00b67f09SDavid van Moolenbroek
276*00b67f09SDavid van Moolenbroek void
isccc_symtab_foreach(isccc_symtab_t * symtab,isccc_symtabforeachaction_t action,void * arg)277*00b67f09SDavid van Moolenbroek isccc_symtab_foreach(isccc_symtab_t *symtab, isccc_symtabforeachaction_t action,
278*00b67f09SDavid van Moolenbroek void *arg)
279*00b67f09SDavid van Moolenbroek {
280*00b67f09SDavid van Moolenbroek unsigned int i;
281*00b67f09SDavid van Moolenbroek elt_t *elt, *nelt;
282*00b67f09SDavid van Moolenbroek
283*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SYMTAB(symtab));
284*00b67f09SDavid van Moolenbroek REQUIRE(action != NULL);
285*00b67f09SDavid van Moolenbroek
286*00b67f09SDavid van Moolenbroek for (i = 0; i < symtab->size; i++) {
287*00b67f09SDavid van Moolenbroek for (elt = ISC_LIST_HEAD(symtab->table[i]);
288*00b67f09SDavid van Moolenbroek elt != NULL;
289*00b67f09SDavid van Moolenbroek elt = nelt) {
290*00b67f09SDavid van Moolenbroek nelt = ISC_LIST_NEXT(elt, link);
291*00b67f09SDavid van Moolenbroek if ((action)(elt->key, elt->type, elt->value, arg))
292*00b67f09SDavid van Moolenbroek free_elt(symtab, i, elt);
293*00b67f09SDavid van Moolenbroek }
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek }
296