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