1 /* $NetBSD: util.c,v 1.21 2020/03/07 19:26:13 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratories. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: @(#)util.c 8.1 (Berkeley) 6/6/93 41 */ 42 43 #if HAVE_NBTOOL_CONFIG_H 44 #include "nbtool_config.h" 45 #endif 46 47 #include <sys/cdefs.h> 48 __RCSID("$NetBSD: util.c,v 1.21 2020/03/07 19:26:13 christos Exp $"); 49 50 #include <sys/types.h> 51 #include <assert.h> 52 #include <ctype.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <stdarg.h> 57 #include <util.h> 58 #include <err.h> 59 #include "defs.h" 60 61 extern const char *yyfile; 62 63 static void cfgvxerror(const char *, int, const char *, va_list) 64 __printflike(3, 0); 65 static void cfgvxdbg(const char *, int, const char *, va_list) 66 __printflike(3, 0); 67 static void cfgvxwarn(const char *, int, const char *, va_list) 68 __printflike(3, 0); 69 static void cfgvxmsg(const char *, int, const char *, const char *, va_list) 70 __printflike(4, 0); 71 72 /************************************************************/ 73 74 /* 75 * Prefix stack 76 */ 77 78 static void 79 prefixlist_push(struct prefixlist *pl, const char *path) 80 { 81 struct prefix *prevpf = SLIST_FIRST(pl); 82 struct prefix *pf; 83 char *cp; 84 85 pf = ecalloc(1, sizeof(struct prefix)); 86 87 if (prevpf != NULL) { 88 cp = emalloc(strlen(prevpf->pf_prefix) + 1 + 89 strlen(path) + 1); 90 (void) sprintf(cp, "%s/%s", prevpf->pf_prefix, path); 91 pf->pf_prefix = intern(cp); 92 free(cp); 93 } else 94 pf->pf_prefix = intern(path); 95 96 SLIST_INSERT_HEAD(pl, pf, pf_next); 97 } 98 99 static void 100 prefixlist_pop(struct prefixlist *allpl, struct prefixlist *pl) 101 { 102 struct prefix *pf; 103 104 if ((pf = SLIST_FIRST(pl)) == NULL) { 105 cfgerror("no prefixes on the stack to pop"); 106 return; 107 } 108 109 SLIST_REMOVE_HEAD(pl, pf_next); 110 /* Remember this prefix for emitting -I... directives later. */ 111 SLIST_INSERT_HEAD(allpl, pf, pf_next); 112 } 113 114 /* 115 * Push a prefix onto the prefix stack. 116 */ 117 void 118 prefix_push(const char *path) 119 { 120 prefixlist_push(&prefixes, path); 121 } 122 123 /* 124 * Pop a prefix off the prefix stack. 125 */ 126 void 127 prefix_pop(void) 128 { 129 prefixlist_pop(&allprefixes, &prefixes); 130 } 131 132 /* 133 * Push a buildprefix onto the buildprefix stack. 134 */ 135 void 136 buildprefix_push(const char *path) 137 { 138 prefixlist_push(&buildprefixes, path); 139 } 140 141 /* 142 * Pop a buildprefix off the buildprefix stack. 143 */ 144 void 145 buildprefix_pop(void) 146 { 147 prefixlist_pop(&allbuildprefixes, &buildprefixes); 148 } 149 150 /* 151 * Prepend the source path to a file name. 152 */ 153 char * 154 sourcepath(const char *file) 155 { 156 size_t len; 157 char *cp; 158 struct prefix *pf; 159 160 pf = SLIST_EMPTY(&prefixes) ? NULL : SLIST_FIRST(&prefixes); 161 if (pf != NULL && *pf->pf_prefix == '/') 162 len = strlen(pf->pf_prefix) + 1 + strlen(file) + 1; 163 else { 164 len = strlen(srcdir) + 1 + strlen(file) + 1; 165 if (pf != NULL) 166 len += strlen(pf->pf_prefix) + 1; 167 } 168 169 cp = emalloc(len); 170 171 if (pf != NULL) { 172 if (*pf->pf_prefix == '/') 173 (void) sprintf(cp, "%s/%s", pf->pf_prefix, file); 174 else 175 (void) sprintf(cp, "%s/%s/%s", srcdir, 176 pf->pf_prefix, file); 177 } else 178 (void) sprintf(cp, "%s/%s", srcdir, file); 179 return (cp); 180 } 181 182 /************************************************************/ 183 184 /* 185 * Data structures 186 */ 187 188 /* 189 * nvlist 190 */ 191 192 struct nvlist * 193 newnv(const char *name, const char *str, void *ptr, long long i, struct nvlist *next) 194 { 195 struct nvlist *nv; 196 197 nv = ecalloc(1, sizeof(*nv)); 198 nv->nv_next = next; 199 nv->nv_name = name; 200 nv->nv_str = str; 201 nv->nv_ptr = ptr; 202 nv->nv_num = i; 203 nv->nv_where.w_srcfile = yyfile; 204 nv->nv_where.w_srcline = currentline(); 205 return nv; 206 } 207 208 /* 209 * Free an nvlist structure (just one). 210 */ 211 void 212 nvfree(struct nvlist *nv) 213 { 214 215 free(nv); 216 } 217 218 /* 219 * Free an nvlist (the whole list). 220 */ 221 void 222 nvfreel(struct nvlist *nv) 223 { 224 struct nvlist *next; 225 226 for (; nv != NULL; nv = next) { 227 next = nv->nv_next; 228 free(nv); 229 } 230 } 231 232 struct nvlist * 233 nvcat(struct nvlist *nv1, struct nvlist *nv2) 234 { 235 struct nvlist *nv; 236 237 if (nv1 == NULL) 238 return nv2; 239 240 for (nv = nv1; nv->nv_next != NULL; nv = nv->nv_next); 241 242 nv->nv_next = nv2; 243 return nv1; 244 } 245 246 /* 247 * Option definition lists 248 */ 249 250 struct defoptlist * 251 defoptlist_create(const char *name, const char *val, const char *lintval) 252 { 253 struct defoptlist *dl; 254 255 dl = emalloc(sizeof(*dl)); 256 dl->dl_next = NULL; 257 dl->dl_name = name; 258 dl->dl_value = val; 259 dl->dl_lintvalue = lintval; 260 dl->dl_obsolete = 0; 261 dl->dl_depends = NULL; 262 dl->dl_where.w_srcfile = yyfile; 263 dl->dl_where.w_srcline = currentline(); 264 return dl; 265 } 266 267 void 268 defoptlist_destroy(struct defoptlist *dl) 269 { 270 struct defoptlist *next; 271 272 while (dl != NULL) { 273 next = dl->dl_next; 274 dl->dl_next = NULL; 275 276 // XXX should we assert that dl->dl_deps is null to 277 // be sure the deps have already been destroyed? 278 free(dl); 279 280 dl = next; 281 } 282 } 283 284 struct defoptlist * 285 defoptlist_append(struct defoptlist *dla, struct defoptlist *dlb) 286 { 287 struct defoptlist *dl; 288 289 if (dla == NULL) 290 return dlb; 291 292 for (dl = dla; dl->dl_next != NULL; dl = dl->dl_next) 293 ; 294 295 dl->dl_next = dlb; 296 return dla; 297 } 298 299 /* 300 * Locator lists 301 */ 302 303 struct loclist * 304 loclist_create(const char *name, const char *string, long long num) 305 { 306 struct loclist *ll; 307 308 ll = emalloc(sizeof(*ll)); 309 ll->ll_name = name; 310 ll->ll_string = string; 311 ll->ll_num = num; 312 ll->ll_next = NULL; 313 return ll; 314 } 315 316 void 317 loclist_destroy(struct loclist *ll) 318 { 319 struct loclist *next; 320 321 while (ll != NULL) { 322 next = ll->ll_next; 323 ll->ll_next = NULL; 324 free(ll); 325 ll = next; 326 } 327 } 328 329 /* 330 * Attribute lists 331 */ 332 333 struct attrlist * 334 attrlist_create(void) 335 { 336 struct attrlist *al; 337 338 al = emalloc(sizeof(*al)); 339 al->al_next = NULL; 340 al->al_this = NULL; 341 return al; 342 } 343 344 struct attrlist * 345 attrlist_cons(struct attrlist *next, struct attr *a) 346 { 347 struct attrlist *al; 348 349 al = attrlist_create(); 350 al->al_next = next; 351 al->al_this = a; 352 return al; 353 } 354 355 void 356 attrlist_destroy(struct attrlist *al) 357 { 358 assert(al->al_next == NULL); 359 assert(al->al_this == NULL); 360 free(al); 361 } 362 363 void 364 attrlist_destroyall(struct attrlist *al) 365 { 366 struct attrlist *next; 367 368 while (al != NULL) { 369 next = al->al_next; 370 al->al_next = NULL; 371 /* XXX should we make the caller guarantee this? */ 372 al->al_this = NULL; 373 attrlist_destroy(al); 374 al = next; 375 } 376 } 377 378 /* 379 * Condition expressions 380 */ 381 382 /* 383 * Create an expression node. 384 */ 385 struct condexpr * 386 condexpr_create(enum condexpr_types type) 387 { 388 struct condexpr *cx; 389 390 cx = emalloc(sizeof(*cx)); 391 cx->cx_type = type; 392 switch (type) { 393 394 case CX_ATOM: 395 cx->cx_atom = NULL; 396 break; 397 398 case CX_NOT: 399 cx->cx_not = NULL; 400 break; 401 402 case CX_AND: 403 cx->cx_and.left = NULL; 404 cx->cx_and.right = NULL; 405 break; 406 407 case CX_OR: 408 cx->cx_or.left = NULL; 409 cx->cx_or.right = NULL; 410 break; 411 412 default: 413 panic("condexpr_create: invalid expr type %d", (int)type); 414 } 415 return cx; 416 } 417 418 /* 419 * Free an expression tree. 420 */ 421 void 422 condexpr_destroy(struct condexpr *expr) 423 { 424 switch (expr->cx_type) { 425 426 case CX_ATOM: 427 /* nothing */ 428 break; 429 430 case CX_NOT: 431 condexpr_destroy(expr->cx_not); 432 break; 433 434 case CX_AND: 435 condexpr_destroy(expr->cx_and.left); 436 condexpr_destroy(expr->cx_and.right); 437 break; 438 439 case CX_OR: 440 condexpr_destroy(expr->cx_or.left); 441 condexpr_destroy(expr->cx_or.right); 442 break; 443 444 default: 445 panic("condexpr_destroy: invalid expr type %d", 446 (int)expr->cx_type); 447 } 448 free(expr); 449 } 450 451 /************************************************************/ 452 453 /* 454 * Diagnostic messages 455 */ 456 457 void 458 cfgdbg(const char *fmt, ...) 459 { 460 va_list ap; 461 extern const char *yyfile; 462 463 va_start(ap, fmt); 464 cfgvxdbg(yyfile, currentline(), fmt, ap); 465 va_end(ap); 466 } 467 468 void 469 cfgwarn(const char *fmt, ...) 470 { 471 va_list ap; 472 extern const char *yyfile; 473 474 va_start(ap, fmt); 475 cfgvxwarn(yyfile, currentline(), fmt, ap); 476 va_end(ap); 477 } 478 479 void 480 cfgxwarn(const char *file, int line, const char *fmt, ...) 481 { 482 va_list ap; 483 484 va_start(ap, fmt); 485 cfgvxwarn(file, line, fmt, ap); 486 va_end(ap); 487 } 488 489 static void 490 cfgvxdbg(const char *file, int line, const char *fmt, va_list ap) 491 { 492 cfgvxmsg(file, line, "debug: ", fmt, ap); 493 } 494 495 static void 496 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap) 497 { 498 cfgvxmsg(file, line, "warning: ", fmt, ap); 499 } 500 501 /* 502 * External (config file) error. Complain, using current file 503 * and line number. 504 */ 505 void 506 cfgerror(const char *fmt, ...) 507 { 508 va_list ap; 509 extern const char *yyfile; 510 511 va_start(ap, fmt); 512 cfgvxerror(yyfile, currentline(), fmt, ap); 513 va_end(ap); 514 } 515 516 /* 517 * Delayed config file error (i.e., something was wrong but we could not 518 * find out about it until later). 519 */ 520 void 521 cfgxerror(const char *file, int line, const char *fmt, ...) 522 { 523 va_list ap; 524 525 va_start(ap, fmt); 526 cfgvxerror(file, line, fmt, ap); 527 va_end(ap); 528 } 529 530 /* 531 * Internal form of error() and xerror(). 532 */ 533 static void 534 cfgvxerror(const char *file, int line, const char *fmt, va_list ap) 535 { 536 cfgvxmsg(file, line, "", fmt, ap); 537 errors++; 538 } 539 540 541 /* 542 * Internal error, abort. 543 */ 544 __dead void 545 panic(const char *fmt, ...) 546 { 547 va_list ap; 548 549 va_start(ap, fmt); 550 (void)fprintf(stderr, "%s: panic: ", getprogname()); 551 (void)vfprintf(stderr, fmt, ap); 552 (void)putc('\n', stderr); 553 va_end(ap); 554 exit(2); 555 } 556 557 /* 558 * Internal form of error() and xerror(). 559 */ 560 static void 561 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt, 562 va_list ap) 563 { 564 565 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass); 566 (void)vfprintf(stderr, fmt, ap); 567 (void)putc('\n', stderr); 568 } 569 570 void 571 autogen_comment(FILE *fp, const char *targetfile) 572 { 573 574 (void)fprintf(fp, 575 "/*\n" 576 " * MACHINE GENERATED: DO NOT EDIT\n" 577 " *\n" 578 " * %s, from \"%s\"\n" 579 " */\n\n", 580 targetfile, conffile); 581 } 582