diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2007-07-08 17:44:21 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2007-07-08 17:44:21 +0000 |
commit | 0954e637714e88074c69e5eafeecf23182248072 (patch) | |
tree | 7bb2e4b16053abb4bf196a6035263dc864d6b5ae | |
parent | e5364898169009014fea0c6cc8b2502881f83ffb (diff) |
A set of big related changes. okay millert@, tested further by kettenis@
and matthieu@
This all revolves around putting ALL global variables into one single big
hash, and using flags. This removes some impossible to understand stuff,
like old varfind, and allows for some nice stuff.
- each time we reference a global variable, we create it, possibly as a dummy
variable.
- each time we go to the environment, we remember it, thus we no longer go
back to it.
Lists of dependant changes:
- isolate changes to oldVars and checkEnvFirst.
- remove VAR_CMD and VAR_GLOBAL contexts. The only distinction is in parsevar.
Split Parse_DoVar into Parse_DoVar and Parse_CmdlineVar
- rework var modules around obtain_global_var, observe flags in various
functions like Var_Value and Var_Seti.
- Var_Seti/Var_Appendi are almost the same code, use that internally.
- add magic to handle the very special SHELL variable.
- introduce Var_Definedi for the cases where we don't want the actual
value, to simplify tests.
- add keyword .poison, parse it and set global flags accordingly.
- do poison_checks where needed.
- document poison.
- in for loops, set variable temporarily, so that Var_SubstVar will also
substitute it in varmodifiers expressions.
-rw-r--r-- | usr.bin/make/Makefile | 5 | ||||
-rw-r--r-- | usr.bin/make/cond.c | 13 | ||||
-rw-r--r-- | usr.bin/make/cond.h | 3 | ||||
-rw-r--r-- | usr.bin/make/cond_int.h | 3 | ||||
-rw-r--r-- | usr.bin/make/defines.h | 5 | ||||
-rw-r--r-- | usr.bin/make/generate.c | 3 | ||||
-rw-r--r-- | usr.bin/make/main.c | 10 | ||||
-rw-r--r-- | usr.bin/make/make.1 | 25 | ||||
-rw-r--r-- | usr.bin/make/parse.c | 70 | ||||
-rw-r--r-- | usr.bin/make/parsevar.c | 32 | ||||
-rw-r--r-- | usr.bin/make/parsevar.h | 12 | ||||
-rw-r--r-- | usr.bin/make/var.c | 578 | ||||
-rw-r--r-- | usr.bin/make/var.h | 26 |
13 files changed, 444 insertions, 341 deletions
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile index 6fd4594126f..d120e49dac7 100644 --- a/usr.bin/make/Makefile +++ b/usr.bin/make/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.40 2007/03/18 15:37:06 mickey Exp $ +# $OpenBSD: Makefile,v 1.41 2007/07/08 17:44:20 espie Exp $ PROG= make CFLAGS+= -I${.OBJDIR} -I${.CURDIR} @@ -6,6 +6,7 @@ HOSTCFLAGS+= -I${.OBJDIR} -I${.CURDIR} CDIAGFLAGS=-Wall -W -Wno-char-subscripts -Wstrict-prototypes -pedantic \ -Wmissing-prototypes +DESTDIR= CDEFS+=-DUSE_TIMESPEC CDEFS+=-DHAS_BOOL_H CDEFS+=-DHAS_PATHS_H @@ -24,6 +25,8 @@ SRCS+= lstAddNew.c lstAppend.c lstConcat.c lstConcatDestroy.c \ lstInsert.c lstMember.c lstRemove.c lstReplace.c lstSucc.c .PATH: ${.CURDIR}/lst.lib +a: + echo "Bindir is ${BINDIR}" CLEANFILES+=generate hashconsts.h generate.o regress.o check diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c index 3b85ca213f5..450fc024d26 100644 --- a/usr.bin/make/cond.c +++ b/usr.bin/make/cond.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: cond.c,v 1.33 2007/03/20 03:50:39 tedu Exp $ */ +/* $OpenBSD: cond.c,v 1.34 2007/07/08 17:44:20 espie Exp $ */ /* $NetBSD: cond.c,v 1.7 1996/11/06 17:59:02 christos Exp $ */ /* @@ -247,10 +247,7 @@ CondGetArg(const char **linePtr, struct Name *arg, const char *func, static bool CondDoDefined(struct Name *arg) { - if (Var_Valuei(arg->s, arg->e) != NULL) - return true; - else - return false; + return Var_Definedi(arg->s, arg->e); } /*- @@ -1026,6 +1023,12 @@ Cond_Eval(const char *line) return COND_ISUNDEF; else return COND_INVALID; + case K_COND_POISON % MAGICSLOTS2: + if (k == K_COND_POISON && len == strlen(COND_POISON) && + strncmp(line, COND_POISON, len) == 0) + return COND_ISPOISON; + else + return COND_INVALID; case K_COND_INCLUDE % MAGICSLOTS2: if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) && strncmp(line, COND_INCLUDE, len) == 0) diff --git a/usr.bin/make/cond.h b/usr.bin/make/cond.h index 8369b35462e..a9655240834 100644 --- a/usr.bin/make/cond.h +++ b/usr.bin/make/cond.h @@ -1,7 +1,7 @@ #ifndef COND_H #define COND_H /* $OpenPackages$ */ -/* $OpenBSD: cond.h,v 1.2 2002/06/11 21:12:11 espie Exp $ */ +/* $OpenBSD: cond.h,v 1.3 2007/07/08 17:44:20 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -39,6 +39,7 @@ #define COND_ISFOR 3 #define COND_ISUNDEF 4 #define COND_ISINCLUDE 5 +#define COND_ISPOISON 6 /* whattodo = Cond_Eval(line); * Parses a conditional expression (without the leading dot), diff --git a/usr.bin/make/cond_int.h b/usr.bin/make/cond_int.h index 146b0aff558..da762932eb9 100644 --- a/usr.bin/make/cond_int.h +++ b/usr.bin/make/cond_int.h @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: cond_int.h,v 1.3 2002/06/11 21:12:11 espie Exp $ */ +/* $OpenBSD: cond_int.h,v 1.4 2007/07/08 17:44:20 espie Exp $ */ /* List of all keywords recognized by the make parser */ #define COND_IF "if" @@ -18,3 +18,4 @@ #define COND_ENDFOR "endfor" #define COND_INCLUDE "include" #define COND_UNDEF "undef" +#define COND_POISON "poison" diff --git a/usr.bin/make/defines.h b/usr.bin/make/defines.h index 11961a94c77..2a926e71236 100644 --- a/usr.bin/make/defines.h +++ b/usr.bin/make/defines.h @@ -2,7 +2,7 @@ #define DEFINES_H /* $OpenPackages$ */ -/* $OpenBSD: defines.h,v 1.2 2002/02/19 19:39:38 millert Exp $ */ +/* $OpenBSD: defines.h,v 1.3 2007/07/08 17:44:20 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -47,9 +47,6 @@ typedef struct List_ *Lst; struct SymTable_; typedef struct SymTable_ SymTable; -struct ohash; -typedef struct ohash GSymT; - struct Buffer_; typedef struct Buffer_ *Buffer; diff --git a/usr.bin/make/generate.c b/usr.bin/make/generate.c index 4ff6f29fda7..e713533513b 100644 --- a/usr.bin/make/generate.c +++ b/usr.bin/make/generate.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: generate.c,v 1.6 2006/01/20 23:10:19 espie Exp $ */ +/* $OpenBSD: generate.c,v 1.7 2007/07/08 17:44:20 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -80,6 +80,7 @@ char *table_cond[] = { M(COND_ENDFOR), M(COND_INCLUDE), M(COND_UNDEF), + M(COND_POISON), NULL }; diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index 9ebdd519013..a5cf3b0fcbd 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: main.c,v 1.69 2006/09/26 18:20:50 mk Exp $ */ +/* $OpenBSD: main.c,v 1.70 2007/07/08 17:44:20 espie Exp $ */ /* $NetBSD: main.c,v 1.34 1997/03/24 20:56:36 gwr Exp $ */ /* @@ -99,8 +99,6 @@ bool touchFlag; /* -t flag */ bool usePipes; /* !-P flag */ bool ignoreErrors; /* -i flag */ bool beSilent; /* -s flag */ -bool oldVars; /* variable substitution style */ -bool checkEnvFirst; /* -e flag */ static void MainParseArgs(int, char **); static char * chdir_verify_path(const char *); @@ -140,7 +138,7 @@ posixParseOptLetter(int c) keepgoing = false; break; case 'e': - checkEnvFirst = true; + Var_setCheckEnvFirst(true); break; case 'i': ignoreErrors = true; @@ -300,7 +298,7 @@ MainParseArgs(int argc, char **argv) case -1: /* Check for variable assignments and targets. */ if (argv[optind] != NULL && - !Parse_DoVar(argv[optind], VAR_CMD)) { + !Parse_CmdlineVar(argv[optind])) { if (!*argv[optind]) Punt("illegal (null) argument."); Lst_AtEnd(create, estrdup(argv[optind])); @@ -318,8 +316,6 @@ MainParseArgs(int argc, char **argv) */ if (!compatMake && !forceJobs) compatMake = true; - - oldVars = true; } /*- diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1 index fa6301e3a68..8458c14adf7 100644 --- a/usr.bin/make/make.1 +++ b/usr.bin/make/make.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: make.1,v 1.68 2007/05/31 19:20:13 jmc Exp $ +.\" $OpenBSD: make.1,v 1.69 2007/07/08 17:44:20 espie Exp $ .\" $OpenPackages$ .\" $NetBSD: make.1,v 1.18 1997/03/10 21:19:53 christos Exp $ .\" @@ -31,7 +31,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: July 8 2007 $ .Dt MAKE 1 .Os .Sh NAME @@ -843,6 +843,27 @@ The possible conditionals are as follows: .It Ic .undef Ar variable Un-define the specified global variable. Only global variables may be un-defined. +.It Ic .poison Ar variable +Poison the specified global variable. +Any further reference to +.Ar variable +will be flagged as an error. +.It Xo +.Ic \&.poison \&!defined +.Po Ar variable +.Pc +.Xc +It is an error to try to use the value of +.Ar variable +in a context where it is not defined. +.It Xo +.Ic \&.poison empty +.Po Ar variable +.Pc +.Xc +It is an error to try to use the value of +.Ar variable +in a context where it is not defined or empty. .It Xo .Ic \&.if .Oo \&! Oc Ns Ar expression diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index 8f2a5bfdaa2..26e9b5f5ad2 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: parse.c,v 1.71 2007/03/20 03:50:39 tedu Exp $ */ +/* $OpenBSD: parse.c,v 1.72 2007/07/08 17:44:20 espie Exp $ */ /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* @@ -213,6 +213,7 @@ static void ParseDoDependency(char *); static void ParseAddCmd(void *, void *); static void ParseHasCommands(void *); static void ParseDoInclude(char *); +static void ParseDoPoison(char *); static void ParseTraditionalInclude(char *); static void ParseConditionalInclude(char *); static void ParseLookupIncludeFile(char *, char *, bool, bool); @@ -1337,6 +1338,68 @@ ParseLookupIncludeFile(char *spec, char *endSpec, bool isSystem, } +static void +ParseDoPoison(char *line) +{ + char *p = line; + int type = POISON_NORMAL; + bool not = false; + bool paren_to_match = false; + char *name, *ename; + + while (isspace(*p)) + p++; + if (*p == '!') { + not = true; + p++; + } + while (isspace(*p)) + p++; + if (strncmp(p, "defined", 7) == 0) { + type = POISON_DEFINED; + p += 7; + } else if (strncmp(p, "empty", 5) == 0) { + type = POISON_EMPTY; + p += 5; + } + while (isspace(*p)) + p++; + if (*p == '(') { + paren_to_match = true; + p++; + } + while (isspace(*p)) + p++; + name = ename = p; + while (*p != '\0' && !isspace(*p)) { + if (*p == ')' && paren_to_match) { + paren_to_match = false; + p++; + break; + } + p++; + ename = p; + } + while (isspace(*p)) + p++; + switch(type) { + case POISON_NORMAL: + case POISON_EMPTY: + if (not) + type = POISON_INVALID; + break; + case POISON_DEFINED: + if (not) + type = POISON_NOT_DEFINED; + else + type = POISON_INVALID; + break; + } + if ((*p != '\0' && *p != '#') || type == POISON_INVALID) + Parse_Error(PARSE_FATAL, "Invalid syntax for .poison: %s", + line); + Var_MarkPoisoned(name, ename, type); +} /* Strip comments from the line. May return either a copy of the line, or @@ -1421,6 +1484,9 @@ ParseIsCond(Buffer linebuf, Buffer copy, char *line) case COND_ISINCLUDE: ParseDoInclude(line + 7); return true; + case COND_ISPOISON: + ParseDoPoison(line + 6); + return true; case COND_ISUNDEF: { char *cp; @@ -1520,7 +1586,7 @@ Parse_File( if (inDependency) ParseFinishDependency(); - if (Parse_DoVar(stripped, VAR_GLOBAL)) + if (Parse_DoVar(stripped)) inDependency = false; else { size_t pos; diff --git a/usr.bin/make/parsevar.c b/usr.bin/make/parsevar.c index 659c290ec5f..282e6ea3753 100644 --- a/usr.bin/make/parsevar.c +++ b/usr.bin/make/parsevar.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: parsevar.c,v 1.2 2004/04/07 13:11:36 espie Exp $ */ +/* $OpenBSD: parsevar.c,v 1.3 2007/07/08 17:44:20 espie Exp $ */ /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* @@ -41,6 +41,7 @@ static const char *find_op1(const char *); static const char *find_op2(const char *); +static bool parse_variable_assignment(const char *, int); static const char * find_op1(const char *p) @@ -68,9 +69,9 @@ find_op2(const char *p) return p; } -bool -Parse_DoVar(const char *line, - GSymT *ctxt) /* Context in which to do the assignment */ +static bool +parse_variable_assignment(const char *line, + int ctxt) /* Context in which to do the assignment */ { const char *arg; char *res1 = NULL, *res2 = NULL; @@ -82,7 +83,7 @@ Parse_DoVar(const char *line, int type; /* Type of assignment */ struct Name name; - arg = VarName_Get(line, &name, (SymTable *)ctxt, true, + arg = VarName_Get(line, &name, NULL, true, FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2); while (isspace(*arg)) @@ -147,7 +148,7 @@ Parse_DoVar(const char *line, while (isspace(*arg)) arg++; /* If the variable already has a value, we don't do anything. */ - if ((type & VAR_OPT) && Var_Valuei(name.s, name.e) != NULL) { + if ((type & VAR_OPT) && Var_Definedi(name.s, name.e)) { VarName_Free(&name); return true; } @@ -188,7 +189,7 @@ Parse_DoVar(const char *line, if (Var_Valuei(name.s, name.e) == NULL) Var_Seti(name.s, name.e, "", ctxt); - res2 = Var_Subst(arg, (SymTable *)ctxt, false); + res2 = Var_Subst(arg, NULL, false); oldVars = oldOldVars; arg = res2; @@ -205,3 +206,20 @@ Parse_DoVar(const char *line, return true; } +bool +Parse_DoVar(const char *line) +{ + return parse_variable_assignment(line, VAR_GLOBAL); +} + +bool +Parse_CmdlineVar(const char *line) +{ + bool result; + + oldVars = false; + result = parse_variable_assignment(line, VAR_CMD); + oldVars = true; + return result; +} + diff --git a/usr.bin/make/parsevar.h b/usr.bin/make/parsevar.h index 95df3ff2d30..75a06b15101 100644 --- a/usr.bin/make/parsevar.h +++ b/usr.bin/make/parsevar.h @@ -1,7 +1,7 @@ #ifndef PARSEVAR_H #define PARSEVAR_H /* $OpenPackages$ */ -/* $OpenBSD: parsevar.h,v 1.1 2001/05/23 12:34:48 espie Exp $ */ +/* $OpenBSD: parsevar.h,v 1.2 2007/07/08 17:44:20 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. * @@ -31,9 +31,13 @@ * Functions to parse variable assignments */ -/* wasvar = Parse_DoVar(str, ctxt); - * Parses variable assignment str and adds it to context ctxt. +/* wasvar = Parse_DoVar(str); + * Parses variable assignment str. * Returns false if this is something else. */ -extern bool Parse_DoVar(const char *, GSymT *); +extern bool Parse_DoVar(const char *); +/* wasvar = Parse_CmdlineVar(str, ctxt); + * Parses variable assignment str, given on the command line. + * Returns false if this is something else. */ +extern bool Parse_CmdlineVar(const char *); #endif diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index 607486e6f77..d24513782fb 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -1,9 +1,9 @@ /* $OpenPackages$ */ -/* $OpenBSD: var.c,v 1.61 2007/01/02 13:21:31 espie Exp $ */ +/* $OpenBSD: var.c,v 1.62 2007/07/08 17:44:20 espie Exp $ */ /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* - * Copyright (c) 1999,2000 Marc Espie. + * Copyright (c) 1999,2000,2007 Marc Espie. * * Extensive code modifications for the OpenBSD project. * @@ -74,6 +74,7 @@ #include "buf.h" #include "stats.h" #include "ohash.h" +#include "pathnames.h" #include "varmodifiers.h" #include "var.h" #include "varname.h" @@ -110,6 +111,15 @@ char var_Error[] = ""; * identical string instances... */ static char varNoError[] = ""; +bool oldVars; /* variable substitution style */ +static bool checkEnvFirst; /* true if environment should be searched for + * variables before the global context */ + +void +Var_setCheckEnvFirst(bool yes) +{ + checkEnvFirst = yes; +} /* * Variable values are obtained from four different contexts: @@ -128,11 +138,8 @@ static char varNoError[] = ""; * The four contexts are searched in the reverse order from which they are * listed. */ -GSymT *VAR_GLOBAL; /* variables from the makefile */ -GSymT *VAR_CMD; /* variables defined on the command-line */ - -static SymTable *CTXT_GLOBAL, *CTXT_CMD; +static struct ohash global_variables; static char *varnames[] = { TARGET, @@ -153,17 +160,17 @@ static char *varnames[] = { }; -#define FIND_MINE 0x1 /* look in CTXT_CMD and CTXT_GLOBAL */ -#define FIND_ENV 0x2 /* look in the environment */ - typedef struct Var_ { BUFFER val; /* its value */ unsigned int flags; /* miscellaneous status flags */ -#define VAR_IN_USE 1 /* Variable's value currently being used. - * Used to avoid recursion */ -#define VAR_READ_ONLY 2 /* Environment variable not modifiable */ -#define VAR_FROM_ENV 4 /* Var was read from env */ -#define VAR_DUMMY 8 /* Var does not exist, actually */ +#define VAR_IN_USE 1 /* Variable's value currently being used. */ + /* Used to avoid recursion */ +#define VAR_DUMMY 2 /* Placeholder: already looked up */ +#define VAR_FROM_CMD 4 /* From the command line */ +#define VAR_FROM_ENV 8 /* Read from environment */ +#define VAR_SEEN_ENV 16 /* Already seen environment */ +#define VAR_SHELL 32 /* magic, see posix */ +#define POISONS (POISON_NORMAL | POISON_EMPTY | POISON_NOT_DEFINED) char name[1]; /* the variable's name */ } Var; @@ -173,18 +180,21 @@ static struct ohash_info var_info = { NULL, hash_alloc, hash_free, element_alloc }; static int quick_lookup(const char *, const char **, uint32_t *); #define VarValue(v) Buf_Retrieve(&((v)->val)) -static Var *varfind(const char *, const char *, SymTable *, int, int, uint32_t); -static Var *VarFindi(const char *, const char *, SymTable *, int); -static Var *VarAdd(const char *, const char *, uint32_t, const char *, GSymT *); +static Var *varfind(const char *, const char *, SymTable *, int, uint32_t); +static Var *find_global_var(const char *, const char *, uint32_t); static void VarDelete(Var *); static void VarPrintVar(Var *); -static const char *context_name(GSymT *); -static Var *new_var(const char *, const char *, const char *); -static Var *getvar(GSymT *, const char *, const char *, uint32_t); + +static Var *obtain_global_var(const char *, const char *, uint32_t); +static void fill_from_env(Var *); static Var *create_var(const char *, const char *); -static Var *var_from_env(const char *, const char *, uint32_t); +static void varq_set_append(int, const char *, GNode *, bool); static void var_init_string(Var *, const char *); - +static void var_set_string(Var *, const char *); +static void var_append_string(Var *, const char *); +static void var_set_append(const char *, const char *, const char *, int, bool); +static void set_magic_shell_variable(void); +static void poison_check(Var *); static const char *find_0(const char *); static const char *find_rparen(const char *); static const char *find_ket(const char *); @@ -324,42 +334,43 @@ quick_lookup(const char *name, const char **enamePtr, uint32_t *pk) return -1; } -void -Varq_Set(int idx, const char *val, GNode *gn) +static void +varq_set_append(int idx, const char *val, GNode *gn, bool append) { - /* We only look for a variable in the given context since anything set - * here will override anything in a lower context, so there's not much - * point in searching them all just to save a bit of memory... */ Var *v = gn->context.locals[idx]; if (v == NULL) { - v = new_var(varnames[idx], NULL, val); + v = create_var(varnames[idx], NULL); +#ifdef STATS_VAR_LOOKUP + STAT_VAR_CREATION++; +#endif + if (val != NULL) + var_init_string(v, val); + else + Buf_Init(&(v->val), 1); v->flags = 0; gn->context.locals[idx] = v; } else { - Buf_Reset(&(v->val)); + if (append) + Buf_AddSpace(&(v->val)); + else + Buf_Reset(&(v->val)); Buf_AddString(&(v->val), val); - } if (DEBUG(VAR)) - printf("%s:%s = %s\n", gn->name, varnames[idx], val); + printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v)); } void -Varq_Append(int idx, const char *val, GNode *gn) +Varq_Set(int idx, const char *val, GNode *gn) { - Var *v = gn->context.locals[idx]; + varq_set_append(idx, val, gn, false); +} - if (v == NULL) { - v = new_var(varnames[idx], NULL, val); - v->flags = 0; - gn->context.locals[idx] = v; - } else { - Buf_AddSpace(&(v->val)); - Buf_AddString(&(v->val), val); - } - if (DEBUG(VAR)) - printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v)); +void +Varq_Append(int idx, const char *val, GNode *gn) +{ + varq_set_append(idx, val, gn, true); } char * @@ -373,21 +384,6 @@ Varq_Value(int idx, GNode *gn) return VarValue(v); } -static const char * -context_name(GSymT *ctxt) -{ - if (ctxt == VAR_GLOBAL) - return "Global"; - if (ctxt == VAR_CMD) - return "Command"; - return "Error"; -} - -/* We separate var creation proper from setting of initial value: - * VAR_DUMMY corresponds to `lazy' setup, e.g., always create global - * variable at first lookup, and then fill it up when value is wanted. - * This avoids looking through the environment several times. - */ static Var * create_var(const char *name, const char *ename) { @@ -405,180 +401,114 @@ var_init_string(Var *v, const char *val) Buf_AddChars(&(v->val), len, val); } -static Var * -new_var(const char *name, const char *ename, const char *val) +static void +var_set_string(Var *v, const char *val) { - Var *v; - - v = create_var(name, ename); -#ifdef STATS_VAR_LOOKUP - STAT_VAR_CREATION++; -#endif - if (val != NULL) - var_init_string(v, val); - else - Buf_Init(&(v->val), 1); + if ((v->flags & VAR_DUMMY) == 0) { + Buf_Reset(&(v->val)); + Buf_AddString(&(v->val), val); + } else { + var_init_string(v, val); + v->flags &= ~VAR_DUMMY; + } +} - return v; +static void +var_append_string(Var *v, const char *val) +{ + if ((v->flags & VAR_DUMMY) == 0) { + Buf_AddSpace(&(v->val)); + Buf_AddString(&(v->val), val); + } else { + var_init_string(v, val); + v->flags &= ~VAR_DUMMY; + } } -static Var * -var_from_env(const char *name, const char *ename, uint32_t k) +static void +fill_from_env(Var *v) { char *env; - Var *v; - /* getenv requires a null-terminated name, so we create the var - * structure first. */ - v = create_var(name, ename); env = getenv(v->name); if (env == NULL) - v->flags = VAR_DUMMY; + v->flags |= VAR_SEEN_ENV; else { - var_init_string(v, env); - if (checkEnvFirst) - v->flags = VAR_READ_ONLY | VAR_FROM_ENV; - else - v->flags = VAR_FROM_ENV; + var_set_string(v, env); + v->flags |= VAR_FROM_ENV | VAR_SEEN_ENV; } #ifdef STATS_VAR_LOOKUP STAT_VAR_FROM_ENV++; #endif - - ohash_insert(VAR_GLOBAL, ohash_lookup_interval(VAR_GLOBAL, name, ename, k), v); - return v; } static Var * -getvar(GSymT *ctxt, const char *name, const char *ename, uint32_t k) +obtain_global_var(const char *name, const char *ename, uint32_t k) { - return ohash_find(ctxt, ohash_lookup_interval(ctxt, name, ename, k)); + unsigned int slot; + Var *v; + + slot = ohash_lookup_interval(&global_variables, name, ename, k); + v = ohash_find(&global_variables, slot); + if (v == NULL) { + v = create_var(name, ename); + v->flags = VAR_DUMMY; + ohash_insert(&global_variables, slot, v); + } + return v; +} + +static void +poison_check(Var *v) +{ + if (v->flags & POISON_NORMAL) { + Parse_Error(PARSE_FATAL, + "Poisoned variable %s has been referenced\n", v->name); + return; + } + if (v->flags & VAR_DUMMY) { + Parse_Error(PARSE_FATAL, + "Poisoned variable %s is not defined\n", v->name); + return; + } + if (v->flags & POISON_EMPTY) + if (strcmp(VarValue(v), "") == 0) + Parse_Error(PARSE_FATAL, + "Poisoned variable %s is empty\n", v->name); } -/*- - *----------------------------------------------------------------------- - * VarFindi -- - * Find the given variable in the given context and any other contexts - * indicated. if end is NULL, name is a string, otherwise, only - * the interval name - end is concerned. - * - * Results: - * A pointer to the structure describing the desired variable or - * NULL if the variable does not exist. - *----------------------------------------------------------------------- - */ static Var * -VarFindi(const char *name, /* name to find */ - const char *ename, /* end of name */ - SymTable *ctxt, /* context in which to find it */ - int flags) /* FIND_MINE set means to look in the - * CTXT_GLOBAL and CTXT_CMD contexts also. - * FIND_ENV set means to look in the - * environment */ +find_global_var(const char *name, const char *ename, uint32_t k) { - uint32_t k; - int idx; + Var *v; -#ifdef STATS_VAR_LOOKUP - STAT_VAR_FIND++; -#endif + v = obtain_global_var(name, ename, k); + + if ((v->flags & VAR_SEEN_ENV) == 0 && + (checkEnvFirst && (v->flags & VAR_FROM_CMD) == 0 || + (v->flags & VAR_DUMMY) != 0)) + fill_from_env(v); - idx = quick_lookup(name, &ename, &k); - return varfind(name, ename, ctxt, flags, idx, k); + return v; } static Var * -varfind(const char *name, const char *ename, SymTable *ctxt, int flags, +varfind(const char *name, const char *ename, SymTable *ctxt, int idx, uint32_t k) { - Var *v; - /* Handle local variables first */ if (idx != -1) { - if (ctxt != NULL && ctxt != CTXT_CMD && ctxt != CTXT_GLOBAL) { + if (ctxt != NULL) { if (idx < LOCAL_SIZE) return ctxt->locals[idx]; else return ctxt->locals[EXTENDED2SIMPLE(idx)]; } else - return NULL; + return NULL; + } else { + return find_global_var(name, ename, k); } - /* First look for the variable in the given context. If it's not there, - look for it in CTXT_CMD, CTXT_GLOBAL and the environment, - depending on the FIND_* flags in 'flags' */ - if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL) - v = getvar((GSymT *)ctxt, name, ename, k); - else - v = NULL; - - if (v == NULL) - switch (flags) { - case 0: - break; - case FIND_MINE: - if (ctxt != CTXT_CMD) - v = getvar(VAR_CMD, name, ename, k); - if (v == NULL && ctxt != CTXT_GLOBAL) - v = getvar(VAR_GLOBAL, name, ename, k); - break; - case FIND_ENV: - v = var_from_env(name, ename, k); - break; - case FIND_ENV | FIND_MINE: - if (ctxt != CTXT_CMD) - v = getvar(VAR_CMD, name, ename, k); - if (v == NULL) { - if (ctxt != CTXT_GLOBAL) - v = getvar(VAR_GLOBAL, name, ename, k); - if (v == NULL) - v = var_from_env(name, ename, k); - else if (checkEnvFirst && (v->flags & VAR_FROM_ENV) == 0) { - char *env; - - env = getenv(v->name); - if (env != NULL) { - Buf_Reset(&(v->val)); - Buf_AddString(&(v->val), env); - } - /* XXX even if no such env variable, fake it, to avoid - * further lookup */ - v->flags |= VAR_FROM_ENV; - } - } - break; - } - return v; -} - -/*- - *----------------------------------------------------------------------- - * VarAdd -- - * Add a new variable of name name and value val to the given context - * - * Results: - * The added variable. - * - * Side Effects: - * The new variable is placed in the given context. - * The name and val arguments are duplicated so they may - * safely be freed. - *----------------------------------------------------------------------- - */ -static Var * -VarAdd(const char *name, const char *ename, uint32_t k, const char *val, - GSymT *ctxt) -{ - Var *v; - - v = new_var(name, ename, val); - - v->flags = 0; - - ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, ename, k), v); - if (DEBUG(VAR)) - printf("%s:%s = %s\n", context_name(ctxt), v->name, val); - return v; } /*- @@ -600,112 +530,152 @@ VarDelete(Var *v) void Var_Delete(const char *name) { - Var *v; - uint32_t k; - unsigned int slot; - const char *ename = NULL; - int idx; - - - if (DEBUG(VAR)) - printf("delete %s\n", name); - - idx = quick_lookup(name, &ename, &k); - if (idx != -1) - Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable"); - slot = ohash_lookup_interval(VAR_GLOBAL, name, ename, k); - v = ohash_find(VAR_GLOBAL, slot); - if (v != NULL && (v->flags & VAR_READ_ONLY) == 0) { - ohash_remove(VAR_GLOBAL, slot); + Var *v; + uint32_t k; + unsigned int slot; + const char *ename = NULL; + int idx; + + + if (DEBUG(VAR)) + printf("delete %s\n", name); + + idx = quick_lookup(name, &ename, &k); + if (idx != -1) + Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable"); + slot = ohash_lookup_interval(&global_variables, name, ename, k); + v = ohash_find(&global_variables, slot); + + if (v == NULL) + return; + if (checkEnvFirst && (v->flags & VAR_FROM_ENV)) + return; + + if (v->flags & VAR_FROM_CMD) + return; + + ohash_remove(&global_variables, slot); VarDelete(v); - } } -/* The variable is searched for only in its context before being - * created in that context. I.e. if the context is CTXT_GLOBAL, - * only CTXT_GLOBAL is searched. Likewise if it is CTXT_CMD, only - * CTXT_CMD is searched. - */ -void -Var_Seti(const char *name, const char *ename, const char *val, GSymT *ctxt) +static void +var_set_append(const char *name, const char *ename, const char *val, int ctxt, + bool append) { - Var *v; - uint32_t k; - int idx; - - idx = quick_lookup(name, &ename, &k); - if (idx != -1) - Parse_Error(PARSE_FATAL, "Trying to set dynamic variable $%s", - varnames[idx]); - - /* We only look for a variable in the given context since anything set - * here will override anything in a lower context, so there's not much - * point in searching them all just to save a bit of memory... */ - v = varfind(name, ename, (SymTable *)ctxt, 0, idx, k); - if (v == NULL) - v = VarAdd(name, ename, k, val, ctxt); - else { - if ((v->flags & VAR_READ_ONLY) == 0) { - if ((v->flags & VAR_DUMMY) == 0) { - Buf_Reset(&(v->val)); - Buf_AddString(&(v->val), val); - } else { - var_init_string(v, val); - v->flags &= ~VAR_DUMMY; - } + Var *v; + uint32_t k; + int idx; + idx = quick_lookup(name, &ename, &k); + if (idx != -1) { + Parse_Error(PARSE_FATAL, "Trying to %s dynamic variable $%s", + append ? "append to" : "set", varnames[idx]); + return; } - } - if (DEBUG(VAR)) - printf("%s:%s = %s\n", context_name(ctxt), v->name, val); - /* Any variables given on the command line are automatically exported - * to the environment (as per POSIX standard). */ - if (ctxt == VAR_CMD) - esetenv(v->name, val); + + v = find_global_var(name, ename, k); + if (v->flags & POISON_NORMAL) + Parse_Error(PARSE_FATAL, "Trying to %s poisoned variable %s\n", + append ? "append to" : "set", v->name); + /* so can we write to it ? */ + if (ctxt == VAR_CMD) { /* always for command line */ + (append ? var_append_string : var_set_string)(v, val); + v->flags |= VAR_FROM_CMD; + if ((v->flags & VAR_SHELL) == 0) { + /* Any variables given on the command line are + * automatically exported to the environment, + * except for SHELL (as per POSIX standard). + */ + esetenv(v->name, val); + } + if (DEBUG(VAR)) + printf("command:%s = %s\n", v->name, VarValue(v)); + } else if ((v->flags & VAR_FROM_CMD) == 0 && + (!checkEnvFirst || (v->flags & VAR_FROM_ENV) == 0)) { + (append ? var_append_string : var_set_string)(v, val); + if (DEBUG(VAR)) + printf("global:%s = %s\n", v->name, VarValue(v)); + } else if (DEBUG(VAR)) + printf("overriden:%s = %s\n", v->name, VarValue(v)); } void -Var_Appendi(const char *name, const char *ename, const char *val, GSymT *ctxt) +Var_Seti(const char *name, const char *ename, const char *val, int ctxt) { - Var *v; - uint32_t k; - int idx; - - assert(ctxt == VAR_GLOBAL || ctxt == VAR_CMD); + var_set_append(name, ename, val, ctxt, false); +} - idx = quick_lookup(name, &ename, &k); - if (idx != -1) - Parse_Error(PARSE_FATAL, "Trying to append to dynamic variable $%s", - varnames[idx]); +void +Var_Appendi(const char *name, const char *ename, const char *val, int ctxt) +{ + var_set_append(name, ename, val, ctxt, true); +} - v = varfind(name, ename, (SymTable *)ctxt, FIND_ENV, idx, k); +void +Var_MarkPoisoned(const char *name, const char *ename, unsigned int type) +{ + Var *v; + uint32_t k; + int idx; + idx = quick_lookup(name, &ename, &k); - if ((v->flags & VAR_READ_ONLY) == 0) { - if ((v->flags & VAR_DUMMY) == 0) { - Buf_AddSpace(&(v->val)); - Buf_AddString(&(v->val), val); - } else { - var_init_string(v, val); - v->flags &= ~VAR_DUMMY; + if (idx != -1) { + Parse_Error(PARSE_FATAL, + "Trying to poison dynamic variable $%s", + varnames[idx]); + return; } - } - if (DEBUG(VAR)) - printf("%s:%s = %s\n", context_name(ctxt), v->name, VarValue(v)); + v = find_global_var(name, ename, k); + v->flags |= type; + if (v->flags & POISON_NORMAL) { + if (v->flags & VAR_DUMMY) + return; + if (v->flags & VAR_FROM_ENV) + return; + Parse_Error(PARSE_FATAL, + "Poisoned variable %s is already set\n", v->name); + } } char * Var_Valuei(const char *name, const char *ename) { - Var *v; + Var *v; + uint32_t k; + int idx; + + idx = quick_lookup(name, &ename, &k); + if (idx == -1) { + v = find_global_var(name, ename, k); + if (v->flags & POISONS) + poison_check(v); + if ((v->flags & VAR_DUMMY) == 0) + return VarValue(v); + } - v = VarFindi(name, ename, NULL, FIND_ENV | FIND_MINE); - if (v != NULL && (v->flags & VAR_DUMMY) == 0) - return VarValue(v); - else return NULL; } +bool +Var_Definedi(const char *name, const char *ename) +{ + Var *v; + uint32_t k; + int idx; + + idx = quick_lookup(name, &ename, &k); + if (idx == -1) { + v = find_global_var(name, ename, k); + if (v->flags & POISON_NORMAL) + poison_check(v); + if ((v->flags & VAR_DUMMY) == 0) + return true; + } + + return false; +} + static const char * find_0(const char *p) { @@ -850,7 +820,9 @@ Var_Parse(const char *str, /* The string to parse */ } idx = quick_lookup(name.s, &name.e, &k); - v = varfind(name.s, name.e, ctxt, FIND_ENV | FIND_MINE, idx, k); + v = varfind(name.s, name.e, ctxt, idx, k); + if (v->flags & POISONS) + poison_check(v); if (v != NULL && (v->flags & VAR_DUMMY) == 0) { if (v->flags & VAR_IN_USE) Fatal("Variable %s is recursive.", v->name); @@ -888,7 +860,7 @@ Var_Parse(const char *str, /* The string to parse */ /* Dynamic source */ if (idx != -1) { /* can't be expanded for now: copy the var spec instead. */ - if (ctxt == NULL || ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD) { + if (ctxt == NULL) { *freePtr = true; val = Str_dupi(start, start+ *lengthPtr); } else { @@ -1072,6 +1044,22 @@ Var_SubstVar(Buffer buf, /* To store result */ } } +static void +set_magic_shell_variable() +{ + const char *name = "SHELL"; + const char *ename = NULL; + uint32_t k; + Var *v; + k = ohash_interval(name, &ename); + v = create_var(name, ename); + ohash_insert(&global_variables, + ohash_lookup_interval(&global_variables, name, ename, k), v); + /* the environment shall not affect it */ + v->flags = VAR_SHELL | VAR_SEEN_ENV; + var_init_string(v, _PATH_BSHELL); +} + /*- *----------------------------------------------------------------------- * Var_Init -- @@ -1084,14 +1072,12 @@ Var_SubstVar(Buffer buf, /* To store result */ void Var_Init(void) { - static GSymT global_vars, cmd_vars; + ohash_init(&global_variables, 10, &var_info); + set_magic_shell_variable(); - VAR_GLOBAL = &global_vars; - VAR_CMD = &cmd_vars; - ohash_init(VAR_GLOBAL, 10, &var_info); - ohash_init(VAR_CMD, 5, &var_info); - CTXT_GLOBAL = (SymTable *)VAR_GLOBAL; - CTXT_CMD = (SymTable *)VAR_CMD; + + oldVars = true; + Var_setCheckEnvFirst(false); VarModifiers_Init(); } @@ -1104,11 +1090,8 @@ Var_End(void) Var *v; unsigned int i; - for (v = ohash_first(VAR_GLOBAL, &i); v != NULL; - v = ohash_next(VAR_GLOBAL, &i)) - VarDelete(v); - for (v = ohash_first(VAR_CMD, &i); v != NULL; - v = ohash_next(VAR_CMD, &i)) + for (v = ohash_first(&global_variables, &i); v != NULL; + v = ohash_next(&global_variables, &i)) VarDelete(v); } #endif @@ -1140,14 +1123,10 @@ Var_Dump(void) printf("#*** Global Variables:\n"); - for (v = ohash_first(VAR_GLOBAL, &i); v != NULL; - v = ohash_next(VAR_GLOBAL, &i)) + for (v = ohash_first(&global_variables, &i); v != NULL; + v = ohash_next(&global_variables, &i)) VarPrintVar(v); - printf("#*** Command-line Variables:\n"); - - for (v = ohash_first(VAR_CMD, &i); v != NULL; v = ohash_next(VAR_CMD, &i)) - VarPrintVar(v); } static const char *quotable = " \t\n\\'\""; @@ -1165,8 +1144,11 @@ Var_AddCmdline(const char *name) Buf_Init(&buf, MAKE_BSIZE); - for (v = ohash_first(VAR_CMD, &i); v != NULL; - v = ohash_next(VAR_CMD, &i)) { + for (v = ohash_first(&global_variables, &i); v != NULL; + v = ohash_next(&global_variables, &i)) { + if (!(v->flags & VAR_FROM_CMD)) { + continue; + } /* We assume variable names don't need quoting */ Buf_AddString(&buf, v->name); Buf_AddChar(&buf, '='); diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h index 8f411ec5a64..223b0e1a188 100644 --- a/usr.bin/make/var.h +++ b/usr.bin/make/var.h @@ -32,26 +32,26 @@ extern void Var_End(void); #define Var_End() #endif -extern GSymT *VAR_GLOBAL; /* Variables defined in a global context, e.g - * in the Makefile itself */ -extern GSymT *VAR_CMD; /* Variables defined on the command line */ +extern void Var_setCheckEnvFirst(bool); /* Global contexts handling. */ /* value = Var_Valuei(name, end); * Returns value of global variable name/end, or NULL if inexistent. */ extern char *Var_Valuei(const char *, const char *); #define Var_Value(n) Var_Valuei(n, NULL) +/* Only check if variable is defined */ +extern bool Var_Definedi(const char *, const char *); /* Var_Seti(name, end, val, ctxt); * Sets value val of variable name/end in context ctxt. Copies val. */ extern void Var_Seti(const char *, const char *, const char *, - GSymT *); + int); #define Var_Set(n, v, ctxt) Var_Seti(n, NULL, v, ctxt) /* Var_Appendi(name, end, val, cxt); * Appends value val to variable name/end in context ctxt, defining it * if it does not already exist, and inserting one space otherwise. */ extern void Var_Appendi(const char *, const char *, - const char *, GSymT *); + const char *, int); #define Var_Append(n, v, ctxt) Var_Appendi(n, NULL, v, ctxt) /* Var_Delete(name); @@ -130,10 +130,20 @@ extern void Var_Dump(void); * Used to propagate variable values to submakes through MAKEFLAGS. */ extern void Var_AddCmdline(const char *); - +/* stuff common to var.c and varparse.c */ extern bool oldVars; /* Do old-style variable substitution */ -extern bool checkEnvFirst; /* true if environment should be searched for - * variables before the global context */ +#define VAR_GLOBAL 0 + /* Variables defined in a global context, e.g in the Makefile itself */ +#define VAR_CMD 1 + /* Variables defined on the command line */ + +#define POISON_INVALID 0 +#define POISON_DEFINED 1 +#define POISON_NORMAL 64 +#define POISON_EMPTY 128 +#define POISON_NOT_DEFINED 256 + +extern void Var_MarkPoisoned(const char *, const char *, unsigned int); #endif |