summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/make/Makefile5
-rw-r--r--usr.bin/make/cond.c13
-rw-r--r--usr.bin/make/cond.h3
-rw-r--r--usr.bin/make/cond_int.h3
-rw-r--r--usr.bin/make/defines.h5
-rw-r--r--usr.bin/make/generate.c3
-rw-r--r--usr.bin/make/main.c10
-rw-r--r--usr.bin/make/make.125
-rw-r--r--usr.bin/make/parse.c70
-rw-r--r--usr.bin/make/parsevar.c32
-rw-r--r--usr.bin/make/parsevar.h12
-rw-r--r--usr.bin/make/var.c578
-rw-r--r--usr.bin/make/var.h26
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