Home | History | Annotate | Line # | Download | only in config
      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