Home | History | Annotate | Line # | Download | only in config
util.c revision 1.12
      1 /*	$NetBSD: util.c,v 1.12 2012/03/11 20:02:55 dholland 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  * Attribute lists
    209  */
    210 
    211 struct attrlist *
    212 attrlist_create(void)
    213 {
    214 	struct attrlist *al;
    215 
    216 	al = emalloc(sizeof(*al));
    217 	al->al_next = NULL;
    218 	al->al_this = NULL;
    219 	return al;
    220 }
    221 
    222 struct attrlist *
    223 attrlist_cons(struct attrlist *next, struct attr *a)
    224 {
    225 	struct attrlist *al;
    226 
    227 	al = attrlist_create();
    228 	al->al_next = next;
    229 	al->al_this = a;
    230 	return al;
    231 }
    232 
    233 void
    234 attrlist_destroy(struct attrlist *al)
    235 {
    236 	assert(al->al_next == NULL);
    237 	assert(al->al_this == NULL);
    238 	free(al);
    239 }
    240 
    241 void
    242 attrlist_destroyall(struct attrlist *al)
    243 {
    244 	struct attrlist *next;
    245 
    246 	while (al != NULL) {
    247 		next = al->al_next;
    248 		al->al_next = NULL;
    249 		/* XXX should we make the caller guarantee this? */
    250 		al->al_this = NULL;
    251 		attrlist_destroy(al);
    252 		al = next;
    253 	}
    254 }
    255 
    256 /*
    257  * Condition expressions
    258  */
    259 
    260 /*
    261  * Create an expression node.
    262  */
    263 struct condexpr *
    264 condexpr_create(enum condexpr_types type)
    265 {
    266 	struct condexpr *cx;
    267 
    268 	cx = emalloc(sizeof(*cx));
    269 	cx->cx_type = type;
    270 	switch (type) {
    271 
    272 	    case CX_ATOM:
    273 		cx->cx_atom = NULL;
    274 		break;
    275 
    276 	    case CX_NOT:
    277 		cx->cx_not = NULL;
    278 		break;
    279 
    280 	    case CX_AND:
    281 		cx->cx_and.left = NULL;
    282 		cx->cx_and.right = NULL;
    283 		break;
    284 
    285 	    case CX_OR:
    286 		cx->cx_or.left = NULL;
    287 		cx->cx_or.right = NULL;
    288 		break;
    289 
    290 	    default:
    291 		panic("condexpr_create: invalid expr type %d", (int)type);
    292 	}
    293 	return cx;
    294 }
    295 
    296 /*
    297  * Free an expression tree.
    298  */
    299 void
    300 condexpr_destroy(struct condexpr *expr)
    301 {
    302 	switch (expr->cx_type) {
    303 
    304 	    case CX_ATOM:
    305 		/* nothing */
    306 		break;
    307 
    308 	    case CX_NOT:
    309 		condexpr_destroy(expr->cx_not);
    310 		break;
    311 
    312 	    case CX_AND:
    313 		condexpr_destroy(expr->cx_and.left);
    314 		condexpr_destroy(expr->cx_and.right);
    315 		break;
    316 
    317 	    case CX_OR:
    318 		condexpr_destroy(expr->cx_or.left);
    319 		condexpr_destroy(expr->cx_or.right);
    320 		break;
    321 
    322 	    default:
    323 		panic("condexpr_destroy: invalid expr type %d",
    324 		      (int)expr->cx_type);
    325 	}
    326 	free(expr);
    327 }
    328 
    329 /************************************************************/
    330 
    331 /*
    332  * Diagnostic messages
    333  */
    334 
    335 void
    336 cfgwarn(const char *fmt, ...)
    337 {
    338 	va_list ap;
    339 	extern const char *yyfile;
    340 
    341 	va_start(ap, fmt);
    342 	cfgvxwarn(yyfile, currentline(), fmt, ap);
    343 	va_end(ap);
    344 }
    345 
    346 void
    347 cfgxwarn(const char *file, int line, const char *fmt, ...)
    348 {
    349 	va_list ap;
    350 
    351 	va_start(ap, fmt);
    352 	cfgvxwarn(file, line, fmt, ap);
    353 	va_end(ap);
    354 }
    355 
    356 static void
    357 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap)
    358 {
    359 	cfgvxmsg(file, line, "warning: ", fmt, ap);
    360 }
    361 
    362 /*
    363  * External (config file) error.  Complain, using current file
    364  * and line number.
    365  */
    366 void
    367 cfgerror(const char *fmt, ...)
    368 {
    369 	va_list ap;
    370 	extern const char *yyfile;
    371 
    372 	va_start(ap, fmt);
    373 	cfgvxerror(yyfile, currentline(), fmt, ap);
    374 	va_end(ap);
    375 }
    376 
    377 /*
    378  * Delayed config file error (i.e., something was wrong but we could not
    379  * find out about it until later).
    380  */
    381 void
    382 cfgxerror(const char *file, int line, const char *fmt, ...)
    383 {
    384 	va_list ap;
    385 
    386 	va_start(ap, fmt);
    387 	cfgvxerror(file, line, fmt, ap);
    388 	va_end(ap);
    389 }
    390 
    391 /*
    392  * Internal form of error() and xerror().
    393  */
    394 static void
    395 cfgvxerror(const char *file, int line, const char *fmt, va_list ap)
    396 {
    397 	cfgvxmsg(file, line, "", fmt, ap);
    398 	errors++;
    399 }
    400 
    401 
    402 /*
    403  * Internal error, abort.
    404  */
    405 __dead void
    406 panic(const char *fmt, ...)
    407 {
    408 	va_list ap;
    409 
    410 	va_start(ap, fmt);
    411 	(void)fprintf(stderr, "%s: panic: ", getprogname());
    412 	(void)vfprintf(stderr, fmt, ap);
    413 	(void)putc('\n', stderr);
    414 	va_end(ap);
    415 	exit(2);
    416 }
    417 
    418 /*
    419  * Internal form of error() and xerror().
    420  */
    421 static void
    422 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt,
    423       va_list ap)
    424 {
    425 
    426 	(void)fprintf(stderr, "%s:%d: %s", file, line, msgclass);
    427 	(void)vfprintf(stderr, fmt, ap);
    428 	(void)putc('\n', stderr);
    429 }
    430 
    431 void
    432 autogen_comment(FILE *fp, const char *targetfile)
    433 {
    434 
    435 	(void)fprintf(fp,
    436 	    "/*\n"
    437 	    " * MACHINE GENERATED: DO NOT EDIT\n"
    438 	    " *\n"
    439 	    " * %s, from \"%s\"\n"
    440 	    " */\n\n",
    441 	    targetfile, conffile);
    442 }
    443