add BSDI-style expression support to optional file specifiers. Code mostly

taken from the parts of BSDI's 'config' which are freely-distributable
(under the LBL/UC Regents license), and adjusted to fit into our version.
This commit is contained in:
cgd 1996-03-17 13:18:15 +00:00
parent 50b3b61ea3
commit 3ac7667c57
6 changed files with 359 additions and 113 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.h,v 1.22 1996/03/17 11:50:09 cgd Exp $ */
/* $NetBSD: config.h,v 1.23 1996/03/17 13:18:15 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -187,7 +187,16 @@ struct devi {
/*
* Files. Each file is either standard (always included) or optional,
* depending on whether it has names on which to *be* optional.
* depending on whether it has names on which to *be* optional. The
* options field (fi_optx) is actually an expression tree, with nodes
* for OR, AND, and NOT, as well as atoms (words) representing some
* particular option. The node type is stored in the nv_int field.
* Subexpressions appear in the `next' field; for the binary operators
* AND and OR, the left subexpression is first stored in the nv_ptr field.
*
* For any file marked as needs-count or needs-flag, fixfiles() will
* build fi_optf, a `flat list' of the options with nv_int fields that
* contain counts or `need' flags; this is used in mkheaders().
*/
struct files {
struct files *fi_next; /* linked list */
@ -198,9 +207,14 @@ struct files {
const char *fi_path; /* full file path */
const char *fi_tail; /* name, i.e., rindex(fi_path, '/') + 1 */
const char *fi_base; /* tail minus ".c" (or whatever) */
struct nvlist *fi_opt; /* optional on ... */
struct nvlist *fi_optx;/* options expression */
struct nvlist *fi_optf;/* flattened version of above, if needed */
const char *fi_mkrule; /* special make rule, if any */
};
#define FX_ATOM 0 /* atom (in nv_name) */
#define FX_NOT 1 /* NOT expr (subexpression in nv_next) */
#define FX_AND 2 /* AND expr (lhs in nv_ptr, rhs in nv_next) */
#define FX_OR 3 /* OR expr (lhs in nv_ptr, rhs in nv_next) */
/* flags */
#define FI_SEL 0x01 /* selected */

View File

@ -1,4 +1,4 @@
/* $NetBSD: files.c,v 1.5 1996/03/17 06:29:22 cgd Exp $ */
/* $NetBSD: files.c,v 1.6 1996/03/17 13:18:17 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -65,6 +65,14 @@ static struct hashtab *pathtab; /* full path names */
static struct files **nextfile;
static struct files **unchecked;
static int checkaux __P((const char *, void *));
static int fixcount __P((const char *, void *));
static int fixfsel __P((const char *, void *));
static int fixsel __P((const char *, void *));
static int expr_eval __P((struct nvlist *,
int (*)(const char *, void *), void *));
static void expr_free __P((struct nvlist *));
void
initfiles()
{
@ -87,17 +95,17 @@ showprev(pref, fi)
}
void
addfile(path, opts, flags, rule)
addfile(path, optx, flags, rule)
const char *path;
struct nvlist *opts;
struct nvlist *optx;
int flags;
const char *rule;
{
struct files *fi;
const char *base, *dotp, *tail;
const char *dotp, *tail;
size_t baselen;
int needc, needf;
char buf[200];
char base[200];
/* check various errors */
needc = flags & FI_NEEDSCOUNT;
@ -106,15 +114,10 @@ addfile(path, opts, flags, rule)
error("cannot mix needs-count and needs-flag");
goto bad;
}
if (opts == NULL && (needc || needf)) {
if (optx == NULL && (needc || needf)) {
error("nothing to %s for %s", needc ? "count" : "flag", path);
goto bad;
}
if ((fi = ht_lookup(pathtab, path)) != NULL) {
showprev("", fi);
error("file %s listed again", path);
goto bad;
}
/* find last part of pathname, and same without trailing suffix */
tail = rindex(path, '/');
@ -124,57 +127,41 @@ addfile(path, opts, flags, rule)
tail++;
dotp = rindex(tail, '.');
if (dotp == NULL || dotp[1] == 0 ||
(baselen = dotp - tail) >= sizeof(buf)) {
(baselen = dotp - tail) >= sizeof(base)) {
error("invalid pathname `%s'", path);
goto bad;
}
/*
* Make a copy of the path without the .c/.s/whatever suffix.
* This must be unique per "files" file (e.g., a specific
* file can override a standard file, but no standard file
* can override another standard file). This is not perfect
* but should catch any major errors.
*/
bcopy(tail, buf, baselen);
buf[baselen] = 0;
base = intern(buf);
if ((fi = ht_lookup(basetab, base)) != NULL) {
if (fi->fi_srcfile != yyfile) {
showprev("note: ", fi);
error("is overridden by %s", path);
errors--; /* take it away */
fi->fi_flags |= FI_HIDDEN;
} else {
showprev("", fi);
error("collides with %s (both make %s.o)",
path, base);
goto bad;
}
}
/*
* Commit this file to memory.
* Commit this file to memory. We will decide later whether it
* will be used after all.
*/
fi = emalloc(sizeof *fi);
if (ht_insert(pathtab, path, fi)) {
free(fi);
if ((fi = ht_lookup(pathtab, path)) == NULL)
panic("addfile: ht_lookup(%s)", path);
error("duplicate file %s", path);
xerror(fi->fi_srcfile, fi->fi_srcline,
"here is the original definition");
}
memcpy(base, tail, baselen);
base[baselen] = 0;
fi->fi_next = NULL;
fi->fi_srcfile = yyfile;
fi->fi_srcline = currentline();
fi->fi_flags = flags;
fi->fi_lastc = dotp[strlen(dotp) - 1];
fi->fi_path = path;
fi->fi_tail = tail;
fi->fi_base = base;
fi->fi_opt = opts;
fi->fi_base = intern(base);
fi->fi_optx = optx;
fi->fi_optf = NULL;
fi->fi_mkrule = rule;
if (ht_insert(pathtab, path, fi))
panic("addfile: ht_insert(%s)", path);
(void)ht_replace(basetab, base, fi);
*nextfile = fi;
nextfile = &fi->fi_next;
return;
bad:
nvfreel(opts);
expr_free(optx);
}
/*
@ -190,73 +177,265 @@ checkfiles()
register struct nvlist *nv;
last = NULL;
for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) {
if ((fi->fi_flags & FI_NEEDSCOUNT) == 0)
continue;
for (nv = fi->fi_opt; nv != NULL; nv = nv->nv_next)
if (ht_lookup(devbasetab, nv->nv_name) == NULL) {
xerror(fi->fi_srcfile, fi->fi_srcline,
"`%s' is not a countable device",
nv->nv_name);
/* keep fixfiles() from complaining again */
fi->fi_flags |= FI_HIDDEN;
}
}
for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next)
if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
(void)expr_eval(fi->fi_optx, checkaux, fi);
if (last != NULL)
unchecked = &last->fi_next;
}
/*
* Auxiliary function for checkfiles, called from expr_eval.
* We are not actually interested in the expression's value.
*/
static int
checkaux(name, context)
const char *name;
void *context;
{
register struct files *fi = context;
if (ht_lookup(devbasetab, name) == NULL) {
xerror(fi->fi_srcfile, fi->fi_srcline,
"`%s' is not a countable device",
name);
/* keep fixfiles() from complaining again */
fi->fi_flags |= FI_HIDDEN;
}
return (0);
}
/*
* We have finished reading everything. Tack the files down: calculate
* selection and counts as needed.
* selection and counts as needed. Check that the object files built
* from the selected sources do not collide.
*/
int
fixfiles()
{
register struct files *fi;
register struct nvlist *nv;
register struct devbase *dev;
int sel, err;
register struct files *fi, *ofi;
struct nvlist *flathead, **flatp;
int err, sel;
err = 0;
for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
/* Skip files that generated counted-device complaints. */
if (fi->fi_flags & FI_HIDDEN)
continue;
if ((nv = fi->fi_opt) == NULL) { /* standard */
fi->fi_flags |= FI_SEL;
continue;
if (fi->fi_optx != NULL) {
/* Optional: see if it is to be included. */
flathead = NULL;
flatp = &flathead;
sel = expr_eval(fi->fi_optx,
fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
fixsel,
&flatp);
fi->fi_optf = flathead;
if (!sel)
continue;
}
/* figure out whether it is selected */
sel = 0;
if (fi->fi_flags & FI_NEEDSCOUNT) {
/* ... and compute counts too */
do {
dev = ht_lookup(devbasetab, nv->nv_name);
if (dev == NULL) {
xerror(fi->fi_srcfile, fi->fi_srcline,
"`%s' is not a countable device",
nv->nv_name);
err = 1;
} else {
if (dev->d_umax)
sel = 1;
nv->nv_int = dev->d_umax;
(void)ht_insert(needcnttab,
nv->nv_name, nv);
}
} while ((nv = nv->nv_next) != NULL);
} else {
do {
if (ht_lookup(selecttab, nv->nv_name)) {
sel = 1;
if (fi->fi_flags & FI_NEEDSFLAG)
nv->nv_int = 1;
}
} while ((nv = nv->nv_next) != NULL);
/* We like this file. Make sure it generates a unique .o. */
if (ht_insert(basetab, fi->fi_base, fi)) {
if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
panic("fixfiles ht_lookup(%s)", fi->fi_base);
/*
* If the new file comes from a different source,
* allow the new one to override the old one.
*/
if (fi->fi_path != ofi->fi_path) {
if (ht_replace(basetab, fi->fi_base, fi) != 1)
panic("fixfiles ht_replace(%s)",
fi->fi_base);
ofi->fi_flags &= ~FI_SEL;
ofi->fi_flags |= FI_HIDDEN;
} else {
xerror(fi->fi_srcfile, fi->fi_srcline,
"object file collision on %s.o, from %s",
fi->fi_base, fi->fi_path);
xerror(ofi->fi_srcfile, ofi->fi_srcline,
"here is the previous file: %s",
ofi->fi_path);
err = 1;
}
}
/* if selected, we are go */
if (sel)
fi->fi_flags |= FI_SEL;
fi->fi_flags |= FI_SEL;
}
return (err);
}
/*
* Called when evaluating a needs-count expression. Make sure the
* atom is a countable device. The expression succeeds iff there
* is at least one of them (note that while `xx*' will not always
* set xx's d_umax > 0, you cannot mix '*' and needs-count). The
* mkheaders() routine wants a flattened, in-order list of the
* atoms for `#define name value' lines, so we build that as we
* are called to eval each atom.
*/
static int
fixcount(name, context)
register const char *name;
void *context;
{
register struct nvlist ***p = context;
register struct devbase *dev;
register struct nvlist *nv;
dev = ht_lookup(devbasetab, name);
if (dev == NULL) /* cannot occur here; we checked earlier */
panic("fixcount(%s)", name);
nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
**p = nv;
*p = &nv->nv_next;
(void)ht_insert(needcnttab, name, nv);
return (dev->d_umax != 0);
}
/*
* Called from fixfiles when eval'ing a selection expression for a
* file that will generate a .h with flags. We will need the flat list.
*/
static int
fixfsel(name, context)
const char *name;
void *context;
{
register struct nvlist ***p = context;
register struct nvlist *nv;
register int sel;
sel = ht_lookup(selecttab, name) != NULL;
nv = newnv(name, NULL, NULL, sel, NULL);
**p = nv;
*p = &nv->nv_next;
return (sel);
}
/*
* As for fixfsel above, but we do not need the flat list.
*/
static int
fixsel(name, context)
const char *name;
void *context;
{
return (ht_lookup(selecttab, name) != NULL);
}
/*
* Eval an expression tree. Calls the given function on each node,
* passing it the given context & the name; return value is &/|/! of
* results of evaluating atoms.
*
* No short circuiting ever occurs. fn must return 0 or 1 (otherwise
* our mixing of C's bitwise & boolean here may give surprises).
*/
static int
expr_eval(expr, fn, context)
register struct nvlist *expr;
register int (*fn) __P((const char *, void *));
register void *context;
{
int lhs, rhs;
switch (expr->nv_int) {
case FX_ATOM:
return ((*fn)(expr->nv_name, context));
case FX_NOT:
return (!expr_eval(expr->nv_next, fn, context));
case FX_AND:
lhs = expr_eval(expr->nv_ptr, fn, context);
rhs = expr_eval(expr->nv_next, fn, context);
return (lhs & rhs);
case FX_OR:
lhs = expr_eval(expr->nv_ptr, fn, context);
rhs = expr_eval(expr->nv_next, fn, context);
return (lhs | rhs);
}
panic("expr_eval %d", expr->nv_int);
/* NOTREACHED */
}
/*
* Free an expression tree.
*/
static void
expr_free(expr)
register struct nvlist *expr;
{
register struct nvlist *rhs;
/* This loop traverses down the RHS of each subexpression. */
for (; expr != NULL; expr = rhs) {
switch (expr->nv_int) {
/* Atoms and !-exprs have no left hand side. */
case FX_ATOM:
case FX_NOT:
break;
/* For AND and OR nodes, free the LHS. */
case FX_AND:
case FX_OR:
expr_free(expr->nv_ptr);
break;
default:
panic("expr_free %d", expr->nv_int);
}
rhs = expr->nv_next;
nvfree(expr);
}
}
#ifdef DEBUG
/*
* Print expression tree.
*/
void
prexpr(expr)
struct nvlist *expr;
{
static void pr0();
printf("expr =");
pr0(expr);
printf("\n");
(void)fflush(stdout);
}
static void
pr0(e)
register struct nvlist *e;
{
switch (e->nv_int) {
case FX_ATOM:
printf(" %s", e->nv_name);
return;
case FX_NOT:
printf(" (!");
break;
case FX_AND:
printf(" (&");
break;
case FX_OR:
printf(" (|");
break;
default:
printf(" (?%d?", e->nv_int);
break;
}
if (e->nv_ptr)
pr0(e->nv_ptr);
pr0(e->nv_next);
printf(")");
}
#endif

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: gram.y,v 1.6 1996/03/17 11:50:11 cgd Exp $ */
/* $NetBSD: gram.y,v 1.7 1996/03/17 13:18:18 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -79,6 +79,11 @@ static int adepth;
#define new_p(p) new0(NULL, NULL, p, 0, NULL)
#define new_px(p, x) new0(NULL, NULL, p, 0, x)
#define fx_atom(s) new0(s, NULL, NULL, FX_ATOM, NULL)
#define fx_not(e) new0(NULL, NULL, NULL, FX_NOT, e)
#define fx_and(e1, e2) new0(NULL, NULL, e1, FX_AND, e2)
#define fx_or(e1, e2) new0(NULL, NULL, e1, FX_OR, e2)
static void cleanup __P((void));
static void setmachine __P((const char *, const char *));
static void setmaxpartitions __P((int));
@ -100,7 +105,7 @@ static void setmaxpartitions __P((int));
%token <val> FFLAG NUMBER
%token <str> PATHNAME WORD
%type <list> fopts
%type <list> fopts fexpr fatom
%type <val> fflgs
%type <str> rule
%type <attr> attr
@ -167,9 +172,19 @@ file:
/* order of options is important, must use right recursion */
fopts:
WORD fopts = { $$ = new_nx($1, $2); } |
fexpr = { $$ = $1; } |
/* empty */ = { $$ = NULL; };
fexpr:
fatom = { $$ = $1; } |
'!' fatom = { $$ = fx_not($2); } |
fexpr '&' fexpr = { $$ = fx_and($1, $3); } |
fexpr '|' fexpr = { $$ = fx_or($1, $3); } |
'(' fexpr ')' = { $$ = $2; };
fatom:
WORD = { $$ = fx_atom($1); };
fflgs:
fflgs FFLAG = { $$ = $1 | $2; } |
/* empty */ = { $$ = 0; };

View File

@ -1,4 +1,4 @@
/* $NetBSD: hash.c,v 1.2 1996/03/03 17:28:15 thorpej Exp $ */
/* $NetBSD: hash.c,v 1.3 1996/03/17 13:18:20 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -261,6 +261,8 @@ ht_insrep(ht, nam, val, replace)
}
*hpp = hp = newhashent(nam, h);
hp->h_value = val;
if (++ht->ht_used > ht->ht_lim)
ht_expand(ht);
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkheaders.c,v 1.9 1996/03/17 06:29:25 cgd Exp $ */
/* $NetBSD: mkheaders.c,v 1.10 1996/03/17 13:18:21 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -68,7 +68,7 @@ mkheaders()
if (fi->fi_flags & FI_HIDDEN)
continue;
if (fi->fi_flags & (FI_NEEDSCOUNT | FI_NEEDSFLAG) &&
emitcnt(fi->fi_opt))
emitcnt(fi->fi_optf))
return (1);
}
return (0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkmakefile.c,v 1.28 1996/03/17 06:29:30 cgd Exp $ */
/* $NetBSD: mkmakefile.c,v 1.29 1996/03/17 13:18:23 cgd Exp $ */
/*
* Copyright (c) 1992, 1993
@ -52,15 +52,19 @@
#include <string.h>
#include "config.h"
#include "sem.h"
/*
* Make the Makefile.
*/
static const char *srcpath __P((struct files *));
static int emitdefs __P((FILE *));
static int emitfiles __P((FILE *, int));
static int emitobjs __P((FILE *));
static int emitcfiles __P((FILE *));
static int emitsfiles __P((FILE *));
static int emitfiles __P((FILE *, int));
static int emitrules __P((FILE *));
static int emitload __P((FILE *));
@ -141,6 +145,33 @@ bad:
return (1);
}
/*
* Return (possibly in a static buffer) the name of the `source' for a
* file. If we have `options source', or if the file is marked `always
* source', this is always the path from the `file' line; otherwise we
* get the .o from the obj-directory.
*/
static const char *
srcpath(fi)
register struct files *fi;
{
#if 1
/* Always have source, don't support object dirs for kernel builds. */
return (fi->fi_path);
#else
static char buf[MAXPATHLEN];
if (have_source || (fi->fi_flags & FI_ALWAYSSRC) != 0)
return (fi->fi_path);
if (objpath == NULL) {
error("obj-directory not set");
return (NULL);
}
(void)snprintf(buf, sizeof buf, "%s/%s.o", objpath, fi->fi_base);
return (buf);
#endif
}
static int
emitdefs(fp)
register FILE *fp;
@ -224,6 +255,7 @@ emitfiles(fp, suffix)
register struct files *fi;
register struct config *cf;
register int lpos, len, sp;
register const char *fpath;
char swapname[100];
if (fprintf(fp, "%cFILES=", toupper(suffix)) < 0)
@ -233,10 +265,12 @@ emitfiles(fp, suffix)
for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
if ((fi->fi_flags & FI_SEL) == 0)
continue;
len = strlen(fi->fi_path);
if (fi->fi_path[len - 1] != suffix)
if ((fpath = srcpath(fi)) == NULL)
return (1);
len = strlen(fpath);
if (fpath[len - 1] != suffix)
continue;
if (*fi->fi_path != '/')
if (*fpath != '/')
len += 3; /* "$S/" */
if (lpos + len > 72) {
if (fputs(" \\\n", fp) < 0)
@ -244,8 +278,8 @@ emitfiles(fp, suffix)
sp = '\t';
lpos = 7;
}
if (fprintf(fp, "%c%s%s", sp, *fi->fi_path != '/' ? "$S/" : "",
fi->fi_path) < 0)
if (fprintf(fp, "%c%s%s", sp, *fpath != '/' ? "$S/" : "",
fpath) < 0)
return (1);
lpos += len + 1;
sp = ' ';
@ -290,19 +324,21 @@ emitrules(fp)
register FILE *fp;
{
register struct files *fi;
register const char *cp;
register const char *cp, *fpath;
int ch;
char buf[200];
for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
if ((fi->fi_flags & FI_SEL) == 0)
continue;
if ((fpath = srcpath(fi)) == NULL)
return (1);
if (fprintf(fp, "%s.o: %s%s\n", fi->fi_base,
*fi->fi_path != '/' ? "$S/" : "", fi->fi_path) < 0)
*fpath != '/' ? "$S/" : "", fpath) < 0)
return (1);
if ((cp = fi->fi_mkrule) == NULL) {
cp = fi->fi_flags & FI_DRIVER ? "DRIVER" : "NORMAL";
ch = fi->fi_lastc;
ch = fpath[strlen(fpath) - 1];
if (islower(ch))
ch = toupper(ch);
(void)sprintf(buf, "${%s_%c%s}", cp, ch,