diff options
Diffstat (limited to 'smtpd/dict.c')
-rw-r--r-- | smtpd/dict.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/smtpd/dict.c b/smtpd/dict.c new file mode 100644 index 00000000..e660f0a5 --- /dev/null +++ b/smtpd/dict.c @@ -0,0 +1,269 @@ +/* $OpenBSD: dict.c,v 1.6 2018/12/23 16:06:24 gilles Exp $ */ + +/* + * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> + * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/tree.h> + +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "dict.h" + +struct dictentry { + SPLAY_ENTRY(dictentry) entry; + const char *key; + void *data; +}; + +static int dictentry_cmp(struct dictentry *, struct dictentry *); + +SPLAY_PROTOTYPE(_dict, dictentry, entry, dictentry_cmp); + +int +dict_check(struct dict *d, const char *k) +{ + struct dictentry key; + + key.key = k; + return (SPLAY_FIND(_dict, &d->dict, &key) != NULL); +} + +static inline struct dictentry * +dict_alloc(const char *k, void *data) +{ + struct dictentry *e; + size_t s = strlen(k) + 1; + void *t; + + if ((e = malloc(sizeof(*e) + s)) == NULL) + return NULL; + + e->key = t = (char*)(e) + sizeof(*e); + e->data = data; + memmove(t, k, s); + + return (e); +} + +void * +dict_set(struct dict *d, const char *k, void *data) +{ + struct dictentry *entry, key; + char *old; + + key.key = k; + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) { + if ((entry = dict_alloc(k, data)) == NULL) + err(1, "dict_set: malloc"); + SPLAY_INSERT(_dict, &d->dict, entry); + old = NULL; + d->count += 1; + } else { + old = entry->data; + entry->data = data; + } + + return (old); +} + +void +dict_xset(struct dict *d, const char * k, void *data) +{ + struct dictentry *entry; + + if ((entry = dict_alloc(k, data)) == NULL) + err(1, "dict_xset: malloc"); + if (SPLAY_INSERT(_dict, &d->dict, entry)) + errx(1, "dict_xset(%p, %s)", d, k); + d->count += 1; +} + +void * +dict_get(struct dict *d, const char *k) +{ + struct dictentry key, *entry; + + key.key = k; + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) + return (NULL); + + return (entry->data); +} + +void * +dict_xget(struct dict *d, const char *k) +{ + struct dictentry key, *entry; + + key.key = k; + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) + errx(1, "dict_xget(%p, %s)", d, k); + + return (entry->data); +} + +void * +dict_pop(struct dict *d, const char *k) +{ + struct dictentry key, *entry; + void *data; + + key.key = k; + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) + return (NULL); + + data = entry->data; + SPLAY_REMOVE(_dict, &d->dict, entry); + free(entry); + d->count -= 1; + + return (data); +} + +void * +dict_xpop(struct dict *d, const char *k) +{ + struct dictentry key, *entry; + void *data; + + key.key = k; + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) + errx(1, "dict_xpop(%p, %s)", d, k); + + data = entry->data; + SPLAY_REMOVE(_dict, &d->dict, entry); + free(entry); + d->count -= 1; + + return (data); +} + +int +dict_poproot(struct dict *d, void **data) +{ + struct dictentry *entry; + + entry = SPLAY_ROOT(&d->dict); + if (entry == NULL) + return (0); + if (data) + *data = entry->data; + SPLAY_REMOVE(_dict, &d->dict, entry); + free(entry); + d->count -= 1; + + return (1); +} + +int +dict_root(struct dict *d, const char **k, void **data) +{ + struct dictentry *entry; + + entry = SPLAY_ROOT(&d->dict); + if (entry == NULL) + return (0); + if (k) + *k = entry->key; + if (data) + *data = entry->data; + return (1); +} + +int +dict_iter(struct dict *d, void **hdl, const char **k, void **data) +{ + struct dictentry *curr = *hdl; + + if (curr == NULL) + curr = SPLAY_MIN(_dict, &d->dict); + else + curr = SPLAY_NEXT(_dict, &d->dict, curr); + + if (curr) { + *hdl = curr; + if (k) + *k = curr->key; + if (data) + *data = curr->data; + return (1); + } + + return (0); +} + +int +dict_iterfrom(struct dict *d, void **hdl, const char *kfrom, const char **k, + void **data) +{ + struct dictentry *curr = *hdl, key; + + if (curr == NULL) { + if (kfrom == NULL) + curr = SPLAY_MIN(_dict, &d->dict); + else { + key.key = kfrom; + curr = SPLAY_FIND(_dict, &d->dict, &key); + if (curr == NULL) { + SPLAY_INSERT(_dict, &d->dict, &key); + curr = SPLAY_NEXT(_dict, &d->dict, &key); + SPLAY_REMOVE(_dict, &d->dict, &key); + } + } + } else + curr = SPLAY_NEXT(_dict, &d->dict, curr); + + if (curr) { + *hdl = curr; + if (k) + *k = curr->key; + if (data) + *data = curr->data; + return (1); + } + + return (0); +} + +void +dict_merge(struct dict *dst, struct dict *src) +{ + struct dictentry *entry; + + while (!SPLAY_EMPTY(&src->dict)) { + entry = SPLAY_ROOT(&src->dict); + SPLAY_REMOVE(_dict, &src->dict, entry); + if (SPLAY_INSERT(_dict, &dst->dict, entry)) + errx(1, "dict_merge: duplicate"); + } + dst->count += src->count; + src->count = 0; +} + +static int +dictentry_cmp(struct dictentry *a, struct dictentry *b) +{ + return strcmp(a->key, b->key); +} + +SPLAY_GENERATE(_dict, dictentry, entry, dictentry_cmp); |