util.c revision 1.23 1 /* $NetBSD: util.c,v 1.23 2025/01/07 14:21:11 joe 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.23 2025/01/07 14:21:11 joe 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
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
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
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
127 prefix_pop(void)
128 {
129 prefixlist_pop(&allprefixes, &prefixes);
130 }
131
132 /*
133 * Push a buildprefix onto the buildprefix stack.
134 */
135 void
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
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 *
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 *
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
212 nvfree(struct nvlist *nv)
213 {
214
215 free(nv);
216 }
217
218 /*
219 * Free an nvlist (the whole list).
220 */
221 void
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 *
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 *
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_mkvar = 0;
262 dl->dl_depends = NULL;
263 dl->dl_where.w_srcfile = yyfile;
264 dl->dl_where.w_srcline = currentline();
265 return dl;
266 }
267
268 void
269 defoptlist_destroy(struct defoptlist *dl)
270 {
271 struct defoptlist *next;
272
273 while (dl != NULL) {
274 next = dl->dl_next;
275 dl->dl_next = NULL;
276
277 // XXX should we assert that dl->dl_deps is null to
278 // be sure the deps have already been destroyed?
279 free(dl);
280
281 dl = next;
282 }
283 }
284
285 struct defoptlist *
286 defoptlist_append(struct defoptlist *dla, struct defoptlist *dlb)
287 {
288 struct defoptlist *dl;
289
290 if (dla == NULL)
291 return dlb;
292
293 for (dl = dla; dl->dl_next != NULL; dl = dl->dl_next)
294 ;
295
296 dl->dl_next = dlb;
297 return dla;
298 }
299
300 /*
301 * Locator lists
302 */
303
304 struct loclist *
305 loclist_create(const char *name, const char *string, long long num)
306 {
307 struct loclist *ll;
308
309 ll = emalloc(sizeof(*ll));
310 ll->ll_name = name;
311 ll->ll_string = string;
312 ll->ll_num = num;
313 ll->ll_next = NULL;
314 return ll;
315 }
316
317 void
318 loclist_destroy(struct loclist *ll)
319 {
320 struct loclist *next;
321
322 while (ll != NULL) {
323 next = ll->ll_next;
324 ll->ll_next = NULL;
325 free(ll);
326 ll = next;
327 }
328 }
329
330 /*
331 * Attribute lists
332 */
333
334 struct attrlist *
335 attrlist_create(void)
336 {
337 struct attrlist *al;
338
339 al = emalloc(sizeof(*al));
340 al->al_next = NULL;
341 al->al_this = NULL;
342 return al;
343 }
344
345 struct attrlist *
346 attrlist_cons(struct attrlist *next, struct attr *a)
347 {
348 struct attrlist *al;
349
350 al = attrlist_create();
351 al->al_next = next;
352 al->al_this = a;
353 return al;
354 }
355
356 void
357 attrlist_destroy(struct attrlist *al)
358 {
359 assert(al->al_next == NULL);
360 assert(al->al_this == NULL);
361 free(al);
362 }
363
364 void
365 attrlist_destroyall(struct attrlist *al)
366 {
367 struct attrlist *next;
368
369 while (al != NULL) {
370 next = al->al_next;
371 al->al_next = NULL;
372 /* XXX should we make the caller guarantee this? */
373 al->al_this = NULL;
374 attrlist_destroy(al);
375 al = next;
376 }
377 }
378
379 /*
380 * Condition expressions
381 */
382
383 /*
384 * Create an expression node.
385 */
386 struct condexpr *
387 condexpr_create(enum condexpr_types type)
388 {
389 struct condexpr *cx;
390
391 cx = emalloc(sizeof(*cx));
392 cx->cx_type = type;
393 switch (type) {
394
395 case CX_ATOM:
396 cx->cx_atom = NULL;
397 break;
398
399 case CX_NOT:
400 cx->cx_not = NULL;
401 break;
402
403 case CX_AND:
404 cx->cx_and.left = NULL;
405 cx->cx_and.right = NULL;
406 break;
407
408 case CX_OR:
409 cx->cx_or.left = NULL;
410 cx->cx_or.right = NULL;
411 break;
412
413 default:
414 panic("condexpr_create: invalid expr type %d", (int)type);
415 }
416 return cx;
417 }
418
419 /*
420 * Free an expression tree.
421 */
422 void
423 condexpr_destroy(struct condexpr *expr)
424 {
425 switch (expr->cx_type) {
426
427 case CX_ATOM:
428 /* nothing */
429 break;
430
431 case CX_NOT:
432 condexpr_destroy(expr->cx_not);
433 break;
434
435 case CX_AND:
436 condexpr_destroy(expr->cx_and.left);
437 condexpr_destroy(expr->cx_and.right);
438 break;
439
440 case CX_OR:
441 condexpr_destroy(expr->cx_or.left);
442 condexpr_destroy(expr->cx_or.right);
443 break;
444
445 default:
446 panic("condexpr_destroy: invalid expr type %d",
447 (int)expr->cx_type);
448 }
449 free(expr);
450 }
451
452 /************************************************************/
453
454 /*
455 * Diagnostic messages
456 */
457
458 void
459 cfgdbg(const char *fmt, ...)
460 {
461 va_list ap;
462 extern const char *yyfile;
463
464 va_start(ap, fmt);
465 cfgvxdbg(yyfile, currentline(), fmt, ap);
466 va_end(ap);
467 }
468
469 void
470 cfgwarn(const char *fmt, ...)
471 {
472 va_list ap;
473 extern const char *yyfile;
474
475 va_start(ap, fmt);
476 cfgvxwarn(yyfile, currentline(), fmt, ap);
477 va_end(ap);
478 }
479
480 void
481 cfgxwarn(const char *file, int line, const char *fmt, ...)
482 {
483 va_list ap;
484
485 va_start(ap, fmt);
486 cfgvxwarn(file, line, fmt, ap);
487 va_end(ap);
488 }
489
490 static void
491 cfgvxdbg(const char *file, int line, const char *fmt, va_list ap)
492 {
493 cfgvxmsg(file, line, "debug: ", fmt, ap);
494 }
495
496 static void
497 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap)
498 {
499 cfgvxmsg(file, line, "warning: ", fmt, ap);
500 }
501
502 /*
503 * External (config file) error. Complain, using current file
504 * and line number.
505 */
506 void
507 cfgerror(const char *fmt, ...)
508 {
509 va_list ap;
510 extern const char *yyfile;
511
512 va_start(ap, fmt);
513 cfgvxerror(yyfile, currentline(), fmt, ap);
514 va_end(ap);
515 }
516
517 /*
518 * Delayed config file error (i.e., something was wrong but we could not
519 * find out about it until later).
520 */
521 void
522 cfgxerror(const char *file, int line, const char *fmt, ...)
523 {
524 va_list ap;
525
526 va_start(ap, fmt);
527 cfgvxerror(file, line, fmt, ap);
528 va_end(ap);
529 }
530
531 /*
532 * Internal form of error() and xerror().
533 */
534 static void
535 cfgvxerror(const char *file, int line, const char *fmt, va_list ap)
536 {
537 cfgvxmsg(file, line, "", fmt, ap);
538 errors++;
539 }
540
541
542 /*
543 * Internal error, abort.
544 */
545 __dead void
546 panic(const char *fmt, ...)
547 {
548 va_list ap;
549
550 va_start(ap, fmt);
551 (void)fprintf(stderr, "%s: panic: ", getprogname());
552 (void)vfprintf(stderr, fmt, ap);
553 (void)putc('\n', stderr);
554 va_end(ap);
555 exit(2);
556 }
557
558 /*
559 * Internal form of error() and xerror().
560 */
561 static void
562 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt,
563 va_list ap)
564 {
565
566 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass);
567 (void)vfprintf(stderr, fmt, ap);
568 (void)putc('\n', stderr);
569 }
570
571 void
572 autogen_comment(FILE *fp, const char *targetfile)
573 {
574
575 (void)fprintf(fp,
576 "/*\n"
577 " * MACHINE GENERATED: DO NOT EDIT\n"
578 " *\n"
579 " * %s, from \"%s\"\n"
580 " */\n\n",
581 targetfile, conffile);
582 }
583