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