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