1135446Strhodes/*
2193149Sdougb * Portions Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Portions Copyright (C) 2001  Internet Software Consortium.
4193149Sdougb *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6193149Sdougb * purpose with or without fee is hereby granted, provided that the above
7193149Sdougb * copyright notice and this permission notice appear in all copies.
8193149Sdougb *
9193149Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
10193149Sdougb * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11193149Sdougb * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
12193149Sdougb * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13193149Sdougb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14193149Sdougb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15193149Sdougb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16193149Sdougb *
17135446Strhodes * Portions Copyright (C) 2001  Nominum, Inc.
18135446Strhodes *
19193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
20135446Strhodes * purpose with or without fee is hereby granted, provided that the above
21135446Strhodes * copyright notice and this permission notice appear in all copies.
22135446Strhodes *
23135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
24135446Strhodes * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
25135446Strhodes * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
26135446Strhodes * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27135446Strhodes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28135446Strhodes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29135446Strhodes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30135446Strhodes */
31135446Strhodes
32234010Sdougb/* $Id: alist.c,v 1.8 2007/08/28 07:20:43 tbox Exp $ */
33135446Strhodes
34170222Sdougb/*! \file */
35170222Sdougb
36135446Strhodes#include <config.h>
37135446Strhodes
38135446Strhodes#include <stdlib.h>
39135446Strhodes#include <string.h>
40135446Strhodes
41135446Strhodes#include <isccc/alist.h>
42135446Strhodes#include <isc/assertions.h>
43135446Strhodes#include <isccc/result.h>
44135446Strhodes#include <isccc/sexpr.h>
45135446Strhodes#include <isccc/util.h>
46135446Strhodes
47135446Strhodes#define CAR(s)			(s)->value.as_dottedpair.car
48135446Strhodes#define CDR(s)			(s)->value.as_dottedpair.cdr
49135446Strhodes
50135446Strhodes#define ALIST_TAG		"*alist*"
51135446Strhodes#define MAX_INDENT		64
52135446Strhodes
53135446Strhodesstatic char spaces[MAX_INDENT + 1] =
54135446Strhodes	"                                                                ";
55135446Strhodes
56135446Strhodesisccc_sexpr_t *
57135446Strhodesisccc_alist_create(void)
58135446Strhodes{
59135446Strhodes	isccc_sexpr_t *alist, *tag;
60135446Strhodes
61135446Strhodes	tag = isccc_sexpr_fromstring(ALIST_TAG);
62135446Strhodes	if (tag == NULL)
63135446Strhodes		return (NULL);
64135446Strhodes	alist = isccc_sexpr_cons(tag, NULL);
65135446Strhodes	if (alist == NULL) {
66135446Strhodes		isccc_sexpr_free(&tag);
67135446Strhodes		return (NULL);
68135446Strhodes	}
69135446Strhodes
70135446Strhodes	return (alist);
71135446Strhodes}
72135446Strhodes
73135446Strhodesisc_boolean_t
74135446Strhodesisccc_alist_alistp(isccc_sexpr_t *alist)
75135446Strhodes{
76135446Strhodes	isccc_sexpr_t *car;
77135446Strhodes
78135446Strhodes	if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR)
79135446Strhodes		return (ISC_FALSE);
80135446Strhodes	car = CAR(alist);
81135446Strhodes	if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING)
82135446Strhodes		return (ISC_FALSE);
83135446Strhodes	if (strcmp(car->value.as_string, ALIST_TAG) != 0)
84135446Strhodes		return (ISC_FALSE);
85135446Strhodes	return (ISC_TRUE);
86135446Strhodes}
87135446Strhodes
88135446Strhodesisc_boolean_t
89135446Strhodesisccc_alist_emptyp(isccc_sexpr_t *alist)
90135446Strhodes{
91135446Strhodes	REQUIRE(isccc_alist_alistp(alist));
92135446Strhodes
93135446Strhodes	if (CDR(alist) == NULL)
94135446Strhodes		return (ISC_TRUE);
95135446Strhodes	return (ISC_FALSE);
96135446Strhodes}
97135446Strhodes
98135446Strhodesisccc_sexpr_t *
99135446Strhodesisccc_alist_first(isccc_sexpr_t *alist)
100135446Strhodes{
101135446Strhodes	REQUIRE(isccc_alist_alistp(alist));
102135446Strhodes
103135446Strhodes	return (CDR(alist));
104135446Strhodes}
105135446Strhodes
106135446Strhodesisccc_sexpr_t *
107135446Strhodesisccc_alist_assq(isccc_sexpr_t *alist, const char *key)
108135446Strhodes{
109135446Strhodes	isccc_sexpr_t *car, *caar;
110135446Strhodes
111135446Strhodes	REQUIRE(isccc_alist_alistp(alist));
112135446Strhodes
113135446Strhodes	/*
114135446Strhodes	 * Skip alist type tag.
115135446Strhodes	 */
116135446Strhodes	alist = CDR(alist);
117135446Strhodes
118135446Strhodes	while (alist != NULL) {
119135446Strhodes		INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
120135446Strhodes		car = CAR(alist);
121135446Strhodes		INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
122135446Strhodes		caar = CAR(car);
123135446Strhodes		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
124135446Strhodes		    strcmp(caar->value.as_string, key) == 0)
125135446Strhodes			return (car);
126135446Strhodes		alist = CDR(alist);
127135446Strhodes	}
128135446Strhodes
129135446Strhodes	return (NULL);
130135446Strhodes}
131135446Strhodes
132135446Strhodesvoid
133135446Strhodesisccc_alist_delete(isccc_sexpr_t *alist, const char *key)
134135446Strhodes{
135135446Strhodes	isccc_sexpr_t *car, *caar, *rest, *prev;
136135446Strhodes
137135446Strhodes	REQUIRE(isccc_alist_alistp(alist));
138135446Strhodes
139135446Strhodes	prev = alist;
140135446Strhodes	rest = CDR(alist);
141135446Strhodes	while (rest != NULL) {
142135446Strhodes		INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
143135446Strhodes		car = CAR(rest);
144135446Strhodes		INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
145135446Strhodes		caar = CAR(car);
146135446Strhodes		if (caar->type == ISCCC_SEXPRTYPE_STRING &&
147135446Strhodes		    strcmp(caar->value.as_string, key) == 0) {
148135446Strhodes			CDR(prev) = CDR(rest);
149135446Strhodes			CDR(rest) = NULL;
150135446Strhodes			isccc_sexpr_free(&rest);
151135446Strhodes			break;
152135446Strhodes		}
153135446Strhodes		prev = rest;
154135446Strhodes		rest = CDR(rest);
155135446Strhodes	}
156135446Strhodes}
157135446Strhodes
158135446Strhodesisccc_sexpr_t *
159135446Strhodesisccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value)
160135446Strhodes{
161135446Strhodes	isccc_sexpr_t *kv, *k, *elt;
162135446Strhodes
163135446Strhodes	kv = isccc_alist_assq(alist, key);
164135446Strhodes	if (kv == NULL) {
165135446Strhodes		/*
166135446Strhodes		 * New association.
167135446Strhodes		 */
168135446Strhodes		k = isccc_sexpr_fromstring(key);
169135446Strhodes		if (k == NULL)
170135446Strhodes			return (NULL);
171135446Strhodes		kv = isccc_sexpr_cons(k, value);
172135446Strhodes		if (kv == NULL) {
173135446Strhodes			isccc_sexpr_free(&kv);
174135446Strhodes			return (NULL);
175135446Strhodes		}
176135446Strhodes		elt = isccc_sexpr_addtolist(&alist, kv);
177135446Strhodes		if (elt == NULL) {
178135446Strhodes			isccc_sexpr_free(&kv);
179135446Strhodes			return (NULL);
180135446Strhodes		}
181135446Strhodes	} else {
182135446Strhodes		/*
183135446Strhodes		 * We've already got an entry for this key.  Replace it.
184135446Strhodes		 */
185135446Strhodes		isccc_sexpr_free(&CDR(kv));
186135446Strhodes		CDR(kv) = value;
187135446Strhodes	}
188135446Strhodes
189135446Strhodes	return (kv);
190135446Strhodes}
191135446Strhodes
192135446Strhodesisccc_sexpr_t *
193135446Strhodesisccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
194135446Strhodes{
195135446Strhodes	isccc_sexpr_t *v, *kv;
196135446Strhodes
197135446Strhodes	v = isccc_sexpr_fromstring(str);
198135446Strhodes	if (v == NULL)
199135446Strhodes		return (NULL);
200135446Strhodes	kv = isccc_alist_define(alist, key, v);
201135446Strhodes	if (kv == NULL)
202135446Strhodes		isccc_sexpr_free(&v);
203135446Strhodes
204135446Strhodes	return (kv);
205135446Strhodes}
206135446Strhodes
207135446Strhodesisccc_sexpr_t *
208135446Strhodesisccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r)
209135446Strhodes{
210135446Strhodes	isccc_sexpr_t *v, *kv;
211135446Strhodes
212135446Strhodes	v = isccc_sexpr_frombinary(r);
213135446Strhodes	if (v == NULL)
214135446Strhodes		return (NULL);
215135446Strhodes	kv = isccc_alist_define(alist, key, v);
216135446Strhodes	if (kv == NULL)
217135446Strhodes		isccc_sexpr_free(&v);
218135446Strhodes
219135446Strhodes	return (kv);
220135446Strhodes}
221135446Strhodes
222135446Strhodesisccc_sexpr_t *
223135446Strhodesisccc_alist_lookup(isccc_sexpr_t *alist, const char *key)
224135446Strhodes{
225135446Strhodes	isccc_sexpr_t *kv;
226135446Strhodes
227135446Strhodes	kv = isccc_alist_assq(alist, key);
228135446Strhodes	if (kv != NULL)
229135446Strhodes		return (CDR(kv));
230135446Strhodes	return (NULL);
231135446Strhodes}
232135446Strhodes
233135446Strhodesisc_result_t
234135446Strhodesisccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
235135446Strhodes{
236135446Strhodes	isccc_sexpr_t *kv, *v;
237135446Strhodes
238135446Strhodes	kv = isccc_alist_assq(alist, key);
239135446Strhodes	if (kv != NULL) {
240135446Strhodes		v = CDR(kv);
241135446Strhodes		if (isccc_sexpr_stringp(v)) {
242135446Strhodes			if (strp != NULL)
243135446Strhodes				*strp = isccc_sexpr_tostring(v);
244135446Strhodes			return (ISC_R_SUCCESS);
245135446Strhodes		} else
246135446Strhodes			return (ISC_R_EXISTS);
247135446Strhodes	}
248135446Strhodes
249135446Strhodes	return (ISC_R_NOTFOUND);
250135446Strhodes}
251135446Strhodes
252135446Strhodesisc_result_t
253135446Strhodesisccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r)
254135446Strhodes{
255135446Strhodes	isccc_sexpr_t *kv, *v;
256135446Strhodes
257135446Strhodes	kv = isccc_alist_assq(alist, key);
258135446Strhodes	if (kv != NULL) {
259135446Strhodes		v = CDR(kv);
260135446Strhodes		if (isccc_sexpr_binaryp(v)) {
261135446Strhodes			if (r != NULL)
262135446Strhodes				*r = isccc_sexpr_tobinary(v);
263135446Strhodes			return (ISC_R_SUCCESS);
264135446Strhodes		} else
265135446Strhodes			return (ISC_R_EXISTS);
266135446Strhodes	}
267135446Strhodes
268135446Strhodes	return (ISC_R_NOTFOUND);
269135446Strhodes}
270135446Strhodes
271135446Strhodesvoid
272135446Strhodesisccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream)
273135446Strhodes{
274135446Strhodes	isccc_sexpr_t *elt, *kv, *k, *v;
275135446Strhodes
276135446Strhodes	if (isccc_alist_alistp(sexpr)) {
277135446Strhodes		fprintf(stream, "{\n");
278135446Strhodes		indent += 4;
279135446Strhodes		for (elt = isccc_alist_first(sexpr);
280135446Strhodes		     elt != NULL;
281135446Strhodes		     elt = CDR(elt)) {
282135446Strhodes			kv = CAR(elt);
283135446Strhodes			INSIST(isccc_sexpr_listp(kv));
284135446Strhodes			k = CAR(kv);
285135446Strhodes			v = CDR(kv);
286135446Strhodes			INSIST(isccc_sexpr_stringp(k));
287135446Strhodes			fprintf(stream, "%.*s%s => ", (int)indent, spaces,
288135446Strhodes				isccc_sexpr_tostring(k));
289135446Strhodes			isccc_alist_prettyprint(v, indent, stream);
290135446Strhodes			if (CDR(elt) != NULL)
291135446Strhodes				fprintf(stream, ",");
292135446Strhodes			fprintf(stream, "\n");
293135446Strhodes		}
294135446Strhodes		indent -= 4;
295135446Strhodes		fprintf(stream, "%.*s}", (int)indent, spaces);
296135446Strhodes	} else if (isccc_sexpr_listp(sexpr)) {
297135446Strhodes		fprintf(stream, "(\n");
298135446Strhodes		indent += 4;
299135446Strhodes		for (elt = sexpr;
300135446Strhodes		     elt != NULL;
301135446Strhodes		     elt = CDR(elt)) {
302135446Strhodes			fprintf(stream, "%.*s", (int)indent, spaces);
303135446Strhodes			isccc_alist_prettyprint(CAR(elt), indent, stream);
304135446Strhodes			if (CDR(elt) != NULL)
305135446Strhodes				fprintf(stream, ",");
306135446Strhodes			fprintf(stream, "\n");
307135446Strhodes		}
308135446Strhodes		indent -= 4;
309135446Strhodes		fprintf(stream, "%.*s)", (int)indent, spaces);
310135446Strhodes	} else
311135446Strhodes		isccc_sexpr_print(sexpr, stream);
312135446Strhodes}
313