util.c revision 1.10 1 /* $NetBSD: util.c,v 1.10 2012/03/11 07:32:41 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 * Push a prefix onto the prefix stack.
67 */
68 void
69 prefix_push(const char *path)
70 {
71 struct prefix *pf;
72 char *cp;
73
74 pf = ecalloc(1, sizeof(struct prefix));
75
76 if (! SLIST_EMPTY(&prefixes) && *path != '/') {
77 cp = emalloc(strlen(SLIST_FIRST(&prefixes)->pf_prefix) + 1 +
78 strlen(path) + 1);
79 (void) sprintf(cp, "%s/%s",
80 SLIST_FIRST(&prefixes)->pf_prefix, path);
81 pf->pf_prefix = intern(cp);
82 free(cp);
83 } else
84 pf->pf_prefix = intern(path);
85
86 SLIST_INSERT_HEAD(&prefixes, pf, pf_next);
87 }
88
89 /*
90 * Pop a prefix off the prefix stack.
91 */
92 void
93 prefix_pop(void)
94 {
95 struct prefix *pf;
96
97 if ((pf = SLIST_FIRST(&prefixes)) == NULL) {
98 cfgerror("no prefixes on the stack to pop");
99 return;
100 }
101
102 SLIST_REMOVE_HEAD(&prefixes, pf_next);
103 /* Remember this prefix for emitting -I... directives later. */
104 SLIST_INSERT_HEAD(&allprefixes, pf, pf_next);
105 }
106
107 /*
108 * Prepend the source path to a file name.
109 */
110 char *
111 sourcepath(const char *file)
112 {
113 size_t len;
114 char *cp;
115 struct prefix *pf;
116
117 pf = SLIST_EMPTY(&prefixes) ? NULL : SLIST_FIRST(&prefixes);
118 if (pf != NULL && *pf->pf_prefix == '/')
119 len = strlen(pf->pf_prefix) + 1 + strlen(file) + 1;
120 else {
121 len = strlen(srcdir) + 1 + strlen(file) + 1;
122 if (pf != NULL)
123 len += strlen(pf->pf_prefix) + 1;
124 }
125
126 cp = emalloc(len);
127
128 if (pf != NULL) {
129 if (*pf->pf_prefix == '/')
130 (void) sprintf(cp, "%s/%s", pf->pf_prefix, file);
131 else
132 (void) sprintf(cp, "%s/%s/%s", srcdir,
133 pf->pf_prefix, file);
134 } else
135 (void) sprintf(cp, "%s/%s", srcdir, file);
136 return (cp);
137 }
138
139 struct nvlist *
140 newnv(const char *name, const char *str, void *ptr, long long i, struct nvlist *next)
141 {
142 struct nvlist *nv;
143
144 nv = ecalloc(1, sizeof(*nv));
145 nv->nv_next = next;
146 nv->nv_name = name;
147 nv->nv_str = str;
148 nv->nv_ptr = ptr;
149 nv->nv_num = i;
150 return nv;
151 }
152
153 /*
154 * Free an nvlist structure (just one).
155 */
156 void
157 nvfree(struct nvlist *nv)
158 {
159
160 free(nv);
161 }
162
163 /*
164 * Free an nvlist (the whole list).
165 */
166 void
167 nvfreel(struct nvlist *nv)
168 {
169 struct nvlist *next;
170
171 for (; nv != NULL; nv = next) {
172 next = nv->nv_next;
173 free(nv);
174 }
175 }
176
177 struct nvlist *
178 nvcat(struct nvlist *nv1, struct nvlist *nv2)
179 {
180 struct nvlist *nv;
181
182 if (nv1 == NULL)
183 return nv2;
184
185 for (nv = nv1; nv->nv_next != NULL; nv = nv->nv_next);
186
187 nv->nv_next = nv2;
188 return nv1;
189 }
190
191 struct attrlist *
192 attrlist_create(void)
193 {
194 struct attrlist *al;
195
196 al = emalloc(sizeof(*al));
197 al->al_next = NULL;
198 al->al_this = NULL;
199 return al;
200 }
201
202 struct attrlist *
203 attrlist_cons(struct attrlist *next, struct attr *a)
204 {
205 struct attrlist *al;
206
207 al = attrlist_create();
208 al->al_next = next;
209 al->al_this = a;
210 return al;
211 }
212
213 void
214 attrlist_destroy(struct attrlist *al)
215 {
216 assert(al->al_next == NULL);
217 assert(al->al_this == NULL);
218 free(al);
219 }
220
221 void
222 attrlist_destroyall(struct attrlist *al)
223 {
224 struct attrlist *next;
225
226 while (al != NULL) {
227 next = al->al_next;
228 al->al_next = NULL;
229 /* XXX should we make the caller guarantee this? */
230 al->al_this = NULL;
231 attrlist_destroy(al);
232 al = next;
233 }
234 }
235
236 void
237 cfgwarn(const char *fmt, ...)
238 {
239 va_list ap;
240 extern const char *yyfile;
241
242 va_start(ap, fmt);
243 cfgvxwarn(yyfile, currentline(), fmt, ap);
244 va_end(ap);
245 }
246
247 void
248 cfgxwarn(const char *file, int line, const char *fmt, ...)
249 {
250 va_list ap;
251
252 va_start(ap, fmt);
253 cfgvxwarn(file, line, fmt, ap);
254 va_end(ap);
255 }
256
257 static void
258 cfgvxwarn(const char *file, int line, const char *fmt, va_list ap)
259 {
260 cfgvxmsg(file, line, "warning: ", fmt, ap);
261 }
262
263 /*
264 * External (config file) error. Complain, using current file
265 * and line number.
266 */
267 void
268 cfgerror(const char *fmt, ...)
269 {
270 va_list ap;
271 extern const char *yyfile;
272
273 va_start(ap, fmt);
274 cfgvxerror(yyfile, currentline(), fmt, ap);
275 va_end(ap);
276 }
277
278 /*
279 * Delayed config file error (i.e., something was wrong but we could not
280 * find out about it until later).
281 */
282 void
283 cfgxerror(const char *file, int line, const char *fmt, ...)
284 {
285 va_list ap;
286
287 va_start(ap, fmt);
288 cfgvxerror(file, line, fmt, ap);
289 va_end(ap);
290 }
291
292 /*
293 * Internal form of error() and xerror().
294 */
295 static void
296 cfgvxerror(const char *file, int line, const char *fmt, va_list ap)
297 {
298 cfgvxmsg(file, line, "", fmt, ap);
299 errors++;
300 }
301
302
303 /*
304 * Internal error, abort.
305 */
306 __dead void
307 panic(const char *fmt, ...)
308 {
309 va_list ap;
310
311 va_start(ap, fmt);
312 (void)fprintf(stderr, "%s: panic: ", getprogname());
313 (void)vfprintf(stderr, fmt, ap);
314 (void)putc('\n', stderr);
315 va_end(ap);
316 exit(2);
317 }
318
319 /*
320 * Internal form of error() and xerror().
321 */
322 static void
323 cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt,
324 va_list ap)
325 {
326
327 (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass);
328 (void)vfprintf(stderr, fmt, ap);
329 (void)putc('\n', stderr);
330 }
331
332 void
333 autogen_comment(FILE *fp, const char *targetfile)
334 {
335
336 (void)fprintf(fp,
337 "/*\n"
338 " * MACHINE GENERATED: DO NOT EDIT\n"
339 " *\n"
340 " * %s, from \"%s\"\n"
341 " */\n\n",
342 targetfile, conffile);
343 }
344