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