Merge from vendor branch PKGSRC:
[netbsd-mini2440.git] / usr.bin / config / files.c
blob1e6496bb2c6af9b5504242ade10f3f12983e44e6
1 /* $NetBSD: files.c,v 1.9 2009/01/20 18:20:48 drochner Exp $ */
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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.
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.
40 * from: @(#)files.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
47 #include <sys/param.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <util.h>
53 #include "defs.h"
55 extern const char *yyfile;
58 * We check that each full path name is unique. File base names
59 * should generally also be unique, e.g., having both a net/xx.c and
60 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
61 * wrong, but is permitted under some conditions.
63 static struct hashtab *basetab; /* file base names */
64 static struct hashtab *pathtab; /* full path names */
66 static struct files **unchecked;
68 static int checkaux(const char *, void *);
69 static int fixcount(const char *, void *);
70 static int fixfsel(const char *, void *);
71 static int fixsel(const char *, void *);
73 void
74 initfiles(void)
77 basetab = ht_new();
78 pathtab = ht_new();
79 TAILQ_INIT(&allfiles);
80 unchecked = &TAILQ_FIRST(&allfiles);
81 TAILQ_INIT(&allobjects);
84 void
85 addfile(const char *path, struct nvlist *optx, int flags, const char *rule)
87 struct files *fi;
88 const char *dotp, *tail;
89 size_t baselen;
90 int needc, needf;
91 char base[200];
93 /* check various errors */
94 needc = flags & FI_NEEDSCOUNT;
95 needf = flags & FI_NEEDSFLAG;
96 if (needc && needf) {
97 cfgerror("cannot mix needs-count and needs-flag");
98 goto bad;
100 if (optx == NULL && (needc || needf)) {
101 cfgerror("nothing to %s for %s", needc ? "count" : "flag",
102 path);
103 goto bad;
106 /* find last part of pathname, and same without trailing suffix */
107 tail = strrchr(path, '/');
108 if (tail == NULL)
109 tail = path;
110 else
111 tail++;
112 dotp = strrchr(tail, '.');
113 if (dotp == NULL || dotp[1] == 0 ||
114 (baselen = dotp - tail) >= sizeof(base)) {
115 cfgerror("invalid pathname `%s'", path);
116 goto bad;
120 * Commit this file to memory. We will decide later whether it
121 * will be used after all.
123 fi = ecalloc(1, sizeof *fi);
124 if (ht_insert(pathtab, path, fi)) {
125 free(fi);
126 if ((fi = ht_lookup(pathtab, path)) == NULL)
127 panic("addfile: ht_lookup(%s)", path);
130 * If it's a duplicate entry, it is must specify a make
131 * rule, and only a make rule, and must come from
132 * a different source file than the original entry.
133 * If it does otherwise, it is disallowed. This allows
134 * machine-dependent files to override the compilation
135 * options for specific files.
137 if (rule != NULL && optx == NULL && flags == 0 &&
138 yyfile != fi->fi_srcfile) {
139 fi->fi_mkrule = rule;
140 return;
142 cfgerror("duplicate file %s", path);
143 cfgxerror(fi->fi_srcfile, fi->fi_srcline,
144 "here is the original definition");
145 goto bad;
147 memcpy(base, tail, baselen);
148 base[baselen] = 0;
149 fi->fi_srcfile = yyfile;
150 fi->fi_srcline = currentline();
151 fi->fi_flags = flags;
152 fi->fi_path = path;
153 fi->fi_tail = tail;
154 fi->fi_base = intern(base);
155 fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
156 SLIST_FIRST(&prefixes)->pf_prefix;
157 fi->fi_optx = optx;
158 fi->fi_optf = NULL;
159 fi->fi_mkrule = rule;
160 TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
161 return;
162 bad:
163 expr_free(optx);
166 void
167 addobject(const char *path, struct nvlist *optx, int flags)
169 struct objects *oi;
172 * Commit this object to memory. We will decide later whether it
173 * will be used after all.
175 oi = ecalloc(1, sizeof *oi);
176 if (ht_insert(pathtab, path, oi)) {
177 free(oi);
178 if ((oi = ht_lookup(pathtab, path)) == NULL)
179 panic("addfile: ht_lookup(%s)", path);
180 cfgerror("duplicate file %s", path);
181 cfgxerror(oi->oi_srcfile, oi->oi_srcline,
182 "here is the original definition");
184 oi->oi_srcfile = yyfile;
185 oi->oi_srcline = currentline();
186 oi->oi_flags = flags;
187 oi->oi_path = path;
188 oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
189 SLIST_FIRST(&prefixes)->pf_prefix;
190 oi->oi_optx = optx;
191 oi->oi_optf = NULL;
192 TAILQ_INSERT_TAIL(&allobjects, oi, oi_next);
193 return;
197 * We have finished reading some "files" file, either ../../conf/files
198 * or ./files.$machine. Make sure that everything that is flagged as
199 * needing a count is reasonable. (This prevents ../../conf/files from
200 * depending on some machine-specific device.)
202 void
203 checkfiles(void)
205 struct files *fi, *last;
207 last = NULL;
208 for (fi = *unchecked; fi != NULL;
209 last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
210 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
211 (void)expr_eval(fi->fi_optx, checkaux, fi);
213 if (last != NULL)
214 unchecked = &TAILQ_NEXT(last, fi_next);
218 * Auxiliary function for checkfiles, called from expr_eval.
219 * We are not actually interested in the expression's value.
221 static int
222 checkaux(const char *name, void *context)
224 struct files *fi = context;
226 if (ht_lookup(devbasetab, name) == NULL) {
227 cfgxerror(fi->fi_srcfile, fi->fi_srcline,
228 "`%s' is not a countable device",
229 name);
230 /* keep fixfiles() from complaining again */
231 fi->fi_flags |= FI_HIDDEN;
233 return (0);
237 * We have finished reading everything. Tack the files down: calculate
238 * selection and counts as needed. Check that the object files built
239 * from the selected sources do not collide.
242 fixfiles(void)
244 struct files *fi, *ofi;
245 struct nvlist *flathead, **flatp;
246 int err, sel;
248 err = 0;
249 TAILQ_FOREACH(fi, &allfiles, fi_next) {
251 /* Skip files that generated counted-device complaints. */
252 if (fi->fi_flags & FI_HIDDEN)
253 continue;
255 /* Optional: see if it is to be included. */
256 if (fi->fi_flags & FIT_FORCESELECT)
258 /* include it */ ;
260 else if (fi->fi_optx != NULL) {
261 flathead = NULL;
262 flatp = &flathead;
263 sel = expr_eval(fi->fi_optx,
264 fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
265 fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
266 fixsel,
267 &flatp);
268 fi->fi_optf = flathead;
269 if (!sel)
270 continue;
273 /* We like this file. Make sure it generates a unique .o. */
274 if (ht_insert(basetab, fi->fi_base, fi)) {
275 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
276 panic("fixfiles ht_lookup(%s)", fi->fi_base);
278 * If the new file comes from a different source,
279 * allow the new one to override the old one.
281 if (fi->fi_path != ofi->fi_path) {
282 if (ht_replace(basetab, fi->fi_base, fi) != 1)
283 panic("fixfiles ht_replace(%s)",
284 fi->fi_base);
285 ofi->fi_flags &= ~FI_SEL;
286 ofi->fi_flags |= FI_HIDDEN;
287 } else {
288 cfgxerror(fi->fi_srcfile, fi->fi_srcline,
289 "object file collision on %s.o, from %s",
290 fi->fi_base, fi->fi_path);
291 cfgxerror(ofi->fi_srcfile, ofi->fi_srcline,
292 "here is the previous file: %s",
293 ofi->fi_path);
294 err = 1;
297 fi->fi_flags |= FI_SEL;
299 return (err);
303 * We have finished reading everything. Tack the objects down: calculate
304 * selection.
306 int
307 fixobjects(void)
309 struct objects *oi;
310 struct nvlist *flathead, **flatp;
311 int err, sel;
313 err = 0;
314 TAILQ_FOREACH(oi, &allobjects, oi_next) {
315 /* Optional: see if it is to be included. */
316 if (oi->oi_optx != NULL) {
317 flathead = NULL;
318 flatp = &flathead;
319 sel = expr_eval(oi->oi_optx,
320 oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
321 fixsel,
322 &flatp);
323 oi->oi_optf = flathead;
324 if (!sel)
325 continue;
328 oi->oi_flags |= OI_SEL;
330 return (err);
334 * We have finished reading everything. Tack the devsws down: calculate
335 * selection.
338 fixdevsw(void)
340 int error;
341 struct devm *dm, *res;
342 struct hashtab *fixdevmtab;
343 char mstr[16];
345 error = 0;
346 fixdevmtab = ht_new();
348 TAILQ_FOREACH(dm, &alldevms, dm_next) {
349 res = ht_lookup(fixdevmtab, intern(dm->dm_name));
350 if (res != NULL) {
351 if (res->dm_cmajor != dm->dm_cmajor ||
352 res->dm_bmajor != dm->dm_bmajor) {
353 cfgxerror(res->dm_srcfile, res->dm_srcline,
354 "device-major '%s' "
355 "block %d, char %d redefined"
356 " at %s:%d as block %d, char %d",
357 res->dm_name,
358 res->dm_bmajor, res->dm_cmajor,
359 dm->dm_srcfile, dm->dm_srcline,
360 dm->dm_bmajor, dm->dm_cmajor);
361 } else {
362 cfgxerror(res->dm_srcfile, res->dm_srcline,
363 "device-major '%s' "
364 "(block %d, char %d) duplicated"
365 " at %s:%d",
366 dm->dm_name, dm->dm_bmajor,
367 dm->dm_cmajor,
368 dm->dm_srcfile, dm->dm_srcline);
370 error = 1;
371 goto out;
373 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
374 panic("fixdevsw: %s char %d block %d",
375 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
378 if (dm->dm_opts != NULL &&
379 !expr_eval(dm->dm_opts, fixsel, NULL))
380 continue;
382 if (dm->dm_cmajor != NODEVMAJOR) {
383 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
384 cfgxerror(dm->dm_srcfile, dm->dm_srcline,
385 "device-major of character device '%s' "
386 "is already defined", dm->dm_name);
387 error = 1;
388 goto out;
390 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
391 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
392 cfgxerror(dm->dm_srcfile, dm->dm_srcline,
393 "device-major of character major '%d' "
394 "is already defined", dm->dm_cmajor);
395 error = 1;
396 goto out;
398 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
399 ht_insert(cdevmtab, intern(mstr), dm)) {
400 panic("fixdevsw: %s character major %d",
401 dm->dm_name, dm->dm_cmajor);
404 if (dm->dm_bmajor != NODEVMAJOR) {
405 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
406 cfgxerror(dm->dm_srcfile, dm->dm_srcline,
407 "device-major of block device '%s' "
408 "is already defined", dm->dm_name);
409 error = 1;
410 goto out;
412 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
413 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
414 cfgxerror(dm->dm_srcfile, dm->dm_srcline,
415 "device-major of block major '%d' "
416 "is already defined", dm->dm_bmajor);
417 error = 1;
418 goto out;
420 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
421 ht_insert(bdevmtab, intern(mstr), dm)) {
422 panic("fixdevsw: %s block major %d",
423 dm->dm_name, dm->dm_bmajor);
428 out:
429 ht_free(fixdevmtab);
430 return (error);
434 * Called when evaluating a needs-count expression. Make sure the
435 * atom is a countable device. The expression succeeds iff there
436 * is at least one of them (note that while `xx*' will not always
437 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The
438 * mkheaders() routine wants a flattened, in-order list of the
439 * atoms for `#define name value' lines, so we build that as we
440 * are called to eval each atom.
442 static int
443 fixcount(const char *name, void *context)
445 struct nvlist ***p = context;
446 struct devbase *dev;
447 struct nvlist *nv;
449 dev = ht_lookup(devbasetab, name);
450 if (dev == NULL) /* cannot occur here; we checked earlier */
451 panic("fixcount(%s)", name);
452 nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
453 **p = nv;
454 *p = &nv->nv_next;
455 (void)ht_insert(needcnttab, name, nv);
456 return (dev->d_umax != 0);
460 * Called from fixfiles when eval'ing a selection expression for a
461 * file that will generate a .h with flags. We will need the flat list.
463 static int
464 fixfsel(const char *name, void *context)
466 struct nvlist ***p = context;
467 struct nvlist *nv;
468 int sel;
470 sel = ht_lookup(selecttab, name) != NULL;
471 nv = newnv(name, NULL, NULL, sel, NULL);
472 **p = nv;
473 *p = &nv->nv_next;
474 return (sel);
478 * As for fixfsel above, but we do not need the flat list.
480 static int
481 /*ARGSUSED*/
482 fixsel(const char *name, void *context)
485 return (ht_lookup(selecttab, name) != NULL);
489 * Eval an expression tree. Calls the given function on each node,
490 * passing it the given context & the name; return value is &/|/! of
491 * results of evaluating atoms.
493 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise
494 * our mixing of C's bitwise & boolean here may give surprises).
497 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
499 int lhs, rhs;
501 switch (expr->nv_num) {
503 case FX_ATOM:
504 return ((*fn)(expr->nv_name, context));
506 case FX_NOT:
507 return (!expr_eval(expr->nv_next, fn, context));
509 case FX_AND:
510 lhs = expr_eval(expr->nv_ptr, fn, context);
511 rhs = expr_eval(expr->nv_next, fn, context);
512 return (lhs & rhs);
514 case FX_OR:
515 lhs = expr_eval(expr->nv_ptr, fn, context);
516 rhs = expr_eval(expr->nv_next, fn, context);
517 return (lhs | rhs);
519 panic("expr_eval %lld", expr->nv_num);
520 /* NOTREACHED */
521 return (0);
525 * Free an expression tree.
527 void
528 expr_free(struct nvlist *expr)
530 struct nvlist *rhs;
532 /* This loop traverses down the RHS of each subexpression. */
533 for (; expr != NULL; expr = rhs) {
534 switch (expr->nv_num) {
536 /* Atoms and !-exprs have no left hand side. */
537 case FX_ATOM:
538 case FX_NOT:
539 break;
541 /* For AND and OR nodes, free the LHS. */
542 case FX_AND:
543 case FX_OR:
544 expr_free(expr->nv_ptr);
545 break;
547 default:
548 panic("expr_free %lld", expr->nv_num);
550 rhs = expr->nv_next;
551 nvfree(expr);
555 #ifdef DEBUG
557 * Print expression tree.
559 void
560 prexpr(struct nvlist *expr)
562 static void pr0();
564 printf("expr =");
565 pr0(expr);
566 printf("\n");
567 (void)fflush(stdout);
570 static void
571 pr0(struct nvlist *e)
574 switch (e->nv_num) {
575 case FX_ATOM:
576 printf(" %s", e->nv_name);
577 return;
578 case FX_NOT:
579 printf(" (!");
580 break;
581 case FX_AND:
582 printf(" (&");
583 break;
584 case FX_OR:
585 printf(" (|");
586 break;
587 default:
588 printf(" (?%lld?", e->nv_num);
589 break;
591 if (e->nv_ptr)
592 pr0(e->nv_ptr);
593 pr0(e->nv_next);
594 printf(")");
596 #endif