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