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