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