Mon Nov 2 16:55:18 2020 UTC ()
make(1): merge variables p and nested_p in ApplyModifiersIndirect

When the code was still in ApplyModifiers, the variable nested_p was
necessary to distinguish the parsing position in the nested modifier
from the parsing position of the main expression.


(rillig)
diff -r1.643 -r1.644 src/usr.bin/make/var.c

cvs diff -r1.643 -r1.644 src/usr.bin/make/var.c (switch to unified diff)

--- src/usr.bin/make/var.c 2020/11/02 16:48:49 1.643
+++ src/usr.bin/make/var.c 2020/11/02 16:55:18 1.644
@@ -1,1132 +1,1132 @@ @@ -1,1132 +1,1132 @@
1/* $NetBSD: var.c,v 1.643 2020/11/02 16:48:49 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.644 2020/11/02 16:55:18 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/* 71/*
72 * Handling of variables and the expressions formed from them. 72 * Handling of variables and the expressions formed from them.
73 * 73 *
74 * Variables are set using lines of the form VAR=value. Both the variable 74 * Variables are set using lines of the form VAR=value. Both the variable
75 * name and the value can contain references to other variables, by using 75 * name and the value can contain references to other variables, by using
76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. 76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77 * 77 *
78 * Interface: 78 * Interface:
79 * Var_Init Initialize this module. 79 * Var_Init Initialize this module.
80 * 80 *
81 * Var_End Clean up the module. 81 * Var_End Clean up the module.
82 * 82 *
83 * Var_Set Set the value of the variable, creating it if 83 * Var_Set Set the value of the variable, creating it if
84 * necessary. 84 * necessary.
85 * 85 *
86 * Var_Append Append more characters to the variable, creating it if 86 * Var_Append Append more characters to the variable, creating it if
87 * necessary. A space is placed between the old value and 87 * necessary. A space is placed between the old value and
88 * the new one. 88 * the new one.
89 * 89 *
90 * Var_Exists See if a variable exists. 90 * Var_Exists See if a variable exists.
91 * 91 *
92 * Var_Value Return the unexpanded value of a variable, or NULL if 92 * Var_Value Return the unexpanded value of a variable, or NULL if
93 * the variable is undefined. 93 * the variable is undefined.
94 * 94 *
95 * Var_Subst Substitute all variable expressions in a string. 95 * Var_Subst Substitute all variable expressions in a string.
96 * 96 *
97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}. 97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
98 * 98 *
99 * Var_Delete Delete a variable. 99 * Var_Delete Delete a variable.
100 * 100 *
101 * Var_ExportVars Export some or even all variables to the environment 101 * Var_ExportVars Export some or even all variables to the environment
102 * of this process and its child processes. 102 * of this process and its child processes.
103 * 103 *
104 * Var_Export Export the variable to the environment of this process 104 * Var_Export Export the variable to the environment of this process
105 * and its child processes. 105 * and its child processes.
106 * 106 *
107 * Var_UnExport Don't export the variable anymore. 107 * Var_UnExport Don't export the variable anymore.
108 * 108 *
109 * Debugging: 109 * Debugging:
110 * Var_Stats Print out hashing statistics if in -dh mode. 110 * Var_Stats Print out hashing statistics if in -dh mode.
111 * 111 *
112 * Var_Dump Print out all variables defined in the given context. 112 * Var_Dump Print out all variables defined in the given context.
113 * 113 *
114 * XXX: There's a lot of duplication in these functions. 114 * XXX: There's a lot of duplication in these functions.
115 */ 115 */
116 116
117#include <sys/stat.h> 117#include <sys/stat.h>
118#ifndef NO_REGEX 118#ifndef NO_REGEX
119#include <sys/types.h> 119#include <sys/types.h>
120#include <regex.h> 120#include <regex.h>
121#endif 121#endif
122#include <errno.h> 122#include <errno.h>
123#include <inttypes.h> 123#include <inttypes.h>
124#include <limits.h> 124#include <limits.h>
125#include <time.h> 125#include <time.h>
126 126
127#include "make.h" 127#include "make.h"
128#include "dir.h" 128#include "dir.h"
129#include "job.h" 129#include "job.h"
130#include "metachar.h" 130#include "metachar.h"
131 131
132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
133MAKE_RCSID("$NetBSD: var.c,v 1.643 2020/11/02 16:48:49 rillig Exp $"); 133MAKE_RCSID("$NetBSD: var.c,v 1.644 2020/11/02 16:55:18 rillig Exp $");
134 134
135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
139 139
140ENUM_FLAGS_RTTI_3(VarEvalFlags, 140ENUM_FLAGS_RTTI_3(VarEvalFlags,
141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
142 142
143/* 143/*
144 * This lets us tell if we have replaced the original environ 144 * This lets us tell if we have replaced the original environ
145 * (which we cannot free). 145 * (which we cannot free).
146 */ 146 */
147char **savedEnv = NULL; 147char **savedEnv = NULL;
148 148
149/* Special return value for Var_Parse, indicating a parse error. It may be 149/* Special return value for Var_Parse, indicating a parse error. It may be
150 * caused by an undefined variable, a syntax error in a modifier or 150 * caused by an undefined variable, a syntax error in a modifier or
151 * something entirely different. */ 151 * something entirely different. */
152char var_Error[] = ""; 152char var_Error[] = "";
153 153
154/* Special return value for Var_Parse, indicating an undefined variable in 154/* Special return value for Var_Parse, indicating an undefined variable in
155 * a case where VARE_UNDEFERR is not set. This undefined variable is 155 * a case where VARE_UNDEFERR is not set. This undefined variable is
156 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 156 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
157 * be deferred until it is defined in an actual target. */ 157 * be deferred until it is defined in an actual target. */
158static char varUndefined[] = ""; 158static char varUndefined[] = "";
159 159
160/* Special return value for Var_Parse, just to avoid allocating empty strings. 160/* Special return value for Var_Parse, just to avoid allocating empty strings.
161 * In contrast to var_Error and varUndefined, this is not an error marker but 161 * In contrast to var_Error and varUndefined, this is not an error marker but
162 * just an ordinary successful return value. */ 162 * just an ordinary successful return value. */
163static char emptyString[] = ""; 163static char emptyString[] = "";
164 164
165/* 165/*
166 * Traditionally this make consumed $$ during := like any other expansion. 166 * Traditionally this make consumed $$ during := like any other expansion.
167 * Other make's do not, and this make follows straight since 2016-01-09. 167 * Other make's do not, and this make follows straight since 2016-01-09.
168 * 168 *
169 * This knob allows controlling the behavior. 169 * This knob allows controlling the behavior.
170 * FALSE to consume $$ during := assignment. 170 * FALSE to consume $$ during := assignment.
171 * TRUE to preserve $$ during := assignment. 171 * TRUE to preserve $$ during := assignment.
172 */ 172 */
173#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 173#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
174static Boolean save_dollars = TRUE; 174static Boolean save_dollars = TRUE;
175 175
176/* 176/*
177 * Internally, variables are contained in four different contexts. 177 * Internally, variables are contained in four different contexts.
178 * 1) the environment. They cannot be changed. If an environment 178 * 1) the environment. They cannot be changed. If an environment
179 * variable is appended to, the result is placed in the global 179 * variable is appended to, the result is placed in the global
180 * context. 180 * context.
181 * 2) the global context. Variables set in the makefiles are located 181 * 2) the global context. Variables set in the makefiles are located
182 * here. 182 * here.
183 * 3) the command-line context. All variables set on the command line 183 * 3) the command-line context. All variables set on the command line
184 * are placed in this context. 184 * are placed in this context.
185 * 4) the local context. Each target has associated with it a context 185 * 4) the local context. Each target has associated with it a context
186 * list. On this list are located the structures describing such 186 * list. On this list are located the structures describing such
187 * local variables as $(@) and $(*) 187 * local variables as $(@) and $(*)
188 * The four contexts are searched in the reverse order from which they are 188 * The four contexts are searched in the reverse order from which they are
189 * listed (but see opts.checkEnvFirst). 189 * listed (but see opts.checkEnvFirst).
190 */ 190 */
191GNode *VAR_INTERNAL; /* variables from make itself */ 191GNode *VAR_INTERNAL; /* variables from make itself */
192GNode *VAR_GLOBAL; /* variables from the makefile */ 192GNode *VAR_GLOBAL; /* variables from the makefile */
193GNode *VAR_CMDLINE; /* variables defined on the command-line */ 193GNode *VAR_CMDLINE; /* variables defined on the command-line */
194 194
195typedef enum VarFlags { 195typedef enum VarFlags {
196 196
197 /* The variable's value is currently being used by Var_Parse or Var_Subst. 197 /* The variable's value is currently being used by Var_Parse or Var_Subst.
198 * This marker is used to avoid endless recursion. */ 198 * This marker is used to avoid endless recursion. */
199 VAR_IN_USE = 0x01, 199 VAR_IN_USE = 0x01,
200 200
201 /* The variable comes from the environment. 201 /* The variable comes from the environment.
202 * These variables are not registered in any GNode, therefore they must 202 * These variables are not registered in any GNode, therefore they must
203 * be freed as soon as they are not used anymore. */ 203 * be freed as soon as they are not used anymore. */
204 VAR_FROM_ENV = 0x02, 204 VAR_FROM_ENV = 0x02,
205 205
206 /* The variable is exported to the environment, to be used by child 206 /* The variable is exported to the environment, to be used by child
207 * processes. */ 207 * processes. */
208 VAR_EXPORTED = 0x10, 208 VAR_EXPORTED = 0x10,
209 209
210 /* At the point where this variable was exported, it contained an 210 /* At the point where this variable was exported, it contained an
211 * unresolved reference to another variable. Before any child process is 211 * unresolved reference to another variable. Before any child process is
212 * started, it needs to be exported again, in the hope that the referenced 212 * started, it needs to be exported again, in the hope that the referenced
213 * variable can then be resolved. */ 213 * variable can then be resolved. */
214 VAR_REEXPORT = 0x20, 214 VAR_REEXPORT = 0x20,
215 215
216 /* The variable came from the command line. */ 216 /* The variable came from the command line. */
217 VAR_FROM_CMD = 0x40, 217 VAR_FROM_CMD = 0x40,
218 218
219 /* The variable value cannot be changed anymore, and the variable cannot 219 /* The variable value cannot be changed anymore, and the variable cannot
220 * be deleted. Any attempts to do so are ignored. */ 220 * be deleted. Any attempts to do so are ignored. */
221 VAR_READONLY = 0x80 221 VAR_READONLY = 0x80
222} VarFlags; 222} VarFlags;
223 223
224ENUM_FLAGS_RTTI_6(VarFlags, 224ENUM_FLAGS_RTTI_6(VarFlags,
225 VAR_IN_USE, VAR_FROM_ENV, 225 VAR_IN_USE, VAR_FROM_ENV,
226 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 226 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
227 227
228/* Variables are defined using one of the VAR=value assignments. Their 228/* Variables are defined using one of the VAR=value assignments. Their
229 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 229 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
230 * such as ${VAR:S,from,to,g:Q}. 230 * such as ${VAR:S,from,to,g:Q}.
231 * 231 *
232 * There are 3 kinds of variables: context variables, environment variables, 232 * There are 3 kinds of variables: context variables, environment variables,
233 * undefined variables. 233 * undefined variables.
234 * 234 *
235 * Context variables are stored in a GNode.context. The only way to undefine 235 * Context variables are stored in a GNode.context. The only way to undefine
236 * a context variable is using the .undef directive. In particular, it must 236 * a context variable is using the .undef directive. In particular, it must
237 * not be possible to undefine a variable during the evaluation of an 237 * not be possible to undefine a variable during the evaluation of an
238 * expression, or Var.name might point nowhere. 238 * expression, or Var.name might point nowhere.
239 * 239 *
240 * Environment variables are temporary. They are returned by VarFind, and 240 * Environment variables are temporary. They are returned by VarFind, and
241 * after using them, they must be freed using VarFreeEnv. 241 * after using them, they must be freed using VarFreeEnv.
242 * 242 *
243 * Undefined variables occur during evaluation of variable expressions such 243 * Undefined variables occur during evaluation of variable expressions such
244 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 244 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
245 */ 245 */
246typedef struct Var { 246typedef struct Var {
247 /* The name of the variable, once set, doesn't change anymore. 247 /* The name of the variable, once set, doesn't change anymore.
248 * For context variables, it aliases the corresponding HashEntry name. 248 * For context variables, it aliases the corresponding HashEntry name.
249 * For environment and undefined variables, it is allocated. */ 249 * For environment and undefined variables, it is allocated. */
250 const char *name; 250 const char *name;
251 void *name_freeIt; 251 void *name_freeIt;
252 252
253 Buffer val; /* its value */ 253 Buffer val; /* its value */
254 VarFlags flags; /* miscellaneous status flags */ 254 VarFlags flags; /* miscellaneous status flags */
255} Var; 255} Var;
256 256
257/* 257/*
258 * Exporting vars is expensive so skip it if we can 258 * Exporting vars is expensive so skip it if we can
259 */ 259 */
260typedef enum VarExportedMode { 260typedef enum VarExportedMode {
261 VAR_EXPORTED_NONE, 261 VAR_EXPORTED_NONE,
262 VAR_EXPORTED_SOME, 262 VAR_EXPORTED_SOME,
263 VAR_EXPORTED_ALL 263 VAR_EXPORTED_ALL
264} VarExportedMode; 264} VarExportedMode;
265 265
266static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 266static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
267 267
268typedef enum VarExportFlags { 268typedef enum VarExportFlags {
269 /* 269 /*
270 * We pass this to Var_Export when doing the initial export 270 * We pass this to Var_Export when doing the initial export
271 * or after updating an exported var. 271 * or after updating an exported var.
272 */ 272 */
273 VAR_EXPORT_PARENT = 0x01, 273 VAR_EXPORT_PARENT = 0x01,
274 /* 274 /*
275 * We pass this to Var_Export1 to tell it to leave the value alone. 275 * We pass this to Var_Export1 to tell it to leave the value alone.
276 */ 276 */
277 VAR_EXPORT_LITERAL = 0x02 277 VAR_EXPORT_LITERAL = 0x02
278} VarExportFlags; 278} VarExportFlags;
279 279
280/* Flags for pattern matching in the :S and :C modifiers */ 280/* Flags for pattern matching in the :S and :C modifiers */
281typedef enum VarPatternFlags { 281typedef enum VarPatternFlags {
282 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */ 282 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
283 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */ 283 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
284 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */ 284 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
285 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */ 285 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
286} VarPatternFlags; 286} VarPatternFlags;
287 287
288static Var * 288static Var *
289VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 289VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
290{ 290{
291 size_t value_len = strlen(value); 291 size_t value_len = strlen(value);
292 Var *var = bmake_malloc(sizeof *var); 292 Var *var = bmake_malloc(sizeof *var);
293 var->name = name; 293 var->name = name;
294 var->name_freeIt = name_freeIt; 294 var->name_freeIt = name_freeIt;
295 Buf_Init(&var->val, value_len + 1); 295 Buf_Init(&var->val, value_len + 1);
296 Buf_AddBytes(&var->val, value, value_len); 296 Buf_AddBytes(&var->val, value, value_len);
297 var->flags = flags; 297 var->flags = flags;
298 return var; 298 return var;
299} 299}
300 300
301static const char * 301static const char *
302CanonicalVarname(const char *name) 302CanonicalVarname(const char *name)
303{ 303{
304 if (*name == '.' && ch_isupper(name[1])) { 304 if (*name == '.' && ch_isupper(name[1])) {
305 switch (name[1]) { 305 switch (name[1]) {
306 case 'A': 306 case 'A':
307 if (strcmp(name, ".ALLSRC") == 0) 307 if (strcmp(name, ".ALLSRC") == 0)
308 name = ALLSRC; 308 name = ALLSRC;
309 if (strcmp(name, ".ARCHIVE") == 0) 309 if (strcmp(name, ".ARCHIVE") == 0)
310 name = ARCHIVE; 310 name = ARCHIVE;
311 break; 311 break;
312 case 'I': 312 case 'I':
313 if (strcmp(name, ".IMPSRC") == 0) 313 if (strcmp(name, ".IMPSRC") == 0)
314 name = IMPSRC; 314 name = IMPSRC;
315 break; 315 break;
316 case 'M': 316 case 'M':
317 if (strcmp(name, ".MEMBER") == 0) 317 if (strcmp(name, ".MEMBER") == 0)
318 name = MEMBER; 318 name = MEMBER;
319 break; 319 break;
320 case 'O': 320 case 'O':
321 if (strcmp(name, ".OODATE") == 0) 321 if (strcmp(name, ".OODATE") == 0)
322 name = OODATE; 322 name = OODATE;
323 break; 323 break;
324 case 'P': 324 case 'P':
325 if (strcmp(name, ".PREFIX") == 0) 325 if (strcmp(name, ".PREFIX") == 0)
326 name = PREFIX; 326 name = PREFIX;
327 break; 327 break;
328 case 'S': 328 case 'S':
329 if (strcmp(name, ".SHELL") == 0) { 329 if (strcmp(name, ".SHELL") == 0) {
330 if (!shellPath) 330 if (!shellPath)
331 Shell_Init(); 331 Shell_Init();
332 } 332 }
333 break; 333 break;
334 case 'T': 334 case 'T':
335 if (strcmp(name, ".TARGET") == 0) 335 if (strcmp(name, ".TARGET") == 0)
336 name = TARGET; 336 name = TARGET;
337 break; 337 break;
338 } 338 }
339 } 339 }
340 340
341 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 341 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
342 342
343 return name; 343 return name;
344} 344}
345 345
346static Var * 346static Var *
347GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 347GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
348{ 348{
349 return HashTable_FindValueHash(&ctxt->context, varname, hash); 349 return HashTable_FindValueHash(&ctxt->context, varname, hash);
350} 350}
351 351
352/* Find the variable in the context, and maybe in other contexts as well. 352/* Find the variable in the context, and maybe in other contexts as well.
353 * 353 *
354 * Input: 354 * Input:
355 * name name to find, is not expanded any further 355 * name name to find, is not expanded any further
356 * ctxt context in which to look first 356 * ctxt context in which to look first
357 * elsewhere TRUE to look in other contexts as well 357 * elsewhere TRUE to look in other contexts as well
358 * 358 *
359 * Results: 359 * Results:
360 * The found variable, or NULL if the variable does not exist. 360 * The found variable, or NULL if the variable does not exist.
361 * If the variable is an environment variable, it must be freed using 361 * If the variable is an environment variable, it must be freed using
362 * VarFreeEnv after use. 362 * VarFreeEnv after use.
363 */ 363 */
364static Var * 364static Var *
365VarFind(const char *name, GNode *ctxt, Boolean elsewhere) 365VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
366{ 366{
367 Var *var; 367 Var *var;
368 unsigned int nameHash; 368 unsigned int nameHash;
369 369
370 /* 370 /*
371 * If the variable name begins with a '.', it could very well be one of 371 * If the variable name begins with a '.', it could very well be one of
372 * the local ones. We check the name against all the local variables 372 * the local ones. We check the name against all the local variables
373 * and substitute the short version in for 'name' if it matches one of 373 * and substitute the short version in for 'name' if it matches one of
374 * them. 374 * them.
375 */ 375 */
376 name = CanonicalVarname(name); 376 name = CanonicalVarname(name);
377 nameHash = Hash_Hash(name); 377 nameHash = Hash_Hash(name);
378 378
379 /* First look for the variable in the given context. */ 379 /* First look for the variable in the given context. */
380 var = GNode_FindVar(ctxt, name, nameHash); 380 var = GNode_FindVar(ctxt, name, nameHash);
381 if (!elsewhere) 381 if (!elsewhere)
382 return var; 382 return var;
383 383
384 /* The variable was not found in the given context. Now look for it in 384 /* The variable was not found in the given context. Now look for it in
385 * the other contexts as well. */ 385 * the other contexts as well. */
386 if (var == NULL && ctxt != VAR_CMDLINE) 386 if (var == NULL && ctxt != VAR_CMDLINE)
387 var = GNode_FindVar(VAR_CMDLINE, name, nameHash); 387 var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
388 388
389 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { 389 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
390 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 390 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
391 if (var == NULL && ctxt != VAR_INTERNAL) { 391 if (var == NULL && ctxt != VAR_INTERNAL) {
392 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 392 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
393 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 393 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
394 } 394 }
395 } 395 }
396 396
397 if (var == NULL) { 397 if (var == NULL) {
398 char *env; 398 char *env;
399 399
400 if ((env = getenv(name)) != NULL) { 400 if ((env = getenv(name)) != NULL) {
401 char *varname = bmake_strdup(name); 401 char *varname = bmake_strdup(name);
402 return VarNew(varname, varname, env, VAR_FROM_ENV); 402 return VarNew(varname, varname, env, VAR_FROM_ENV);
403 } 403 }
404 404
405 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { 405 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
406 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 406 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
407 if (var == NULL && ctxt != VAR_INTERNAL) 407 if (var == NULL && ctxt != VAR_INTERNAL)
408 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 408 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
409 return var; 409 return var;
410 } 410 }
411 411
412 return NULL; 412 return NULL;
413 } 413 }
414 414
415 return var; 415 return var;
416} 416}
417 417
418/* If the variable is an environment variable, free it. 418/* If the variable is an environment variable, free it.
419 * 419 *
420 * Input: 420 * Input:
421 * v the variable 421 * v the variable
422 * freeValue true if the variable value should be freed as well 422 * freeValue true if the variable value should be freed as well
423 * 423 *
424 * Results: 424 * Results:
425 * TRUE if it is an environment variable, FALSE otherwise. 425 * TRUE if it is an environment variable, FALSE otherwise.
426 */ 426 */
427static Boolean 427static Boolean
428VarFreeEnv(Var *v, Boolean freeValue) 428VarFreeEnv(Var *v, Boolean freeValue)
429{ 429{
430 if (!(v->flags & VAR_FROM_ENV)) 430 if (!(v->flags & VAR_FROM_ENV))
431 return FALSE; 431 return FALSE;
432 432
433 free(v->name_freeIt); 433 free(v->name_freeIt);
434 Buf_Destroy(&v->val, freeValue); 434 Buf_Destroy(&v->val, freeValue);
435 free(v); 435 free(v);
436 return TRUE; 436 return TRUE;
437} 437}
438 438
439/* Add a new variable of the given name and value to the given context. 439/* Add a new variable of the given name and value to the given context.
440 * The name and val arguments are duplicated so they may safely be freed. */ 440 * The name and val arguments are duplicated so they may safely be freed. */
441static void 441static void
442VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 442VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
443{ 443{
444 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 444 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
445 Var *v = VarNew(he->key /* aliased */, NULL, val, 445 Var *v = VarNew(he->key /* aliased */, NULL, val,
446 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 446 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
447 HashEntry_Set(he, v); 447 HashEntry_Set(he, v);
448 if (!(ctxt->flags & INTERNAL)) { 448 if (!(ctxt->flags & INTERNAL)) {
449 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 449 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
450 } 450 }
451} 451}
452 452
453/* Remove a variable from a context, freeing all related memory as well. 453/* Remove a variable from a context, freeing all related memory as well.
454 * The variable name is expanded once. */ 454 * The variable name is expanded once. */
455void 455void
456Var_Delete(const char *name, GNode *ctxt) 456Var_Delete(const char *name, GNode *ctxt)
457{ 457{
458 char *name_freeIt = NULL; 458 char *name_freeIt = NULL;
459 HashEntry *he; 459 HashEntry *he;
460 460
461 if (strchr(name, '$') != NULL) { 461 if (strchr(name, '$') != NULL) {
462 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 462 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
463 /* TODO: handle errors */ 463 /* TODO: handle errors */
464 name = name_freeIt; 464 name = name_freeIt;
465 } 465 }
466 he = HashTable_FindEntry(&ctxt->context, name); 466 he = HashTable_FindEntry(&ctxt->context, name);
467 VAR_DEBUG3("%s:delete %s%s\n", 467 VAR_DEBUG3("%s:delete %s%s\n",
468 ctxt->name, name, he != NULL ? "" : " (not found)"); 468 ctxt->name, name, he != NULL ? "" : " (not found)");
469 free(name_freeIt); 469 free(name_freeIt);
470 470
471 if (he != NULL) { 471 if (he != NULL) {
472 Var *v = HashEntry_Get(he); 472 Var *v = HashEntry_Get(he);
473 if (v->flags & VAR_EXPORTED) 473 if (v->flags & VAR_EXPORTED)
474 unsetenv(v->name); 474 unsetenv(v->name);
475 if (strcmp(v->name, MAKE_EXPORTED) == 0) 475 if (strcmp(v->name, MAKE_EXPORTED) == 0)
476 var_exportedVars = VAR_EXPORTED_NONE; 476 var_exportedVars = VAR_EXPORTED_NONE;
477 assert(v->name_freeIt == NULL); 477 assert(v->name_freeIt == NULL);
478 HashTable_DeleteEntry(&ctxt->context, he); 478 HashTable_DeleteEntry(&ctxt->context, he);
479 Buf_Destroy(&v->val, TRUE); 479 Buf_Destroy(&v->val, TRUE);
480 free(v); 480 free(v);
481 } 481 }
482} 482}
483 483
484static Boolean 484static Boolean
485MayExport(const char *name) 485MayExport(const char *name)
486{ 486{
487 if (name[0] == '.') 487 if (name[0] == '.')
488 return FALSE; /* skip internals */ 488 return FALSE; /* skip internals */
489 if (name[0] == '-') 489 if (name[0] == '-')
490 return FALSE; /* skip misnamed variables */ 490 return FALSE; /* skip misnamed variables */
491 if (name[1] == '\0') { 491 if (name[1] == '\0') {
492 /* 492 /*
493 * A single char. 493 * A single char.
494 * If it is one of the vars that should only appear in 494 * If it is one of the vars that should only appear in
495 * local context, skip it, else we can get Var_Subst 495 * local context, skip it, else we can get Var_Subst
496 * into a loop. 496 * into a loop.
497 */ 497 */
498 switch (name[0]) { 498 switch (name[0]) {
499 case '@': 499 case '@':
500 case '%': 500 case '%':
501 case '*': 501 case '*':
502 case '!': 502 case '!':
503 return FALSE; 503 return FALSE;
504 } 504 }
505 } 505 }
506 return TRUE; 506 return TRUE;
507} 507}
508 508
509/* 509/*
510 * Export a single variable. 510 * Export a single variable.
511 * We ignore make internal variables (those which start with '.'). 511 * We ignore make internal variables (those which start with '.').
512 * Also we jump through some hoops to avoid calling setenv 512 * Also we jump through some hoops to avoid calling setenv
513 * more than necessary since it can leak. 513 * more than necessary since it can leak.
514 * We only manipulate flags of vars if 'parent' is set. 514 * We only manipulate flags of vars if 'parent' is set.
515 */ 515 */
516static Boolean 516static Boolean
517Var_Export1(const char *name, VarExportFlags flags) 517Var_Export1(const char *name, VarExportFlags flags)
518{ 518{
519 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 519 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
520 Var *v; 520 Var *v;
521 char *val; 521 char *val;
522 522
523 if (!MayExport(name)) 523 if (!MayExport(name))
524 return FALSE; 524 return FALSE;
525 525
526 v = VarFind(name, VAR_GLOBAL, 0); 526 v = VarFind(name, VAR_GLOBAL, 0);
527 if (v == NULL) 527 if (v == NULL)
528 return FALSE; 528 return FALSE;
529 529
530 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 530 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
531 return FALSE; /* nothing to do */ 531 return FALSE; /* nothing to do */
532 532
533 val = Buf_GetAll(&v->val, NULL); 533 val = Buf_GetAll(&v->val, NULL);
534 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 534 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
535 char *expr; 535 char *expr;
536 536
537 if (parent) { 537 if (parent) {
538 /* 538 /*
539 * Flag the variable as something we need to re-export. 539 * Flag the variable as something we need to re-export.
540 * No point actually exporting it now though, 540 * No point actually exporting it now though,
541 * the child process can do it at the last minute. 541 * the child process can do it at the last minute.
542 */ 542 */
543 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 543 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
544 return TRUE; 544 return TRUE;
545 } 545 }
546 if (v->flags & VAR_IN_USE) { 546 if (v->flags & VAR_IN_USE) {
547 /* 547 /*
548 * We recursed while exporting in a child. 548 * We recursed while exporting in a child.
549 * This isn't going to end well, just skip it. 549 * This isn't going to end well, just skip it.
550 */ 550 */
551 return FALSE; 551 return FALSE;
552 } 552 }
553 553
554 /* XXX: name is injected without escaping it */ 554 /* XXX: name is injected without escaping it */
555 expr = str_concat3("${", name, "}"); 555 expr = str_concat3("${", name, "}");
556 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 556 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
557 /* TODO: handle errors */ 557 /* TODO: handle errors */
558 setenv(name, val, 1); 558 setenv(name, val, 1);
559 free(val); 559 free(val);
560 free(expr); 560 free(expr);
561 } else { 561 } else {
562 if (parent) 562 if (parent)
563 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 563 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
564 if (parent || !(v->flags & VAR_EXPORTED)) 564 if (parent || !(v->flags & VAR_EXPORTED))
565 setenv(name, val, 1); 565 setenv(name, val, 1);
566 } 566 }
567 567
568 /* 568 /*
569 * This is so Var_Set knows to call Var_Export again... 569 * This is so Var_Set knows to call Var_Export again...
570 */ 570 */
571 if (parent) { 571 if (parent) {
572 v->flags |= VAR_EXPORTED; 572 v->flags |= VAR_EXPORTED;
573 } 573 }
574 return TRUE; 574 return TRUE;
575} 575}
576 576
577/* 577/*
578 * This gets called from our child processes. 578 * This gets called from our child processes.
579 */ 579 */
580void 580void
581Var_ExportVars(void) 581Var_ExportVars(void)
582{ 582{
583 char *val; 583 char *val;
584 584
585 /* 585 /*
586 * Several make's support this sort of mechanism for tracking 586 * Several make's support this sort of mechanism for tracking
587 * recursion - but each uses a different name. 587 * recursion - but each uses a different name.
588 * We allow the makefiles to update MAKELEVEL and ensure 588 * We allow the makefiles to update MAKELEVEL and ensure
589 * children see a correctly incremented value. 589 * children see a correctly incremented value.
590 */ 590 */
591 char tmp[BUFSIZ]; 591 char tmp[BUFSIZ];
592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
593 setenv(MAKE_LEVEL_ENV, tmp, 1); 593 setenv(MAKE_LEVEL_ENV, tmp, 1);
594 594
595 if (var_exportedVars == VAR_EXPORTED_NONE) 595 if (var_exportedVars == VAR_EXPORTED_NONE)
596 return; 596 return;
597 597
598 if (var_exportedVars == VAR_EXPORTED_ALL) { 598 if (var_exportedVars == VAR_EXPORTED_ALL) {
599 HashIter hi; 599 HashIter hi;
600 600
601 /* Ouch! Exporting all variables at once is crazy... */ 601 /* Ouch! Exporting all variables at once is crazy... */
602 HashIter_Init(&hi, &VAR_GLOBAL->context); 602 HashIter_Init(&hi, &VAR_GLOBAL->context);
603 while (HashIter_Next(&hi) != NULL) { 603 while (HashIter_Next(&hi) != NULL) {
604 Var *var = hi.entry->value; 604 Var *var = hi.entry->value;
605 Var_Export1(var->name, 0); 605 Var_Export1(var->name, 0);
606 } 606 }
607 return; 607 return;
608 } 608 }
609 609
610 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 610 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
611 /* TODO: handle errors */ 611 /* TODO: handle errors */
612 if (*val) { 612 if (*val) {
613 Words words = Str_Words(val, FALSE); 613 Words words = Str_Words(val, FALSE);
614 size_t i; 614 size_t i;
615 615
616 for (i = 0; i < words.len; i++) 616 for (i = 0; i < words.len; i++)
617 Var_Export1(words.words[i], 0); 617 Var_Export1(words.words[i], 0);
618 Words_Free(words); 618 Words_Free(words);
619 } 619 }
620 free(val); 620 free(val);
621} 621}
622 622
623/* 623/*
624 * This is called when .export is seen or .MAKE.EXPORTED is modified. 624 * This is called when .export is seen or .MAKE.EXPORTED is modified.
625 * 625 *
626 * It is also called when any exported variable is modified. 626 * It is also called when any exported variable is modified.
627 * XXX: Is it really? 627 * XXX: Is it really?
628 * 628 *
629 * str has the format "[-env|-literal] varname...". 629 * str has the format "[-env|-literal] varname...".
630 */ 630 */
631void 631void
632Var_Export(const char *str, Boolean isExport) 632Var_Export(const char *str, Boolean isExport)
633{ 633{
634 VarExportFlags flags; 634 VarExportFlags flags;
635 char *val; 635 char *val;
636 636
637 if (isExport && str[0] == '\0') { 637 if (isExport && str[0] == '\0') {
638 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 638 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
639 return; 639 return;
640 } 640 }
641 641
642 if (isExport && strncmp(str, "-env", 4) == 0) { 642 if (isExport && strncmp(str, "-env", 4) == 0) {
643 str += 4; 643 str += 4;
644 flags = 0; 644 flags = 0;
645 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 645 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
646 str += 8; 646 str += 8;
647 flags = VAR_EXPORT_LITERAL; 647 flags = VAR_EXPORT_LITERAL;
648 } else { 648 } else {
649 flags = VAR_EXPORT_PARENT; 649 flags = VAR_EXPORT_PARENT;
650 } 650 }
651 651
652 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 652 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
653 /* TODO: handle errors */ 653 /* TODO: handle errors */
654 if (val[0] != '\0') { 654 if (val[0] != '\0') {
655 Words words = Str_Words(val, FALSE); 655 Words words = Str_Words(val, FALSE);
656 656
657 size_t i; 657 size_t i;
658 for (i = 0; i < words.len; i++) { 658 for (i = 0; i < words.len; i++) {
659 const char *name = words.words[i]; 659 const char *name = words.words[i];
660 if (Var_Export1(name, flags)) { 660 if (Var_Export1(name, flags)) {
661 if (var_exportedVars == VAR_EXPORTED_NONE) 661 if (var_exportedVars == VAR_EXPORTED_NONE)
662 var_exportedVars = VAR_EXPORTED_SOME; 662 var_exportedVars = VAR_EXPORTED_SOME;
663 if (isExport && (flags & VAR_EXPORT_PARENT)) { 663 if (isExport && (flags & VAR_EXPORT_PARENT)) {
664 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 664 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
665 } 665 }
666 } 666 }
667 } 667 }
668 Words_Free(words); 668 Words_Free(words);
669 } 669 }
670 free(val); 670 free(val);
671} 671}
672 672
673 673
674extern char **environ; 674extern char **environ;
675 675
676/* 676/*
677 * This is called when .unexport[-env] is seen. 677 * This is called when .unexport[-env] is seen.
678 * 678 *
679 * str must have the form "unexport[-env] varname...". 679 * str must have the form "unexport[-env] varname...".
680 */ 680 */
681void 681void
682Var_UnExport(const char *str) 682Var_UnExport(const char *str)
683{ 683{
684 const char *varnames; 684 const char *varnames;
685 char *varnames_freeIt; 685 char *varnames_freeIt;
686 Boolean unexport_env; 686 Boolean unexport_env;
687 687
688 varnames = NULL; 688 varnames = NULL;
689 varnames_freeIt = NULL; 689 varnames_freeIt = NULL;
690 690
691 str += strlen("unexport"); 691 str += strlen("unexport");
692 unexport_env = strncmp(str, "-env", 4) == 0; 692 unexport_env = strncmp(str, "-env", 4) == 0;
693 if (unexport_env) { 693 if (unexport_env) {
694 const char *cp; 694 const char *cp;
695 char **newenv; 695 char **newenv;
696 696
697 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 697 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
698 if (environ == savedEnv) { 698 if (environ == savedEnv) {
699 /* we have been here before! */ 699 /* we have been here before! */
700 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 700 newenv = bmake_realloc(environ, 2 * sizeof(char *));
701 } else { 701 } else {
702 if (savedEnv) { 702 if (savedEnv) {
703 free(savedEnv); 703 free(savedEnv);
704 savedEnv = NULL; 704 savedEnv = NULL;
705 } 705 }
706 newenv = bmake_malloc(2 * sizeof(char *)); 706 newenv = bmake_malloc(2 * sizeof(char *));
707 } 707 }
708 708
709 /* Note: we cannot safely free() the original environ. */ 709 /* Note: we cannot safely free() the original environ. */
710 environ = savedEnv = newenv; 710 environ = savedEnv = newenv;
711 newenv[0] = NULL; 711 newenv[0] = NULL;
712 newenv[1] = NULL; 712 newenv[1] = NULL;
713 if (cp && *cp) 713 if (cp && *cp)
714 setenv(MAKE_LEVEL_ENV, cp, 1); 714 setenv(MAKE_LEVEL_ENV, cp, 1);
715 } else { 715 } else {
716 cpp_skip_whitespace(&str); 716 cpp_skip_whitespace(&str);
717 if (str[0] != '\0') 717 if (str[0] != '\0')
718 varnames = str; 718 varnames = str;
719 } 719 }
720 720
721 if (varnames == NULL) { 721 if (varnames == NULL) {
722 /* Using .MAKE.EXPORTED */ 722 /* Using .MAKE.EXPORTED */
723 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 723 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
724 &varnames_freeIt); 724 &varnames_freeIt);
725 /* TODO: handle errors */ 725 /* TODO: handle errors */
726 varnames = varnames_freeIt; 726 varnames = varnames_freeIt;
727 } 727 }
728 728
729 { 729 {
730 Var *v; 730 Var *v;
731 size_t i; 731 size_t i;
732 732
733 Words words = Str_Words(varnames, FALSE); 733 Words words = Str_Words(varnames, FALSE);
734 for (i = 0; i < words.len; i++) { 734 for (i = 0; i < words.len; i++) {
735 const char *varname = words.words[i]; 735 const char *varname = words.words[i];
736 v = VarFind(varname, VAR_GLOBAL, 0); 736 v = VarFind(varname, VAR_GLOBAL, 0);
737 if (v == NULL) { 737 if (v == NULL) {
738 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 738 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
739 continue; 739 continue;
740 } 740 }
741 741
742 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 742 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
743 if (!unexport_env && (v->flags & VAR_EXPORTED) && 743 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
744 !(v->flags & VAR_REEXPORT)) 744 !(v->flags & VAR_REEXPORT))
745 unsetenv(v->name); 745 unsetenv(v->name);
746 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 746 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
747 747
748 /* 748 /*
749 * If we are unexporting a list, 749 * If we are unexporting a list,
750 * remove each one from .MAKE.EXPORTED. 750 * remove each one from .MAKE.EXPORTED.
751 * If we are removing them all, 751 * If we are removing them all,
752 * just delete .MAKE.EXPORTED below. 752 * just delete .MAKE.EXPORTED below.
753 */ 753 */
754 if (varnames == str) { 754 if (varnames == str) {
755 /* XXX: v->name is injected without escaping it */ 755 /* XXX: v->name is injected without escaping it */
756 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 756 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
757 char *cp; 757 char *cp;
758 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 758 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
759 /* TODO: handle errors */ 759 /* TODO: handle errors */
760 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 760 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
761 free(cp); 761 free(cp);
762 free(expr); 762 free(expr);
763 } 763 }
764 } 764 }
765 Words_Free(words); 765 Words_Free(words);
766 if (varnames != str) { 766 if (varnames != str) {
767 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 767 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
768 free(varnames_freeIt); 768 free(varnames_freeIt);
769 } 769 }
770 } 770 }
771} 771}
772 772
773/* See Var_Set for documentation. */ 773/* See Var_Set for documentation. */
774void 774void
775Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 775Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
776 VarSet_Flags flags) 776 VarSet_Flags flags)
777{ 777{
778 const char *unexpanded_name = name; 778 const char *unexpanded_name = name;
779 char *name_freeIt = NULL; 779 char *name_freeIt = NULL;
780 Var *v; 780 Var *v;
781 781
782 assert(val != NULL); 782 assert(val != NULL);
783 783
784 if (strchr(name, '$') != NULL) { 784 if (strchr(name, '$') != NULL) {
785 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 785 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
786 /* TODO: handle errors */ 786 /* TODO: handle errors */
787 name = name_freeIt; 787 name = name_freeIt;
788 } 788 }
789 789
790 if (name[0] == '\0') { 790 if (name[0] == '\0') {
791 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 791 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
792 "name expands to empty string - ignored\n", 792 "name expands to empty string - ignored\n",
793 unexpanded_name, val); 793 unexpanded_name, val);
794 free(name_freeIt); 794 free(name_freeIt);
795 return; 795 return;
796 } 796 }
797 797
798 if (ctxt == VAR_GLOBAL) { 798 if (ctxt == VAR_GLOBAL) {
799 v = VarFind(name, VAR_CMDLINE, 0); 799 v = VarFind(name, VAR_CMDLINE, 0);
800 if (v != NULL) { 800 if (v != NULL) {
801 if (v->flags & VAR_FROM_CMD) { 801 if (v->flags & VAR_FROM_CMD) {
802 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 802 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
803 goto out; 803 goto out;
804 } 804 }
805 VarFreeEnv(v, TRUE); 805 VarFreeEnv(v, TRUE);
806 } 806 }
807 } 807 }
808 808
809 /* 809 /*
810 * We only look for a variable in the given context since anything set 810 * We only look for a variable in the given context since anything set
811 * here will override anything in a lower context, so there's not much 811 * here will override anything in a lower context, so there's not much
812 * point in searching them all just to save a bit of memory... 812 * point in searching them all just to save a bit of memory...
813 */ 813 */
814 v = VarFind(name, ctxt, 0); 814 v = VarFind(name, ctxt, 0);
815 if (v == NULL) { 815 if (v == NULL) {
816 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 816 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
817 /* 817 /*
818 * This var would normally prevent the same name being added 818 * This var would normally prevent the same name being added
819 * to VAR_GLOBAL, so delete it from there if needed. 819 * to VAR_GLOBAL, so delete it from there if needed.
820 * Otherwise -V name may show the wrong value. 820 * Otherwise -V name may show the wrong value.
821 */ 821 */
822 /* XXX: name is expanded for the second time */ 822 /* XXX: name is expanded for the second time */
823 Var_Delete(name, VAR_GLOBAL); 823 Var_Delete(name, VAR_GLOBAL);
824 } 824 }
825 VarAdd(name, val, ctxt, flags); 825 VarAdd(name, val, ctxt, flags);
826 } else { 826 } else {
827 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 827 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
828 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 828 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
829 ctxt->name, name, val); 829 ctxt->name, name, val);
830 goto out; 830 goto out;
831 } 831 }
832 Buf_Empty(&v->val); 832 Buf_Empty(&v->val);
833 Buf_AddStr(&v->val, val); 833 Buf_AddStr(&v->val, val);
834 834
835 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 835 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
836 if (v->flags & VAR_EXPORTED) { 836 if (v->flags & VAR_EXPORTED) {
837 Var_Export1(name, VAR_EXPORT_PARENT); 837 Var_Export1(name, VAR_EXPORT_PARENT);
838 } 838 }
839 } 839 }
840 /* 840 /*
841 * Any variables given on the command line are automatically exported 841 * Any variables given on the command line are automatically exported
842 * to the environment (as per POSIX standard) 842 * to the environment (as per POSIX standard)
843 * Other than internals. 843 * Other than internals.
844 */ 844 */
845 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 845 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
846 if (v == NULL) 846 if (v == NULL)
847 v = VarFind(name, ctxt, 0); /* we just added it */ 847 v = VarFind(name, ctxt, 0); /* we just added it */
848 v->flags |= VAR_FROM_CMD; 848 v->flags |= VAR_FROM_CMD;
849 849
850 /* 850 /*
851 * If requested, don't export these in the environment 851 * If requested, don't export these in the environment
852 * individually. We still put them in MAKEOVERRIDES so 852 * individually. We still put them in MAKEOVERRIDES so
853 * that the command-line settings continue to override 853 * that the command-line settings continue to override
854 * Makefile settings. 854 * Makefile settings.
855 */ 855 */
856 if (!opts.varNoExportEnv) 856 if (!opts.varNoExportEnv)
857 setenv(name, val, 1); 857 setenv(name, val, 1);
858 858
859 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 859 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
860 } 860 }
861 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 861 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
862 save_dollars = s2Boolean(val, save_dollars); 862 save_dollars = s2Boolean(val, save_dollars);
863 863
864out: 864out:
865 free(name_freeIt); 865 free(name_freeIt);
866 if (v != NULL) 866 if (v != NULL)
867 VarFreeEnv(v, TRUE); 867 VarFreeEnv(v, TRUE);
868} 868}
869 869
870/*- 870/*-
871 *----------------------------------------------------------------------- 871 *-----------------------------------------------------------------------
872 * Var_Set -- 872 * Var_Set --
873 * Set the variable name to the value val in the given context. 873 * Set the variable name to the value val in the given context.
874 * 874 *
875 * If the variable doesn't yet exist, it is created. 875 * If the variable doesn't yet exist, it is created.
876 * Otherwise the new value overwrites and replaces the old value. 876 * Otherwise the new value overwrites and replaces the old value.
877 * 877 *
878 * Input: 878 * Input:
879 * name name of the variable to set, is expanded once 879 * name name of the variable to set, is expanded once
880 * val value to give to the variable 880 * val value to give to the variable
881 * ctxt context in which to set it 881 * ctxt context in which to set it
882 * 882 *
883 * Notes: 883 * Notes:
884 * The variable is searched for only in its context before being 884 * The variable is searched for only in its context before being
885 * created in that context. I.e. if the context is VAR_GLOBAL, 885 * created in that context. I.e. if the context is VAR_GLOBAL,
886 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 886 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
887 * only VAR_CMDLINE->context is searched. This is done to avoid the 887 * only VAR_CMDLINE->context is searched. This is done to avoid the
888 * literally thousands of unnecessary strcmp's that used to be done to 888 * literally thousands of unnecessary strcmp's that used to be done to
889 * set, say, $(@) or $(<). 889 * set, say, $(@) or $(<).
890 * If the context is VAR_GLOBAL though, we check if the variable 890 * If the context is VAR_GLOBAL though, we check if the variable
891 * was set in VAR_CMDLINE from the command line and skip it if so. 891 * was set in VAR_CMDLINE from the command line and skip it if so.
892 *----------------------------------------------------------------------- 892 *-----------------------------------------------------------------------
893 */ 893 */
894void 894void
895Var_Set(const char *name, const char *val, GNode *ctxt) 895Var_Set(const char *name, const char *val, GNode *ctxt)
896{ 896{
897 Var_Set_with_flags(name, val, ctxt, 0); 897 Var_Set_with_flags(name, val, ctxt, 0);
898} 898}
899 899
900/*- 900/*-
901 *----------------------------------------------------------------------- 901 *-----------------------------------------------------------------------
902 * Var_Append -- 902 * Var_Append --
903 * The variable of the given name has the given value appended to it in 903 * The variable of the given name has the given value appended to it in
904 * the given context. 904 * the given context.
905 * 905 *
906 * If the variable doesn't exist, it is created. Otherwise the strings 906 * If the variable doesn't exist, it is created. Otherwise the strings
907 * are concatenated, with a space in between. 907 * are concatenated, with a space in between.
908 * 908 *
909 * Input: 909 * Input:
910 * name name of the variable to modify, is expanded once 910 * name name of the variable to modify, is expanded once
911 * val string to append to it 911 * val string to append to it
912 * ctxt context in which this should occur 912 * ctxt context in which this should occur
913 * 913 *
914 * Notes: 914 * Notes:
915 * Only if the variable is being sought in the global context is the 915 * Only if the variable is being sought in the global context is the
916 * environment searched. 916 * environment searched.
917 * XXX: Knows its calling circumstances in that if called with ctxt 917 * XXX: Knows its calling circumstances in that if called with ctxt
918 * an actual target, it will only search that context since only 918 * an actual target, it will only search that context since only
919 * a local variable could be being appended to. This is actually 919 * a local variable could be being appended to. This is actually
920 * a big win and must be tolerated. 920 * a big win and must be tolerated.
921 *----------------------------------------------------------------------- 921 *-----------------------------------------------------------------------
922 */ 922 */
923void 923void
924Var_Append(const char *name, const char *val, GNode *ctxt) 924Var_Append(const char *name, const char *val, GNode *ctxt)
925{ 925{
926 char *name_freeIt = NULL; 926 char *name_freeIt = NULL;
927 Var *v; 927 Var *v;
928 928
929 assert(val != NULL); 929 assert(val != NULL);
930 930
931 if (strchr(name, '$') != NULL) { 931 if (strchr(name, '$') != NULL) {
932 const char *unexpanded_name = name; 932 const char *unexpanded_name = name;
933 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 933 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
934 /* TODO: handle errors */ 934 /* TODO: handle errors */
935 name = name_freeIt; 935 name = name_freeIt;
936 if (name[0] == '\0') { 936 if (name[0] == '\0') {
937 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 937 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
938 "name expands to empty string - ignored\n", 938 "name expands to empty string - ignored\n",
939 unexpanded_name, val); 939 unexpanded_name, val);
940 free(name_freeIt); 940 free(name_freeIt);
941 return; 941 return;
942 } 942 }
943 } 943 }
944 944
945 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 945 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
946 946
947 if (v == NULL) { 947 if (v == NULL) {
948 /* XXX: name is expanded for the second time */ 948 /* XXX: name is expanded for the second time */
949 Var_Set(name, val, ctxt); 949 Var_Set(name, val, ctxt);
950 } else if (v->flags & VAR_READONLY) { 950 } else if (v->flags & VAR_READONLY) {
951 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 951 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
952 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 952 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
953 Buf_AddByte(&v->val, ' '); 953 Buf_AddByte(&v->val, ' ');
954 Buf_AddStr(&v->val, val); 954 Buf_AddStr(&v->val, val);
955 955
956 VAR_DEBUG3("%s:%s = %s\n", 956 VAR_DEBUG3("%s:%s = %s\n",
957 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 957 ctxt->name, name, Buf_GetAll(&v->val, NULL));
958 958
959 if (v->flags & VAR_FROM_ENV) { 959 if (v->flags & VAR_FROM_ENV) {
960 HashEntry *h; 960 HashEntry *h;
961 961
962 /* 962 /*
963 * If the original variable came from the environment, we 963 * If the original variable came from the environment, we
964 * have to install it in the global context (we could place 964 * have to install it in the global context (we could place
965 * it in the environment, but then we should provide a way to 965 * it in the environment, but then we should provide a way to
966 * export other variables...) 966 * export other variables...)
967 */ 967 */
968 v->flags &= ~(unsigned)VAR_FROM_ENV; 968 v->flags &= ~(unsigned)VAR_FROM_ENV;
969 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 969 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
970 HashEntry_Set(h, v); 970 HashEntry_Set(h, v);
971 } 971 }
972 } 972 }
973 free(name_freeIt); 973 free(name_freeIt);
974} 974}
975 975
976/* See if the given variable exists, in the given context or in other 976/* See if the given variable exists, in the given context or in other
977 * fallback contexts. 977 * fallback contexts.
978 * 978 *
979 * Input: 979 * Input:
980 * name Variable to find, is expanded once 980 * name Variable to find, is expanded once
981 * ctxt Context in which to start search 981 * ctxt Context in which to start search
982 */ 982 */
983Boolean 983Boolean
984Var_Exists(const char *name, GNode *ctxt) 984Var_Exists(const char *name, GNode *ctxt)
985{ 985{
986 char *name_freeIt = NULL; 986 char *name_freeIt = NULL;
987 Var *v; 987 Var *v;
988 988
989 if (strchr(name, '$') != NULL) { 989 if (strchr(name, '$') != NULL) {
990 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 990 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
991 /* TODO: handle errors */ 991 /* TODO: handle errors */
992 name = name_freeIt; 992 name = name_freeIt;
993 } 993 }
994 994
995 v = VarFind(name, ctxt, TRUE); 995 v = VarFind(name, ctxt, TRUE);
996 free(name_freeIt); 996 free(name_freeIt);
997 if (v == NULL) 997 if (v == NULL)
998 return FALSE; 998 return FALSE;
999 999
1000 (void)VarFreeEnv(v, TRUE); 1000 (void)VarFreeEnv(v, TRUE);
1001 return TRUE; 1001 return TRUE;
1002} 1002}
1003 1003
1004/*- 1004/*-
1005 *----------------------------------------------------------------------- 1005 *-----------------------------------------------------------------------
1006 * Var_Value -- 1006 * Var_Value --
1007 * Return the unexpanded value of the given variable in the given 1007 * Return the unexpanded value of the given variable in the given
1008 * context, or the usual contexts. 1008 * context, or the usual contexts.
1009 * 1009 *
1010 * Input: 1010 * Input:
1011 * name name to find, is not expanded any further 1011 * name name to find, is not expanded any further
1012 * ctxt context in which to search for it 1012 * ctxt context in which to search for it
1013 * 1013 *
1014 * Results: 1014 * Results:
1015 * The value if the variable exists, NULL if it doesn't. 1015 * The value if the variable exists, NULL if it doesn't.
1016 * If the returned value is not NULL, the caller must free 1016 * If the returned value is not NULL, the caller must free
1017 * out_freeIt when the returned value is no longer needed. 1017 * out_freeIt when the returned value is no longer needed.
1018 *----------------------------------------------------------------------- 1018 *-----------------------------------------------------------------------
1019 */ 1019 */
1020const char * 1020const char *
1021Var_Value(const char *name, GNode *ctxt, void **out_freeIt) 1021Var_Value(const char *name, GNode *ctxt, void **out_freeIt)
1022{ 1022{
1023 Var *v = VarFind(name, ctxt, TRUE); 1023 Var *v = VarFind(name, ctxt, TRUE);
1024 char *value; 1024 char *value;
1025 1025
1026 *out_freeIt = NULL; 1026 *out_freeIt = NULL;
1027 if (v == NULL) 1027 if (v == NULL)
1028 return NULL; 1028 return NULL;
1029 1029
1030 value = Buf_GetAll(&v->val, NULL); 1030 value = Buf_GetAll(&v->val, NULL);
1031 if (VarFreeEnv(v, FALSE)) 1031 if (VarFreeEnv(v, FALSE))
1032 *out_freeIt = value; 1032 *out_freeIt = value;
1033 return value; 1033 return value;
1034} 1034}
1035 1035
1036/* Return the unexpanded variable value from this node, without trying to look 1036/* Return the unexpanded variable value from this node, without trying to look
1037 * up the variable in any other context. */ 1037 * up the variable in any other context. */
1038const char * 1038const char *
1039Var_ValueDirect(const char *name, GNode *ctxt) 1039Var_ValueDirect(const char *name, GNode *ctxt)
1040{ 1040{
1041 Var *v = VarFind(name, ctxt, FALSE); 1041 Var *v = VarFind(name, ctxt, FALSE);
1042 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL; 1042 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
1043} 1043}
1044 1044
1045 1045
1046/* SepBuf is a string being built from words, interleaved with separators. */ 1046/* SepBuf is a string being built from words, interleaved with separators. */
1047typedef struct SepBuf { 1047typedef struct SepBuf {
1048 Buffer buf; 1048 Buffer buf;
1049 Boolean needSep; 1049 Boolean needSep;
1050 char sep; /* usually ' ', but see the :ts modifier */ 1050 char sep; /* usually ' ', but see the :ts modifier */
1051} SepBuf; 1051} SepBuf;
1052 1052
1053static void 1053static void
1054SepBuf_Init(SepBuf *buf, char sep) 1054SepBuf_Init(SepBuf *buf, char sep)
1055{ 1055{
1056 Buf_Init(&buf->buf, 32 /* bytes */); 1056 Buf_Init(&buf->buf, 32 /* bytes */);
1057 buf->needSep = FALSE; 1057 buf->needSep = FALSE;
1058 buf->sep = sep; 1058 buf->sep = sep;
1059} 1059}
1060 1060
1061static void 1061static void
1062SepBuf_Sep(SepBuf *buf) 1062SepBuf_Sep(SepBuf *buf)
1063{ 1063{
1064 buf->needSep = TRUE; 1064 buf->needSep = TRUE;
1065} 1065}
1066 1066
1067static void 1067static void
1068SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1068SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1069{ 1069{
1070 if (mem_size == 0) 1070 if (mem_size == 0)
1071 return; 1071 return;
1072 if (buf->needSep && buf->sep != '\0') { 1072 if (buf->needSep && buf->sep != '\0') {
1073 Buf_AddByte(&buf->buf, buf->sep); 1073 Buf_AddByte(&buf->buf, buf->sep);
1074 buf->needSep = FALSE; 1074 buf->needSep = FALSE;
1075 } 1075 }
1076 Buf_AddBytes(&buf->buf, mem, mem_size); 1076 Buf_AddBytes(&buf->buf, mem, mem_size);
1077} 1077}
1078 1078
1079static void 1079static void
1080SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1080SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1081{ 1081{
1082 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1082 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1083} 1083}
1084 1084
1085static void 1085static void
1086SepBuf_AddStr(SepBuf *buf, const char *str) 1086SepBuf_AddStr(SepBuf *buf, const char *str)
1087{ 1087{
1088 SepBuf_AddBytes(buf, str, strlen(str)); 1088 SepBuf_AddBytes(buf, str, strlen(str));
1089} 1089}
1090 1090
1091static char * 1091static char *
1092SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1092SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1093{ 1093{
1094 return Buf_Destroy(&buf->buf, free_buf); 1094 return Buf_Destroy(&buf->buf, free_buf);
1095} 1095}
1096 1096
1097 1097
1098/* This callback for ModifyWords gets a single word from a variable expression 1098/* This callback for ModifyWords gets a single word from a variable expression
1099 * and typically adds a modification of this word to the buffer. It may also 1099 * and typically adds a modification of this word to the buffer. It may also
1100 * do nothing or add several words. 1100 * do nothing or add several words.
1101 * 1101 *
1102 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for 1102 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1103 * each word of "a b c". */ 1103 * each word of "a b c". */
1104typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1104typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1105 1105
1106 1106
1107/* Callback for ModifyWords to implement the :H modifier. 1107/* Callback for ModifyWords to implement the :H modifier.
1108 * Add the dirname of the given word to the buffer. */ 1108 * Add the dirname of the given word to the buffer. */
1109static void 1109static void
1110ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1110ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1111{ 1111{
1112 const char *slash = strrchr(word, '/'); 1112 const char *slash = strrchr(word, '/');
1113 if (slash != NULL) 1113 if (slash != NULL)
1114 SepBuf_AddBytesBetween(buf, word, slash); 1114 SepBuf_AddBytesBetween(buf, word, slash);
1115 else 1115 else
1116 SepBuf_AddStr(buf, "."); 1116 SepBuf_AddStr(buf, ".");
1117} 1117}
1118 1118
1119/* Callback for ModifyWords to implement the :T modifier. 1119/* Callback for ModifyWords to implement the :T modifier.
1120 * Add the basename of the given word to the buffer. */ 1120 * Add the basename of the given word to the buffer. */
1121static void 1121static void
1122ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1122ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1123{ 1123{
1124 const char *slash = strrchr(word, '/'); 1124 const char *slash = strrchr(word, '/');
1125 const char *base = slash != NULL ? slash + 1 : word; 1125 const char *base = slash != NULL ? slash + 1 : word;
1126 SepBuf_AddStr(buf, base); 1126 SepBuf_AddStr(buf, base);
1127} 1127}
1128 1128
1129/* Callback for ModifyWords to implement the :E modifier. 1129/* Callback for ModifyWords to implement the :E modifier.
1130 * Add the filename suffix of the given word to the buffer, if it exists. */ 1130 * Add the filename suffix of the given word to the buffer, if it exists. */
1131static void 1131static void
1132ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1132ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
@@ -2276,1802 +2276,1798 @@ ApplyModifier_Path(const char **pp, Appl @@ -2276,1802 +2276,1798 @@ ApplyModifier_Path(const char **pp, Appl
2276 if (path == NULL) 2276 if (path == NULL)
2277 path = bmake_strdup(st->v->name); 2277 path = bmake_strdup(st->v->name);
2278 st->newVal = path; 2278 st->newVal = path;
2279 2279
2280 (*pp)++; 2280 (*pp)++;
2281 return AMR_OK; 2281 return AMR_OK;
2282} 2282}
2283 2283
2284/* :!cmd! */ 2284/* :!cmd! */
2285static ApplyModifierResult 2285static ApplyModifierResult
2286ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2286ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2287{ 2287{
2288 char *cmd; 2288 char *cmd;
2289 const char *errfmt; 2289 const char *errfmt;
2290 VarParseResult res; 2290 VarParseResult res;
2291 2291
2292 (*pp)++; 2292 (*pp)++;
2293 res = ParseModifierPart(pp, '!', st->eflags, st, 2293 res = ParseModifierPart(pp, '!', st->eflags, st,
2294 &cmd, NULL, NULL, NULL); 2294 &cmd, NULL, NULL, NULL);
2295 if (res != VPR_OK) 2295 if (res != VPR_OK)
2296 return AMR_CLEANUP; 2296 return AMR_CLEANUP;
2297 2297
2298 errfmt = NULL; 2298 errfmt = NULL;
2299 if (st->eflags & VARE_WANTRES) 2299 if (st->eflags & VARE_WANTRES)
2300 st->newVal = Cmd_Exec(cmd, &errfmt); 2300 st->newVal = Cmd_Exec(cmd, &errfmt);
2301 else 2301 else
2302 st->newVal = emptyString; 2302 st->newVal = emptyString;
2303 free(cmd); 2303 free(cmd);
2304 2304
2305 if (errfmt != NULL) 2305 if (errfmt != NULL)
2306 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2306 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2307 2307
2308 ApplyModifiersState_Define(st); 2308 ApplyModifiersState_Define(st);
2309 return AMR_OK; 2309 return AMR_OK;
2310} 2310}
2311 2311
2312/* The :range modifier generates an integer sequence as long as the words. 2312/* The :range modifier generates an integer sequence as long as the words.
2313 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2313 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2314static ApplyModifierResult 2314static ApplyModifierResult
2315ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2315ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2316{ 2316{
2317 size_t n; 2317 size_t n;
2318 Buffer buf; 2318 Buffer buf;
2319 size_t i; 2319 size_t i;
2320 2320
2321 const char *mod = *pp; 2321 const char *mod = *pp;
2322 if (!ModMatchEq(mod, "range", st->endc)) 2322 if (!ModMatchEq(mod, "range", st->endc))
2323 return AMR_UNKNOWN; 2323 return AMR_UNKNOWN;
2324 2324
2325 if (mod[5] == '=') { 2325 if (mod[5] == '=') {
2326 const char *p = mod + 6; 2326 const char *p = mod + 6;
2327 if (!TryParseSize(&p, &n)) { 2327 if (!TryParseSize(&p, &n)) {
2328 Parse_Error(PARSE_FATAL, "Invalid number: %s\n", mod + 6); 2328 Parse_Error(PARSE_FATAL, "Invalid number: %s\n", mod + 6);
2329 return AMR_CLEANUP; 2329 return AMR_CLEANUP;
2330 } 2330 }
2331 *pp = p; 2331 *pp = p;
2332 } else { 2332 } else {
2333 n = 0; 2333 n = 0;
2334 *pp = mod + 5; 2334 *pp = mod + 5;
2335 } 2335 }
2336 2336
2337 if (n == 0) { 2337 if (n == 0) {
2338 Words words = Str_Words(st->val, FALSE); 2338 Words words = Str_Words(st->val, FALSE);
2339 n = words.len; 2339 n = words.len;
2340 Words_Free(words); 2340 Words_Free(words);
2341 } 2341 }
2342 2342
2343 Buf_Init(&buf, 0); 2343 Buf_Init(&buf, 0);
2344 2344
2345 for (i = 0; i < n; i++) { 2345 for (i = 0; i < n; i++) {
2346 if (i != 0) 2346 if (i != 0)
2347 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2347 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2348 Buf_AddInt(&buf, 1 + (int)i); 2348 Buf_AddInt(&buf, 1 + (int)i);
2349 } 2349 }
2350 2350
2351 st->newVal = Buf_Destroy(&buf, FALSE); 2351 st->newVal = Buf_Destroy(&buf, FALSE);
2352 return AMR_OK; 2352 return AMR_OK;
2353} 2353}
2354 2354
2355/* :Mpattern or :Npattern */ 2355/* :Mpattern or :Npattern */
2356static ApplyModifierResult 2356static ApplyModifierResult
2357ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2357ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2358{ 2358{
2359 const char *mod = *pp; 2359 const char *mod = *pp;
2360 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2360 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2361 Boolean needSubst = FALSE; 2361 Boolean needSubst = FALSE;
2362 const char *endpat; 2362 const char *endpat;
2363 char *pattern; 2363 char *pattern;
2364 ModifyWordsCallback callback; 2364 ModifyWordsCallback callback;
2365 2365
2366 /* 2366 /*
2367 * In the loop below, ignore ':' unless we are at (or back to) the 2367 * In the loop below, ignore ':' unless we are at (or back to) the
2368 * original brace level. 2368 * original brace level.
2369 * XXX This will likely not work right if $() and ${} are intermixed. 2369 * XXX This will likely not work right if $() and ${} are intermixed.
2370 */ 2370 */
2371 int nest = 0; 2371 int nest = 0;
2372 const char *p; 2372 const char *p;
2373 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2373 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2374 if (*p == '\\' && 2374 if (*p == '\\' &&
2375 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2375 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2376 if (!needSubst) 2376 if (!needSubst)
2377 copy = TRUE; 2377 copy = TRUE;
2378 p++; 2378 p++;
2379 continue; 2379 continue;
2380 } 2380 }
2381 if (*p == '$') 2381 if (*p == '$')
2382 needSubst = TRUE; 2382 needSubst = TRUE;
2383 if (*p == '(' || *p == '{') 2383 if (*p == '(' || *p == '{')
2384 nest++; 2384 nest++;
2385 if (*p == ')' || *p == '}') { 2385 if (*p == ')' || *p == '}') {
2386 nest--; 2386 nest--;
2387 if (nest < 0) 2387 if (nest < 0)
2388 break; 2388 break;
2389 } 2389 }
2390 } 2390 }
2391 *pp = p; 2391 *pp = p;
2392 endpat = p; 2392 endpat = p;
2393 2393
2394 if (copy) { 2394 if (copy) {
2395 char *dst; 2395 char *dst;
2396 const char *src; 2396 const char *src;
2397 2397
2398 /* Compress the \:'s out of the pattern. */ 2398 /* Compress the \:'s out of the pattern. */
2399 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2399 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2400 dst = pattern; 2400 dst = pattern;
2401 src = mod + 1; 2401 src = mod + 1;
2402 for (; src < endpat; src++, dst++) { 2402 for (; src < endpat; src++, dst++) {
2403 if (src[0] == '\\' && src + 1 < endpat && 2403 if (src[0] == '\\' && src + 1 < endpat &&
2404 /* XXX: st->startc is missing here; see above */ 2404 /* XXX: st->startc is missing here; see above */
2405 (src[1] == ':' || src[1] == st->endc)) 2405 (src[1] == ':' || src[1] == st->endc))
2406 src++; 2406 src++;
2407 *dst = *src; 2407 *dst = *src;
2408 } 2408 }
2409 *dst = '\0'; 2409 *dst = '\0';
2410 endpat = dst; 2410 endpat = dst;
2411 } else { 2411 } else {
2412 pattern = bmake_strsedup(mod + 1, endpat); 2412 pattern = bmake_strsedup(mod + 1, endpat);
2413 } 2413 }
2414 2414
2415 if (needSubst) { 2415 if (needSubst) {
2416 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2416 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2417 char *old_pattern = pattern; 2417 char *old_pattern = pattern;
2418 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2418 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2419 /* TODO: handle errors */ 2419 /* TODO: handle errors */
2420 free(old_pattern); 2420 free(old_pattern);
2421 } 2421 }
2422 2422
2423 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2423 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2424 2424
2425 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2425 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2426 st->newVal = ModifyWords(st->val, callback, pattern, 2426 st->newVal = ModifyWords(st->val, callback, pattern,
2427 st->oneBigWord, st->sep); 2427 st->oneBigWord, st->sep);
2428 free(pattern); 2428 free(pattern);
2429 return AMR_OK; 2429 return AMR_OK;
2430} 2430}
2431 2431
2432/* :S,from,to, */ 2432/* :S,from,to, */
2433static ApplyModifierResult 2433static ApplyModifierResult
2434ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2434ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2435{ 2435{
2436 struct ModifyWord_SubstArgs args; 2436 struct ModifyWord_SubstArgs args;
2437 char *lhs, *rhs; 2437 char *lhs, *rhs;
2438 Boolean oneBigWord; 2438 Boolean oneBigWord;
2439 VarParseResult res; 2439 VarParseResult res;
2440 2440
2441 char delim = (*pp)[1]; 2441 char delim = (*pp)[1];
2442 if (delim == '\0') { 2442 if (delim == '\0') {
2443 Error("Missing delimiter for :S modifier"); 2443 Error("Missing delimiter for :S modifier");
2444 (*pp)++; 2444 (*pp)++;
2445 return AMR_CLEANUP; 2445 return AMR_CLEANUP;
2446 } 2446 }
2447 2447
2448 *pp += 2; 2448 *pp += 2;
2449 2449
2450 args.pflags = 0; 2450 args.pflags = 0;
2451 args.matched = FALSE; 2451 args.matched = FALSE;
2452 2452
2453 /* 2453 /*
2454 * If pattern begins with '^', it is anchored to the 2454 * If pattern begins with '^', it is anchored to the
2455 * start of the word -- skip over it and flag pattern. 2455 * start of the word -- skip over it and flag pattern.
2456 */ 2456 */
2457 if (**pp == '^') { 2457 if (**pp == '^') {
2458 args.pflags |= VARP_ANCHOR_START; 2458 args.pflags |= VARP_ANCHOR_START;
2459 (*pp)++; 2459 (*pp)++;
2460 } 2460 }
2461 2461
2462 res = ParseModifierPart(pp, delim, st->eflags, st, 2462 res = ParseModifierPart(pp, delim, st->eflags, st,
2463 &lhs, &args.lhsLen, &args.pflags, NULL); 2463 &lhs, &args.lhsLen, &args.pflags, NULL);
2464 if (res != VPR_OK) 2464 if (res != VPR_OK)
2465 return AMR_CLEANUP; 2465 return AMR_CLEANUP;
2466 args.lhs = lhs; 2466 args.lhs = lhs;
2467 2467
2468 res = ParseModifierPart(pp, delim, st->eflags, st, 2468 res = ParseModifierPart(pp, delim, st->eflags, st,
2469 &rhs, &args.rhsLen, NULL, &args); 2469 &rhs, &args.rhsLen, NULL, &args);
2470 if (res != VPR_OK) 2470 if (res != VPR_OK)
2471 return AMR_CLEANUP; 2471 return AMR_CLEANUP;
2472 args.rhs = rhs; 2472 args.rhs = rhs;
2473 2473
2474 oneBigWord = st->oneBigWord; 2474 oneBigWord = st->oneBigWord;
2475 for (;; (*pp)++) { 2475 for (;; (*pp)++) {
2476 switch (**pp) { 2476 switch (**pp) {
2477 case 'g': 2477 case 'g':
2478 args.pflags |= VARP_SUB_GLOBAL; 2478 args.pflags |= VARP_SUB_GLOBAL;
2479 continue; 2479 continue;
2480 case '1': 2480 case '1':
2481 args.pflags |= VARP_SUB_ONE; 2481 args.pflags |= VARP_SUB_ONE;
2482 continue; 2482 continue;
2483 case 'W': 2483 case 'W':
2484 oneBigWord = TRUE; 2484 oneBigWord = TRUE;
2485 continue; 2485 continue;
2486 } 2486 }
2487 break; 2487 break;
2488 } 2488 }
2489 2489
2490 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args, 2490 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
2491 oneBigWord, st->sep); 2491 oneBigWord, st->sep);
2492 2492
2493 free(lhs); 2493 free(lhs);
2494 free(rhs); 2494 free(rhs);
2495 return AMR_OK; 2495 return AMR_OK;
2496} 2496}
2497 2497
2498#ifndef NO_REGEX 2498#ifndef NO_REGEX
2499 2499
2500/* :C,from,to, */ 2500/* :C,from,to, */
2501static ApplyModifierResult 2501static ApplyModifierResult
2502ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2502ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2503{ 2503{
2504 char *re; 2504 char *re;
2505 struct ModifyWord_SubstRegexArgs args; 2505 struct ModifyWord_SubstRegexArgs args;
2506 Boolean oneBigWord; 2506 Boolean oneBigWord;
2507 int error; 2507 int error;
2508 VarParseResult res; 2508 VarParseResult res;
2509 2509
2510 char delim = (*pp)[1]; 2510 char delim = (*pp)[1];
2511 if (delim == '\0') { 2511 if (delim == '\0') {
2512 Error("Missing delimiter for :C modifier"); 2512 Error("Missing delimiter for :C modifier");
2513 (*pp)++; 2513 (*pp)++;
2514 return AMR_CLEANUP; 2514 return AMR_CLEANUP;
2515 } 2515 }
2516 2516
2517 *pp += 2; 2517 *pp += 2;
2518 2518
2519 res = ParseModifierPart(pp, delim, st->eflags, st, 2519 res = ParseModifierPart(pp, delim, st->eflags, st,
2520 &re, NULL, NULL, NULL); 2520 &re, NULL, NULL, NULL);
2521 if (res != VPR_OK) 2521 if (res != VPR_OK)
2522 return AMR_CLEANUP; 2522 return AMR_CLEANUP;
2523 2523
2524 res = ParseModifierPart(pp, delim, st->eflags, st, 2524 res = ParseModifierPart(pp, delim, st->eflags, st,
2525 &args.replace, NULL, NULL, NULL); 2525 &args.replace, NULL, NULL, NULL);
2526 if (args.replace == NULL) { 2526 if (args.replace == NULL) {
2527 free(re); 2527 free(re);
2528 return AMR_CLEANUP; 2528 return AMR_CLEANUP;
2529 } 2529 }
2530 2530
2531 args.pflags = 0; 2531 args.pflags = 0;
2532 args.matched = FALSE; 2532 args.matched = FALSE;
2533 oneBigWord = st->oneBigWord; 2533 oneBigWord = st->oneBigWord;
2534 for (;; (*pp)++) { 2534 for (;; (*pp)++) {
2535 switch (**pp) { 2535 switch (**pp) {
2536 case 'g': 2536 case 'g':
2537 args.pflags |= VARP_SUB_GLOBAL; 2537 args.pflags |= VARP_SUB_GLOBAL;
2538 continue; 2538 continue;
2539 case '1': 2539 case '1':
2540 args.pflags |= VARP_SUB_ONE; 2540 args.pflags |= VARP_SUB_ONE;
2541 continue; 2541 continue;
2542 case 'W': 2542 case 'W':
2543 oneBigWord = TRUE; 2543 oneBigWord = TRUE;
2544 continue; 2544 continue;
2545 } 2545 }
2546 break; 2546 break;
2547 } 2547 }
2548 2548
2549 error = regcomp(&args.re, re, REG_EXTENDED); 2549 error = regcomp(&args.re, re, REG_EXTENDED);
2550 free(re); 2550 free(re);
2551 if (error) { 2551 if (error) {
2552 VarREError(error, &args.re, "Regex compilation error"); 2552 VarREError(error, &args.re, "Regex compilation error");
2553 free(args.replace); 2553 free(args.replace);
2554 return AMR_CLEANUP; 2554 return AMR_CLEANUP;
2555 } 2555 }
2556 2556
2557 args.nsub = args.re.re_nsub + 1; 2557 args.nsub = args.re.re_nsub + 1;
2558 if (args.nsub > 10) 2558 if (args.nsub > 10)
2559 args.nsub = 10; 2559 args.nsub = 10;
2560 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args, 2560 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
2561 oneBigWord, st->sep); 2561 oneBigWord, st->sep);
2562 regfree(&args.re); 2562 regfree(&args.re);
2563 free(args.replace); 2563 free(args.replace);
2564 return AMR_OK; 2564 return AMR_OK;
2565} 2565}
2566#endif 2566#endif
2567 2567
2568/* :Q, :q */ 2568/* :Q, :q */
2569static ApplyModifierResult 2569static ApplyModifierResult
2570ApplyModifier_Quote(const char **pp, ApplyModifiersState *st) 2570ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
2571{ 2571{
2572 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2572 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2573 st->newVal = VarQuote(st->val, **pp == 'q'); 2573 st->newVal = VarQuote(st->val, **pp == 'q');
2574 (*pp)++; 2574 (*pp)++;
2575 return AMR_OK; 2575 return AMR_OK;
2576 } else 2576 } else
2577 return AMR_UNKNOWN; 2577 return AMR_UNKNOWN;
2578} 2578}
2579 2579
2580static void 2580static void
2581ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2581ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2582{ 2582{
2583 SepBuf_AddStr(buf, word); 2583 SepBuf_AddStr(buf, word);
2584} 2584}
2585 2585
2586/* :ts<separator> */ 2586/* :ts<separator> */
2587static ApplyModifierResult 2587static ApplyModifierResult
2588ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2588ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2589{ 2589{
2590 const char *sep = *pp + 2; 2590 const char *sep = *pp + 2;
2591 2591
2592 /* ":ts<any><endc>" or ":ts<any>:" */ 2592 /* ":ts<any><endc>" or ":ts<any>:" */
2593 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2593 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2594 st->sep = sep[0]; 2594 st->sep = sep[0];
2595 *pp = sep + 1; 2595 *pp = sep + 1;
2596 goto ok; 2596 goto ok;
2597 } 2597 }
2598 2598
2599 /* ":ts<endc>" or ":ts:" */ 2599 /* ":ts<endc>" or ":ts:" */
2600 if (sep[0] == st->endc || sep[0] == ':') { 2600 if (sep[0] == st->endc || sep[0] == ':') {
2601 st->sep = '\0'; /* no separator */ 2601 st->sep = '\0'; /* no separator */
2602 *pp = sep; 2602 *pp = sep;
2603 goto ok; 2603 goto ok;
2604 } 2604 }
2605 2605
2606 /* ":ts<unrecognised><unrecognised>". */ 2606 /* ":ts<unrecognised><unrecognised>". */
2607 if (sep[0] != '\\') { 2607 if (sep[0] != '\\') {
2608 (*pp)++; /* just for backwards compatibility */ 2608 (*pp)++; /* just for backwards compatibility */
2609 return AMR_BAD; 2609 return AMR_BAD;
2610 } 2610 }
2611 2611
2612 /* ":ts\n" */ 2612 /* ":ts\n" */
2613 if (sep[1] == 'n') { 2613 if (sep[1] == 'n') {
2614 st->sep = '\n'; 2614 st->sep = '\n';
2615 *pp = sep + 2; 2615 *pp = sep + 2;
2616 goto ok; 2616 goto ok;
2617 } 2617 }
2618 2618
2619 /* ":ts\t" */ 2619 /* ":ts\t" */
2620 if (sep[1] == 't') { 2620 if (sep[1] == 't') {
2621 st->sep = '\t'; 2621 st->sep = '\t';
2622 *pp = sep + 2; 2622 *pp = sep + 2;
2623 goto ok; 2623 goto ok;
2624 } 2624 }
2625 2625
2626 /* ":ts\x40" or ":ts\100" */ 2626 /* ":ts\x40" or ":ts\100" */
2627 { 2627 {
2628 const char *p = sep + 1; 2628 const char *p = sep + 1;
2629 int base = 8; /* assume octal */ 2629 int base = 8; /* assume octal */
2630 2630
2631 if (sep[1] == 'x') { 2631 if (sep[1] == 'x') {
2632 base = 16; 2632 base = 16;
2633 p++; 2633 p++;
2634 } else if (!ch_isdigit(sep[1])) { 2634 } else if (!ch_isdigit(sep[1])) {
2635 (*pp)++; /* just for backwards compatibility */ 2635 (*pp)++; /* just for backwards compatibility */
2636 return AMR_BAD; /* ":ts<backslash><unrecognised>". */ 2636 return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2637 } 2637 }
2638 2638
2639 if (!TryParseChar(&p, base, &st->sep)) { 2639 if (!TryParseChar(&p, base, &st->sep)) {
2640 Parse_Error(PARSE_FATAL, "Invalid character number: %s\n", p); 2640 Parse_Error(PARSE_FATAL, "Invalid character number: %s\n", p);
2641 return AMR_CLEANUP; 2641 return AMR_CLEANUP;
2642 } 2642 }
2643 if (*p != ':' && *p != st->endc) { 2643 if (*p != ':' && *p != st->endc) {
2644 (*pp)++; /* just for backwards compatibility */ 2644 (*pp)++; /* just for backwards compatibility */
2645 return AMR_BAD; 2645 return AMR_BAD;
2646 } 2646 }
2647 2647
2648 *pp = p; 2648 *pp = p;
2649 } 2649 }
2650 2650
2651ok: 2651ok:
2652 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL, 2652 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
2653 st->oneBigWord, st->sep); 2653 st->oneBigWord, st->sep);
2654 return AMR_OK; 2654 return AMR_OK;
2655} 2655}
2656 2656
2657/* :tA, :tu, :tl, :ts<separator>, etc. */ 2657/* :tA, :tu, :tl, :ts<separator>, etc. */
2658static ApplyModifierResult 2658static ApplyModifierResult
2659ApplyModifier_To(const char **pp, ApplyModifiersState *st) 2659ApplyModifier_To(const char **pp, ApplyModifiersState *st)
2660{ 2660{
2661 const char *mod = *pp; 2661 const char *mod = *pp;
2662 assert(mod[0] == 't'); 2662 assert(mod[0] == 't');
2663 2663
2664 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { 2664 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2665 *pp = mod + 1; 2665 *pp = mod + 1;
2666 return AMR_BAD; /* Found ":t<endc>" or ":t:". */ 2666 return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2667 } 2667 }
2668 2668
2669 if (mod[1] == 's') 2669 if (mod[1] == 's')
2670 return ApplyModifier_ToSep(pp, st); 2670 return ApplyModifier_ToSep(pp, st);
2671 2671
2672 if (mod[2] != st->endc && mod[2] != ':') { 2672 if (mod[2] != st->endc && mod[2] != ':') {
2673 *pp = mod + 1; 2673 *pp = mod + 1;
2674 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ 2674 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2675 } 2675 }
2676 2676
2677 /* Check for two-character options: ":tu", ":tl" */ 2677 /* Check for two-character options: ":tu", ":tl" */
2678 if (mod[1] == 'A') { /* absolute path */ 2678 if (mod[1] == 'A') { /* absolute path */
2679 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL, 2679 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
2680 st->oneBigWord, st->sep); 2680 st->oneBigWord, st->sep);
2681 *pp = mod + 2; 2681 *pp = mod + 2;
2682 return AMR_OK; 2682 return AMR_OK;
2683 } 2683 }
2684 2684
2685 if (mod[1] == 'u') { /* :tu */ 2685 if (mod[1] == 'u') { /* :tu */
2686 size_t i; 2686 size_t i;
2687 size_t len = strlen(st->val); 2687 size_t len = strlen(st->val);
2688 st->newVal = bmake_malloc(len + 1); 2688 st->newVal = bmake_malloc(len + 1);
2689 for (i = 0; i < len + 1; i++) 2689 for (i = 0; i < len + 1; i++)
2690 st->newVal[i] = ch_toupper(st->val[i]); 2690 st->newVal[i] = ch_toupper(st->val[i]);
2691 *pp = mod + 2; 2691 *pp = mod + 2;
2692 return AMR_OK; 2692 return AMR_OK;
2693 } 2693 }
2694 2694
2695 if (mod[1] == 'l') { /* :tl */ 2695 if (mod[1] == 'l') { /* :tl */
2696 size_t i; 2696 size_t i;
2697 size_t len = strlen(st->val); 2697 size_t len = strlen(st->val);
2698 st->newVal = bmake_malloc(len + 1); 2698 st->newVal = bmake_malloc(len + 1);
2699 for (i = 0; i < len + 1; i++) 2699 for (i = 0; i < len + 1; i++)
2700 st->newVal[i] = ch_tolower(st->val[i]); 2700 st->newVal[i] = ch_tolower(st->val[i]);
2701 *pp = mod + 2; 2701 *pp = mod + 2;
2702 return AMR_OK; 2702 return AMR_OK;
2703 } 2703 }
2704 2704
2705 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ 2705 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2706 st->oneBigWord = mod[1] == 'W'; 2706 st->oneBigWord = mod[1] == 'W';
2707 st->newVal = st->val; 2707 st->newVal = st->val;
2708 *pp = mod + 2; 2708 *pp = mod + 2;
2709 return AMR_OK; 2709 return AMR_OK;
2710 } 2710 }
2711 2711
2712 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2712 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2713 *pp = mod + 1; 2713 *pp = mod + 1;
2714 return AMR_BAD; 2714 return AMR_BAD;
2715} 2715}
2716 2716
2717/* :[#], :[1], :[-1..1], etc. */ 2717/* :[#], :[1], :[-1..1], etc. */
2718static ApplyModifierResult 2718static ApplyModifierResult
2719ApplyModifier_Words(const char **pp, ApplyModifiersState *st) 2719ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
2720{ 2720{
2721 char *estr; 2721 char *estr;
2722 int first, last; 2722 int first, last;
2723 VarParseResult res; 2723 VarParseResult res;
2724 const char *p; 2724 const char *p;
2725 2725
2726 (*pp)++; /* skip the '[' */ 2726 (*pp)++; /* skip the '[' */
2727 res = ParseModifierPart(pp, ']', st->eflags, st, 2727 res = ParseModifierPart(pp, ']', st->eflags, st,
2728 &estr, NULL, NULL, NULL); 2728 &estr, NULL, NULL, NULL);
2729 if (res != VPR_OK) 2729 if (res != VPR_OK)
2730 return AMR_CLEANUP; 2730 return AMR_CLEANUP;
2731 2731
2732 /* now *pp points just after the closing ']' */ 2732 /* now *pp points just after the closing ']' */
2733 if (**pp != ':' && **pp != st->endc) 2733 if (**pp != ':' && **pp != st->endc)
2734 goto bad_modifier; /* Found junk after ']' */ 2734 goto bad_modifier; /* Found junk after ']' */
2735 2735
2736 if (estr[0] == '\0') 2736 if (estr[0] == '\0')
2737 goto bad_modifier; /* empty square brackets in ":[]". */ 2737 goto bad_modifier; /* empty square brackets in ":[]". */
2738 2738
2739 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2739 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2740 if (st->oneBigWord) { 2740 if (st->oneBigWord) {
2741 st->newVal = bmake_strdup("1"); 2741 st->newVal = bmake_strdup("1");
2742 } else { 2742 } else {
2743 Buffer buf; 2743 Buffer buf;
2744 2744
2745 Words words = Str_Words(st->val, FALSE); 2745 Words words = Str_Words(st->val, FALSE);
2746 size_t ac = words.len; 2746 size_t ac = words.len;
2747 Words_Free(words); 2747 Words_Free(words);
2748 2748
2749 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */ 2749 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */
2750 Buf_AddInt(&buf, (int)ac); 2750 Buf_AddInt(&buf, (int)ac);
2751 st->newVal = Buf_Destroy(&buf, FALSE); 2751 st->newVal = Buf_Destroy(&buf, FALSE);
2752 } 2752 }
2753 goto ok; 2753 goto ok;
2754 } 2754 }
2755 2755
2756 if (estr[0] == '*' && estr[1] == '\0') { 2756 if (estr[0] == '*' && estr[1] == '\0') {
2757 /* Found ":[*]" */ 2757 /* Found ":[*]" */
2758 st->oneBigWord = TRUE; 2758 st->oneBigWord = TRUE;
2759 st->newVal = st->val; 2759 st->newVal = st->val;
2760 goto ok; 2760 goto ok;
2761 } 2761 }
2762 2762
2763 if (estr[0] == '@' && estr[1] == '\0') { 2763 if (estr[0] == '@' && estr[1] == '\0') {
2764 /* Found ":[@]" */ 2764 /* Found ":[@]" */
2765 st->oneBigWord = FALSE; 2765 st->oneBigWord = FALSE;
2766 st->newVal = st->val; 2766 st->newVal = st->val;
2767 goto ok; 2767 goto ok;
2768 } 2768 }
2769 2769
2770 /* 2770 /*
2771 * We expect estr to contain a single integer for :[N], or two integers 2771 * We expect estr to contain a single integer for :[N], or two integers
2772 * separated by ".." for :[start..end]. 2772 * separated by ".." for :[start..end].
2773 */ 2773 */
2774 p = estr; 2774 p = estr;
2775 if (!TryParseIntBase0(&p, &first)) 2775 if (!TryParseIntBase0(&p, &first))
2776 goto bad_modifier; /* Found junk instead of a number */ 2776 goto bad_modifier; /* Found junk instead of a number */
2777 2777
2778 if (p[0] == '\0') { /* Found only one integer in :[N] */ 2778 if (p[0] == '\0') { /* Found only one integer in :[N] */
2779 last = first; 2779 last = first;
2780 } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') { 2780 } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
2781 /* Expecting another integer after ".." */ 2781 /* Expecting another integer after ".." */
2782 p += 2; 2782 p += 2;
2783 if (!TryParseIntBase0(&p, &last) || *p != '\0') 2783 if (!TryParseIntBase0(&p, &last) || *p != '\0')
2784 goto bad_modifier; /* Found junk after ".." */ 2784 goto bad_modifier; /* Found junk after ".." */
2785 } else 2785 } else
2786 goto bad_modifier; /* Found junk instead of ".." */ 2786 goto bad_modifier; /* Found junk instead of ".." */
2787 2787
2788 /* 2788 /*
2789 * Now first and last are properly filled in, but we still have to check 2789 * Now first and last are properly filled in, but we still have to check
2790 * for 0 as a special case. 2790 * for 0 as a special case.
2791 */ 2791 */
2792 if (first == 0 && last == 0) { 2792 if (first == 0 && last == 0) {
2793 /* ":[0]" or perhaps ":[0..0]" */ 2793 /* ":[0]" or perhaps ":[0..0]" */
2794 st->oneBigWord = TRUE; 2794 st->oneBigWord = TRUE;
2795 st->newVal = st->val; 2795 st->newVal = st->val;
2796 goto ok; 2796 goto ok;
2797 } 2797 }
2798 2798
2799 /* ":[0..N]" or ":[N..0]" */ 2799 /* ":[0..N]" or ":[N..0]" */
2800 if (first == 0 || last == 0) 2800 if (first == 0 || last == 0)
2801 goto bad_modifier; 2801 goto bad_modifier;
2802 2802
2803 /* Normal case: select the words described by first and last. */ 2803 /* Normal case: select the words described by first and last. */
2804 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last); 2804 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last);
2805 2805
2806ok: 2806ok:
2807 free(estr); 2807 free(estr);
2808 return AMR_OK; 2808 return AMR_OK;
2809 2809
2810bad_modifier: 2810bad_modifier:
2811 free(estr); 2811 free(estr);
2812 return AMR_BAD; 2812 return AMR_BAD;
2813} 2813}
2814 2814
2815static int 2815static int
2816str_cmp_asc(const void *a, const void *b) 2816str_cmp_asc(const void *a, const void *b)
2817{ 2817{
2818 return strcmp(*(const char * const *)a, *(const char * const *)b); 2818 return strcmp(*(const char * const *)a, *(const char * const *)b);
2819} 2819}
2820 2820
2821static int 2821static int
2822str_cmp_desc(const void *a, const void *b) 2822str_cmp_desc(const void *a, const void *b)
2823{ 2823{
2824 return strcmp(*(const char * const *)b, *(const char * const *)a); 2824 return strcmp(*(const char * const *)b, *(const char * const *)a);
2825} 2825}
2826 2826
2827/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ 2827/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
2828static ApplyModifierResult 2828static ApplyModifierResult
2829ApplyModifier_Order(const char **pp, ApplyModifiersState *st) 2829ApplyModifier_Order(const char **pp, ApplyModifiersState *st)
2830{ 2830{
2831 const char *mod = (*pp)++; /* skip past the 'O' in any case */ 2831 const char *mod = (*pp)++; /* skip past the 'O' in any case */
2832 2832
2833 Words words = Str_Words(st->val, FALSE); 2833 Words words = Str_Words(st->val, FALSE);
2834 2834
2835 if (mod[1] == st->endc || mod[1] == ':') { 2835 if (mod[1] == st->endc || mod[1] == ':') {
2836 /* :O sorts ascending */ 2836 /* :O sorts ascending */
2837 qsort(words.words, words.len, sizeof(char *), str_cmp_asc); 2837 qsort(words.words, words.len, sizeof(char *), str_cmp_asc);
2838 2838
2839 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2839 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2840 (mod[2] == st->endc || mod[2] == ':')) { 2840 (mod[2] == st->endc || mod[2] == ':')) {
2841 (*pp)++; 2841 (*pp)++;
2842 2842
2843 if (mod[1] == 'r') { 2843 if (mod[1] == 'r') {
2844 /* :Or sorts descending */ 2844 /* :Or sorts descending */
2845 qsort(words.words, words.len, sizeof(char *), str_cmp_desc); 2845 qsort(words.words, words.len, sizeof(char *), str_cmp_desc);
2846 2846
2847 } else { 2847 } else {
2848 /* :Ox shuffles 2848 /* :Ox shuffles
2849 * 2849 *
2850 * We will use [ac..2] range for mod factors. This will produce 2850 * We will use [ac..2] range for mod factors. This will produce
2851 * random numbers in [(ac-1)..0] interval, and minimal 2851 * random numbers in [(ac-1)..0] interval, and minimal
2852 * reasonable value for mod factor is 2 (the mod 1 will produce 2852 * reasonable value for mod factor is 2 (the mod 1 will produce
2853 * 0 with probability 1). 2853 * 0 with probability 1).
2854 */ 2854 */
2855 size_t i; 2855 size_t i;
2856 for (i = words.len - 1; i > 0; i--) { 2856 for (i = words.len - 1; i > 0; i--) {
2857 size_t rndidx = (size_t)random() % (i + 1); 2857 size_t rndidx = (size_t)random() % (i + 1);
2858 char *t = words.words[i]; 2858 char *t = words.words[i];
2859 words.words[i] = words.words[rndidx]; 2859 words.words[i] = words.words[rndidx];
2860 words.words[rndidx] = t; 2860 words.words[rndidx] = t;
2861 } 2861 }
2862 } 2862 }
2863 } else { 2863 } else {
2864 Words_Free(words); 2864 Words_Free(words);
2865 return AMR_BAD; 2865 return AMR_BAD;
2866 } 2866 }
2867 2867
2868 st->newVal = Words_JoinFree(words); 2868 st->newVal = Words_JoinFree(words);
2869 return AMR_OK; 2869 return AMR_OK;
2870} 2870}
2871 2871
2872/* :? then : else */ 2872/* :? then : else */
2873static ApplyModifierResult 2873static ApplyModifierResult
2874ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) 2874ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
2875{ 2875{
2876 char *then_expr, *else_expr; 2876 char *then_expr, *else_expr;
2877 VarParseResult res; 2877 VarParseResult res;
2878 2878
2879 Boolean value = FALSE; 2879 Boolean value = FALSE;
2880 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2880 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2881 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2881 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2882 2882
2883 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */ 2883 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
2884 if (st->eflags & VARE_WANTRES) { 2884 if (st->eflags & VARE_WANTRES) {
2885 cond_rc = Cond_EvalCondition(st->v->name, &value); 2885 cond_rc = Cond_EvalCondition(st->v->name, &value);
2886 if (cond_rc != COND_INVALID && value) 2886 if (cond_rc != COND_INVALID && value)
2887 then_eflags |= VARE_WANTRES; 2887 then_eflags |= VARE_WANTRES;
2888 if (cond_rc != COND_INVALID && !value) 2888 if (cond_rc != COND_INVALID && !value)
2889 else_eflags |= VARE_WANTRES; 2889 else_eflags |= VARE_WANTRES;
2890 } 2890 }
2891 2891
2892 (*pp)++; /* skip past the '?' */ 2892 (*pp)++; /* skip past the '?' */
2893 res = ParseModifierPart(pp, ':', then_eflags, st, 2893 res = ParseModifierPart(pp, ':', then_eflags, st,
2894 &then_expr, NULL, NULL, NULL); 2894 &then_expr, NULL, NULL, NULL);
2895 if (res != VPR_OK) 2895 if (res != VPR_OK)
2896 return AMR_CLEANUP; 2896 return AMR_CLEANUP;
2897 2897
2898 res = ParseModifierPart(pp, st->endc, else_eflags, st, 2898 res = ParseModifierPart(pp, st->endc, else_eflags, st,
2899 &else_expr, NULL, NULL, NULL); 2899 &else_expr, NULL, NULL, NULL);
2900 if (res != VPR_OK) 2900 if (res != VPR_OK)
2901 return AMR_CLEANUP; 2901 return AMR_CLEANUP;
2902 2902
2903 (*pp)--; 2903 (*pp)--;
2904 if (cond_rc == COND_INVALID) { 2904 if (cond_rc == COND_INVALID) {
2905 Error("Bad conditional expression `%s' in %s?%s:%s", 2905 Error("Bad conditional expression `%s' in %s?%s:%s",
2906 st->v->name, st->v->name, then_expr, else_expr); 2906 st->v->name, st->v->name, then_expr, else_expr);
2907 return AMR_CLEANUP; 2907 return AMR_CLEANUP;
2908 } 2908 }
2909 2909
2910 if (value) { 2910 if (value) {
2911 st->newVal = then_expr; 2911 st->newVal = then_expr;
2912 free(else_expr); 2912 free(else_expr);
2913 } else { 2913 } else {
2914 st->newVal = else_expr; 2914 st->newVal = else_expr;
2915 free(then_expr); 2915 free(then_expr);
2916 } 2916 }
2917 ApplyModifiersState_Define(st); 2917 ApplyModifiersState_Define(st);
2918 return AMR_OK; 2918 return AMR_OK;
2919} 2919}
2920 2920
2921/* 2921/*
2922 * The ::= modifiers actually assign a value to the variable. 2922 * The ::= modifiers actually assign a value to the variable.
2923 * Their main purpose is in supporting modifiers of .for loop 2923 * Their main purpose is in supporting modifiers of .for loop
2924 * iterators and other obscure uses. They always expand to 2924 * iterators and other obscure uses. They always expand to
2925 * nothing. In a target rule that would otherwise expand to an 2925 * nothing. In a target rule that would otherwise expand to an
2926 * empty line they can be preceded with @: to keep make happy. 2926 * empty line they can be preceded with @: to keep make happy.
2927 * Eg. 2927 * Eg.
2928 * 2928 *
2929 * foo: .USE 2929 * foo: .USE
2930 * .for i in ${.TARGET} ${.TARGET:R}.gz 2930 * .for i in ${.TARGET} ${.TARGET:R}.gz
2931 * @: ${t::=$i} 2931 * @: ${t::=$i}
2932 * @echo blah ${t:T} 2932 * @echo blah ${t:T}
2933 * .endfor 2933 * .endfor
2934 * 2934 *
2935 * ::=<str> Assigns <str> as the new value of variable. 2935 * ::=<str> Assigns <str> as the new value of variable.
2936 * ::?=<str> Assigns <str> as value of variable if 2936 * ::?=<str> Assigns <str> as value of variable if
2937 * it was not already set. 2937 * it was not already set.
2938 * ::+=<str> Appends <str> to variable. 2938 * ::+=<str> Appends <str> to variable.
2939 * ::!=<cmd> Assigns output of <cmd> as the new value of 2939 * ::!=<cmd> Assigns output of <cmd> as the new value of
2940 * variable. 2940 * variable.
2941 */ 2941 */
2942static ApplyModifierResult 2942static ApplyModifierResult
2943ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) 2943ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
2944{ 2944{
2945 GNode *v_ctxt; 2945 GNode *v_ctxt;
2946 char delim; 2946 char delim;
2947 char *val; 2947 char *val;
2948 VarParseResult res; 2948 VarParseResult res;
2949 2949
2950 const char *mod = *pp; 2950 const char *mod = *pp;
2951 const char *op = mod + 1; 2951 const char *op = mod + 1;
2952 2952
2953 if (op[0] == '=') 2953 if (op[0] == '=')
2954 goto ok; 2954 goto ok;
2955 if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=') 2955 if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
2956 goto ok; 2956 goto ok;
2957 return AMR_UNKNOWN; /* "::<unrecognised>" */ 2957 return AMR_UNKNOWN; /* "::<unrecognised>" */
2958ok: 2958ok:
2959 2959
2960 if (st->v->name[0] == '\0') { 2960 if (st->v->name[0] == '\0') {
2961 *pp = mod + 1; 2961 *pp = mod + 1;
2962 return AMR_BAD; 2962 return AMR_BAD;
2963 } 2963 }
2964 2964
2965 v_ctxt = st->ctxt; /* context where v belongs */ 2965 v_ctxt = st->ctxt; /* context where v belongs */
2966 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) { 2966 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
2967 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2967 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2968 if (gv == NULL) 2968 if (gv == NULL)
2969 v_ctxt = VAR_GLOBAL; 2969 v_ctxt = VAR_GLOBAL;
2970 else 2970 else
2971 VarFreeEnv(gv, TRUE); 2971 VarFreeEnv(gv, TRUE);
2972 } 2972 }
2973 2973
2974 switch (op[0]) { 2974 switch (op[0]) {
2975 case '+': 2975 case '+':
2976 case '?': 2976 case '?':
2977 case '!': 2977 case '!':
2978 *pp = mod + 3; 2978 *pp = mod + 3;
2979 break; 2979 break;
2980 default: 2980 default:
2981 *pp = mod + 2; 2981 *pp = mod + 2;
2982 break; 2982 break;
2983 } 2983 }
2984 2984
2985 delim = st->startc == '(' ? ')' : '}'; 2985 delim = st->startc == '(' ? ')' : '}';
2986 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL); 2986 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL);
2987 if (res != VPR_OK) 2987 if (res != VPR_OK)
2988 return AMR_CLEANUP; 2988 return AMR_CLEANUP;
2989 2989
2990 (*pp)--; 2990 (*pp)--;
2991 2991
2992 if (st->eflags & VARE_WANTRES) { 2992 if (st->eflags & VARE_WANTRES) {
2993 switch (op[0]) { 2993 switch (op[0]) {
2994 case '+': 2994 case '+':
2995 Var_Append(st->v->name, val, v_ctxt); 2995 Var_Append(st->v->name, val, v_ctxt);
2996 break; 2996 break;
2997 case '!': { 2997 case '!': {
2998 const char *errfmt; 2998 const char *errfmt;
2999 char *cmd_output = Cmd_Exec(val, &errfmt); 2999 char *cmd_output = Cmd_Exec(val, &errfmt);
3000 if (errfmt) 3000 if (errfmt)
3001 Error(errfmt, val); 3001 Error(errfmt, val);
3002 else 3002 else
3003 Var_Set(st->v->name, cmd_output, v_ctxt); 3003 Var_Set(st->v->name, cmd_output, v_ctxt);
3004 free(cmd_output); 3004 free(cmd_output);
3005 break; 3005 break;
3006 } 3006 }
3007 case '?': 3007 case '?':
3008 if (!(st->exprFlags & VEF_UNDEF)) 3008 if (!(st->exprFlags & VEF_UNDEF))
3009 break; 3009 break;
3010 /* FALLTHROUGH */ 3010 /* FALLTHROUGH */
3011 default: 3011 default:
3012 Var_Set(st->v->name, val, v_ctxt); 3012 Var_Set(st->v->name, val, v_ctxt);
3013 break; 3013 break;
3014 } 3014 }
3015 } 3015 }
3016 free(val); 3016 free(val);
3017 st->newVal = emptyString; 3017 st->newVal = emptyString;
3018 return AMR_OK; 3018 return AMR_OK;
3019} 3019}
3020 3020
3021/* :_=... 3021/* :_=...
3022 * remember current value */ 3022 * remember current value */
3023static ApplyModifierResult 3023static ApplyModifierResult
3024ApplyModifier_Remember(const char **pp, ApplyModifiersState *st) 3024ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
3025{ 3025{
3026 const char *mod = *pp; 3026 const char *mod = *pp;
3027 if (!ModMatchEq(mod, "_", st->endc)) 3027 if (!ModMatchEq(mod, "_", st->endc))
3028 return AMR_UNKNOWN; 3028 return AMR_UNKNOWN;
3029 3029
3030 if (mod[1] == '=') { 3030 if (mod[1] == '=') {
3031 size_t n = strcspn(mod + 2, ":)}"); 3031 size_t n = strcspn(mod + 2, ":)}");
3032 char *name = bmake_strldup(mod + 2, n); 3032 char *name = bmake_strldup(mod + 2, n);
3033 Var_Set(name, st->val, st->ctxt); 3033 Var_Set(name, st->val, st->ctxt);
3034 free(name); 3034 free(name);
3035 *pp = mod + 2 + n; 3035 *pp = mod + 2 + n;
3036 } else { 3036 } else {
3037 Var_Set("_", st->val, st->ctxt); 3037 Var_Set("_", st->val, st->ctxt);
3038 *pp = mod + 1; 3038 *pp = mod + 1;
3039 } 3039 }
3040 st->newVal = st->val; 3040 st->newVal = st->val;
3041 return AMR_OK; 3041 return AMR_OK;
3042} 3042}
3043 3043
3044/* Apply the given function to each word of the variable value, 3044/* Apply the given function to each word of the variable value,
3045 * for a single-letter modifier such as :H, :T. */ 3045 * for a single-letter modifier such as :H, :T. */
3046static ApplyModifierResult 3046static ApplyModifierResult
3047ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, 3047ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
3048 ModifyWordsCallback modifyWord) 3048 ModifyWordsCallback modifyWord)
3049{ 3049{
3050 char delim = (*pp)[1]; 3050 char delim = (*pp)[1];
3051 if (delim != st->endc && delim != ':') 3051 if (delim != st->endc && delim != ':')
3052 return AMR_UNKNOWN; 3052 return AMR_UNKNOWN;
3053 3053
3054 st->newVal = ModifyWords(st->val, modifyWord, NULL, 3054 st->newVal = ModifyWords(st->val, modifyWord, NULL,
3055 st->oneBigWord, st->sep); 3055 st->oneBigWord, st->sep);
3056 (*pp)++; 3056 (*pp)++;
3057 return AMR_OK; 3057 return AMR_OK;
3058} 3058}
3059 3059
3060static ApplyModifierResult 3060static ApplyModifierResult
3061ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) 3061ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
3062{ 3062{
3063 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 3063 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
3064 st->newVal = VarUniq(st->val); 3064 st->newVal = VarUniq(st->val);
3065 (*pp)++; 3065 (*pp)++;
3066 return AMR_OK; 3066 return AMR_OK;
3067 } else 3067 } else
3068 return AMR_UNKNOWN; 3068 return AMR_UNKNOWN;
3069} 3069}
3070 3070
3071#ifdef SYSVVARSUB 3071#ifdef SYSVVARSUB
3072/* :from=to */ 3072/* :from=to */
3073static ApplyModifierResult 3073static ApplyModifierResult
3074ApplyModifier_SysV(const char **pp, ApplyModifiersState *st) 3074ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
3075{ 3075{
3076 char *lhs, *rhs; 3076 char *lhs, *rhs;
3077 VarParseResult res; 3077 VarParseResult res;
3078 3078
3079 const char *mod = *pp; 3079 const char *mod = *pp;
3080 Boolean eqFound = FALSE; 3080 Boolean eqFound = FALSE;
3081 3081
3082 /* 3082 /*
3083 * First we make a pass through the string trying to verify it is a 3083 * First we make a pass through the string trying to verify it is a
3084 * SysV-make-style translation. It must be: <lhs>=<rhs> 3084 * SysV-make-style translation. It must be: <lhs>=<rhs>
3085 */ 3085 */
3086 int depth = 1; 3086 int depth = 1;
3087 const char *p = mod; 3087 const char *p = mod;
3088 while (*p != '\0' && depth > 0) { 3088 while (*p != '\0' && depth > 0) {
3089 if (*p == '=') { /* XXX: should also test depth == 1 */ 3089 if (*p == '=') { /* XXX: should also test depth == 1 */
3090 eqFound = TRUE; 3090 eqFound = TRUE;
3091 /* continue looking for st->endc */ 3091 /* continue looking for st->endc */
3092 } else if (*p == st->endc) 3092 } else if (*p == st->endc)
3093 depth--; 3093 depth--;
3094 else if (*p == st->startc) 3094 else if (*p == st->startc)
3095 depth++; 3095 depth++;
3096 if (depth > 0) 3096 if (depth > 0)
3097 p++; 3097 p++;
3098 } 3098 }
3099 if (*p != st->endc || !eqFound) 3099 if (*p != st->endc || !eqFound)
3100 return AMR_UNKNOWN; 3100 return AMR_UNKNOWN;
3101 3101
3102 *pp = mod; 3102 *pp = mod;
3103 res = ParseModifierPart(pp, '=', st->eflags, st, 3103 res = ParseModifierPart(pp, '=', st->eflags, st,
3104 &lhs, NULL, NULL, NULL); 3104 &lhs, NULL, NULL, NULL);
3105 if (res != VPR_OK) 3105 if (res != VPR_OK)
3106 return AMR_CLEANUP; 3106 return AMR_CLEANUP;
3107 3107
3108 /* The SysV modifier lasts until the end of the variable expression. */ 3108 /* The SysV modifier lasts until the end of the variable expression. */
3109 res = ParseModifierPart(pp, st->endc, st->eflags, st, 3109 res = ParseModifierPart(pp, st->endc, st->eflags, st,
3110 &rhs, NULL, NULL, NULL); 3110 &rhs, NULL, NULL, NULL);
3111 if (res != VPR_OK) 3111 if (res != VPR_OK)
3112 return AMR_CLEANUP; 3112 return AMR_CLEANUP;
3113 3113
3114 (*pp)--; 3114 (*pp)--;
3115 if (lhs[0] == '\0' && st->val[0] == '\0') { 3115 if (lhs[0] == '\0' && st->val[0] == '\0') {
3116 st->newVal = st->val; /* special case */ 3116 st->newVal = st->val; /* special case */
3117 } else { 3117 } else {
3118 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs}; 3118 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs};
3119 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args, 3119 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args,
3120 st->oneBigWord, st->sep); 3120 st->oneBigWord, st->sep);
3121 } 3121 }
3122 free(lhs); 3122 free(lhs);
3123 free(rhs); 3123 free(rhs);
3124 return AMR_OK; 3124 return AMR_OK;
3125} 3125}
3126#endif 3126#endif
3127 3127
3128#ifdef SUNSHCMD 3128#ifdef SUNSHCMD
3129/* :sh */ 3129/* :sh */
3130static ApplyModifierResult 3130static ApplyModifierResult
3131ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) 3131ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
3132{ 3132{
3133 const char *p = *pp; 3133 const char *p = *pp;
3134 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) { 3134 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3135 if (st->eflags & VARE_WANTRES) { 3135 if (st->eflags & VARE_WANTRES) {
3136 const char *errfmt; 3136 const char *errfmt;
3137 st->newVal = Cmd_Exec(st->val, &errfmt); 3137 st->newVal = Cmd_Exec(st->val, &errfmt);
3138 if (errfmt) 3138 if (errfmt)
3139 Error(errfmt, st->val); 3139 Error(errfmt, st->val);
3140 } else 3140 } else
3141 st->newVal = emptyString; 3141 st->newVal = emptyString;
3142 *pp = p + 2; 3142 *pp = p + 2;
3143 return AMR_OK; 3143 return AMR_OK;
3144 } else 3144 } else
3145 return AMR_UNKNOWN; 3145 return AMR_UNKNOWN;
3146} 3146}
3147#endif 3147#endif
3148 3148
3149static void 3149static void
3150LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc) 3150LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc)
3151{ 3151{
3152 char eflags_str[VarEvalFlags_ToStringSize]; 3152 char eflags_str[VarEvalFlags_ToStringSize];
3153 char vflags_str[VarFlags_ToStringSize]; 3153 char vflags_str[VarFlags_ToStringSize];
3154 char exprflags_str[VarExprFlags_ToStringSize]; 3154 char exprflags_str[VarExprFlags_ToStringSize];
3155 Boolean is_single_char = mod[0] != '\0' && 3155 Boolean is_single_char = mod[0] != '\0' &&
3156 (mod[1] == endc || mod[1] == ':'); 3156 (mod[1] == endc || mod[1] == ':');
3157 3157
3158 /* At this point, only the first character of the modifier can 3158 /* At this point, only the first character of the modifier can
3159 * be used since the end of the modifier is not yet known. */ 3159 * be used since the end of the modifier is not yet known. */
3160 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n", 3160 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
3161 st->v->name, mod[0], is_single_char ? "" : "...", st->val, 3161 st->v->name, mod[0], is_single_char ? "" : "...", st->val,
3162 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3162 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3163 st->eflags, VarEvalFlags_ToStringSpecs), 3163 st->eflags, VarEvalFlags_ToStringSpecs),
3164 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3164 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3165 st->v->flags, VarFlags_ToStringSpecs), 3165 st->v->flags, VarFlags_ToStringSpecs),
3166 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3166 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3167 st->exprFlags, 3167 st->exprFlags,
3168 VarExprFlags_ToStringSpecs)); 3168 VarExprFlags_ToStringSpecs));
3169} 3169}
3170 3170
3171static void 3171static void
3172LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod) 3172LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3173{ 3173{
3174 char eflags_str[VarEvalFlags_ToStringSize]; 3174 char eflags_str[VarEvalFlags_ToStringSize];
3175 char vflags_str[VarFlags_ToStringSize]; 3175 char vflags_str[VarFlags_ToStringSize];
3176 char exprflags_str[VarExprFlags_ToStringSize]; 3176 char exprflags_str[VarExprFlags_ToStringSize];
3177 const char *quot = st->newVal == var_Error ? "" : "\""; 3177 const char *quot = st->newVal == var_Error ? "" : "\"";
3178 const char *newVal = st->newVal == var_Error ? "error" : st->newVal; 3178 const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
3179 3179
3180 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n", 3180 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
3181 st->v->name, (int)(p - mod), mod, quot, newVal, quot, 3181 st->v->name, (int)(p - mod), mod, quot, newVal, quot,
3182 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3182 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3183 st->eflags, VarEvalFlags_ToStringSpecs), 3183 st->eflags, VarEvalFlags_ToStringSpecs),
3184 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3184 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3185 st->v->flags, VarFlags_ToStringSpecs), 3185 st->v->flags, VarFlags_ToStringSpecs),
3186 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3186 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3187 st->exprFlags, 3187 st->exprFlags,
3188 VarExprFlags_ToStringSpecs)); 3188 VarExprFlags_ToStringSpecs));
3189} 3189}
3190 3190
3191static ApplyModifierResult 3191static ApplyModifierResult
3192ApplyModifier(const char **pp, ApplyModifiersState *st) 3192ApplyModifier(const char **pp, ApplyModifiersState *st)
3193{ 3193{
3194 switch (**pp) { 3194 switch (**pp) {
3195 case ':': 3195 case ':':
3196 return ApplyModifier_Assign(pp, st); 3196 return ApplyModifier_Assign(pp, st);
3197 case '@': 3197 case '@':
3198 return ApplyModifier_Loop(pp, st); 3198 return ApplyModifier_Loop(pp, st);
3199 case '_': 3199 case '_':
3200 return ApplyModifier_Remember(pp, st); 3200 return ApplyModifier_Remember(pp, st);
3201 case 'D': 3201 case 'D':
3202 case 'U': 3202 case 'U':
3203 return ApplyModifier_Defined(pp, st); 3203 return ApplyModifier_Defined(pp, st);
3204 case 'L': 3204 case 'L':
3205 return ApplyModifier_Literal(pp, st); 3205 return ApplyModifier_Literal(pp, st);
3206 case 'P': 3206 case 'P':
3207 return ApplyModifier_Path(pp, st); 3207 return ApplyModifier_Path(pp, st);
3208 case '!': 3208 case '!':
3209 return ApplyModifier_ShellCommand(pp, st); 3209 return ApplyModifier_ShellCommand(pp, st);
3210 case '[': 3210 case '[':
3211 return ApplyModifier_Words(pp, st); 3211 return ApplyModifier_Words(pp, st);
3212 case 'g': 3212 case 'g':
3213 return ApplyModifier_Gmtime(pp, st); 3213 return ApplyModifier_Gmtime(pp, st);
3214 case 'h': 3214 case 'h':
3215 return ApplyModifier_Hash(pp, st); 3215 return ApplyModifier_Hash(pp, st);
3216 case 'l': 3216 case 'l':
3217 return ApplyModifier_Localtime(pp, st); 3217 return ApplyModifier_Localtime(pp, st);
3218 case 't': 3218 case 't':
3219 return ApplyModifier_To(pp, st); 3219 return ApplyModifier_To(pp, st);
3220 case 'N': 3220 case 'N':
3221 case 'M': 3221 case 'M':
3222 return ApplyModifier_Match(pp, st); 3222 return ApplyModifier_Match(pp, st);
3223 case 'S': 3223 case 'S':
3224 return ApplyModifier_Subst(pp, st); 3224 return ApplyModifier_Subst(pp, st);
3225 case '?': 3225 case '?':
3226 return ApplyModifier_IfElse(pp, st); 3226 return ApplyModifier_IfElse(pp, st);
3227#ifndef NO_REGEX 3227#ifndef NO_REGEX
3228 case 'C': 3228 case 'C':
3229 return ApplyModifier_Regex(pp, st); 3229 return ApplyModifier_Regex(pp, st);
3230#endif 3230#endif
3231 case 'q': 3231 case 'q':
3232 case 'Q': 3232 case 'Q':
3233 return ApplyModifier_Quote(pp, st); 3233 return ApplyModifier_Quote(pp, st);
3234 case 'T': 3234 case 'T':
3235 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail); 3235 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
3236 case 'H': 3236 case 'H':
3237 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head); 3237 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
3238 case 'E': 3238 case 'E':
3239 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix); 3239 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
3240 case 'R': 3240 case 'R':
3241 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root); 3241 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
3242 case 'r': 3242 case 'r':
3243 return ApplyModifier_Range(pp, st); 3243 return ApplyModifier_Range(pp, st);
3244 case 'O': 3244 case 'O':
3245 return ApplyModifier_Order(pp, st); 3245 return ApplyModifier_Order(pp, st);
3246 case 'u': 3246 case 'u':
3247 return ApplyModifier_Unique(pp, st); 3247 return ApplyModifier_Unique(pp, st);
3248#ifdef SUNSHCMD 3248#ifdef SUNSHCMD
3249 case 's': 3249 case 's':
3250 return ApplyModifier_SunShell(pp, st); 3250 return ApplyModifier_SunShell(pp, st);
3251#endif 3251#endif
3252 default: 3252 default:
3253 return AMR_UNKNOWN; 3253 return AMR_UNKNOWN;
3254 } 3254 }
3255} 3255}
3256 3256
3257static char *ApplyModifiers(const char **, char *, char, char, Var *, 3257static char *ApplyModifiers(const char **, char *, char, char, Var *,
3258 VarExprFlags *, GNode *, VarEvalFlags, void **); 3258 VarExprFlags *, GNode *, VarEvalFlags, void **);
3259 3259
3260typedef enum ApplyModifiersIndirectResult { 3260typedef enum ApplyModifiersIndirectResult {
3261 AMIR_CONTINUE, 3261 AMIR_CONTINUE,
3262 AMIR_APPLY_MODS, 3262 AMIR_APPLY_MODS,
3263 AMIR_OUT 3263 AMIR_OUT
3264} ApplyModifiersIndirectResult; 3264} ApplyModifiersIndirectResult;
3265 3265
3266/* While expanding a variable expression, expand and apply indirect 3266/* While expanding a variable expression, expand and apply indirect
3267 * modifiers. */ 3267 * modifiers. */
3268static ApplyModifiersIndirectResult 3268static ApplyModifiersIndirectResult
3269ApplyModifiersIndirect( 3269ApplyModifiersIndirect(
3270 ApplyModifiersState *const st, 3270 ApplyModifiersState *const st,
3271 const char **inout_p, 3271 const char **inout_p,
3272 void **const out_freeIt 3272 void **const out_freeIt
3273) { 3273) {
3274 const char *p = *inout_p; 3274 const char *p = *inout_p;
3275 const char *nested_p = p; 
3276 const char *mods; 3275 const char *mods;
3277 void *mods_freeIt; 3276 void *mods_freeIt;
3278 3277
3279 (void)Var_Parse(&nested_p, st->ctxt, st->eflags, &mods, &mods_freeIt); 3278 (void)Var_Parse(&p, st->ctxt, st->eflags, &mods, &mods_freeIt);
3280 /* TODO: handle errors */ 3279 /* TODO: handle errors */
3281 3280
3282 /* 3281 /*
3283 * If we have not parsed up to st->endc or ':', we are not 3282 * If we have not parsed up to st->endc or ':', we are not
3284 * interested. This means the expression ${VAR:${M_1}${M_2}} 3283 * interested. This means the expression ${VAR:${M_1}${M_2}}
3285 * is not accepted, but ${VAR:${M_1}:${M_2}} is. 3284 * is not accepted, but ${VAR:${M_1}:${M_2}} is.
3286 */ 3285 */
3287 if (mods[0] != '\0' && 3286 if (mods[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
3288 *nested_p != '\0' && *nested_p != ':' && *nested_p != st->endc) { 
3289 if (DEBUG(LINT)) 3287 if (DEBUG(LINT))
3290 Parse_Error(PARSE_FATAL, 3288 Parse_Error(PARSE_FATAL,
3291 "Missing delimiter ':' after indirect modifier \"%.*s\"", 3289 "Missing delimiter ':' after indirect modifier \"%.*s\"",
3292 (int)(nested_p - p), p); 3290 (int)(p - *inout_p), *inout_p);
3293 3291
3294 free(mods_freeIt); 3292 free(mods_freeIt);
3295 /* XXX: apply_mods doesn't sound like "not interested". */ 3293 /* XXX: apply_mods doesn't sound like "not interested". */
3296 /* XXX: Why is the indirect modifier parsed again by 3294 /* XXX: Why is the indirect modifier parsed again by
3297 * apply_mods? If any, p should be advanced to nested_p. */ 3295 * apply_mods? If any, p should be advanced to nested_p. */
3298 return AMIR_APPLY_MODS; 3296 return AMIR_APPLY_MODS;
3299 } 3297 }
3300 3298
3301 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", 3299 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
3302 mods, (int)(size_t)(nested_p - p), p); 3300 mods, (int)(p - *inout_p), *inout_p);
3303 
3304 p = nested_p; 
3305 3301
3306 if (mods[0] != '\0') { 3302 if (mods[0] != '\0') {
3307 const char *rval_pp = mods; 3303 const char *rval_pp = mods;
3308 st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v, 3304 st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v,
3309 &st->exprFlags, st->ctxt, st->eflags, out_freeIt); 3305 &st->exprFlags, st->ctxt, st->eflags, out_freeIt);
3310 if (st->val == var_Error 3306 if (st->val == var_Error
3311 || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR)) 3307 || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR))
3312 || *rval_pp != '\0') { 3308 || *rval_pp != '\0') {
3313 free(mods_freeIt); 3309 free(mods_freeIt);
3314 *inout_p = p; 3310 *inout_p = p;
3315 return AMIR_OUT; /* error already reported */ 3311 return AMIR_OUT; /* error already reported */
3316 } 3312 }
3317 } 3313 }
3318 free(mods_freeIt); 3314 free(mods_freeIt);
3319 3315
3320 if (*p == ':') 3316 if (*p == ':')
3321 p++; 3317 p++;
3322 else if (*p == '\0' && st->endc != '\0') { 3318 else if (*p == '\0' && st->endc != '\0') {
3323 Error("Unclosed variable specification after complex " 3319 Error("Unclosed variable specification after complex "
3324 "modifier (expecting '%c') for %s", st->endc, st->v->name); 3320 "modifier (expecting '%c') for %s", st->endc, st->v->name);
3325 *inout_p = p; 3321 *inout_p = p;
3326 return AMIR_OUT; 3322 return AMIR_OUT;
3327 } 3323 }
3328 3324
3329 *inout_p = p; 3325 *inout_p = p;
3330 return AMIR_CONTINUE; 3326 return AMIR_CONTINUE;
3331} 3327}
3332 3328
3333/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ 3329/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3334static char * 3330static char *
3335ApplyModifiers( 3331ApplyModifiers(
3336 const char **pp, /* the parsing position, updated upon return */ 3332 const char **pp, /* the parsing position, updated upon return */
3337 char *const val, /* the current value of the expression */ 3333 char *const val, /* the current value of the expression */
3338 char const startc, /* '(' or '{', or '\0' for indirect modifiers */ 3334 char const startc, /* '(' or '{', or '\0' for indirect modifiers */
3339 char const endc, /* ')' or '}', or '\0' for indirect modifiers */ 3335 char const endc, /* ')' or '}', or '\0' for indirect modifiers */
3340 Var * const v, 3336 Var * const v,
3341 VarExprFlags *exprFlags, 3337 VarExprFlags *exprFlags,
3342 GNode * const ctxt, /* for looking up and modifying variables */ 3338 GNode * const ctxt, /* for looking up and modifying variables */
3343 VarEvalFlags const eflags, 3339 VarEvalFlags const eflags,
3344 void ** const out_freeIt /* free this after using the return value */ 3340 void ** const out_freeIt /* free this after using the return value */
3345) { 3341) {
3346 ApplyModifiersState st = { 3342 ApplyModifiersState st = {
3347 startc, endc, v, ctxt, eflags, 3343 startc, endc, v, ctxt, eflags,
3348 val, /* .val */ 3344 val, /* .val */
3349 var_Error, /* .newVal */ 3345 var_Error, /* .newVal */
3350 ' ', /* .sep */ 3346 ' ', /* .sep */
3351 FALSE, /* .oneBigWord */ 3347 FALSE, /* .oneBigWord */
3352 *exprFlags /* .exprFlags */ 3348 *exprFlags /* .exprFlags */
3353 }; 3349 };
3354 const char *p; 3350 const char *p;
3355 const char *mod; 3351 const char *mod;
3356 ApplyModifierResult res; 3352 ApplyModifierResult res;
3357 3353
3358 assert(startc == '(' || startc == '{' || startc == '\0'); 3354 assert(startc == '(' || startc == '{' || startc == '\0');
3359 assert(endc == ')' || endc == '}' || endc == '\0'); 3355 assert(endc == ')' || endc == '}' || endc == '\0');
3360 assert(val != NULL); 3356 assert(val != NULL);
3361 3357
3362 p = *pp; 3358 p = *pp;
3363 while (*p != '\0' && *p != endc) { 3359 while (*p != '\0' && *p != endc) {
3364 3360
3365 if (*p == '$') { 3361 if (*p == '$') {
3366 ApplyModifiersIndirectResult amir; 3362 ApplyModifiersIndirectResult amir;
3367 amir = ApplyModifiersIndirect(&st, &p, out_freeIt); 3363 amir = ApplyModifiersIndirect(&st, &p, out_freeIt);
3368 if (amir == AMIR_CONTINUE) 3364 if (amir == AMIR_CONTINUE)
3369 continue; 3365 continue;
3370 if (amir == AMIR_OUT) 3366 if (amir == AMIR_OUT)
3371 goto out; 3367 goto out;
3372 } 3368 }
3373 st.newVal = var_Error; /* default value, in case of errors */ 3369 st.newVal = var_Error; /* default value, in case of errors */
3374 mod = p; 3370 mod = p;
3375 3371
3376 if (DEBUG(VAR)) 3372 if (DEBUG(VAR))
3377 LogBeforeApply(&st, mod, endc); 3373 LogBeforeApply(&st, mod, endc);
3378 3374
3379 res = ApplyModifier(&p, &st); 3375 res = ApplyModifier(&p, &st);
3380 3376
3381#ifdef SYSVVARSUB 3377#ifdef SYSVVARSUB
3382 if (res == AMR_UNKNOWN) { 3378 if (res == AMR_UNKNOWN) {
3383 assert(p == mod); 3379 assert(p == mod);
3384 res = ApplyModifier_SysV(&p, &st); 3380 res = ApplyModifier_SysV(&p, &st);
3385 } 3381 }
3386#endif 3382#endif
3387 3383
3388 if (res == AMR_UNKNOWN) { 3384 if (res == AMR_UNKNOWN) {
3389 Error("Unknown modifier '%c'", *mod); 3385 Error("Unknown modifier '%c'", *mod);
3390 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++) 3386 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
3391 continue; 3387 continue;
3392 st.newVal = var_Error; 3388 st.newVal = var_Error;
3393 } 3389 }
3394 if (res == AMR_CLEANUP) 3390 if (res == AMR_CLEANUP)
3395 goto cleanup; 3391 goto cleanup;
3396 if (res == AMR_BAD) 3392 if (res == AMR_BAD)
3397 goto bad_modifier; 3393 goto bad_modifier;
3398 3394
3399 if (DEBUG(VAR)) 3395 if (DEBUG(VAR))
3400 LogAfterApply(&st, p, mod); 3396 LogAfterApply(&st, p, mod);
3401 3397
3402 if (st.newVal != st.val) { 3398 if (st.newVal != st.val) {
3403 if (*out_freeIt) { 3399 if (*out_freeIt) {
3404 free(st.val); 3400 free(st.val);
3405 *out_freeIt = NULL; 3401 *out_freeIt = NULL;
3406 } 3402 }
3407 st.val = st.newVal; 3403 st.val = st.newVal;
3408 if (st.val != var_Error && st.val != varUndefined && 3404 if (st.val != var_Error && st.val != varUndefined &&
3409 st.val != emptyString) { 3405 st.val != emptyString) {
3410 *out_freeIt = st.val; 3406 *out_freeIt = st.val;
3411 } 3407 }
3412 } 3408 }
3413 if (*p == '\0' && st.endc != '\0') { 3409 if (*p == '\0' && st.endc != '\0') {
3414 Error("Unclosed variable specification (expecting '%c') " 3410 Error("Unclosed variable specification (expecting '%c') "
3415 "for \"%s\" (value \"%s\") modifier %c", 3411 "for \"%s\" (value \"%s\") modifier %c",
3416 st.endc, st.v->name, st.val, *mod); 3412 st.endc, st.v->name, st.val, *mod);
3417 } else if (*p == ':') { 3413 } else if (*p == ':') {
3418 p++; 3414 p++;
3419 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) { 3415 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) {
3420 Parse_Error(PARSE_FATAL, 3416 Parse_Error(PARSE_FATAL,
3421 "Missing delimiter ':' after modifier \"%.*s\"", 3417 "Missing delimiter ':' after modifier \"%.*s\"",
3422 (int)(p - mod), mod); 3418 (int)(p - mod), mod);
3423 } 3419 }
3424 } 3420 }
3425out: 3421out:
3426 *pp = p; 3422 *pp = p;
3427 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */ 3423 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
3428 *exprFlags = st.exprFlags; 3424 *exprFlags = st.exprFlags;
3429 return st.val; 3425 return st.val;
3430 3426
3431bad_modifier: 3427bad_modifier:
3432 Error("Bad modifier `:%.*s' for %s", 3428 Error("Bad modifier `:%.*s' for %s",
3433 (int)strcspn(mod, ":)}"), mod, st.v->name); 3429 (int)strcspn(mod, ":)}"), mod, st.v->name);
3434 3430
3435cleanup: 3431cleanup:
3436 *pp = p; 3432 *pp = p;
3437 free(*out_freeIt); 3433 free(*out_freeIt);
3438 *out_freeIt = NULL; 3434 *out_freeIt = NULL;
3439 *exprFlags = st.exprFlags; 3435 *exprFlags = st.exprFlags;
3440 return var_Error; 3436 return var_Error;
3441} 3437}
3442 3438
3443/* Only four of the local variables are treated specially as they are the 3439/* Only four of the local variables are treated specially as they are the
3444 * only four that will be set when dynamic sources are expanded. */ 3440 * only four that will be set when dynamic sources are expanded. */
3445static Boolean 3441static Boolean
3446VarnameIsDynamic(const char *name, size_t len) 3442VarnameIsDynamic(const char *name, size_t len)
3447{ 3443{
3448 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) { 3444 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3449 switch (name[0]) { 3445 switch (name[0]) {
3450 case '@': 3446 case '@':
3451 case '%': 3447 case '%':
3452 case '*': 3448 case '*':
3453 case '!': 3449 case '!':
3454 return TRUE; 3450 return TRUE;
3455 } 3451 }
3456 return FALSE; 3452 return FALSE;
3457 } 3453 }
3458 3454
3459 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) { 3455 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3460 return strcmp(name, ".TARGET") == 0 || 3456 return strcmp(name, ".TARGET") == 0 ||
3461 strcmp(name, ".ARCHIVE") == 0 || 3457 strcmp(name, ".ARCHIVE") == 0 ||
3462 strcmp(name, ".PREFIX") == 0 || 3458 strcmp(name, ".PREFIX") == 0 ||
3463 strcmp(name, ".MEMBER") == 0; 3459 strcmp(name, ".MEMBER") == 0;
3464 } 3460 }
3465 3461
3466 return FALSE; 3462 return FALSE;
3467} 3463}
3468 3464
3469static const char * 3465static const char *
3470UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3466UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3471{ 3467{
3472 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3468 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3473 /* 3469 /*
3474 * If substituting a local variable in a non-local context, 3470 * If substituting a local variable in a non-local context,
3475 * assume it's for dynamic source stuff. We have to handle 3471 * assume it's for dynamic source stuff. We have to handle
3476 * this specially and return the longhand for the variable 3472 * this specially and return the longhand for the variable
3477 * with the dollar sign escaped so it makes it back to the 3473 * with the dollar sign escaped so it makes it back to the
3478 * caller. Only four of the local variables are treated 3474 * caller. Only four of the local variables are treated
3479 * specially as they are the only four that will be set 3475 * specially as they are the only four that will be set
3480 * when dynamic sources are expanded. 3476 * when dynamic sources are expanded.
3481 */ 3477 */
3482 switch (varname) { 3478 switch (varname) {
3483 case '@': 3479 case '@':
3484 return "$(.TARGET)"; 3480 return "$(.TARGET)";
3485 case '%': 3481 case '%':
3486 return "$(.MEMBER)"; 3482 return "$(.MEMBER)";
3487 case '*': 3483 case '*':
3488 return "$(.PREFIX)"; 3484 return "$(.PREFIX)";
3489 case '!': 3485 case '!':
3490 return "$(.ARCHIVE)"; 3486 return "$(.ARCHIVE)";
3491 } 3487 }
3492 } 3488 }
3493 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3489 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3494} 3490}
3495 3491
3496/* Parse a variable name, until the end character or a colon, whichever 3492/* Parse a variable name, until the end character or a colon, whichever
3497 * comes first. */ 3493 * comes first. */
3498static char * 3494static char *
3499ParseVarname(const char **pp, char startc, char endc, 3495ParseVarname(const char **pp, char startc, char endc,
3500 GNode *ctxt, VarEvalFlags eflags, 3496 GNode *ctxt, VarEvalFlags eflags,
3501 size_t *out_varname_len) 3497 size_t *out_varname_len)
3502{ 3498{
3503 Buffer buf; 3499 Buffer buf;
3504 const char *p = *pp; 3500 const char *p = *pp;
3505 int depth = 1; 3501 int depth = 1;
3506 3502
3507 Buf_Init(&buf, 0); 3503 Buf_Init(&buf, 0);
3508 3504
3509 while (*p != '\0') { 3505 while (*p != '\0') {
3510 /* Track depth so we can spot parse errors. */ 3506 /* Track depth so we can spot parse errors. */
3511 if (*p == startc) 3507 if (*p == startc)
3512 depth++; 3508 depth++;
3513 if (*p == endc) { 3509 if (*p == endc) {
3514 if (--depth == 0) 3510 if (--depth == 0)
3515 break; 3511 break;
3516 } 3512 }
3517 if (*p == ':' && depth == 1) 3513 if (*p == ':' && depth == 1)
3518 break; 3514 break;
3519 3515
3520 /* A variable inside a variable, expand. */ 3516 /* A variable inside a variable, expand. */
3521 if (*p == '$') { 3517 if (*p == '$') {
3522 void *freeIt; 3518 void *freeIt;
3523 const char *rval; 3519 const char *rval;
3524 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3520 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3525 /* TODO: handle errors */ 3521 /* TODO: handle errors */
3526 Buf_AddStr(&buf, rval); 3522 Buf_AddStr(&buf, rval);
3527 free(freeIt); 3523 free(freeIt);
3528 } else { 3524 } else {
3529 Buf_AddByte(&buf, *p); 3525 Buf_AddByte(&buf, *p);
3530 p++; 3526 p++;
3531 } 3527 }
3532 } 3528 }
3533 *pp = p; 3529 *pp = p;
3534 *out_varname_len = Buf_Len(&buf); 3530 *out_varname_len = Buf_Len(&buf);
3535 return Buf_Destroy(&buf, FALSE); 3531 return Buf_Destroy(&buf, FALSE);
3536} 3532}
3537 3533
3538static Boolean 3534static Boolean
3539ValidShortVarname(char varname, const char *start) 3535ValidShortVarname(char varname, const char *start)
3540{ 3536{
3541 switch (varname) { 3537 switch (varname) {
3542 case '\0': 3538 case '\0':
3543 case ')': 3539 case ')':
3544 case '}': 3540 case '}':
3545 case ':': 3541 case ':':
3546 case '$': 3542 case '$':
3547 break; /* and continue below */ 3543 break; /* and continue below */
3548 default: 3544 default:
3549 return TRUE; 3545 return TRUE;
3550 } 3546 }
3551 3547
3552 if (!DEBUG(LINT)) 3548 if (!DEBUG(LINT))
3553 return FALSE; 3549 return FALSE;
3554 3550
3555 if (varname == '$') 3551 if (varname == '$')
3556 Parse_Error(PARSE_FATAL, 3552 Parse_Error(PARSE_FATAL,
3557 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3553 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3558 else if (varname == '\0') 3554 else if (varname == '\0')
3559 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3555 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3560 else 3556 else
3561 Parse_Error(PARSE_FATAL, 3557 Parse_Error(PARSE_FATAL,
3562 "Invalid variable name '%c', at \"%s\"", varname, start); 3558 "Invalid variable name '%c', at \"%s\"", varname, start);
3563 3559
3564 return FALSE; 3560 return FALSE;
3565} 3561}
3566 3562
3567/* Parse a single-character variable name such as $V or $@. 3563/* Parse a single-character variable name such as $V or $@.
3568 * Return whether to continue parsing. */ 3564 * Return whether to continue parsing. */
3569static Boolean 3565static Boolean
3570ParseVarnameShort( 3566ParseVarnameShort(
3571 char startc, 3567 char startc,
3572 const char **pp, 3568 const char **pp,
3573 GNode *ctxt, 3569 GNode *ctxt,
3574 VarEvalFlags eflags, 3570 VarEvalFlags eflags,
3575 VarParseResult *out_FALSE_res, 3571 VarParseResult *out_FALSE_res,
3576 const char **out_FALSE_val, 3572 const char **out_FALSE_val,
3577 Var **out_TRUE_var 3573 Var **out_TRUE_var
3578) { 3574) {
3579 char name[2]; 3575 char name[2];
3580 Var *v; 3576 Var *v;
3581 3577
3582 /* 3578 /*
3583 * If it's not bounded by braces of some sort, life is much simpler. 3579 * If it's not bounded by braces of some sort, life is much simpler.
3584 * We just need to check for the first character and return the 3580 * We just need to check for the first character and return the
3585 * value if it exists. 3581 * value if it exists.
3586 */ 3582 */
3587 3583
3588 if (!ValidShortVarname(startc, *pp)) { 3584 if (!ValidShortVarname(startc, *pp)) {
3589 (*pp)++; 3585 (*pp)++;
3590 *out_FALSE_val = var_Error; 3586 *out_FALSE_val = var_Error;
3591 *out_FALSE_res = VPR_PARSE_MSG; 3587 *out_FALSE_res = VPR_PARSE_MSG;
3592 return FALSE; 3588 return FALSE;
3593 } 3589 }
3594 3590
3595 name[0] = startc; 3591 name[0] = startc;
3596 name[1] = '\0'; 3592 name[1] = '\0';
3597 v = VarFind(name, ctxt, TRUE); 3593 v = VarFind(name, ctxt, TRUE);
3598 if (v == NULL) { 3594 if (v == NULL) {
3599 *pp += 2; 3595 *pp += 2;
3600 3596
3601 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3597 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3602 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3598 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3603 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3599 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3604 *out_FALSE_res = VPR_UNDEF_MSG; 3600 *out_FALSE_res = VPR_UNDEF_MSG;
3605 return FALSE; 3601 return FALSE;
3606 } 3602 }
3607 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3603 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3608 return FALSE; 3604 return FALSE;
3609 } 3605 }
3610 3606
3611 *out_TRUE_var = v; 3607 *out_TRUE_var = v;
3612 return TRUE; 3608 return TRUE;
3613} 3609}
3614 3610
3615/* Parse a long variable name enclosed in braces or parentheses such as $(VAR) 3611/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3616 * or ${VAR}, up to the closing brace or parenthesis, or in the case of 3612 * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3617 * ${VAR:Modifiers}, up to the ':' that starts the modifiers. 3613 * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3618 * Return whether to continue parsing. */ 3614 * Return whether to continue parsing. */
3619static Boolean 3615static Boolean
3620ParseVarnameLong( 3616ParseVarnameLong(
3621 const char **pp, 3617 const char **pp,
3622 char startc, 3618 char startc,
3623 GNode *ctxt, 3619 GNode *ctxt,
3624 VarEvalFlags eflags, 3620 VarEvalFlags eflags,
3625 3621
3626 VarParseResult *out_FALSE_res, 3622 VarParseResult *out_FALSE_res,
3627 const char **out_FALSE_val, 3623 const char **out_FALSE_val,
3628 void **out_FALSE_freePtr, 3624 void **out_FALSE_freePtr,
3629 3625
3630 char *out_TRUE_endc, 3626 char *out_TRUE_endc,
3631 const char **out_TRUE_p, 3627 const char **out_TRUE_p,
3632 Var **out_TRUE_v, 3628 Var **out_TRUE_v,
3633 Boolean *out_TRUE_haveModifier, 3629 Boolean *out_TRUE_haveModifier,
3634 const char **out_TRUE_extraModifiers, 3630 const char **out_TRUE_extraModifiers,
3635 Boolean *out_TRUE_dynamic, 3631 Boolean *out_TRUE_dynamic,
3636 VarExprFlags *out_TRUE_exprFlags 3632 VarExprFlags *out_TRUE_exprFlags
3637) { 3633) {
3638 size_t namelen; 3634 size_t namelen;
3639 char *varname; 3635 char *varname;
3640 Var *v; 3636 Var *v;
3641 Boolean haveModifier; 3637 Boolean haveModifier;
3642 Boolean dynamic = FALSE; 3638 Boolean dynamic = FALSE;
3643 3639
3644 const char *const start = *pp; 3640 const char *const start = *pp;
3645 char endc = startc == '(' ? ')' : '}'; 3641 char endc = startc == '(' ? ')' : '}';
3646 3642
3647 const char *p = start + 2; 3643 const char *p = start + 2;
3648 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3644 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3649 3645
3650 if (*p == ':') { 3646 if (*p == ':') {
3651 haveModifier = TRUE; 3647 haveModifier = TRUE;
3652 } else if (*p == endc) { 3648 } else if (*p == endc) {
3653 haveModifier = FALSE; 3649 haveModifier = FALSE;
3654 } else { 3650 } else {
3655 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3651 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3656 *pp = p; 3652 *pp = p;
3657 free(varname); 3653 free(varname);
3658 *out_FALSE_val = var_Error; 3654 *out_FALSE_val = var_Error;
3659 *out_FALSE_res = VPR_PARSE_MSG; 3655 *out_FALSE_res = VPR_PARSE_MSG;
3660 return FALSE; 3656 return FALSE;
3661 } 3657 }
3662 3658
3663 v = VarFind(varname, ctxt, TRUE); 3659 v = VarFind(varname, ctxt, TRUE);
3664 3660
3665 /* At this point, p points just after the variable name, 3661 /* At this point, p points just after the variable name,
3666 * either at ':' or at endc. */ 3662 * either at ':' or at endc. */
3667 3663
3668 /* 3664 /*
3669 * Check also for bogus D and F forms of local variables since we're 3665 * Check also for bogus D and F forms of local variables since we're
3670 * in a local context and the name is the right length. 3666 * in a local context and the name is the right length.
3671 */ 3667 */
3672 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3668 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3673 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3669 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3674 strchr("@%?*!<>", varname[0]) != NULL) 3670 strchr("@%?*!<>", varname[0]) != NULL)
3675 { 3671 {
3676 /* 3672 /*
3677 * Well, it's local -- go look for it. 3673 * Well, it's local -- go look for it.
3678 */ 3674 */
3679 char name[] = { varname[0], '\0' }; 3675 char name[] = { varname[0], '\0' };
3680 v = VarFind(name, ctxt, 0); 3676 v = VarFind(name, ctxt, 0);
3681 3677
3682 if (v != NULL) { 3678 if (v != NULL) {
3683 if (varname[1] == 'D') { 3679 if (varname[1] == 'D') {
3684 *out_TRUE_extraModifiers = "H:"; 3680 *out_TRUE_extraModifiers = "H:";
3685 } else { /* F */ 3681 } else { /* F */
3686 *out_TRUE_extraModifiers = "T:"; 3682 *out_TRUE_extraModifiers = "T:";
3687 } 3683 }
3688 } 3684 }
3689 } 3685 }
3690 3686
3691 if (v == NULL) { 3687 if (v == NULL) {
3692 /* Defer expansion of dynamic variables if they appear in non-local 3688 /* Defer expansion of dynamic variables if they appear in non-local
3693 * context since they are not defined there. */ 3689 * context since they are not defined there. */
3694 dynamic = VarnameIsDynamic(varname, namelen) && 3690 dynamic = VarnameIsDynamic(varname, namelen) &&
3695 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL); 3691 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
3696 3692
3697 if (!haveModifier) { 3693 if (!haveModifier) {
3698 p++; /* skip endc */ 3694 p++; /* skip endc */
3699 *pp = p; 3695 *pp = p;
3700 if (dynamic) { 3696 if (dynamic) {
3701 char *pstr = bmake_strsedup(start, p); 3697 char *pstr = bmake_strsedup(start, p);
3702 free(varname); 3698 free(varname);
3703 *out_FALSE_res = VPR_OK; 3699 *out_FALSE_res = VPR_OK;
3704 *out_FALSE_freePtr = pstr; 3700 *out_FALSE_freePtr = pstr;
3705 *out_FALSE_val = pstr; 3701 *out_FALSE_val = pstr;
3706 return FALSE; 3702 return FALSE;
3707 } 3703 }
3708 3704
3709 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3705 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3710 DEBUG(LINT)) 3706 DEBUG(LINT))
3711 { 3707 {
3712 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3708 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3713 varname); 3709 varname);
3714 free(varname); 3710 free(varname);
3715 *out_FALSE_res = VPR_UNDEF_MSG; 3711 *out_FALSE_res = VPR_UNDEF_MSG;
3716 *out_FALSE_val = var_Error; 3712 *out_FALSE_val = var_Error;
3717 return FALSE; 3713 return FALSE;
3718 } 3714 }
3719 3715
3720 if (eflags & VARE_UNDEFERR) { 3716 if (eflags & VARE_UNDEFERR) {
3721 free(varname); 3717 free(varname);
3722 *out_FALSE_res = VPR_UNDEF_SILENT; 3718 *out_FALSE_res = VPR_UNDEF_SILENT;
3723 *out_FALSE_val = var_Error; 3719 *out_FALSE_val = var_Error;
3724 return FALSE; 3720 return FALSE;
3725 } 3721 }
3726 3722
3727 free(varname); 3723 free(varname);
3728 *out_FALSE_res = VPR_OK; 3724 *out_FALSE_res = VPR_OK;
3729 *out_FALSE_val = varUndefined; 3725 *out_FALSE_val = varUndefined;
3730 return FALSE; 3726 return FALSE;
3731 } 3727 }
3732 3728
3733 /* The variable expression is based on an undefined variable. 3729 /* The variable expression is based on an undefined variable.
3734 * Nevertheless it needs a Var, for modifiers that access the 3730 * Nevertheless it needs a Var, for modifiers that access the
3735 * variable name, such as :L or :?. 3731 * variable name, such as :L or :?.
3736 * 3732 *
3737 * Most modifiers leave this expression in the "undefined" state 3733 * Most modifiers leave this expression in the "undefined" state
3738 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3734 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3739 * undefined expression into a defined expression (VEF_DEF). 3735 * undefined expression into a defined expression (VEF_DEF).
3740 * 3736 *
3741 * At the end, after applying all modifiers, if the expression 3737 * At the end, after applying all modifiers, if the expression
3742 * is still undefined, Var_Parse will return an empty string 3738 * is still undefined, Var_Parse will return an empty string
3743 * instead of the actually computed value. */ 3739 * instead of the actually computed value. */
3744 v = VarNew(varname, varname, "", 0); 3740 v = VarNew(varname, varname, "", 0);
3745 *out_TRUE_exprFlags = VEF_UNDEF; 3741 *out_TRUE_exprFlags = VEF_UNDEF;
3746 } else 3742 } else
3747 free(varname); 3743 free(varname);
3748 3744
3749 *out_TRUE_endc = endc; 3745 *out_TRUE_endc = endc;
3750 *out_TRUE_p = p; 3746 *out_TRUE_p = p;
3751 *out_TRUE_v = v; 3747 *out_TRUE_v = v;
3752 *out_TRUE_haveModifier = haveModifier; 3748 *out_TRUE_haveModifier = haveModifier;
3753 *out_TRUE_dynamic = dynamic; 3749 *out_TRUE_dynamic = dynamic;
3754 return TRUE; 3750 return TRUE;
3755} 3751}
3756 3752
3757/*- 3753/*-
3758 *----------------------------------------------------------------------- 3754 *-----------------------------------------------------------------------
3759 * Var_Parse -- 3755 * Var_Parse --
3760 * Given the start of a variable expression (such as $v, $(VAR), 3756 * Given the start of a variable expression (such as $v, $(VAR),
3761 * ${VAR:Mpattern}), extract the variable name, possibly some 3757 * ${VAR:Mpattern}), extract the variable name, possibly some
3762 * modifiers and find its value by applying the modifiers to the 3758 * modifiers and find its value by applying the modifiers to the
3763 * original value. 3759 * original value.
3764 * 3760 *
3765 * When parsing a condition in ParseEmptyArg, pp may also point to 3761 * When parsing a condition in ParseEmptyArg, pp may also point to
3766 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3762 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3767 * identical. 3763 * identical.
3768 * 3764 *
3769 * Input: 3765 * Input:
3770 * str The string to parse 3766 * str The string to parse
3771 * ctxt The context for the variable 3767 * ctxt The context for the variable
3772 * flags Select the exact details of parsing 3768 * flags Select the exact details of parsing
3773 * out_val_freeIt Must be freed by the caller after using out_val 3769 * out_val_freeIt Must be freed by the caller after using out_val
3774 * 3770 *
3775 * Results: 3771 * Results:
3776 * Returns the value of the variable expression, never NULL. 3772 * Returns the value of the variable expression, never NULL.
3777 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3773 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3778 * set. 3774 * set.
3779 * Returns varUndefined if there was an undefined variable and 3775 * Returns varUndefined if there was an undefined variable and
3780 * VARE_UNDEFERR was not set. 3776 * VARE_UNDEFERR was not set.
3781 * 3777 *
3782 * Parsing should continue at *pp. 3778 * Parsing should continue at *pp.
3783 * TODO: Document the value of *pp on parse errors. It might be advanced 3779 * TODO: Document the value of *pp on parse errors. It might be advanced
3784 * by 0, or +1, or the index of the parse error, or the guessed end of the 3780 * by 0, or +1, or the index of the parse error, or the guessed end of the
3785 * variable expression. 3781 * variable expression.
3786 * 3782 *
3787 * If var_Error is returned, a diagnostic may or may not have been 3783 * If var_Error is returned, a diagnostic may or may not have been
3788 * printed. XXX: This is inconsistent. 3784 * printed. XXX: This is inconsistent.
3789 * 3785 *
3790 * If varUndefined is returned, a diagnostic may or may not have been 3786 * If varUndefined is returned, a diagnostic may or may not have been
3791 * printed. XXX: This is inconsistent. 3787 * printed. XXX: This is inconsistent.
3792 * 3788 *
3793 * After using the returned value, *out_val_freeIt must be freed, 3789 * After using the returned value, *out_val_freeIt must be freed,
3794 * preferably using bmake_free since it is NULL in most cases. 3790 * preferably using bmake_free since it is NULL in most cases.
3795 * 3791 *
3796 * Side Effects: 3792 * Side Effects:
3797 * Any effects from the modifiers, such as :!cmd! or ::=value. 3793 * Any effects from the modifiers, such as :!cmd! or ::=value.
3798 *----------------------------------------------------------------------- 3794 *-----------------------------------------------------------------------
3799 */ 3795 */
3800/* coverity[+alloc : arg-*4] */ 3796/* coverity[+alloc : arg-*4] */
3801VarParseResult 3797VarParseResult
3802Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3798Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3803 const char **out_val, void **out_val_freeIt) 3799 const char **out_val, void **out_val_freeIt)
3804{ 3800{
3805 const char *const start = *pp; 3801 const char *const start = *pp;
3806 const char *p; 3802 const char *p;
3807 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3803 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3808 char startc; /* Starting character if variable in parens 3804 char startc; /* Starting character if variable in parens
3809 * or braces */ 3805 * or braces */
3810 char endc; /* Ending character if variable in parens 3806 char endc; /* Ending character if variable in parens
3811 * or braces */ 3807 * or braces */
3812 Boolean dynamic; /* TRUE if the variable is local and we're 3808 Boolean dynamic; /* TRUE if the variable is local and we're
3813 * expanding it in a non-local context. This 3809 * expanding it in a non-local context. This
3814 * is done to support dynamic sources. The 3810 * is done to support dynamic sources. The
3815 * result is just the expression, unaltered */ 3811 * result is just the expression, unaltered */
3816 const char *extramodifiers; 3812 const char *extramodifiers;
3817 Var *v; 3813 Var *v;
3818 char *nstr; 3814 char *nstr;
3819 char eflags_str[VarEvalFlags_ToStringSize]; 3815 char eflags_str[VarEvalFlags_ToStringSize];
3820 VarExprFlags exprFlags = 0; 3816 VarExprFlags exprFlags = 0;
3821 3817
3822 VAR_DEBUG2("Var_Parse: %s with %s\n", start, 3818 VAR_DEBUG2("Var_Parse: %s with %s\n", start,
3823 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3819 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3824 VarEvalFlags_ToStringSpecs)); 3820 VarEvalFlags_ToStringSpecs));
3825 3821
3826 *out_val_freeIt = NULL; 3822 *out_val_freeIt = NULL;
3827 extramodifiers = NULL; /* extra modifiers to apply first */ 3823 extramodifiers = NULL; /* extra modifiers to apply first */
3828 dynamic = FALSE; 3824 dynamic = FALSE;
3829 3825
3830 /* Appease GCC, which thinks that the variable might not be 3826 /* Appease GCC, which thinks that the variable might not be
3831 * initialized. */ 3827 * initialized. */
3832 endc = '\0'; 3828 endc = '\0';
3833 3829
3834 startc = start[1]; 3830 startc = start[1];
3835 if (startc != '(' && startc != '{') { 3831 if (startc != '(' && startc != '{') {
3836 VarParseResult res; 3832 VarParseResult res;
3837 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v)) 3833 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v))
3838 return res; 3834 return res;
3839 haveModifier = FALSE; 3835 haveModifier = FALSE;
3840 p = start + 1; 3836 p = start + 1;
3841 } else { 3837 } else {
3842 VarParseResult res; 3838 VarParseResult res;
3843 if (!ParseVarnameLong(pp, startc, ctxt, eflags, 3839 if (!ParseVarnameLong(pp, startc, ctxt, eflags,
3844 &res, out_val, out_val_freeIt, 3840 &res, out_val, out_val_freeIt,
3845 &endc, &p, &v, &haveModifier, &extramodifiers, 3841 &endc, &p, &v, &haveModifier, &extramodifiers,
3846 &dynamic, &exprFlags)) 3842 &dynamic, &exprFlags))
3847 return res; 3843 return res;
3848 } 3844 }
3849 3845
3850 if (v->flags & VAR_IN_USE) 3846 if (v->flags & VAR_IN_USE)
3851 Fatal("Variable %s is recursive.", v->name); 3847 Fatal("Variable %s is recursive.", v->name);
3852 3848
3853 /* 3849 /*
3854 * Before doing any modification, we have to make sure the value 3850 * Before doing any modification, we have to make sure the value
3855 * has been fully expanded. If it looks like recursion might be 3851 * has been fully expanded. If it looks like recursion might be
3856 * necessary (there's a dollar sign somewhere in the variable's value) 3852 * necessary (there's a dollar sign somewhere in the variable's value)
3857 * we just call Var_Subst to do any other substitutions that are 3853 * we just call Var_Subst to do any other substitutions that are
3858 * necessary. Note that the value returned by Var_Subst will have 3854 * necessary. Note that the value returned by Var_Subst will have
3859 * been dynamically-allocated, so it will need freeing when we 3855 * been dynamically-allocated, so it will need freeing when we
3860 * return. 3856 * return.
3861 */ 3857 */
3862 nstr = Buf_GetAll(&v->val, NULL); 3858 nstr = Buf_GetAll(&v->val, NULL);
3863 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) { 3859 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) {
3864 VarEvalFlags nested_eflags = eflags; 3860 VarEvalFlags nested_eflags = eflags;
3865 if (DEBUG(LINT)) 3861 if (DEBUG(LINT))
3866 nested_eflags &= ~(unsigned)VARE_UNDEFERR; 3862 nested_eflags &= ~(unsigned)VARE_UNDEFERR;
3867 v->flags |= VAR_IN_USE; 3863 v->flags |= VAR_IN_USE;
3868 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr); 3864 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr);
3869 v->flags &= ~(unsigned)VAR_IN_USE; 3865 v->flags &= ~(unsigned)VAR_IN_USE;
3870 /* TODO: handle errors */ 3866 /* TODO: handle errors */
3871 *out_val_freeIt = nstr; 3867 *out_val_freeIt = nstr;
3872 } 3868 }
3873 3869
3874 if (haveModifier || extramodifiers != NULL) { 3870 if (haveModifier || extramodifiers != NULL) {
3875 void *extraFree; 3871 void *extraFree;
3876 3872
3877 extraFree = NULL; 3873 extraFree = NULL;
3878 if (extramodifiers != NULL) { 3874 if (extramodifiers != NULL) {
3879 const char *em = extramodifiers; 3875 const char *em = extramodifiers;
3880 nstr = ApplyModifiers(&em, nstr, '(', ')', 3876 nstr = ApplyModifiers(&em, nstr, '(', ')',
3881 v, &exprFlags, ctxt, eflags, &extraFree); 3877 v, &exprFlags, ctxt, eflags, &extraFree);
3882 } 3878 }
3883 3879
3884 if (haveModifier) { 3880 if (haveModifier) {
3885 /* Skip initial colon. */ 3881 /* Skip initial colon. */
3886 p++; 3882 p++;
3887 3883
3888 nstr = ApplyModifiers(&p, nstr, startc, endc, 3884 nstr = ApplyModifiers(&p, nstr, startc, endc,
3889 v, &exprFlags, ctxt, eflags, out_val_freeIt); 3885 v, &exprFlags, ctxt, eflags, out_val_freeIt);
3890 free(extraFree); 3886 free(extraFree);
3891 } else { 3887 } else {
3892 *out_val_freeIt = extraFree; 3888 *out_val_freeIt = extraFree;
3893 } 3889 }
3894 } 3890 }
3895 3891
3896 if (*p != '\0') /* Skip past endc if possible. */ 3892 if (*p != '\0') /* Skip past endc if possible. */
3897 p++; 3893 p++;
3898 3894
3899 *pp = p; 3895 *pp = p;
3900 3896
3901 if (v->flags & VAR_FROM_ENV) { 3897 if (v->flags & VAR_FROM_ENV) {
3902 /* Free the environment variable now since we own it, 3898 /* Free the environment variable now since we own it,
3903 * but don't free the variable value if it will be returned. */ 3899 * but don't free the variable value if it will be returned. */
3904 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL); 3900 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL);
3905 if (keepValue) 3901 if (keepValue)
3906 *out_val_freeIt = nstr; 3902 *out_val_freeIt = nstr;
3907 (void)VarFreeEnv(v, !keepValue); 3903 (void)VarFreeEnv(v, !keepValue);
3908 3904
3909 } else if (exprFlags & VEF_UNDEF) { 3905 } else if (exprFlags & VEF_UNDEF) {
3910 if (!(exprFlags & VEF_DEF)) { 3906 if (!(exprFlags & VEF_DEF)) {
3911 if (*out_val_freeIt != NULL) { 3907 if (*out_val_freeIt != NULL) {
3912 free(*out_val_freeIt); 3908 free(*out_val_freeIt);
3913 *out_val_freeIt = NULL; 3909 *out_val_freeIt = NULL;
3914 } 3910 }
3915 if (dynamic) { 3911 if (dynamic) {
3916 nstr = bmake_strsedup(start, p); 3912 nstr = bmake_strsedup(start, p);
3917 *out_val_freeIt = nstr; 3913 *out_val_freeIt = nstr;
3918 } else { 3914 } else {
3919 /* The expression is still undefined, therefore discard the 3915 /* The expression is still undefined, therefore discard the
3920 * actual value and return an error marker instead. */ 3916 * actual value and return an error marker instead. */
3921 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined; 3917 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined;
3922 } 3918 }
3923 } 3919 }
3924 if (nstr != Buf_GetAll(&v->val, NULL)) 3920 if (nstr != Buf_GetAll(&v->val, NULL))
3925 Buf_Destroy(&v->val, TRUE); 3921 Buf_Destroy(&v->val, TRUE);
3926 free(v->name_freeIt); 3922 free(v->name_freeIt);
3927 free(v); 3923 free(v);
3928 } 3924 }
3929 *out_val = nstr; 3925 *out_val = nstr;
3930 return VPR_UNKNOWN; 3926 return VPR_UNKNOWN;
3931} 3927}
3932 3928
3933/* Substitute for all variables in the given string in the given context. 3929/* Substitute for all variables in the given string in the given context.
3934 * 3930 *
3935 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3931 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3936 * variable is encountered. 3932 * variable is encountered.
3937 * 3933 *
3938 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=, 3934 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=,
3939 * :sh or !cmd! take place. 3935 * :sh or !cmd! take place.
3940 * 3936 *
3941 * Input: 3937 * Input:
3942 * str the string which to substitute 3938 * str the string which to substitute
3943 * ctxt the context wherein to find variables 3939 * ctxt the context wherein to find variables
3944 * eflags VARE_UNDEFERR if undefineds are an error 3940 * eflags VARE_UNDEFERR if undefineds are an error
3945 * VARE_WANTRES if we actually want the result 3941 * VARE_WANTRES if we actually want the result
3946 * VARE_ASSIGN if we are in a := assignment 3942 * VARE_ASSIGN if we are in a := assignment
3947 * 3943 *
3948 * Results: 3944 * Results:
3949 * The resulting string. 3945 * The resulting string.
3950 */ 3946 */
3951VarParseResult 3947VarParseResult
3952Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res) 3948Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
3953{ 3949{
3954 const char *p = str; 3950 const char *p = str;
3955 Buffer buf; /* Buffer for forming things */ 3951 Buffer buf; /* Buffer for forming things */
3956 3952
3957 /* Set true if an error has already been reported, 3953 /* Set true if an error has already been reported,
3958 * to prevent a plethora of messages when recursing */ 3954 * to prevent a plethora of messages when recursing */
3959 static Boolean errorReported; 3955 static Boolean errorReported;
3960 3956
3961 Buf_Init(&buf, 0); 3957 Buf_Init(&buf, 0);
3962 errorReported = FALSE; 3958 errorReported = FALSE;
3963 3959
3964 while (*p != '\0') { 3960 while (*p != '\0') {
3965 if (p[0] == '$' && p[1] == '$') { 3961 if (p[0] == '$' && p[1] == '$') {
3966 /* A dollar sign may be escaped with another dollar sign. */ 3962 /* A dollar sign may be escaped with another dollar sign. */
3967 if (save_dollars && (eflags & VARE_ASSIGN)) 3963 if (save_dollars && (eflags & VARE_ASSIGN))
3968 Buf_AddByte(&buf, '$'); 3964 Buf_AddByte(&buf, '$');
3969 Buf_AddByte(&buf, '$'); 3965 Buf_AddByte(&buf, '$');
3970 p += 2; 3966 p += 2;
3971 } else if (*p != '$') { 3967 } else if (*p != '$') {
3972 /* 3968 /*
3973 * Skip as many characters as possible -- either to the end of 3969 * Skip as many characters as possible -- either to the end of
3974 * the string or to the next dollar sign (variable expression). 3970 * the string or to the next dollar sign (variable expression).
3975 */ 3971 */
3976 const char *plainStart = p; 3972 const char *plainStart = p;
3977 3973
3978 for (p++; *p != '$' && *p != '\0'; p++) 3974 for (p++; *p != '$' && *p != '\0'; p++)
3979 continue; 3975 continue;
3980 Buf_AddBytesBetween(&buf, plainStart, p); 3976 Buf_AddBytesBetween(&buf, plainStart, p);
3981 } else { 3977 } else {
3982 const char *nested_p = p; 3978 const char *nested_p = p;
3983 void *freeIt; 3979 void *freeIt;
3984 const char *val; 3980 const char *val;
3985 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt); 3981 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt);
3986 /* TODO: handle errors */ 3982 /* TODO: handle errors */
3987 3983
3988 if (val == var_Error || val == varUndefined) { 3984 if (val == var_Error || val == varUndefined) {
3989 /* 3985 /*
3990 * If performing old-time variable substitution, skip over 3986 * If performing old-time variable substitution, skip over
3991 * the variable and continue with the substitution. Otherwise, 3987 * the variable and continue with the substitution. Otherwise,
3992 * store the dollar sign and advance str so we continue with 3988 * store the dollar sign and advance str so we continue with
3993 * the string... 3989 * the string...
3994 */ 3990 */
3995 if (oldVars) { 3991 if (oldVars) {
3996 p = nested_p; 3992 p = nested_p;
3997 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 3993 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
3998 /* 3994 /*
3999 * If variable is undefined, complain and skip the 3995 * If variable is undefined, complain and skip the
4000 * variable. The complaint will stop us from doing anything 3996 * variable. The complaint will stop us from doing anything
4001 * when the file is parsed. 3997 * when the file is parsed.
4002 */ 3998 */
4003 if (!errorReported) { 3999 if (!errorReported) {
4004 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 4000 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
4005 (int)(size_t)(nested_p - p), p); 4001 (int)(size_t)(nested_p - p), p);
4006 } 4002 }
4007 p = nested_p; 4003 p = nested_p;
4008 errorReported = TRUE; 4004 errorReported = TRUE;
4009 } else { 4005 } else {
4010 /* Copy the initial '$' of the undefined expression, 4006 /* Copy the initial '$' of the undefined expression,
4011 * thereby deferring expansion of the expression, but 4007 * thereby deferring expansion of the expression, but
4012 * expand nested expressions if already possible. 4008 * expand nested expressions if already possible.
4013 * See unit-tests/varparse-undef-partial.mk. */ 4009 * See unit-tests/varparse-undef-partial.mk. */
4014 Buf_AddByte(&buf, *p); 4010 Buf_AddByte(&buf, *p);
4015 p++; 4011 p++;
4016 } 4012 }
4017 } else { 4013 } else {
4018 p = nested_p; 4014 p = nested_p;
4019 Buf_AddStr(&buf, val); 4015 Buf_AddStr(&buf, val);
4020 } 4016 }
4021 free(freeIt); 4017 free(freeIt);
4022 freeIt = NULL; 4018 freeIt = NULL;
4023 } 4019 }
4024 } 4020 }
4025 4021
4026 *out_res = Buf_DestroyCompact(&buf); 4022 *out_res = Buf_DestroyCompact(&buf);
4027 return VPR_OK; 4023 return VPR_OK;
4028} 4024}
4029 4025
4030/* Initialize the variables module. */ 4026/* Initialize the variables module. */
4031void 4027void
4032Var_Init(void) 4028Var_Init(void)
4033{ 4029{
4034 VAR_INTERNAL = Targ_NewGN("Internal"); 4030 VAR_INTERNAL = Targ_NewGN("Internal");
4035 VAR_GLOBAL = Targ_NewGN("Global"); 4031 VAR_GLOBAL = Targ_NewGN("Global");
4036 VAR_CMDLINE = Targ_NewGN("Command"); 4032 VAR_CMDLINE = Targ_NewGN("Command");
4037} 4033}
4038 4034
4039/* Clean up the variables module. */ 4035/* Clean up the variables module. */
4040void 4036void
4041Var_End(void) 4037Var_End(void)
4042{ 4038{
4043 Var_Stats(); 4039 Var_Stats();
4044} 4040}
4045 4041
4046void 4042void
4047Var_Stats(void) 4043Var_Stats(void)
4048{ 4044{
4049 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 4045 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
4050} 4046}
4051 4047
4052/* Print all variables in a context, sorted by name. */ 4048/* Print all variables in a context, sorted by name. */
4053void 4049void
4054Var_Dump(GNode *ctxt) 4050Var_Dump(GNode *ctxt)
4055{ 4051{
4056 Vector /* of const char * */ vec; 4052 Vector /* of const char * */ vec;
4057 HashIter hi; 4053 HashIter hi;
4058 size_t i; 4054 size_t i;
4059 const char **varnames; 4055 const char **varnames;
4060 4056
4061 Vector_Init(&vec, sizeof(const char *)); 4057 Vector_Init(&vec, sizeof(const char *));
4062 4058
4063 HashIter_Init(&hi, &ctxt->context); 4059 HashIter_Init(&hi, &ctxt->context);
4064 while (HashIter_Next(&hi) != NULL) 4060 while (HashIter_Next(&hi) != NULL)
4065 *(const char **)Vector_Push(&vec) = hi.entry->key; 4061 *(const char **)Vector_Push(&vec) = hi.entry->key;
4066 varnames = vec.items; 4062 varnames = vec.items;
4067 4063
4068 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc); 4064 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
4069 4065
4070 for (i = 0; i < vec.len; i++) { 4066 for (i = 0; i < vec.len; i++) {
4071 const char *varname = varnames[i]; 4067 const char *varname = varnames[i];
4072 Var *var = HashTable_FindValue(&ctxt->context, varname); 4068 Var *var = HashTable_FindValue(&ctxt->context, varname);
4073 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL)); 4069 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
4074 } 4070 }
4075 4071
4076 Vector_Done(&vec); 4072 Vector_Done(&vec);
4077} 4073}