summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/make/for.c6
-rw-r--r--usr.bin/make/parse.c5
-rw-r--r--usr.bin/make/var.c1497
-rw-r--r--usr.bin/make/var.h51
-rw-r--r--usr.bin/make/varmodifiers.c19
-rw-r--r--usr.bin/make/varmodifiers.h6
6 files changed, 867 insertions, 717 deletions
diff --git a/usr.bin/make/for.c b/usr.bin/make/for.c
index 0565d01fae0..a68e8edd29b 100644
--- a/usr.bin/make/for.c
+++ b/usr.bin/make/for.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: for.c,v 1.31 2007/03/20 03:50:39 tedu Exp $ */
+/* $OpenBSD: for.c,v 1.32 2007/07/20 12:32:45 espie Exp $ */
/* $NetBSD: for.c,v 1.4 1996/11/06 17:59:05 christos Exp $ */
/*
@@ -162,7 +162,7 @@ For_Eval(const char *line)
/* End of variable list ? */
if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n')
break;
- Lst_AtEnd(&arg->vars, Str_dupi(wrd, endVar));
+ Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar));
arg->nvars++;
}
if (arg->nvars == 0) {
@@ -268,7 +268,7 @@ For_Run(For *arg)
arg->var = NULL;
Lst_ForEach(&arg->lst, ForExec, arg);
Buf_Destroy(&arg->buf);
- Lst_Destroy(&arg->vars, (SimpleProc)free);
+ Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar);
Lst_Destroy(&arg->lst, (SimpleProc)free);
free(arg);
}
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
index 26e9b5f5ad2..c0834ca6ab7 100644
--- a/usr.bin/make/parse.c
+++ b/usr.bin/make/parse.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: parse.c,v 1.72 2007/07/08 17:44:20 espie Exp $ */
+/* $OpenBSD: parse.c,v 1.73 2007/07/20 12:32:45 espie Exp $ */
/* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */
/*
@@ -1495,8 +1495,7 @@ ParseIsCond(Buffer linebuf, Buffer copy, char *line)
line++;
for (cp = line; !isspace(*cp) && *cp != '\0';)
cp++;
- *cp = '\0';
- Var_Delete(line);
+ Var_Deletei(line, cp);
return true;
}
default:
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c
index 6d698445ba5..f3215765446 100644
--- a/usr.bin/make/var.c
+++ b/usr.bin/make/var.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: var.c,v 1.65 2007/07/20 12:18:47 espie Exp $ */
+/* $OpenBSD: var.c,v 1.66 2007/07/20 12:32:45 espie Exp $ */
/* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */
/*
@@ -98,9 +98,9 @@ char var_Error[] = "";
* identical string instances...
*/
static char varNoError[] = "";
-bool errorIsOkay;
-static bool checkEnvFirst; /* true if environment should be searched for
- * variables before the global context */
+bool errorIsOkay;
+static bool checkEnvFirst; /* true if environment should be searched for
+ * variables before the global context */
void
Var_setCheckEnvFirst(bool yes)
@@ -109,42 +109,56 @@ Var_setCheckEnvFirst(bool yes)
}
/*
- * Variable values are obtained from four different contexts:
- * 1) the process environment. The process environment itself
- * may not be changed, but these variables may be modified,
- * unless make is invoked with -e, in which case those variables
- * are unmodifiable and supersede the global context.
- * 2) the global context. Variables set in the Makefile are located in
- * the global context. It is the penultimate context searched when
- * substituting.
- * 3) the command-line context. All variables set on the command line
- * are placed in this context. They are UNALTERABLE once placed here.
- * 4) the local context. Each target has associated with it a context
- * list. On this list are located the structures describing such
- * local variables as $(@) and $(*)
- * The four contexts are searched in the reverse order from which they are
- * listed.
+ * The rules for variable look-up are complicated.
+ *
+ * - Dynamic variables like $@ and $* are special. They always pertain to
+ * a given variable. In this implementation of make, it is an error to
+ * try to affect them manually. They are stored in a local symtable directly
+ * inside the gnode.
+ *
+ * Global variables can be obtained:
+ * - from the command line
+ * - from the environment
+ * - from the Makefile proper.
+ * All of these are stored in a hash global_variables.
+ *
+ * Variables set on the command line override Makefile contents, are
+ * passed to submakes (see Var_AddCmdLine), and are also exported to the
+ * environment.
+ *
+ * Without -e (!checkEnvFirst), make will see variables set in the
+ * Makefile, and default to the environment otherwise.
+ *
+ * With -e (checkEnvFirst), make will see the environment first, and that
+ * will override anything that's set in the Makefile (but not set on
+ * the command line).
+ *
+ * The SHELL variable is very special: it is never obtained from the
+ * environment, and never passed to the environment.
*/
+/* definitions pertaining to dynamic variables */
+
+/* full names of dynamic variables */
static char *varnames[] = {
- TARGET,
- PREFIX,
- ARCHIVE,
- MEMBER,
- OODATE,
- ALLSRC,
- IMPSRC,
- FTARGET,
- DTARGET,
- FPREFIX,
- DPREFIX,
- FARCHIVE,
- DARCHIVE,
- FMEMBER,
- DMEMBER
- };
-
-/* retrieve the hashed values for well-known variables. */
+ TARGET,
+ PREFIX,
+ ARCHIVE,
+ MEMBER,
+ OODATE,
+ ALLSRC,
+ IMPSRC,
+ FTARGET,
+ DTARGET,
+ FPREFIX,
+ DPREFIX,
+ FARCHIVE,
+ DARCHIVE,
+ FMEMBER,
+ DMEMBER
+};
+
+/* hashed names of dynamic variables */
#include "varhashconsts.h"
/* extended indices for System V stuff */
@@ -157,291 +171,348 @@ static char *varnames[] = {
#define FMEMBER_INDEX 13
#define DMEMBER_INDEX 14
+#define GLOBAL_INDEX -1
+
#define EXTENDED2SIMPLE(i) (((i)-LOCAL_SIZE)/2)
#define IS_EXTENDED_F(i) ((i)%2 == 1)
+
static struct ohash global_variables;
+
typedef struct Var_ {
- BUFFER val; /* its value */
- unsigned int flags; /* miscellaneous status flags */
+ BUFFER val; /* the variable value */
+ unsigned int flags; /* miscellaneous status flags */
#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 */
+ /* (Used to avoid recursion) */
+#define VAR_DUMMY 2 /* Variable is currently just a name */
+ /* In particular: BUFFER is invalid */
+#define VAR_FROM_CMD 4 /* Special source: command line */
+#define VAR_FROM_ENV 8 /* Special source: environment */
+#define VAR_SEEN_ENV 16 /* No need to go look up environment again */
+#define VAR_SHELL 32 /* Magic behavior */
+
#define POISONS (POISON_NORMAL | POISON_EMPTY | POISON_NOT_DEFINED)
- char name[1]; /* the variable's name */
+ /* Defined in var.h */
+ char name[1]; /* the variable's name */
} Var;
static struct ohash_info var_info = {
offsetof(Var, name),
- 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, uint32_t);
-static Var *find_global_var(const char *, const char *, uint32_t);
-static void VarDelete(Var *);
-static void VarPrintVar(Var *);
+ NULL,
+ hash_alloc, hash_free, element_alloc
+};
-static Var *obtain_global_var(const char *, const char *, uint32_t);
+static int classify_var(const char *, const char **, uint32_t *);
+static Var *find_any_var(const char *, const char *, SymTable *, int, uint32_t);
+static Var *find_global_var(const char *, const char *, uint32_t);
+static Var *find_global_var_without_env(const char *, const char *, uint32_t);
static void fill_from_env(Var *);
static Var *create_var(const char *, const char *);
+static void var_set_initial_value(Var *, const char *);
+static void var_set_value(Var *, const char *);
+#define var_get_value(v) Buf_Retrieve(&((v)->val))
+static void var_append_value(Var *, const char *);
+static void poison_check(Var *);
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 void delete_var(Var *);
+static void print_var(Var *);
+
+
static const char *find_rparen(const char *);
static const char *find_ket(const char *);
typedef const char * (*find_t)(const char *);
static find_t find_pos(int);
+
+
+/* Variable lookup function: return idx for dynamic variable, or
+ * GLOBAL_INDEX if name is not dynamic. Set up *pk for further use.
+ */
static int
-quick_lookup(const char *name, const char **enamePtr, uint32_t *pk)
+classify_var(const char *name, const char **enamePtr, uint32_t *pk)
{
- size_t len;
-
- *pk = ohash_interval(name, enamePtr);
- len = *enamePtr - name;
- /* substitute short version for long local name */
- switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */
- case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */
- /* distinct case values */
- if (*pk == K_LONGALLSRC && len == strlen(LONGALLSRC) &&
- strncmp(name, LONGALLSRC, len) == 0)
- return ALLSRC_INDEX;
- break;
- case K_LONGARCHIVE % MAGICSLOTS1:
- if (*pk == K_LONGARCHIVE && len == strlen(LONGARCHIVE) &&
- strncmp(name, LONGARCHIVE, len) == 0)
- return ARCHIVE_INDEX;
- break;
- case K_LONGIMPSRC % MAGICSLOTS1:
- if (*pk == K_LONGIMPSRC && len == strlen(LONGIMPSRC) &&
- strncmp(name, LONGIMPSRC, len) == 0)
- return IMPSRC_INDEX;
- break;
- case K_LONGMEMBER % MAGICSLOTS1:
- if (*pk == K_LONGMEMBER && len == strlen(LONGMEMBER) &&
- strncmp(name, LONGMEMBER, len) == 0)
- return MEMBER_INDEX;
- break;
- case K_LONGOODATE % MAGICSLOTS1:
- if (*pk == K_LONGOODATE && len == strlen(LONGOODATE) &&
- strncmp(name, LONGOODATE, len) == 0)
- return OODATE_INDEX;
- break;
- case K_LONGPREFIX % MAGICSLOTS1:
- if (*pk == K_LONGPREFIX && len == strlen(LONGPREFIX) &&
- strncmp(name, LONGPREFIX, len) == 0)
- return PREFIX_INDEX;
- break;
- case K_LONGTARGET % MAGICSLOTS1:
- if (*pk == K_LONGTARGET && len == strlen(LONGTARGET) &&
- strncmp(name, LONGTARGET, len) == 0)
- return TARGET_INDEX;
- break;
- case K_TARGET % MAGICSLOTS1:
- if (name[0] == TARGET[0] && len == 1)
- return TARGET_INDEX;
- break;
- case K_OODATE % MAGICSLOTS1:
- if (name[0] == OODATE[0] && len == 1)
- return OODATE_INDEX;
- break;
- case K_ALLSRC % MAGICSLOTS1:
- if (name[0] == ALLSRC[0] && len == 1)
- return ALLSRC_INDEX;
- break;
- case K_IMPSRC % MAGICSLOTS1:
- if (name[0] == IMPSRC[0] && len == 1)
- return IMPSRC_INDEX;
- break;
- case K_PREFIX % MAGICSLOTS1:
- if (name[0] == PREFIX[0] && len == 1)
- return PREFIX_INDEX;
- break;
- case K_ARCHIVE % MAGICSLOTS1:
- if (name[0] == ARCHIVE[0] && len == 1)
- return ARCHIVE_INDEX;
- break;
- case K_MEMBER % MAGICSLOTS1:
- if (name[0] == MEMBER[0] && len == 1)
- return MEMBER_INDEX;
- break;
- case K_FTARGET % MAGICSLOTS1:
- if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2)
- return FTARGET_INDEX;
- break;
- case K_DTARGET % MAGICSLOTS1:
- if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2)
- return DTARGET_INDEX;
- break;
- case K_FPREFIX % MAGICSLOTS1:
- if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2)
- return FPREFIX_INDEX;
- break;
- case K_DPREFIX % MAGICSLOTS1:
- if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2)
- return DPREFIX_INDEX;
- break;
- case K_FARCHIVE % MAGICSLOTS1:
- if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] && len == 2)
- return FARCHIVE_INDEX;
- break;
- case K_DARCHIVE % MAGICSLOTS1:
- if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] && len == 2)
- return DARCHIVE_INDEX;
- break;
- case K_FMEMBER % MAGICSLOTS1:
- if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2)
- return FMEMBER_INDEX;
- break;
- case K_DMEMBER % MAGICSLOTS1:
- if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2)
- return DMEMBER_INDEX;
- break;
- default:
- break;
- }
- return -1;
+ size_t len;
+
+ *pk = ohash_interval(name, enamePtr);
+ len = *enamePtr - name;
+ /* substitute short version for long local name */
+ switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */
+ case K_LONGALLSRC % MAGICSLOTS1:/* smallest constant yielding */
+ /* distinct case values */
+ if (*pk == K_LONGALLSRC && len == strlen(LONGALLSRC) &&
+ strncmp(name, LONGALLSRC, len) == 0)
+ return ALLSRC_INDEX;
+ break;
+ case K_LONGARCHIVE % MAGICSLOTS1:
+ if (*pk == K_LONGARCHIVE && len == strlen(LONGARCHIVE) &&
+ strncmp(name, LONGARCHIVE, len) == 0)
+ return ARCHIVE_INDEX;
+ break;
+ case K_LONGIMPSRC % MAGICSLOTS1:
+ if (*pk == K_LONGIMPSRC && len == strlen(LONGIMPSRC) &&
+ strncmp(name, LONGIMPSRC, len) == 0)
+ return IMPSRC_INDEX;
+ break;
+ case K_LONGMEMBER % MAGICSLOTS1:
+ if (*pk == K_LONGMEMBER && len == strlen(LONGMEMBER) &&
+ strncmp(name, LONGMEMBER, len) == 0)
+ return MEMBER_INDEX;
+ break;
+ case K_LONGOODATE % MAGICSLOTS1:
+ if (*pk == K_LONGOODATE && len == strlen(LONGOODATE) &&
+ strncmp(name, LONGOODATE, len) == 0)
+ return OODATE_INDEX;
+ break;
+ case K_LONGPREFIX % MAGICSLOTS1:
+ if (*pk == K_LONGPREFIX && len == strlen(LONGPREFIX) &&
+ strncmp(name, LONGPREFIX, len) == 0)
+ return PREFIX_INDEX;
+ break;
+ case K_LONGTARGET % MAGICSLOTS1:
+ if (*pk == K_LONGTARGET && len == strlen(LONGTARGET) &&
+ strncmp(name, LONGTARGET, len) == 0)
+ return TARGET_INDEX;
+ break;
+ case K_TARGET % MAGICSLOTS1:
+ if (name[0] == TARGET[0] && len == 1)
+ return TARGET_INDEX;
+ break;
+ case K_OODATE % MAGICSLOTS1:
+ if (name[0] == OODATE[0] && len == 1)
+ return OODATE_INDEX;
+ break;
+ case K_ALLSRC % MAGICSLOTS1:
+ if (name[0] == ALLSRC[0] && len == 1)
+ return ALLSRC_INDEX;
+ break;
+ case K_IMPSRC % MAGICSLOTS1:
+ if (name[0] == IMPSRC[0] && len == 1)
+ return IMPSRC_INDEX;
+ break;
+ case K_PREFIX % MAGICSLOTS1:
+ if (name[0] == PREFIX[0] && len == 1)
+ return PREFIX_INDEX;
+ break;
+ case K_ARCHIVE % MAGICSLOTS1:
+ if (name[0] == ARCHIVE[0] && len == 1)
+ return ARCHIVE_INDEX;
+ break;
+ case K_MEMBER % MAGICSLOTS1:
+ if (name[0] == MEMBER[0] && len == 1)
+ return MEMBER_INDEX;
+ break;
+ case K_FTARGET % MAGICSLOTS1:
+ if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2)
+ return FTARGET_INDEX;
+ break;
+ case K_DTARGET % MAGICSLOTS1:
+ if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2)
+ return DTARGET_INDEX;
+ break;
+ case K_FPREFIX % MAGICSLOTS1:
+ if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2)
+ return FPREFIX_INDEX;
+ break;
+ case K_DPREFIX % MAGICSLOTS1:
+ if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2)
+ return DPREFIX_INDEX;
+ break;
+ case K_FARCHIVE % MAGICSLOTS1:
+ if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] &&
+ len == 2)
+ return FARCHIVE_INDEX;
+ break;
+ case K_DARCHIVE % MAGICSLOTS1:
+ if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] &&
+ len == 2)
+ return DARCHIVE_INDEX;
+ break;
+ case K_FMEMBER % MAGICSLOTS1:
+ if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2)
+ return FMEMBER_INDEX;
+ break;
+ case K_DMEMBER % MAGICSLOTS1:
+ if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2)
+ return DMEMBER_INDEX;
+ break;
+ default:
+ break;
+ }
+ return GLOBAL_INDEX;
}
+
+/***
+ *** Internal handling of variables.
+ ***/
+
+
+/* Create a new variable, does not initialize anything except the name.
+ * in particular, buffer is invalid, and flag value is invalid. Accordingly,
+ * must either:
+ * - set flags to VAR_DUMMY
+ * - set flags to !VAR_DUMMY, and initialize buffer, for instance with
+ * var_set_initial_value().
+ */
static Var *
create_var(const char *name, const char *ename)
{
- return ohash_create_entry(&var_info, name, &ename);
+ return ohash_create_entry(&var_info, name, &ename);
}
-/* Set the initial value a var should have */
+/* Initial version of var_set_value(), to be called after create_var().
+ */
static void
-var_init_string(Var *v, const char *val)
+var_set_initial_value(Var *v, const char *val)
{
- size_t len;
+ size_t len;
- len = strlen(val);
- Buf_Init(&(v->val), len+1);
- Buf_AddChars(&(v->val), len, val);
+ len = strlen(val);
+ Buf_Init(&(v->val), len+1);
+ Buf_AddChars(&(v->val), len, val);
}
+/* Normal version of var_set_value(), to be called after variable is fully
+ * initialized.
+ */
static void
-var_set_string(Var *v, const char *val)
+var_set_value(Var *v, const char *val)
{
- 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;
- }
+ if ((v->flags & VAR_DUMMY) == 0) {
+ Buf_Reset(&(v->val));
+ Buf_AddString(&(v->val), val);
+ } else {
+ var_set_initial_value(v, val);
+ v->flags &= ~VAR_DUMMY;
+ }
}
+/* Add to a variable, insert a separating space if the variable was already
+ * defined.
+ */
static void
-var_append_string(Var *v, const char *val)
+var_append_value(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;
- }
+ if ((v->flags & VAR_DUMMY) == 0) {
+ Buf_AddSpace(&(v->val));
+ Buf_AddString(&(v->val), val);
+ } else {
+ var_set_initial_value(v, val);
+ v->flags &= ~VAR_DUMMY;
+ }
}
-/*-
- *-----------------------------------------------------------------------
- * VarDelete --
- * Delete a variable and all the space associated with it.
- *-----------------------------------------------------------------------
+
+/* Delete a variable and all the space associated with it.
*/
static void
-VarDelete(Var *v)
+delete_var(Var *v)
{
- if ((v->flags & VAR_DUMMY) == 0)
- Buf_Destroy(&(v->val));
- free(v);
+ if ((v->flags & VAR_DUMMY) == 0)
+ Buf_Destroy(&(v->val));
+ free(v);
}
+
+/***
+ *** Dynamic variable handling.
+ ***/
+
+
+
+/* create empty symtable.
+ * XXX: to save space, dynamic variables may be NULL pointers.
+ */
void
SymTable_Init(SymTable *ctxt)
{
- static SymTable sym_template;
- memcpy(ctxt, &sym_template, sizeof(*ctxt));
+ static SymTable sym_template;
+ memcpy(ctxt, &sym_template, sizeof(*ctxt));
}
+/* free symtable.
+ */
#ifdef CLEANUP
void
SymTable_Destroy(SymTable *ctxt)
{
- int i;
+ int i;
- for (i = 0; i < LOCAL_SIZE; i++)
- if (ctxt->locals[i] != NULL)
- VarDelete(ctxt->locals[i]);
+ for (i = 0; i < LOCAL_SIZE; i++)
+ if (ctxt->locals[i] != NULL)
+ delete_var(ctxt->locals[i]);
}
#endif
+/* set or append to dynamic variable.
+ */
static void
varq_set_append(int idx, const char *val, GNode *gn, bool append)
{
- Var *v = gn->context.locals[idx];
+ Var *v = gn->context.locals[idx];
- if (v == NULL) {
- v = create_var(varnames[idx], NULL);
+ if (v == NULL) {
+ v = create_var(varnames[idx], NULL);
#ifdef STATS_VAR_LOOKUP
- STAT_VAR_CREATION++;
+ 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 {
- 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], VarValue(v));
+ if (val != NULL)
+ var_set_initial_value(v, val);
+ else
+ Buf_Init(&(v->val), 1);
+ v->flags = 0;
+ gn->context.locals[idx] = v;
+ } else {
+ 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],
+ var_get_value(v));
}
void
Varq_Set(int idx, const char *val, GNode *gn)
{
- varq_set_append(idx, val, gn, false);
+ varq_set_append(idx, val, gn, false);
}
void
Varq_Append(int idx, const char *val, GNode *gn)
{
- varq_set_append(idx, val, gn, true);
+ varq_set_append(idx, val, gn, true);
}
char *
Varq_Value(int idx, GNode *gn)
{
- Var *v = gn->context.locals[idx];
+ Var *v = gn->context.locals[idx];
- if (v == NULL)
- return NULL;
- else
- return VarValue(v);
+ if (v == NULL)
+ return NULL;
+ else
+ return var_get_value(v);
}
+/***
+ *** Global variable handling.
+ ***/
+
+/* Create a new global var if necessary, and set it up correctly.
+ * Do not take environment into account.
+ */
static Var *
-obtain_global_var(const char *name, const char *ename, uint32_t k)
+find_global_var_without_env(const char *name, const char *ename, uint32_t k)
{
unsigned int slot;
Var *v;
@@ -456,50 +527,55 @@ obtain_global_var(const char *name, const char *ename, uint32_t k)
return v;
}
+/* Helper for find_global_var(): grab environment value if needed.
+ */
static void
fill_from_env(Var *v)
{
- char *env;
-
- env = getenv(v->name);
- if (env == NULL)
- v->flags |= VAR_SEEN_ENV;
- else {
- var_set_string(v, env);
- v->flags |= VAR_FROM_ENV | VAR_SEEN_ENV;
- }
+ char *env;
+
+ env = getenv(v->name);
+ if (env == NULL)
+ v->flags |= VAR_SEEN_ENV;
+ else {
+ var_set_value(v, env);
+ v->flags |= VAR_FROM_ENV | VAR_SEEN_ENV;
+ }
#ifdef STATS_VAR_LOOKUP
- STAT_VAR_FROM_ENV++;
+ STAT_VAR_FROM_ENV++;
#endif
}
+/* Find global var, and obtain its value from the environment if needed.
+ */
static Var *
find_global_var(const char *name, const char *ename, uint32_t k)
{
- Var *v;
+ Var *v;
- v = obtain_global_var(name, ename, k);
+ v = find_global_var_without_env(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);
+ if ((v->flags & VAR_SEEN_ENV) == 0 &&
+ (checkEnvFirst && (v->flags & VAR_FROM_CMD) == 0 ||
+ (v->flags & VAR_DUMMY) != 0))
+ fill_from_env(v);
- return v;
+ return v;
}
-
+/* mark variable as poisoned, in a given setup.
+ */
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);
+ idx = classify_var(name, &ename, &k);
- if (idx != -1) {
- Parse_Error(PARSE_FATAL,
+ if (idx != GLOBAL_INDEX) {
+ Parse_Error(PARSE_FATAL,
"Trying to poison dynamic variable $%s",
varnames[idx]);
return;
@@ -507,6 +583,9 @@ Var_MarkPoisoned(const char *name, const char *ename, unsigned int type)
v = find_global_var(name, ename, k);
v->flags |= type;
+ /* POISON_NORMAL is not lazy: if the variable already exists in
+ * the Makefile, then it's a mistake.
+ */
if (v->flags & POISON_NORMAL) {
if (v->flags & VAR_DUMMY)
return;
@@ -517,11 +596,13 @@ Var_MarkPoisoned(const char *name, const char *ename, unsigned int type)
}
}
+/* Check if there's any reason not to use the variable in this context.
+ */
static void
poison_check(Var *v)
{
if (v->flags & POISON_NORMAL) {
- Parse_Error(PARSE_FATAL,
+ Parse_Error(PARSE_FATAL,
"Poisoned variable %s has been referenced\n", v->name);
return;
}
@@ -531,32 +612,33 @@ poison_check(Var *v)
return;
}
if (v->flags & POISON_EMPTY)
- if (strcmp(VarValue(v), "") == 0)
- Parse_Error(PARSE_FATAL,
+ if (strcmp(var_get_value(v), "") == 0)
+ Parse_Error(PARSE_FATAL,
"Poisoned variable %s is empty\n", v->name);
}
+/* Delete global variable.
+ */
void
-Var_Delete(const char *name)
+Var_Deletei(const char *name, const char *ename)
{
- Var *v;
- uint32_t k;
+ Var *v;
+ uint32_t k;
unsigned int slot;
- const char *ename = NULL;
- int idx;
-
-
- if (DEBUG(VAR))
- printf("delete %s\n", name);
+ int idx;
- idx = quick_lookup(name, &ename, &k);
- if (idx != -1)
- Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable");
+ idx = classify_var(name, &ename, &k);
+ if (idx != GLOBAL_INDEX) {
+ Parse_Error(PARSE_FATAL,
+ "Trying to delete dynamic variable $%s", varnames[idx]);
+ return;
+ }
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;
@@ -564,19 +646,21 @@ Var_Delete(const char *name)
return;
ohash_remove(&global_variables, slot);
- VarDelete(v);
+ delete_var(v);
}
+/* Set or add a global variable, in VAR_CMD or VAR_GLOBAL context.
+ */
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;
+ Var *v;
+ uint32_t k;
+ int idx;
- idx = quick_lookup(name, &ename, &k);
- if (idx != -1) {
+ idx = classify_var(name, &ename, &k);
+ if (idx != GLOBAL_INDEX) {
Parse_Error(PARSE_FATAL, "Trying to %s dynamic variable $%s",
append ? "append to" : "set", varnames[idx]);
return;
@@ -587,25 +671,25 @@ var_set_append(const char *name, const char *ename, const char *val, int ctxt,
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);
+ if (ctxt == VAR_CMD) { /* always for command line */
+ (append ? var_append_value : var_set_value)(v, val);
v->flags |= VAR_FROM_CMD;
if ((v->flags & VAR_SHELL) == 0) {
- /* Any variables given on the command line are
+ /* Any variables given on the command line are
* automatically exported to the environment,
- * except for SHELL (as per POSIX standard).
+ * except for SHELL (as per POSIX standard).
*/
esetenv(v->name, val);
- }
+ }
if (DEBUG(VAR))
- printf("command:%s = %s\n", v->name, VarValue(v));
+ printf("command:%s = %s\n", v->name, var_get_value(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);
+ (append ? var_append_value : var_set_value)(v, val);
if (DEBUG(VAR))
- printf("global:%s = %s\n", v->name, VarValue(v));
+ printf("global:%s = %s\n", v->name, var_get_value(v));
} else if (DEBUG(VAR))
- printf("overriden:%s = %s\n", v->name, VarValue(v));
+ printf("overriden:%s = %s\n", v->name, var_get_value(v));
}
void
@@ -620,69 +704,86 @@ Var_Appendi(const char *name, const char *ename, const char *val, int ctxt)
var_set_append(name, ename, val, ctxt, true);
}
+/* XXX different semantics for Var_Valuei() and Var_Definedi():
+ * references to poisoned value variables will error out in Var_Valuei(),
+ * but not in Var_Definedi(), so the following construct works:
+ * .poison BINDIR
+ * BINDIR ?= /usr/bin
+ */
char *
Var_Valuei(const char *name, const char *ename)
{
- Var *v;
- uint32_t k;
- int idx;
+ 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);
+ idx = classify_var(name, &ename, &k);
+ if (idx != GLOBAL_INDEX) {
+ Parse_Error(PARSE_FATAL,
+ "Trying to get value of dynamic variable $%s",
+ varnames[idx]);
+ return NULL;
}
-
- return NULL;
+ v = find_global_var(name, ename, k);
+ if (v->flags & POISONS)
+ poison_check(v);
+ if ((v->flags & VAR_DUMMY) == 0)
+ return var_get_value(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) {
+ Var *v;
+ uint32_t k;
+ int idx;
+
+ idx = classify_var(name, &ename, &k);
+ /* We don't bother writing an error message for dynamic variables,
+ * these will be caught when getting set later, usually.
+ */
+ if (idx == GLOBAL_INDEX) {
v = find_global_var(name, ename, k);
if (v->flags & POISON_NORMAL)
- poison_check(v);
+ poison_check(v);
if ((v->flags & VAR_DUMMY) == 0)
return true;
}
-
return false;
}
+
+/***
+ *** Substitution functions, handling both global and dynamic variables.
+ ***/
+
+
+/* XXX contrary to find_global_var(), find_any_var() can return NULL pointers.
+ */
static Var *
-varfind(const char *name, const char *ename, SymTable *ctxt,
+find_any_var(const char *name, const char *ename, SymTable *ctxt,
int idx, uint32_t k)
{
- /* Handle local variables first */
- if (idx != -1) {
- if (ctxt != NULL) {
- if (idx < LOCAL_SIZE)
- return ctxt->locals[idx];
- else
- return ctxt->locals[EXTENDED2SIMPLE(idx)];
- } else
- return NULL;
- } else {
- return find_global_var(name, ename, k);
- }
+ /* Handle local variables first */
+ if (idx != GLOBAL_INDEX) {
+ if (ctxt != NULL) {
+ if (idx < LOCAL_SIZE)
+ return ctxt->locals[idx];
+ else
+ return ctxt->locals[EXTENDED2SIMPLE(idx)];
+ } else
+ return NULL;
+ } else {
+ return find_global_var(name, ename, k);
+ }
}
-static const char *
-find_0(const char *p)
-{
- while (*p != '$' && *p != '\0' && *p != ':')
- p++;
- return p;
-}
+/* All the scanning functions needed to account for all the forms of
+ * variable names that exist:
+ * $A, ${AB}, $(ABC), ${A:mod}, $(A:mod)
+ */
static const char *
find_rparen(const char *p)
@@ -700,397 +801,427 @@ find_ket(const char *p)
return p;
}
+/* Figure out what kind of name we're looking for from a start character.
+ */
static find_t
find_pos(int c)
{
switch(c) {
- case '\0':
- return find_0;
- case ')':
+ case '(':
return find_rparen;
- case '}':
+ case '{':
return find_ket;
default:
- return 0;
+ Parse_Error(PARSE_FATAL,
+ "Wrong character in variable spec %c (can't happen)");
+ return find_rparen;
}
}
size_t
Var_ParseSkip(const char *str, SymTable *ctxt, bool *result)
{
- const char *tstr; /* Pointer into str */
- Var *v; /* Variable in invocation */
- char endc; /* Ending character when variable in parens
- * or braces */
- const char *start;
- size_t length;
- struct Name name;
-
- v = NULL;
- start = str;
- str++;
-
- if (*str != '(' && *str != '{') {
- name.tofree = false;
- tstr = str + 1;
- length = 2;
- endc = '\0';
- } else {
- endc = *str == '(' ? ')' : '}';
+ const char *tstr; /* Pointer into str */
+ Var *v; /* Variable in invocation */
+ char paren; /* Parenthesis or brace or nothing */
+ const char *start;
+ size_t length;
+ struct Name name;
+
+ v = NULL;
+ start = str;
str++;
- /* Find eventual modifiers in the variable */
- tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc));
- VarName_Free(&name);
- length = tstr - start;
- if (*tstr != 0)
- length++;
- }
-
- if (result != NULL)
- *result = true;
- if (*tstr == ':' && endc != '\0')
- if (VarModifiers_Apply(NULL, NULL, ctxt, true, NULL, tstr, endc,
- &length) == var_Error)
- if (result != NULL)
- *result = false;
- return length;
+ if (*str != '(' && *str != '{') {
+ name.tofree = false;
+ tstr = str + 1;
+ length = 2;
+ paren = '\0';
+ } else {
+ paren = *str;
+ str++;
+
+ /* Find eventual modifiers in the variable */
+ tstr = VarName_Get(str, &name, ctxt, false, find_pos(paren));
+ VarName_Free(&name);
+ length = tstr - start;
+ if (*tstr != 0)
+ length++;
+ }
+
+ if (result != NULL)
+ *result = true;
+ if (*tstr == ':' && paren != '\0')
+ if (VarModifiers_Apply(NULL, NULL, ctxt, true, NULL, tstr,
+ paren, &length) == var_Error)
+ if (result != NULL)
+ *result = false;
+ return length;
}
/* As of now, Var_ParseBuffer is just a wrapper around Var_Parse. For
* speed, it may be better to revisit the implementation to do things
* directly. */
bool
-Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err,
+Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err,
size_t *lengthPtr)
{
- char *result;
- bool freeIt;
+ char *result;
+ bool freeIt;
- result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt);
- if (result == var_Error)
- return false;
+ result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt);
+ if (result == var_Error)
+ return false;
- Buf_AddString(buf, result);
- if (freeIt)
- free(result);
- return true;
+ Buf_AddString(buf, result);
+ if (freeIt)
+ free(result);
+ return true;
}
char *
-Var_Parse(const char *str, /* The string to parse */
- SymTable *ctxt, /* The context for the variable */
- bool err, /* true if undefined variables are an error */
- size_t *lengthPtr, /* OUT: The length of the specification */
+Var_Parse(const char *str, /* The string to parse */
+ SymTable *ctxt, /* The context for the variable */
+ bool err, /* true if undefined variables are an error */
+ size_t *lengthPtr, /* OUT: The length of the specification */
bool *freePtr) /* OUT: true if caller should free result */
{
- const char *tstr; /* Pointer into str */
- Var *v; /* Variable in invocation */
- char endc; /* Ending character when variable in parens
- * or braces */
- struct Name name;
- const char *start;
- char *val; /* Variable value */
- uint32_t k;
- int idx;
-
- *freePtr = false;
- start = str++;
-
- val = NULL;
- v = NULL;
- idx = -1;
-
- if (*str != '(' && *str != '{') {
- name.s = str;
- name.e = str+1;
- name.tofree = false;
- tstr = str + 1;
- *lengthPtr = 2;
- endc = '\0';
- } else {
- endc = *str == '(' ? ')' : '}';
- str++;
+ const char *tstr; /* Pointer into str */
+ Var *v; /* Variable in invocation */
+ char paren; /* Parenthesis or brace or nothing */
+ struct Name name;
+ const char *start;
+ char *val; /* Variable value */
+ uint32_t k;
+ int idx;
+
+ *freePtr = false;
+ start = str++;
+
+ val = NULL;
+ v = NULL;
+ idx = GLOBAL_INDEX;
+
+ if (*str != '(' && *str != '{') {
+ name.s = str;
+ name.e = str+1;
+ name.tofree = false;
+ tstr = str + 1;
+ *lengthPtr = 2;
+ paren = '\0';
+ } else {
+ paren = *str;
+ str++;
- /* Find eventual modifiers in the variable */
- tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc));
- *lengthPtr = tstr - start;
- if (*tstr != '\0')
- (*lengthPtr)++;
- }
-
- idx = quick_lookup(name.s, &name.e, &k);
- v = varfind(name.s, name.e, ctxt, idx, k);
- if (v != NULL && (v->flags & POISONS) != 0)
- poison_check(v);
- if (v != NULL && (v->flags & VAR_DUMMY) == 0) {
- if (v->flags & VAR_IN_USE)
- Fatal("Variable %s is recursive.", v->name);
- /*NOTREACHED*/
- else
- v->flags |= VAR_IN_USE;
-
- /* Before doing any modification, we have to make sure the value
- * has been fully expanded. If it looks like recursion might be
- * necessary (there's a dollar sign somewhere in the variable's value)
- * we just call Var_Subst to do any other substitutions that are
- * necessary. Note that the value returned by Var_Subst will have
- * been dynamically-allocated, so it will need freeing when we
- * return. */
- val = VarValue(v);
- if (idx == -1) {
- if (strchr(val, '$') != NULL) {
- val = Var_Subst(val, ctxt, err);
- *freePtr = true;
- }
- } else if (idx >= LOCAL_SIZE) {
- if (IS_EXTENDED_F(idx))
- val = Var_GetTail(val);
- else
- val = Var_GetHead(val);
- *freePtr = true;
+ /* Find eventual modifiers in the variable */
+ tstr = VarName_Get(str, &name, ctxt, false, find_pos(paren));
+ *lengthPtr = tstr - start;
+ if (*tstr != '\0')
+ (*lengthPtr)++;
}
- v->flags &= ~VAR_IN_USE;
- }
- if (*tstr == ':' && endc != '\0')
- val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, tstr, endc,
- lengthPtr);
- if (val == NULL) {
- val = err ? var_Error : varNoError;
- /* Dynamic source */
- if (idx != -1) {
- /* can't be expanded for now: copy the var spec instead. */
- if (ctxt == NULL) {
- *freePtr = true;
- val = Str_dupi(start, start+ *lengthPtr);
- } else {
- /* somehow, this should have been expanded already. */
- GNode *n;
-
- n = (GNode *)(((char *)ctxt) - offsetof(GNode, context));
- if (idx >= LOCAL_SIZE)
- idx = EXTENDED2SIMPLE(idx);
- switch(idx) {
- case IMPSRC_INDEX:
- Fatal("Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)",
- n->lineno, n->fname);
- default:
- Error("Using undefined dynamic variable $%s (line %lu of %s)",
- varnames[idx], n->lineno, n->fname);
- break;
+
+ idx = classify_var(name.s, &name.e, &k);
+ v = find_any_var(name.s, name.e, ctxt, idx, k);
+ if (v != NULL && (v->flags & POISONS) != 0)
+ poison_check(v);
+ if (v != NULL && (v->flags & VAR_DUMMY) == 0) {
+ if (v->flags & VAR_IN_USE)
+ Fatal("Variable %s is recursive.", v->name);
+ /*NOTREACHED*/
+ else
+ v->flags |= VAR_IN_USE;
+
+ /* Before doing any modification, we have to make sure the
+ * value has been fully expanded. If it looks like recursion
+ * might be necessary (there's a dollar sign somewhere in
+ * the variable's value) we just call Var_Subst to do any
+ * other substitutions that are necessary. Note that the
+ * value returned by Var_Subst will have been dynamically
+ * allocated, so it will need freeing when we return.
+ */
+ val = var_get_value(v);
+ if (idx == GLOBAL_INDEX) {
+ if (strchr(val, '$') != NULL) {
+ val = Var_Subst(val, ctxt, err);
+ *freePtr = true;
+ }
+ } else if (idx >= LOCAL_SIZE) {
+ if (IS_EXTENDED_F(idx))
+ val = Var_GetTail(val);
+ else
+ val = Var_GetHead(val);
+ *freePtr = true;
+ }
+ v->flags &= ~VAR_IN_USE;
+ }
+ if (*tstr == ':' && paren != '\0')
+ val = VarModifiers_Apply(val, &name, ctxt, err, freePtr,
+ tstr, paren, lengthPtr);
+ if (val == NULL) {
+ val = err ? var_Error : varNoError;
+ /* Dynamic source */
+ if (idx != GLOBAL_INDEX) {
+ /* can't be expanded for now: copy the spec instead. */
+ if (ctxt == NULL) {
+ *freePtr = true;
+ val = Str_dupi(start, start+ *lengthPtr);
+ } else {
+ /* somehow, this should have been expanded already. */
+ GNode *n;
+
+ /* XXX */
+ n = (GNode *)(((char *)ctxt) -
+ offsetof(GNode, context));
+ if (idx >= LOCAL_SIZE)
+ idx = EXTENDED2SIMPLE(idx);
+ switch(idx) {
+ case IMPSRC_INDEX:
+ Fatal(
+"Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)",
+ n->lineno, n->fname);
+ default:
+ Error(
+"Using undefined dynamic variable $%s (line %lu of %s)",
+ varnames[idx], n->lineno, n->fname);
+ break;
+ }
+ }
}
- }
}
- }
- VarName_Free(&name);
- return val;
+ VarName_Free(&name);
+ return val;
}
+
char *
-Var_Subst(const char *str, /* the string in which to substitute */
- SymTable *ctxt, /* the context wherein to find variables */
+Var_Subst(const char *str, /* the string in which to substitute */
+ SymTable *ctxt, /* the context wherein to find variables */
bool undefErr) /* true if undefineds are an error */
{
- BUFFER buf; /* Buffer for forming things */
- static bool errorReported; /* Set true if an error has already
- * been reported to prevent a plethora
- * of messages when recursing */
-
- Buf_Init(&buf, MAKE_BSIZE);
- errorReported = false;
-
- for (;;) {
- char *val; /* Value to substitute for a variable */
- size_t length; /* Length of the variable invocation */
- bool doFree; /* Set true if val should be freed */
- const char *cp;
-
- /* copy uninteresting stuff */
- for (cp = str; *str != '\0' && *str != '$'; str++)
- ;
- Buf_Addi(&buf, cp, str);
- if (*str == '\0')
- break;
- if (str[1] == '$') {
- /* A dollar sign may be escaped with another dollar sign. */
- Buf_AddChar(&buf, '$');
- str += 2;
- continue;
- }
- val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
- /* When we come down here, val should either point to the
- * value of this variable, suitably modified, or be NULL.
- * Length should be the total length of the potential
- * variable invocation (from $ to end character...) */
- if (val == var_Error || val == varNoError) {
- /* If performing old-time variable substitution, skip over
- * the variable and continue with the substitution. Otherwise,
- * store the dollar sign and advance str so we continue with
- * the string... */
- if (errorIsOkay)
- str += length;
- else if (undefErr) {
- /* If variable is undefined, complain and skip the
- * variable. The complaint will stop us from doing anything
- * when the file is parsed. */
- if (!errorReported)
- Parse_Error(PARSE_FATAL,
- "Undefined variable \"%.*s\"",length,str);
- str += length;
- errorReported = true;
- } else {
- Buf_AddChar(&buf, *str);
- str++;
- }
- } else {
- /* We've now got a variable structure to store in. But first,
- * advance the string pointer. */
- str += length;
-
- /* Copy all the characters from the variable value straight
- * into the new string. */
- Buf_AddString(&buf, val);
- if (doFree)
- free(val);
+ BUFFER buf; /* Buffer for forming things */
+ static bool errorReported;
+
+ Buf_Init(&buf, MAKE_BSIZE);
+ errorReported = false;
+
+ for (;;) {
+ char *val; /* Value to substitute for a variable */
+ size_t length; /* Length of the variable invocation */
+ bool doFree; /* Set true if val should be freed */
+ const char *cp;
+
+ /* copy uninteresting stuff */
+ for (cp = str; *str != '\0' && *str != '$'; str++)
+ ;
+ Buf_Addi(&buf, cp, str);
+ if (*str == '\0')
+ break;
+ if (str[1] == '$') {
+ /* A $ may be escaped with another $. */
+ Buf_AddChar(&buf, '$');
+ str += 2;
+ continue;
+ }
+ val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
+ /* When we come down here, val should either point to the
+ * value of this variable, suitably modified, or be NULL.
+ * Length should be the total length of the potential
+ * variable invocation (from $ to end character...) */
+ if (val == var_Error || val == varNoError) {
+ /* If errors are not an issue, skip over the variable
+ * and continue with the substitution. Otherwise, store
+ * the dollar sign and advance str so we continue with
+ * the string... */
+ if (errorIsOkay)
+ str += length;
+ else if (undefErr) {
+ /* If variable is undefined, complain and
+ * skip the variable name. The complaint
+ * will stop us from doing anything when
+ * the file is parsed. */
+ if (!errorReported)
+ Parse_Error(PARSE_FATAL,
+ "Undefined variable \"%.*s\"",
+ length, str);
+ str += length;
+ errorReported = true;
+ } else {
+ Buf_AddChar(&buf, *str);
+ str++;
+ }
+ } else {
+ /* We've now got a variable structure to store in.
+ * But first, advance the string pointer. */
+ str += length;
+
+ /* Copy all the characters from the variable value
+ * straight into the new string. */
+ Buf_AddString(&buf, val);
+ if (doFree)
+ free(val);
+ }
}
- }
- return Buf_Retrieve(&buf);
+ return Buf_Retrieve(&buf);
+}
+
+
+/***
+ *** Supplementary support for .for loops.
+ ***/
+
+
+
+struct LoopVar
+{
+ Var old; /* keep old variable value (before the loop) */
+ Var *me; /* the variable we're dealing with */
+};
+
+
+struct LoopVar *
+Var_NewLoopVar(const char *name, const char *ename)
+{
+ struct LoopVar *l;
+ uint32_t k;
+
+ l = emalloc(sizeof(struct LoopVar));
+
+ /* we obtain a new variable quickly, make a snapshot of its old
+ * value, and make sure the environment cannot touch us.
+ */
+ /* XXX: should we avoid dynamic variables ? */
+ k = ohash_interval(name, &ename);
+
+ l->me = find_global_var_without_env(name, ename, k);
+ l->old = *(l->me);
+ l->me->flags |= VAR_SEEN_ENV;
+ return l;
+}
+
+void
+Var_DeleteLoopVar(struct LoopVar *l)
+{
+ *(l->me) = l->old;
+ free(l);
}
void
-Var_SubstVar(Buffer buf, /* To store result */
- const char *str, /* The string in which to substitute */
- const char *var, /* Named variable */
+Var_SubstVar(Buffer buf, /* To store result */
+ const char *str, /* The string in which to substitute */
+ struct LoopVar *l, /* Handle */
const char *val) /* Its value */
{
- /* we save the old value and affect the new value temporarily */
- Var old;
- const char *ename = NULL;
- uint32_t k;
- Var *me;
- k = ohash_interval(var, &ename);
- me = obtain_global_var(var, ename, k);
- old = *me;
- var_init_string(me, val);
- me->flags = VAR_SEEN_ENV;
-
- assert(*var != '\0');
-
- for (;;) {
- const char *start;
- /* Copy uninteresting stuff */
- for (start = str; *str != '\0' && *str != '$'; str++)
- ;
- Buf_Addi(buf, start, str);
+ const char *var = l->me->name;
- start = str;
- if (*str++ == '\0')
- break;
- str++;
- /* and escaped dollars */
- if (start[1] == '$') {
- Buf_Addi(buf, start, start+2);
- continue;
- }
- /* Simple variable, if it's not us, copy. */
- if (start[1] != '(' && start[1] != '{') {
- if (start[1] != *var || var[1] != '\0') {
- Buf_AddChars(buf, 2, start);
- continue;
- }
- } else {
- const char *p;
- char endc;
+ var_set_value(l->me, val);
- if (start[1] == '(')
- endc = ')';
- else
- endc = '}';
+ for (;;) {
+ const char *start;
+ /* Copy uninteresting stuff */
+ for (start = str; *str != '\0' && *str != '$'; str++)
+ ;
+ Buf_Addi(buf, start, str);
- /* Find the end of the variable specification. */
- p = str;
- while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
- p++;
- /* A variable inside the variable. We don't know how to
- * expand the external variable at this point, so we try
- * again with the nested variable. */
- if (*p == '$') {
- Buf_Addi(buf, start, p);
- str = p;
- continue;
- }
-
- if (strncmp(var, str, p - str) != 0 ||
- var[p - str] != '\0') {
- /* Not the variable we want to expand. */
- Buf_Addi(buf, start, p);
- str = p;
- continue;
- }
- if (*p == ':') {
- size_t length; /* Length of the variable invocation */
- bool doFree; /* Set true if val should be freed */
- char *newval; /* Value substituted for a variable */
- struct Name name;
-
- length = p - str + 1;
- doFree = false;
- name.s = var;
- name.e = var + (p-str);
-
- /* val won't be freed since doFree == false, but
- * VarModifiers_Apply doesn't know that, hence the cast. */
- newval = VarModifiers_Apply((char *)val, &name, NULL, false,
- &doFree, p, endc, &length);
- Buf_AddString(buf, newval);
- if (doFree)
- free(newval);
- str += length;
- continue;
- } else
- str = p+1;
+ start = str;
+ if (*str++ == '\0')
+ break;
+ str++;
+ /* and escaped dollars */
+ if (start[1] == '$') {
+ Buf_Addi(buf, start, start+2);
+ continue;
+ }
+ /* Simple variable, if it's not us, copy. */
+ if (start[1] != '(' && start[1] != '{') {
+ if (start[1] != *var || var[1] != '\0') {
+ Buf_AddChars(buf, 2, start);
+ continue;
+ }
+ } else {
+ const char *p;
+ char paren = start[1];
+
+
+ /* Find the end of the variable specification. */
+ p = find_pos(paren)(str);
+ /* A variable inside the variable. We don't know how to
+ * expand the external variable at this point, so we
+ * try again with the nested variable. */
+ if (*p == '$') {
+ Buf_Addi(buf, start, p);
+ str = p;
+ continue;
+ }
+
+ if (strncmp(var, str, p - str) != 0 ||
+ var[p - str] != '\0') {
+ /* Not the variable we want to expand. */
+ Buf_Addi(buf, start, p);
+ str = p;
+ continue;
+ }
+ if (*p == ':') {
+ size_t length; /* Length of variable name */
+ bool doFree; /* should val be freed ? */
+ char *newval;
+ struct Name name;
+
+ length = p - str + 1;
+ doFree = false;
+ name.s = var;
+ name.e = var + (p-str);
+
+ /* val won't be freed since !doFree, but
+ * VarModifiers_Apply doesn't know that,
+ * hence the cast. */
+ newval = VarModifiers_Apply((char *)val, &name,
+ NULL, false, &doFree, p, paren, &length);
+ Buf_AddString(buf, newval);
+ if (doFree)
+ free(newval);
+ str += length;
+ continue;
+ } else
+ str = p+1;
+ }
+ Buf_AddString(buf, val);
}
- Buf_AddString(buf, val);
- }
- *me = old;
}
+/***
+ *** Odds and ends
+ ***/
+
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);
+ const char *name = "SHELL";
+ const char *ename = NULL;
+ uint32_t k;
+ Var *v;
+
+ k = ohash_interval(name, &ename);
+ v = find_global_var_without_env(name, ename, k);
+ var_set_value(v, _PATH_BSHELL);
+ /* XXX the environment shall never affect it */
+ v->flags = VAR_SHELL | VAR_SEEN_ENV;
}
-/*-
- *-----------------------------------------------------------------------
- * Var_Init --
+/*
+ * Var_Init
* Initialize the module
- *
- * Side Effects:
- * The CTXT_CMD and CTXT_GLOBAL contexts are initialized
- *-----------------------------------------------------------------------
*/
void
Var_Init(void)
{
- ohash_init(&global_variables, 10, &var_info);
- set_magic_shell_variable();
+ ohash_init(&global_variables, 10, &var_info);
+ set_magic_shell_variable();
- errorIsOkay = true;
- Var_setCheckEnvFirst(false);
+ errorIsOkay = true;
+ Var_setCheckEnvFirst(false);
- VarModifiers_Init();
+ VarModifiers_Init();
}
@@ -1098,12 +1229,12 @@ Var_Init(void)
void
Var_End(void)
{
- Var *v;
- unsigned int i;
+ Var *v;
+ unsigned int i;
- for (v = ohash_first(&global_variables, &i); v != NULL;
- v = ohash_next(&global_variables, &i))
- VarDelete(v);
+ for (v = ohash_first(&global_variables, &i); v != NULL;
+ v = ohash_next(&global_variables, &i))
+ delete_var(v);
}
#endif
@@ -1112,64 +1243,66 @@ static const char *interpret(int);
static const char *
interpret(int f)
{
- if (f & VAR_DUMMY)
- return "(D)";
- return "";
+ if (f & VAR_DUMMY)
+ return "(D)";
+ return "";
}
-/****************** PRINT DEBUGGING INFO *****************/
static void
-VarPrintVar(Var *v)
+print_var(Var *v)
{
- printf("%-16s%s = %s\n", v->name, interpret(v->flags),
- (v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)");
+ printf("%-16s%s = %s\n", v->name, interpret(v->flags),
+ (v->flags & VAR_DUMMY) == 0 ? var_get_value(v) : "(none)");
}
void
Var_Dump(void)
{
- Var *v;
- unsigned int i;
-
- printf("#*** Global Variables:\n");
+ Var *v;
+ unsigned int i;
- for (v = ohash_first(&global_variables, &i); v != NULL;
- v = ohash_next(&global_variables, &i))
- VarPrintVar(v);
+ printf("#*** Global Variables:\n");
+ for (v = ohash_first(&global_variables, &i); v != NULL;
+ v = ohash_next(&global_variables, &i))
+ print_var(v);
}
static const char *quotable = " \t\n\\'\"";
-/* In POSIX mode, variable assignments passed on the command line are
+/* POSIX says that variable assignments passed on the command line should be
* propagated to sub makes through MAKEFLAGS.
*/
void
Var_AddCmdline(const char *name)
{
- Var *v;
- unsigned int i;
- BUFFER buf;
- char *s;
-
- Buf_Init(&buf, MAKE_BSIZE);
-
- for (v = ohash_first(&global_variables, &i); v != NULL;
- v = ohash_next(&global_variables, &i)) {
+ Var *v;
+ unsigned int i;
+ BUFFER buf;
+ char *s;
+
+ Buf_Init(&buf, MAKE_BSIZE);
+
+ for (v = ohash_first(&global_variables, &i); v != NULL;
+ v = ohash_next(&global_variables, &i)) {
+ /* This is not as expensive as it looks: this function is
+ * called before parsing Makefiles, so there are just a
+ * few non cmdling variables in there.
+ */
if (!(v->flags & VAR_FROM_CMD)) {
continue;
}
/* We assume variable names don't need quoting */
Buf_AddString(&buf, v->name);
Buf_AddChar(&buf, '=');
- for (s = VarValue(v); *s != '\0'; s++) {
+ for (s = var_get_value(v); *s != '\0'; s++) {
if (strchr(quotable, *s))
Buf_AddChar(&buf, '\\');
Buf_AddChar(&buf, *s);
}
Buf_AddSpace(&buf);
- }
- Var_Append(name, Buf_Retrieve(&buf), VAR_GLOBAL);
- Buf_Destroy(&buf);
+ }
+ Var_Append(name, Buf_Retrieve(&buf), VAR_GLOBAL);
+ Buf_Destroy(&buf);
}
diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h
index 01c15efd13a..c53c777feda 100644
--- a/usr.bin/make/var.h
+++ b/usr.bin/make/var.h
@@ -34,16 +34,19 @@ extern void Var_End(void);
extern void Var_setCheckEnvFirst(bool);
-/* Global contexts handling. */
+/* Global variable 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 */
+
+/* isDefined = Var_Definedi(name, end);
+ * Checks whether global variable name/end 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. */
+ * Sets value val of variable name/end. Copies val.
+ * ctxt can be VAR_CMD (command line) or VAR_GLOBAL (normal variable). */
extern void Var_Seti(const char *, const char *, const char *,
int);
#define Var_Set(n, v, ctxt) Var_Seti(n, NULL, v, ctxt)
@@ -54,11 +57,11 @@ extern void Var_Appendi(const char *, const char *,
const char *, int);
#define Var_Append(n, v, ctxt) Var_Appendi(n, NULL, v, ctxt)
-/* Var_Delete(name);
- * Deletes a variable from the global context. */
-extern void Var_Delete(const char *);
+/* Var_Deletei(name, end);
+ * Deletes a global variable. */
+extern void Var_Deletei(const char *, const char *);
-/* Local context handling */
+/* Dynamic variable indices */
#define TARGET_INDEX 0
#define PREFIX_INDEX 1
#define ARCHIVE_INDEX 2
@@ -66,8 +69,14 @@ extern void Var_Delete(const char *);
#define OODATE_INDEX 4
#define ALLSRC_INDEX 5
#define IMPSRC_INDEX 6
+/* value = Varq_Value(index, node);
+ * Returns value of dynamic variable for a given node. */
extern char *Varq_Value(int, GNode *);
+/* Varq_Set(index, val, node);
+ * Sets value of dynamic variable for a given node. Copies val. */
extern void Varq_Set(int, const char *, GNode *);
+/* Varq_Append(index, val, node);
+ * Appends to value of dynamic variable for a given node. */
extern void Varq_Append(int, const char *, GNode *);
/* SymTable_Init(t);
@@ -112,14 +121,22 @@ extern bool Var_ParseBuffer(Buffer, const char *, SymTable *,
* encountered. The result is always a copy that should be free. */
extern char *Var_Subst(const char *, SymTable *, bool);
-/* Var_SubstVar(buf, str, varname, val);
- * Substitutes variable varname with value val in string str, adding
- * the result to buffer buf. undefs are never error. */
-extern void Var_SubstVar(Buffer, const char *, const char *, const char *);
-/* Note that substituting to a buffer in Var_Subst is not useful. On the
- * other hand, handling intervals in Var_Subst and Var_Parse would be
- * useful, but this is hard. */
+/* For loop handling.
+ * // Create handle for variable name.
+ * handle = Var_NewLoopVar(name, end);
+ * // set up buffer
+ * for (...)
+ * // Substitute val for variable in str, and accumulate in buffer
+ * Var_SubstVar(buffer, str, handle, val);
+ * // Free handle
+ * Var_DeleteLoopVar(handle);
+ */
+struct LoopVar; /* opaque handle */
+struct LoopVar *Var_NewLoopVar(const char *, const char *);
+void Var_DeleteLoopVar(struct LoopVar *);
+extern void Var_SubstVar(Buffer, const char *, struct LoopVar *, const char *);
+
/* Var_Dump();
* Print out all global variables. */
@@ -133,13 +150,13 @@ extern void Var_AddCmdline(const char *);
/* stuff common to var.c and varparse.c */
extern bool errorIsOkay;
-#define VAR_GLOBAL 0
+#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_INVALID 0
+#define POISON_DEFINED 1
#define POISON_NORMAL 64
#define POISON_EMPTY 128
#define POISON_NOT_DEFINED 256
diff --git a/usr.bin/make/varmodifiers.c b/usr.bin/make/varmodifiers.c
index 09957c5b4ab..2a24ef7f1e5 100644
--- a/usr.bin/make/varmodifiers.c
+++ b/usr.bin/make/varmodifiers.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: varmodifiers.c,v 1.14 2005/07/15 20:43:23 espie Exp $ */
+/* $OpenBSD: varmodifiers.c,v 1.15 2007/07/20 12:32:45 espie Exp $ */
/* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */
/*
@@ -112,9 +112,8 @@ typedef struct {
} VarPattern;
struct LoopStuff {
- char *var;
+ struct LoopVar *var;
char *expand;
- SymTable *ctxt;
bool err;
};
@@ -423,7 +422,7 @@ finish_loop(const char *s, const struct Name *n UNUSED , void *p)
{
struct LoopStuff *l = (struct LoopStuff *)p;
- return Var_Subst(s, l->ctxt, l->err);
+ return Var_Subst(s, NULL, l->err);
}
static int
@@ -1173,7 +1172,7 @@ free_looparg(void *arg)
{
struct LoopStuff *l = (struct LoopStuff *)arg;
- free(l->var);
+ Var_DeleteLoopVar(l->var);
free(l->expand);
}
@@ -1198,18 +1197,19 @@ get_loop(const char **p, SymTable *ctxt, bool err, int endc)
{
static struct LoopStuff loop;
const char *s;
+ const char *var;
s = *p +1;
loop.var = NULL;
loop.expand = NULL;
- loop.ctxt =ctxt;
loop.err = err;
- loop.var = LoopGrab(&s);
- if (loop.var != NULL) {
+ var = LoopGrab(&s);
+ if (var != NULL) {
loop.expand = LoopGrab(&s);
if (*s == endc || *s == ':') {
*p = s;
+ loop.var = Var_NewLoopVar(var, NULL);
return &loop;
}
}
@@ -1372,10 +1372,11 @@ do_regex(const char *s, const struct Name *n UNUSED, void *arg)
char *
VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
- bool err, bool *freePtr, const char *start, int endc, size_t *lengthPtr)
+ bool err, bool *freePtr, const char *start, int paren, size_t *lengthPtr)
{
const char *tstr;
bool atstart; /* Some ODE modifiers only make sense at start */
+ char endc = paren == '(' ? ')' : '}';
tstr = start;
/*
diff --git a/usr.bin/make/varmodifiers.h b/usr.bin/make/varmodifiers.h
index 590e86fa612..f64f88f172a 100644
--- a/usr.bin/make/varmodifiers.h
+++ b/usr.bin/make/varmodifiers.h
@@ -2,7 +2,7 @@
#define VARMODIFIERS_H
/* $OpenPackages$ */
-/* $OpenBSD: varmodifiers.h,v 1.3 2001/05/23 12:34:52 espie Exp $ */
+/* $OpenBSD: varmodifiers.h,v 1.4 2007/07/20 12:32:45 espie Exp $ */
/*
* Copyright (c) 1999 Marc Espie.
@@ -38,9 +38,9 @@ extern void VarModifiers_Init(void);
/* result = VarModifiers_Apply(val, name, ctxt, undef_is_bad,
- * &should_free, modstart, endc, &length);
+ * &should_free, modstart, paren, &length);
* Applies variable modifiers starting at modstart (including :),
- * ending with character endc, to value val.
+ * using parenthesis paren, to value val.
* Variables in spec are taken from context ctxt.
* If undef_is_bad, error occurs if undefined variables are mentioned.
* length is filled with the total length of the modifier spec.