diff options
Diffstat (limited to 'usr.bin')
-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 |