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