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