1 /* $NetBSD: util.c,v 1.20 2015/09/01 13:42:48 uebayasi 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.20 2015/09/01 13:42:48 uebayasi 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 static void cfgvxerror(const char *, int, const char *, va_list) 62 __printflike(3, 0); 63 static void cfgvxdbg(const char *, int, const char *, va_list) 64 __printflike(3, 0); 65 static void cfgvxwarn(const char *, int, const char *, va_list) 66 __printflike(3, 0); 67 static void cfgvxmsg(const char *, int, const char *, const char *, va_list) 68 __printflike(4, 0); 69 70 /************************************************************/ 71 72 /* 73 * Prefix stack 74 */ 75 76 static void 77 prefixlist_push(struct prefixlist *pl, const char *path) 78 { 79 struct prefix *prevpf = SLIST_FIRST(pl); 80 struct prefix *pf; 81 char *cp; 82 83 pf = ecalloc(1, sizeof(struct prefix)); 84 85 if (prevpf != NULL) { 86 cp = emalloc(strlen(prevpf->pf_prefix) + 1 + 87 strlen(path) + 1); 88 (void) sprintf(cp, "%s/%s", prevpf->pf_prefix, path); 89 pf->pf_prefix = intern(cp); 90 free(cp); 91 } else 92 pf->pf_prefix = intern(path); 93 94 SLIST_INSERT_HEAD(pl, pf, pf_next); 95 } 96 97 static void 98 prefixlist_pop(struct prefixlist *allpl, struct prefixlist *pl) 99 { 100 struct prefix *pf; 101 102 if ((pf = SLIST_FIRST(pl)) == NULL) { 103 cfgerror("no prefixes on the stack to pop"); 104 return; 105 } 106 107 SLIST_REMOVE_HEAD(pl, pf_next); 108 /* Remember this prefix for emitting -I... directives later. */ 109 SLIST_INSERT_HEAD(allpl, pf, pf_next); 110 } 111 112 /* 113 * Push a prefix onto the prefix stack. 114 */ 115 void 116 prefix_push(const char *path) 117 { 118 prefixlist_push(&prefixes, path); 119 } 120 121 /* 122 * Pop a prefix off the prefix stack. 123 */ 124 void 125 prefix_pop(void) 126 { 127 prefixlist_pop(&allprefixes, &prefixes); 128 } 129 130 /* 131 * Push a buildprefix onto the buildprefix stack. 132 */ 133 void 134 buildprefix_push(const char *path) 135 { 136 prefixlist_push(&buildprefixes, path); 137 } 138 139 /* 140 * Pop a buildprefix off the buildprefix stack. 141 */ 142 void 143 buildprefix_pop(void) 144 { 145 prefixlist_pop(&allbuildprefixes, &buildprefixes); 146 } 147 148 /* 149 * Prepend the source path to a file name. 150 */ 151 char * 152 sourcepath(const char *file) 153 { 154 size_t len; 155 char *cp; 156 struct prefix *pf; 157 158 pf = SLIST_EMPTY(&prefixes) ? NULL : SLIST_FIRST(&prefixes); 159 if (pf != NULL && *pf->pf_prefix == '/') 160 len = strlen(pf->pf_prefix) + 1 + strlen(file) + 1; 161 else { 162 len = strlen(srcdir) + 1 + strlen(file) + 1; 163 if (pf != NULL) 164 len += strlen(pf->pf_prefix) + 1; 165 } 166 167 cp = emalloc(len); 168 169 if (pf != NULL) { 170 if (*pf->pf_prefix == '/') 171 (void) sprintf(cp, "%s/%s", pf->pf_prefix, file); 172 else 173 (void) sprintf(cp, "%s/%s/%s", srcdir, 174 pf->pf_prefix, file); 175 } else 176 (void) sprintf(cp, "%s/%s", srcdir, file); 177 return (cp); 178 } 179 180 /************************************************************/ 181 182 /* 183 * Data structures 184 */ 185 186 /* 187 * nvlist 188 */ 189 190 struct nvlist * 191 newnv(const char *name, const char *str, void *ptr, long long i, struct nvlist *next) 192 { 193 struct nvlist *nv; 194 195 nv = ecalloc(1, sizeof(*nv)); 196 nv->nv_next = next; 197 nv->nv_name = name; 198 nv->nv_str = str; 199 nv->nv_ptr = ptr; 200 nv->nv_num = i; 201 return nv; 202 } 203 204 /* 205 * Free an nvlist structure (just one). 206 */ 207 void 208 nvfree(struct nvlist *nv) 209 { 210 211 free(nv); 212 } 213 214 /* 215 * Free an nvlist (the whole list). 216 */ 217 void 218 nvfreel(struct nvlist *nv) 219 { 220 struct nvlist *next; 221 222 for (; nv != NULL; nv = next) { 223 next = nv->nv_next; 224 free(nv); 225 } 226 } 227 228 struct nvlist * 229 nvcat(struct nvlist *nv1, struct nvlist *nv2) 230 { 231 struct nvlist *nv; 232 233 if (nv1 == NULL) 234 return nv2; 235 236 for (nv = nv1; nv->nv_next != NULL; nv = nv->nv_next); 237 238 nv->nv_next = nv2; 239 return nv1; 240 } 241 242 /* 243 * Option definition lists 244 */ 245 246 struct defoptlist * 247 defoptlist_create(const char *name, const char *val, const char *lintval) 248 { 249 struct defoptlist *dl; 250 251 dl = emalloc(sizeof(*dl)); 252 dl->dl_next = NULL; 253 dl->dl_name = name; 254 dl->dl_value = val; 255 dl->dl_lintvalue = lintval; 256 dl->dl_obsolete = 0; 257 dl->dl_depends = NULL; 258 return dl; 259 } 260 261 void 262 defoptlist_destroy(struct defoptlist *dl) 263 { 264 struct defoptlist *next; 265 266 while (dl != NULL) { 267 next = dl->dl_next; 268 dl->dl_next = NULL; 269 270 // XXX should we assert that dl->dl_deps is null to 271 // be sure the deps have already been destroyed? 272 free(dl); 273 274 dl = next; 275 } 276 } 277 278 struct defoptlist * 279 defoptlist_append(struct defoptlist *dla, struct defoptlist *dlb) 280 { 281 struct defoptlist *dl; 282 283 if (dla == NULL) 284 return dlb; 285 286 for (dl = dla; dl->dl_next != NULL; dl = dl->dl_next) 287 ; 288 289 dl->dl_next = dlb; 290 return dla; 291 } 292 293 /* 294 * Locator lists 295 */ 296 297 struct loclist * 298 loclist_create(const char *name, const char *string, long long num) 299 { 300 struct loclist *ll; 301 302 ll = emalloc(sizeof(*ll)); 303 ll->ll_name = name; 304 ll->ll_string = string; 305 ll->ll_num = num; 306 ll->ll_next = NULL; 307 return ll; 308 } 309 310 void 311 loclist_destroy(struct loclist *ll) 312 { 313 struct loclist *next; 314 315 while (ll != NULL) { 316 next = ll->ll_next; 317 ll->ll_next = NULL; 318 free(ll); 319 ll = next; 320 } 321 } 322 323 /* 324 * Attribute lists 325 */ 326 327 struct attrlist * 328 attrlist_create(void) 329 { 330 struct attrlist *al; 331 332 al = emalloc(sizeof(*al)); 333 al->al_next = NULL; 334 al->al_this = NULL; 335 return al; 336 } 337 338 struct attrlist * 339 attrlist_cons(struct attrlist *next, struct attr *a) 340 { 341 struct attrlist *al; 342 343 al = attrlist_create(); 344 al->al_next = next; 345 al->al_this = a; 346 return al; 347 } 348 349 void 350 attrlist_destroy(struct attrlist *al) 351 { 352 assert(al->al_next == NULL); 353 assert(al->al_this == NULL); 354 free(al); 355 } 356 357 void 358 attrlist_destroyall(struct attrlist *al) 359 { 360 struct attrlist *next; 361 362 while (al != NULL) { 363 next = al->al_next; 364 al->al_next = NULL; 365 /* XXX should we make the caller guarantee this? */ 366 al->al_this = NULL; 367 attrlist_destroy(al); 368 al = next; 369 } 370 } 371 372 /* 373 * Condition expressions 374 */ 375 376 /* 377 * Create an expression node. 378 */ 379 struct condexpr * 380 condexpr_create(enum condexpr_types type) 381 { 382 struct condexpr *cx; 383 384 cx = emalloc(sizeof(*cx)); 385 cx->cx_type = type; 386 switch (type) { 387 388 case CX_ATOM: 389 cx->cx_atom = NULL; 390 break; 391 392 case CX_NOT: 393 cx->cx_not = NULL; 394 break; 395 396 case CX_AND: 397 cx->cx_and.left = NULL; 398 cx->cx_and.right = NULL; 399 break; 400 401 case CX_OR: 402 cx->cx_or.left = NULL; 403 cx->cx_or.right = NULL; 404 break; 405 406 default: 407 panic("condexpr_create: invalid expr type %d", (int)type); 408 } 409 return cx; 410 } 411 412 /* 413 * Free an expression tree. 414 */ 415 void 416 condexpr_destroy(struct condexpr *expr) 417 { 418 switch (expr->cx_type) { 419 420 case CX_ATOM: 421 /* nothing */ 422 break; 423 424 case CX_NOT: 425 condexpr_destroy(expr->cx_not); 426 break; 427 428 case CX_AND: 429 condexpr_destroy(expr->cx_and.left); 430 condexpr_destroy(expr->cx_and.right); 431 break; 432 433 case CX_OR: 434 condexpr_destroy(expr->cx_or.left); 435 condexpr_destroy(expr->cx_or.right); 436 break; 437 438 default: 439 panic("condexpr_destroy: invalid expr type %d", 440 (int)expr->cx_type); 441 } 442 free(expr); 443 } 444 445 /************************************************************/ 446 447 /* 448 * Diagnostic messages 449 */ 450 451 void 452 cfgdbg(const char *fmt, ...) 453 { 454 va_list ap; 455 extern const char *yyfile; 456 457 va_start(ap, fmt); 458 cfgvxdbg(yyfile, currentline(), fmt, ap); 459 va_end(ap); 460 } 461 462 void 463 cfgwarn(const char *fmt, ...) 464 { 465 va_list ap; 466 extern const char *yyfile; 467 468 va_start(ap, fmt); 469 cfgvxwarn(yyfile, currentline(), fmt, ap); 470 va_end(ap); 471 } 472 473 void 474 cfgxwarn(const char *file, int line, const char *fmt, ...) 475 { 476 va_list ap; 477 478 va_start(ap, fmt); 479 cfgvxwarn(file, line, fmt, ap); 480 va_end(ap); 481 } 482 483 static void 484 cfgvxdbg(const char *file, int line, const char *fmt, va_list ap) 485 { 486 cfgvxmsg(file, line, "debug: ", fmt, ap); 487 } 488 489 static void 490 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap) 491 { 492 cfgvxmsg(file, line, "warning: ", fmt, ap); 493 } 494 495 /* 496 * External (config file) error. Complain, using current file 497 * and line number. 498 */ 499 void 500 cfgerror(const char *fmt, ...) 501 { 502 va_list ap; 503 extern const char *yyfile; 504 505 va_start(ap, fmt); 506 cfgvxerror(yyfile, currentline(), fmt, ap); 507 va_end(ap); 508 } 509 510 /* 511 * Delayed config file error (i.e., something was wrong but we could not 512 * find out about it until later). 513 */ 514 void 515 cfgxerror(const char *file, int line, const char *fmt, ...) 516 { 517 va_list ap; 518 519 va_start(ap, fmt); 520 cfgvxerror(file, line, fmt, ap); 521 va_end(ap); 522 } 523 524 /* 525 * Internal form of error() and xerror(). 526 */ 527 static void 528 cfgvxerror(const char *file, int line, const char *fmt, va_list ap) 529 { 530 cfgvxmsg(file, line, "", fmt, ap); 531 errors++; 532 } 533 534 535 /* 536 * Internal error, abort. 537 */ 538 __dead void 539 panic(const char *fmt, ...) 540 { 541 va_list ap; 542 543 va_start(ap, fmt); 544 (void)fprintf(stderr, "%s: panic: ", getprogname()); 545 (void)vfprintf(stderr, fmt, ap); 546 (void)putc('\n', stderr); 547 va_end(ap); 548 exit(2); 549 } 550 551 /* 552 * Internal form of error() and xerror(). 553 */ 554 static void 555 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt, 556 va_list ap) 557 { 558 559 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass); 560 (void)vfprintf(stderr, fmt, ap); 561 (void)putc('\n', stderr); 562 } 563 564 void 565 autogen_comment(FILE *fp, const char *targetfile) 566 { 567 568 (void)fprintf(fp, 569 "/*\n" 570 " * MACHINE GENERATED: DO NOT EDIT\n" 571 " *\n" 572 " * %s, from \"%s\"\n" 573 " */\n\n", 574 targetfile, conffile); 575 } 576