1 /* $NetBSD: sexpr.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */ 2 3 /* 4 * Portions Copyright (C) 2004, 2005, 2007, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Portions Copyright (C) 2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL 12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 13 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY 14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * Portions Copyright (C) 2001 Nominum, Inc. 20 * 21 * Permission to use, copy, modify, and/or distribute this software for any 22 * purpose with or without fee is hereby granted, provided that the above 23 * copyright notice and this permission notice appear in all copies. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL 26 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY 28 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 */ 33 34 /* Id: sexpr.c,v 1.9 2007/08/28 07:20:43 tbox Exp */ 35 36 /*! \file */ 37 38 #include <config.h> 39 40 #include <ctype.h> 41 #include <stdlib.h> 42 #include <string.h> 43 44 #include <isc/assertions.h> 45 #include <isccc/sexpr.h> 46 #include <isccc/util.h> 47 48 static isccc_sexpr_t sexpr_t = { ISCCC_SEXPRTYPE_T, { NULL } }; 49 50 #define CAR(s) (s)->value.as_dottedpair.car 51 #define CDR(s) (s)->value.as_dottedpair.cdr 52 53 isccc_sexpr_t * 54 isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr) 55 { 56 isccc_sexpr_t *sexpr; 57 58 sexpr = malloc(sizeof(*sexpr)); 59 if (sexpr == NULL) 60 return (NULL); 61 sexpr->type = ISCCC_SEXPRTYPE_DOTTEDPAIR; 62 CAR(sexpr) = car; 63 CDR(sexpr) = cdr; 64 65 return (sexpr); 66 } 67 68 isccc_sexpr_t * 69 isccc_sexpr_tconst(void) 70 { 71 return (&sexpr_t); 72 } 73 74 isccc_sexpr_t * 75 isccc_sexpr_fromstring(const char *str) 76 { 77 isccc_sexpr_t *sexpr; 78 79 sexpr = malloc(sizeof(*sexpr)); 80 if (sexpr == NULL) 81 return (NULL); 82 sexpr->type = ISCCC_SEXPRTYPE_STRING; 83 sexpr->value.as_string = strdup(str); 84 if (sexpr->value.as_string == NULL) { 85 free(sexpr); 86 return (NULL); 87 } 88 89 return (sexpr); 90 } 91 92 isccc_sexpr_t * 93 isccc_sexpr_frombinary(const isccc_region_t *region) 94 { 95 isccc_sexpr_t *sexpr; 96 unsigned int region_size; 97 98 sexpr = malloc(sizeof(*sexpr)); 99 if (sexpr == NULL) 100 return (NULL); 101 sexpr->type = ISCCC_SEXPRTYPE_BINARY; 102 region_size = REGION_SIZE(*region); 103 /* 104 * We add an extra byte when we malloc so we can NUL terminate 105 * the binary data. This allows the caller to use it as a C 106 * string. It's up to the caller to ensure this is safe. We don't 107 * add 1 to the length of the binary region, because the NUL is 108 * not part of the binary data. 109 */ 110 sexpr->value.as_region.rstart = malloc(region_size + 1); 111 if (sexpr->value.as_region.rstart == NULL) { 112 free(sexpr); 113 return (NULL); 114 } 115 sexpr->value.as_region.rend = sexpr->value.as_region.rstart + 116 region_size; 117 memmove(sexpr->value.as_region.rstart, region->rstart, region_size); 118 /* 119 * NUL terminate. 120 */ 121 sexpr->value.as_region.rstart[region_size] = '\0'; 122 123 return (sexpr); 124 } 125 126 void 127 isccc_sexpr_free(isccc_sexpr_t **sexprp) 128 { 129 isccc_sexpr_t *sexpr; 130 isccc_sexpr_t *item; 131 132 sexpr = *sexprp; 133 if (sexpr == NULL) 134 return; 135 switch (sexpr->type) { 136 case ISCCC_SEXPRTYPE_STRING: 137 free(sexpr->value.as_string); 138 break; 139 case ISCCC_SEXPRTYPE_DOTTEDPAIR: 140 item = CAR(sexpr); 141 if (item != NULL) 142 isccc_sexpr_free(&item); 143 item = CDR(sexpr); 144 if (item != NULL) 145 isccc_sexpr_free(&item); 146 break; 147 case ISCCC_SEXPRTYPE_BINARY: 148 free(sexpr->value.as_region.rstart); 149 break; 150 } 151 free(sexpr); 152 153 *sexprp = NULL; 154 } 155 156 static isc_boolean_t 157 printable(isccc_region_t *r) 158 { 159 unsigned char *curr; 160 161 curr = r->rstart; 162 while (curr != r->rend) { 163 if (!isprint(*curr)) 164 return (ISC_FALSE); 165 curr++; 166 } 167 168 return (ISC_TRUE); 169 } 170 171 void 172 isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream) 173 { 174 isccc_sexpr_t *cdr; 175 unsigned int size, i; 176 unsigned char *curr; 177 178 if (sexpr == NULL) { 179 fprintf(stream, "nil"); 180 return; 181 } 182 183 switch (sexpr->type) { 184 case ISCCC_SEXPRTYPE_T: 185 fprintf(stream, "t"); 186 break; 187 case ISCCC_SEXPRTYPE_STRING: 188 fprintf(stream, "\"%s\"", sexpr->value.as_string); 189 break; 190 case ISCCC_SEXPRTYPE_DOTTEDPAIR: 191 fprintf(stream, "("); 192 do { 193 isccc_sexpr_print(CAR(sexpr), stream); 194 cdr = CDR(sexpr); 195 if (cdr != NULL) { 196 fprintf(stream, " "); 197 if (cdr->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) { 198 fprintf(stream, ". "); 199 isccc_sexpr_print(cdr, stream); 200 cdr = NULL; 201 } 202 } 203 sexpr = cdr; 204 } while (sexpr != NULL); 205 fprintf(stream, ")"); 206 break; 207 case ISCCC_SEXPRTYPE_BINARY: 208 size = REGION_SIZE(sexpr->value.as_region); 209 curr = sexpr->value.as_region.rstart; 210 if (printable(&sexpr->value.as_region)) { 211 fprintf(stream, "'%.*s'", (int)size, curr); 212 } else { 213 fprintf(stream, "0x"); 214 for (i = 0; i < size; i++) 215 fprintf(stream, "%02x", *curr++); 216 } 217 break; 218 default: 219 INSIST(0); 220 } 221 } 222 223 isccc_sexpr_t * 224 isccc_sexpr_car(isccc_sexpr_t *list) 225 { 226 REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 227 228 return (CAR(list)); 229 } 230 231 isccc_sexpr_t * 232 isccc_sexpr_cdr(isccc_sexpr_t *list) 233 { 234 REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 235 236 return (CDR(list)); 237 } 238 239 void 240 isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car) 241 { 242 REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 243 244 CAR(pair) = car; 245 } 246 247 void 248 isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr) 249 { 250 REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 251 252 CDR(pair) = cdr; 253 } 254 255 isccc_sexpr_t * 256 isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2) 257 { 258 isccc_sexpr_t *last, *elt, *l1; 259 260 REQUIRE(l1p != NULL); 261 l1 = *l1p; 262 REQUIRE(l1 == NULL || l1->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); 263 264 elt = isccc_sexpr_cons(l2, NULL); 265 if (elt == NULL) 266 return (NULL); 267 if (l1 == NULL) { 268 *l1p = elt; 269 return (elt); 270 } 271 for (last = l1; CDR(last) != NULL; last = CDR(last)) 272 /* Nothing */; 273 CDR(last) = elt; 274 275 return (elt); 276 } 277 278 isc_boolean_t 279 isccc_sexpr_listp(isccc_sexpr_t *sexpr) 280 { 281 if (sexpr == NULL || sexpr->type == ISCCC_SEXPRTYPE_DOTTEDPAIR) 282 return (ISC_TRUE); 283 return (ISC_FALSE); 284 } 285 286 isc_boolean_t 287 isccc_sexpr_emptyp(isccc_sexpr_t *sexpr) 288 { 289 if (sexpr == NULL) 290 return (ISC_TRUE); 291 return (ISC_FALSE); 292 } 293 294 isc_boolean_t 295 isccc_sexpr_stringp(isccc_sexpr_t *sexpr) 296 { 297 if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_STRING) 298 return (ISC_TRUE); 299 return (ISC_FALSE); 300 } 301 302 isc_boolean_t 303 isccc_sexpr_binaryp(isccc_sexpr_t *sexpr) 304 { 305 if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY) 306 return (ISC_TRUE); 307 return (ISC_FALSE); 308 } 309 310 char * 311 isccc_sexpr_tostring(isccc_sexpr_t *sexpr) 312 { 313 REQUIRE(sexpr != NULL && 314 (sexpr->type == ISCCC_SEXPRTYPE_STRING || 315 sexpr->type == ISCCC_SEXPRTYPE_BINARY)); 316 317 if (sexpr->type == ISCCC_SEXPRTYPE_BINARY) 318 return ((char *)sexpr->value.as_region.rstart); 319 return (sexpr->value.as_string); 320 } 321 322 isccc_region_t * 323 isccc_sexpr_tobinary(isccc_sexpr_t *sexpr) 324 { 325 REQUIRE(sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY); 326 return (&sexpr->value.as_region); 327 } 328