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