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