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