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