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
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_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
defoptlist_destroy(struct defoptlist * dl)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 *
defoptlist_append(struct defoptlist * dla,struct defoptlist * dlb)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 *
loclist_create(const char * name,const char * string,long long num)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
loclist_destroy(struct loclist * ll)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 *
attrlist_create(void)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 *
attrlist_cons(struct attrlist * next,struct attr * a)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
attrlist_destroy(struct attrlist * al)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
attrlist_destroyall(struct attrlist * al)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 *
condexpr_create(enum condexpr_types type)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
condexpr_destroy(struct condexpr * expr)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
cfgdbg(const char * fmt,...)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
cfgwarn(const char * fmt,...)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
cfgxwarn(const char * file,int line,const char * fmt,...)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
cfgvxdbg(const char * file,int line,const char * fmt,va_list ap)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
cfgvxwarn(const char * file,int line,const char * fmt,va_list ap)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
cfgerror(const char * fmt,...)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
cfgxerror(const char * file,int line,const char * fmt,...)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
cfgvxerror(const char * file,int line,const char * fmt,va_list ap)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
panic(const char * fmt,...)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
cfgvxmsg(const char * file,int line,const char * msgclass,const char * fmt,va_list ap)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
autogen_comment(FILE * fp,const char * targetfile)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