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