Merge from vendor branch NTPD:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isccc / alist.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 2001  Internet Software Consortium.
4  * Portions Copyright (C) 2001  Nominum, Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
13  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 /* $Id: alist.c,v 1.2.2.1 2004/03/09 06:12:25 marka Exp $ */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <isccc/alist.h>
27 #include <isc/assertions.h>
28 #include <isccc/result.h>
29 #include <isccc/sexpr.h>
30 #include <isccc/util.h>
31
32 #define CAR(s)                  (s)->value.as_dottedpair.car
33 #define CDR(s)                  (s)->value.as_dottedpair.cdr
34
35 #define ALIST_TAG               "*alist*"
36 #define MAX_INDENT              64
37
38 static char spaces[MAX_INDENT + 1] = 
39         "                                                                ";
40
41 isccc_sexpr_t *
42 isccc_alist_create(void)
43 {
44         isccc_sexpr_t *alist, *tag;
45
46         tag = isccc_sexpr_fromstring(ALIST_TAG);
47         if (tag == NULL)
48                 return (NULL);
49         alist = isccc_sexpr_cons(tag, NULL);
50         if (alist == NULL) {
51                 isccc_sexpr_free(&tag);
52                 return (NULL);
53         }
54
55         return (alist);
56 }
57
58 isc_boolean_t
59 isccc_alist_alistp(isccc_sexpr_t *alist)
60 {
61         isccc_sexpr_t *car;
62
63         if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR)
64                 return (ISC_FALSE);
65         car = CAR(alist);
66         if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING)
67                 return (ISC_FALSE);
68         if (strcmp(car->value.as_string, ALIST_TAG) != 0)
69                 return (ISC_FALSE);
70         return (ISC_TRUE);
71 }
72
73 isc_boolean_t
74 isccc_alist_emptyp(isccc_sexpr_t *alist)
75 {
76         REQUIRE(isccc_alist_alistp(alist));
77
78         if (CDR(alist) == NULL)
79                 return (ISC_TRUE);
80         return (ISC_FALSE);
81 }
82
83 isccc_sexpr_t *
84 isccc_alist_first(isccc_sexpr_t *alist)
85 {
86         REQUIRE(isccc_alist_alistp(alist));
87
88         return (CDR(alist));
89 }
90
91 isccc_sexpr_t *
92 isccc_alist_assq(isccc_sexpr_t *alist, const char *key)
93 {
94         isccc_sexpr_t *car, *caar;
95
96         REQUIRE(isccc_alist_alistp(alist));
97
98         /*
99          * Skip alist type tag.
100          */
101         alist = CDR(alist);
102
103         while (alist != NULL) {
104                 INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
105                 car = CAR(alist);
106                 INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
107                 caar = CAR(car);
108                 if (caar->type == ISCCC_SEXPRTYPE_STRING &&
109                     strcmp(caar->value.as_string, key) == 0)
110                         return (car);
111                 alist = CDR(alist);
112         }
113
114         return (NULL);
115 }
116
117 void
118 isccc_alist_delete(isccc_sexpr_t *alist, const char *key)
119 {
120         isccc_sexpr_t *car, *caar, *rest, *prev;
121
122         REQUIRE(isccc_alist_alistp(alist));
123
124         prev = alist;
125         rest = CDR(alist);
126         while (rest != NULL) {
127                 INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
128                 car = CAR(rest);
129                 INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
130                 caar = CAR(car);
131                 if (caar->type == ISCCC_SEXPRTYPE_STRING &&
132                     strcmp(caar->value.as_string, key) == 0) {
133                         CDR(prev) = CDR(rest);
134                         CDR(rest) = NULL;
135                         isccc_sexpr_free(&rest);
136                         break;
137                 }
138                 prev = rest;
139                 rest = CDR(rest);
140         }
141 }
142
143 isccc_sexpr_t *
144 isccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value)
145 {
146         isccc_sexpr_t *kv, *k, *elt;
147
148         kv = isccc_alist_assq(alist, key);
149         if (kv == NULL) {
150                 /*
151                  * New association.
152                  */
153                 k = isccc_sexpr_fromstring(key);
154                 if (k == NULL)
155                         return (NULL);
156                 kv = isccc_sexpr_cons(k, value);
157                 if (kv == NULL) {
158                         isccc_sexpr_free(&kv);
159                         return (NULL);
160                 }
161                 elt = isccc_sexpr_addtolist(&alist, kv);
162                 if (elt == NULL) {
163                         isccc_sexpr_free(&kv);
164                         return (NULL);
165                 }
166         } else {
167                 /*
168                  * We've already got an entry for this key.  Replace it.
169                  */
170                 isccc_sexpr_free(&CDR(kv));
171                 CDR(kv) = value;
172         }
173
174         return (kv);
175 }
176
177 isccc_sexpr_t *
178 isccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
179 {
180         isccc_sexpr_t *v, *kv;
181
182         v = isccc_sexpr_fromstring(str);
183         if (v == NULL)
184                 return (NULL);
185         kv = isccc_alist_define(alist, key, v);
186         if (kv == NULL)
187                 isccc_sexpr_free(&v);
188
189         return (kv);
190 }
191
192 isccc_sexpr_t *
193 isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r)
194 {
195         isccc_sexpr_t *v, *kv;
196
197         v = isccc_sexpr_frombinary(r);
198         if (v == NULL)
199                 return (NULL);
200         kv = isccc_alist_define(alist, key, v);
201         if (kv == NULL)
202                 isccc_sexpr_free(&v);
203
204         return (kv);
205 }
206
207 isccc_sexpr_t *
208 isccc_alist_lookup(isccc_sexpr_t *alist, const char *key)
209 {
210         isccc_sexpr_t *kv;
211
212         kv = isccc_alist_assq(alist, key);
213         if (kv != NULL)
214                 return (CDR(kv));
215         return (NULL);
216 }
217
218 isc_result_t
219 isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
220 {
221         isccc_sexpr_t *kv, *v;
222
223         kv = isccc_alist_assq(alist, key);
224         if (kv != NULL) {
225                 v = CDR(kv);
226                 if (isccc_sexpr_stringp(v)) {
227                         if (strp != NULL)
228                                 *strp = isccc_sexpr_tostring(v);
229                         return (ISC_R_SUCCESS);
230                 } else
231                         return (ISC_R_EXISTS);
232         }
233
234         return (ISC_R_NOTFOUND);
235 }
236
237 isc_result_t
238 isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r)
239 {
240         isccc_sexpr_t *kv, *v;
241
242         kv = isccc_alist_assq(alist, key);
243         if (kv != NULL) {
244                 v = CDR(kv);
245                 if (isccc_sexpr_binaryp(v)) {
246                         if (r != NULL)
247                                 *r = isccc_sexpr_tobinary(v);
248                         return (ISC_R_SUCCESS);
249                 } else
250                         return (ISC_R_EXISTS);
251         }
252
253         return (ISC_R_NOTFOUND);
254 }
255
256 void
257 isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream)
258 {
259         isccc_sexpr_t *elt, *kv, *k, *v;
260
261         if (isccc_alist_alistp(sexpr)) {
262                 fprintf(stream, "{\n");
263                 indent += 4;
264                 for (elt = isccc_alist_first(sexpr);
265                      elt != NULL;
266                      elt = CDR(elt)) {
267                         kv = CAR(elt);
268                         INSIST(isccc_sexpr_listp(kv));
269                         k = CAR(kv);
270                         v = CDR(kv);
271                         INSIST(isccc_sexpr_stringp(k));
272                         fprintf(stream, "%.*s%s => ", (int)indent, spaces,
273                                 isccc_sexpr_tostring(k));
274                         isccc_alist_prettyprint(v, indent, stream);
275                         if (CDR(elt) != NULL)
276                                 fprintf(stream, ",");
277                         fprintf(stream, "\n");
278                 }
279                 indent -= 4;
280                 fprintf(stream, "%.*s}", (int)indent, spaces);
281         } else if (isccc_sexpr_listp(sexpr)) {
282                 fprintf(stream, "(\n");
283                 indent += 4;
284                 for (elt = sexpr;
285                      elt != NULL;
286                      elt = CDR(elt)) {
287                         fprintf(stream, "%.*s", (int)indent, spaces);
288                         isccc_alist_prettyprint(CAR(elt), indent, stream);
289                         if (CDR(elt) != NULL)
290                                 fprintf(stream, ",");
291                         fprintf(stream, "\n");
292                 }
293                 indent -= 4;
294                 fprintf(stream, "%.*s)", (int)indent, spaces);
295         } else
296                 isccc_sexpr_print(sexpr, stream);
297 }