Home | History | Annotate | Line # | Download | only in config
files.c revision 1.33
      1  1.18  uebayasi /*	$NetBSD: files.c,v 1.33 2015/09/04 10:16:35 uebayasi 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.17  christos #include <sys/cdefs.h>
     48  1.17  christos __RCSID("$NetBSD: files.c,v 1.33 2015/09/04 10:16:35 uebayasi Exp $");
     49  1.17  christos 
     50   1.1   thorpej #include <sys/param.h>
     51   1.1   thorpej #include <errno.h>
     52   1.1   thorpej #include <stdio.h>
     53   1.1   thorpej #include <stdlib.h>
     54   1.1   thorpej #include <string.h>
     55   1.3  christos #include <util.h>
     56   1.1   thorpej #include "defs.h"
     57   1.1   thorpej 
     58   1.1   thorpej extern const char *yyfile;
     59   1.1   thorpej 
     60  1.33  uebayasi int nallfiles;
     61  1.33  uebayasi size_t nselfiles;
     62  1.33  uebayasi struct files **selfiles;
     63  1.33  uebayasi 
     64   1.1   thorpej /*
     65   1.1   thorpej  * We check that each full path name is unique.  File base names
     66   1.1   thorpej  * should generally also be unique, e.g., having both a net/xx.c and
     67   1.1   thorpej  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
     68   1.1   thorpej  * wrong, but is permitted under some conditions.
     69   1.1   thorpej  */
     70   1.1   thorpej static struct hashtab *basetab;		/* file base names */
     71   1.1   thorpej static struct hashtab *pathtab;		/* full path names */
     72   1.1   thorpej 
     73   1.1   thorpej static struct files **unchecked;
     74   1.1   thorpej 
     75  1.14  uebayasi static void	addfiletoattr(const char *, struct files *);
     76   1.1   thorpej static int	checkaux(const char *, void *);
     77   1.1   thorpej static int	fixcount(const char *, void *);
     78   1.1   thorpej static int	fixfsel(const char *, void *);
     79   1.1   thorpej static int	fixsel(const char *, void *);
     80   1.1   thorpej 
     81   1.1   thorpej void
     82   1.1   thorpej initfiles(void)
     83   1.1   thorpej {
     84   1.1   thorpej 
     85   1.1   thorpej 	basetab = ht_new();
     86   1.1   thorpej 	pathtab = ht_new();
     87   1.1   thorpej 	TAILQ_INIT(&allfiles);
     88  1.22  uebayasi 	TAILQ_INIT(&allcfiles);
     89  1.22  uebayasi 	TAILQ_INIT(&allsfiles);
     90  1.22  uebayasi 	TAILQ_INIT(&allofiles);
     91   1.1   thorpej 	unchecked = &TAILQ_FIRST(&allfiles);
     92   1.1   thorpej }
     93   1.1   thorpej 
     94   1.1   thorpej void
     95  1.21  uebayasi addfile(const char *path, struct condexpr *optx, u_char flags, const char *rule)
     96   1.1   thorpej {
     97   1.1   thorpej 	struct files *fi;
     98   1.1   thorpej 	const char *dotp, *tail;
     99   1.1   thorpej 	size_t baselen;
    100  1.24  uebayasi 	size_t dirlen;
    101   1.1   thorpej 	int needc, needf;
    102   1.1   thorpej 	char base[200];
    103  1.24  uebayasi 	char dir[MAXPATHLEN];
    104   1.1   thorpej 
    105   1.1   thorpej 	/* check various errors */
    106   1.1   thorpej 	needc = flags & FI_NEEDSCOUNT;
    107   1.1   thorpej 	needf = flags & FI_NEEDSFLAG;
    108   1.1   thorpej 	if (needc && needf) {
    109   1.6  christos 		cfgerror("cannot mix needs-count and needs-flag");
    110   1.1   thorpej 		goto bad;
    111   1.1   thorpej 	}
    112   1.1   thorpej 	if (optx == NULL && (needc || needf)) {
    113   1.6  christos 		cfgerror("nothing to %s for %s", needc ? "count" : "flag",
    114   1.6  christos 		    path);
    115   1.1   thorpej 		goto bad;
    116   1.1   thorpej 	}
    117  1.19  uebayasi 	if (*path == '/') {
    118  1.19  uebayasi 		cfgerror("path must be relative");
    119  1.19  uebayasi 		goto bad;
    120  1.19  uebayasi 	}
    121   1.1   thorpej 
    122   1.1   thorpej 	/* find last part of pathname, and same without trailing suffix */
    123   1.1   thorpej 	tail = strrchr(path, '/');
    124  1.24  uebayasi 	if (tail == NULL) {
    125  1.24  uebayasi 		dirlen = 0;
    126   1.1   thorpej 		tail = path;
    127  1.24  uebayasi 	} else {
    128  1.24  uebayasi 		dirlen = (size_t)(tail - path);
    129   1.1   thorpej 		tail++;
    130  1.24  uebayasi 	}
    131  1.24  uebayasi 	memcpy(dir, path, dirlen);
    132  1.24  uebayasi 	dir[dirlen] = '\0';
    133  1.24  uebayasi 
    134   1.1   thorpej 	dotp = strrchr(tail, '.');
    135   1.1   thorpej 	if (dotp == NULL || dotp[1] == 0 ||
    136  1.17  christos 	    (baselen = (size_t)(dotp - tail)) >= sizeof(base)) {
    137   1.6  christos 		cfgerror("invalid pathname `%s'", path);
    138   1.1   thorpej 		goto bad;
    139   1.1   thorpej 	}
    140   1.1   thorpej 
    141   1.1   thorpej 	/*
    142   1.1   thorpej 	 * Commit this file to memory.  We will decide later whether it
    143   1.1   thorpej 	 * will be used after all.
    144   1.1   thorpej 	 */
    145   1.1   thorpej 	fi = ecalloc(1, sizeof *fi);
    146   1.1   thorpej 	if (ht_insert(pathtab, path, fi)) {
    147   1.1   thorpej 		free(fi);
    148   1.1   thorpej 		if ((fi = ht_lookup(pathtab, path)) == NULL)
    149   1.1   thorpej 			panic("addfile: ht_lookup(%s)", path);
    150  1.21  uebayasi 
    151  1.21  uebayasi 		/*
    152  1.21  uebayasi 		 * If it's a duplicate entry, it is must specify a make
    153  1.21  uebayasi 		 * rule, and only a make rule, and must come from
    154  1.21  uebayasi 		 * a different source file than the original entry.
    155  1.21  uebayasi 		 * If it does otherwise, it is disallowed.  This allows
    156  1.21  uebayasi 		 * machine-dependent files to override the compilation
    157  1.21  uebayasi 		 * options for specific files.
    158  1.21  uebayasi 		 */
    159  1.21  uebayasi 		if (rule != NULL && optx == NULL && flags == 0 &&
    160  1.21  uebayasi 		    yyfile != fi->fi_srcfile) {
    161  1.21  uebayasi 			fi->fi_mkrule = rule;
    162  1.21  uebayasi 			return;
    163  1.21  uebayasi 		}
    164   1.6  christos 		cfgerror("duplicate file %s", path);
    165   1.6  christos 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    166   1.1   thorpej 		    "here is the original definition");
    167   1.1   thorpej 		goto bad;
    168   1.1   thorpej 	}
    169   1.1   thorpej 	memcpy(base, tail, baselen);
    170  1.24  uebayasi 	base[baselen] = '\0';
    171   1.1   thorpej 	fi->fi_srcfile = yyfile;
    172   1.1   thorpej 	fi->fi_srcline = currentline();
    173   1.1   thorpej 	fi->fi_flags = flags;
    174   1.1   thorpej 	fi->fi_path = path;
    175   1.1   thorpej 	fi->fi_tail = tail;
    176   1.1   thorpej 	fi->fi_base = intern(base);
    177  1.24  uebayasi 	fi->fi_dir = intern(dir);
    178   1.1   thorpej 	fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
    179   1.1   thorpej 			SLIST_FIRST(&prefixes)->pf_prefix;
    180  1.25  uebayasi 	fi->fi_buildprefix = SLIST_EMPTY(&buildprefixes) ? NULL :
    181  1.25  uebayasi 			SLIST_FIRST(&buildprefixes)->pf_prefix;
    182  1.18  uebayasi 	fi->fi_len = strlen(path);
    183  1.18  uebayasi 	fi->fi_suffix = path[fi->fi_len - 1];
    184   1.1   thorpej 	fi->fi_optx = optx;
    185   1.1   thorpej 	fi->fi_optf = NULL;
    186  1.21  uebayasi 	fi->fi_mkrule = rule;
    187  1.14  uebayasi 	fi->fi_attr = NULL;
    188  1.33  uebayasi 	fi->fi_order = (int)nallfiles + (includedepth << 16);
    189  1.22  uebayasi 	switch (fi->fi_suffix) {
    190  1.22  uebayasi 	case 'c':
    191  1.22  uebayasi 		TAILQ_INSERT_TAIL(&allcfiles, fi, fi_snext);
    192  1.22  uebayasi 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
    193  1.22  uebayasi 		break;
    194  1.22  uebayasi 	case 'S':
    195  1.23  uebayasi 		fi->fi_suffix = 's';
    196  1.23  uebayasi 		/* FALLTHRU */
    197  1.22  uebayasi 	case 's':
    198  1.22  uebayasi 		TAILQ_INSERT_TAIL(&allsfiles, fi, fi_snext);
    199  1.22  uebayasi 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
    200  1.22  uebayasi 		break;
    201  1.22  uebayasi 	case 'o':
    202  1.22  uebayasi 		TAILQ_INSERT_TAIL(&allofiles, fi, fi_snext);
    203  1.30  uebayasi 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
    204  1.23  uebayasi 		break;
    205  1.23  uebayasi 	default:
    206  1.23  uebayasi 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    207  1.23  uebayasi 		    "unknown suffix");
    208  1.22  uebayasi 		break;
    209  1.22  uebayasi 	}
    210  1.33  uebayasi 	CFGDBG(3, "file added `%s' at order score %d", fi->fi_path, fi->fi_order);
    211  1.33  uebayasi 	nallfiles++;
    212   1.1   thorpej 	return;
    213   1.1   thorpej  bad:
    214  1.12  dholland 	if (optx != NULL) {
    215  1.12  dholland 		condexpr_destroy(optx);
    216  1.12  dholland 	}
    217   1.1   thorpej }
    218   1.1   thorpej 
    219  1.14  uebayasi static void
    220  1.14  uebayasi addfiletoattr(const char *name, struct files *fi)
    221  1.14  uebayasi {
    222  1.14  uebayasi 	struct attr *a;
    223  1.14  uebayasi 
    224  1.14  uebayasi 	a = ht_lookup(attrtab, name);
    225  1.15  uebayasi 	if (a == NULL) {
    226  1.15  uebayasi 		CFGDBG(1, "attr `%s' not found", name);
    227  1.15  uebayasi 	} else {
    228  1.15  uebayasi 		fi->fi_attr = a;
    229  1.14  uebayasi 		TAILQ_INSERT_TAIL(&a->a_files, fi, fi_anext);
    230  1.14  uebayasi 	}
    231  1.14  uebayasi }
    232  1.14  uebayasi 
    233   1.1   thorpej /*
    234   1.1   thorpej  * We have finished reading some "files" file, either ../../conf/files
    235   1.1   thorpej  * or ./files.$machine.  Make sure that everything that is flagged as
    236   1.1   thorpej  * needing a count is reasonable.  (This prevents ../../conf/files from
    237   1.1   thorpej  * depending on some machine-specific device.)
    238   1.1   thorpej  */
    239   1.1   thorpej void
    240   1.1   thorpej checkfiles(void)
    241   1.1   thorpej {
    242   1.1   thorpej 	struct files *fi, *last;
    243   1.1   thorpej 
    244   1.1   thorpej 	last = NULL;
    245   1.1   thorpej 	for (fi = *unchecked; fi != NULL;
    246   1.1   thorpej 	    last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
    247   1.1   thorpej 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
    248   1.1   thorpej 			(void)expr_eval(fi->fi_optx, checkaux, fi);
    249   1.1   thorpej 	}
    250   1.1   thorpej 	if (last != NULL)
    251   1.1   thorpej 		unchecked = &TAILQ_NEXT(last, fi_next);
    252   1.1   thorpej }
    253   1.1   thorpej 
    254   1.1   thorpej /*
    255   1.1   thorpej  * Auxiliary function for checkfiles, called from expr_eval.
    256   1.1   thorpej  * We are not actually interested in the expression's value.
    257   1.1   thorpej  */
    258   1.1   thorpej static int
    259   1.1   thorpej checkaux(const char *name, void *context)
    260   1.1   thorpej {
    261   1.1   thorpej 	struct files *fi = context;
    262   1.1   thorpej 
    263   1.1   thorpej 	if (ht_lookup(devbasetab, name) == NULL) {
    264   1.6  christos 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    265   1.1   thorpej 		    "`%s' is not a countable device",
    266   1.1   thorpej 		    name);
    267   1.1   thorpej 		/* keep fixfiles() from complaining again */
    268   1.1   thorpej 		fi->fi_flags |= FI_HIDDEN;
    269   1.1   thorpej 	}
    270   1.1   thorpej 	return (0);
    271   1.1   thorpej }
    272   1.1   thorpej 
    273  1.33  uebayasi static int
    274  1.33  uebayasi cmpfiles(const void *a, const void *b)
    275  1.33  uebayasi {
    276  1.33  uebayasi 	const struct files * const *fia = a, * const *fib = b;
    277  1.33  uebayasi 	int sa = (*fia)->fi_order;
    278  1.33  uebayasi 	int sb = (*fib)->fi_order;
    279  1.33  uebayasi 
    280  1.33  uebayasi 	if (sa < sb)
    281  1.33  uebayasi 		return -1;
    282  1.33  uebayasi 	else if (sa > sb)
    283  1.33  uebayasi 		return 1;
    284  1.33  uebayasi 	else
    285  1.33  uebayasi 		return 0;
    286  1.33  uebayasi }
    287  1.33  uebayasi 
    288   1.1   thorpej /*
    289   1.1   thorpej  * We have finished reading everything.  Tack the files down: calculate
    290   1.1   thorpej  * selection and counts as needed.  Check that the object files built
    291   1.1   thorpej  * from the selected sources do not collide.
    292   1.1   thorpej  */
    293   1.1   thorpej int
    294   1.1   thorpej fixfiles(void)
    295   1.1   thorpej {
    296   1.1   thorpej 	struct files *fi, *ofi;
    297   1.1   thorpej 	struct nvlist *flathead, **flatp;
    298   1.1   thorpej 	int err, sel;
    299  1.31  uebayasi 	struct config *cf;
    300  1.31  uebayasi  	char swapname[100];
    301   1.1   thorpej 
    302  1.33  uebayasi 	/* Place these files at last. */
    303  1.33  uebayasi 	int onallfiles = nallfiles;
    304  1.33  uebayasi 	nallfiles = 1 << 30;
    305  1.29  uebayasi 	addfile("devsw.c", NULL, 0, NULL);
    306  1.29  uebayasi 	addfile("ioconf.c", NULL, 0, NULL);
    307  1.29  uebayasi 
    308  1.31  uebayasi 	TAILQ_FOREACH(cf, &allcf, cf_next) {
    309  1.31  uebayasi  		(void)snprintf(swapname, sizeof(swapname), "swap%s.c",
    310  1.31  uebayasi  		    cf->cf_name);
    311  1.31  uebayasi  		addfile(intern(swapname), NULL, 0, NULL);
    312  1.31  uebayasi  	}
    313  1.33  uebayasi 	nallfiles = onallfiles;
    314  1.26  uebayasi 
    315   1.1   thorpej 	err = 0;
    316   1.1   thorpej 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    317   1.2       erh 
    318   1.1   thorpej 		/* Skip files that generated counted-device complaints. */
    319   1.1   thorpej 		if (fi->fi_flags & FI_HIDDEN)
    320   1.1   thorpej 			continue;
    321   1.1   thorpej 
    322  1.16  uebayasi 		if (fi->fi_optx != NULL) {
    323  1.14  uebayasi 			if (fi->fi_optx->cx_type == CX_ATOM) {
    324  1.14  uebayasi 				addfiletoattr(fi->fi_optx->cx_u.atom, fi);
    325  1.14  uebayasi 			}
    326   1.1   thorpej 			flathead = NULL;
    327   1.1   thorpej 			flatp = &flathead;
    328   1.1   thorpej 			sel = expr_eval(fi->fi_optx,
    329   1.1   thorpej 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
    330   1.1   thorpej 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
    331   1.1   thorpej 			    fixsel,
    332   1.1   thorpej 			    &flatp);
    333   1.1   thorpej 			fi->fi_optf = flathead;
    334   1.1   thorpej 			if (!sel)
    335   1.1   thorpej 				continue;
    336   1.1   thorpej 		}
    337   1.1   thorpej 
    338   1.1   thorpej 		/* We like this file.  Make sure it generates a unique .o. */
    339   1.1   thorpej 		if (ht_insert(basetab, fi->fi_base, fi)) {
    340   1.1   thorpej 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
    341   1.1   thorpej 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
    342   1.1   thorpej 			/*
    343   1.1   thorpej 			 * If the new file comes from a different source,
    344   1.1   thorpej 			 * allow the new one to override the old one.
    345   1.1   thorpej 			 */
    346   1.1   thorpej 			if (fi->fi_path != ofi->fi_path) {
    347   1.1   thorpej 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
    348   1.1   thorpej 					panic("fixfiles ht_replace(%s)",
    349   1.1   thorpej 					    fi->fi_base);
    350  1.17  christos 				ofi->fi_flags &= (u_char)~FI_SEL;
    351   1.1   thorpej 				ofi->fi_flags |= FI_HIDDEN;
    352   1.1   thorpej 			} else {
    353   1.6  christos 				cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    354   1.1   thorpej 				    "object file collision on %s.o, from %s",
    355   1.1   thorpej 				    fi->fi_base, fi->fi_path);
    356   1.6  christos 				cfgxerror(ofi->fi_srcfile, ofi->fi_srcline,
    357   1.1   thorpej 				    "here is the previous file: %s",
    358   1.1   thorpej 				    ofi->fi_path);
    359   1.1   thorpej 				err = 1;
    360   1.1   thorpej 			}
    361   1.1   thorpej 		}
    362   1.1   thorpej 		fi->fi_flags |= FI_SEL;
    363  1.33  uebayasi 		nselfiles++;
    364  1.15  uebayasi 		CFGDBG(3, "file selected `%s'", fi->fi_path);
    365  1.15  uebayasi 
    366  1.15  uebayasi 		/* Add other files to the default "netbsd" attribute. */
    367  1.15  uebayasi 		if (fi->fi_attr == NULL) {
    368  1.15  uebayasi 			addfiletoattr(allattr.a_name, fi);
    369  1.15  uebayasi 		}
    370  1.15  uebayasi 		CFGDBG(3, "file `%s' belongs to attr `%s'", fi->fi_path,
    371  1.15  uebayasi 		    fi->fi_attr->a_name);
    372   1.1   thorpej 	}
    373  1.33  uebayasi 
    374  1.33  uebayasi 	/* Order files. */
    375  1.33  uebayasi 	selfiles = malloc(nselfiles * sizeof(fi));
    376  1.33  uebayasi 	int i = 0;
    377  1.33  uebayasi 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    378  1.33  uebayasi 		if ((fi->fi_flags & FI_SEL) == 0)
    379  1.33  uebayasi 			continue;
    380  1.33  uebayasi 		selfiles[i++] = fi;
    381  1.33  uebayasi 	}
    382  1.33  uebayasi 	qsort(selfiles, nselfiles, (unsigned)sizeof(fi), cmpfiles);
    383   1.1   thorpej 	return (err);
    384   1.1   thorpej }
    385   1.1   thorpej 
    386   1.1   thorpej 
    387   1.1   thorpej /*
    388   1.1   thorpej  * We have finished reading everything.  Tack the devsws down: calculate
    389   1.1   thorpej  * selection.
    390   1.1   thorpej  */
    391   1.1   thorpej int
    392   1.1   thorpej fixdevsw(void)
    393   1.1   thorpej {
    394   1.5       alc 	int error;
    395   1.1   thorpej 	struct devm *dm, *res;
    396   1.1   thorpej 	struct hashtab *fixdevmtab;
    397   1.1   thorpej 	char mstr[16];
    398   1.1   thorpej 
    399   1.5       alc 	error = 0;
    400   1.1   thorpej 	fixdevmtab = ht_new();
    401   1.1   thorpej 
    402   1.1   thorpej 	TAILQ_FOREACH(dm, &alldevms, dm_next) {
    403   1.1   thorpej 		res = ht_lookup(fixdevmtab, intern(dm->dm_name));
    404   1.1   thorpej 		if (res != NULL) {
    405   1.1   thorpej 			if (res->dm_cmajor != dm->dm_cmajor ||
    406   1.1   thorpej 			    res->dm_bmajor != dm->dm_bmajor) {
    407   1.6  christos 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    408   1.7       dsl 					"device-major '%s' "
    409   1.7       dsl 					"block %d, char %d redefined"
    410   1.7       dsl 					" at %s:%d as block %d, char %d",
    411   1.7       dsl 					res->dm_name,
    412   1.7       dsl 					res->dm_bmajor, res->dm_cmajor,
    413   1.7       dsl 					dm->dm_srcfile, dm->dm_srcline,
    414   1.7       dsl 					dm->dm_bmajor, dm->dm_cmajor);
    415   1.1   thorpej 			} else {
    416   1.7       dsl 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    417   1.7       dsl 					"device-major '%s' "
    418   1.7       dsl 					"(block %d, char %d) duplicated"
    419   1.7       dsl 					" at %s:%d",
    420   1.7       dsl 					dm->dm_name, dm->dm_bmajor,
    421   1.7       dsl 					dm->dm_cmajor,
    422   1.7       dsl 					dm->dm_srcfile, dm->dm_srcline);
    423   1.1   thorpej 			}
    424   1.7       dsl 			error = 1;
    425   1.7       dsl 			goto out;
    426   1.1   thorpej 		}
    427   1.1   thorpej 		if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
    428   1.1   thorpej 			panic("fixdevsw: %s char %d block %d",
    429   1.1   thorpej 			      dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
    430   1.1   thorpej 		}
    431   1.1   thorpej 
    432   1.1   thorpej 		if (dm->dm_opts != NULL &&
    433   1.1   thorpej 		    !expr_eval(dm->dm_opts, fixsel, NULL))
    434   1.1   thorpej 			continue;
    435   1.1   thorpej 
    436   1.9  drochner 		if (dm->dm_cmajor != NODEVMAJOR) {
    437   1.1   thorpej 			if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
    438   1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    439   1.1   thorpej 				       "device-major of character device '%s' "
    440   1.1   thorpej 				       "is already defined", dm->dm_name);
    441   1.5       alc 				error = 1;
    442   1.4  christos 				goto out;
    443   1.1   thorpej 			}
    444   1.1   thorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
    445   1.1   thorpej 			if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
    446   1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    447   1.1   thorpej 				       "device-major of character major '%d' "
    448   1.1   thorpej 				       "is already defined", dm->dm_cmajor);
    449   1.5       alc 				error = 1;
    450   1.4  christos 				goto out;
    451   1.1   thorpej 			}
    452   1.1   thorpej 			if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
    453   1.1   thorpej 			    ht_insert(cdevmtab, intern(mstr), dm)) {
    454   1.1   thorpej 				panic("fixdevsw: %s character major %d",
    455   1.1   thorpej 				      dm->dm_name, dm->dm_cmajor);
    456   1.1   thorpej 			}
    457   1.1   thorpej 		}
    458   1.9  drochner 		if (dm->dm_bmajor != NODEVMAJOR) {
    459   1.1   thorpej 			if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
    460   1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    461   1.1   thorpej 				       "device-major of block device '%s' "
    462   1.1   thorpej 				       "is already defined", dm->dm_name);
    463   1.5       alc 				error = 1;
    464   1.4  christos 				goto out;
    465   1.1   thorpej 			}
    466   1.1   thorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
    467   1.1   thorpej 			if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
    468   1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    469   1.1   thorpej 				       "device-major of block major '%d' "
    470   1.1   thorpej 				       "is already defined", dm->dm_bmajor);
    471   1.5       alc 				error = 1;
    472   1.4  christos 				goto out;
    473   1.1   thorpej 			}
    474   1.1   thorpej 			if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
    475   1.1   thorpej 			    ht_insert(bdevmtab, intern(mstr), dm)) {
    476   1.1   thorpej 				panic("fixdevsw: %s block major %d",
    477   1.1   thorpej 				      dm->dm_name, dm->dm_bmajor);
    478   1.1   thorpej 			}
    479   1.1   thorpej 		}
    480   1.1   thorpej 	}
    481   1.1   thorpej 
    482   1.4  christos out:
    483   1.4  christos 	ht_free(fixdevmtab);
    484   1.5       alc 	return (error);
    485   1.1   thorpej }
    486   1.1   thorpej 
    487   1.1   thorpej /*
    488   1.1   thorpej  * Called when evaluating a needs-count expression.  Make sure the
    489   1.1   thorpej  * atom is a countable device.  The expression succeeds iff there
    490   1.1   thorpej  * is at least one of them (note that while `xx*' will not always
    491   1.1   thorpej  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
    492   1.1   thorpej  * mkheaders() routine wants a flattened, in-order list of the
    493   1.1   thorpej  * atoms for `#define name value' lines, so we build that as we
    494   1.1   thorpej  * are called to eval each atom.
    495   1.1   thorpej  */
    496   1.1   thorpej static int
    497   1.1   thorpej fixcount(const char *name, void *context)
    498   1.1   thorpej {
    499   1.1   thorpej 	struct nvlist ***p = context;
    500   1.1   thorpej 	struct devbase *dev;
    501   1.1   thorpej 	struct nvlist *nv;
    502   1.1   thorpej 
    503   1.1   thorpej 	dev = ht_lookup(devbasetab, name);
    504   1.1   thorpej 	if (dev == NULL)	/* cannot occur here; we checked earlier */
    505   1.1   thorpej 		panic("fixcount(%s)", name);
    506   1.1   thorpej 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
    507   1.1   thorpej 	**p = nv;
    508   1.1   thorpej 	*p = &nv->nv_next;
    509   1.1   thorpej 	(void)ht_insert(needcnttab, name, nv);
    510   1.1   thorpej 	return (dev->d_umax != 0);
    511   1.1   thorpej }
    512   1.1   thorpej 
    513   1.1   thorpej /*
    514   1.1   thorpej  * Called from fixfiles when eval'ing a selection expression for a
    515   1.1   thorpej  * file that will generate a .h with flags.  We will need the flat list.
    516   1.1   thorpej  */
    517   1.1   thorpej static int
    518   1.1   thorpej fixfsel(const char *name, void *context)
    519   1.1   thorpej {
    520   1.1   thorpej 	struct nvlist ***p = context;
    521   1.1   thorpej 	struct nvlist *nv;
    522   1.1   thorpej 	int sel;
    523   1.1   thorpej 
    524   1.1   thorpej 	sel = ht_lookup(selecttab, name) != NULL;
    525   1.1   thorpej 	nv = newnv(name, NULL, NULL, sel, NULL);
    526   1.1   thorpej 	**p = nv;
    527   1.1   thorpej 	*p = &nv->nv_next;
    528   1.1   thorpej 	return (sel);
    529   1.1   thorpej }
    530   1.1   thorpej 
    531   1.1   thorpej /*
    532   1.1   thorpej  * As for fixfsel above, but we do not need the flat list.
    533   1.1   thorpej  */
    534   1.1   thorpej static int
    535   1.6  christos /*ARGSUSED*/
    536   1.1   thorpej fixsel(const char *name, void *context)
    537   1.1   thorpej {
    538   1.1   thorpej 
    539   1.1   thorpej 	return (ht_lookup(selecttab, name) != NULL);
    540   1.1   thorpej }
    541   1.1   thorpej 
    542   1.1   thorpej /*
    543   1.1   thorpej  * Eval an expression tree.  Calls the given function on each node,
    544   1.1   thorpej  * passing it the given context & the name; return value is &/|/! of
    545   1.1   thorpej  * results of evaluating atoms.
    546   1.1   thorpej  *
    547   1.1   thorpej  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
    548   1.1   thorpej  * our mixing of C's bitwise & boolean here may give surprises).
    549   1.1   thorpej  */
    550  1.10      cube int
    551  1.11  dholland expr_eval(struct condexpr *expr, int (*fn)(const char *, void *), void *ctx)
    552   1.1   thorpej {
    553   1.1   thorpej 	int lhs, rhs;
    554   1.1   thorpej 
    555  1.11  dholland 	switch (expr->cx_type) {
    556   1.1   thorpej 
    557  1.11  dholland 	case CX_ATOM:
    558  1.11  dholland 		return ((*fn)(expr->cx_atom, ctx));
    559   1.1   thorpej 
    560  1.11  dholland 	case CX_NOT:
    561  1.11  dholland 		return (!expr_eval(expr->cx_not, fn, ctx));
    562   1.1   thorpej 
    563  1.11  dholland 	case CX_AND:
    564  1.11  dholland 		lhs = expr_eval(expr->cx_and.left, fn, ctx);
    565  1.11  dholland 		rhs = expr_eval(expr->cx_and.right, fn, ctx);
    566   1.1   thorpej 		return (lhs & rhs);
    567   1.1   thorpej 
    568  1.11  dholland 	case CX_OR:
    569  1.11  dholland 		lhs = expr_eval(expr->cx_or.left, fn, ctx);
    570  1.11  dholland 		rhs = expr_eval(expr->cx_or.right, fn, ctx);
    571   1.1   thorpej 		return (lhs | rhs);
    572   1.1   thorpej 	}
    573  1.11  dholland 	panic("invalid condexpr type %d", (int)expr->cx_type);
    574   1.1   thorpej 	/* NOTREACHED */
    575   1.1   thorpej 	return (0);
    576   1.1   thorpej }
    577   1.1   thorpej 
    578   1.1   thorpej #ifdef DEBUG
    579   1.1   thorpej /*
    580   1.1   thorpej  * Print expression tree.
    581   1.1   thorpej  */
    582   1.1   thorpej void
    583   1.1   thorpej prexpr(struct nvlist *expr)
    584   1.1   thorpej {
    585   1.1   thorpej 	static void pr0();
    586   1.1   thorpej 
    587   1.1   thorpej 	printf("expr =");
    588   1.1   thorpej 	pr0(expr);
    589   1.1   thorpej 	printf("\n");
    590   1.1   thorpej 	(void)fflush(stdout);
    591   1.1   thorpej }
    592   1.1   thorpej 
    593   1.1   thorpej static void
    594   1.1   thorpej pr0(struct nvlist *e)
    595   1.1   thorpej {
    596   1.1   thorpej 
    597   1.8  christos 	switch (e->nv_num) {
    598   1.1   thorpej 	case FX_ATOM:
    599   1.1   thorpej 		printf(" %s", e->nv_name);
    600   1.1   thorpej 		return;
    601   1.1   thorpej 	case FX_NOT:
    602   1.1   thorpej 		printf(" (!");
    603   1.1   thorpej 		break;
    604   1.1   thorpej 	case FX_AND:
    605   1.1   thorpej 		printf(" (&");
    606   1.1   thorpej 		break;
    607   1.1   thorpej 	case FX_OR:
    608   1.1   thorpej 		printf(" (|");
    609   1.1   thorpej 		break;
    610   1.1   thorpej 	default:
    611   1.8  christos 		printf(" (?%lld?", e->nv_num);
    612   1.1   thorpej 		break;
    613   1.1   thorpej 	}
    614   1.1   thorpej 	if (e->nv_ptr)
    615   1.1   thorpej 		pr0(e->nv_ptr);
    616   1.1   thorpej 	pr0(e->nv_next);
    617   1.1   thorpej 	printf(")");
    618   1.1   thorpej }
    619   1.1   thorpej #endif
    620