util.c revision 1.12 1 /* $NetBSD: util.c,v 1.12 2012/03/11 20:02:55 dholland 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 * Attribute lists
209 */
210
211 struct attrlist *
212 attrlist_create(void)
213 {
214 struct attrlist *al;
215
216 al = emalloc(sizeof(*al));
217 al->al_next = NULL;
218 al->al_this = NULL;
219 return al;
220 }
221
222 struct attrlist *
223 attrlist_cons(struct attrlist *next, struct attr *a)
224 {
225 struct attrlist *al;
226
227 al = attrlist_create();
228 al->al_next = next;
229 al->al_this = a;
230 return al;
231 }
232
233 void
234 attrlist_destroy(struct attrlist *al)
235 {
236 assert(al->al_next == NULL);
237 assert(al->al_this == NULL);
238 free(al);
239 }
240
241 void
242 attrlist_destroyall(struct attrlist *al)
243 {
244 struct attrlist *next;
245
246 while (al != NULL) {
247 next = al->al_next;
248 al->al_next = NULL;
249 /* XXX should we make the caller guarantee this? */
250 al->al_this = NULL;
251 attrlist_destroy(al);
252 al = next;
253 }
254 }
255
256 /*
257 * Condition expressions
258 */
259
260 /*
261 * Create an expression node.
262 */
263 struct condexpr *
264 condexpr_create(enum condexpr_types type)
265 {
266 struct condexpr *cx;
267
268 cx = emalloc(sizeof(*cx));
269 cx->cx_type = type;
270 switch (type) {
271
272 case CX_ATOM:
273 cx->cx_atom = NULL;
274 break;
275
276 case CX_NOT:
277 cx->cx_not = NULL;
278 break;
279
280 case CX_AND:
281 cx->cx_and.left = NULL;
282 cx->cx_and.right = NULL;
283 break;
284
285 case CX_OR:
286 cx->cx_or.left = NULL;
287 cx->cx_or.right = NULL;
288 break;
289
290 default:
291 panic("condexpr_create: invalid expr type %d", (int)type);
292 }
293 return cx;
294 }
295
296 /*
297 * Free an expression tree.
298 */
299 void
300 condexpr_destroy(struct condexpr *expr)
301 {
302 switch (expr->cx_type) {
303
304 case CX_ATOM:
305 /* nothing */
306 break;
307
308 case CX_NOT:
309 condexpr_destroy(expr->cx_not);
310 break;
311
312 case CX_AND:
313 condexpr_destroy(expr->cx_and.left);
314 condexpr_destroy(expr->cx_and.right);
315 break;
316
317 case CX_OR:
318 condexpr_destroy(expr->cx_or.left);
319 condexpr_destroy(expr->cx_or.right);
320 break;
321
322 default:
323 panic("condexpr_destroy: invalid expr type %d",
324 (int)expr->cx_type);
325 }
326 free(expr);
327 }
328
329 /************************************************************/
330
331 /*
332 * Diagnostic messages
333 */
334
335 void
336 cfgwarn(const char *fmt, ...)
337 {
338 va_list ap;
339 extern const char *yyfile;
340
341 va_start(ap, fmt);
342 cfgvxwarn(yyfile, currentline(), fmt, ap);
343 va_end(ap);
344 }
345
346 void
347 cfgxwarn(const char *file, int line, const char *fmt, ...)
348 {
349 va_list ap;
350
351 va_start(ap, fmt);
352 cfgvxwarn(file, line, fmt, ap);
353 va_end(ap);
354 }
355
356 static void
357 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap)
358 {
359 cfgvxmsg(file, line, "warning: ", fmt, ap);
360 }
361
362 /*
363 * External (config file) error. Complain, using current file
364 * and line number.
365 */
366 void
367 cfgerror(const char *fmt, ...)
368 {
369 va_list ap;
370 extern const char *yyfile;
371
372 va_start(ap, fmt);
373 cfgvxerror(yyfile, currentline(), fmt, ap);
374 va_end(ap);
375 }
376
377 /*
378 * Delayed config file error (i.e., something was wrong but we could not
379 * find out about it until later).
380 */
381 void
382 cfgxerror(const char *file, int line, const char *fmt, ...)
383 {
384 va_list ap;
385
386 va_start(ap, fmt);
387 cfgvxerror(file, line, fmt, ap);
388 va_end(ap);
389 }
390
391 /*
392 * Internal form of error() and xerror().
393 */
394 static void
395 cfgvxerror(const char *file, int line, const char *fmt, va_list ap)
396 {
397 cfgvxmsg(file, line, "", fmt, ap);
398 errors++;
399 }
400
401
402 /*
403 * Internal error, abort.
404 */
405 __dead void
406 panic(const char *fmt, ...)
407 {
408 va_list ap;
409
410 va_start(ap, fmt);
411 (void)fprintf(stderr, "%s: panic: ", getprogname());
412 (void)vfprintf(stderr, fmt, ap);
413 (void)putc('\n', stderr);
414 va_end(ap);
415 exit(2);
416 }
417
418 /*
419 * Internal form of error() and xerror().
420 */
421 static void
422 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt,
423 va_list ap)
424 {
425
426 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass);
427 (void)vfprintf(stderr, fmt, ap);
428 (void)putc('\n', stderr);
429 }
430
431 void
432 autogen_comment(FILE *fp, const char *targetfile)
433 {
434
435 (void)fprintf(fp,
436 "/*\n"
437 " * MACHINE GENERATED: DO NOT EDIT\n"
438 " *\n"
439 " * %s, from \"%s\"\n"
440 " */\n\n",
441 targetfile, conffile);
442 }
443