xref: /netbsd-src/usr.bin/config/util.c (revision 6d322f2f4598f0d8a138f10ea648ec4fabe41f8b)
1 /*	$NetBSD: util.c,v 1.16 2013/11/01 21:39:13 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