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