Home | History | Annotate | Line # | Download | only in config
util.c revision 1.21
      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