Module Name: src
Committed By: rillig
Date: Sat Dec 5 14:28:09 UTC 2020
Modified Files:
src/usr.bin/make: var.c
Log Message:
make(1): indent large parts of var.c with tabs instead of spaces
The few remaining functions need to be cleaned up before being indented
further, to reduce the overall indentation.
To generate a diff of this commit:
cvs rdiff -u -r1.702 -r1.703 src/usr.bin/make/var.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.702 src/usr.bin/make/var.c:1.703
--- src/usr.bin/make/var.c:1.702 Sat Dec 5 13:01:33 2020
+++ src/usr.bin/make/var.c Sat Dec 5 14:28:09 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.702 2020/12/05 13:01:33 rillig Exp $ */
+/* $NetBSD: var.c,v 1.703 2020/12/05 14:28:09 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -130,7 +130,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.702 2020/12/05 13:01:33 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.703 2020/12/05 14:28:09 rillig Exp $");
#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
@@ -189,31 +189,42 @@ GNode *VAR_CMDLINE; /* variable
typedef enum VarFlags {
- /* The variable's value is currently being used by Var_Parse or Var_Subst.
- * This marker is used to avoid endless recursion. */
- VAR_IN_USE = 0x01,
-
- /* The variable comes from the environment.
- * These variables are not registered in any GNode, therefore they must
- * be freed as soon as they are not used anymore. */
- VAR_FROM_ENV = 0x02,
-
- /* The variable is exported to the environment, to be used by child
- * processes. */
- VAR_EXPORTED = 0x10,
-
- /* At the point where this variable was exported, it contained an
- * unresolved reference to another variable. Before any child process is
- * started, it needs to be exported again, in the hope that the referenced
- * variable can then be resolved. */
- VAR_REEXPORT = 0x20,
-
- /* The variable came from the command line. */
- VAR_FROM_CMD = 0x40,
-
- /* The variable value cannot be changed anymore, and the variable cannot
- * be deleted. Any attempts to do so are ignored. */
- VAR_READONLY = 0x80
+ /*
+ * The variable's value is currently being used by Var_Parse or
+ * Var_Subst. This marker is used to avoid endless recursion.
+ */
+ VAR_IN_USE = 0x01,
+
+ /*
+ * The variable comes from the environment.
+ * These variables are not registered in any GNode, therefore they
+ * must be freed as soon as they are not used anymore.
+ */
+ VAR_FROM_ENV = 0x02,
+
+ /*
+ * The variable is exported to the environment, to be used by child
+ * processes.
+ */
+ VAR_EXPORTED = 0x10,
+
+ /*
+ * At the point where this variable was exported, it contained an
+ * unresolved reference to another variable. Before any child
+ * process is started, it needs to be exported again, in the hope
+ * that the referenced variable can then be resolved.
+ */
+ VAR_REEXPORT = 0x20,
+
+ /* The variable came from the command line. */
+ VAR_FROM_CMD = 0x40,
+
+ /*
+ * The variable value cannot be changed anymore, and the variable
+ * cannot be deleted. Any attempts to do so are silently ignored,
+ * they are logged with -dv though.
+ */
+ VAR_READONLY = 0x80
} VarFlags;
ENUM_FLAGS_RTTI_6(VarFlags,
@@ -239,110 +250,118 @@ ENUM_FLAGS_RTTI_6(VarFlags,
* as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
*/
typedef struct Var {
- /* The name of the variable, once set, doesn't change anymore.
- * For context variables, it aliases the corresponding HashEntry name.
- * For environment and undefined variables, it is allocated. */
- const char *name;
- void *name_freeIt;
+ /*
+ * The name of the variable, once set, doesn't change anymore.
+ * For context variables, it aliases the corresponding HashEntry name.
+ * For environment and undefined variables, it is allocated.
+ */
+ const char *name;
+ void *name_freeIt;
- Buffer val; /* its value */
- VarFlags flags; /* miscellaneous status flags */
+ /* The unexpanded value of the variable. */
+ Buffer val;
+ /* Miscellaneous status flags. */
+ VarFlags flags;
} Var;
/*
* Exporting vars is expensive so skip it if we can
*/
typedef enum VarExportedMode {
- VAR_EXPORTED_NONE,
- VAR_EXPORTED_SOME,
- VAR_EXPORTED_ALL
+ VAR_EXPORTED_NONE,
+ VAR_EXPORTED_SOME,
+ VAR_EXPORTED_ALL
} VarExportedMode;
static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
typedef enum VarExportFlags {
- VAR_EXPORT_NORMAL = 0,
- /*
- * We pass this to Var_Export when doing the initial export
- * or after updating an exported var.
- */
- VAR_EXPORT_PARENT = 0x01,
- /*
- * We pass this to Var_Export1 to tell it to leave the value alone.
- */
- VAR_EXPORT_LITERAL = 0x02
+ VAR_EXPORT_NORMAL = 0,
+ /*
+ * We pass this to Var_Export when doing the initial export
+ * or after updating an exported var.
+ */
+ VAR_EXPORT_PARENT = 0x01,
+ /*
+ * We pass this to Var_Export1 to tell it to leave the value alone.
+ */
+ VAR_EXPORT_LITERAL = 0x02
} VarExportFlags;
/* Flags for pattern matching in the :S and :C modifiers */
typedef enum VarPatternFlags {
- VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
- VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
- VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
- VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
+ /* Replace as often as possible ('g') */
+ VARP_SUB_GLOBAL = 1 << 0,
+ /* Replace only once ('1') */
+ VARP_SUB_ONE = 1 << 1,
+ /* Match at start of word ('^') */
+ VARP_ANCHOR_START = 1 << 2,
+ /* Match at end of word ('$') */
+ VARP_ANCHOR_END = 1 << 3
} VarPatternFlags;
static Var *
VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
{
- size_t value_len = strlen(value);
- Var *var = bmake_malloc(sizeof *var);
- var->name = name;
- var->name_freeIt = name_freeIt;
- Buf_InitSize(&var->val, value_len + 1);
- Buf_AddBytes(&var->val, value, value_len);
- var->flags = flags;
- return var;
+ size_t value_len = strlen(value);
+ Var *var = bmake_malloc(sizeof *var);
+ var->name = name;
+ var->name_freeIt = name_freeIt;
+ Buf_InitSize(&var->val, value_len + 1);
+ Buf_AddBytes(&var->val, value, value_len);
+ var->flags = flags;
+ return var;
}
static const char *
CanonicalVarname(const char *name)
{
- if (*name == '.' && ch_isupper(name[1])) {
- switch (name[1]) {
- case 'A':
- if (strcmp(name, ".ALLSRC") == 0)
- name = ALLSRC;
- if (strcmp(name, ".ARCHIVE") == 0)
- name = ARCHIVE;
- break;
- case 'I':
- if (strcmp(name, ".IMPSRC") == 0)
- name = IMPSRC;
- break;
- case 'M':
- if (strcmp(name, ".MEMBER") == 0)
- name = MEMBER;
- break;
- case 'O':
- if (strcmp(name, ".OODATE") == 0)
- name = OODATE;
- break;
- case 'P':
- if (strcmp(name, ".PREFIX") == 0)
- name = PREFIX;
- break;
- case 'S':
- if (strcmp(name, ".SHELL") == 0) {
- if (!shellPath)
- Shell_Init();
- }
- break;
- case 'T':
- if (strcmp(name, ".TARGET") == 0)
- name = TARGET;
- break;
+ if (*name == '.' && ch_isupper(name[1])) {
+ switch (name[1]) {
+ case 'A':
+ if (strcmp(name, ".ALLSRC") == 0)
+ name = ALLSRC;
+ if (strcmp(name, ".ARCHIVE") == 0)
+ name = ARCHIVE;
+ break;
+ case 'I':
+ if (strcmp(name, ".IMPSRC") == 0)
+ name = IMPSRC;
+ break;
+ case 'M':
+ if (strcmp(name, ".MEMBER") == 0)
+ name = MEMBER;
+ break;
+ case 'O':
+ if (strcmp(name, ".OODATE") == 0)
+ name = OODATE;
+ break;
+ case 'P':
+ if (strcmp(name, ".PREFIX") == 0)
+ name = PREFIX;
+ break;
+ case 'S':
+ if (strcmp(name, ".SHELL") == 0) {
+ if (!shellPath)
+ Shell_Init();
+ }
+ break;
+ case 'T':
+ if (strcmp(name, ".TARGET") == 0)
+ name = TARGET;
+ break;
+ }
}
- }
- /* GNU make has an additional alias $^ == ${.ALLSRC}. */
+ /* GNU make has an additional alias $^ == ${.ALLSRC}. */
- return name;
+ return name;
}
static Var *
GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
{
- return HashTable_FindValueHash(&ctxt->vars, varname, hash);
+ return HashTable_FindValueHash(&ctxt->vars, varname, hash);
}
/* Find the variable in the context, and maybe in other contexts as well.
@@ -360,55 +379,58 @@ GNode_FindVar(GNode *ctxt, const char *v
static Var *
VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
{
- Var *var;
- unsigned int nameHash;
+ Var *var;
+ unsigned int nameHash;
- /*
- * If the variable name begins with a '.', it could very well be one of
- * the local ones. We check the name against all the local variables
- * and substitute the short version in for 'name' if it matches one of
- * them.
- */
- name = CanonicalVarname(name);
- nameHash = Hash_Hash(name);
+ /*
+ * If the variable name begins with a '.', it could very well be
+ * one of the local ones. We check the name against all the local
+ * variables and substitute the short version in for 'name' if it
+ * matches one of them.
+ */
+ name = CanonicalVarname(name);
+ nameHash = Hash_Hash(name);
- /* First look for the variable in the given context. */
- var = GNode_FindVar(ctxt, name, nameHash);
- if (!elsewhere)
- return var;
+ /* First look for the variable in the given context. */
+ var = GNode_FindVar(ctxt, name, nameHash);
+ if (!elsewhere)
+ return var;
+
+ /*
+ * The variable was not found in the given context.
+ * Now look for it in the other contexts as well.
+ */
+ if (var == NULL && ctxt != VAR_CMDLINE)
+ var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
- /* The variable was not found in the given context. Now look for it in
- * the other contexts as well. */
- if (var == NULL && ctxt != VAR_CMDLINE)
- var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
-
- if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
- var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
- if (var == NULL && ctxt != VAR_INTERNAL) {
- /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
- var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
+ if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
+ var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
+ if (var == NULL && ctxt != VAR_INTERNAL) {
+ /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
+ var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
+ }
}
- }
- if (var == NULL) {
- char *env;
+ if (var == NULL) {
+ char *env;
- if ((env = getenv(name)) != NULL) {
- char *varname = bmake_strdup(name);
- return VarNew(varname, varname, env, VAR_FROM_ENV);
- }
+ if ((env = getenv(name)) != NULL) {
+ char *varname = bmake_strdup(name);
+ return VarNew(varname, varname, env, VAR_FROM_ENV);
+ }
- if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
- var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
- if (var == NULL && ctxt != VAR_INTERNAL)
- var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
- return var;
- }
+ if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
+ var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
+ if (var == NULL && ctxt != VAR_INTERNAL)
+ var = GNode_FindVar(VAR_INTERNAL, name,
+ nameHash);
+ return var;
+ }
- return NULL;
- }
+ return NULL;
+ }
- return var;
+ return var;
}
/* If the variable is an environment variable, free it.
@@ -423,13 +445,13 @@ VarFind(const char *name, GNode *ctxt, B
static Boolean
VarFreeEnv(Var *v, Boolean freeValue)
{
- if (!(v->flags & VAR_FROM_ENV))
- return FALSE;
+ if (!(v->flags & VAR_FROM_ENV))
+ return FALSE;
- free(v->name_freeIt);
- Buf_Destroy(&v->val, freeValue);
- free(v);
- return TRUE;
+ free(v->name_freeIt);
+ Buf_Destroy(&v->val, freeValue);
+ free(v);
+ return TRUE;
}
/* Add a new variable of the given name and value to the given context.
@@ -437,13 +459,13 @@ VarFreeEnv(Var *v, Boolean freeValue)
static void
VarAdd(const char *name, const char *val, GNode *ctxt, VarSetFlags flags)
{
- HashEntry *he = HashTable_CreateEntry(&ctxt->vars, name, NULL);
- Var *v = VarNew(he->key /* aliased */, NULL, val,
- flags & VAR_SET_READONLY ? VAR_READONLY : 0);
- HashEntry_Set(he, v);
- if (!(ctxt->flags & INTERNAL)) {
- VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
- }
+ HashEntry *he = HashTable_CreateEntry(&ctxt->vars, name, NULL);
+ Var *v = VarNew(he->key /* aliased */, NULL, val,
+ flags & VAR_SET_READONLY ? VAR_READONLY : 0);
+ HashEntry_Set(he, v);
+ if (!(ctxt->flags & INTERNAL)) {
+ VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
+ }
}
/* Remove a variable from a context, freeing all related memory as well.
@@ -451,59 +473,60 @@ VarAdd(const char *name, const char *val
void
Var_Delete(const char *name, GNode *ctxt)
{
- char *name_freeIt = NULL;
- HashEntry *he;
+ char *name_freeIt = NULL;
+ HashEntry *he;
- if (strchr(name, '$') != NULL) {
- (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
- /* TODO: handle errors */
- name = name_freeIt;
- }
- he = HashTable_FindEntry(&ctxt->vars, name);
- VAR_DEBUG3("%s:delete %s%s\n",
- ctxt->name, name, he != NULL ? "" : " (not found)");
- free(name_freeIt);
+ if (strchr(name, '$') != NULL) {
+ (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
+ /* TODO: handle errors */
+ name = name_freeIt;
+ }
+ he = HashTable_FindEntry(&ctxt->vars, name);
+ VAR_DEBUG3("%s:delete %s%s\n",
+ ctxt->name, name, he != NULL ? "" : " (not found)");
+ free(name_freeIt);
- if (he != NULL) {
- Var *v = HashEntry_Get(he);
- if (v->flags & VAR_EXPORTED)
- unsetenv(v->name);
- if (strcmp(v->name, MAKE_EXPORTED) == 0)
- var_exportedVars = VAR_EXPORTED_NONE;
- assert(v->name_freeIt == NULL);
- HashTable_DeleteEntry(&ctxt->vars, he);
- Buf_Destroy(&v->val, TRUE);
- free(v);
- }
+ if (he != NULL) {
+ Var *v = HashEntry_Get(he);
+ if (v->flags & VAR_EXPORTED)
+ unsetenv(v->name);
+ if (strcmp(v->name, MAKE_EXPORTED) == 0)
+ var_exportedVars = VAR_EXPORTED_NONE;
+ assert(v->name_freeIt == NULL);
+ HashTable_DeleteEntry(&ctxt->vars, he);
+ Buf_Destroy(&v->val, TRUE);
+ free(v);
+ }
}
static Boolean
MayExport(const char *name)
{
- if (name[0] == '.')
- return FALSE; /* skip internals */
- if (name[0] == '-')
- return FALSE; /* skip misnamed variables */
- if (name[1] == '\0') {
- /*
- * A single char.
- * If it is one of the vars that should only appear in
- * local context, skip it, else we can get Var_Subst
- * into a loop.
- */
- switch (name[0]) {
- case '@':
- case '%':
- case '*':
- case '!':
- return FALSE;
+ if (name[0] == '.')
+ return FALSE; /* skip internals */
+ if (name[0] == '-')
+ return FALSE; /* skip misnamed variables */
+ if (name[1] == '\0') {
+ /*
+ * A single char.
+ * If it is one of the vars that should only appear in
+ * local context, skip it, else we can get Var_Subst
+ * into a loop.
+ */
+ switch (name[0]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ return FALSE;
+ }
}
- }
- return TRUE;
+ return TRUE;
}
/*
* Export a single variable.
+ *
* We ignore make internal variables (those which start with '.').
* Also we jump through some hoops to avoid calling setenv
* more than necessary since it can leak.
@@ -512,62 +535,60 @@ MayExport(const char *name)
static Boolean
Var_Export1(const char *name, VarExportFlags flags)
{
- Boolean parent = (flags & VAR_EXPORT_PARENT) != 0;
- Var *v;
- char *val;
+ Boolean parent = (flags & VAR_EXPORT_PARENT) != 0;
+ Var *v;
+ char *val;
- if (!MayExport(name))
- return FALSE;
+ if (!MayExport(name))
+ return FALSE;
- v = VarFind(name, VAR_GLOBAL, FALSE);
- if (v == NULL)
- return FALSE;
+ v = VarFind(name, VAR_GLOBAL, FALSE);
+ if (v == NULL)
+ return FALSE;
- if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
- return FALSE; /* nothing to do */
+ if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
+ return FALSE; /* nothing to do */
- val = Buf_GetAll(&v->val, NULL);
- if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
- char *expr;
+ val = Buf_GetAll(&v->val, NULL);
+ if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
+ char *expr;
+
+ if (parent) {
+ /*
+ * Flag the variable as something we need to re-export.
+ * No point actually exporting it now though,
+ * the child process can do it at the last minute.
+ */
+ v->flags |= VAR_EXPORTED | VAR_REEXPORT;
+ return TRUE;
+ }
+ if (v->flags & VAR_IN_USE) {
+ /*
+ * We recursed while exporting in a child.
+ * This isn't going to end well, just skip it.
+ */
+ return FALSE;
+ }
- if (parent) {
- /*
- * Flag the variable as something we need to re-export.
- * No point actually exporting it now though,
- * the child process can do it at the last minute.
- */
- v->flags |= VAR_EXPORTED | VAR_REEXPORT;
- return TRUE;
- }
- if (v->flags & VAR_IN_USE) {
- /*
- * We recursed while exporting in a child.
- * This isn't going to end well, just skip it.
- */
- return FALSE;
+ /* XXX: name is injected without escaping it */
+ expr = str_concat3("${", name, "}");
+ (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
+ /* TODO: handle errors */
+ setenv(name, val, 1);
+ free(val);
+ free(expr);
+ } else {
+ if (parent)
+ v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
+ if (parent || !(v->flags & VAR_EXPORTED))
+ setenv(name, val, 1);
}
- /* XXX: name is injected without escaping it */
- expr = str_concat3("${", name, "}");
- (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
- /* TODO: handle errors */
- setenv(name, val, 1);
- free(val);
- free(expr);
- } else {
+ /* This is so Var_Set knows to call Var_Export again. */
if (parent)
- v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
- if (parent || !(v->flags & VAR_EXPORTED))
- setenv(name, val, 1);
- }
+ v->flags |= VAR_EXPORTED;
- /*
- * This is so Var_Set knows to call Var_Export again...
- */
- if (parent) {
- v->flags |= VAR_EXPORTED;
- }
- return TRUE;
+ return TRUE;
}
/*
@@ -576,44 +597,45 @@ Var_Export1(const char *name, VarExportF
void
Var_ExportVars(void)
{
- char *val;
+ char *val;
- /*
- * Several make's support this sort of mechanism for tracking
- * recursion - but each uses a different name.
- * We allow the makefiles to update MAKELEVEL and ensure
- * children see a correctly incremented value.
- */
- char tmp[BUFSIZ];
- snprintf(tmp, sizeof tmp, "%d", makelevel + 1);
- setenv(MAKE_LEVEL_ENV, tmp, 1);
+ /*
+ * Several make implementations support this sort of mechanism for
+ * tracking recursion - but each uses a different name.
+ * We allow the makefiles to update MAKELEVEL and ensure
+ * children see a correctly incremented value.
+ */
+ char tmp[BUFSIZ];
+ snprintf(tmp, sizeof tmp, "%d", makelevel + 1);
+ setenv(MAKE_LEVEL_ENV, tmp, 1);
- if (var_exportedVars == VAR_EXPORTED_NONE)
- return;
+ if (var_exportedVars == VAR_EXPORTED_NONE)
+ return;
- if (var_exportedVars == VAR_EXPORTED_ALL) {
- HashIter hi;
+ if (var_exportedVars == VAR_EXPORTED_ALL) {
+ HashIter hi;
- /* Ouch! Exporting all variables at once is crazy... */
- HashIter_Init(&hi, &VAR_GLOBAL->vars);
- while (HashIter_Next(&hi) != NULL) {
- Var *var = hi.entry->value;
- Var_Export1(var->name, VAR_EXPORT_NORMAL);
+ /* Ouch! Exporting all variables at once is crazy... */
+ HashIter_Init(&hi, &VAR_GLOBAL->vars);
+ while (HashIter_Next(&hi) != NULL) {
+ Var *var = hi.entry->value;
+ Var_Export1(var->name, VAR_EXPORT_NORMAL);
+ }
+ return;
}
- return;
- }
- (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
- /* TODO: handle errors */
- if (val[0] != '\0') {
- Words words = Str_Words(val, FALSE);
- size_t i;
-
- for (i = 0; i < words.len; i++)
- Var_Export1(words.words[i], VAR_EXPORT_NORMAL);
- Words_Free(words);
- }
- free(val);
+ (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
+ &val);
+ /* TODO: handle errors */
+ if (val[0] != '\0') {
+ Words words = Str_Words(val, FALSE);
+ size_t i;
+
+ for (i = 0; i < words.len; i++)
+ Var_Export1(words.words[i], VAR_EXPORT_NORMAL);
+ Words_Free(words);
+ }
+ free(val);
}
/*
@@ -627,43 +649,44 @@ Var_ExportVars(void)
void
Var_Export(const char *str, Boolean isExport)
{
- VarExportFlags flags;
- char *val;
+ VarExportFlags flags;
+ char *val;
- if (isExport && str[0] == '\0') {
- var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
- return;
- }
+ if (isExport && str[0] == '\0') {
+ var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
+ return;
+ }
- if (isExport && strncmp(str, "-env", 4) == 0) {
- str += 4;
- flags = 0;
- } else if (isExport && strncmp(str, "-literal", 8) == 0) {
- str += 8;
- flags = VAR_EXPORT_LITERAL;
- } else {
- flags = VAR_EXPORT_PARENT;
- }
+ if (isExport && strncmp(str, "-env", 4) == 0) {
+ str += 4;
+ flags = 0;
+ } else if (isExport && strncmp(str, "-literal", 8) == 0) {
+ str += 8;
+ flags = VAR_EXPORT_LITERAL;
+ } else {
+ flags = VAR_EXPORT_PARENT;
+ }
- (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
- /* TODO: handle errors */
- if (val[0] != '\0') {
- Words words = Str_Words(val, FALSE);
+ (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
+ /* TODO: handle errors */
+ if (val[0] != '\0') {
+ Words words = Str_Words(val, FALSE);
- size_t i;
- for (i = 0; i < words.len; i++) {
- const char *name = words.words[i];
- if (Var_Export1(name, flags)) {
- if (var_exportedVars == VAR_EXPORTED_NONE)
- var_exportedVars = VAR_EXPORTED_SOME;
- if (isExport && (flags & VAR_EXPORT_PARENT)) {
- Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
+ size_t i;
+ for (i = 0; i < words.len; i++) {
+ const char *name = words.words[i];
+ if (Var_Export1(name, flags)) {
+ if (var_exportedVars == VAR_EXPORTED_NONE)
+ var_exportedVars = VAR_EXPORTED_SOME;
+ if (isExport && (flags & VAR_EXPORT_PARENT)) {
+ Var_Append(MAKE_EXPORTED, name,
+ VAR_GLOBAL);
+ }
+ }
}
- }
+ Words_Free(words);
}
- Words_Free(words);
- }
- free(val);
+ free(val);
}
@@ -731,45 +754,45 @@ UnexportVar(const char *varname, Boolean
void
Var_UnExport(const char *str)
{
- const char *varnames;
- char *varnames_freeIt;
- Boolean unexport_env;
-
- varnames = NULL;
- varnames_freeIt = NULL;
-
- str += strlen("unexport");
- unexport_env = strncmp(str, "-env", 4) == 0;
- if (unexport_env) {
- UnexportEnv();
- } else {
- cpp_skip_whitespace(&str);
- if (str[0] != '\0')
- varnames = str;
- }
+ const char *varnames;
+ char *varnames_freeIt;
+ Boolean unexport_env;
+
+ varnames = NULL;
+ varnames_freeIt = NULL;
+
+ str += strlen("unexport");
+ unexport_env = strncmp(str, "-env", 4) == 0;
+ if (unexport_env) {
+ UnexportEnv();
+ } else {
+ cpp_skip_whitespace(&str);
+ if (str[0] != '\0')
+ varnames = str;
+ }
- if (varnames == NULL) {
- /* Using .MAKE.EXPORTED */
- (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
- &varnames_freeIt);
- /* TODO: handle errors */
- varnames = varnames_freeIt;
- }
+ if (varnames == NULL) {
+ /* Using .MAKE.EXPORTED */
+ (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
+ VARE_WANTRES, &varnames_freeIt);
+ /* TODO: handle errors */
+ varnames = varnames_freeIt;
+ }
- {
- size_t i;
+ {
+ size_t i;
- Words words = Str_Words(varnames, FALSE);
- for (i = 0; i < words.len; i++) {
- const char *varname = words.words[i];
- UnexportVar(varname, unexport_env, varnames == str);
- }
- Words_Free(words);
- if (varnames != str) {
- Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
- free(varnames_freeIt);
+ Words words = Str_Words(varnames, FALSE);
+ for (i = 0; i < words.len; i++) {
+ const char *varname = words.words[i];
+ UnexportVar(varname, unexport_env, varnames == str);
+ }
+ Words_Free(words);
+ if (varnames != str) {
+ Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
+ free(varnames_freeIt);
+ }
}
- }
}
/* See Var_Set for documentation. */
@@ -896,7 +919,7 @@ out:
void
Var_Set(const char *name, const char *val, GNode *ctxt)
{
- Var_SetWithFlags(name, val, ctxt, VAR_SET_NONE);
+ Var_SetWithFlags(name, val, ctxt, VAR_SET_NONE);
}
/*-
@@ -984,22 +1007,22 @@ Var_Append(const char *name, const char
Boolean
Var_Exists(const char *name, GNode *ctxt)
{
- char *name_freeIt = NULL;
- Var *v;
+ char *name_freeIt = NULL;
+ Var *v;
- if (strchr(name, '$') != NULL) {
- (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
- /* TODO: handle errors */
- name = name_freeIt;
- }
+ if (strchr(name, '$') != NULL) {
+ (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
+ /* TODO: handle errors */
+ name = name_freeIt;
+ }
- v = VarFind(name, ctxt, TRUE);
- free(name_freeIt);
- if (v == NULL)
- return FALSE;
+ v = VarFind(name, ctxt, TRUE);
+ free(name_freeIt);
+ if (v == NULL)
+ return FALSE;
- (void)VarFreeEnv(v, TRUE);
- return TRUE;
+ (void)VarFreeEnv(v, TRUE);
+ return TRUE;
}
/*-
@@ -1021,17 +1044,17 @@ Var_Exists(const char *name, GNode *ctxt
const char *
Var_Value(const char *name, GNode *ctxt, void **out_freeIt)
{
- Var *v = VarFind(name, ctxt, TRUE);
- char *value;
+ Var *v = VarFind(name, ctxt, TRUE);
+ char *value;
+
+ *out_freeIt = NULL;
+ if (v == NULL)
+ return NULL;
- *out_freeIt = NULL;
- if (v == NULL)
- return NULL;
-
- value = Buf_GetAll(&v->val, NULL);
- if (VarFreeEnv(v, FALSE))
- *out_freeIt = value;
- return value;
+ value = Buf_GetAll(&v->val, NULL);
+ if (VarFreeEnv(v, FALSE))
+ *out_freeIt = value;
+ return value;
}
/* Return the unexpanded variable value from this node, without trying to look
@@ -1039,60 +1062,61 @@ Var_Value(const char *name, GNode *ctxt,
const char *
Var_ValueDirect(const char *name, GNode *ctxt)
{
- Var *v = VarFind(name, ctxt, FALSE);
- return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
+ Var *v = VarFind(name, ctxt, FALSE);
+ return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
}
/* SepBuf is a string being built from words, interleaved with separators. */
typedef struct SepBuf {
- Buffer buf;
- Boolean needSep;
- char sep; /* usually ' ', but see the :ts modifier */
+ Buffer buf;
+ Boolean needSep;
+ /* Usually ' ', but see the ':ts' modifier. */
+ char sep;
} SepBuf;
static void
SepBuf_Init(SepBuf *buf, char sep)
{
- Buf_InitSize(&buf->buf, 32);
- buf->needSep = FALSE;
- buf->sep = sep;
+ Buf_InitSize(&buf->buf, 32);
+ buf->needSep = FALSE;
+ buf->sep = sep;
}
static void
SepBuf_Sep(SepBuf *buf)
{
- buf->needSep = TRUE;
+ buf->needSep = TRUE;
}
static void
SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
{
- if (mem_size == 0)
- return;
- if (buf->needSep && buf->sep != '\0') {
- Buf_AddByte(&buf->buf, buf->sep);
- buf->needSep = FALSE;
- }
- Buf_AddBytes(&buf->buf, mem, mem_size);
+ if (mem_size == 0)
+ return;
+ if (buf->needSep && buf->sep != '\0') {
+ Buf_AddByte(&buf->buf, buf->sep);
+ buf->needSep = FALSE;
+ }
+ Buf_AddBytes(&buf->buf, mem, mem_size);
}
static void
SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
{
- SepBuf_AddBytes(buf, start, (size_t)(end - start));
+ SepBuf_AddBytes(buf, start, (size_t)(end - start));
}
static void
SepBuf_AddStr(SepBuf *buf, const char *str)
{
- SepBuf_AddBytes(buf, str, strlen(str));
+ SepBuf_AddBytes(buf, str, strlen(str));
}
static char *
SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
{
- return Buf_Destroy(&buf->buf, free_buf);
+ return Buf_Destroy(&buf->buf, free_buf);
}
@@ -1110,11 +1134,11 @@ typedef void (*ModifyWordsCallback)(cons
static void
ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
{
- const char *slash = strrchr(word, '/');
- if (slash != NULL)
- SepBuf_AddBytesBetween(buf, word, slash);
- else
- SepBuf_AddStr(buf, ".");
+ const char *slash = strrchr(word, '/');
+ if (slash != NULL)
+ SepBuf_AddBytesBetween(buf, word, slash);
+ else
+ SepBuf_AddStr(buf, ".");
}
/* Callback for ModifyWords to implement the :T modifier.
@@ -1122,9 +1146,9 @@ ModifyWord_Head(const char *word, SepBuf
static void
ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
{
- const char *slash = strrchr(word, '/');
- const char *base = slash != NULL ? slash + 1 : word;
- SepBuf_AddStr(buf, base);
+ const char *slash = strrchr(word, '/');
+ const char *base = slash != NULL ? slash + 1 : word;
+ SepBuf_AddStr(buf, base);
}
/* Callback for ModifyWords to implement the :E modifier.
@@ -1132,9 +1156,9 @@ ModifyWord_Tail(const char *word, SepBuf
static void
ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
{
- const char *lastDot = strrchr(word, '.');
- if (lastDot != NULL)
- SepBuf_AddStr(buf, lastDot + 1);
+ const char *lastDot = strrchr(word, '.');
+ if (lastDot != NULL)
+ SepBuf_AddStr(buf, lastDot + 1);
}
/* Callback for ModifyWords to implement the :R modifier.
@@ -1142,9 +1166,9 @@ ModifyWord_Suffix(const char *word, SepB
static void
ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
{
- const char *lastDot = strrchr(word, '.');
- size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word);
- SepBuf_AddBytes(buf, word, len);
+ const char *lastDot = strrchr(word, '.');
+ size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word);
+ SepBuf_AddBytes(buf, word, len);
}
/* Callback for ModifyWords to implement the :M modifier.
@@ -1152,10 +1176,10 @@ ModifyWord_Root(const char *word, SepBuf
static void
ModifyWord_Match(const char *word, SepBuf *buf, void *data)
{
- const char *pattern = data;
- VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
- if (Str_Match(word, pattern))
- SepBuf_AddStr(buf, word);
+ const char *pattern = data;
+ VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
+ if (Str_Match(word, pattern))
+ SepBuf_AddStr(buf, word);
}
/* Callback for ModifyWords to implement the :N modifier.
@@ -1163,12 +1187,13 @@ ModifyWord_Match(const char *word, SepBu
static void
ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
{
- const char *pattern = data;
- if (!Str_Match(word, pattern))
- SepBuf_AddStr(buf, word);
+ const char *pattern = data;
+ if (!Str_Match(word, pattern))
+ SepBuf_AddStr(buf, word);
}
#ifdef SYSVVARSUB
+
/* Check word against pattern for a match (% is a wildcard).
*
* Input:
@@ -1182,105 +1207,107 @@ ModifyWord_NoMatch(const char *word, Sep
*/
static const char *
SysVMatch(const char *word, const char *pattern,
- size_t *out_match_len, Boolean *out_hasPercent)
+ size_t *out_match_len, Boolean *out_hasPercent)
{
- const char *p = pattern;
- const char *w = word;
- const char *percent;
- size_t w_len;
- size_t p_len;
- const char *w_tail;
-
- *out_hasPercent = FALSE;
- percent = strchr(p, '%');
- if (percent != NULL) { /* ${VAR:...%...=...} */
- *out_hasPercent = TRUE;
- if (w[0] == '\0')
- return NULL; /* empty word does not match pattern */
-
- /* check that the prefix matches */
- for (; p != percent && *w != '\0' && *w == *p; w++, p++)
- continue;
- if (p != percent)
- return NULL; /* No match */
-
- p++; /* Skip the percent */
- if (*p == '\0') {
- /* No more pattern, return the rest of the string */
- *out_match_len = strlen(w);
- return w;
+ const char *p = pattern;
+ const char *w = word;
+ const char *percent;
+ size_t w_len;
+ size_t p_len;
+ const char *w_tail;
+
+ *out_hasPercent = FALSE;
+ percent = strchr(p, '%');
+ if (percent != NULL) { /* ${VAR:...%...=...} */
+ *out_hasPercent = TRUE;
+ if (w[0] == '\0')
+ return NULL; /* empty word does not match pattern */
+
+ /* check that the prefix matches */
+ for (; p != percent && *w != '\0' && *w == *p; w++, p++)
+ continue;
+ if (p != percent)
+ return NULL; /* No match */
+
+ p++; /* Skip the percent */
+ if (*p == '\0') {
+ /* No more pattern, return the rest of the string */
+ *out_match_len = strlen(w);
+ return w;
+ }
}
- }
- /* Test whether the tail matches */
- w_len = strlen(w);
- p_len = strlen(p);
- if (w_len < p_len)
- return NULL;
-
- w_tail = w + w_len - p_len;
- if (memcmp(p, w_tail, p_len) != 0)
- return NULL;
+ /* Test whether the tail matches */
+ w_len = strlen(w);
+ p_len = strlen(p);
+ if (w_len < p_len)
+ return NULL;
+
+ w_tail = w + w_len - p_len;
+ if (memcmp(p, w_tail, p_len) != 0)
+ return NULL;
- *out_match_len = (size_t)(w_tail - w);
- return w;
+ *out_match_len = (size_t)(w_tail - w);
+ return w;
}
struct ModifyWord_SYSVSubstArgs {
- GNode *ctx;
- const char *lhs;
- const char *rhs;
+ GNode *ctx;
+ const char *lhs;
+ const char *rhs;
};
/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
static void
ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
{
- const struct ModifyWord_SYSVSubstArgs *args = data;
- char *rhs_expanded;
- const char *rhs;
- const char *percent;
-
- size_t match_len;
- Boolean lhsPercent;
- const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
- if (match == NULL) {
- SepBuf_AddStr(buf, word);
- return;
- }
+ const struct ModifyWord_SYSVSubstArgs *args = data;
+ char *rhs_expanded;
+ const char *rhs;
+ const char *percent;
+
+ size_t match_len;
+ Boolean lhsPercent;
+ const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
+ if (match == NULL) {
+ SepBuf_AddStr(buf, word);
+ return;
+ }
- /* Append rhs to the buffer, substituting the first '%' with the
- * match, but only if the lhs had a '%' as well. */
+ /*
+ * Append rhs to the buffer, substituting the first '%' with the
+ * match, but only if the lhs had a '%' as well.
+ */
- (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
- /* TODO: handle errors */
+ (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
+ /* TODO: handle errors */
- rhs = rhs_expanded;
- percent = strchr(rhs, '%');
+ rhs = rhs_expanded;
+ percent = strchr(rhs, '%');
- if (percent != NULL && lhsPercent) {
- /* Copy the prefix of the replacement pattern */
- SepBuf_AddBytesBetween(buf, rhs, percent);
- rhs = percent + 1;
- }
- if (percent != NULL || !lhsPercent)
- SepBuf_AddBytes(buf, match, match_len);
+ if (percent != NULL && lhsPercent) {
+ /* Copy the prefix of the replacement pattern */
+ SepBuf_AddBytesBetween(buf, rhs, percent);
+ rhs = percent + 1;
+ }
+ if (percent != NULL || !lhsPercent)
+ SepBuf_AddBytes(buf, match, match_len);
- /* Append the suffix of the replacement pattern */
- SepBuf_AddStr(buf, rhs);
+ /* Append the suffix of the replacement pattern */
+ SepBuf_AddStr(buf, rhs);
- free(rhs_expanded);
+ free(rhs_expanded);
}
#endif
struct ModifyWord_SubstArgs {
- const char *lhs;
- size_t lhsLen;
- const char *rhs;
- size_t rhsLen;
- VarPatternFlags pflags;
- Boolean matched;
+ const char *lhs;
+ size_t lhsLen;
+ const char *rhs;
+ size_t rhsLen;
+ VarPatternFlags pflags;
+ Boolean matched;
};
/* Callback for ModifyWords to implement the :S,from,to, modifier.
@@ -1288,60 +1315,61 @@ struct ModifyWord_SubstArgs {
static void
ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
{
- size_t wordLen = strlen(word);
- struct ModifyWord_SubstArgs *args = data;
- const char *match;
-
- if ((args->pflags & VARP_SUB_ONE) && args->matched)
- goto nosub;
-
- if (args->pflags & VARP_ANCHOR_START) {
- if (wordLen < args->lhsLen ||
- memcmp(word, args->lhs, args->lhsLen) != 0)
- goto nosub;
-
- if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
- goto nosub;
-
- /* :S,^prefix,replacement, or :S,^whole$,replacement, */
- SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
- SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
- args->matched = TRUE;
- return;
- }
+ size_t wordLen = strlen(word);
+ struct ModifyWord_SubstArgs *args = data;
+ const char *match;
+
+ if ((args->pflags & VARP_SUB_ONE) && args->matched)
+ goto nosub;
+
+ if (args->pflags & VARP_ANCHOR_START) {
+ if (wordLen < args->lhsLen ||
+ memcmp(word, args->lhs, args->lhsLen) != 0)
+ goto nosub;
+
+ if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
+ goto nosub;
+
+ /* :S,^prefix,replacement, or :S,^whole$,replacement, */
+ SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
+ SepBuf_AddBytes(buf, word + args->lhsLen,
+ wordLen - args->lhsLen);
+ args->matched = TRUE;
+ return;
+ }
- if (args->pflags & VARP_ANCHOR_END) {
- const char *start;
+ if (args->pflags & VARP_ANCHOR_END) {
+ const char *start;
- if (wordLen < args->lhsLen)
- goto nosub;
+ if (wordLen < args->lhsLen)
+ goto nosub;
- start = word + (wordLen - args->lhsLen);
- if (memcmp(start, args->lhs, args->lhsLen) != 0)
- goto nosub;
-
- /* :S,suffix$,replacement, */
- SepBuf_AddBytesBetween(buf, word, start);
- SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
- args->matched = TRUE;
- return;
- }
+ start = word + (wordLen - args->lhsLen);
+ if (memcmp(start, args->lhs, args->lhsLen) != 0)
+ goto nosub;
+
+ /* :S,suffix$,replacement, */
+ SepBuf_AddBytesBetween(buf, word, start);
+ SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
+ args->matched = TRUE;
+ return;
+ }
- if (args->lhs[0] == '\0')
- goto nosub;
+ if (args->lhs[0] == '\0')
+ goto nosub;
- /* unanchored case, may match more than once */
- while ((match = strstr(word, args->lhs)) != NULL) {
- SepBuf_AddBytesBetween(buf, word, match);
- SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
- args->matched = TRUE;
- wordLen -= (size_t)(match - word) + args->lhsLen;
- word += (size_t)(match - word) + args->lhsLen;
- if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
- break;
- }
+ /* unanchored case, may match more than once */
+ while ((match = strstr(word, args->lhs)) != NULL) {
+ SepBuf_AddBytesBetween(buf, word, match);
+ SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
+ args->matched = TRUE;
+ wordLen -= (size_t)(match - word) + args->lhsLen;
+ word += (size_t)(match - word) + args->lhsLen;
+ if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
+ break;
+ }
nosub:
- SepBuf_AddBytes(buf, word, wordLen);
+ SepBuf_AddBytes(buf, word, wordLen);
}
#ifndef NO_REGEX
@@ -1349,19 +1377,19 @@ nosub:
static void
VarREError(int reerr, const regex_t *pat, const char *str)
{
- size_t errlen = regerror(reerr, pat, NULL, 0);
- char *errbuf = bmake_malloc(errlen);
- regerror(reerr, pat, errbuf, errlen);
- Error("%s: %s", str, errbuf);
- free(errbuf);
+ size_t errlen = regerror(reerr, pat, NULL, 0);
+ char *errbuf = bmake_malloc(errlen);
+ regerror(reerr, pat, errbuf, errlen);
+ Error("%s: %s", str, errbuf);
+ free(errbuf);
}
struct ModifyWord_SubstRegexArgs {
- regex_t re;
- size_t nsub;
- char *replace;
- VarPatternFlags pflags;
- Boolean matched;
+ regex_t re;
+ size_t nsub;
+ char *replace;
+ VarPatternFlags pflags;
+ Boolean matched;
};
/* Callback for ModifyWords to implement the :C/from/to/ modifier.
@@ -1445,35 +1473,35 @@ tryagain:
struct ModifyWord_LoopArgs {
- GNode *ctx;
- char *tvar; /* name of temporary variable */
- char *str; /* string to expand */
- VarEvalFlags eflags;
+ GNode *ctx;
+ char *tvar; /* name of temporary variable */
+ char *str; /* string to expand */
+ VarEvalFlags eflags;
};
/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
static void
ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
{
- const struct ModifyWord_LoopArgs *args;
- char *s;
+ const struct ModifyWord_LoopArgs *args;
+ char *s;
- if (word[0] == '\0')
- return;
+ if (word[0] == '\0')
+ return;
- args = data;
- Var_SetWithFlags(args->tvar, word, args->ctx, VAR_SET_NO_EXPORT);
- (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
- /* TODO: handle errors */
-
- VAR_DEBUG4("ModifyWord_Loop: "
- "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
- word, args->tvar, args->str, s);
+ args = data;
+ Var_SetWithFlags(args->tvar, word, args->ctx, VAR_SET_NO_EXPORT);
+ (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
+ /* TODO: handle errors */
- if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
- buf->needSep = FALSE;
- SepBuf_AddStr(buf, s);
- free(s);
+ VAR_DEBUG4("ModifyWord_Loop: "
+ "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
+ word, args->tvar, args->str, s);
+
+ if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
+ buf->needSep = FALSE;
+ SepBuf_AddStr(buf, s);
+ free(s);
}
@@ -1483,56 +1511,55 @@ static char *
VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
int last)
{
- Words words;
- int len, start, end, step;
- int i;
-
- SepBuf buf;
- SepBuf_Init(&buf, sep);
-
- if (oneBigWord) {
- /* fake what Str_Words() would do if there were only one word */
- words.len = 1;
- words.words = bmake_malloc((words.len + 1) * sizeof(words.words[0]));
- words.freeIt = bmake_strdup(str);
- words.words[0] = words.freeIt;
- words.words[1] = NULL;
- } else {
- words = Str_Words(str, FALSE);
- }
-
- /*
- * Now sanitize the given range.
- * If first or last are negative, convert them to the positive equivalents
- * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
- */
- len = (int)words.len;
- if (first < 0)
- first += len + 1;
- if (last < 0)
- last += len + 1;
+ Words words;
+ int len, start, end, step;
+ int i;
+
+ SepBuf buf;
+ SepBuf_Init(&buf, sep);
+
+ if (oneBigWord) {
+ /* fake what Str_Words() would do if there were only one word */
+ words.len = 1;
+ words.words = bmake_malloc(
+ (words.len + 1) * sizeof(words.words[0]));
+ words.freeIt = bmake_strdup(str);
+ words.words[0] = words.freeIt;
+ words.words[1] = NULL;
+ } else {
+ words = Str_Words(str, FALSE);
+ }
- /*
- * We avoid scanning more of the list than we need to.
- */
- if (first > last) {
- start = (first > len ? len : first) - 1;
- end = last < 1 ? 0 : last - 1;
- step = -1;
- } else {
- start = first < 1 ? 0 : first - 1;
- end = last > len ? len : last;
- step = 1;
- }
+ /*
+ * Now sanitize the given range. If first or last are negative,
+ * convert them to the positive equivalents (-1 gets converted to len,
+ * -2 gets converted to (len - 1), etc.).
+ */
+ len = (int)words.len;
+ if (first < 0)
+ first += len + 1;
+ if (last < 0)
+ last += len + 1;
+
+ /* We avoid scanning more of the list than we need to. */
+ if (first > last) {
+ start = (first > len ? len : first) - 1;
+ end = last < 1 ? 0 : last - 1;
+ step = -1;
+ } else {
+ start = first < 1 ? 0 : first - 1;
+ end = last > len ? len : last;
+ step = 1;
+ }
- for (i = start; (step < 0) == (i >= end); i += step) {
- SepBuf_AddStr(&buf, words.words[i]);
- SepBuf_Sep(&buf);
- }
+ for (i = start; (step < 0) == (i >= end); i += step) {
+ SepBuf_AddStr(&buf, words.words[i]);
+ SepBuf_Sep(&buf);
+ }
- Words_Free(words);
+ Words_Free(words);
- return SepBuf_Destroy(&buf, FALSE);
+ return SepBuf_Destroy(&buf, FALSE);
}
@@ -1541,14 +1568,14 @@ VarSelectWords(char sep, Boolean oneBigW
static void
ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
{
- struct stat st;
- char rbuf[MAXPATHLEN];
+ struct stat st;
+ char rbuf[MAXPATHLEN];
- const char *rp = cached_realpath(word, rbuf);
- if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
- word = rp;
+ const char *rp = cached_realpath(word, rbuf);
+ if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
+ word = rp;
- SepBuf_AddStr(buf, word);
+ SepBuf_AddStr(buf, word);
}
/* Modify each of the words of the passed string using the given function.
@@ -1567,68 +1594,72 @@ ModifyWords(const char *str,
ModifyWordsCallback modifyWord, void *modifyWord_args,
Boolean oneBigWord, char sep)
{
- SepBuf result;
- Words words;
- size_t i;
+ SepBuf result;
+ Words words;
+ size_t i;
- if (oneBigWord) {
- SepBuf_Init(&result, sep);
- modifyWord(str, &result, modifyWord_args);
- return SepBuf_Destroy(&result, FALSE);
- }
+ if (oneBigWord) {
+ SepBuf_Init(&result, sep);
+ modifyWord(str, &result, modifyWord_args);
+ return SepBuf_Destroy(&result, FALSE);
+ }
- SepBuf_Init(&result, sep);
+ SepBuf_Init(&result, sep);
- words = Str_Words(str, FALSE);
+ words = Str_Words(str, FALSE);
- VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
+ VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n",
+ str, words.len);
- for (i = 0; i < words.len; i++) {
- modifyWord(words.words[i], &result, modifyWord_args);
- if (Buf_Len(&result.buf) > 0)
- SepBuf_Sep(&result);
- }
+ for (i = 0; i < words.len; i++) {
+ modifyWord(words.words[i], &result, modifyWord_args);
+ if (Buf_Len(&result.buf) > 0)
+ SepBuf_Sep(&result);
+ }
- Words_Free(words);
+ Words_Free(words);
- return SepBuf_Destroy(&result, FALSE);
+ return SepBuf_Destroy(&result, FALSE);
}
static char *
Words_JoinFree(Words words)
{
- Buffer buf;
- size_t i;
+ Buffer buf;
+ size_t i;
- Buf_Init(&buf);
+ Buf_Init(&buf);
- for (i = 0; i < words.len; i++) {
- if (i != 0)
- Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
- Buf_AddStr(&buf, words.words[i]);
- }
+ for (i = 0; i < words.len; i++) {
+ if (i != 0) {
+ /* XXX: Use st->sep instead of ' ', for consistency. */
+ Buf_AddByte(&buf, ' ');
+ }
+ Buf_AddStr(&buf, words.words[i]);
+ }
- Words_Free(words);
+ Words_Free(words);
- return Buf_Destroy(&buf, FALSE);
+ return Buf_Destroy(&buf, FALSE);
}
/* Remove adjacent duplicate words. */
static char *
VarUniq(const char *str)
{
- Words words = Str_Words(str, FALSE);
+ Words words = Str_Words(str, FALSE);
- if (words.len > 1) {
- size_t i, j;
- for (j = 0, i = 1; i < words.len; i++)
- if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
- words.words[j] = words.words[i];
- words.len = j + 1;
- }
+ if (words.len > 1) {
+ size_t i, j;
+ for (j = 0, i = 1; i < words.len; i++)
+ if (strcmp(words.words[i], words.words[j]) != 0 &&
+ (++j != i))
+ words.words[j] = words.words[i];
+ words.len = j + 1;
+ }
- return Words_JoinFree(words);
+ return Words_JoinFree(words);
}
@@ -1637,25 +1668,25 @@ VarUniq(const char *str)
static char *
VarQuote(const char *str, Boolean quoteDollar)
{
- Buffer buf;
- Buf_Init(&buf);
+ Buffer buf;
+ Buf_Init(&buf);
- for (; *str != '\0'; str++) {
- if (*str == '\n') {
- const char *newline = Shell_GetNewline();
- if (newline == NULL)
- newline = "\\\n";
- Buf_AddStr(&buf, newline);
- continue;
+ for (; *str != '\0'; str++) {
+ if (*str == '\n') {
+ const char *newline = Shell_GetNewline();
+ if (newline == NULL)
+ newline = "\\\n";
+ Buf_AddStr(&buf, newline);
+ continue;
+ }
+ if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str))
+ Buf_AddByte(&buf, '\\');
+ Buf_AddByte(&buf, *str);
+ if (quoteDollar && *str == '$')
+ Buf_AddStr(&buf, "\\$");
}
- if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str))
- Buf_AddByte(&buf, '\\');
- Buf_AddByte(&buf, *str);
- if (quoteDollar && *str == '$')
- Buf_AddStr(&buf, "\\$");
- }
- return Buf_Destroy(&buf, FALSE);
+ return Buf_Destroy(&buf, FALSE);
}
/* Compute the 32-bit hash of the given string, using the MurmurHash3
@@ -1663,76 +1694,76 @@ VarQuote(const char *str, Boolean quoteD
static char *
VarHash(const char *str)
{
- static const char hexdigits[16] = "0123456789abcdef";
- const unsigned char *ustr = (const unsigned char *)str;
+ static const char hexdigits[16] = "0123456789abcdef";
+ const unsigned char *ustr = (const unsigned char *)str;
- uint32_t h = 0x971e137bU;
- uint32_t c1 = 0x95543787U;
- uint32_t c2 = 0x2ad7eb25U;
- size_t len2 = strlen(str);
-
- char *buf;
- size_t i;
-
- size_t len;
- for (len = len2; len; ) {
- uint32_t k = 0;
- switch (len) {
- default:
- k = ((uint32_t)ustr[3] << 24) |
- ((uint32_t)ustr[2] << 16) |
- ((uint32_t)ustr[1] << 8) |
- (uint32_t)ustr[0];
- len -= 4;
- ustr += 4;
- break;
- case 3:
- k |= (uint32_t)ustr[2] << 16;
- /* FALLTHROUGH */
- case 2:
- k |= (uint32_t)ustr[1] << 8;
- /* FALLTHROUGH */
- case 1:
- k |= (uint32_t)ustr[0];
- len = 0;
- }
- c1 = c1 * 5 + 0x7b7d159cU;
- c2 = c2 * 5 + 0x6bce6396U;
- k *= c1;
- k = (k << 11) ^ (k >> 21);
- k *= c2;
- h = (h << 13) ^ (h >> 19);
- h = h * 5 + 0x52dce729U;
- h ^= k;
- }
- h ^= (uint32_t)len2;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- buf = bmake_malloc(9);
- for (i = 0; i < 8; i++) {
- buf[i] = hexdigits[h & 0x0f];
- h >>= 4;
- }
- buf[8] = '\0';
- return buf;
+ uint32_t h = 0x971e137bU;
+ uint32_t c1 = 0x95543787U;
+ uint32_t c2 = 0x2ad7eb25U;
+ size_t len2 = strlen(str);
+
+ char *buf;
+ size_t i;
+
+ size_t len;
+ for (len = len2; len;) {
+ uint32_t k = 0;
+ switch (len) {
+ default:
+ k = ((uint32_t)ustr[3] << 24) |
+ ((uint32_t)ustr[2] << 16) |
+ ((uint32_t)ustr[1] << 8) |
+ (uint32_t)ustr[0];
+ len -= 4;
+ ustr += 4;
+ break;
+ case 3:
+ k |= (uint32_t)ustr[2] << 16;
+ /* FALLTHROUGH */
+ case 2:
+ k |= (uint32_t)ustr[1] << 8;
+ /* FALLTHROUGH */
+ case 1:
+ k |= (uint32_t)ustr[0];
+ len = 0;
+ }
+ c1 = c1 * 5 + 0x7b7d159cU;
+ c2 = c2 * 5 + 0x6bce6396U;
+ k *= c1;
+ k = (k << 11) ^ (k >> 21);
+ k *= c2;
+ h = (h << 13) ^ (h >> 19);
+ h = h * 5 + 0x52dce729U;
+ h ^= k;
+ }
+ h ^= (uint32_t)len2;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ buf = bmake_malloc(9);
+ for (i = 0; i < 8; i++) {
+ buf[i] = hexdigits[h & 0x0f];
+ h >>= 4;
+ }
+ buf[8] = '\0';
+ return buf;
}
static char *
VarStrftime(const char *fmt, Boolean zulu, time_t tim)
{
- char buf[BUFSIZ];
+ char buf[BUFSIZ];
- if (tim == 0)
- time(&tim);
- if (*fmt == '\0')
- fmt = "%c";
- strftime(buf, sizeof buf, fmt, zulu ? gmtime(&tim) : localtime(&tim));
+ if (tim == 0)
+ time(&tim);
+ if (*fmt == '\0')
+ fmt = "%c";
+ strftime(buf, sizeof buf, fmt, zulu ? gmtime(&tim) : localtime(&tim));
- buf[sizeof buf - 1] = '\0';
- return bmake_strdup(buf);
+ buf[sizeof buf - 1] = '\0';
+ return bmake_strdup(buf);
}
/*
@@ -1805,12 +1836,14 @@ VarStrftime(const char *fmt, Boolean zul
*/
typedef enum VarExprFlags {
- /* The variable expression is based on an undefined variable. */
- VEF_UNDEF = 0x01,
- /* The variable expression started as an undefined expression, but one
- * of the modifiers (such as :D or :U) has turned the expression from
- * undefined to defined. */
- VEF_DEF = 0x02
+ /* The variable expression is based on an undefined variable. */
+ VEF_UNDEF = 0x01,
+ /*
+ * The variable expression started as an undefined expression, but one
+ * of the modifiers (such as :D or :U) has turned the expression from
+ * undefined to defined.
+ */
+ VEF_DEF = 0x02
} VarExprFlags;
ENUM_FLAGS_RTTI_2(VarExprFlags,
@@ -1818,50 +1851,65 @@ ENUM_FLAGS_RTTI_2(VarExprFlags,
typedef struct ApplyModifiersState {
- const char startc; /* '\0' or '{' or '(' */
- const char endc; /* '\0' or '}' or ')' */
- Var * const var;
- GNode * const ctxt;
- const VarEvalFlags eflags;
-
- char *val; /* The old value of the expression,
- * before applying the modifier, never NULL */
- char *newVal; /* The new value of the expression,
- * after applying the modifier, never NULL */
- char sep; /* Word separator in expansions
- * (see the :ts modifier) */
- Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
- * the variable value into words, like :S and
- * :C, treat the variable value as a single big
- * word, possibly containing spaces. */
- VarExprFlags exprFlags;
+ /* '\0' or '{' or '(' */
+ const char startc;
+ /* '\0' or '}' or ')' */
+ const char endc;
+ Var *const var;
+ GNode *const ctxt;
+ const VarEvalFlags eflags;
+ /*
+ * The old value of the expression, before applying the modifier,
+ * never NULL.
+ */
+ char *val;
+ /*
+ * The new value of the expression, after applying the modifier,
+ * never NULL.
+ */
+ char *newVal;
+ /* Word separator in expansions (see the :ts modifier). */
+ char sep;
+ /*
+ * TRUE if some modifiers that otherwise split the variable value
+ * into words, like :S and :C, treat the variable value as a single
+ * big word, possibly containing spaces.
+ */
+ Boolean oneBigWord;
+ VarExprFlags exprFlags;
} ApplyModifiersState;
static void
ApplyModifiersState_Define(ApplyModifiersState *st)
{
- if (st->exprFlags & VEF_UNDEF)
- st->exprFlags |= VEF_DEF;
+ if (st->exprFlags & VEF_UNDEF)
+ st->exprFlags |= VEF_DEF;
}
typedef enum ApplyModifierResult {
- AMR_OK, /* Continue parsing */
- AMR_UNKNOWN, /* Not a match, try other modifiers as well */
- AMR_BAD, /* Error out with "Bad modifier" message */
- AMR_CLEANUP /* Error out without error message */
+ /* Continue parsing */
+ AMR_OK,
+ /* Not a match, try other modifiers as well */
+ AMR_UNKNOWN,
+ /* Error out with "Bad modifier" message */
+ AMR_BAD,
+ /* Error out without error message */
+ AMR_CLEANUP
} ApplyModifierResult;
-/* Allow backslashes to escape the delimiter, $, and \, but don't touch other
- * backslashes. */
+/*
+ * Allow backslashes to escape the delimiter, $, and \, but don't touch other
+ * backslashes.
+ */
static Boolean
IsEscapedModifierPart(const char *p, char delim,
struct ModifyWord_SubstArgs *subst)
{
- if (p[0] != '\\')
- return FALSE;
- if (p[1] == delim || p[1] == '\\' || p[1] == '$')
- return TRUE;
- return p[1] == '&' && subst != NULL;
+ if (p[0] != '\\')
+ return FALSE;
+ if (p[1] == delim || p[1] == '\\' || p[1] == '$')
+ return TRUE;
+ return p[1] == '&' && subst != NULL;
}
/*
@@ -1877,22 +1925,24 @@ IsEscapedModifierPart(const char *p, cha
*/
static VarParseResult
ParseModifierPart(
- const char **pp, /* The parsing position, updated upon return */
- char delim, /* Parsing stops at this delimiter */
- VarEvalFlags eflags, /* Flags for evaluating nested variables;
- * if VARE_WANTRES is not set, the text is
- * only parsed */
+ /* The parsing position, updated upon return */
+ const char **pp,
+ /* Parsing stops at this delimiter */
+ char delim,
+ /* Flags for evaluating nested variables; if VARE_WANTRES is not set,
+ * the text is only parsed. */
+ VarEvalFlags eflags,
ApplyModifiersState *st,
char **out_part,
- size_t *out_length, /* Optionally stores the length of the returned
- * string, just to save another strlen call. */
- VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
- * sets the VARP_ANCHOR_END flag if the last
- * character of the pattern is a $. */
+ /* Optionally stores the length of the returned string, just to save
+ * another strlen call. */
+ size_t *out_length,
+ /* For the first part of the :S modifier, sets the VARP_ANCHOR_END flag
+ * if the last character of the pattern is a $. */
+ VarPatternFlags *out_pflags,
+ /* For the second part of the :S modifier, allow ampersands to be
+ * escaped and replace unescaped ampersands with subst->lhs. */
struct ModifyWord_SubstArgs *subst
- /* For the second part of the :S modifier,
- * allow ampersands to be escaped and replace
- * unescaped ampersands with subst->lhs. */
) {
Buffer buf;
const char *p;
@@ -2002,323 +2052,326 @@ ParseModifierPart(
MAKE_INLINE Boolean
ModMatch(const char *mod, const char *modname, char endc)
{
- size_t n = strlen(modname);
- return strncmp(mod, modname, n) == 0 &&
- (mod[n] == endc || mod[n] == ':');
+ size_t n = strlen(modname);
+ return strncmp(mod, modname, n) == 0 &&
+ (mod[n] == endc || mod[n] == ':');
}
/* Test whether mod starts with modname, followed by a delimiter or '='. */
MAKE_INLINE Boolean
ModMatchEq(const char *mod, const char *modname, char endc)
{
- size_t n = strlen(modname);
- return strncmp(mod, modname, n) == 0 &&
- (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
+ size_t n = strlen(modname);
+ return strncmp(mod, modname, n) == 0 &&
+ (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
}
static Boolean
TryParseIntBase0(const char **pp, int *out_num)
{
- char *end;
- long n;
+ char *end;
+ long n;
- errno = 0;
- n = strtol(*pp, &end, 0);
- if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE)
- return FALSE;
- if (n < INT_MIN || n > INT_MAX)
- return FALSE;
+ errno = 0;
+ n = strtol(*pp, &end, 0);
+ if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE)
+ return FALSE;
+ if (n < INT_MIN || n > INT_MAX)
+ return FALSE;
- *pp = end;
- *out_num = (int)n;
- return TRUE;
+ *pp = end;
+ *out_num = (int)n;
+ return TRUE;
}
static Boolean
TryParseSize(const char **pp, size_t *out_num)
{
- char *end;
- unsigned long n;
+ char *end;
+ unsigned long n;
- if (!ch_isdigit(**pp))
- return FALSE;
+ if (!ch_isdigit(**pp))
+ return FALSE;
- errno = 0;
- n = strtoul(*pp, &end, 10);
- if (n == ULONG_MAX && errno == ERANGE)
- return FALSE;
- if (n > SIZE_MAX)
- return FALSE;
+ errno = 0;
+ n = strtoul(*pp, &end, 10);
+ if (n == ULONG_MAX && errno == ERANGE)
+ return FALSE;
+ if (n > SIZE_MAX)
+ return FALSE;
- *pp = end;
- *out_num = (size_t)n;
- return TRUE;
+ *pp = end;
+ *out_num = (size_t)n;
+ return TRUE;
}
static Boolean
TryParseChar(const char **pp, int base, char *out_ch)
{
- char *end;
- unsigned long n;
+ char *end;
+ unsigned long n;
- if (!ch_isalnum(**pp))
- return FALSE;
+ if (!ch_isalnum(**pp))
+ return FALSE;
- errno = 0;
- n = strtoul(*pp, &end, base);
- if (n == ULONG_MAX && errno == ERANGE)
- return FALSE;
- if (n > UCHAR_MAX)
- return FALSE;
+ errno = 0;
+ n = strtoul(*pp, &end, base);
+ if (n == ULONG_MAX && errno == ERANGE)
+ return FALSE;
+ if (n > UCHAR_MAX)
+ return FALSE;
- *pp = end;
- *out_ch = (char)n;
- return TRUE;
+ *pp = end;
+ *out_ch = (char)n;
+ return TRUE;
}
/* :@var@...${var}...@ */
static ApplyModifierResult
ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
{
- struct ModifyWord_LoopArgs args;
- char prev_sep;
- VarParseResult res;
-
- args.ctx = st->ctxt;
-
- (*pp)++; /* Skip the first '@' */
- res = ParseModifierPart(pp, '@', VARE_NONE, st,
- &args.tvar, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
- if (opts.lint && strchr(args.tvar, '$') != NULL) {
- Parse_Error(PARSE_FATAL,
+ struct ModifyWord_LoopArgs args;
+ char prev_sep;
+ VarParseResult res;
+
+ args.ctx = st->ctxt;
+
+ (*pp)++; /* Skip the first '@' */
+ res = ParseModifierPart(pp, '@', VARE_NONE, st,
+ &args.tvar, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+ if (opts.lint && strchr(args.tvar, '$') != NULL) {
+ Parse_Error(PARSE_FATAL,
"In the :@ modifier of \"%s\", the variable name \"%s\" "
"must not contain a dollar.",
st->var->name, args.tvar);
- return AMR_CLEANUP;
- }
+ return AMR_CLEANUP;
+ }
- res = ParseModifierPart(pp, '@', VARE_NONE, st,
- &args.str, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- args.eflags = st->eflags & ~(unsigned)VARE_KEEP_DOLLAR;
- prev_sep = st->sep;
- st->sep = ' '; /* XXX: should be st->sep for consistency */
- st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args,
- st->oneBigWord, st->sep);
- st->sep = prev_sep;
- /* XXX: Consider restoring the previous variable instead of deleting. */
- Var_Delete(args.tvar, st->ctxt);
- free(args.tvar);
- free(args.str);
- return AMR_OK;
+ res = ParseModifierPart(pp, '@', VARE_NONE, st,
+ &args.str, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ args.eflags = st->eflags & ~(unsigned)VARE_KEEP_DOLLAR;
+ prev_sep = st->sep;
+ st->sep = ' '; /* XXX: should be st->sep for consistency */
+ st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args,
+ st->oneBigWord, st->sep);
+ st->sep = prev_sep;
+ /* XXX: Consider restoring the previous variable instead of deleting. */
+ Var_Delete(args.tvar, st->ctxt);
+ free(args.tvar);
+ free(args.str);
+ return AMR_OK;
}
/* :Ddefined or :Uundefined */
static ApplyModifierResult
ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
{
- Buffer buf;
- const char *p;
+ Buffer buf;
+ const char *p;
- VarEvalFlags eflags = VARE_NONE;
- if (st->eflags & VARE_WANTRES)
- if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
- eflags = st->eflags;
+ VarEvalFlags eflags = VARE_NONE;
+ if (st->eflags & VARE_WANTRES)
+ if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
+ eflags = st->eflags;
+
+ Buf_Init(&buf);
+ p = *pp + 1;
+ while (*p != st->endc && *p != ':' && *p != '\0') {
+
+ /* XXX: This code is similar to the one in Var_Parse.
+ * See if the code can be merged.
+ * See also ApplyModifier_Match. */
+
+ /* Escaped delimiter or other special character */
+ if (*p == '\\') {
+ char c = p[1];
+ if (c == st->endc || c == ':' || c == '$' ||
+ c == '\\') {
+ Buf_AddByte(&buf, c);
+ p += 2;
+ continue;
+ }
+ }
- Buf_Init(&buf);
- p = *pp + 1;
- while (*p != st->endc && *p != ':' && *p != '\0') {
+ /* Nested variable expression */
+ if (*p == '$') {
+ const char *nested_val;
+ void *nested_val_freeIt;
- /* XXX: This code is similar to the one in Var_Parse.
- * See if the code can be merged.
- * See also ApplyModifier_Match. */
+ (void)Var_Parse(&p, st->ctxt, eflags,
+ &nested_val, &nested_val_freeIt);
+ /* TODO: handle errors */
+ Buf_AddStr(&buf, nested_val);
+ free(nested_val_freeIt);
+ continue;
+ }
- /* Escaped delimiter or other special character */
- if (*p == '\\') {
- char c = p[1];
- if (c == st->endc || c == ':' || c == '$' || c == '\\') {
- Buf_AddByte(&buf, c);
- p += 2;
- continue;
- }
+ /* Ordinary text */
+ Buf_AddByte(&buf, *p);
+ p++;
}
+ *pp = p;
- /* Nested variable expression */
- if (*p == '$') {
- const char *nested_val;
- void *nested_val_freeIt;
+ ApplyModifiersState_Define(st);
- (void)Var_Parse(&p, st->ctxt, eflags,
- &nested_val, &nested_val_freeIt);
- /* TODO: handle errors */
- Buf_AddStr(&buf, nested_val);
- free(nested_val_freeIt);
- continue;
+ if (eflags & VARE_WANTRES) {
+ st->newVal = Buf_Destroy(&buf, FALSE);
+ } else {
+ st->newVal = st->val;
+ Buf_Destroy(&buf, TRUE);
}
-
- /* Ordinary text */
- Buf_AddByte(&buf, *p);
- p++;
- }
- *pp = p;
-
- ApplyModifiersState_Define(st);
-
- if (eflags & VARE_WANTRES) {
- st->newVal = Buf_Destroy(&buf, FALSE);
- } else {
- st->newVal = st->val;
- Buf_Destroy(&buf, TRUE);
- }
- return AMR_OK;
+ return AMR_OK;
}
/* :L */
static ApplyModifierResult
ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
{
- ApplyModifiersState_Define(st);
- st->newVal = bmake_strdup(st->var->name);
- (*pp)++;
- return AMR_OK;
+ ApplyModifiersState_Define(st);
+ st->newVal = bmake_strdup(st->var->name);
+ (*pp)++;
+ return AMR_OK;
}
static Boolean
TryParseTime(const char **pp, time_t *out_time)
{
- char *end;
- unsigned long n;
+ char *end;
+ unsigned long n;
- if (!ch_isdigit(**pp))
- return FALSE;
+ if (!ch_isdigit(**pp))
+ return FALSE;
- errno = 0;
- n = strtoul(*pp, &end, 10);
- if (n == ULONG_MAX && errno == ERANGE)
- return FALSE;
+ errno = 0;
+ n = strtoul(*pp, &end, 10);
+ if (n == ULONG_MAX && errno == ERANGE)
+ return FALSE;
- *pp = end;
- *out_time = (time_t)n; /* ignore possible truncation for now */
- return TRUE;
+ *pp = end;
+ *out_time = (time_t)n; /* ignore possible truncation for now */
+ return TRUE;
}
/* :gmtime */
static ApplyModifierResult
ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
{
- time_t utc;
+ time_t utc;
- const char *mod = *pp;
- if (!ModMatchEq(mod, "gmtime", st->endc))
- return AMR_UNKNOWN;
-
- if (mod[6] == '=') {
- const char *arg = mod + 7;
- if (!TryParseTime(&arg, &utc)) {
- Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 7);
- return AMR_CLEANUP;
+ const char *mod = *pp;
+ if (!ModMatchEq(mod, "gmtime", st->endc))
+ return AMR_UNKNOWN;
+
+ if (mod[6] == '=') {
+ const char *arg = mod + 7;
+ if (!TryParseTime(&arg, &utc)) {
+ Parse_Error(PARSE_FATAL,
+ "Invalid time value: %s\n", mod + 7);
+ return AMR_CLEANUP;
+ }
+ *pp = arg;
+ } else {
+ utc = 0;
+ *pp = mod + 6;
}
- *pp = arg;
- } else {
- utc = 0;
- *pp = mod + 6;
- }
- st->newVal = VarStrftime(st->val, TRUE, utc);
- return AMR_OK;
+ st->newVal = VarStrftime(st->val, TRUE, utc);
+ return AMR_OK;
}
/* :localtime */
static ApplyModifierResult
ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
{
- time_t utc;
+ time_t utc;
- const char *mod = *pp;
- if (!ModMatchEq(mod, "localtime", st->endc))
- return AMR_UNKNOWN;
-
- if (mod[9] == '=') {
- const char *arg = mod + 10;
- if (!TryParseTime(&arg, &utc)) {
- Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 10);
- return AMR_CLEANUP;
+ const char *mod = *pp;
+ if (!ModMatchEq(mod, "localtime", st->endc))
+ return AMR_UNKNOWN;
+
+ if (mod[9] == '=') {
+ const char *arg = mod + 10;
+ if (!TryParseTime(&arg, &utc)) {
+ Parse_Error(PARSE_FATAL,
+ "Invalid time value: %s\n", mod + 10);
+ return AMR_CLEANUP;
+ }
+ *pp = arg;
+ } else {
+ utc = 0;
+ *pp = mod + 9;
}
- *pp = arg;
- } else {
- utc = 0;
- *pp = mod + 9;
- }
- st->newVal = VarStrftime(st->val, FALSE, utc);
- return AMR_OK;
+ st->newVal = VarStrftime(st->val, FALSE, utc);
+ return AMR_OK;
}
/* :hash */
static ApplyModifierResult
ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
{
- if (!ModMatch(*pp, "hash", st->endc))
- return AMR_UNKNOWN;
+ if (!ModMatch(*pp, "hash", st->endc))
+ return AMR_UNKNOWN;
- st->newVal = VarHash(st->val);
- *pp += 4;
- return AMR_OK;
+ st->newVal = VarHash(st->val);
+ *pp += 4;
+ return AMR_OK;
}
/* :P */
static ApplyModifierResult
ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
{
- GNode *gn;
- char *path;
+ GNode *gn;
+ char *path;
- ApplyModifiersState_Define(st);
+ ApplyModifiersState_Define(st);
- gn = Targ_FindNode(st->var->name);
- if (gn == NULL || gn->type & OP_NOPATH) {
- path = NULL;
- } else if (gn->path != NULL) {
- path = bmake_strdup(gn->path);
- } else {
- SearchPath *searchPath = Suff_FindPath(gn);
- path = Dir_FindFile(st->var->name, searchPath);
- }
- if (path == NULL)
- path = bmake_strdup(st->var->name);
- st->newVal = path;
+ gn = Targ_FindNode(st->var->name);
+ if (gn == NULL || gn->type & OP_NOPATH) {
+ path = NULL;
+ } else if (gn->path != NULL) {
+ path = bmake_strdup(gn->path);
+ } else {
+ SearchPath *searchPath = Suff_FindPath(gn);
+ path = Dir_FindFile(st->var->name, searchPath);
+ }
+ if (path == NULL)
+ path = bmake_strdup(st->var->name);
+ st->newVal = path;
- (*pp)++;
- return AMR_OK;
+ (*pp)++;
+ return AMR_OK;
}
/* :!cmd! */
static ApplyModifierResult
ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
{
- char *cmd;
- const char *errfmt;
- VarParseResult res;
-
- (*pp)++;
- res = ParseModifierPart(pp, '!', st->eflags, st,
- &cmd, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- errfmt = NULL;
- if (st->eflags & VARE_WANTRES)
- st->newVal = Cmd_Exec(cmd, &errfmt);
- else
- st->newVal = bmake_strdup("");
- if (errfmt != NULL)
- Error(errfmt, cmd); /* XXX: why still return AMR_OK? */
- free(cmd);
+ char *cmd;
+ const char *errfmt;
+ VarParseResult res;
- ApplyModifiersState_Define(st);
- return AMR_OK;
+ (*pp)++;
+ res = ParseModifierPart(pp, '!', st->eflags, st,
+ &cmd, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ errfmt = NULL;
+ if (st->eflags & VARE_WANTRES)
+ st->newVal = Cmd_Exec(cmd, &errfmt);
+ else
+ st->newVal = bmake_strdup("");
+ if (errfmt != NULL)
+ Error(errfmt, cmd); /* XXX: why still return AMR_OK? */
+ free(cmd);
+
+ ApplyModifiersState_Define(st);
+ return AMR_OK;
}
/* The :range modifier generates an integer sequence as long as the words.
@@ -2326,189 +2379,191 @@ ApplyModifier_ShellCommand(const char **
static ApplyModifierResult
ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
{
- size_t n;
- Buffer buf;
- size_t i;
+ size_t n;
+ Buffer buf;
+ size_t i;
- const char *mod = *pp;
- if (!ModMatchEq(mod, "range", st->endc))
- return AMR_UNKNOWN;
-
- if (mod[5] == '=') {
- const char *p = mod + 6;
- if (!TryParseSize(&p, &n)) {
- Parse_Error(PARSE_FATAL, "Invalid number: %s\n", mod + 6);
- return AMR_CLEANUP;
+ const char *mod = *pp;
+ if (!ModMatchEq(mod, "range", st->endc))
+ return AMR_UNKNOWN;
+
+ if (mod[5] == '=') {
+ const char *p = mod + 6;
+ if (!TryParseSize(&p, &n)) {
+ Parse_Error(PARSE_FATAL,
+ "Invalid number: %s\n", mod + 6);
+ return AMR_CLEANUP;
+ }
+ *pp = p;
+ } else {
+ n = 0;
+ *pp = mod + 5;
}
- *pp = p;
- } else {
- n = 0;
- *pp = mod + 5;
- }
- if (n == 0) {
- Words words = Str_Words(st->val, FALSE);
- n = words.len;
- Words_Free(words);
- }
+ if (n == 0) {
+ Words words = Str_Words(st->val, FALSE);
+ n = words.len;
+ Words_Free(words);
+ }
- Buf_Init(&buf);
+ Buf_Init(&buf);
- for (i = 0; i < n; i++) {
- if (i != 0)
- Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
- Buf_AddInt(&buf, 1 + (int)i);
- }
+ for (i = 0; i < n; i++) {
+ if (i != 0) {
+ /* XXX: Use st->sep instead of ' ', for consistency. */
+ Buf_AddByte(&buf, ' ');
+ }
+ Buf_AddInt(&buf, 1 + (int)i);
+ }
- st->newVal = Buf_Destroy(&buf, FALSE);
- return AMR_OK;
+ st->newVal = Buf_Destroy(&buf, FALSE);
+ return AMR_OK;
}
/* :Mpattern or :Npattern */
static ApplyModifierResult
ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
{
- const char *mod = *pp;
- Boolean copy = FALSE; /* pattern should be, or has been, copied */
- Boolean needSubst = FALSE;
- const char *endpat;
- char *pattern;
- ModifyWordsCallback callback;
+ const char *mod = *pp;
+ Boolean copy = FALSE; /* pattern should be, or has been, copied */
+ Boolean needSubst = FALSE;
+ const char *endpat;
+ char *pattern;
+ ModifyWordsCallback callback;
- /*
- * In the loop below, ignore ':' unless we are at (or back to) the
- * original brace level.
- * XXX: This will likely not work right if $() and ${} are intermixed.
- */
- /* XXX: This code is similar to the one in Var_Parse.
- * See if the code can be merged.
- * See also ApplyModifier_Defined. */
- int nest = 0;
- const char *p;
- for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
- if (*p == '\\' &&
- (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
- if (!needSubst)
- copy = TRUE;
- p++;
- continue;
- }
- if (*p == '$')
- needSubst = TRUE;
- if (*p == '(' || *p == '{')
- nest++;
- if (*p == ')' || *p == '}') {
- nest--;
- if (nest < 0)
- break;
+ /*
+ * In the loop below, ignore ':' unless we are at (or back to) the
+ * original brace level.
+ * XXX: This will likely not work right if $() and ${} are intermixed.
+ */
+ /* XXX: This code is similar to the one in Var_Parse.
+ * See if the code can be merged.
+ * See also ApplyModifier_Defined. */
+ int nest = 0;
+ const char *p;
+ for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
+ if (*p == '\\' &&
+ (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
+ if (!needSubst)
+ copy = TRUE;
+ p++;
+ continue;
+ }
+ if (*p == '$')
+ needSubst = TRUE;
+ if (*p == '(' || *p == '{')
+ nest++;
+ if (*p == ')' || *p == '}') {
+ nest--;
+ if (nest < 0)
+ break;
+ }
}
- }
- *pp = p;
- endpat = p;
+ *pp = p;
+ endpat = p;
- if (copy) {
- char *dst;
- const char *src;
-
- /* Compress the \:'s out of the pattern. */
- pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
- dst = pattern;
- src = mod + 1;
- for (; src < endpat; src++, dst++) {
- if (src[0] == '\\' && src + 1 < endpat &&
- /* XXX: st->startc is missing here; see above */
- (src[1] == ':' || src[1] == st->endc))
- src++;
- *dst = *src;
+ if (copy) {
+ char *dst;
+ const char *src;
+
+ /* Compress the \:'s out of the pattern. */
+ pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
+ dst = pattern;
+ src = mod + 1;
+ for (; src < endpat; src++, dst++) {
+ if (src[0] == '\\' && src + 1 < endpat &&
+ /* XXX: st->startc is missing here; see above */
+ (src[1] == ':' || src[1] == st->endc))
+ src++;
+ *dst = *src;
+ }
+ *dst = '\0';
+ endpat = dst;
+ } else {
+ pattern = bmake_strsedup(mod + 1, endpat);
}
- *dst = '\0';
- endpat = dst;
- } else {
- pattern = bmake_strsedup(mod + 1, endpat);
- }
- if (needSubst) {
- /* pattern contains embedded '$', so use Var_Subst to expand it. */
- char *old_pattern = pattern;
- (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
- /* TODO: handle errors */
- free(old_pattern);
- }
+ if (needSubst) {
+ char *old_pattern = pattern;
+ (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
+ /* TODO: handle errors */
+ free(old_pattern);
+ }
- VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n",
- st->var->name, st->val, pattern);
+ VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n",
+ st->var->name, st->val, pattern);
- callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
- st->newVal = ModifyWords(st->val, callback, pattern,
- st->oneBigWord, st->sep);
- free(pattern);
- return AMR_OK;
+ callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
+ st->newVal = ModifyWords(st->val, callback, pattern,
+ st->oneBigWord, st->sep);
+ free(pattern);
+ return AMR_OK;
}
/* :S,from,to, */
static ApplyModifierResult
ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
{
- struct ModifyWord_SubstArgs args;
- char *lhs, *rhs;
- Boolean oneBigWord;
- VarParseResult res;
-
- char delim = (*pp)[1];
- if (delim == '\0') {
- Error("Missing delimiter for :S modifier");
- (*pp)++;
- return AMR_CLEANUP;
- }
-
- *pp += 2;
+ struct ModifyWord_SubstArgs args;
+ char *lhs, *rhs;
+ Boolean oneBigWord;
+ VarParseResult res;
- args.pflags = 0;
- args.matched = FALSE;
+ char delim = (*pp)[1];
+ if (delim == '\0') {
+ Error("Missing delimiter for :S modifier");
+ (*pp)++;
+ return AMR_CLEANUP;
+ }
- /*
- * If pattern begins with '^', it is anchored to the
- * start of the word -- skip over it and flag pattern.
- */
- if (**pp == '^') {
- args.pflags |= VARP_ANCHOR_START;
- (*pp)++;
- }
+ *pp += 2;
- res = ParseModifierPart(pp, delim, st->eflags, st,
- &lhs, &args.lhsLen, &args.pflags, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
- args.lhs = lhs;
-
- res = ParseModifierPart(pp, delim, st->eflags, st,
- &rhs, &args.rhsLen, NULL, &args);
- if (res != VPR_OK)
- return AMR_CLEANUP;
- args.rhs = rhs;
+ args.pflags = 0;
+ args.matched = FALSE;
- oneBigWord = st->oneBigWord;
- for (;; (*pp)++) {
- switch (**pp) {
- case 'g':
- args.pflags |= VARP_SUB_GLOBAL;
- continue;
- case '1':
- args.pflags |= VARP_SUB_ONE;
- continue;
- case 'W':
- oneBigWord = TRUE;
- continue;
+ /*
+ * If pattern begins with '^', it is anchored to the
+ * start of the word -- skip over it and flag pattern.
+ */
+ if (**pp == '^') {
+ args.pflags |= VARP_ANCHOR_START;
+ (*pp)++;
+ }
+
+ res = ParseModifierPart(pp, delim, st->eflags, st,
+ &lhs, &args.lhsLen, &args.pflags, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+ args.lhs = lhs;
+
+ res = ParseModifierPart(pp, delim, st->eflags, st,
+ &rhs, &args.rhsLen, NULL, &args);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+ args.rhs = rhs;
+
+ oneBigWord = st->oneBigWord;
+ for (;; (*pp)++) {
+ switch (**pp) {
+ case 'g':
+ args.pflags |= VARP_SUB_GLOBAL;
+ continue;
+ case '1':
+ args.pflags |= VARP_SUB_ONE;
+ continue;
+ case 'W':
+ oneBigWord = TRUE;
+ continue;
+ }
+ break;
}
- break;
- }
- st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
- oneBigWord, st->sep);
+ st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
+ oneBigWord, st->sep);
- free(lhs);
- free(rhs);
- return AMR_OK;
+ free(lhs);
+ free(rhs);
+ return AMR_OK;
}
#ifndef NO_REGEX
@@ -2517,327 +2572,331 @@ ApplyModifier_Subst(const char **pp, App
static ApplyModifierResult
ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
{
- char *re;
- struct ModifyWord_SubstRegexArgs args;
- Boolean oneBigWord;
- int error;
- VarParseResult res;
-
- char delim = (*pp)[1];
- if (delim == '\0') {
- Error("Missing delimiter for :C modifier");
- (*pp)++;
- return AMR_CLEANUP;
- }
+ char *re;
+ struct ModifyWord_SubstRegexArgs args;
+ Boolean oneBigWord;
+ int error;
+ VarParseResult res;
- *pp += 2;
+ char delim = (*pp)[1];
+ if (delim == '\0') {
+ Error("Missing delimiter for :C modifier");
+ (*pp)++;
+ return AMR_CLEANUP;
+ }
- res = ParseModifierPart(pp, delim, st->eflags, st,
- &re, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- res = ParseModifierPart(pp, delim, st->eflags, st,
- &args.replace, NULL, NULL, NULL);
- if (args.replace == NULL) {
- free(re);
- return AMR_CLEANUP;
- }
+ *pp += 2;
- args.pflags = 0;
- args.matched = FALSE;
- oneBigWord = st->oneBigWord;
- for (;; (*pp)++) {
- switch (**pp) {
- case 'g':
- args.pflags |= VARP_SUB_GLOBAL;
- continue;
- case '1':
- args.pflags |= VARP_SUB_ONE;
- continue;
- case 'W':
- oneBigWord = TRUE;
- continue;
+ res = ParseModifierPart(pp, delim, st->eflags, st,
+ &re, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ res = ParseModifierPart(pp, delim, st->eflags, st,
+ &args.replace, NULL, NULL, NULL);
+ if (args.replace == NULL) {
+ free(re);
+ return AMR_CLEANUP;
+ }
+
+ args.pflags = 0;
+ args.matched = FALSE;
+ oneBigWord = st->oneBigWord;
+ for (;; (*pp)++) {
+ switch (**pp) {
+ case 'g':
+ args.pflags |= VARP_SUB_GLOBAL;
+ continue;
+ case '1':
+ args.pflags |= VARP_SUB_ONE;
+ continue;
+ case 'W':
+ oneBigWord = TRUE;
+ continue;
+ }
+ break;
}
- break;
- }
- error = regcomp(&args.re, re, REG_EXTENDED);
- free(re);
- if (error != 0) {
- VarREError(error, &args.re, "Regex compilation error");
- free(args.replace);
- return AMR_CLEANUP;
- }
+ error = regcomp(&args.re, re, REG_EXTENDED);
+ free(re);
+ if (error != 0) {
+ VarREError(error, &args.re, "Regex compilation error");
+ free(args.replace);
+ return AMR_CLEANUP;
+ }
- args.nsub = args.re.re_nsub + 1;
- if (args.nsub > 10)
- args.nsub = 10;
- st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
- oneBigWord, st->sep);
- regfree(&args.re);
- free(args.replace);
- return AMR_OK;
+ args.nsub = args.re.re_nsub + 1;
+ if (args.nsub > 10)
+ args.nsub = 10;
+ st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
+ oneBigWord, st->sep);
+ regfree(&args.re);
+ free(args.replace);
+ return AMR_OK;
}
+
#endif
/* :Q, :q */
static ApplyModifierResult
ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
{
- if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
- st->newVal = VarQuote(st->val, **pp == 'q');
- (*pp)++;
- return AMR_OK;
- } else
- return AMR_UNKNOWN;
+ if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
+ st->newVal = VarQuote(st->val, **pp == 'q');
+ (*pp)++;
+ return AMR_OK;
+ } else
+ return AMR_UNKNOWN;
}
static void
ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
{
- SepBuf_AddStr(buf, word);
+ SepBuf_AddStr(buf, word);
}
/* :ts<separator> */
static ApplyModifierResult
ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
{
- const char *sep = *pp + 2;
+ const char *sep = *pp + 2;
- /* ":ts<any><endc>" or ":ts<any>:" */
- if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
- st->sep = sep[0];
- *pp = sep + 1;
- goto ok;
- }
+ /* ":ts<any><endc>" or ":ts<any>:" */
+ if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
+ st->sep = sep[0];
+ *pp = sep + 1;
+ goto ok;
+ }
- /* ":ts<endc>" or ":ts:" */
- if (sep[0] == st->endc || sep[0] == ':') {
- st->sep = '\0'; /* no separator */
- *pp = sep;
- goto ok;
- }
+ /* ":ts<endc>" or ":ts:" */
+ if (sep[0] == st->endc || sep[0] == ':') {
+ st->sep = '\0'; /* no separator */
+ *pp = sep;
+ goto ok;
+ }
- /* ":ts<unrecognised><unrecognised>". */
- if (sep[0] != '\\') {
- (*pp)++; /* just for backwards compatibility */
- return AMR_BAD;
- }
+ /* ":ts<unrecognised><unrecognised>". */
+ if (sep[0] != '\\') {
+ (*pp)++; /* just for backwards compatibility */
+ return AMR_BAD;
+ }
- /* ":ts\n" */
- if (sep[1] == 'n') {
- st->sep = '\n';
- *pp = sep + 2;
- goto ok;
- }
+ /* ":ts\n" */
+ if (sep[1] == 'n') {
+ st->sep = '\n';
+ *pp = sep + 2;
+ goto ok;
+ }
- /* ":ts\t" */
- if (sep[1] == 't') {
- st->sep = '\t';
- *pp = sep + 2;
- goto ok;
- }
+ /* ":ts\t" */
+ if (sep[1] == 't') {
+ st->sep = '\t';
+ *pp = sep + 2;
+ goto ok;
+ }
- /* ":ts\x40" or ":ts\100" */
- {
- const char *p = sep + 1;
- int base = 8; /* assume octal */
+ /* ":ts\x40" or ":ts\100" */
+ {
+ const char *p = sep + 1;
+ int base = 8; /* assume octal */
- if (sep[1] == 'x') {
- base = 16;
- p++;
- } else if (!ch_isdigit(sep[1])) {
- (*pp)++; /* just for backwards compatibility */
- return AMR_BAD; /* ":ts<backslash><unrecognised>". */
- }
+ if (sep[1] == 'x') {
+ base = 16;
+ p++;
+ } else if (!ch_isdigit(sep[1])) {
+ (*pp)++; /* just for backwards compatibility */
+ return AMR_BAD; /* ":ts<backslash><unrecognised>". */
+ }
- if (!TryParseChar(&p, base, &st->sep)) {
- Parse_Error(PARSE_FATAL, "Invalid character number: %s\n", p);
- return AMR_CLEANUP;
- }
- if (*p != ':' && *p != st->endc) {
- (*pp)++; /* just for backwards compatibility */
- return AMR_BAD;
- }
+ if (!TryParseChar(&p, base, &st->sep)) {
+ Parse_Error(PARSE_FATAL,
+ "Invalid character number: %s\n", p);
+ return AMR_CLEANUP;
+ }
+ if (*p != ':' && *p != st->endc) {
+ (*pp)++; /* just for backwards compatibility */
+ return AMR_BAD;
+ }
- *pp = p;
- }
+ *pp = p;
+ }
ok:
- st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
- st->oneBigWord, st->sep);
- return AMR_OK;
+ st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
+ st->oneBigWord, st->sep);
+ return AMR_OK;
}
/* :tA, :tu, :tl, :ts<separator>, etc. */
static ApplyModifierResult
ApplyModifier_To(const char **pp, ApplyModifiersState *st)
{
- const char *mod = *pp;
- assert(mod[0] == 't');
+ const char *mod = *pp;
+ assert(mod[0] == 't');
- if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
- *pp = mod + 1;
- return AMR_BAD; /* Found ":t<endc>" or ":t:". */
- }
+ if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
+ *pp = mod + 1;
+ return AMR_BAD; /* Found ":t<endc>" or ":t:". */
+ }
- if (mod[1] == 's')
- return ApplyModifier_ToSep(pp, st);
+ if (mod[1] == 's')
+ return ApplyModifier_ToSep(pp, st);
- if (mod[2] != st->endc && mod[2] != ':') {
- *pp = mod + 1;
- return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
- }
+ if (mod[2] != st->endc && mod[2] != ':') {
+ *pp = mod + 1;
+ return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
+ }
- /* Check for two-character options: ":tu", ":tl" */
- if (mod[1] == 'A') { /* absolute path */
- st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
- st->oneBigWord, st->sep);
- *pp = mod + 2;
- return AMR_OK;
- }
+ /* Check for two-character options: ":tu", ":tl" */
+ if (mod[1] == 'A') { /* absolute path */
+ st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
+ st->oneBigWord, st->sep);
+ *pp = mod + 2;
+ return AMR_OK;
+ }
- if (mod[1] == 'u') { /* :tu */
- size_t i;
- size_t len = strlen(st->val);
- st->newVal = bmake_malloc(len + 1);
- for (i = 0; i < len + 1; i++)
- st->newVal[i] = ch_toupper(st->val[i]);
- *pp = mod + 2;
- return AMR_OK;
- }
+ if (mod[1] == 'u') { /* :tu */
+ size_t i;
+ size_t len = strlen(st->val);
+ st->newVal = bmake_malloc(len + 1);
+ for (i = 0; i < len + 1; i++)
+ st->newVal[i] = ch_toupper(st->val[i]);
+ *pp = mod + 2;
+ return AMR_OK;
+ }
- if (mod[1] == 'l') { /* :tl */
- size_t i;
- size_t len = strlen(st->val);
- st->newVal = bmake_malloc(len + 1);
- for (i = 0; i < len + 1; i++)
- st->newVal[i] = ch_tolower(st->val[i]);
- *pp = mod + 2;
- return AMR_OK;
- }
+ if (mod[1] == 'l') { /* :tl */
+ size_t i;
+ size_t len = strlen(st->val);
+ st->newVal = bmake_malloc(len + 1);
+ for (i = 0; i < len + 1; i++)
+ st->newVal[i] = ch_tolower(st->val[i]);
+ *pp = mod + 2;
+ return AMR_OK;
+ }
- if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
- st->oneBigWord = mod[1] == 'W';
- st->newVal = st->val;
- *pp = mod + 2;
- return AMR_OK;
- }
+ if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
+ st->oneBigWord = mod[1] == 'W';
+ st->newVal = st->val;
+ *pp = mod + 2;
+ return AMR_OK;
+ }
- /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
- *pp = mod + 1;
- return AMR_BAD;
+ /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
+ *pp = mod + 1;
+ return AMR_BAD;
}
/* :[#], :[1], :[-1..1], etc. */
static ApplyModifierResult
ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
{
- char *estr;
- int first, last;
- VarParseResult res;
- const char *p;
+ char *estr;
+ int first, last;
+ VarParseResult res;
+ const char *p;
- (*pp)++; /* skip the '[' */
- res = ParseModifierPart(pp, ']', st->eflags, st,
- &estr, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- /* now *pp points just after the closing ']' */
- if (**pp != ':' && **pp != st->endc)
- goto bad_modifier; /* Found junk after ']' */
-
- if (estr[0] == '\0')
- goto bad_modifier; /* empty square brackets in ":[]". */
-
- if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
- if (st->oneBigWord) {
- st->newVal = bmake_strdup("1");
- } else {
- Buffer buf;
+ (*pp)++; /* skip the '[' */
+ res = ParseModifierPart(pp, ']', st->eflags, st,
+ &estr, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ /* now *pp points just after the closing ']' */
+ if (**pp != ':' && **pp != st->endc)
+ goto bad_modifier; /* Found junk after ']' */
+
+ if (estr[0] == '\0')
+ goto bad_modifier; /* empty square brackets in ":[]". */
+
+ if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
+ if (st->oneBigWord) {
+ st->newVal = bmake_strdup("1");
+ } else {
+ Buffer buf;
- Words words = Str_Words(st->val, FALSE);
- size_t ac = words.len;
- Words_Free(words);
+ Words words = Str_Words(st->val, FALSE);
+ size_t ac = words.len;
+ Words_Free(words);
+
+ /* 3 digits + '\0' is usually enough */
+ Buf_InitSize(&buf, 4);
+ Buf_AddInt(&buf, (int)ac);
+ st->newVal = Buf_Destroy(&buf, FALSE);
+ }
+ goto ok;
+ }
- Buf_InitSize(&buf, 4); /* 3 digits + '\0' is usually enough */
- Buf_AddInt(&buf, (int)ac);
- st->newVal = Buf_Destroy(&buf, FALSE);
+ if (estr[0] == '*' && estr[1] == '\0') {
+ /* Found ":[*]" */
+ st->oneBigWord = TRUE;
+ st->newVal = st->val;
+ goto ok;
}
- goto ok;
- }
- if (estr[0] == '*' && estr[1] == '\0') {
- /* Found ":[*]" */
- st->oneBigWord = TRUE;
- st->newVal = st->val;
- goto ok;
- }
-
- if (estr[0] == '@' && estr[1] == '\0') {
- /* Found ":[@]" */
- st->oneBigWord = FALSE;
- st->newVal = st->val;
- goto ok;
- }
-
- /*
- * We expect estr to contain a single integer for :[N], or two integers
- * separated by ".." for :[start..end].
- */
- p = estr;
- if (!TryParseIntBase0(&p, &first))
- goto bad_modifier; /* Found junk instead of a number */
-
- if (p[0] == '\0') { /* Found only one integer in :[N] */
- last = first;
- } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
- /* Expecting another integer after ".." */
- p += 2;
- if (!TryParseIntBase0(&p, &last) || *p != '\0')
- goto bad_modifier; /* Found junk after ".." */
- } else
- goto bad_modifier; /* Found junk instead of ".." */
+ if (estr[0] == '@' && estr[1] == '\0') {
+ /* Found ":[@]" */
+ st->oneBigWord = FALSE;
+ st->newVal = st->val;
+ goto ok;
+ }
- /*
- * Now first and last are properly filled in, but we still have to check
- * for 0 as a special case.
- */
- if (first == 0 && last == 0) {
- /* ":[0]" or perhaps ":[0..0]" */
- st->oneBigWord = TRUE;
- st->newVal = st->val;
- goto ok;
- }
+ /*
+ * We expect estr to contain a single integer for :[N], or two
+ * integers separated by ".." for :[start..end].
+ */
+ p = estr;
+ if (!TryParseIntBase0(&p, &first))
+ goto bad_modifier; /* Found junk instead of a number */
+
+ if (p[0] == '\0') { /* Found only one integer in :[N] */
+ last = first;
+ } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
+ /* Expecting another integer after ".." */
+ p += 2;
+ if (!TryParseIntBase0(&p, &last) || *p != '\0')
+ goto bad_modifier; /* Found junk after ".." */
+ } else
+ goto bad_modifier; /* Found junk instead of ".." */
- /* ":[0..N]" or ":[N..0]" */
- if (first == 0 || last == 0)
- goto bad_modifier;
+ /*
+ * Now first and last are properly filled in, but we still have to
+ * check for 0 as a special case.
+ */
+ if (first == 0 && last == 0) {
+ /* ":[0]" or perhaps ":[0..0]" */
+ st->oneBigWord = TRUE;
+ st->newVal = st->val;
+ goto ok;
+ }
- /* Normal case: select the words described by first and last. */
- st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last);
+ /* ":[0..N]" or ":[N..0]" */
+ if (first == 0 || last == 0)
+ goto bad_modifier;
+
+ /* Normal case: select the words described by first and last. */
+ st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val,
+ first, last);
ok:
- free(estr);
- return AMR_OK;
+ free(estr);
+ return AMR_OK;
bad_modifier:
- free(estr);
- return AMR_BAD;
+ free(estr);
+ return AMR_BAD;
}
static int
str_cmp_asc(const void *a, const void *b)
{
- return strcmp(*(const char * const *)a, *(const char * const *)b);
+ return strcmp(*(const char *const *)a, *(const char *const *)b);
}
static int
str_cmp_desc(const void *a, const void *b)
{
- return strcmp(*(const char * const *)b, *(const char * const *)a);
+ return strcmp(*(const char *const *)b, *(const char *const *)a);
}
/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
@@ -2889,49 +2948,49 @@ ApplyModifier_Order(const char **pp, App
static ApplyModifierResult
ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
{
- char *then_expr, *else_expr;
- VarParseResult res;
-
- Boolean value = FALSE;
- VarEvalFlags then_eflags = VARE_NONE;
- VarEvalFlags else_eflags = VARE_NONE;
-
- int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
- if (st->eflags & VARE_WANTRES) {
- cond_rc = Cond_EvalCondition(st->var->name, &value);
- if (cond_rc != COND_INVALID && value)
- then_eflags = st->eflags;
- if (cond_rc != COND_INVALID && !value)
- else_eflags = st->eflags;
- }
+ char *then_expr, *else_expr;
+ VarParseResult res;
- (*pp)++; /* skip past the '?' */
- res = ParseModifierPart(pp, ':', then_eflags, st,
- &then_expr, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- res = ParseModifierPart(pp, st->endc, else_eflags, st,
- &else_expr, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- (*pp)--;
- if (cond_rc == COND_INVALID) {
- Error("Bad conditional expression `%s' in %s?%s:%s",
- st->var->name, st->var->name, then_expr, else_expr);
- return AMR_CLEANUP;
- }
+ Boolean value = FALSE;
+ VarEvalFlags then_eflags = VARE_NONE;
+ VarEvalFlags else_eflags = VARE_NONE;
- if (value) {
- st->newVal = then_expr;
- free(else_expr);
- } else {
- st->newVal = else_expr;
- free(then_expr);
- }
- ApplyModifiersState_Define(st);
- return AMR_OK;
+ int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
+ if (st->eflags & VARE_WANTRES) {
+ cond_rc = Cond_EvalCondition(st->var->name, &value);
+ if (cond_rc != COND_INVALID && value)
+ then_eflags = st->eflags;
+ if (cond_rc != COND_INVALID && !value)
+ else_eflags = st->eflags;
+ }
+
+ (*pp)++; /* skip past the '?' */
+ res = ParseModifierPart(pp, ':', then_eflags, st,
+ &then_expr, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ res = ParseModifierPart(pp, st->endc, else_eflags, st,
+ &else_expr, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ (*pp)--;
+ if (cond_rc == COND_INVALID) {
+ Error("Bad conditional expression `%s' in %s?%s:%s",
+ st->var->name, st->var->name, then_expr, else_expr);
+ return AMR_CLEANUP;
+ }
+
+ if (value) {
+ st->newVal = then_expr;
+ free(else_expr);
+ } else {
+ st->newVal = else_expr;
+ free(then_expr);
+ }
+ ApplyModifiersState_Define(st);
+ return AMR_OK;
}
/*
@@ -2958,80 +3017,81 @@ ApplyModifier_IfElse(const char **pp, Ap
static ApplyModifierResult
ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
{
- GNode *ctxt;
- char delim;
- char *val;
- VarParseResult res;
-
- const char *mod = *pp;
- const char *op = mod + 1;
-
- if (op[0] == '=')
- goto ok;
- if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
- goto ok;
- return AMR_UNKNOWN; /* "::<unrecognised>" */
-ok:
-
- if (st->var->name[0] == '\0') {
- *pp = mod + 1;
- return AMR_BAD;
- }
+ GNode *ctxt;
+ char delim;
+ char *val;
+ VarParseResult res;
- ctxt = st->ctxt; /* context where v belongs */
- if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
- Var *gv = VarFind(st->var->name, st->ctxt, FALSE);
- if (gv == NULL)
- ctxt = VAR_GLOBAL;
- else
- VarFreeEnv(gv, TRUE);
- }
+ const char *mod = *pp;
+ const char *op = mod + 1;
- switch (op[0]) {
- case '+':
- case '?':
- case '!':
- *pp = mod + 3;
- break;
- default:
- *pp = mod + 2;
- break;
- }
+ if (op[0] == '=')
+ goto ok;
+ if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
+ goto ok;
+ return AMR_UNKNOWN; /* "::<unrecognised>" */
+ok:
- delim = st->startc == '(' ? ')' : '}';
- res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
+ if (st->var->name[0] == '\0') {
+ *pp = mod + 1;
+ return AMR_BAD;
+ }
- (*pp)--;
+ ctxt = st->ctxt; /* context where v belongs */
+ if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
+ Var *gv = VarFind(st->var->name, st->ctxt, FALSE);
+ if (gv == NULL)
+ ctxt = VAR_GLOBAL;
+ else
+ VarFreeEnv(gv, TRUE);
+ }
- if (st->eflags & VARE_WANTRES) {
switch (op[0]) {
case '+':
- Var_Append(st->var->name, val, ctxt);
- break;
- case '!': {
- const char *errfmt;
- char *cmd_output = Cmd_Exec(val, &errfmt);
- if (errfmt != NULL)
- Error(errfmt, val);
- else
- Var_Set(st->var->name, cmd_output, ctxt);
- free(cmd_output);
- break;
- }
case '?':
- if (!(st->exprFlags & VEF_UNDEF))
+ case '!':
+ *pp = mod + 3;
break;
- /* FALLTHROUGH */
default:
- Var_Set(st->var->name, val, ctxt);
- break;
+ *pp = mod + 2;
+ break;
}
- }
- free(val);
- st->newVal = bmake_strdup("");
- return AMR_OK;
+
+ delim = st->startc == '(' ? ')' : '}';
+ res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL,
+ NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ (*pp)--;
+
+ if (st->eflags & VARE_WANTRES) {
+ switch (op[0]) {
+ case '+':
+ Var_Append(st->var->name, val, ctxt);
+ break;
+ case '!': {
+ const char *errfmt;
+ char *cmd_output = Cmd_Exec(val, &errfmt);
+ if (errfmt != NULL)
+ Error(errfmt, val);
+ else
+ Var_Set(st->var->name, cmd_output, ctxt);
+ free(cmd_output);
+ break;
+ }
+ case '?':
+ if (!(st->exprFlags & VEF_UNDEF))
+ break;
+ /* FALLTHROUGH */
+ default:
+ Var_Set(st->var->name, val, ctxt);
+ break;
+ }
+ }
+ free(val);
+ st->newVal = bmake_strdup("");
+ return AMR_OK;
}
/* :_=...
@@ -3039,22 +3099,22 @@ ok:
static ApplyModifierResult
ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
{
- const char *mod = *pp;
- if (!ModMatchEq(mod, "_", st->endc))
- return AMR_UNKNOWN;
-
- if (mod[1] == '=') {
- size_t n = strcspn(mod + 2, ":)}");
- char *name = bmake_strldup(mod + 2, n);
- Var_Set(name, st->val, st->ctxt);
- free(name);
- *pp = mod + 2 + n;
- } else {
- Var_Set("_", st->val, st->ctxt);
- *pp = mod + 1;
- }
- st->newVal = st->val;
- return AMR_OK;
+ const char *mod = *pp;
+ if (!ModMatchEq(mod, "_", st->endc))
+ return AMR_UNKNOWN;
+
+ if (mod[1] == '=') {
+ size_t n = strcspn(mod + 2, ":)}");
+ char *name = bmake_strldup(mod + 2, n);
+ Var_Set(name, st->val, st->ctxt);
+ free(name);
+ *pp = mod + 2 + n;
+ } else {
+ Var_Set("_", st->val, st->ctxt);
+ *pp = mod + 1;
+ }
+ st->newVal = st->val;
+ return AMR_OK;
}
/* Apply the given function to each word of the variable value,
@@ -3063,25 +3123,25 @@ static ApplyModifierResult
ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
ModifyWordsCallback modifyWord)
{
- char delim = (*pp)[1];
- if (delim != st->endc && delim != ':')
- return AMR_UNKNOWN;
-
- st->newVal = ModifyWords(st->val, modifyWord, NULL,
- st->oneBigWord, st->sep);
- (*pp)++;
- return AMR_OK;
+ char delim = (*pp)[1];
+ if (delim != st->endc && delim != ':')
+ return AMR_UNKNOWN;
+
+ st->newVal = ModifyWords(st->val, modifyWord, NULL,
+ st->oneBigWord, st->sep);
+ (*pp)++;
+ return AMR_OK;
}
static ApplyModifierResult
ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
{
- if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
- st->newVal = VarUniq(st->val);
- (*pp)++;
- return AMR_OK;
- } else
- return AMR_UNKNOWN;
+ if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
+ st->newVal = VarUniq(st->val);
+ (*pp)++;
+ return AMR_OK;
+ } else
+ return AMR_UNKNOWN;
}
#ifdef SYSVVARSUB
@@ -3089,55 +3149,55 @@ ApplyModifier_Unique(const char **pp, Ap
static ApplyModifierResult
ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
{
- char *lhs, *rhs;
- VarParseResult res;
+ char *lhs, *rhs;
+ VarParseResult res;
- const char *mod = *pp;
- Boolean eqFound = FALSE;
+ const char *mod = *pp;
+ Boolean eqFound = FALSE;
- /*
- * First we make a pass through the string trying to verify it is a
- * SysV-make-style translation. It must be: <lhs>=<rhs>
- */
- int depth = 1;
- const char *p = mod;
- while (*p != '\0' && depth > 0) {
- if (*p == '=') { /* XXX: should also test depth == 1 */
- eqFound = TRUE;
- /* continue looking for st->endc */
- } else if (*p == st->endc)
- depth--;
- else if (*p == st->startc)
- depth++;
- if (depth > 0)
- p++;
- }
- if (*p != st->endc || !eqFound)
- return AMR_UNKNOWN;
+ /*
+ * First we make a pass through the string trying to verify it is a
+ * SysV-make-style translation. It must be: <lhs>=<rhs>
+ */
+ int depth = 1;
+ const char *p = mod;
+ while (*p != '\0' && depth > 0) {
+ if (*p == '=') { /* XXX: should also test depth == 1 */
+ eqFound = TRUE;
+ /* continue looking for st->endc */
+ } else if (*p == st->endc)
+ depth--;
+ else if (*p == st->startc)
+ depth++;
+ if (depth > 0)
+ p++;
+ }
+ if (*p != st->endc || !eqFound)
+ return AMR_UNKNOWN;
- *pp = mod;
- res = ParseModifierPart(pp, '=', st->eflags, st,
- &lhs, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- /* The SysV modifier lasts until the end of the variable expression. */
- res = ParseModifierPart(pp, st->endc, st->eflags, st,
- &rhs, NULL, NULL, NULL);
- if (res != VPR_OK)
- return AMR_CLEANUP;
-
- (*pp)--;
- if (lhs[0] == '\0' && st->val[0] == '\0') {
- st->newVal = st->val; /* special case */
- } else {
- struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs};
- st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args,
- st->oneBigWord, st->sep);
- }
- free(lhs);
- free(rhs);
- return AMR_OK;
+ *pp = mod;
+ res = ParseModifierPart(pp, '=', st->eflags, st,
+ &lhs, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ /* The SysV modifier lasts until the end of the variable expression. */
+ res = ParseModifierPart(pp, st->endc, st->eflags, st,
+ &rhs, NULL, NULL, NULL);
+ if (res != VPR_OK)
+ return AMR_CLEANUP;
+
+ (*pp)--;
+ if (lhs[0] == '\0' && st->val[0] == '\0') {
+ st->newVal = st->val; /* special case */
+ } else {
+ struct ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
+ st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args,
+ st->oneBigWord, st->sep);
+ }
+ free(lhs);
+ free(rhs);
+ return AMR_OK;
}
#endif
@@ -3146,200 +3206,203 @@ ApplyModifier_SysV(const char **pp, Appl
static ApplyModifierResult
ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
{
- const char *p = *pp;
- if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
- if (st->eflags & VARE_WANTRES) {
- const char *errfmt;
- st->newVal = Cmd_Exec(st->val, &errfmt);
- if (errfmt != NULL)
- Error(errfmt, st->val);
+ const char *p = *pp;
+ if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
+ if (st->eflags & VARE_WANTRES) {
+ const char *errfmt;
+ st->newVal = Cmd_Exec(st->val, &errfmt);
+ if (errfmt != NULL)
+ Error(errfmt, st->val);
+ } else
+ st->newVal = bmake_strdup("");
+ *pp = p + 2;
+ return AMR_OK;
} else
- st->newVal = bmake_strdup("");
- *pp = p + 2;
- return AMR_OK;
- } else
- return AMR_UNKNOWN;
+ return AMR_UNKNOWN;
}
#endif
static void
LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc)
{
- char eflags_str[VarEvalFlags_ToStringSize];
- char vflags_str[VarFlags_ToStringSize];
- char exprflags_str[VarExprFlags_ToStringSize];
- Boolean is_single_char = mod[0] != '\0' &&
- (mod[1] == endc || mod[1] == ':');
-
- /* At this point, only the first character of the modifier can
- * be used since the end of the modifier is not yet known. */
- debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
- st->var->name, mod[0], is_single_char ? "" : "...", st->val,
- Enum_FlagsToString(eflags_str, sizeof eflags_str,
- st->eflags, VarEvalFlags_ToStringSpecs),
- Enum_FlagsToString(vflags_str, sizeof vflags_str,
- st->var->flags, VarFlags_ToStringSpecs),
- Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
- st->exprFlags,
- VarExprFlags_ToStringSpecs));
+ char eflags_str[VarEvalFlags_ToStringSize];
+ char vflags_str[VarFlags_ToStringSize];
+ char exprflags_str[VarExprFlags_ToStringSize];
+ Boolean is_single_char = mod[0] != '\0' &&
+ (mod[1] == endc || mod[1] == ':');
+
+ /* At this point, only the first character of the modifier can
+ * be used since the end of the modifier is not yet known. */
+ debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
+ st->var->name, mod[0], is_single_char ? "" : "...", st->val,
+ Enum_FlagsToString(eflags_str, sizeof eflags_str,
+ st->eflags, VarEvalFlags_ToStringSpecs),
+ Enum_FlagsToString(vflags_str, sizeof vflags_str,
+ st->var->flags, VarFlags_ToStringSpecs),
+ Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
+ st->exprFlags,
+ VarExprFlags_ToStringSpecs));
}
static void
LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
{
- char eflags_str[VarEvalFlags_ToStringSize];
- char vflags_str[VarFlags_ToStringSize];
- char exprflags_str[VarExprFlags_ToStringSize];
- const char *quot = st->newVal == var_Error ? "" : "\"";
- const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
-
- debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
- st->var->name, (int)(p - mod), mod, quot, newVal, quot,
- Enum_FlagsToString(eflags_str, sizeof eflags_str,
- st->eflags, VarEvalFlags_ToStringSpecs),
- Enum_FlagsToString(vflags_str, sizeof vflags_str,
- st->var->flags, VarFlags_ToStringSpecs),
- Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
- st->exprFlags,
- VarExprFlags_ToStringSpecs));
+ char eflags_str[VarEvalFlags_ToStringSize];
+ char vflags_str[VarFlags_ToStringSize];
+ char exprflags_str[VarExprFlags_ToStringSize];
+ const char *quot = st->newVal == var_Error ? "" : "\"";
+ const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
+
+ debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
+ st->var->name, (int)(p - mod), mod, quot, newVal, quot,
+ Enum_FlagsToString(eflags_str, sizeof eflags_str,
+ st->eflags, VarEvalFlags_ToStringSpecs),
+ Enum_FlagsToString(vflags_str, sizeof vflags_str,
+ st->var->flags, VarFlags_ToStringSpecs),
+ Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
+ st->exprFlags,
+ VarExprFlags_ToStringSpecs));
}
static ApplyModifierResult
ApplyModifier(const char **pp, ApplyModifiersState *st)
{
- switch (**pp) {
- case ':':
- return ApplyModifier_Assign(pp, st);
- case '@':
- return ApplyModifier_Loop(pp, st);
- case '_':
- return ApplyModifier_Remember(pp, st);
- case 'D':
- case 'U':
- return ApplyModifier_Defined(pp, st);
- case 'L':
- return ApplyModifier_Literal(pp, st);
- case 'P':
- return ApplyModifier_Path(pp, st);
- case '!':
- return ApplyModifier_ShellCommand(pp, st);
- case '[':
- return ApplyModifier_Words(pp, st);
- case 'g':
- return ApplyModifier_Gmtime(pp, st);
- case 'h':
- return ApplyModifier_Hash(pp, st);
- case 'l':
- return ApplyModifier_Localtime(pp, st);
- case 't':
- return ApplyModifier_To(pp, st);
- case 'N':
- case 'M':
- return ApplyModifier_Match(pp, st);
- case 'S':
- return ApplyModifier_Subst(pp, st);
- case '?':
- return ApplyModifier_IfElse(pp, st);
+ switch (**pp) {
+ case ':':
+ return ApplyModifier_Assign(pp, st);
+ case '@':
+ return ApplyModifier_Loop(pp, st);
+ case '_':
+ return ApplyModifier_Remember(pp, st);
+ case 'D':
+ case 'U':
+ return ApplyModifier_Defined(pp, st);
+ case 'L':
+ return ApplyModifier_Literal(pp, st);
+ case 'P':
+ return ApplyModifier_Path(pp, st);
+ case '!':
+ return ApplyModifier_ShellCommand(pp, st);
+ case '[':
+ return ApplyModifier_Words(pp, st);
+ case 'g':
+ return ApplyModifier_Gmtime(pp, st);
+ case 'h':
+ return ApplyModifier_Hash(pp, st);
+ case 'l':
+ return ApplyModifier_Localtime(pp, st);
+ case 't':
+ return ApplyModifier_To(pp, st);
+ case 'N':
+ case 'M':
+ return ApplyModifier_Match(pp, st);
+ case 'S':
+ return ApplyModifier_Subst(pp, st);
+ case '?':
+ return ApplyModifier_IfElse(pp, st);
#ifndef NO_REGEX
- case 'C':
- return ApplyModifier_Regex(pp, st);
+ case 'C':
+ return ApplyModifier_Regex(pp, st);
#endif
- case 'q':
- case 'Q':
- return ApplyModifier_Quote(pp, st);
- case 'T':
- return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
- case 'H':
- return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
- case 'E':
- return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
- case 'R':
- return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
- case 'r':
- return ApplyModifier_Range(pp, st);
- case 'O':
- return ApplyModifier_Order(pp, st);
- case 'u':
- return ApplyModifier_Unique(pp, st);
+ case 'q':
+ case 'Q':
+ return ApplyModifier_Quote(pp, st);
+ case 'T':
+ return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
+ case 'H':
+ return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
+ case 'E':
+ return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
+ case 'R':
+ return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
+ case 'r':
+ return ApplyModifier_Range(pp, st);
+ case 'O':
+ return ApplyModifier_Order(pp, st);
+ case 'u':
+ return ApplyModifier_Unique(pp, st);
#ifdef SUNSHCMD
- case 's':
- return ApplyModifier_SunShell(pp, st);
+ case 's':
+ return ApplyModifier_SunShell(pp, st);
#endif
- default:
- return AMR_UNKNOWN;
- }
+ default:
+ return AMR_UNKNOWN;
+ }
}
static char *ApplyModifiers(const char **, char *, char, char, Var *,
VarExprFlags *, GNode *, VarEvalFlags, void **);
typedef enum ApplyModifiersIndirectResult {
- AMIR_CONTINUE,
- AMIR_APPLY_MODS,
- AMIR_OUT
+ AMIR_CONTINUE,
+ AMIR_APPLY_MODS,
+ AMIR_OUT
} ApplyModifiersIndirectResult;
/* While expanding a variable expression, expand and apply indirect
* modifiers such as in ${VAR:${M_indirect}}. */
static ApplyModifiersIndirectResult
ApplyModifiersIndirect(
- ApplyModifiersState *const st,
- const char **const inout_p,
- void **const inout_freeIt
-) {
- const char *p = *inout_p;
- const char *mods;
- void *mods_freeIt;
-
- (void)Var_Parse(&p, st->ctxt, st->eflags, &mods, &mods_freeIt);
- /* TODO: handle errors */
+ ApplyModifiersState *const st,
+ const char **const inout_p,
+ void **const inout_freeIt
+)
+{
+ const char *p = *inout_p;
+ const char *mods;
+ void *mods_freeIt;
- /*
- * If we have not parsed up to st->endc or ':', we are not
- * interested. This means the expression ${VAR:${M_1}${M_2}}
- * is not accepted, but ${VAR:${M_1}:${M_2}} is.
- */
- if (mods[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
- if (opts.lint)
- Parse_Error(PARSE_FATAL,
- "Missing delimiter ':' after indirect modifier \"%.*s\"",
- (int)(p - *inout_p), *inout_p);
+ (void)Var_Parse(&p, st->ctxt, st->eflags, &mods, &mods_freeIt);
+ /* TODO: handle errors */
+ /*
+ * If we have not parsed up to st->endc or ':', we are not
+ * interested. This means the expression ${VAR:${M_1}${M_2}}
+ * is not accepted, but ${VAR:${M_1}:${M_2}} is.
+ */
+ if (mods[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
+ if (opts.lint)
+ Parse_Error(PARSE_FATAL,
+ "Missing delimiter ':' "
+ "after indirect modifier \"%.*s\"",
+ (int)(p - *inout_p), *inout_p);
+
+ free(mods_freeIt);
+ /* XXX: apply_mods doesn't sound like "not interested". */
+ /* XXX: Why is the indirect modifier parsed once more by
+ * apply_mods? If any, p should be advanced to nested_p. */
+ return AMIR_APPLY_MODS;
+ }
+
+ VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
+ mods, (int)(p - *inout_p), *inout_p);
+
+ if (mods[0] != '\0') {
+ const char *rval_pp = mods;
+ st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0',
+ st->var, &st->exprFlags, st->ctxt, st->eflags,
+ inout_freeIt);
+ if (st->val == var_Error || st->val == varUndefined ||
+ *rval_pp != '\0') {
+ free(mods_freeIt);
+ *inout_p = p;
+ return AMIR_OUT; /* error already reported */
+ }
+ }
free(mods_freeIt);
- /* XXX: apply_mods doesn't sound like "not interested". */
- /* XXX: Why is the indirect modifier parsed once more by
- * apply_mods? If any, p should be advanced to nested_p. */
- return AMIR_APPLY_MODS;
- }
-
- VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
- mods, (int)(p - *inout_p), *inout_p);
- if (mods[0] != '\0') {
- const char *rval_pp = mods;
- st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->var,
- &st->exprFlags, st->ctxt, st->eflags,
- inout_freeIt);
- if (st->val == var_Error || st->val == varUndefined ||
- *rval_pp != '\0') {
- free(mods_freeIt);
- *inout_p = p;
- return AMIR_OUT; /* error already reported */
+ if (*p == ':')
+ p++;
+ else if (*p == '\0' && st->endc != '\0') {
+ Error("Unclosed variable specification after complex "
+ "modifier (expecting '%c') for %s",
+ st->endc, st->var->name);
+ *inout_p = p;
+ return AMIR_OUT;
}
- }
- free(mods_freeIt);
- if (*p == ':')
- p++;
- else if (*p == '\0' && st->endc != '\0') {
- Error("Unclosed variable specification after complex "
- "modifier (expecting '%c') for %s", st->endc, st->var->name);
*inout_p = p;
- return AMIR_OUT;
- }
-
- *inout_p = p;
- return AMIR_CONTINUE;
+ return AMIR_CONTINUE;
}
/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
@@ -3354,112 +3417,121 @@ ApplyModifiers(
GNode *const ctxt, /* for looking up and modifying variables */
VarEvalFlags const eflags,
void **const inout_freeIt /* free this after using the return value */
-) {
- ApplyModifiersState st = {
- startc, endc, v, ctxt, eflags,
- val, /* .val */
- var_Error, /* .newVal */
- ' ', /* .sep */
- FALSE, /* .oneBigWord */
- *exprFlags /* .exprFlags */
- };
- const char *p;
- const char *mod;
- ApplyModifierResult res;
-
- assert(startc == '(' || startc == '{' || startc == '\0');
- assert(endc == ')' || endc == '}' || endc == '\0');
- assert(val != NULL);
-
- p = *pp;
-
- if (*p == '\0' && endc != '\0') {
- Error("Unclosed variable expression (expecting '%c') for \"%s\"",
- st.endc, st.var->name);
- goto cleanup;
- }
-
- while (*p != '\0' && *p != endc) {
-
- if (*p == '$') {
- ApplyModifiersIndirectResult amir;
- amir = ApplyModifiersIndirect(&st, &p, inout_freeIt);
- if (amir == AMIR_CONTINUE)
- continue;
- if (amir == AMIR_OUT)
- goto out;
- }
- st.newVal = var_Error; /* default value, in case of errors */
- mod = p;
+)
+{
+ ApplyModifiersState st = {
+ startc, endc, v, ctxt, eflags,
+ val, /* .val */
+ var_Error, /* .newVal */
+ ' ', /* .sep */
+ FALSE, /* .oneBigWord */
+ *exprFlags /* .exprFlags */
+ };
+ const char *p;
+ const char *mod;
+ ApplyModifierResult res;
+
+ assert(startc == '(' || startc == '{' || startc == '\0');
+ assert(endc == ')' || endc == '}' || endc == '\0');
+ assert(val != NULL);
+
+ p = *pp;
+
+ if (*p == '\0' && endc != '\0') {
+ Error(
+ "Unclosed variable expression (expecting '%c') for \"%s\"",
+ st.endc, st.var->name);
+ goto cleanup;
+ }
+
+ while (*p != '\0' && *p != endc) {
+
+ if (*p == '$') {
+ ApplyModifiersIndirectResult amir;
+ amir = ApplyModifiersIndirect(&st, &p, inout_freeIt);
+ if (amir == AMIR_CONTINUE)
+ continue;
+ if (amir == AMIR_OUT)
+ goto out;
+ }
+ st.newVal = var_Error; /* default value, in case of errors */
+ mod = p;
- if (DEBUG(VAR))
- LogBeforeApply(&st, mod, endc);
+ if (DEBUG(VAR))
+ LogBeforeApply(&st, mod, endc);
- res = ApplyModifier(&p, &st);
+ res = ApplyModifier(&p, &st);
#ifdef SYSVVARSUB
- if (res == AMR_UNKNOWN) {
- assert(p == mod);
- res = ApplyModifier_SysV(&p, &st);
- }
+ if (res == AMR_UNKNOWN) {
+ assert(p == mod);
+ res = ApplyModifier_SysV(&p, &st);
+ }
#endif
- if (res == AMR_UNKNOWN) {
- Error("Unknown modifier '%c'", *mod);
- /* Guess the end of the current modifier.
- * XXX: Skipping the rest of the modifier hides errors and leads
- * to wrong results. Parsing should rather stop here. */
- for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
- continue;
- st.newVal = var_Error;
- }
- if (res == AMR_CLEANUP)
- goto cleanup;
- if (res == AMR_BAD)
- goto bad_modifier;
-
- if (DEBUG(VAR))
- LogAfterApply(&st, p, mod);
-
- if (st.newVal != st.val) {
- if (*inout_freeIt != NULL) {
- free(st.val);
- *inout_freeIt = NULL;
- }
- st.val = st.newVal;
- if (st.val != var_Error && st.val != varUndefined)
- *inout_freeIt = st.val;
- }
- if (*p == '\0' && st.endc != '\0') {
- Error("Unclosed variable specification (expecting '%c') "
- "for \"%s\" (value \"%s\") modifier %c",
- st.endc, st.var->name, st.val, *mod);
- } else if (*p == ':') {
- p++;
- } else if (opts.lint && *p != '\0' && *p != endc) {
- Parse_Error(PARSE_FATAL,
- "Missing delimiter ':' after modifier \"%.*s\"",
- (int)(p - mod), mod);
- /* TODO: propagate parse error to the enclosing expression */
+ if (res == AMR_UNKNOWN) {
+ Error("Unknown modifier '%c'", *mod);
+ /*
+ * Guess the end of the current modifier.
+ * XXX: Skipping the rest of the modifier hides
+ * errors and leads to wrong results.
+ * Parsing should rather stop here.
+ */
+ for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
+ continue;
+ st.newVal = var_Error;
+ }
+ if (res == AMR_CLEANUP)
+ goto cleanup;
+ if (res == AMR_BAD)
+ goto bad_modifier;
+
+ if (DEBUG(VAR))
+ LogAfterApply(&st, p, mod);
+
+ if (st.newVal != st.val) {
+ if (*inout_freeIt != NULL) {
+ free(st.val);
+ *inout_freeIt = NULL;
+ }
+ st.val = st.newVal;
+ if (st.val != var_Error && st.val != varUndefined)
+ *inout_freeIt = st.val;
+ }
+ if (*p == '\0' && st.endc != '\0') {
+ Error(
+ "Unclosed variable specification (expecting '%c') "
+ "for \"%s\" (value \"%s\") modifier %c",
+ st.endc, st.var->name, st.val, *mod);
+ } else if (*p == ':') {
+ p++;
+ } else if (opts.lint && *p != '\0' && *p != endc) {
+ Parse_Error(PARSE_FATAL,
+ "Missing delimiter ':' after modifier \"%.*s\"",
+ (int)(p - mod), mod);
+ /*
+ * TODO: propagate parse error to the enclosing
+ * expression
+ */
+ }
}
- }
out:
- *pp = p;
- assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
- *exprFlags = st.exprFlags;
- return st.val;
+ *pp = p;
+ assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
+ *exprFlags = st.exprFlags;
+ return st.val;
bad_modifier:
- /* XXX: The modifier end is only guessed. */
- Error("Bad modifier `:%.*s' for %s",
- (int)strcspn(mod, ":)}"), mod, st.var->name);
+ /* XXX: The modifier end is only guessed. */
+ Error("Bad modifier `:%.*s' for %s",
+ (int)strcspn(mod, ":)}"), mod, st.var->name);
cleanup:
- *pp = p;
- free(*inout_freeIt);
- *inout_freeIt = NULL;
- *exprFlags = st.exprFlags;
- return var_Error;
+ *pp = p;
+ free(*inout_freeIt);
+ *inout_freeIt = NULL;
+ *exprFlags = st.exprFlags;
+ return var_Error;
}
/* Only four of the local variables are treated specially as they are the
@@ -3467,52 +3539,52 @@ cleanup:
static Boolean
VarnameIsDynamic(const char *name, size_t len)
{
- if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
- switch (name[0]) {
- case '@':
- case '%':
- case '*':
- case '!':
- return TRUE;
+ if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
+ switch (name[0]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ return TRUE;
+ }
+ return FALSE;
}
- return FALSE;
- }
- if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
- return strcmp(name, ".TARGET") == 0 ||
- strcmp(name, ".ARCHIVE") == 0 ||
- strcmp(name, ".PREFIX") == 0 ||
- strcmp(name, ".MEMBER") == 0;
- }
+ if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
+ return strcmp(name, ".TARGET") == 0 ||
+ strcmp(name, ".ARCHIVE") == 0 ||
+ strcmp(name, ".PREFIX") == 0 ||
+ strcmp(name, ".MEMBER") == 0;
+ }
- return FALSE;
+ return FALSE;
}
static const char *
UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
{
- if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
- /*
- * If substituting a local variable in a non-local context,
- * assume it's for dynamic source stuff. We have to handle
- * this specially and return the longhand for the variable
- * with the dollar sign escaped so it makes it back to the
- * caller. Only four of the local variables are treated
- * specially as they are the only four that will be set
- * when dynamic sources are expanded.
- */
- switch (varname) {
- case '@':
- return "$(.TARGET)";
- case '%':
- return "$(.MEMBER)";
- case '*':
- return "$(.PREFIX)";
- case '!':
- return "$(.ARCHIVE)";
+ if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
+ /*
+ * If substituting a local variable in a non-local context,
+ * assume it's for dynamic source stuff. We have to handle
+ * this specially and return the longhand for the variable
+ * with the dollar sign escaped so it makes it back to the
+ * caller. Only four of the local variables are treated
+ * specially as they are the only four that will be set
+ * when dynamic sources are expanded.
+ */
+ switch (varname) {
+ case '@':
+ return "$(.TARGET)";
+ case '%':
+ return "$(.MEMBER)";
+ case '*':
+ return "$(.PREFIX)";
+ case '!':
+ return "$(.ARCHIVE)";
+ }
}
- }
- return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
+ return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
}
/* Parse a variable name, until the end character or a colon, whichever
@@ -3522,68 +3594,69 @@ ParseVarname(const char **pp, char start
GNode *ctxt, VarEvalFlags eflags,
size_t *out_varname_len)
{
- Buffer buf;
- const char *p = *pp;
- int depth = 1;
-
- Buf_Init(&buf);
-
- while (*p != '\0') {
- /* Track depth so we can spot parse errors. */
- if (*p == startc)
- depth++;
- if (*p == endc) {
- if (--depth == 0)
- break;
- }
- if (*p == ':' && depth == 1)
- break;
+ Buffer buf;
+ const char *p = *pp;
+ int depth = 1;
+
+ Buf_Init(&buf);
+
+ while (*p != '\0') {
+ /* Track depth so we can spot parse errors. */
+ if (*p == startc)
+ depth++;
+ if (*p == endc) {
+ if (--depth == 0)
+ break;
+ }
+ if (*p == ':' && depth == 1)
+ break;
- /* A variable inside a variable, expand. */
- if (*p == '$') {
- const char *nested_val;
- void *nested_val_freeIt;
- (void)Var_Parse(&p, ctxt, eflags, &nested_val, &nested_val_freeIt);
- /* TODO: handle errors */
- Buf_AddStr(&buf, nested_val);
- free(nested_val_freeIt);
- } else {
- Buf_AddByte(&buf, *p);
- p++;
+ /* A variable inside a variable, expand. */
+ if (*p == '$') {
+ const char *nested_val;
+ void *nested_val_freeIt;
+ (void)Var_Parse(&p, ctxt, eflags, &nested_val,
+ &nested_val_freeIt);
+ /* TODO: handle errors */
+ Buf_AddStr(&buf, nested_val);
+ free(nested_val_freeIt);
+ } else {
+ Buf_AddByte(&buf, *p);
+ p++;
+ }
}
- }
- *pp = p;
- *out_varname_len = Buf_Len(&buf);
- return Buf_Destroy(&buf, FALSE);
+ *pp = p;
+ *out_varname_len = Buf_Len(&buf);
+ return Buf_Destroy(&buf, FALSE);
}
static VarParseResult
ValidShortVarname(char varname, const char *start)
{
- switch (varname) {
- case '\0':
- case ')':
- case '}':
- case ':':
- case '$':
- break; /* and continue below */
- default:
- return VPR_OK;
- }
+ switch (varname) {
+ case '\0':
+ case ')':
+ case '}':
+ case ':':
+ case '$':
+ break; /* and continue below */
+ default:
+ return VPR_OK;
+ }
- if (!opts.lint)
- return VPR_PARSE_SILENT;
+ if (!opts.lint)
+ return VPR_PARSE_SILENT;
- if (varname == '$')
- Parse_Error(PARSE_FATAL,
+ if (varname == '$')
+ Parse_Error(PARSE_FATAL,
"To escape a dollar, use \\$, not $$, at \"%s\"", start);
- else if (varname == '\0')
- Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
- else
- Parse_Error(PARSE_FATAL,
+ else if (varname == '\0')
+ Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
+ else
+ Parse_Error(PARSE_FATAL,
"Invalid variable name '%c', at \"%s\"", varname, start);
- return VPR_PARSE_MSG;
+ return VPR_PARSE_MSG;
}
/* Parse a single-character variable name such as $V or $@.
@@ -3594,42 +3667,44 @@ ParseVarnameShort(char startc, const cha
VarParseResult *out_FALSE_res, const char **out_FALSE_val,
Var **out_TRUE_var)
{
- char name[2];
- Var *v;
- VarParseResult vpr;
+ char name[2];
+ Var *v;
+ VarParseResult vpr;
- /*
- * If it's not bounded by braces of some sort, life is much simpler.
- * We just need to check for the first character and return the
- * value if it exists.
- */
+ /*
+ * If it's not bounded by braces of some sort, life is much simpler.
+ * We just need to check for the first character and return the
+ * value if it exists.
+ */
- vpr = ValidShortVarname(startc, *pp);
- if (vpr != VPR_OK) {
- (*pp)++;
- *out_FALSE_val = var_Error;
- *out_FALSE_res = vpr;
- return FALSE;
- }
+ vpr = ValidShortVarname(startc, *pp);
+ if (vpr != VPR_OK) {
+ (*pp)++;
+ *out_FALSE_val = var_Error;
+ *out_FALSE_res = vpr;
+ return FALSE;
+ }
- name[0] = startc;
- name[1] = '\0';
- v = VarFind(name, ctxt, TRUE);
- if (v == NULL) {
- *pp += 2;
+ name[0] = startc;
+ name[1] = '\0';
+ v = VarFind(name, ctxt, TRUE);
+ if (v == NULL) {
+ *pp += 2;
- *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
- if (opts.lint && *out_FALSE_val == var_Error) {
- Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
- *out_FALSE_res = VPR_UNDEF_MSG;
- return FALSE;
+ *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
+ if (opts.lint && *out_FALSE_val == var_Error) {
+ Parse_Error(PARSE_FATAL,
+ "Variable \"%s\" is undefined", name);
+ *out_FALSE_res = VPR_UNDEF_MSG;
+ return FALSE;
+ }
+ *out_FALSE_res =
+ eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
+ return FALSE;
}
- *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
- return FALSE;
- }
- *out_TRUE_var = v;
- return TRUE;
+ *out_TRUE_var = v;
+ return TRUE;
}
/* Find variables like @F or <D. */
@@ -3637,30 +3712,30 @@ static Var *
FindLocalLegacyVar(const char *varname, size_t namelen, GNode *ctxt,
const char **out_extraModifiers)
{
- /* Only resolve these variables if ctxt is a "real" target. */
- if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)
- return NULL;
-
- if (namelen != 2)
- return NULL;
- if (varname[1] != 'F' && varname[1] != 'D')
- return NULL;
- if (strchr("@%?*!<>", varname[0]) == NULL)
- return NULL;
-
- {
- char name[] = { varname[0], '\0' };
- Var *v = VarFind(name, ctxt, FALSE);
-
- if (v != NULL) {
- if (varname[1] == 'D') {
- *out_extraModifiers = "H:";
- } else { /* F */
- *out_extraModifiers = "T:";
- }
+ /* Only resolve these variables if ctxt is a "real" target. */
+ if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)
+ return NULL;
+
+ if (namelen != 2)
+ return NULL;
+ if (varname[1] != 'F' && varname[1] != 'D')
+ return NULL;
+ if (strchr("@%?*!<>", varname[0]) == NULL)
+ return NULL;
+
+ {
+ char name[] = { varname[0], '\0' };
+ Var *v = VarFind(name, ctxt, FALSE);
+
+ if (v != NULL) {
+ if (varname[1] == 'D') {
+ *out_extraModifiers = "H:";
+ } else { /* F */
+ *out_extraModifiers = "T:";
+ }
+ }
+ return v;
}
- return v;
- }
}
static VarParseResult
@@ -3668,30 +3743,31 @@ EvalUndefined(Boolean dynamic, const cha
VarEvalFlags eflags,
const char **out_val, void **out_freeIt)
{
- if (dynamic) {
- char *pstr = bmake_strsedup(start, p);
- free(varname);
- *out_val = pstr;
- *out_freeIt = pstr;
- return VPR_OK;
- }
-
- if ((eflags & VARE_UNDEFERR) && opts.lint) {
- Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", varname);
- free(varname);
- *out_val = var_Error;
- return VPR_UNDEF_MSG;
- }
+ if (dynamic) {
+ char *pstr = bmake_strsedup(start, p);
+ free(varname);
+ *out_val = pstr;
+ *out_freeIt = pstr;
+ return VPR_OK;
+ }
+
+ if ((eflags & VARE_UNDEFERR) && opts.lint) {
+ Parse_Error(PARSE_FATAL,
+ "Variable \"%s\" is undefined", varname);
+ free(varname);
+ *out_val = var_Error;
+ return VPR_UNDEF_MSG;
+ }
+
+ if (eflags & VARE_UNDEFERR) {
+ free(varname);
+ *out_val = var_Error;
+ return VPR_UNDEF_SILENT;
+ }
- if (eflags & VARE_UNDEFERR) {
free(varname);
- *out_val = var_Error;
- return VPR_UNDEF_SILENT;
- }
-
- free(varname);
- *out_val = varUndefined;
- return VPR_OK;
+ *out_val = varUndefined;
+ return VPR_OK;
}
/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
@@ -3717,76 +3793,84 @@ ParseVarnameLong(
const char **out_TRUE_extraModifiers,
Boolean *out_TRUE_dynamic,
VarExprFlags *out_TRUE_exprFlags
-) {
- size_t namelen;
- char *varname;
- Var *v;
- Boolean haveModifier;
- Boolean dynamic = FALSE;
-
- const char *const start = p;
- char endc = startc == '(' ? ')' : '}';
-
- p += 2; /* skip "${" or "$(" or "y(" */
- varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
+)
+{
+ size_t namelen;
+ char *varname;
+ Var *v;
+ Boolean haveModifier;
+ Boolean dynamic = FALSE;
+
+ const char *const start = p;
+ char endc = startc == '(' ? ')' : '}';
+
+ p += 2; /* skip "${" or "$(" or "y(" */
+ varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
+
+ if (*p == ':') {
+ haveModifier = TRUE;
+ } else if (*p == endc) {
+ haveModifier = FALSE;
+ } else {
+ Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
+ free(varname);
+ *out_FALSE_pp = p;
+ *out_FALSE_val = var_Error;
+ *out_FALSE_res = VPR_PARSE_MSG;
+ return FALSE;
+ }
- if (*p == ':') {
- haveModifier = TRUE;
- } else if (*p == endc) {
- haveModifier = FALSE;
- } else {
- Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
- free(varname);
- *out_FALSE_pp = p;
- *out_FALSE_val = var_Error;
- *out_FALSE_res = VPR_PARSE_MSG;
- return FALSE;
- }
+ v = VarFind(varname, ctxt, TRUE);
- v = VarFind(varname, ctxt, TRUE);
+ /* At this point, p points just after the variable name,
+ * either at ':' or at endc. */
- /* At this point, p points just after the variable name,
- * either at ':' or at endc. */
+ if (v == NULL) {
+ v = FindLocalLegacyVar(varname, namelen, ctxt,
+ out_TRUE_extraModifiers);
+ }
- if (v == NULL)
- v = FindLocalLegacyVar(varname, namelen, ctxt, out_TRUE_extraModifiers);
+ if (v == NULL) {
+ /*
+ * Defer expansion of dynamic variables if they appear in
+ * non-local context since they are not defined there.
+ */
+ dynamic = VarnameIsDynamic(varname, namelen) &&
+ (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
+
+ if (!haveModifier) {
+ p++; /* skip endc */
+ *out_FALSE_pp = p;
+ *out_FALSE_res = EvalUndefined(dynamic, start, p,
+ varname, eflags, out_FALSE_val, out_FALSE_freeIt);
+ return FALSE;
+ }
- if (v == NULL) {
- /* Defer expansion of dynamic variables if they appear in non-local
- * context since they are not defined there. */
- dynamic = VarnameIsDynamic(varname, namelen) &&
- (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
-
- if (!haveModifier) {
- p++; /* skip endc */
- *out_FALSE_pp = p;
- *out_FALSE_res = EvalUndefined(dynamic, start, p, varname, eflags,
- out_FALSE_val, out_FALSE_freeIt);
- return FALSE;
- }
-
- /* The variable expression is based on an undefined variable.
- * Nevertheless it needs a Var, for modifiers that access the
- * variable name, such as :L or :?.
- *
- * Most modifiers leave this expression in the "undefined" state
- * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
- * undefined expression into a defined expression (VEF_DEF).
- *
- * At the end, after applying all modifiers, if the expression
- * is still undefined, Var_Parse will return an empty string
- * instead of the actually computed value. */
- v = VarNew(varname, varname, "", 0);
- *out_TRUE_exprFlags = VEF_UNDEF;
- } else
- free(varname);
+ /*
+ * The variable expression is based on an undefined variable.
+ * Nevertheless it needs a Var, for modifiers that access the
+ * variable name, such as :L or :?.
+ *
+ * Most modifiers leave this expression in the "undefined"
+ * state (VEF_UNDEF), only a few modifiers like :D, :U, :L,
+ * :P turn this undefined expression into a defined
+ * expression (VEF_DEF).
+ *
+ * At the end, after applying all modifiers, if the expression
+ * is still undefined, Var_Parse will return an empty string
+ * instead of the actually computed value.
+ */
+ v = VarNew(varname, varname, "", 0);
+ *out_TRUE_exprFlags = VEF_UNDEF;
+ } else
+ free(varname);
- *out_TRUE_endc = endc;
- *out_TRUE_p = p;
- *out_TRUE_v = v;
- *out_TRUE_haveModifier = haveModifier;
- *out_TRUE_dynamic = dynamic;
- return TRUE;
+ *out_TRUE_endc = endc;
+ *out_TRUE_p = p;
+ *out_TRUE_v = v;
+ *out_TRUE_haveModifier = haveModifier;
+ *out_TRUE_dynamic = dynamic;
+ return TRUE;
}
/*
@@ -3832,190 +3916,210 @@ VarParseResult
Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
const char **out_val, void **out_val_freeIt)
{
- const char *p = *pp;
- const char *const start = p;
- Boolean haveModifier; /* TRUE if have modifiers for the variable */
- char startc; /* Starting character if variable in parens
- * or braces */
- char endc; /* Ending character if variable in parens
- * or braces */
- Boolean dynamic; /* TRUE if the variable is local and we're
- * expanding it in a non-local context. This
- * is done to support dynamic sources. The
- * result is just the expression, unaltered */
- const char *extramodifiers;
- Var *v;
- char *value;
- char eflags_str[VarEvalFlags_ToStringSize];
- VarExprFlags exprFlags = 0;
-
- VAR_DEBUG2("Var_Parse: %s with %s\n", start,
- Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
- VarEvalFlags_ToStringSpecs));
-
- *out_val_freeIt = NULL;
- extramodifiers = NULL; /* extra modifiers to apply first */
- dynamic = FALSE;
-
- /* Appease GCC, which thinks that the variable might not be
- * initialized. */
- endc = '\0';
+ const char *p = *pp;
+ const char *const start = p;
+ /* TRUE if have modifiers for the variable. */
+ Boolean haveModifier;
+ /* Starting character if variable in parens or braces. */
+ char startc;
+ /* Ending character if variable in parens or braces. */
+ char endc;
+ /*
+ * TRUE if the variable is local and we're expanding it in a
+ * non-local context. This is done to support dynamic sources.
+ * The result is just the expression, unaltered.
+ */
+ Boolean dynamic;
+ const char *extramodifiers;
+ Var *v;
+ char *value;
+ char eflags_str[VarEvalFlags_ToStringSize];
+ VarExprFlags exprFlags = 0;
+
+ VAR_DEBUG2("Var_Parse: %s with %s\n", start,
+ Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
+ VarEvalFlags_ToStringSpecs));
+
+ *out_val_freeIt = NULL;
+ extramodifiers = NULL; /* extra modifiers to apply first */
+ dynamic = FALSE;
- startc = p[1];
- if (startc != '(' && startc != '{') {
- VarParseResult res;
- if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v))
- return res;
- haveModifier = FALSE;
- p++;
- } else {
- VarParseResult res;
- if (!ParseVarnameLong(p, startc, ctxt, eflags,
- pp, &res, out_val, out_val_freeIt,
- &endc, &p, &v, &haveModifier, &extramodifiers,
- &dynamic, &exprFlags))
- return res;
- }
+ /*
+ * Appease GCC, which thinks that the variable might not be
+ * initialized.
+ */
+ endc = '\0';
- if (v->flags & VAR_IN_USE)
- Fatal("Variable %s is recursive.", v->name);
+ startc = p[1];
+ if (startc != '(' && startc != '{') {
+ VarParseResult res;
+ if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res,
+ out_val, &v))
+ return res;
+ haveModifier = FALSE;
+ p++;
+ } else {
+ VarParseResult res;
+ if (!ParseVarnameLong(p, startc, ctxt, eflags,
+ pp, &res, out_val, out_val_freeIt,
+ &endc, &p, &v, &haveModifier, &extramodifiers,
+ &dynamic, &exprFlags))
+ return res;
+ }
- /* XXX: This assignment creates an alias to the current value of the
- * variable. This means that as long as the value of the expression stays
- * the same, the value of the variable must not change.
- * Using the '::=' modifier, it could be possible to do exactly this.
- * At the bottom of this function, the resulting value is compared to the
- * then-current value of the variable. This might also invoke undefined
- * behavior. */
- value = Buf_GetAll(&v->val, NULL);
-
- /* Before applying any modifiers, expand any nested expressions from the
- * variable value. */
- if (strchr(value, '$') != NULL && (eflags & VARE_WANTRES)) {
- VarEvalFlags nested_eflags = eflags;
- if (opts.lint)
- nested_eflags &= ~(unsigned)VARE_UNDEFERR;
- v->flags |= VAR_IN_USE;
- (void)Var_Subst(value, ctxt, nested_eflags, &value);
- v->flags &= ~(unsigned)VAR_IN_USE;
- /* TODO: handle errors */
- *out_val_freeIt = value;
- }
+ if (v->flags & VAR_IN_USE)
+ Fatal("Variable %s is recursive.", v->name);
- if (haveModifier || extramodifiers != NULL) {
- void *extraFree;
+ /*
+ * XXX: This assignment creates an alias to the current value of the
+ * variable. This means that as long as the value of the expression
+ * stays the same, the value of the variable must not change.
+ * Using the '::=' modifier, it could be possible to do exactly this.
+ * At the bottom of this function, the resulting value is compared to
+ * the then-current value of the variable. This might also invoke
+ * undefined behavior.
+ */
+ value = Buf_GetAll(&v->val, NULL);
- extraFree = NULL;
- if (extramodifiers != NULL) {
- const char *em = extramodifiers;
- value = ApplyModifiers(&em, value, '\0', '\0',
- v, &exprFlags, ctxt, eflags, &extraFree);
+ /*
+ * Before applying any modifiers, expand any nested expressions from
+ * the variable value.
+ */
+ if (strchr(value, '$') != NULL && (eflags & VARE_WANTRES)) {
+ VarEvalFlags nested_eflags = eflags;
+ if (opts.lint)
+ nested_eflags &= ~(unsigned)VARE_UNDEFERR;
+ v->flags |= VAR_IN_USE;
+ (void)Var_Subst(value, ctxt, nested_eflags, &value);
+ v->flags &= ~(unsigned)VAR_IN_USE;
+ /* TODO: handle errors */
+ *out_val_freeIt = value;
}
- if (haveModifier) {
- /* Skip initial colon. */
- p++;
-
- value = ApplyModifiers(&p, value, startc, endc,
- v, &exprFlags, ctxt, eflags, out_val_freeIt);
- free(extraFree);
- } else {
- *out_val_freeIt = extraFree;
- }
- }
+ if (haveModifier || extramodifiers != NULL) {
+ void *extraFree;
- if (*p != '\0') /* Skip past endc if possible. */
- p++;
+ extraFree = NULL;
+ if (extramodifiers != NULL) {
+ const char *em = extramodifiers;
+ value = ApplyModifiers(&em, value, '\0', '\0',
+ v, &exprFlags, ctxt, eflags, &extraFree);
+ }
- *pp = p;
+ if (haveModifier) {
+ /* Skip initial colon. */
+ p++;
+
+ value = ApplyModifiers(&p, value, startc, endc,
+ v, &exprFlags, ctxt, eflags, out_val_freeIt);
+ free(extraFree);
+ } else {
+ *out_val_freeIt = extraFree;
+ }
+ }
- if (v->flags & VAR_FROM_ENV) {
- /* Free the environment variable now since we own it. */
+ if (*p != '\0') /* Skip past endc if possible. */
+ p++;
- char *varValue = Buf_Destroy(&v->val, FALSE);
- if (value == varValue) {
- /* Don't free the variable value since it will be returned. */
- *out_val_freeIt = varValue;
- } else
- free(varValue);
+ *pp = p;
- free(v->name_freeIt);
- free(v);
+ if (v->flags & VAR_FROM_ENV) {
+ /* Free the environment variable now since we own it. */
- } else if (exprFlags & VEF_UNDEF) {
- if (!(exprFlags & VEF_DEF)) {
- /* TODO: Use a local variable instead of out_val_freeIt.
- * Variables named out_* must only be written to. */
- if (*out_val_freeIt != NULL) {
- free(*out_val_freeIt);
- *out_val_freeIt = NULL;
- }
- if (dynamic) {
- value = bmake_strsedup(start, p);
- *out_val_freeIt = value;
- } else {
- /* The expression is still undefined, therefore discard the
- * actual value and return an error marker instead. */
- value = eflags & VARE_UNDEFERR ? var_Error : varUndefined;
- }
+ char *varValue = Buf_Destroy(&v->val, FALSE);
+ if (value == varValue)
+ *out_val_freeIt = varValue;
+ else
+ free(varValue);
+
+ free(v->name_freeIt);
+ free(v);
+
+ } else if (exprFlags & VEF_UNDEF) {
+ if (!(exprFlags & VEF_DEF)) {
+ /*
+ * TODO: Use a local variable instead of
+ * out_val_freeIt. Variables named out_* must only
+ * be written to.
+ */
+ if (*out_val_freeIt != NULL) {
+ free(*out_val_freeIt);
+ *out_val_freeIt = NULL;
+ }
+ if (dynamic) {
+ value = bmake_strsedup(start, p);
+ *out_val_freeIt = value;
+ } else {
+ /*
+ * The expression is still undefined,
+ * therefore discard the actual value and
+ * return an error marker instead.
+ */
+ value = eflags & VARE_UNDEFERR
+ ? var_Error : varUndefined;
+ }
+ }
+ if (value != Buf_GetAll(&v->val, NULL))
+ Buf_Destroy(&v->val, TRUE);
+ free(v->name_freeIt);
+ free(v);
}
- if (value != Buf_GetAll(&v->val, NULL))
- Buf_Destroy(&v->val, TRUE);
- free(v->name_freeIt);
- free(v);
- }
- *out_val = value;
- return VPR_UNKNOWN;
+ *out_val = value;
+ return VPR_UNKNOWN;
}
static void
VarSubstNested(const char **const pp, Buffer *const buf, GNode *const ctxt,
VarEvalFlags const eflags, Boolean *inout_errorReported)
{
- const char *p = *pp;
- const char *nested_p = p;
- const char *val;
- void *val_freeIt;
-
- (void)Var_Parse(&nested_p, ctxt, eflags, &val, &val_freeIt);
- /* TODO: handle errors */
-
- if (val == var_Error || val == varUndefined) {
- if (!preserveUndefined) {
- p = nested_p;
- } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
- /* XXX: This condition is wrong. If val == var_Error,
- * this doesn't necessarily mean there was an undefined
- * variable. It could equally well be a parse error; see
- * unit-tests/varmod-order.exp. */
+ const char *p = *pp;
+ const char *nested_p = p;
+ const char *val;
+ void *val_freeIt;
- /*
- * If variable is undefined, complain and skip the
- * variable. The complaint will stop us from doing anything
- * when the file is parsed.
- */
- if (!*inout_errorReported) {
- Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
- (int)(size_t)(nested_p - p), p);
- }
- p = nested_p;
- *inout_errorReported = TRUE;
+ (void)Var_Parse(&nested_p, ctxt, eflags, &val, &val_freeIt);
+ /* TODO: handle errors */
+
+ if (val == var_Error || val == varUndefined) {
+ if (!preserveUndefined) {
+ p = nested_p;
+ } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
+
+ /*
+ * XXX: This condition is wrong. If val == var_Error,
+ * this doesn't necessarily mean there was an undefined
+ * variable. It could equally well be a parse error;
+ * see unit-tests/varmod-order.exp.
+ */
+
+ /*
+ * If variable is undefined, complain and skip the
+ * variable. The complaint will stop us from doing
+ * anything when the file is parsed.
+ */
+ if (!*inout_errorReported) {
+ Parse_Error(PARSE_FATAL,
+ "Undefined variable \"%.*s\"",
+ (int)(size_t)(nested_p - p), p);
+ }
+ p = nested_p;
+ *inout_errorReported = TRUE;
+ } else {
+ /* Copy the initial '$' of the undefined expression,
+ * thereby deferring expansion of the expression, but
+ * expand nested expressions if already possible.
+ * See unit-tests/varparse-undef-partial.mk. */
+ Buf_AddByte(buf, *p);
+ p++;
+ }
} else {
- /* Copy the initial '$' of the undefined expression,
- * thereby deferring expansion of the expression, but
- * expand nested expressions if already possible.
- * See unit-tests/varparse-undef-partial.mk. */
- Buf_AddByte(buf, *p);
- p++;
+ p = nested_p;
+ Buf_AddStr(buf, val);
}
- } else {
- p = nested_p;
- Buf_AddStr(buf, val);
- }
- free(val_freeIt);
+ free(val_freeIt);
- *pp = p;
+ *pp = p;
}
/* Expand all variable expressions like $V, ${VAR}, $(VAR:Modifiers) in the
@@ -4031,90 +4135,95 @@ VarSubstNested(const char **const pp, Bu
VarParseResult
Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
{
- const char *p = str;
- Buffer res;
+ const char *p = str;
+ Buffer res;
- /* Set true if an error has already been reported,
- * to prevent a plethora of messages when recursing */
- /* XXX: Why is the 'static' necessary here? */
- static Boolean errorReported;
-
- Buf_Init(&res);
- errorReported = FALSE;
-
- while (*p != '\0') {
- if (p[0] == '$' && p[1] == '$') {
- /* A dollar sign may be escaped with another dollar sign. */
- if (save_dollars && (eflags & VARE_KEEP_DOLLAR))
- Buf_AddByte(&res, '$');
- Buf_AddByte(&res, '$');
- p += 2;
-
- } else if (p[0] == '$') {
- VarSubstNested(&p, &res, ctxt, eflags, &errorReported);
+ /* Set true if an error has already been reported,
+ * to prevent a plethora of messages when recursing */
+ /* XXX: Why is the 'static' necessary here? */
+ static Boolean errorReported;
+
+ Buf_Init(&res);
+ errorReported = FALSE;
+
+ while (*p != '\0') {
+ if (p[0] == '$' && p[1] == '$') {
+ /*
+ * A dollar sign may be escaped with another dollar
+ * sign.
+ */
+ if (save_dollars && (eflags & VARE_KEEP_DOLLAR))
+ Buf_AddByte(&res, '$');
+ Buf_AddByte(&res, '$');
+ p += 2;
- } else {
- /*
- * Skip as many characters as possible -- either to the end of
- * the string or to the next dollar sign (variable expression).
- */
- const char *plainStart = p;
+ } else if (p[0] == '$') {
+ VarSubstNested(&p, &res, ctxt, eflags, &errorReported);
- for (p++; *p != '$' && *p != '\0'; p++)
- continue;
- Buf_AddBytesBetween(&res, plainStart, p);
+ } else {
+ /*
+ * Skip as many characters as possible -- either to
+ * the end of the string or to the next dollar sign
+ * (variable expression).
+ */
+ const char *plainStart = p;
+
+ for (p++; *p != '$' && *p != '\0'; p++)
+ continue;
+ Buf_AddBytesBetween(&res, plainStart, p);
+ }
}
- }
- *out_res = Buf_DestroyCompact(&res);
- return VPR_OK;
+ *out_res = Buf_DestroyCompact(&res);
+ return VPR_OK;
}
/* Initialize the variables module. */
void
Var_Init(void)
{
- VAR_INTERNAL = GNode_New("Internal");
- VAR_GLOBAL = GNode_New("Global");
- VAR_CMDLINE = GNode_New("Command");
+ VAR_INTERNAL = GNode_New("Internal");
+ VAR_GLOBAL = GNode_New("Global");
+ VAR_CMDLINE = GNode_New("Command");
}
/* Clean up the variables module. */
void
Var_End(void)
{
- Var_Stats();
+ Var_Stats();
}
void
Var_Stats(void)
{
- HashTable_DebugStats(&VAR_GLOBAL->vars, "VAR_GLOBAL");
+ HashTable_DebugStats(&VAR_GLOBAL->vars, "VAR_GLOBAL");
}
/* Print all variables in a context, sorted by name. */
void
Var_Dump(GNode *ctxt)
{
- Vector /* of const char * */ vec;
- HashIter hi;
- size_t i;
- const char **varnames;
-
- Vector_Init(&vec, sizeof(const char *));
-
- HashIter_Init(&hi, &ctxt->vars);
- while (HashIter_Next(&hi) != NULL)
- *(const char **)Vector_Push(&vec) = hi.entry->key;
- varnames = vec.items;
-
- qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
-
- for (i = 0; i < vec.len; i++) {
- const char *varname = varnames[i];
- Var *var = HashTable_FindValue(&ctxt->vars, varname);
- debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
- }
+ Vector /* of const char * */ vec;
+ HashIter hi;
+ size_t i;
+ const char **varnames;
+
+ Vector_Init(&vec, sizeof(const char *));
+
+ HashIter_Init(&hi, &ctxt->vars);
+ while (HashIter_Next(&hi) != NULL)
+ *(const char **)Vector_Push(&vec) = hi.entry->key;
+ varnames = vec.items;
+
+ qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
+
+ for (i = 0; i < vec.len; i++) {
+ const char *varname = varnames[i];
+ Var *var = HashTable_FindValue(&ctxt->vars, varname);
+ debug_printf("%-16s = %s\n",
+ varname, Buf_GetAll(&var->val, NULL));
+ }
- Vector_Done(&vec);
+ Vector_Done(&vec);
}