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