1 /* $NetBSD: symtab.c,v 1.4 2014/12/10 04:38:01 christos Exp $ */
4 * Portions Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 2001 Nominum, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
26 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
28 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 /* Id: symtab.c,v 1.11 2007/09/13 04:45:18 each Exp */
43 #include <isc/assertions.h>
44 #include <isc/magic.h>
45 #include <isc/string.h>
47 #include <isccc/result.h>
48 #include <isccc/symtab.h>
49 #include <isccc/util.h>
54 isccc_symvalue_t value
;
55 ISC_LINK(struct elt
) link
;
58 typedef ISC_LIST(elt_t
) eltlist_t
;
60 #define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
61 #define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
67 isccc_symtabundefaction_t undefine_action
;
69 isc_boolean_t case_sensitive
;
73 isccc_symtab_create(unsigned int size
,
74 isccc_symtabundefaction_t undefine_action
,
76 isc_boolean_t case_sensitive
,
77 isccc_symtab_t
**symtabp
)
79 isccc_symtab_t
*symtab
;
82 REQUIRE(symtabp
!= NULL
&& *symtabp
== NULL
);
83 REQUIRE(size
> 0); /* Should be prime. */
85 symtab
= malloc(sizeof(*symtab
));
87 return (ISC_R_NOMEMORY
);
88 symtab
->table
= malloc(size
* sizeof(eltlist_t
));
89 if (symtab
->table
== NULL
) {
91 return (ISC_R_NOMEMORY
);
93 for (i
= 0; i
< size
; i
++)
94 ISC_LIST_INIT(symtab
->table
[i
]);
96 symtab
->undefine_action
= undefine_action
;
97 symtab
->undefine_arg
= undefine_arg
;
98 symtab
->case_sensitive
= case_sensitive
;
99 symtab
->magic
= SYMTAB_MAGIC
;
103 return (ISC_R_SUCCESS
);
107 free_elt(isccc_symtab_t
*symtab
, unsigned int bucket
, elt_t
*elt
) {
108 ISC_LIST_UNLINK(symtab
->table
[bucket
], elt
, link
);
109 if (symtab
->undefine_action
!= NULL
)
110 (symtab
->undefine_action
)(elt
->key
, elt
->type
, elt
->value
,
111 symtab
->undefine_arg
);
116 isccc_symtab_destroy(isccc_symtab_t
**symtabp
) {
117 isccc_symtab_t
*symtab
;
121 REQUIRE(symtabp
!= NULL
);
123 REQUIRE(VALID_SYMTAB(symtab
));
125 for (i
= 0; i
< symtab
->size
; i
++) {
126 for (elt
= ISC_LIST_HEAD(symtab
->table
[i
]);
129 nelt
= ISC_LIST_NEXT(elt
, link
);
130 free_elt(symtab
, i
, elt
);
140 static inline unsigned int
141 hash(const char *key
, isc_boolean_t case_sensitive
) {
148 * P. J. Weinberger's hash function, adapted from p. 436 of
149 * _Compilers: Principles, Techniques, and Tools_, Aho, Sethi
150 * and Ullman, Addison-Wesley, 1986, ISBN 0-201-10088-6.
153 if (case_sensitive
) {
154 for (s
= key
; *s
!= '\0'; s
++) {
156 if ((g
= ( h
& 0xf0000000 )) != 0) {
162 for (s
= key
; *s
!= '\0'; s
++) {
164 c
= tolower((unsigned char)c
);
166 if ((g
= ( h
& 0xf0000000 )) != 0) {
176 #define FIND(s, k, t, b, e) \
177 b = hash((k), (s)->case_sensitive) % (s)->size; \
178 if ((s)->case_sensitive) { \
179 for (e = ISC_LIST_HEAD((s)->table[b]); \
181 e = ISC_LIST_NEXT(e, link)) { \
182 if (((t) == 0 || e->type == (t)) && \
183 strcmp(e->key, (k)) == 0) \
187 for (e = ISC_LIST_HEAD((s)->table[b]); \
189 e = ISC_LIST_NEXT(e, link)) { \
190 if (((t) == 0 || e->type == (t)) && \
191 strcasecmp(e->key, (k)) == 0) \
197 isccc_symtab_lookup(isccc_symtab_t
*symtab
, const char *key
, unsigned int type
,
198 isccc_symvalue_t
*value
)
203 REQUIRE(VALID_SYMTAB(symtab
));
204 REQUIRE(key
!= NULL
);
206 FIND(symtab
, key
, type
, bucket
, elt
);
209 return (ISC_R_NOTFOUND
);
214 return (ISC_R_SUCCESS
);
218 isccc_symtab_define(isccc_symtab_t
*symtab
, char *key
, unsigned int type
,
219 isccc_symvalue_t value
, isccc_symexists_t exists_policy
)
224 REQUIRE(VALID_SYMTAB(symtab
));
225 REQUIRE(key
!= NULL
);
228 FIND(symtab
, key
, type
, bucket
, elt
);
230 if (exists_policy
!= isccc_symexists_add
&& elt
!= NULL
) {
231 if (exists_policy
== isccc_symexists_reject
)
232 return (ISC_R_EXISTS
);
233 INSIST(exists_policy
== isccc_symexists_replace
);
234 ISC_LIST_UNLINK(symtab
->table
[bucket
], elt
, link
);
235 if (symtab
->undefine_action
!= NULL
)
236 (symtab
->undefine_action
)(elt
->key
, elt
->type
,
238 symtab
->undefine_arg
);
240 elt
= malloc(sizeof(*elt
));
242 return (ISC_R_NOMEMORY
);
243 ISC_LINK_INIT(elt
, link
);
251 * We prepend so that the most recent definition will be found.
253 ISC_LIST_PREPEND(symtab
->table
[bucket
], elt
, link
);
255 return (ISC_R_SUCCESS
);
259 isccc_symtab_undefine(isccc_symtab_t
*symtab
, const char *key
, unsigned int type
) {
263 REQUIRE(VALID_SYMTAB(symtab
));
264 REQUIRE(key
!= NULL
);
266 FIND(symtab
, key
, type
, bucket
, elt
);
269 return (ISC_R_NOTFOUND
);
271 free_elt(symtab
, bucket
, elt
);
273 return (ISC_R_SUCCESS
);
277 isccc_symtab_foreach(isccc_symtab_t
*symtab
, isccc_symtabforeachaction_t action
,
283 REQUIRE(VALID_SYMTAB(symtab
));
284 REQUIRE(action
!= NULL
);
286 for (i
= 0; i
< symtab
->size
; i
++) {
287 for (elt
= ISC_LIST_HEAD(symtab
->table
[i
]);
290 nelt
= ISC_LIST_NEXT(elt
, link
);
291 if ((action
)(elt
->key
, elt
->type
, elt
->value
, arg
))
292 free_elt(symtab
, i
, elt
);