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