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