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