Home | History | Annotate | Line # | Download | only in config
util.c revision 1.15
      1 /*	$NetBSD: util.c,v 1.15 2013/11/01 17:09:59 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/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