1 /* $NetBSD: util.c,v 1.23 2025/01/07 14:21:11 joe 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.23 2025/01/07 14:21:11 joe 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_mkvar = 0; 262 dl->dl_depends = NULL; 263 dl->dl_where.w_srcfile = yyfile; 264 dl->dl_where.w_srcline = currentline(); 265 return dl; 266 } 267 268 void 269 defoptlist_destroy(struct defoptlist *dl) 270 { 271 struct defoptlist *next; 272 273 while (dl != NULL) { 274 next = dl->dl_next; 275 dl->dl_next = NULL; 276 277 // XXX should we assert that dl->dl_deps is null to 278 // be sure the deps have already been destroyed? 279 free(dl); 280 281 dl = next; 282 } 283 } 284 285 struct defoptlist * 286 defoptlist_append(struct defoptlist *dla, struct defoptlist *dlb) 287 { 288 struct defoptlist *dl; 289 290 if (dla == NULL) 291 return dlb; 292 293 for (dl = dla; dl->dl_next != NULL; dl = dl->dl_next) 294 ; 295 296 dl->dl_next = dlb; 297 return dla; 298 } 299 300 /* 301 * Locator lists 302 */ 303 304 struct loclist * 305 loclist_create(const char *name, const char *string, long long num) 306 { 307 struct loclist *ll; 308 309 ll = emalloc(sizeof(*ll)); 310 ll->ll_name = name; 311 ll->ll_string = string; 312 ll->ll_num = num; 313 ll->ll_next = NULL; 314 return ll; 315 } 316 317 void 318 loclist_destroy(struct loclist *ll) 319 { 320 struct loclist *next; 321 322 while (ll != NULL) { 323 next = ll->ll_next; 324 ll->ll_next = NULL; 325 free(ll); 326 ll = next; 327 } 328 } 329 330 /* 331 * Attribute lists 332 */ 333 334 struct attrlist * 335 attrlist_create(void) 336 { 337 struct attrlist *al; 338 339 al = emalloc(sizeof(*al)); 340 al->al_next = NULL; 341 al->al_this = NULL; 342 return al; 343 } 344 345 struct attrlist * 346 attrlist_cons(struct attrlist *next, struct attr *a) 347 { 348 struct attrlist *al; 349 350 al = attrlist_create(); 351 al->al_next = next; 352 al->al_this = a; 353 return al; 354 } 355 356 void 357 attrlist_destroy(struct attrlist *al) 358 { 359 assert(al->al_next == NULL); 360 assert(al->al_this == NULL); 361 free(al); 362 } 363 364 void 365 attrlist_destroyall(struct attrlist *al) 366 { 367 struct attrlist *next; 368 369 while (al != NULL) { 370 next = al->al_next; 371 al->al_next = NULL; 372 /* XXX should we make the caller guarantee this? */ 373 al->al_this = NULL; 374 attrlist_destroy(al); 375 al = next; 376 } 377 } 378 379 /* 380 * Condition expressions 381 */ 382 383 /* 384 * Create an expression node. 385 */ 386 struct condexpr * 387 condexpr_create(enum condexpr_types type) 388 { 389 struct condexpr *cx; 390 391 cx = emalloc(sizeof(*cx)); 392 cx->cx_type = type; 393 switch (type) { 394 395 case CX_ATOM: 396 cx->cx_atom = NULL; 397 break; 398 399 case CX_NOT: 400 cx->cx_not = NULL; 401 break; 402 403 case CX_AND: 404 cx->cx_and.left = NULL; 405 cx->cx_and.right = NULL; 406 break; 407 408 case CX_OR: 409 cx->cx_or.left = NULL; 410 cx->cx_or.right = NULL; 411 break; 412 413 default: 414 panic("condexpr_create: invalid expr type %d", (int)type); 415 } 416 return cx; 417 } 418 419 /* 420 * Free an expression tree. 421 */ 422 void 423 condexpr_destroy(struct condexpr *expr) 424 { 425 switch (expr->cx_type) { 426 427 case CX_ATOM: 428 /* nothing */ 429 break; 430 431 case CX_NOT: 432 condexpr_destroy(expr->cx_not); 433 break; 434 435 case CX_AND: 436 condexpr_destroy(expr->cx_and.left); 437 condexpr_destroy(expr->cx_and.right); 438 break; 439 440 case CX_OR: 441 condexpr_destroy(expr->cx_or.left); 442 condexpr_destroy(expr->cx_or.right); 443 break; 444 445 default: 446 panic("condexpr_destroy: invalid expr type %d", 447 (int)expr->cx_type); 448 } 449 free(expr); 450 } 451 452 /************************************************************/ 453 454 /* 455 * Diagnostic messages 456 */ 457 458 void 459 cfgdbg(const char *fmt, ...) 460 { 461 va_list ap; 462 extern const char *yyfile; 463 464 va_start(ap, fmt); 465 cfgvxdbg(yyfile, currentline(), fmt, ap); 466 va_end(ap); 467 } 468 469 void 470 cfgwarn(const char *fmt, ...) 471 { 472 va_list ap; 473 extern const char *yyfile; 474 475 va_start(ap, fmt); 476 cfgvxwarn(yyfile, currentline(), fmt, ap); 477 va_end(ap); 478 } 479 480 void 481 cfgxwarn(const char *file, int line, const char *fmt, ...) 482 { 483 va_list ap; 484 485 va_start(ap, fmt); 486 cfgvxwarn(file, line, fmt, ap); 487 va_end(ap); 488 } 489 490 static void 491 cfgvxdbg(const char *file, int line, const char *fmt, va_list ap) 492 { 493 cfgvxmsg(file, line, "debug: ", fmt, ap); 494 } 495 496 static void 497 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap) 498 { 499 cfgvxmsg(file, line, "warning: ", fmt, ap); 500 } 501 502 /* 503 * External (config file) error. Complain, using current file 504 * and line number. 505 */ 506 void 507 cfgerror(const char *fmt, ...) 508 { 509 va_list ap; 510 extern const char *yyfile; 511 512 va_start(ap, fmt); 513 cfgvxerror(yyfile, currentline(), fmt, ap); 514 va_end(ap); 515 } 516 517 /* 518 * Delayed config file error (i.e., something was wrong but we could not 519 * find out about it until later). 520 */ 521 void 522 cfgxerror(const char *file, int line, const char *fmt, ...) 523 { 524 va_list ap; 525 526 va_start(ap, fmt); 527 cfgvxerror(file, line, fmt, ap); 528 va_end(ap); 529 } 530 531 /* 532 * Internal form of error() and xerror(). 533 */ 534 static void 535 cfgvxerror(const char *file, int line, const char *fmt, va_list ap) 536 { 537 cfgvxmsg(file, line, "", fmt, ap); 538 errors++; 539 } 540 541 542 /* 543 * Internal error, abort. 544 */ 545 __dead void 546 panic(const char *fmt, ...) 547 { 548 va_list ap; 549 550 va_start(ap, fmt); 551 (void)fprintf(stderr, "%s: panic: ", getprogname()); 552 (void)vfprintf(stderr, fmt, ap); 553 (void)putc('\n', stderr); 554 va_end(ap); 555 exit(2); 556 } 557 558 /* 559 * Internal form of error() and xerror(). 560 */ 561 static void 562 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt, 563 va_list ap) 564 { 565 566 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass); 567 (void)vfprintf(stderr, fmt, ap); 568 (void)putc('\n', stderr); 569 } 570 571 void 572 autogen_comment(FILE *fp, const char *targetfile) 573 { 574 575 (void)fprintf(fp, 576 "/*\n" 577 " * MACHINE GENERATED: DO NOT EDIT\n" 578 " *\n" 579 " * %s, from \"%s\"\n" 580 " */\n\n", 581 targetfile, conffile); 582 } 583