xref: /netbsd-src/external/mpl/bind/dist/lib/isccc/alist.c (revision 528ce0b18ee40383f14928382d06afd754b01561)
1 /*	$NetBSD: alist.c,v 1.7 2023/01/25 21:43:32 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0 AND ISC
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*
17  * Copyright (C) 2001 Nominum, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
24  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
26  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31 
32 /*! \file */
33 
34 #include <stdbool.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include <isc/assertions.h>
39 #include <isc/print.h>
40 
41 #include <isccc/alist.h>
42 #include <isccc/result.h>
43 #include <isccc/sexpr.h>
44 #include <isccc/util.h>
45 
46 #define CAR(s) (s)->value.as_dottedpair.car
47 #define CDR(s) (s)->value.as_dottedpair.cdr
48 
49 #define ALIST_TAG  "*alist*"
50 #define MAX_INDENT 64
51 
52 static char spaces[MAX_INDENT + 1] = "                                         "
53 				     "                       ";
54 
55 isccc_sexpr_t *
56 isccc_alist_create(void) {
57 	isccc_sexpr_t *alist, *tag;
58 
59 	tag = isccc_sexpr_fromstring(ALIST_TAG);
60 	if (tag == NULL) {
61 		return (NULL);
62 	}
63 	alist = isccc_sexpr_cons(tag, NULL);
64 	if (alist == NULL) {
65 		isccc_sexpr_free(&tag);
66 		return (NULL);
67 	}
68 
69 	return (alist);
70 }
71 
72 bool
73 isccc_alist_alistp(isccc_sexpr_t *alist) {
74 	isccc_sexpr_t *car;
75 
76 	if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) {
77 		return (false);
78 	}
79 	car = CAR(alist);
80 	if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING) {
81 		return (false);
82 	}
83 	if (strcmp(car->value.as_string, ALIST_TAG) != 0) {
84 		return (false);
85 	}
86 	return (true);
87 }
88 
89 bool
90 isccc_alist_emptyp(isccc_sexpr_t *alist) {
91 	REQUIRE(isccc_alist_alistp(alist));
92 
93 	if (CDR(alist) == NULL) {
94 		return (true);
95 	}
96 	return (false);
97 }
98 
99 isccc_sexpr_t *
100 isccc_alist_first(isccc_sexpr_t *alist) {
101 	REQUIRE(isccc_alist_alistp(alist));
102 
103 	return (CDR(alist));
104 }
105 
106 isccc_sexpr_t *
107 isccc_alist_assq(isccc_sexpr_t *alist, const char *key) {
108 	isccc_sexpr_t *car, *caar;
109 
110 	REQUIRE(isccc_alist_alistp(alist));
111 
112 	/*
113 	 * Skip alist type tag.
114 	 */
115 	alist = CDR(alist);
116 
117 	while (alist != NULL) {
118 		INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
119 		car = CAR(alist);
120 		INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
121 		caar = CAR(car);
122 		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
123 		    strcmp(caar->value.as_string, key) == 0)
124 		{
125 			return (car);
126 		}
127 		alist = CDR(alist);
128 	}
129 
130 	return (NULL);
131 }
132 
133 void
134 isccc_alist_delete(isccc_sexpr_t *alist, const char *key) {
135 	isccc_sexpr_t *car, *caar, *rest, *prev;
136 
137 	REQUIRE(isccc_alist_alistp(alist));
138 
139 	prev = alist;
140 	rest = CDR(alist);
141 	while (rest != NULL) {
142 		INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
143 		car = CAR(rest);
144 		INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
145 		caar = CAR(car);
146 		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
147 		    strcmp(caar->value.as_string, key) == 0)
148 		{
149 			CDR(prev) = CDR(rest);
150 			CDR(rest) = NULL;
151 			isccc_sexpr_free(&rest);
152 			break;
153 		}
154 		prev = rest;
155 		rest = CDR(rest);
156 	}
157 }
158 
159 isccc_sexpr_t *
160 isccc_alist_define(isccc_sexpr_t *alist, const char *key,
161 		   isccc_sexpr_t *value) {
162 	isccc_sexpr_t *kv, *k, *elt;
163 
164 	kv = isccc_alist_assq(alist, key);
165 	if (kv == NULL) {
166 		/*
167 		 * New association.
168 		 */
169 		k = isccc_sexpr_fromstring(key);
170 		if (k == NULL) {
171 			return (NULL);
172 		}
173 		kv = isccc_sexpr_cons(k, value);
174 		if (kv == NULL) {
175 			isccc_sexpr_free(&kv);
176 			return (NULL);
177 		}
178 		elt = isccc_sexpr_addtolist(&alist, kv);
179 		if (elt == NULL) {
180 			isccc_sexpr_free(&kv);
181 			return (NULL);
182 		}
183 	} else {
184 		/*
185 		 * We've already got an entry for this key.  Replace it.
186 		 */
187 		isccc_sexpr_free(&CDR(kv));
188 		CDR(kv) = value;
189 	}
190 
191 	return (kv);
192 }
193 
194 isccc_sexpr_t *
195 isccc_alist_definestring(isccc_sexpr_t *alist, const char *key,
196 			 const char *str) {
197 	isccc_sexpr_t *v, *kv;
198 
199 	v = isccc_sexpr_fromstring(str);
200 	if (v == NULL) {
201 		return (NULL);
202 	}
203 	kv = isccc_alist_define(alist, key, v);
204 	if (kv == NULL) {
205 		isccc_sexpr_free(&v);
206 	}
207 
208 	return (kv);
209 }
210 
211 isccc_sexpr_t *
212 isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key,
213 			 isccc_region_t *r) {
214 	isccc_sexpr_t *v, *kv;
215 
216 	v = isccc_sexpr_frombinary(r);
217 	if (v == NULL) {
218 		return (NULL);
219 	}
220 	kv = isccc_alist_define(alist, key, v);
221 	if (kv == NULL) {
222 		isccc_sexpr_free(&v);
223 	}
224 
225 	return (kv);
226 }
227 
228 isccc_sexpr_t *
229 isccc_alist_lookup(isccc_sexpr_t *alist, const char *key) {
230 	isccc_sexpr_t *kv;
231 
232 	kv = isccc_alist_assq(alist, key);
233 	if (kv != NULL) {
234 		return (CDR(kv));
235 	}
236 	return (NULL);
237 }
238 
239 isc_result_t
240 isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
241 	isccc_sexpr_t *kv, *v;
242 
243 	kv = isccc_alist_assq(alist, key);
244 	if (kv != NULL) {
245 		v = CDR(kv);
246 		if (isccc_sexpr_stringp(v)) {
247 			if (strp != NULL) {
248 				*strp = isccc_sexpr_tostring(v);
249 			}
250 			return (ISC_R_SUCCESS);
251 		} else {
252 			return (ISC_R_EXISTS);
253 		}
254 	}
255 
256 	return (ISC_R_NOTFOUND);
257 }
258 
259 isc_result_t
260 isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key,
261 			 isccc_region_t **r) {
262 	isccc_sexpr_t *kv, *v;
263 
264 	kv = isccc_alist_assq(alist, key);
265 	if (kv != NULL) {
266 		v = CDR(kv);
267 		if (isccc_sexpr_binaryp(v)) {
268 			if (r != NULL) {
269 				*r = isccc_sexpr_tobinary(v);
270 			}
271 			return (ISC_R_SUCCESS);
272 		} else {
273 			return (ISC_R_EXISTS);
274 		}
275 	}
276 
277 	return (ISC_R_NOTFOUND);
278 }
279 
280 void
281 isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent,
282 			FILE *stream) {
283 	isccc_sexpr_t *elt, *kv, *k, *v;
284 
285 	if (isccc_alist_alistp(sexpr)) {
286 		fprintf(stream, "{\n");
287 		indent += 4;
288 		for (elt = isccc_alist_first(sexpr); elt != NULL;
289 		     elt = CDR(elt))
290 		{
291 			kv = CAR(elt);
292 			INSIST(isccc_sexpr_listp(kv));
293 			k = CAR(kv);
294 			v = CDR(kv);
295 			INSIST(isccc_sexpr_stringp(k));
296 			fprintf(stream, "%.*s%s => ", (int)indent, spaces,
297 				isccc_sexpr_tostring(k));
298 			isccc_alist_prettyprint(v, indent, stream);
299 			if (CDR(elt) != NULL) {
300 				fprintf(stream, ",");
301 			}
302 			fprintf(stream, "\n");
303 		}
304 		indent -= 4;
305 		fprintf(stream, "%.*s}", (int)indent, spaces);
306 	} else if (isccc_sexpr_listp(sexpr)) {
307 		fprintf(stream, "(\n");
308 		indent += 4;
309 		for (elt = sexpr; elt != NULL; elt = CDR(elt)) {
310 			fprintf(stream, "%.*s", (int)indent, spaces);
311 			isccc_alist_prettyprint(CAR(elt), indent, stream);
312 			if (CDR(elt) != NULL) {
313 				fprintf(stream, ",");
314 			}
315 			fprintf(stream, "\n");
316 		}
317 		indent -= 4;
318 		fprintf(stream, "%.*s)", (int)indent, spaces);
319 	} else {
320 		isccc_sexpr_print(sexpr, stream);
321 	}
322 }
323