xref: /openbsd/usr.sbin/smtpd/dict.c (revision d3140113)
1 /*	$OpenBSD: dict.c,v 1.8 2021/06/14 17:58:15 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
6  *
7  * Permission to use, copy, modify, and 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.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY 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.
18  */
19 
20 #include <sys/tree.h>
21 
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "dict.h"
26 #include "log.h"
27 
28 struct dictentry {
29 	SPLAY_ENTRY(dictentry)	entry;
30 	const char	       *key;
31 	void		       *data;
32 };
33 
34 static int dictentry_cmp(struct dictentry *, struct dictentry *);
35 
36 SPLAY_PROTOTYPE(_dict, dictentry, entry, dictentry_cmp);
37 
38 int
dict_check(struct dict * d,const char * k)39 dict_check(struct dict *d, const char *k)
40 {
41 	struct dictentry	key;
42 
43 	key.key = k;
44 	return (SPLAY_FIND(_dict, &d->dict, &key) != NULL);
45 }
46 
47 static inline struct dictentry *
dict_alloc(const char * k,void * data)48 dict_alloc(const char *k, void *data)
49 {
50 	struct dictentry	*e;
51 	size_t			 s = strlen(k) + 1;
52 	void			*t;
53 
54 	if ((e = malloc(sizeof(*e) + s)) == NULL)
55 		return NULL;
56 
57 	e->key = t = (char*)(e) + sizeof(*e);
58 	e->data = data;
59 	memmove(t, k, s);
60 
61 	return (e);
62 }
63 
64 void *
dict_set(struct dict * d,const char * k,void * data)65 dict_set(struct dict *d, const char *k, void *data)
66 {
67 	struct dictentry	*entry, key;
68 	char			*old;
69 
70 	key.key = k;
71 	if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) {
72 		if ((entry = dict_alloc(k, data)) == NULL)
73 			fatal("dict_set: malloc");
74 		SPLAY_INSERT(_dict, &d->dict, entry);
75 		old = NULL;
76 		d->count += 1;
77 	} else {
78 		old = entry->data;
79 		entry->data = data;
80 	}
81 
82 	return (old);
83 }
84 
85 void
dict_xset(struct dict * d,const char * k,void * data)86 dict_xset(struct dict *d, const char * k, void *data)
87 {
88 	struct dictentry	*entry;
89 
90 	if ((entry = dict_alloc(k, data)) == NULL)
91 		fatal("dict_xset: malloc");
92 	if (SPLAY_INSERT(_dict, &d->dict, entry))
93 		fatalx("dict_xset(%p, %s)", d, k);
94 	d->count += 1;
95 }
96 
97 void *
dict_get(struct dict * d,const char * k)98 dict_get(struct dict *d, const char *k)
99 {
100 	struct dictentry	key, *entry;
101 
102 	key.key = k;
103 	if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL)
104 		return (NULL);
105 
106 	return (entry->data);
107 }
108 
109 void *
dict_xget(struct dict * d,const char * k)110 dict_xget(struct dict *d, const char *k)
111 {
112 	struct dictentry	key, *entry;
113 
114 	key.key = k;
115 	if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL)
116 		fatalx("dict_xget(%p, %s)", d, k);
117 
118 	return (entry->data);
119 }
120 
121 void *
dict_pop(struct dict * d,const char * k)122 dict_pop(struct dict *d, const char *k)
123 {
124 	struct dictentry	key, *entry;
125 	void			*data;
126 
127 	key.key = k;
128 	if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL)
129 		return (NULL);
130 
131 	data = entry->data;
132 	SPLAY_REMOVE(_dict, &d->dict, entry);
133 	free(entry);
134 	d->count -= 1;
135 
136 	return (data);
137 }
138 
139 void *
dict_xpop(struct dict * d,const char * k)140 dict_xpop(struct dict *d, const char *k)
141 {
142 	struct dictentry	key, *entry;
143 	void			*data;
144 
145 	key.key = k;
146 	if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL)
147 		fatalx("dict_xpop(%p, %s)", d, k);
148 
149 	data = entry->data;
150 	SPLAY_REMOVE(_dict, &d->dict, entry);
151 	free(entry);
152 	d->count -= 1;
153 
154 	return (data);
155 }
156 
157 int
dict_poproot(struct dict * d,void ** data)158 dict_poproot(struct dict *d, void **data)
159 {
160 	struct dictentry	*entry;
161 
162 	entry = SPLAY_ROOT(&d->dict);
163 	if (entry == NULL)
164 		return (0);
165 	if (data)
166 		*data = entry->data;
167 	SPLAY_REMOVE(_dict, &d->dict, entry);
168 	free(entry);
169 	d->count -= 1;
170 
171 	return (1);
172 }
173 
174 int
dict_root(struct dict * d,const char ** k,void ** data)175 dict_root(struct dict *d, const char **k, void **data)
176 {
177 	struct dictentry	*entry;
178 
179 	entry = SPLAY_ROOT(&d->dict);
180 	if (entry == NULL)
181 		return (0);
182 	if (k)
183 		*k = entry->key;
184 	if (data)
185 		*data = entry->data;
186 	return (1);
187 }
188 
189 int
dict_iter(struct dict * d,void ** hdl,const char ** k,void ** data)190 dict_iter(struct dict *d, void **hdl, const char **k, void **data)
191 {
192 	struct dictentry *curr = *hdl;
193 
194 	if (curr == NULL)
195 		curr = SPLAY_MIN(_dict, &d->dict);
196 	else
197 		curr = SPLAY_NEXT(_dict, &d->dict, curr);
198 
199 	if (curr) {
200 		*hdl = curr;
201 		if (k)
202 			*k = curr->key;
203 		if (data)
204 			*data = curr->data;
205 		return (1);
206 	}
207 
208 	return (0);
209 }
210 
211 int
dict_iterfrom(struct dict * d,void ** hdl,const char * kfrom,const char ** k,void ** data)212 dict_iterfrom(struct dict *d, void **hdl, const char *kfrom, const char **k,
213     void **data)
214 {
215 	struct dictentry *curr = *hdl, key;
216 
217 	if (curr == NULL) {
218 		if (kfrom == NULL)
219 			curr = SPLAY_MIN(_dict, &d->dict);
220 		else {
221 			key.key = kfrom;
222 			curr = SPLAY_FIND(_dict, &d->dict, &key);
223 			if (curr == NULL) {
224 				SPLAY_INSERT(_dict, &d->dict, &key);
225 				curr = SPLAY_NEXT(_dict, &d->dict, &key);
226 				SPLAY_REMOVE(_dict, &d->dict, &key);
227 			}
228 		}
229 	} else
230 		curr = SPLAY_NEXT(_dict, &d->dict, curr);
231 
232 	if (curr) {
233 		*hdl = curr;
234 		if (k)
235 			*k = curr->key;
236 		if (data)
237 			*data = curr->data;
238 		return (1);
239 	}
240 
241 	return (0);
242 }
243 
244 void
dict_merge(struct dict * dst,struct dict * src)245 dict_merge(struct dict *dst, struct dict *src)
246 {
247 	struct dictentry	*entry;
248 
249 	while (!SPLAY_EMPTY(&src->dict)) {
250 		entry = SPLAY_ROOT(&src->dict);
251 		SPLAY_REMOVE(_dict, &src->dict, entry);
252 		if (SPLAY_INSERT(_dict, &dst->dict, entry))
253 			fatalx("dict_merge: duplicate");
254 	}
255 	dst->count += src->count;
256 	src->count = 0;
257 }
258 
259 static int
dictentry_cmp(struct dictentry * a,struct dictentry * b)260 dictentry_cmp(struct dictentry *a, struct dictentry *b)
261 {
262 	return strcmp(a->key, b->key);
263 }
264 
265 SPLAY_GENERATE(_dict, dictentry, entry, dictentry_cmp);
266