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: sexpr.c,v 1.9 2007/08/28 07:20:43 tbox Exp $ */ 33 34/*! \file */ 35 36#include <config.h> 37 38#include <ctype.h> 39#include <stdlib.h> 40#include <string.h> 41 42#include <isc/assertions.h> 43#include <isccc/sexpr.h> 44#include <isccc/util.h> 45 46static isccc_sexpr_t sexpr_t = { ISCCC_SEXPRTYPE_T, { NULL } }; 47 48#define CAR(s) (s)->value.as_dottedpair.car 49#define CDR(s) (s)->value.as_dottedpair.cdr 50 51isccc_sexpr_t * 52isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr) 53{ 54 isccc_sexpr_t *sexpr; 55 56 sexpr = malloc(sizeof(*sexpr)); 57 if (sexpr == NULL) 58 return (NULL); 59 sexpr->type = ISCCC_SEXPRTYPE_DOTTEDPAIR; 60 CAR(sexpr) = car; 61 CDR(sexpr) = cdr; 62 63 return (sexpr); 64} 65 66isccc_sexpr_t * 67isccc_sexpr_tconst(void) 68{ 69 return (&sexpr_t); 70} 71 72isccc_sexpr_t * 73isccc_sexpr_fromstring(const char *str) 74{ 75 isccc_sexpr_t *sexpr; 76 77 sexpr = malloc(sizeof(*sexpr)); 78 if (sexpr == NULL) 79 return (NULL); 80 sexpr->type = ISCCC_SEXPRTYPE_STRING; 81 sexpr->value.as_string = strdup(str); 82 if (sexpr->value.as_string == NULL) { 83 free(sexpr); 84 return (NULL); 85 } 86 87 return (sexpr); 88} 89 90isccc_sexpr_t * 91isccc_sexpr_frombinary(const isccc_region_t *region) 92{ 93 isccc_sexpr_t *sexpr; 94 unsigned int region_size; 95 96 sexpr = malloc(sizeof(*sexpr)); 97 if (sexpr == NULL) 98 return (NULL); 99 sexpr->type = ISCCC_SEXPRTYPE_BINARY; 100 region_size = REGION_SIZE(*region); 101 /* 102 * We add an extra byte when we malloc so we can NUL terminate 103 * the binary data. This allows the caller to use it as a C 104 * string. It's up to the caller to ensure this is safe. We don't 105 * add 1 to the length of the binary region, because the NUL is 106 * not part of the binary data. 107 */ 108 sexpr->value.as_region.rstart = malloc(region_size + 1); 109 if (sexpr->value.as_region.rstart == NULL) { 110 free(sexpr); 111 return (NULL); 112 } 113 sexpr->value.as_region.rend = sexpr->value.as_region.rstart + 114 region_size; 115 memcpy(sexpr->value.as_region.rstart, region->rstart, region_size); 116 /* 117 * NUL terminate. 118 */ 119 sexpr->value.as_region.rstart[region_size] = '\0'; 120 121 return (sexpr); 122} 123 124void 125isccc_sexpr_free(isccc_sexpr_t **sexprp) 126{ 127 isccc_sexpr_t *sexpr; 128 isccc_sexpr_t *item; 129 130 sexpr = *sexprp; 131 if (sexpr == NULL) 132 return; 133 switch (sexpr->type) { 134 case ISCCC_SEXPRTYPE_STRING: 135 free(sexpr->value.as_string); 136 break; 137 case ISCCC_SEXPRTYPE_DOTTEDPAIR: 138 item = CAR(sexpr); 139 if (item != NULL) 140 isccc_sexpr_free(&item); 141 item = CDR(sexpr); 142 if (item != NULL) 143 isccc_sexpr_free(&item); 144 break; 145 case ISCCC_SEXPRTYPE_BINARY: 146 free(sexpr->value.as_region.rstart); 147 break; 148 } 149 free(sexpr); 150 151 *sexprp = NULL; 152} 153 154static isc_boolean_t 155printable(isccc_region_t *r) 156{ 157 unsigned char *curr; 158 159 curr = r->rstart; 160 while (curr != r->rend) { 161 if (!isprint(*curr)) 162 return (ISC_FALSE); 163 curr++; 164 } 165 166 return (ISC_TRUE); 167} 168 169void 170isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream) 171{ 172 isccc_sexpr_t *cdr; 173 unsigned int size, i; 174 unsigned char *curr; 175 176 if (sexpr == NULL) { 177 fprintf(stream, "nil"); 178 return; 179 } 180 181 switch (sexpr->type) { 182 case ISCCC_SEXPRTYPE_T: 183 fprintf(stream, "t"); 184 break; 185 case ISCCC_SEXPRTYPE_STRING: 186 fprintf(stream, "\"%s\"", sexpr->value.as_string); 187 break; 188 case ISCCC_SEXPRTYPE_DOTTEDPAIR: 189 fprintf(stream, "("); 190 do { 191 isccc_sexpr_print(CAR(sexpr), stream); 192 cdr = CDR(sexpr); 193 if (cdr != NULL) { 194 fprintf(stream, " "); 195 if (cdr->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) { 196 fprintf(stream, ". "); 197 isccc_sexpr_print(cdr, stream); 198 cdr = NULL; 199 } 200 } 201 sexpr = cdr; 202 } while (sexpr != NULL); 203 fprintf(stream, ")"); 204 break; 205 case ISCCC_SEXPRTYPE_BINARY: 206 size = REGION_SIZE(sexpr->value.as_region); 207 curr = sexpr->value.as_region.rstart; 208 if (printable(&sexpr->value.as_region)) { 209 fprintf(stream, "'%.*s'", (int)size, curr); 210 } else { 211 fprintf(stream, "0x"); 212 for (i = 0; i < size; i++) 213 fprintf(stream, "%02x", *curr++); 214 } 215 break; 216 default: 217 INSIST(0); 218 } 219} 220 221isccc_sexpr_t * 222isccc_sexpr_car(isccc_sexpr_t *list) 223{ 224 REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 225 226 return (CAR(list)); 227} 228 229isccc_sexpr_t * 230isccc_sexpr_cdr(isccc_sexpr_t *list) 231{ 232 REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 233 234 return (CDR(list)); 235} 236 237void 238isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car) 239{ 240 REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 241 242 CAR(pair) = car; 243} 244 245void 246isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr) 247{ 248 REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 249 250 CDR(pair) = cdr; 251} 252 253isccc_sexpr_t * 254isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2) 255{ 256 isccc_sexpr_t *last, *elt, *l1; 257 258 REQUIRE(l1p != NULL); 259 l1 = *l1p; 260 REQUIRE(l1 == NULL || l1->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 261 262 elt = isccc_sexpr_cons(l2, NULL); 263 if (elt == NULL) 264 return (NULL); 265 if (l1 == NULL) { 266 *l1p = elt; 267 return (elt); 268 } 269 for (last = l1; CDR(last) != NULL; last = CDR(last)) 270 /* Nothing */; 271 CDR(last) = elt; 272 273 return (elt); 274} 275 276isc_boolean_t 277isccc_sexpr_listp(isccc_sexpr_t *sexpr) 278{ 279 if (sexpr == NULL || sexpr->type == ISCCC_SEXPRTYPE_DOTTEDPAIR) 280 return (ISC_TRUE); 281 return (ISC_FALSE); 282} 283 284isc_boolean_t 285isccc_sexpr_emptyp(isccc_sexpr_t *sexpr) 286{ 287 if (sexpr == NULL) 288 return (ISC_TRUE); 289 return (ISC_FALSE); 290} 291 292isc_boolean_t 293isccc_sexpr_stringp(isccc_sexpr_t *sexpr) 294{ 295 if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_STRING) 296 return (ISC_TRUE); 297 return (ISC_FALSE); 298} 299 300isc_boolean_t 301isccc_sexpr_binaryp(isccc_sexpr_t *sexpr) 302{ 303 if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY) 304 return (ISC_TRUE); 305 return (ISC_FALSE); 306} 307 308char * 309isccc_sexpr_tostring(isccc_sexpr_t *sexpr) 310{ 311 REQUIRE(sexpr != NULL && 312 (sexpr->type == ISCCC_SEXPRTYPE_STRING || 313 sexpr->type == ISCCC_SEXPRTYPE_BINARY)); 314 315 if (sexpr->type == ISCCC_SEXPRTYPE_BINARY) 316 return ((char *)sexpr->value.as_region.rstart); 317 return (sexpr->value.as_string); 318} 319 320isccc_region_t * 321isccc_sexpr_tobinary(isccc_sexpr_t *sexpr) 322{ 323 REQUIRE(sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY); 324 return (&sexpr->value.as_region); 325} 326