aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd/dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'smtpd/dict.c')
-rw-r--r--smtpd/dict.c269
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);