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