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