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