files.c revision 1.7 1 1.7 dsl /* $NetBSD: files.c,v 1.7 2007/11/30 23:19:18 dsl Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.1 thorpej * Copyright (c) 1992, 1993
5 1.1 thorpej * The Regents of the University of California. All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * This software was developed by the Computer Systems Engineering group
8 1.1 thorpej * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 1.1 thorpej * contributed to Berkeley.
10 1.1 thorpej *
11 1.1 thorpej * All advertising materials mentioning features or use of this software
12 1.1 thorpej * must display the following acknowledgement:
13 1.1 thorpej * This product includes software developed by the University of
14 1.1 thorpej * California, Lawrence Berkeley Laboratories.
15 1.1 thorpej *
16 1.1 thorpej * Redistribution and use in source and binary forms, with or without
17 1.1 thorpej * modification, are permitted provided that the following conditions
18 1.1 thorpej * are met:
19 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
20 1.1 thorpej * notice, this list of conditions and the following disclaimer.
21 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
22 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
23 1.1 thorpej * documentation and/or other materials provided with the distribution.
24 1.1 thorpej * 3. Neither the name of the University nor the names of its contributors
25 1.1 thorpej * may be used to endorse or promote products derived from this software
26 1.1 thorpej * without specific prior written permission.
27 1.1 thorpej *
28 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.1 thorpej * SUCH DAMAGE.
39 1.1 thorpej *
40 1.1 thorpej * from: @(#)files.c 8.1 (Berkeley) 6/6/93
41 1.1 thorpej */
42 1.1 thorpej
43 1.1 thorpej #if HAVE_NBTOOL_CONFIG_H
44 1.1 thorpej #include "nbtool_config.h"
45 1.1 thorpej #endif
46 1.1 thorpej
47 1.1 thorpej #include <sys/param.h>
48 1.1 thorpej #include <errno.h>
49 1.1 thorpej #include <stdio.h>
50 1.1 thorpej #include <stdlib.h>
51 1.1 thorpej #include <string.h>
52 1.3 christos #include <util.h>
53 1.1 thorpej #include "defs.h"
54 1.1 thorpej
55 1.1 thorpej extern const char *yyfile;
56 1.1 thorpej
57 1.1 thorpej /*
58 1.1 thorpej * We check that each full path name is unique. File base names
59 1.1 thorpej * should generally also be unique, e.g., having both a net/xx.c and
60 1.1 thorpej * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
61 1.1 thorpej * wrong, but is permitted under some conditions.
62 1.1 thorpej */
63 1.1 thorpej static struct hashtab *basetab; /* file base names */
64 1.1 thorpej static struct hashtab *pathtab; /* full path names */
65 1.1 thorpej
66 1.1 thorpej static struct files **unchecked;
67 1.1 thorpej
68 1.1 thorpej static int checkaux(const char *, void *);
69 1.1 thorpej static int fixcount(const char *, void *);
70 1.1 thorpej static int fixfsel(const char *, void *);
71 1.1 thorpej static int fixsel(const char *, void *);
72 1.1 thorpej static int expr_eval(struct nvlist *,
73 1.1 thorpej int (*)(const char *, void *), void *);
74 1.1 thorpej static void expr_free(struct nvlist *);
75 1.1 thorpej
76 1.1 thorpej void
77 1.1 thorpej initfiles(void)
78 1.1 thorpej {
79 1.1 thorpej
80 1.1 thorpej basetab = ht_new();
81 1.1 thorpej pathtab = ht_new();
82 1.1 thorpej TAILQ_INIT(&allfiles);
83 1.1 thorpej unchecked = &TAILQ_FIRST(&allfiles);
84 1.1 thorpej TAILQ_INIT(&allobjects);
85 1.1 thorpej }
86 1.1 thorpej
87 1.1 thorpej void
88 1.1 thorpej addfile(const char *path, struct nvlist *optx, int flags, const char *rule)
89 1.1 thorpej {
90 1.1 thorpej struct files *fi;
91 1.1 thorpej const char *dotp, *tail;
92 1.1 thorpej size_t baselen;
93 1.1 thorpej int needc, needf;
94 1.1 thorpej char base[200];
95 1.1 thorpej
96 1.1 thorpej /* check various errors */
97 1.1 thorpej needc = flags & FI_NEEDSCOUNT;
98 1.1 thorpej needf = flags & FI_NEEDSFLAG;
99 1.1 thorpej if (needc && needf) {
100 1.6 christos cfgerror("cannot mix needs-count and needs-flag");
101 1.1 thorpej goto bad;
102 1.1 thorpej }
103 1.1 thorpej if (optx == NULL && (needc || needf)) {
104 1.6 christos cfgerror("nothing to %s for %s", needc ? "count" : "flag",
105 1.6 christos path);
106 1.1 thorpej goto bad;
107 1.1 thorpej }
108 1.1 thorpej
109 1.1 thorpej /* find last part of pathname, and same without trailing suffix */
110 1.1 thorpej tail = strrchr(path, '/');
111 1.1 thorpej if (tail == NULL)
112 1.1 thorpej tail = path;
113 1.1 thorpej else
114 1.1 thorpej tail++;
115 1.1 thorpej dotp = strrchr(tail, '.');
116 1.1 thorpej if (dotp == NULL || dotp[1] == 0 ||
117 1.1 thorpej (baselen = dotp - tail) >= sizeof(base)) {
118 1.6 christos cfgerror("invalid pathname `%s'", path);
119 1.1 thorpej goto bad;
120 1.1 thorpej }
121 1.1 thorpej
122 1.1 thorpej /*
123 1.1 thorpej * Commit this file to memory. We will decide later whether it
124 1.1 thorpej * will be used after all.
125 1.1 thorpej */
126 1.1 thorpej fi = ecalloc(1, sizeof *fi);
127 1.1 thorpej if (ht_insert(pathtab, path, fi)) {
128 1.1 thorpej free(fi);
129 1.1 thorpej if ((fi = ht_lookup(pathtab, path)) == NULL)
130 1.1 thorpej panic("addfile: ht_lookup(%s)", path);
131 1.1 thorpej
132 1.1 thorpej /*
133 1.1 thorpej * If it's a duplicate entry, it is must specify a make
134 1.1 thorpej * rule, and only a make rule, and must come from
135 1.1 thorpej * a different source file than the original entry.
136 1.1 thorpej * If it does otherwise, it is disallowed. This allows
137 1.1 thorpej * machine-dependent files to override the compilation
138 1.1 thorpej * options for specific files.
139 1.1 thorpej */
140 1.1 thorpej if (rule != NULL && optx == NULL && flags == 0 &&
141 1.1 thorpej yyfile != fi->fi_srcfile) {
142 1.1 thorpej fi->fi_mkrule = rule;
143 1.1 thorpej return;
144 1.1 thorpej }
145 1.6 christos cfgerror("duplicate file %s", path);
146 1.6 christos cfgxerror(fi->fi_srcfile, fi->fi_srcline,
147 1.1 thorpej "here is the original definition");
148 1.1 thorpej goto bad;
149 1.1 thorpej }
150 1.1 thorpej memcpy(base, tail, baselen);
151 1.1 thorpej base[baselen] = 0;
152 1.1 thorpej fi->fi_srcfile = yyfile;
153 1.1 thorpej fi->fi_srcline = currentline();
154 1.1 thorpej fi->fi_flags = flags;
155 1.1 thorpej fi->fi_path = path;
156 1.1 thorpej fi->fi_tail = tail;
157 1.1 thorpej fi->fi_base = intern(base);
158 1.1 thorpej fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
159 1.1 thorpej SLIST_FIRST(&prefixes)->pf_prefix;
160 1.1 thorpej fi->fi_optx = optx;
161 1.1 thorpej fi->fi_optf = NULL;
162 1.1 thorpej fi->fi_mkrule = rule;
163 1.1 thorpej TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
164 1.1 thorpej return;
165 1.1 thorpej bad:
166 1.1 thorpej expr_free(optx);
167 1.1 thorpej }
168 1.1 thorpej
169 1.1 thorpej void
170 1.1 thorpej addobject(const char *path, struct nvlist *optx, int flags)
171 1.1 thorpej {
172 1.1 thorpej struct objects *oi;
173 1.1 thorpej
174 1.1 thorpej /*
175 1.1 thorpej * Commit this object to memory. We will decide later whether it
176 1.1 thorpej * will be used after all.
177 1.1 thorpej */
178 1.1 thorpej oi = ecalloc(1, sizeof *oi);
179 1.1 thorpej if (ht_insert(pathtab, path, oi)) {
180 1.1 thorpej free(oi);
181 1.1 thorpej if ((oi = ht_lookup(pathtab, path)) == NULL)
182 1.1 thorpej panic("addfile: ht_lookup(%s)", path);
183 1.6 christos cfgerror("duplicate file %s", path);
184 1.6 christos cfgxerror(oi->oi_srcfile, oi->oi_srcline,
185 1.1 thorpej "here is the original definition");
186 1.1 thorpej }
187 1.1 thorpej oi->oi_srcfile = yyfile;
188 1.1 thorpej oi->oi_srcline = currentline();
189 1.1 thorpej oi->oi_flags = flags;
190 1.1 thorpej oi->oi_path = path;
191 1.1 thorpej oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
192 1.1 thorpej SLIST_FIRST(&prefixes)->pf_prefix;
193 1.1 thorpej oi->oi_optx = optx;
194 1.1 thorpej oi->oi_optf = NULL;
195 1.1 thorpej TAILQ_INSERT_TAIL(&allobjects, oi, oi_next);
196 1.1 thorpej return;
197 1.1 thorpej }
198 1.1 thorpej
199 1.1 thorpej /*
200 1.1 thorpej * We have finished reading some "files" file, either ../../conf/files
201 1.1 thorpej * or ./files.$machine. Make sure that everything that is flagged as
202 1.1 thorpej * needing a count is reasonable. (This prevents ../../conf/files from
203 1.1 thorpej * depending on some machine-specific device.)
204 1.1 thorpej */
205 1.1 thorpej void
206 1.1 thorpej checkfiles(void)
207 1.1 thorpej {
208 1.1 thorpej struct files *fi, *last;
209 1.1 thorpej
210 1.1 thorpej last = NULL;
211 1.1 thorpej for (fi = *unchecked; fi != NULL;
212 1.1 thorpej last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
213 1.1 thorpej if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
214 1.1 thorpej (void)expr_eval(fi->fi_optx, checkaux, fi);
215 1.1 thorpej }
216 1.1 thorpej if (last != NULL)
217 1.1 thorpej unchecked = &TAILQ_NEXT(last, fi_next);
218 1.1 thorpej }
219 1.1 thorpej
220 1.1 thorpej /*
221 1.1 thorpej * Auxiliary function for checkfiles, called from expr_eval.
222 1.1 thorpej * We are not actually interested in the expression's value.
223 1.1 thorpej */
224 1.1 thorpej static int
225 1.1 thorpej checkaux(const char *name, void *context)
226 1.1 thorpej {
227 1.1 thorpej struct files *fi = context;
228 1.1 thorpej
229 1.1 thorpej if (ht_lookup(devbasetab, name) == NULL) {
230 1.6 christos cfgxerror(fi->fi_srcfile, fi->fi_srcline,
231 1.1 thorpej "`%s' is not a countable device",
232 1.1 thorpej name);
233 1.1 thorpej /* keep fixfiles() from complaining again */
234 1.1 thorpej fi->fi_flags |= FI_HIDDEN;
235 1.1 thorpej }
236 1.1 thorpej return (0);
237 1.1 thorpej }
238 1.1 thorpej
239 1.1 thorpej /*
240 1.1 thorpej * We have finished reading everything. Tack the files down: calculate
241 1.1 thorpej * selection and counts as needed. Check that the object files built
242 1.1 thorpej * from the selected sources do not collide.
243 1.1 thorpej */
244 1.1 thorpej int
245 1.1 thorpej fixfiles(void)
246 1.1 thorpej {
247 1.1 thorpej struct files *fi, *ofi;
248 1.1 thorpej struct nvlist *flathead, **flatp;
249 1.1 thorpej int err, sel;
250 1.1 thorpej
251 1.1 thorpej err = 0;
252 1.1 thorpej TAILQ_FOREACH(fi, &allfiles, fi_next) {
253 1.2 erh
254 1.1 thorpej /* Skip files that generated counted-device complaints. */
255 1.1 thorpej if (fi->fi_flags & FI_HIDDEN)
256 1.1 thorpej continue;
257 1.1 thorpej
258 1.1 thorpej /* Optional: see if it is to be included. */
259 1.2 erh if (fi->fi_flags & FIT_FORCESELECT)
260 1.2 erh {
261 1.2 erh /* include it */ ;
262 1.2 erh }
263 1.2 erh else if (fi->fi_optx != NULL) {
264 1.1 thorpej flathead = NULL;
265 1.1 thorpej flatp = &flathead;
266 1.1 thorpej sel = expr_eval(fi->fi_optx,
267 1.1 thorpej fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
268 1.1 thorpej fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
269 1.1 thorpej fixsel,
270 1.1 thorpej &flatp);
271 1.1 thorpej fi->fi_optf = flathead;
272 1.1 thorpej if (!sel)
273 1.1 thorpej continue;
274 1.1 thorpej }
275 1.1 thorpej
276 1.1 thorpej /* We like this file. Make sure it generates a unique .o. */
277 1.1 thorpej if (ht_insert(basetab, fi->fi_base, fi)) {
278 1.1 thorpej if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
279 1.1 thorpej panic("fixfiles ht_lookup(%s)", fi->fi_base);
280 1.1 thorpej /*
281 1.1 thorpej * If the new file comes from a different source,
282 1.1 thorpej * allow the new one to override the old one.
283 1.1 thorpej */
284 1.1 thorpej if (fi->fi_path != ofi->fi_path) {
285 1.1 thorpej if (ht_replace(basetab, fi->fi_base, fi) != 1)
286 1.1 thorpej panic("fixfiles ht_replace(%s)",
287 1.1 thorpej fi->fi_base);
288 1.1 thorpej ofi->fi_flags &= ~FI_SEL;
289 1.1 thorpej ofi->fi_flags |= FI_HIDDEN;
290 1.1 thorpej } else {
291 1.6 christos cfgxerror(fi->fi_srcfile, fi->fi_srcline,
292 1.1 thorpej "object file collision on %s.o, from %s",
293 1.1 thorpej fi->fi_base, fi->fi_path);
294 1.6 christos cfgxerror(ofi->fi_srcfile, ofi->fi_srcline,
295 1.1 thorpej "here is the previous file: %s",
296 1.1 thorpej ofi->fi_path);
297 1.1 thorpej err = 1;
298 1.1 thorpej }
299 1.1 thorpej }
300 1.1 thorpej fi->fi_flags |= FI_SEL;
301 1.1 thorpej }
302 1.1 thorpej return (err);
303 1.1 thorpej }
304 1.1 thorpej
305 1.1 thorpej /*
306 1.1 thorpej * We have finished reading everything. Tack the objects down: calculate
307 1.1 thorpej * selection.
308 1.1 thorpej */
309 1.1 thorpej int
310 1.1 thorpej fixobjects(void)
311 1.1 thorpej {
312 1.1 thorpej struct objects *oi;
313 1.1 thorpej struct nvlist *flathead, **flatp;
314 1.1 thorpej int err, sel;
315 1.1 thorpej
316 1.1 thorpej err = 0;
317 1.1 thorpej TAILQ_FOREACH(oi, &allobjects, oi_next) {
318 1.1 thorpej /* Optional: see if it is to be included. */
319 1.1 thorpej if (oi->oi_optx != NULL) {
320 1.1 thorpej flathead = NULL;
321 1.1 thorpej flatp = &flathead;
322 1.1 thorpej sel = expr_eval(oi->oi_optx,
323 1.1 thorpej oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
324 1.1 thorpej fixsel,
325 1.1 thorpej &flatp);
326 1.1 thorpej oi->oi_optf = flathead;
327 1.1 thorpej if (!sel)
328 1.1 thorpej continue;
329 1.1 thorpej }
330 1.1 thorpej
331 1.1 thorpej oi->oi_flags |= OI_SEL;
332 1.1 thorpej }
333 1.1 thorpej return (err);
334 1.1 thorpej }
335 1.1 thorpej
336 1.1 thorpej /*
337 1.1 thorpej * We have finished reading everything. Tack the devsws down: calculate
338 1.1 thorpej * selection.
339 1.1 thorpej */
340 1.1 thorpej int
341 1.1 thorpej fixdevsw(void)
342 1.1 thorpej {
343 1.5 alc int error;
344 1.1 thorpej struct devm *dm, *res;
345 1.1 thorpej struct hashtab *fixdevmtab;
346 1.1 thorpej char mstr[16];
347 1.1 thorpej
348 1.5 alc error = 0;
349 1.1 thorpej fixdevmtab = ht_new();
350 1.1 thorpej
351 1.1 thorpej TAILQ_FOREACH(dm, &alldevms, dm_next) {
352 1.1 thorpej res = ht_lookup(fixdevmtab, intern(dm->dm_name));
353 1.1 thorpej if (res != NULL) {
354 1.1 thorpej if (res->dm_cmajor != dm->dm_cmajor ||
355 1.1 thorpej res->dm_bmajor != dm->dm_bmajor) {
356 1.6 christos cfgxerror(res->dm_srcfile, res->dm_srcline,
357 1.7 dsl "device-major '%s' "
358 1.7 dsl "block %d, char %d redefined"
359 1.7 dsl " at %s:%d as block %d, char %d",
360 1.7 dsl res->dm_name,
361 1.7 dsl res->dm_bmajor, res->dm_cmajor,
362 1.7 dsl dm->dm_srcfile, dm->dm_srcline,
363 1.7 dsl dm->dm_bmajor, dm->dm_cmajor);
364 1.1 thorpej } else {
365 1.7 dsl cfgxerror(res->dm_srcfile, res->dm_srcline,
366 1.7 dsl "device-major '%s' "
367 1.7 dsl "(block %d, char %d) duplicated"
368 1.7 dsl " at %s:%d",
369 1.7 dsl dm->dm_name, dm->dm_bmajor,
370 1.7 dsl dm->dm_cmajor,
371 1.7 dsl dm->dm_srcfile, dm->dm_srcline);
372 1.1 thorpej }
373 1.7 dsl error = 1;
374 1.7 dsl goto out;
375 1.1 thorpej }
376 1.1 thorpej if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
377 1.1 thorpej panic("fixdevsw: %s char %d block %d",
378 1.1 thorpej dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
379 1.1 thorpej }
380 1.1 thorpej
381 1.1 thorpej if (dm->dm_opts != NULL &&
382 1.1 thorpej !expr_eval(dm->dm_opts, fixsel, NULL))
383 1.1 thorpej continue;
384 1.1 thorpej
385 1.1 thorpej if (dm->dm_cmajor != -1) {
386 1.1 thorpej if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
387 1.6 christos cfgxerror(dm->dm_srcfile, dm->dm_srcline,
388 1.1 thorpej "device-major of character device '%s' "
389 1.1 thorpej "is already defined", dm->dm_name);
390 1.5 alc error = 1;
391 1.4 christos goto out;
392 1.1 thorpej }
393 1.1 thorpej (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
394 1.1 thorpej if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
395 1.6 christos cfgxerror(dm->dm_srcfile, dm->dm_srcline,
396 1.1 thorpej "device-major of character major '%d' "
397 1.1 thorpej "is already defined", dm->dm_cmajor);
398 1.5 alc error = 1;
399 1.4 christos goto out;
400 1.1 thorpej }
401 1.1 thorpej if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
402 1.1 thorpej ht_insert(cdevmtab, intern(mstr), dm)) {
403 1.1 thorpej panic("fixdevsw: %s character major %d",
404 1.1 thorpej dm->dm_name, dm->dm_cmajor);
405 1.1 thorpej }
406 1.1 thorpej }
407 1.1 thorpej if (dm->dm_bmajor != -1) {
408 1.1 thorpej if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
409 1.6 christos cfgxerror(dm->dm_srcfile, dm->dm_srcline,
410 1.1 thorpej "device-major of block device '%s' "
411 1.1 thorpej "is already defined", dm->dm_name);
412 1.5 alc error = 1;
413 1.4 christos goto out;
414 1.1 thorpej }
415 1.1 thorpej (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
416 1.1 thorpej if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
417 1.6 christos cfgxerror(dm->dm_srcfile, dm->dm_srcline,
418 1.1 thorpej "device-major of block major '%d' "
419 1.1 thorpej "is already defined", dm->dm_bmajor);
420 1.5 alc error = 1;
421 1.4 christos goto out;
422 1.1 thorpej }
423 1.1 thorpej if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
424 1.1 thorpej ht_insert(bdevmtab, intern(mstr), dm)) {
425 1.1 thorpej panic("fixdevsw: %s block major %d",
426 1.1 thorpej dm->dm_name, dm->dm_bmajor);
427 1.1 thorpej }
428 1.1 thorpej }
429 1.1 thorpej }
430 1.1 thorpej
431 1.4 christos out:
432 1.4 christos ht_free(fixdevmtab);
433 1.5 alc return (error);
434 1.1 thorpej }
435 1.1 thorpej
436 1.1 thorpej /*
437 1.1 thorpej * Called when evaluating a needs-count expression. Make sure the
438 1.1 thorpej * atom is a countable device. The expression succeeds iff there
439 1.1 thorpej * is at least one of them (note that while `xx*' will not always
440 1.1 thorpej * set xx's d_umax > 0, you cannot mix '*' and needs-count). The
441 1.1 thorpej * mkheaders() routine wants a flattened, in-order list of the
442 1.1 thorpej * atoms for `#define name value' lines, so we build that as we
443 1.1 thorpej * are called to eval each atom.
444 1.1 thorpej */
445 1.1 thorpej static int
446 1.1 thorpej fixcount(const char *name, void *context)
447 1.1 thorpej {
448 1.1 thorpej struct nvlist ***p = context;
449 1.1 thorpej struct devbase *dev;
450 1.1 thorpej struct nvlist *nv;
451 1.1 thorpej
452 1.1 thorpej dev = ht_lookup(devbasetab, name);
453 1.1 thorpej if (dev == NULL) /* cannot occur here; we checked earlier */
454 1.1 thorpej panic("fixcount(%s)", name);
455 1.1 thorpej nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
456 1.1 thorpej **p = nv;
457 1.1 thorpej *p = &nv->nv_next;
458 1.1 thorpej (void)ht_insert(needcnttab, name, nv);
459 1.1 thorpej return (dev->d_umax != 0);
460 1.1 thorpej }
461 1.1 thorpej
462 1.1 thorpej /*
463 1.1 thorpej * Called from fixfiles when eval'ing a selection expression for a
464 1.1 thorpej * file that will generate a .h with flags. We will need the flat list.
465 1.1 thorpej */
466 1.1 thorpej static int
467 1.1 thorpej fixfsel(const char *name, void *context)
468 1.1 thorpej {
469 1.1 thorpej struct nvlist ***p = context;
470 1.1 thorpej struct nvlist *nv;
471 1.1 thorpej int sel;
472 1.1 thorpej
473 1.1 thorpej sel = ht_lookup(selecttab, name) != NULL;
474 1.1 thorpej nv = newnv(name, NULL, NULL, sel, NULL);
475 1.1 thorpej **p = nv;
476 1.1 thorpej *p = &nv->nv_next;
477 1.1 thorpej return (sel);
478 1.1 thorpej }
479 1.1 thorpej
480 1.1 thorpej /*
481 1.1 thorpej * As for fixfsel above, but we do not need the flat list.
482 1.1 thorpej */
483 1.1 thorpej static int
484 1.6 christos /*ARGSUSED*/
485 1.1 thorpej fixsel(const char *name, void *context)
486 1.1 thorpej {
487 1.1 thorpej
488 1.1 thorpej return (ht_lookup(selecttab, name) != NULL);
489 1.1 thorpej }
490 1.1 thorpej
491 1.1 thorpej /*
492 1.1 thorpej * Eval an expression tree. Calls the given function on each node,
493 1.1 thorpej * passing it the given context & the name; return value is &/|/! of
494 1.1 thorpej * results of evaluating atoms.
495 1.1 thorpej *
496 1.1 thorpej * No short circuiting ever occurs. fn must return 0 or 1 (otherwise
497 1.1 thorpej * our mixing of C's bitwise & boolean here may give surprises).
498 1.1 thorpej */
499 1.1 thorpej static int
500 1.1 thorpej expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
501 1.1 thorpej {
502 1.1 thorpej int lhs, rhs;
503 1.1 thorpej
504 1.1 thorpej switch (expr->nv_int) {
505 1.1 thorpej
506 1.1 thorpej case FX_ATOM:
507 1.1 thorpej return ((*fn)(expr->nv_name, context));
508 1.1 thorpej
509 1.1 thorpej case FX_NOT:
510 1.1 thorpej return (!expr_eval(expr->nv_next, fn, context));
511 1.1 thorpej
512 1.1 thorpej case FX_AND:
513 1.1 thorpej lhs = expr_eval(expr->nv_ptr, fn, context);
514 1.1 thorpej rhs = expr_eval(expr->nv_next, fn, context);
515 1.1 thorpej return (lhs & rhs);
516 1.1 thorpej
517 1.1 thorpej case FX_OR:
518 1.1 thorpej lhs = expr_eval(expr->nv_ptr, fn, context);
519 1.1 thorpej rhs = expr_eval(expr->nv_next, fn, context);
520 1.1 thorpej return (lhs | rhs);
521 1.1 thorpej }
522 1.1 thorpej panic("expr_eval %d", expr->nv_int);
523 1.1 thorpej /* NOTREACHED */
524 1.1 thorpej return (0);
525 1.1 thorpej }
526 1.1 thorpej
527 1.1 thorpej /*
528 1.1 thorpej * Free an expression tree.
529 1.1 thorpej */
530 1.1 thorpej static void
531 1.1 thorpej expr_free(struct nvlist *expr)
532 1.1 thorpej {
533 1.1 thorpej struct nvlist *rhs;
534 1.1 thorpej
535 1.1 thorpej /* This loop traverses down the RHS of each subexpression. */
536 1.1 thorpej for (; expr != NULL; expr = rhs) {
537 1.1 thorpej switch (expr->nv_int) {
538 1.1 thorpej
539 1.1 thorpej /* Atoms and !-exprs have no left hand side. */
540 1.1 thorpej case FX_ATOM:
541 1.1 thorpej case FX_NOT:
542 1.1 thorpej break;
543 1.1 thorpej
544 1.1 thorpej /* For AND and OR nodes, free the LHS. */
545 1.1 thorpej case FX_AND:
546 1.1 thorpej case FX_OR:
547 1.1 thorpej expr_free(expr->nv_ptr);
548 1.1 thorpej break;
549 1.1 thorpej
550 1.1 thorpej default:
551 1.1 thorpej panic("expr_free %d", expr->nv_int);
552 1.1 thorpej }
553 1.1 thorpej rhs = expr->nv_next;
554 1.1 thorpej nvfree(expr);
555 1.1 thorpej }
556 1.1 thorpej }
557 1.1 thorpej
558 1.1 thorpej #ifdef DEBUG
559 1.1 thorpej /*
560 1.1 thorpej * Print expression tree.
561 1.1 thorpej */
562 1.1 thorpej void
563 1.1 thorpej prexpr(struct nvlist *expr)
564 1.1 thorpej {
565 1.1 thorpej static void pr0();
566 1.1 thorpej
567 1.1 thorpej printf("expr =");
568 1.1 thorpej pr0(expr);
569 1.1 thorpej printf("\n");
570 1.1 thorpej (void)fflush(stdout);
571 1.1 thorpej }
572 1.1 thorpej
573 1.1 thorpej static void
574 1.1 thorpej pr0(struct nvlist *e)
575 1.1 thorpej {
576 1.1 thorpej
577 1.1 thorpej switch (e->nv_int) {
578 1.1 thorpej case FX_ATOM:
579 1.1 thorpej printf(" %s", e->nv_name);
580 1.1 thorpej return;
581 1.1 thorpej case FX_NOT:
582 1.1 thorpej printf(" (!");
583 1.1 thorpej break;
584 1.1 thorpej case FX_AND:
585 1.1 thorpej printf(" (&");
586 1.1 thorpej break;
587 1.1 thorpej case FX_OR:
588 1.1 thorpej printf(" (|");
589 1.1 thorpej break;
590 1.1 thorpej default:
591 1.1 thorpej printf(" (?%d?", e->nv_int);
592 1.1 thorpej break;
593 1.1 thorpej }
594 1.1 thorpej if (e->nv_ptr)
595 1.1 thorpej pr0(e->nv_ptr);
596 1.1 thorpej pr0(e->nv_next);
597 1.1 thorpej printf(")");
598 1.1 thorpej }
599 1.1 thorpej #endif
600