1998-12-18 19:06:16 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
2021-06-03 08:37:05 +02:00
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2020-09-14 16:20:40 -07:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
1998-12-18 19:06:16 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
2000-06-22 22:00:42 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2022-06-24 22:11:02 +01:00
|
|
|
#include <isc/ascii.h>
|
2025-02-27 07:37:04 +01:00
|
|
|
#include <isc/fxhash.h>
|
2024-11-29 10:02:13 +01:00
|
|
|
#include <isc/hash.h>
|
|
|
|
#include <isc/hashmap.h>
|
2001-06-04 19:33:39 +00:00
|
|
|
#include <isc/magic.h>
|
2000-04-28 04:16:34 +00:00
|
|
|
#include <isc/mem.h>
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/string.h>
|
1998-12-18 19:06:16 +00:00
|
|
|
#include <isc/symtab.h>
|
1999-12-16 22:24:22 +00:00
|
|
|
#include <isc/util.h>
|
1998-12-18 21:17:37 +00:00
|
|
|
|
1998-12-18 19:06:16 +00:00
|
|
|
typedef struct elt {
|
2024-11-29 10:02:13 +01:00
|
|
|
void *key;
|
|
|
|
size_t size;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int type;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_symvalue_t value;
|
1998-12-18 19:06:16 +00:00
|
|
|
} elt_t;
|
|
|
|
|
2025-02-27 07:37:04 +01:00
|
|
|
/* 4 bits means 16 entries at creation, which matches the common use of
|
2024-11-29 10:02:13 +01:00
|
|
|
* symtab */
|
2025-02-27 07:37:04 +01:00
|
|
|
#define ISC_SYMTAB_INIT_HASH_BITS 4
|
2024-11-29 10:02:13 +01:00
|
|
|
#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
|
|
|
|
#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
|
1998-12-18 21:17:37 +00:00
|
|
|
|
1998-12-18 19:06:16 +00:00
|
|
|
struct isc_symtab {
|
1998-12-18 21:17:37 +00:00
|
|
|
/* Unlocked. */
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int magic;
|
|
|
|
isc_mem_t *mctx;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_symtabaction_t undefine_action;
|
2020-02-13 14:44:37 -08:00
|
|
|
void *undefine_arg;
|
2024-11-29 10:02:13 +01:00
|
|
|
|
|
|
|
isc_hashmap_t *hashmap;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool case_sensitive;
|
1998-12-18 19:06:16 +00:00
|
|
|
};
|
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
static void
|
|
|
|
elt_destroy(isc_symtab_t *symtab, elt_t *elt) {
|
|
|
|
if (symtab->undefine_action != NULL) {
|
|
|
|
(symtab->undefine_action)(elt->key, elt->type, elt->value,
|
|
|
|
symtab->undefine_arg);
|
|
|
|
}
|
|
|
|
isc_mem_put(symtab->mctx, elt, sizeof(*elt));
|
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
void
|
|
|
|
isc_symtab_create(isc_mem_t *mctx, isc_symtabaction_t undefine_action,
|
|
|
|
void *undefine_arg, bool case_sensitive,
|
|
|
|
isc_symtab_t **symtabp) {
|
1998-12-18 19:06:16 +00:00
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(symtabp != NULL && *symtabp == NULL);
|
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_symtab_t *symtab = isc_mem_get(mctx, sizeof(*symtab));
|
|
|
|
*symtab = (isc_symtab_t){
|
|
|
|
.undefine_action = undefine_action,
|
|
|
|
.undefine_arg = undefine_arg,
|
|
|
|
.case_sensitive = case_sensitive,
|
|
|
|
.magic = SYMTAB_MAGIC,
|
|
|
|
};
|
2013-03-08 14:38:03 +11:00
|
|
|
|
|
|
|
isc_mem_attach(mctx, &symtab->mctx);
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_hashmap_create(symtab->mctx, ISC_SYMTAB_INIT_HASH_BITS,
|
|
|
|
&symtab->hashmap);
|
1998-12-18 19:06:16 +00:00
|
|
|
|
|
|
|
*symtabp = symtab;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_symtab_destroy(isc_symtab_t **symtabp) {
|
2024-11-29 10:02:13 +01:00
|
|
|
REQUIRE(symtabp != NULL && VALID_SYMTAB(*symtabp));
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_result_t result;
|
|
|
|
isc_hashmap_iter_t *it = NULL;
|
|
|
|
isc_symtab_t *symtab = *symtabp;
|
2020-02-08 04:37:54 -08:00
|
|
|
*symtabp = NULL;
|
1998-12-18 19:06:16 +00:00
|
|
|
|
1998-12-18 21:17:37 +00:00
|
|
|
symtab->magic = 0;
|
2024-11-29 10:02:13 +01:00
|
|
|
|
|
|
|
isc_hashmap_iter_create(symtab->hashmap, &it);
|
|
|
|
for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;
|
|
|
|
result = isc_hashmap_iter_delcurrent_next(it))
|
|
|
|
{
|
|
|
|
elt_t *elt = NULL;
|
|
|
|
isc_hashmap_iter_current(it, (void **)&elt);
|
|
|
|
elt_destroy(symtab, elt);
|
|
|
|
}
|
|
|
|
INSIST(result == ISC_R_NOMORE);
|
|
|
|
isc_hashmap_iter_destroy(&it);
|
|
|
|
|
|
|
|
isc_hashmap_destroy(&symtab->hashmap);
|
|
|
|
|
2013-03-08 14:38:03 +11:00
|
|
|
isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
|
1998-12-18 19:06:16 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
static bool
|
|
|
|
elt__match(void *node, const void *key0, bool case_sensitive) {
|
|
|
|
const elt_t *elt = node;
|
|
|
|
const elt_t *key = key0;
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
if (elt->size != key->size) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elt->type != key->type) {
|
|
|
|
return false;
|
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
1999-01-04 22:30:28 +00:00
|
|
|
if (case_sensitive) {
|
2024-11-29 10:02:13 +01:00
|
|
|
return memcmp(elt->key, key->key, key->size) == 0;
|
1999-01-04 22:30:28 +00:00
|
|
|
} else {
|
2025-02-27 07:37:04 +01:00
|
|
|
return isc_ascii_lowerequal(elt->key, key->key, key->size);
|
1998-12-18 19:06:16 +00:00
|
|
|
}
|
2024-11-29 10:02:13 +01:00
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
static bool
|
|
|
|
elt_match_case(void *node, const void *key) {
|
|
|
|
return elt__match(node, key, true);
|
1998-12-18 19:06:16 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
static bool
|
|
|
|
elt_match_nocase(void *node, const void *key) {
|
|
|
|
return elt__match(node, key, false);
|
|
|
|
}
|
|
|
|
|
2025-02-27 07:37:04 +01:00
|
|
|
static inline uint32_t
|
|
|
|
elt_hash(elt_t *restrict elt, bool case_sensitive) {
|
|
|
|
const uint8_t *ptr = elt->key;
|
|
|
|
size_t len = elt->size;
|
|
|
|
return fx_hash_bytes(0, ptr, len, case_sensitive);
|
2024-11-29 10:02:13 +01:00
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_symvalue_t *valuep) {
|
1998-12-18 21:17:37 +00:00
|
|
|
REQUIRE(VALID_SYMTAB(symtab));
|
|
|
|
REQUIRE(key != NULL);
|
2024-11-29 10:02:13 +01:00
|
|
|
REQUIRE(type != 0);
|
1998-12-18 21:17:37 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
elt_t *found = NULL;
|
|
|
|
elt_t elt = {
|
|
|
|
.key = UNCONST(key),
|
|
|
|
.size = strlen(key),
|
|
|
|
.type = type,
|
|
|
|
};
|
|
|
|
uint32_t elt_hashval = elt_hash(&elt, symtab->case_sensitive);
|
|
|
|
isc_hashmap_match_fn elt_match = symtab->case_sensitive
|
|
|
|
? elt_match_case
|
|
|
|
: elt_match_nocase;
|
|
|
|
isc_result_t result = isc_hashmap_find(
|
|
|
|
symtab->hashmap, elt_hashval, elt_match, &elt, (void **)&found);
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
SET_IF_NOT_NULL(valuep, found->value);
|
2011-11-30 04:27:17 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
return result;
|
2011-11-30 04:27:17 +00:00
|
|
|
}
|
|
|
|
|
1998-12-18 19:06:16 +00:00
|
|
|
isc_result_t
|
2000-06-01 17:20:56 +00:00
|
|
|
isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_symvalue_t value, isc_symexists_t exists_policy) {
|
2024-11-29 10:02:13 +01:00
|
|
|
return isc_symtab_define_and_return(symtab, key, type, value,
|
|
|
|
exists_policy, NULL);
|
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_result_t
|
|
|
|
isc_symtab_define_and_return(isc_symtab_t *symtab, const char *key,
|
|
|
|
unsigned int type, isc_symvalue_t value,
|
|
|
|
isc_symexists_t exists_policy,
|
|
|
|
isc_symvalue_t *valuep) {
|
1998-12-18 21:17:37 +00:00
|
|
|
REQUIRE(VALID_SYMTAB(symtab));
|
|
|
|
REQUIRE(key != NULL);
|
1998-12-19 00:15:19 +00:00
|
|
|
REQUIRE(type != 0);
|
1998-12-18 21:17:37 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
isc_result_t result;
|
|
|
|
elt_t *found = NULL;
|
|
|
|
elt_t *elt = isc_mem_get(symtab->mctx, sizeof(*elt));
|
|
|
|
*elt = (elt_t){
|
|
|
|
.key = UNCONST(key),
|
|
|
|
.size = strlen(key),
|
|
|
|
.type = type,
|
|
|
|
.value = value,
|
|
|
|
};
|
|
|
|
uint32_t elt_hashval = elt_hash(elt, symtab->case_sensitive);
|
|
|
|
isc_hashmap_match_fn elt_match = symtab->case_sensitive
|
|
|
|
? elt_match_case
|
|
|
|
: elt_match_nocase;
|
|
|
|
again:
|
|
|
|
result = isc_hashmap_add(symtab->hashmap, elt_hashval, elt_match, elt,
|
|
|
|
(void *)elt, (void *)&found);
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
SET_IF_NOT_NULL(valuep, elt->value);
|
|
|
|
return ISC_R_SUCCESS;
|
1998-12-19 00:13:59 +00:00
|
|
|
}
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
switch (exists_policy) {
|
|
|
|
case isc_symexists_reject:
|
|
|
|
SET_IF_NOT_NULL(valuep, found->value);
|
|
|
|
isc_mem_put(symtab->mctx, elt, sizeof(*elt));
|
|
|
|
return ISC_R_EXISTS;
|
|
|
|
case isc_symexists_replace:
|
|
|
|
result = isc_hashmap_delete(symtab->hashmap, elt_hashval,
|
|
|
|
elt_match, elt);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
elt_destroy(symtab, found);
|
|
|
|
goto again;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-11-30 04:27:17 +00:00
|
|
|
|
2024-11-19 10:38:03 +01:00
|
|
|
return ISC_R_SUCCESS;
|
1998-12-18 19:06:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
|
1998-12-18 21:17:37 +00:00
|
|
|
REQUIRE(VALID_SYMTAB(symtab));
|
|
|
|
REQUIRE(key != NULL);
|
2024-11-29 10:02:13 +01:00
|
|
|
REQUIRE(type != 0);
|
1998-12-18 21:17:37 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
elt_t *found = NULL;
|
|
|
|
elt_t elt = {
|
|
|
|
.key = UNCONST(key),
|
|
|
|
.size = strlen(key),
|
|
|
|
.type = type,
|
|
|
|
};
|
|
|
|
uint32_t elt_hashval = elt_hash(&elt, symtab->case_sensitive);
|
|
|
|
isc_hashmap_match_fn elt_match = symtab->case_sensitive
|
|
|
|
? elt_match_case
|
|
|
|
: elt_match_nocase;
|
|
|
|
|
|
|
|
isc_result_t result = isc_hashmap_find(
|
|
|
|
symtab->hashmap, elt_hashval, elt_match, &elt, (void **)&found);
|
|
|
|
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
2024-11-19 10:38:03 +01:00
|
|
|
return ISC_R_NOTFOUND;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-29 10:02:13 +01:00
|
|
|
result = isc_hashmap_delete(symtab->hashmap, elt_hashval, elt_match,
|
|
|
|
&elt);
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
elt_destroy(symtab, found);
|
1998-12-18 19:06:16 +00:00
|
|
|
|
2024-11-19 10:38:03 +01:00
|
|
|
return ISC_R_SUCCESS;
|
1998-12-18 19:06:16 +00:00
|
|
|
}
|
2013-11-13 20:35:40 -08:00
|
|
|
|
|
|
|
unsigned int
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_symtab_count(isc_symtab_t *symtab) {
|
2013-11-13 20:35:40 -08:00
|
|
|
REQUIRE(VALID_SYMTAB(symtab));
|
2024-11-29 10:02:13 +01:00
|
|
|
|
|
|
|
return isc_hashmap_count(symtab->hashmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc_symtab_foreach(isc_symtab_t *symtab, isc_symtabforeachaction_t action,
|
|
|
|
void *arg) {
|
|
|
|
REQUIRE(VALID_SYMTAB(symtab));
|
|
|
|
REQUIRE(action != NULL);
|
|
|
|
|
|
|
|
isc_result_t result;
|
|
|
|
isc_hashmap_iter_t *it = NULL;
|
|
|
|
|
|
|
|
isc_hashmap_iter_create(symtab->hashmap, &it);
|
|
|
|
for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;) {
|
|
|
|
elt_t *elt = NULL;
|
|
|
|
isc_hashmap_iter_current(it, (void **)&elt);
|
|
|
|
if ((action)(elt->key, elt->type, elt->value, arg)) {
|
|
|
|
elt_destroy(symtab, elt);
|
|
|
|
result = isc_hashmap_iter_delcurrent_next(it);
|
|
|
|
} else {
|
|
|
|
result = isc_hashmap_iter_next(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
INSIST(result == ISC_R_NOMORE);
|
|
|
|
isc_hashmap_iter_destroy(&it);
|
2013-11-13 20:35:40 -08:00
|
|
|
}
|