xref: /netbsd-src/external/mpl/bind/dist/lib/isccc/alist.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: alist.c,v 1.9 2025/01/26 16:25:44 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/result.h>
40 
41 #include <isccc/alist.h>
42 #include <isccc/sexpr.h>
43 #include <isccc/util.h>
44 
45 #define CAR(s) (s)->value.as_dottedpair.car
46 #define CDR(s) (s)->value.as_dottedpair.cdr
47 
48 #define ALIST_TAG  "*alist*"
49 #define MAX_INDENT 64
50 
51 static char spaces[MAX_INDENT + 1] = "                                         "
52 				     "                       ";
53 
54 isccc_sexpr_t *
55 isccc_alist_create(void) {
56 	isccc_sexpr_t *alist, *tag;
57 
58 	tag = isccc_sexpr_fromstring(ALIST_TAG);
59 	if (tag == NULL) {
60 		return NULL;
61 	}
62 	alist = isccc_sexpr_cons(tag, NULL);
63 	if (alist == NULL) {
64 		isccc_sexpr_free(&tag);
65 		return NULL;
66 	}
67 
68 	return alist;
69 }
70 
71 bool
72 isccc_alist_alistp(isccc_sexpr_t *alist) {
73 	isccc_sexpr_t *car;
74 
75 	if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) {
76 		return false;
77 	}
78 	car = CAR(alist);
79 	if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING) {
80 		return false;
81 	}
82 	if (strcmp(car->value.as_string, ALIST_TAG) != 0) {
83 		return false;
84 	}
85 	return true;
86 }
87 
88 bool
89 isccc_alist_emptyp(isccc_sexpr_t *alist) {
90 	REQUIRE(isccc_alist_alistp(alist));
91 
92 	if (CDR(alist) == NULL) {
93 		return true;
94 	}
95 	return false;
96 }
97 
98 isccc_sexpr_t *
99 isccc_alist_first(isccc_sexpr_t *alist) {
100 	REQUIRE(isccc_alist_alistp(alist));
101 
102 	return CDR(alist);
103 }
104 
105 isccc_sexpr_t *
106 isccc_alist_assq(isccc_sexpr_t *alist, const char *key) {
107 	isccc_sexpr_t *car, *caar;
108 
109 	REQUIRE(isccc_alist_alistp(alist));
110 
111 	/*
112 	 * Skip alist type tag.
113 	 */
114 	alist = CDR(alist);
115 
116 	while (alist != NULL) {
117 		INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
118 		car = CAR(alist);
119 		INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
120 		caar = CAR(car);
121 		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
122 		    strcmp(caar->value.as_string, key) == 0)
123 		{
124 			return car;
125 		}
126 		alist = CDR(alist);
127 	}
128 
129 	return NULL;
130 }
131 
132 void
133 isccc_alist_delete(isccc_sexpr_t *alist, const char *key) {
134 	isccc_sexpr_t *car, *caar, *rest, *prev;
135 
136 	REQUIRE(isccc_alist_alistp(alist));
137 
138 	prev = alist;
139 	rest = CDR(alist);
140 	while (rest != NULL) {
141 		INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
142 		car = CAR(rest);
143 		INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
144 		caar = CAR(car);
145 		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
146 		    strcmp(caar->value.as_string, key) == 0)
147 		{
148 			CDR(prev) = CDR(rest);
149 			CDR(rest) = NULL;
150 			isccc_sexpr_free(&rest);
151 			break;
152 		}
153 		prev = rest;
154 		rest = CDR(rest);
155 	}
156 }
157 
158 isccc_sexpr_t *
159 isccc_alist_define(isccc_sexpr_t *alist, const char *key,
160 		   isccc_sexpr_t *value) {
161 	isccc_sexpr_t *kv, *k, *elt;
162 
163 	kv = isccc_alist_assq(alist, key);
164 	if (kv == NULL) {
165 		/*
166 		 * New association.
167 		 */
168 		k = isccc_sexpr_fromstring(key);
169 		if (k == NULL) {
170 			return NULL;
171 		}
172 		kv = isccc_sexpr_cons(k, value);
173 		if (kv == NULL) {
174 			isccc_sexpr_free(&kv);
175 			return NULL;
176 		}
177 		elt = isccc_sexpr_addtolist(&alist, kv);
178 		if (elt == NULL) {
179 			isccc_sexpr_free(&kv);
180 			return NULL;
181 		}
182 	} else {
183 		/*
184 		 * We've already got an entry for this key.  Replace it.
185 		 */
186 		isccc_sexpr_free(&CDR(kv));
187 		CDR(kv) = value;
188 	}
189 
190 	return kv;
191 }
192 
193 isccc_sexpr_t *
194 isccc_alist_definestring(isccc_sexpr_t *alist, const char *key,
195 			 const char *str) {
196 	isccc_sexpr_t *v, *kv;
197 
198 	v = isccc_sexpr_fromstring(str);
199 	if (v == NULL) {
200 		return NULL;
201 	}
202 	kv = isccc_alist_define(alist, key, v);
203 	if (kv == NULL) {
204 		isccc_sexpr_free(&v);
205 	}
206 
207 	return kv;
208 }
209 
210 isccc_sexpr_t *
211 isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key,
212 			 isccc_region_t *r) {
213 	isccc_sexpr_t *v, *kv;
214 
215 	v = isccc_sexpr_frombinary(r);
216 	if (v == NULL) {
217 		return NULL;
218 	}
219 	kv = isccc_alist_define(alist, key, v);
220 	if (kv == NULL) {
221 		isccc_sexpr_free(&v);
222 	}
223 
224 	return kv;
225 }
226 
227 isccc_sexpr_t *
228 isccc_alist_lookup(isccc_sexpr_t *alist, const char *key) {
229 	isccc_sexpr_t *kv;
230 
231 	kv = isccc_alist_assq(alist, key);
232 	if (kv != NULL) {
233 		return CDR(kv);
234 	}
235 	return NULL;
236 }
237 
238 isc_result_t
239 isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
240 	isccc_sexpr_t *kv, *v;
241 
242 	kv = isccc_alist_assq(alist, key);
243 	if (kv != NULL) {
244 		v = CDR(kv);
245 		if (isccc_sexpr_stringp(v)) {
246 			if (strp != NULL) {
247 				*strp = isccc_sexpr_tostring(v);
248 			}
249 			return ISC_R_SUCCESS;
250 		} else {
251 			return ISC_R_EXISTS;
252 		}
253 	}
254 
255 	return ISC_R_NOTFOUND;
256 }
257 
258 isc_result_t
259 isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key,
260 			 isccc_region_t **r) {
261 	isccc_sexpr_t *kv, *v;
262 
263 	kv = isccc_alist_assq(alist, key);
264 	if (kv != NULL) {
265 		v = CDR(kv);
266 		if (isccc_sexpr_binaryp(v)) {
267 			if (r != NULL) {
268 				*r = isccc_sexpr_tobinary(v);
269 			}
270 			return ISC_R_SUCCESS;
271 		} else {
272 			return ISC_R_EXISTS;
273 		}
274 	}
275 
276 	return ISC_R_NOTFOUND;
277 }
278 
279 void
280 isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent,
281 			FILE *stream) {
282 	isccc_sexpr_t *elt, *kv, *k, *v;
283 
284 	if (isccc_alist_alistp(sexpr)) {
285 		fprintf(stream, "{\n");
286 		indent += 4;
287 		for (elt = isccc_alist_first(sexpr); elt != NULL;
288 		     elt = CDR(elt))
289 		{
290 			kv = CAR(elt);
291 			INSIST(isccc_sexpr_listp(kv));
292 			k = CAR(kv);
293 			v = CDR(kv);
294 			INSIST(isccc_sexpr_stringp(k));
295 			fprintf(stream, "%.*s%s => ", (int)indent, spaces,
296 				isccc_sexpr_tostring(k));
297 			isccc_alist_prettyprint(v, indent, stream);
298 			if (CDR(elt) != NULL) {
299 				fprintf(stream, ",");
300 			}
301 			fprintf(stream, "\n");
302 		}
303 		indent -= 4;
304 		fprintf(stream, "%.*s}", (int)indent, spaces);
305 	} else if (isccc_sexpr_listp(sexpr)) {
306 		fprintf(stream, "(\n");
307 		indent += 4;
308 		for (elt = sexpr; elt != NULL; elt = CDR(elt)) {
309 			fprintf(stream, "%.*s", (int)indent, spaces);
310 			isccc_alist_prettyprint(CAR(elt), indent, stream);
311 			if (CDR(elt) != NULL) {
312 				fprintf(stream, ",");
313 			}
314 			fprintf(stream, "\n");
315 		}
316 		indent -= 4;
317 		fprintf(stream, "%.*s)", (int)indent, spaces);
318 	} else {
319 		isccc_sexpr_print(sexpr, stream);
320 	}
321 }
322