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