Mon Nov 2 21:15:00 2020 UTC ()
make(1): document that skipping a modifier on parse errors is risky


(rillig)
diff -r1.649 -r1.650 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/11/02 20:48:36 1.649
+++ src/usr.bin/make/var.c 2020/11/02 21:15:00 1.650
@@ -1,1132 +1,1132 @@ @@ -1,1132 +1,1132 @@
1/* $NetBSD: var.c,v 1.649 2020/11/02 20:48:36 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.650 2020/11/02 21:15:00 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.649 2020/11/02 20:48:36 rillig Exp $"); 133MAKE_RCSID("$NetBSD: var.c,v 1.650 2020/11/02 21:15:00 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)
@@ -2395,1688 +2395,1691 @@ ApplyModifier_Match(const char **pp, App @@ -2395,1688 +2395,1691 @@ ApplyModifier_Match(const char **pp, App
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 such as in ${VAR:${M_indirect}}. */ 3267 * modifiers such as in ${VAR:${M_indirect}}. */
3268static ApplyModifiersIndirectResult 3268static ApplyModifiersIndirectResult
3269ApplyModifiersIndirect( 3269ApplyModifiersIndirect(
3270 ApplyModifiersState *const st, 3270 ApplyModifiersState *const st,
3271 const char **const inout_p, 3271 const char **const 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 *mods; 3275 const char *mods;
3276 void *mods_freeIt; 3276 void *mods_freeIt;
3277 3277
3278 (void)Var_Parse(&p, st->ctxt, st->eflags, &mods, &mods_freeIt); 3278 (void)Var_Parse(&p, st->ctxt, st->eflags, &mods, &mods_freeIt);
3279 /* TODO: handle errors */ 3279 /* TODO: handle errors */
3280 3280
3281 /* 3281 /*
3282 * 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
3283 * interested. This means the expression ${VAR:${M_1}${M_2}} 3283 * interested. This means the expression ${VAR:${M_1}${M_2}}
3284 * is not accepted, but ${VAR:${M_1}:${M_2}} is. 3284 * is not accepted, but ${VAR:${M_1}:${M_2}} is.
3285 */ 3285 */
3286 if (mods[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) { 3286 if (mods[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
3287 if (DEBUG(LINT)) 3287 if (DEBUG(LINT))
3288 Parse_Error(PARSE_FATAL, 3288 Parse_Error(PARSE_FATAL,
3289 "Missing delimiter ':' after indirect modifier \"%.*s\"", 3289 "Missing delimiter ':' after indirect modifier \"%.*s\"",
3290 (int)(p - *inout_p), *inout_p); 3290 (int)(p - *inout_p), *inout_p);
3291 3291
3292 free(mods_freeIt); 3292 free(mods_freeIt);
3293 /* XXX: apply_mods doesn't sound like "not interested". */ 3293 /* XXX: apply_mods doesn't sound like "not interested". */
3294 /* XXX: Why is the indirect modifier parsed once more by 3294 /* XXX: Why is the indirect modifier parsed once more by
3295 * apply_mods? If any, p should be advanced to nested_p. */ 3295 * apply_mods? If any, p should be advanced to nested_p. */
3296 return AMIR_APPLY_MODS; 3296 return AMIR_APPLY_MODS;
3297 } 3297 }
3298 3298
3299 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", 3299 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
3300 mods, (int)(p - *inout_p), *inout_p); 3300 mods, (int)(p - *inout_p), *inout_p);
3301 3301
3302 if (mods[0] != '\0') { 3302 if (mods[0] != '\0') {
3303 const char *rval_pp = mods; 3303 const char *rval_pp = mods;
3304 st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v, 3304 st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v,
3305 &st->exprFlags, st->ctxt, st->eflags, 3305 &st->exprFlags, st->ctxt, st->eflags,
3306 out_freeIt); 3306 out_freeIt);
3307 if (st->val == var_Error 3307 if (st->val == var_Error
3308 || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR)) 3308 || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR))
3309 || *rval_pp != '\0') { 3309 || *rval_pp != '\0') {
3310 free(mods_freeIt); 3310 free(mods_freeIt);
3311 *inout_p = p; 3311 *inout_p = p;
3312 return AMIR_OUT; /* error already reported */ 3312 return AMIR_OUT; /* error already reported */
3313 } 3313 }
3314 } 3314 }
3315 free(mods_freeIt); 3315 free(mods_freeIt);
3316 3316
3317 if (*p == ':') 3317 if (*p == ':')
3318 p++; 3318 p++;
3319 else if (*p == '\0' && st->endc != '\0') { 3319 else if (*p == '\0' && st->endc != '\0') {
3320 Error("Unclosed variable specification after complex " 3320 Error("Unclosed variable specification after complex "
3321 "modifier (expecting '%c') for %s", st->endc, st->v->name); 3321 "modifier (expecting '%c') for %s", st->endc, st->v->name);
3322 *inout_p = p; 3322 *inout_p = p;
3323 return AMIR_OUT; 3323 return AMIR_OUT;
3324 } 3324 }
3325 3325
3326 *inout_p = p; 3326 *inout_p = p;
3327 return AMIR_CONTINUE; 3327 return AMIR_CONTINUE;
3328} 3328}
3329 3329
3330/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ 3330/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3331static char * 3331static char *
3332ApplyModifiers( 3332ApplyModifiers(
3333 const char **const pp, /* the parsing position, updated upon return */ 3333 const char **const pp, /* the parsing position, updated upon return */
3334 char *const val, /* the current value of the expression */ 3334 char *const val, /* the current value of the expression */
3335 char const startc, /* '(' or '{', or '\0' for indirect modifiers */ 3335 char const startc, /* '(' or '{', or '\0' for indirect modifiers */
3336 char const endc, /* ')' or '}', or '\0' for indirect modifiers */ 3336 char const endc, /* ')' or '}', or '\0' for indirect modifiers */
3337 Var *const v, 3337 Var *const v,
3338 VarExprFlags *const exprFlags, 3338 VarExprFlags *const exprFlags,
3339 GNode *const ctxt, /* for looking up and modifying variables */ 3339 GNode *const ctxt, /* for looking up and modifying variables */
3340 VarEvalFlags const eflags, 3340 VarEvalFlags const eflags,
3341 void **const out_freeIt /* free this after using the return value */ 3341 void **const out_freeIt /* free this after using the return value */
3342) { 3342) {
3343 ApplyModifiersState st = { 3343 ApplyModifiersState st = {
3344 startc, endc, v, ctxt, eflags, 3344 startc, endc, v, ctxt, eflags,
3345 val, /* .val */ 3345 val, /* .val */
3346 var_Error, /* .newVal */ 3346 var_Error, /* .newVal */
3347 ' ', /* .sep */ 3347 ' ', /* .sep */
3348 FALSE, /* .oneBigWord */ 3348 FALSE, /* .oneBigWord */
3349 *exprFlags /* .exprFlags */ 3349 *exprFlags /* .exprFlags */
3350 }; 3350 };
3351 const char *p; 3351 const char *p;
3352 const char *mod; 3352 const char *mod;
3353 ApplyModifierResult res; 3353 ApplyModifierResult res;
3354 3354
3355 assert(startc == '(' || startc == '{' || startc == '\0'); 3355 assert(startc == '(' || startc == '{' || startc == '\0');
3356 assert(endc == ')' || endc == '}' || endc == '\0'); 3356 assert(endc == ')' || endc == '}' || endc == '\0');
3357 assert(val != NULL); 3357 assert(val != NULL);
3358 3358
3359 p = *pp; 3359 p = *pp;
3360 3360
3361 if (*p == '\0' && endc != '\0') { 3361 if (*p == '\0' && endc != '\0') {
3362 Error("Unclosed variable expression (expecting '%c') for \"%s\"", 3362 Error("Unclosed variable expression (expecting '%c') for \"%s\"",
3363 st.endc, st.v->name); 3363 st.endc, st.v->name);
3364 goto cleanup; 3364 goto cleanup;
3365 } 3365 }
3366 3366
3367 while (*p != '\0' && *p != endc) { 3367 while (*p != '\0' && *p != endc) {
3368 3368
3369 if (*p == '$') { 3369 if (*p == '$') {
3370 ApplyModifiersIndirectResult amir; 3370 ApplyModifiersIndirectResult amir;
3371 amir = ApplyModifiersIndirect(&st, &p, out_freeIt); 3371 amir = ApplyModifiersIndirect(&st, &p, out_freeIt);
3372 if (amir == AMIR_CONTINUE) 3372 if (amir == AMIR_CONTINUE)
3373 continue; 3373 continue;
3374 if (amir == AMIR_OUT) 3374 if (amir == AMIR_OUT)
3375 goto out; 3375 goto out;
3376 } 3376 }
3377 st.newVal = var_Error; /* default value, in case of errors */ 3377 st.newVal = var_Error; /* default value, in case of errors */
3378 mod = p; 3378 mod = p;
3379 3379
3380 if (DEBUG(VAR)) 3380 if (DEBUG(VAR))
3381 LogBeforeApply(&st, mod, endc); 3381 LogBeforeApply(&st, mod, endc);
3382 3382
3383 res = ApplyModifier(&p, &st); 3383 res = ApplyModifier(&p, &st);
3384 3384
3385#ifdef SYSVVARSUB 3385#ifdef SYSVVARSUB
3386 if (res == AMR_UNKNOWN) { 3386 if (res == AMR_UNKNOWN) {
3387 assert(p == mod); 3387 assert(p == mod);
3388 res = ApplyModifier_SysV(&p, &st); 3388 res = ApplyModifier_SysV(&p, &st);
3389 } 3389 }
3390#endif 3390#endif
3391 3391
3392 if (res == AMR_UNKNOWN) { 3392 if (res == AMR_UNKNOWN) {
3393 Error("Unknown modifier '%c'", *mod); 3393 Error("Unknown modifier '%c'", *mod);
 3394 /* Guess the end of the current modifier.
 3395 * XXX: Skipping the rest of the modifier hides errors and leads
 3396 * to wrong results. Parsing should rather stop here. */
3394 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++) 3397 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
3395 continue; 3398 continue;
3396 st.newVal = var_Error; 3399 st.newVal = var_Error;
3397 } 3400 }
3398 if (res == AMR_CLEANUP) 3401 if (res == AMR_CLEANUP)
3399 goto cleanup; 3402 goto cleanup;
3400 if (res == AMR_BAD) 3403 if (res == AMR_BAD)
3401 goto bad_modifier; 3404 goto bad_modifier;
3402 3405
3403 if (DEBUG(VAR)) 3406 if (DEBUG(VAR))
3404 LogAfterApply(&st, p, mod); 3407 LogAfterApply(&st, p, mod);
3405 3408
3406 if (st.newVal != st.val) { 3409 if (st.newVal != st.val) {
3407 if (*out_freeIt) { 3410 if (*out_freeIt) {
3408 free(st.val); 3411 free(st.val);
3409 *out_freeIt = NULL; 3412 *out_freeIt = NULL;
3410 } 3413 }
3411 st.val = st.newVal; 3414 st.val = st.newVal;
3412 if (st.val != var_Error && st.val != varUndefined && 3415 if (st.val != var_Error && st.val != varUndefined &&
3413 st.val != emptyString) { 3416 st.val != emptyString) {
3414 *out_freeIt = st.val; 3417 *out_freeIt = st.val;
3415 } 3418 }
3416 } 3419 }
3417 if (*p == '\0' && st.endc != '\0') { 3420 if (*p == '\0' && st.endc != '\0') {
3418 Error("Unclosed variable specification (expecting '%c') " 3421 Error("Unclosed variable specification (expecting '%c') "
3419 "for \"%s\" (value \"%s\") modifier %c", 3422 "for \"%s\" (value \"%s\") modifier %c",
3420 st.endc, st.v->name, st.val, *mod); 3423 st.endc, st.v->name, st.val, *mod);
3421 } else if (*p == ':') { 3424 } else if (*p == ':') {
3422 p++; 3425 p++;
3423 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) { 3426 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) {
3424 Parse_Error(PARSE_FATAL, 3427 Parse_Error(PARSE_FATAL,
3425 "Missing delimiter ':' after modifier \"%.*s\"", 3428 "Missing delimiter ':' after modifier \"%.*s\"",
3426 (int)(p - mod), mod); 3429 (int)(p - mod), mod);
3427 /* TODO: propagate parse error to the enclosing expression */ 3430 /* TODO: propagate parse error to the enclosing expression */
3428 } 3431 }
3429 } 3432 }
3430out: 3433out:
3431 *pp = p; 3434 *pp = p;
3432 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */ 3435 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
3433 *exprFlags = st.exprFlags; 3436 *exprFlags = st.exprFlags;
3434 return st.val; 3437 return st.val;
3435 3438
3436bad_modifier: 3439bad_modifier:
3437 Error("Bad modifier `:%.*s' for %s", 3440 Error("Bad modifier `:%.*s' for %s",
3438 (int)strcspn(mod, ":)}"), mod, st.v->name); 3441 (int)strcspn(mod, ":)}"), mod, st.v->name);
3439 3442
3440cleanup: 3443cleanup:
3441 *pp = p; 3444 *pp = p;
3442 free(*out_freeIt); 3445 free(*out_freeIt);
3443 *out_freeIt = NULL; 3446 *out_freeIt = NULL;
3444 *exprFlags = st.exprFlags; 3447 *exprFlags = st.exprFlags;
3445 return var_Error; 3448 return var_Error;
3446} 3449}
3447 3450
3448/* Only four of the local variables are treated specially as they are the 3451/* Only four of the local variables are treated specially as they are the
3449 * only four that will be set when dynamic sources are expanded. */ 3452 * only four that will be set when dynamic sources are expanded. */
3450static Boolean 3453static Boolean
3451VarnameIsDynamic(const char *name, size_t len) 3454VarnameIsDynamic(const char *name, size_t len)
3452{ 3455{
3453 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) { 3456 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3454 switch (name[0]) { 3457 switch (name[0]) {
3455 case '@': 3458 case '@':
3456 case '%': 3459 case '%':
3457 case '*': 3460 case '*':
3458 case '!': 3461 case '!':
3459 return TRUE; 3462 return TRUE;
3460 } 3463 }
3461 return FALSE; 3464 return FALSE;
3462 } 3465 }
3463 3466
3464 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) { 3467 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3465 return strcmp(name, ".TARGET") == 0 || 3468 return strcmp(name, ".TARGET") == 0 ||
3466 strcmp(name, ".ARCHIVE") == 0 || 3469 strcmp(name, ".ARCHIVE") == 0 ||
3467 strcmp(name, ".PREFIX") == 0 || 3470 strcmp(name, ".PREFIX") == 0 ||
3468 strcmp(name, ".MEMBER") == 0; 3471 strcmp(name, ".MEMBER") == 0;
3469 } 3472 }
3470 3473
3471 return FALSE; 3474 return FALSE;
3472} 3475}
3473 3476
3474static const char * 3477static const char *
3475UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3478UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3476{ 3479{
3477 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3480 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3478 /* 3481 /*
3479 * If substituting a local variable in a non-local context, 3482 * If substituting a local variable in a non-local context,
3480 * assume it's for dynamic source stuff. We have to handle 3483 * assume it's for dynamic source stuff. We have to handle
3481 * this specially and return the longhand for the variable 3484 * this specially and return the longhand for the variable
3482 * with the dollar sign escaped so it makes it back to the 3485 * with the dollar sign escaped so it makes it back to the
3483 * caller. Only four of the local variables are treated 3486 * caller. Only four of the local variables are treated
3484 * specially as they are the only four that will be set 3487 * specially as they are the only four that will be set
3485 * when dynamic sources are expanded. 3488 * when dynamic sources are expanded.
3486 */ 3489 */
3487 switch (varname) { 3490 switch (varname) {
3488 case '@': 3491 case '@':
3489 return "$(.TARGET)"; 3492 return "$(.TARGET)";
3490 case '%': 3493 case '%':
3491 return "$(.MEMBER)"; 3494 return "$(.MEMBER)";
3492 case '*': 3495 case '*':
3493 return "$(.PREFIX)"; 3496 return "$(.PREFIX)";
3494 case '!': 3497 case '!':
3495 return "$(.ARCHIVE)"; 3498 return "$(.ARCHIVE)";
3496 } 3499 }
3497 } 3500 }
3498 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3501 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3499} 3502}
3500 3503
3501/* Parse a variable name, until the end character or a colon, whichever 3504/* Parse a variable name, until the end character or a colon, whichever
3502 * comes first. */ 3505 * comes first. */
3503static char * 3506static char *
3504ParseVarname(const char **pp, char startc, char endc, 3507ParseVarname(const char **pp, char startc, char endc,
3505 GNode *ctxt, VarEvalFlags eflags, 3508 GNode *ctxt, VarEvalFlags eflags,
3506 size_t *out_varname_len) 3509 size_t *out_varname_len)
3507{ 3510{
3508 Buffer buf; 3511 Buffer buf;
3509 const char *p = *pp; 3512 const char *p = *pp;
3510 int depth = 1; 3513 int depth = 1;
3511 3514
3512 Buf_Init(&buf, 0); 3515 Buf_Init(&buf, 0);
3513 3516
3514 while (*p != '\0') { 3517 while (*p != '\0') {
3515 /* Track depth so we can spot parse errors. */ 3518 /* Track depth so we can spot parse errors. */
3516 if (*p == startc) 3519 if (*p == startc)
3517 depth++; 3520 depth++;
3518 if (*p == endc) { 3521 if (*p == endc) {
3519 if (--depth == 0) 3522 if (--depth == 0)
3520 break; 3523 break;
3521 } 3524 }
3522 if (*p == ':' && depth == 1) 3525 if (*p == ':' && depth == 1)
3523 break; 3526 break;
3524 3527
3525 /* A variable inside a variable, expand. */ 3528 /* A variable inside a variable, expand. */
3526 if (*p == '$') { 3529 if (*p == '$') {
3527 void *freeIt; 3530 void *freeIt;
3528 const char *rval; 3531 const char *rval;
3529 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3532 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3530 /* TODO: handle errors */ 3533 /* TODO: handle errors */
3531 Buf_AddStr(&buf, rval); 3534 Buf_AddStr(&buf, rval);
3532 free(freeIt); 3535 free(freeIt);
3533 } else { 3536 } else {
3534 Buf_AddByte(&buf, *p); 3537 Buf_AddByte(&buf, *p);
3535 p++; 3538 p++;
3536 } 3539 }
3537 } 3540 }
3538 *pp = p; 3541 *pp = p;
3539 *out_varname_len = Buf_Len(&buf); 3542 *out_varname_len = Buf_Len(&buf);
3540 return Buf_Destroy(&buf, FALSE); 3543 return Buf_Destroy(&buf, FALSE);
3541} 3544}
3542 3545
3543static Boolean 3546static Boolean
3544ValidShortVarname(char varname, const char *start) 3547ValidShortVarname(char varname, const char *start)
3545{ 3548{
3546 switch (varname) { 3549 switch (varname) {
3547 case '\0': 3550 case '\0':
3548 case ')': 3551 case ')':
3549 case '}': 3552 case '}':
3550 case ':': 3553 case ':':
3551 case '$': 3554 case '$':
3552 break; /* and continue below */ 3555 break; /* and continue below */
3553 default: 3556 default:
3554 return TRUE; 3557 return TRUE;
3555 } 3558 }
3556 3559
3557 if (!DEBUG(LINT)) 3560 if (!DEBUG(LINT))
3558 return FALSE; 3561 return FALSE;
3559 3562
3560 if (varname == '$') 3563 if (varname == '$')
3561 Parse_Error(PARSE_FATAL, 3564 Parse_Error(PARSE_FATAL,
3562 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3565 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3563 else if (varname == '\0') 3566 else if (varname == '\0')
3564 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3567 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3565 else 3568 else
3566 Parse_Error(PARSE_FATAL, 3569 Parse_Error(PARSE_FATAL,
3567 "Invalid variable name '%c', at \"%s\"", varname, start); 3570 "Invalid variable name '%c', at \"%s\"", varname, start);
3568 3571
3569 return FALSE; 3572 return FALSE;
3570} 3573}
3571 3574
3572/* Parse a single-character variable name such as $V or $@. 3575/* Parse a single-character variable name such as $V or $@.
3573 * Return whether to continue parsing. */ 3576 * Return whether to continue parsing. */
3574static Boolean 3577static Boolean
3575ParseVarnameShort( 3578ParseVarnameShort(
3576 char startc, 3579 char startc,
3577 const char **pp, 3580 const char **pp,
3578 GNode *ctxt, 3581 GNode *ctxt,
3579 VarEvalFlags eflags, 3582 VarEvalFlags eflags,
3580 VarParseResult *out_FALSE_res, 3583 VarParseResult *out_FALSE_res,
3581 const char **out_FALSE_val, 3584 const char **out_FALSE_val,
3582 Var **out_TRUE_var 3585 Var **out_TRUE_var
3583) { 3586) {
3584 char name[2]; 3587 char name[2];
3585 Var *v; 3588 Var *v;
3586 3589
3587 /* 3590 /*
3588 * If it's not bounded by braces of some sort, life is much simpler. 3591 * If it's not bounded by braces of some sort, life is much simpler.
3589 * We just need to check for the first character and return the 3592 * We just need to check for the first character and return the
3590 * value if it exists. 3593 * value if it exists.
3591 */ 3594 */
3592 3595
3593 if (!ValidShortVarname(startc, *pp)) { 3596 if (!ValidShortVarname(startc, *pp)) {
3594 (*pp)++; 3597 (*pp)++;
3595 *out_FALSE_val = var_Error; 3598 *out_FALSE_val = var_Error;
3596 *out_FALSE_res = VPR_PARSE_MSG; 3599 *out_FALSE_res = VPR_PARSE_MSG;
3597 return FALSE; 3600 return FALSE;
3598 } 3601 }
3599 3602
3600 name[0] = startc; 3603 name[0] = startc;
3601 name[1] = '\0'; 3604 name[1] = '\0';
3602 v = VarFind(name, ctxt, TRUE); 3605 v = VarFind(name, ctxt, TRUE);
3603 if (v == NULL) { 3606 if (v == NULL) {
3604 *pp += 2; 3607 *pp += 2;
3605 3608
3606 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3609 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3607 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3610 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3608 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3611 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3609 *out_FALSE_res = VPR_UNDEF_MSG; 3612 *out_FALSE_res = VPR_UNDEF_MSG;
3610 return FALSE; 3613 return FALSE;
3611 } 3614 }
3612 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3615 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3613 return FALSE; 3616 return FALSE;
3614 } 3617 }
3615 3618
3616 *out_TRUE_var = v; 3619 *out_TRUE_var = v;
3617 return TRUE; 3620 return TRUE;
3618} 3621}
3619 3622
3620/* Parse a long variable name enclosed in braces or parentheses such as $(VAR) 3623/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3621 * or ${VAR}, up to the closing brace or parenthesis, or in the case of 3624 * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3622 * ${VAR:Modifiers}, up to the ':' that starts the modifiers. 3625 * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3623 * Return whether to continue parsing. */ 3626 * Return whether to continue parsing. */
3624static Boolean 3627static Boolean
3625ParseVarnameLong( 3628ParseVarnameLong(
3626 const char **pp, 3629 const char **pp,
3627 char startc, 3630 char startc,
3628 GNode *ctxt, 3631 GNode *ctxt,
3629 VarEvalFlags eflags, 3632 VarEvalFlags eflags,
3630 3633
3631 VarParseResult *out_FALSE_res, 3634 VarParseResult *out_FALSE_res,
3632 const char **out_FALSE_val, 3635 const char **out_FALSE_val,
3633 void **out_FALSE_freeIt, 3636 void **out_FALSE_freeIt,
3634 3637
3635 char *out_TRUE_endc, 3638 char *out_TRUE_endc,
3636 const char **out_TRUE_p, 3639 const char **out_TRUE_p,
3637 Var **out_TRUE_v, 3640 Var **out_TRUE_v,
3638 Boolean *out_TRUE_haveModifier, 3641 Boolean *out_TRUE_haveModifier,
3639 const char **out_TRUE_extraModifiers, 3642 const char **out_TRUE_extraModifiers,
3640 Boolean *out_TRUE_dynamic, 3643 Boolean *out_TRUE_dynamic,
3641 VarExprFlags *out_TRUE_exprFlags 3644 VarExprFlags *out_TRUE_exprFlags
3642) { 3645) {
3643 size_t namelen; 3646 size_t namelen;
3644 char *varname; 3647 char *varname;
3645 Var *v; 3648 Var *v;
3646 Boolean haveModifier; 3649 Boolean haveModifier;
3647 Boolean dynamic = FALSE; 3650 Boolean dynamic = FALSE;
3648 3651
3649 const char *const start = *pp; 3652 const char *const start = *pp;
3650 char endc = startc == '(' ? ')' : '}'; 3653 char endc = startc == '(' ? ')' : '}';
3651 3654
3652 const char *p = start + 2; 3655 const char *p = start + 2;
3653 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3656 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3654 3657
3655 if (*p == ':') { 3658 if (*p == ':') {
3656 haveModifier = TRUE; 3659 haveModifier = TRUE;
3657 } else if (*p == endc) { 3660 } else if (*p == endc) {
3658 haveModifier = FALSE; 3661 haveModifier = FALSE;
3659 } else { 3662 } else {
3660 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3663 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3661 *pp = p; 3664 *pp = p;
3662 free(varname); 3665 free(varname);
3663 *out_FALSE_val = var_Error; 3666 *out_FALSE_val = var_Error;
3664 *out_FALSE_res = VPR_PARSE_MSG; 3667 *out_FALSE_res = VPR_PARSE_MSG;
3665 return FALSE; 3668 return FALSE;
3666 } 3669 }
3667 3670
3668 v = VarFind(varname, ctxt, TRUE); 3671 v = VarFind(varname, ctxt, TRUE);
3669 3672
3670 /* At this point, p points just after the variable name, 3673 /* At this point, p points just after the variable name,
3671 * either at ':' or at endc. */ 3674 * either at ':' or at endc. */
3672 3675
3673 /* 3676 /*
3674 * Check also for bogus D and F forms of local variables since we're 3677 * Check also for bogus D and F forms of local variables since we're
3675 * in a local context and the name is the right length. 3678 * in a local context and the name is the right length.
3676 */ 3679 */
3677 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3680 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3678 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3681 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3679 strchr("@%?*!<>", varname[0]) != NULL) 3682 strchr("@%?*!<>", varname[0]) != NULL)
3680 { 3683 {
3681 /* 3684 /*
3682 * Well, it's local -- go look for it. 3685 * Well, it's local -- go look for it.
3683 */ 3686 */
3684 char name[] = { varname[0], '\0' }; 3687 char name[] = { varname[0], '\0' };
3685 v = VarFind(name, ctxt, 0); 3688 v = VarFind(name, ctxt, 0);
3686 3689
3687 if (v != NULL) { 3690 if (v != NULL) {
3688 if (varname[1] == 'D') { 3691 if (varname[1] == 'D') {
3689 *out_TRUE_extraModifiers = "H:"; 3692 *out_TRUE_extraModifiers = "H:";
3690 } else { /* F */ 3693 } else { /* F */
3691 *out_TRUE_extraModifiers = "T:"; 3694 *out_TRUE_extraModifiers = "T:";
3692 } 3695 }
3693 } 3696 }
3694 } 3697 }
3695 3698
3696 if (v == NULL) { 3699 if (v == NULL) {
3697 /* Defer expansion of dynamic variables if they appear in non-local 3700 /* Defer expansion of dynamic variables if they appear in non-local
3698 * context since they are not defined there. */ 3701 * context since they are not defined there. */
3699 dynamic = VarnameIsDynamic(varname, namelen) && 3702 dynamic = VarnameIsDynamic(varname, namelen) &&
3700 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL); 3703 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
3701 3704
3702 if (!haveModifier) { 3705 if (!haveModifier) {
3703 p++; /* skip endc */ 3706 p++; /* skip endc */
3704 *pp = p; 3707 *pp = p;
3705 if (dynamic) { 3708 if (dynamic) {
3706 char *pstr = bmake_strsedup(start, p); 3709 char *pstr = bmake_strsedup(start, p);
3707 free(varname); 3710 free(varname);
3708 *out_FALSE_res = VPR_OK; 3711 *out_FALSE_res = VPR_OK;
3709 *out_FALSE_freeIt = pstr; 3712 *out_FALSE_freeIt = pstr;
3710 *out_FALSE_val = pstr; 3713 *out_FALSE_val = pstr;
3711 return FALSE; 3714 return FALSE;
3712 } 3715 }
3713 3716
3714 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3717 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3715 DEBUG(LINT)) 3718 DEBUG(LINT))
3716 { 3719 {
3717 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3720 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3718 varname); 3721 varname);
3719 free(varname); 3722 free(varname);
3720 *out_FALSE_res = VPR_UNDEF_MSG; 3723 *out_FALSE_res = VPR_UNDEF_MSG;
3721 *out_FALSE_val = var_Error; 3724 *out_FALSE_val = var_Error;
3722 return FALSE; 3725 return FALSE;
3723 } 3726 }
3724 3727
3725 if (eflags & VARE_UNDEFERR) { 3728 if (eflags & VARE_UNDEFERR) {
3726 free(varname); 3729 free(varname);
3727 *out_FALSE_res = VPR_UNDEF_SILENT; 3730 *out_FALSE_res = VPR_UNDEF_SILENT;
3728 *out_FALSE_val = var_Error; 3731 *out_FALSE_val = var_Error;
3729 return FALSE; 3732 return FALSE;
3730 } 3733 }
3731 3734
3732 free(varname); 3735 free(varname);
3733 *out_FALSE_res = VPR_OK; 3736 *out_FALSE_res = VPR_OK;
3734 *out_FALSE_val = varUndefined; 3737 *out_FALSE_val = varUndefined;
3735 return FALSE; 3738 return FALSE;
3736 } 3739 }
3737 3740
3738 /* The variable expression is based on an undefined variable. 3741 /* The variable expression is based on an undefined variable.
3739 * Nevertheless it needs a Var, for modifiers that access the 3742 * Nevertheless it needs a Var, for modifiers that access the
3740 * variable name, such as :L or :?. 3743 * variable name, such as :L or :?.
3741 * 3744 *
3742 * Most modifiers leave this expression in the "undefined" state 3745 * Most modifiers leave this expression in the "undefined" state
3743 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3746 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3744 * undefined expression into a defined expression (VEF_DEF). 3747 * undefined expression into a defined expression (VEF_DEF).
3745 * 3748 *
3746 * At the end, after applying all modifiers, if the expression 3749 * At the end, after applying all modifiers, if the expression
3747 * is still undefined, Var_Parse will return an empty string 3750 * is still undefined, Var_Parse will return an empty string
3748 * instead of the actually computed value. */ 3751 * instead of the actually computed value. */
3749 v = VarNew(varname, varname, "", 0); 3752 v = VarNew(varname, varname, "", 0);
3750 *out_TRUE_exprFlags = VEF_UNDEF; 3753 *out_TRUE_exprFlags = VEF_UNDEF;
3751 } else 3754 } else
3752 free(varname); 3755 free(varname);
3753 3756
3754 *out_TRUE_endc = endc; 3757 *out_TRUE_endc = endc;
3755 *out_TRUE_p = p; 3758 *out_TRUE_p = p;
3756 *out_TRUE_v = v; 3759 *out_TRUE_v = v;
3757 *out_TRUE_haveModifier = haveModifier; 3760 *out_TRUE_haveModifier = haveModifier;
3758 *out_TRUE_dynamic = dynamic; 3761 *out_TRUE_dynamic = dynamic;
3759 return TRUE; 3762 return TRUE;
3760} 3763}
3761 3764
3762/*- 3765/*-
3763 *----------------------------------------------------------------------- 3766 *-----------------------------------------------------------------------
3764 * Var_Parse -- 3767 * Var_Parse --
3765 * Given the start of a variable expression (such as $v, $(VAR), 3768 * Given the start of a variable expression (such as $v, $(VAR),
3766 * ${VAR:Mpattern}), extract the variable name, possibly some 3769 * ${VAR:Mpattern}), extract the variable name, possibly some
3767 * modifiers and find its value by applying the modifiers to the 3770 * modifiers and find its value by applying the modifiers to the
3768 * original value. 3771 * original value.
3769 * 3772 *
3770 * When parsing a condition in ParseEmptyArg, pp may also point to 3773 * When parsing a condition in ParseEmptyArg, pp may also point to
3771 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3774 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3772 * identical. 3775 * identical.
3773 * 3776 *
3774 * Input: 3777 * Input:
3775 * str The string to parse 3778 * str The string to parse
3776 * ctxt The context for the variable 3779 * ctxt The context for the variable
3777 * flags Select the exact details of parsing 3780 * flags Select the exact details of parsing
3778 * out_val_freeIt Must be freed by the caller after using out_val 3781 * out_val_freeIt Must be freed by the caller after using out_val
3779 * 3782 *
3780 * Results: 3783 * Results:
3781 * Returns the value of the variable expression, never NULL. 3784 * Returns the value of the variable expression, never NULL.
3782 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3785 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3783 * set. 3786 * set.
3784 * Returns varUndefined if there was an undefined variable and 3787 * Returns varUndefined if there was an undefined variable and
3785 * VARE_UNDEFERR was not set. 3788 * VARE_UNDEFERR was not set.
3786 * 3789 *
3787 * Parsing should continue at *pp. 3790 * Parsing should continue at *pp.
3788 * TODO: Document the value of *pp on parse errors. It might be advanced 3791 * TODO: Document the value of *pp on parse errors. It might be advanced
3789 * by 0, or +1, or the index of the parse error, or the guessed end of the 3792 * by 0, or +1, or the index of the parse error, or the guessed end of the
3790 * variable expression. 3793 * variable expression.
3791 * 3794 *
3792 * If var_Error is returned, a diagnostic may or may not have been 3795 * If var_Error is returned, a diagnostic may or may not have been
3793 * printed. XXX: This is inconsistent. 3796 * printed. XXX: This is inconsistent.
3794 * 3797 *
3795 * If varUndefined is returned, a diagnostic may or may not have been 3798 * If varUndefined is returned, a diagnostic may or may not have been
3796 * printed. XXX: This is inconsistent. 3799 * printed. XXX: This is inconsistent.
3797 * 3800 *
3798 * After using the returned value, *out_val_freeIt must be freed, 3801 * After using the returned value, *out_val_freeIt must be freed,
3799 * preferably using bmake_free since it is NULL in most cases. 3802 * preferably using bmake_free since it is NULL in most cases.
3800 * 3803 *
3801 * Side Effects: 3804 * Side Effects:
3802 * Any effects from the modifiers, such as :!cmd! or ::=value. 3805 * Any effects from the modifiers, such as :!cmd! or ::=value.
3803 *----------------------------------------------------------------------- 3806 *-----------------------------------------------------------------------
3804 */ 3807 */
3805/* coverity[+alloc : arg-*4] */ 3808/* coverity[+alloc : arg-*4] */
3806VarParseResult 3809VarParseResult
3807Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3810Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3808 const char **out_val, void **out_val_freeIt) 3811 const char **out_val, void **out_val_freeIt)
3809{ 3812{
3810 const char *const start = *pp; 3813 const char *const start = *pp;
3811 const char *p; 3814 const char *p;
3812 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3815 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3813 char startc; /* Starting character if variable in parens 3816 char startc; /* Starting character if variable in parens
3814 * or braces */ 3817 * or braces */
3815 char endc; /* Ending character if variable in parens 3818 char endc; /* Ending character if variable in parens
3816 * or braces */ 3819 * or braces */
3817 Boolean dynamic; /* TRUE if the variable is local and we're 3820 Boolean dynamic; /* TRUE if the variable is local and we're
3818 * expanding it in a non-local context. This 3821 * expanding it in a non-local context. This
3819 * is done to support dynamic sources. The 3822 * is done to support dynamic sources. The
3820 * result is just the expression, unaltered */ 3823 * result is just the expression, unaltered */
3821 const char *extramodifiers; 3824 const char *extramodifiers;
3822 Var *v; 3825 Var *v;
3823 char *nstr; 3826 char *nstr;
3824 char eflags_str[VarEvalFlags_ToStringSize]; 3827 char eflags_str[VarEvalFlags_ToStringSize];
3825 VarExprFlags exprFlags = 0; 3828 VarExprFlags exprFlags = 0;
3826 3829
3827 VAR_DEBUG2("Var_Parse: %s with %s\n", start, 3830 VAR_DEBUG2("Var_Parse: %s with %s\n", start,
3828 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3831 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3829 VarEvalFlags_ToStringSpecs)); 3832 VarEvalFlags_ToStringSpecs));
3830 3833
3831 *out_val_freeIt = NULL; 3834 *out_val_freeIt = NULL;
3832 extramodifiers = NULL; /* extra modifiers to apply first */ 3835 extramodifiers = NULL; /* extra modifiers to apply first */
3833 dynamic = FALSE; 3836 dynamic = FALSE;
3834 3837
3835 /* Appease GCC, which thinks that the variable might not be 3838 /* Appease GCC, which thinks that the variable might not be
3836 * initialized. */ 3839 * initialized. */
3837 endc = '\0'; 3840 endc = '\0';
3838 3841
3839 startc = start[1]; 3842 startc = start[1];
3840 if (startc != '(' && startc != '{') { 3843 if (startc != '(' && startc != '{') {
3841 VarParseResult res; 3844 VarParseResult res;
3842 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v)) 3845 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v))
3843 return res; 3846 return res;
3844 haveModifier = FALSE; 3847 haveModifier = FALSE;
3845 p = start + 1; 3848 p = start + 1;
3846 } else { 3849 } else {
3847 VarParseResult res; 3850 VarParseResult res;
3848 if (!ParseVarnameLong(pp, startc, ctxt, eflags, 3851 if (!ParseVarnameLong(pp, startc, ctxt, eflags,
3849 &res, out_val, out_val_freeIt, 3852 &res, out_val, out_val_freeIt,
3850 &endc, &p, &v, &haveModifier, &extramodifiers, 3853 &endc, &p, &v, &haveModifier, &extramodifiers,
3851 &dynamic, &exprFlags)) 3854 &dynamic, &exprFlags))
3852 return res; 3855 return res;
3853 } 3856 }
3854 3857
3855 if (v->flags & VAR_IN_USE) 3858 if (v->flags & VAR_IN_USE)
3856 Fatal("Variable %s is recursive.", v->name); 3859 Fatal("Variable %s is recursive.", v->name);
3857 3860
3858 /* 3861 /*
3859 * Before doing any modification, we have to make sure the value 3862 * Before doing any modification, we have to make sure the value
3860 * has been fully expanded. If it looks like recursion might be 3863 * has been fully expanded. If it looks like recursion might be
3861 * necessary (there's a dollar sign somewhere in the variable's value) 3864 * necessary (there's a dollar sign somewhere in the variable's value)
3862 * we just call Var_Subst to do any other substitutions that are 3865 * we just call Var_Subst to do any other substitutions that are
3863 * necessary. Note that the value returned by Var_Subst will have 3866 * necessary. Note that the value returned by Var_Subst will have
3864 * been dynamically-allocated, so it will need freeing when we 3867 * been dynamically-allocated, so it will need freeing when we
3865 * return. 3868 * return.
3866 */ 3869 */
3867 nstr = Buf_GetAll(&v->val, NULL); 3870 nstr = Buf_GetAll(&v->val, NULL);
3868 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) { 3871 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) {
3869 VarEvalFlags nested_eflags = eflags; 3872 VarEvalFlags nested_eflags = eflags;
3870 if (DEBUG(LINT)) 3873 if (DEBUG(LINT))
3871 nested_eflags &= ~(unsigned)VARE_UNDEFERR; 3874 nested_eflags &= ~(unsigned)VARE_UNDEFERR;
3872 v->flags |= VAR_IN_USE; 3875 v->flags |= VAR_IN_USE;
3873 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr); 3876 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr);
3874 v->flags &= ~(unsigned)VAR_IN_USE; 3877 v->flags &= ~(unsigned)VAR_IN_USE;
3875 /* TODO: handle errors */ 3878 /* TODO: handle errors */
3876 *out_val_freeIt = nstr; 3879 *out_val_freeIt = nstr;
3877 } 3880 }
3878 3881
3879 if (haveModifier || extramodifiers != NULL) { 3882 if (haveModifier || extramodifiers != NULL) {
3880 void *extraFree; 3883 void *extraFree;
3881 3884
3882 extraFree = NULL; 3885 extraFree = NULL;
3883 if (extramodifiers != NULL) { 3886 if (extramodifiers != NULL) {
3884 const char *em = extramodifiers; 3887 const char *em = extramodifiers;
3885 nstr = ApplyModifiers(&em, nstr, '(', ')', 3888 nstr = ApplyModifiers(&em, nstr, '(', ')',
3886 v, &exprFlags, ctxt, eflags, &extraFree); 3889 v, &exprFlags, ctxt, eflags, &extraFree);
3887 } 3890 }
3888 3891
3889 if (haveModifier) { 3892 if (haveModifier) {
3890 /* Skip initial colon. */ 3893 /* Skip initial colon. */
3891 p++; 3894 p++;
3892 3895
3893 nstr = ApplyModifiers(&p, nstr, startc, endc, 3896 nstr = ApplyModifiers(&p, nstr, startc, endc,
3894 v, &exprFlags, ctxt, eflags, out_val_freeIt); 3897 v, &exprFlags, ctxt, eflags, out_val_freeIt);
3895 free(extraFree); 3898 free(extraFree);
3896 } else { 3899 } else {
3897 *out_val_freeIt = extraFree; 3900 *out_val_freeIt = extraFree;
3898 } 3901 }
3899 } 3902 }
3900 3903
3901 if (*p != '\0') /* Skip past endc if possible. */ 3904 if (*p != '\0') /* Skip past endc if possible. */
3902 p++; 3905 p++;
3903 3906
3904 *pp = p; 3907 *pp = p;
3905 3908
3906 if (v->flags & VAR_FROM_ENV) { 3909 if (v->flags & VAR_FROM_ENV) {
3907 /* Free the environment variable now since we own it, 3910 /* Free the environment variable now since we own it,
3908 * but don't free the variable value if it will be returned. */ 3911 * but don't free the variable value if it will be returned. */
3909 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL); 3912 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL);
3910 if (keepValue) 3913 if (keepValue)
3911 *out_val_freeIt = nstr; 3914 *out_val_freeIt = nstr;
3912 (void)VarFreeEnv(v, !keepValue); 3915 (void)VarFreeEnv(v, !keepValue);
3913 3916
3914 } else if (exprFlags & VEF_UNDEF) { 3917 } else if (exprFlags & VEF_UNDEF) {
3915 if (!(exprFlags & VEF_DEF)) { 3918 if (!(exprFlags & VEF_DEF)) {
3916 if (*out_val_freeIt != NULL) { 3919 if (*out_val_freeIt != NULL) {
3917 free(*out_val_freeIt); 3920 free(*out_val_freeIt);
3918 *out_val_freeIt = NULL; 3921 *out_val_freeIt = NULL;
3919 } 3922 }
3920 if (dynamic) { 3923 if (dynamic) {
3921 nstr = bmake_strsedup(start, p); 3924 nstr = bmake_strsedup(start, p);
3922 *out_val_freeIt = nstr; 3925 *out_val_freeIt = nstr;
3923 } else { 3926 } else {
3924 /* The expression is still undefined, therefore discard the 3927 /* The expression is still undefined, therefore discard the
3925 * actual value and return an error marker instead. */ 3928 * actual value and return an error marker instead. */
3926 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined; 3929 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined;
3927 } 3930 }
3928 } 3931 }
3929 if (nstr != Buf_GetAll(&v->val, NULL)) 3932 if (nstr != Buf_GetAll(&v->val, NULL))
3930 Buf_Destroy(&v->val, TRUE); 3933 Buf_Destroy(&v->val, TRUE);
3931 free(v->name_freeIt); 3934 free(v->name_freeIt);
3932 free(v); 3935 free(v);
3933 } 3936 }
3934 *out_val = nstr; 3937 *out_val = nstr;
3935 return VPR_UNKNOWN; 3938 return VPR_UNKNOWN;
3936} 3939}
3937 3940
3938/* Substitute for all variables in the given string in the given context. 3941/* Substitute for all variables in the given string in the given context.
3939 * 3942 *
3940 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3943 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3941 * variable is encountered. 3944 * variable is encountered.
3942 * 3945 *
3943 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=, 3946 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=,
3944 * :sh or !cmd! take place. 3947 * :sh or !cmd! take place.
3945 * 3948 *
3946 * Input: 3949 * Input:
3947 * str the string which to substitute 3950 * str the string which to substitute
3948 * ctxt the context wherein to find variables 3951 * ctxt the context wherein to find variables
3949 * eflags VARE_UNDEFERR if undefineds are an error 3952 * eflags VARE_UNDEFERR if undefineds are an error
3950 * VARE_WANTRES if we actually want the result 3953 * VARE_WANTRES if we actually want the result
3951 * VARE_ASSIGN if we are in a := assignment 3954 * VARE_ASSIGN if we are in a := assignment
3952 * 3955 *
3953 * Results: 3956 * Results:
3954 * The resulting string. 3957 * The resulting string.
3955 */ 3958 */
3956VarParseResult 3959VarParseResult
3957Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res) 3960Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
3958{ 3961{
3959 const char *p = str; 3962 const char *p = str;
3960 Buffer buf; /* Buffer for forming things */ 3963 Buffer buf; /* Buffer for forming things */
3961 3964
3962 /* Set true if an error has already been reported, 3965 /* Set true if an error has already been reported,
3963 * to prevent a plethora of messages when recursing */ 3966 * to prevent a plethora of messages when recursing */
3964 static Boolean errorReported; 3967 static Boolean errorReported;
3965 3968
3966 Buf_Init(&buf, 0); 3969 Buf_Init(&buf, 0);
3967 errorReported = FALSE; 3970 errorReported = FALSE;
3968 3971
3969 while (*p != '\0') { 3972 while (*p != '\0') {
3970 if (p[0] == '$' && p[1] == '$') { 3973 if (p[0] == '$' && p[1] == '$') {
3971 /* A dollar sign may be escaped with another dollar sign. */ 3974 /* A dollar sign may be escaped with another dollar sign. */
3972 if (save_dollars && (eflags & VARE_ASSIGN)) 3975 if (save_dollars && (eflags & VARE_ASSIGN))
3973 Buf_AddByte(&buf, '$'); 3976 Buf_AddByte(&buf, '$');
3974 Buf_AddByte(&buf, '$'); 3977 Buf_AddByte(&buf, '$');
3975 p += 2; 3978 p += 2;
3976 } else if (*p != '$') { 3979 } else if (*p != '$') {
3977 /* 3980 /*
3978 * Skip as many characters as possible -- either to the end of 3981 * Skip as many characters as possible -- either to the end of
3979 * the string or to the next dollar sign (variable expression). 3982 * the string or to the next dollar sign (variable expression).
3980 */ 3983 */
3981 const char *plainStart = p; 3984 const char *plainStart = p;
3982 3985
3983 for (p++; *p != '$' && *p != '\0'; p++) 3986 for (p++; *p != '$' && *p != '\0'; p++)
3984 continue; 3987 continue;
3985 Buf_AddBytesBetween(&buf, plainStart, p); 3988 Buf_AddBytesBetween(&buf, plainStart, p);
3986 } else { 3989 } else {
3987 const char *nested_p = p; 3990 const char *nested_p = p;
3988 void *freeIt; 3991 void *freeIt;
3989 const char *val; 3992 const char *val;
3990 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt); 3993 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt);
3991 /* TODO: handle errors */ 3994 /* TODO: handle errors */
3992 3995
3993 if (val == var_Error || val == varUndefined) { 3996 if (val == var_Error || val == varUndefined) {
3994 /* 3997 /*
3995 * If performing old-time variable substitution, skip over 3998 * If performing old-time variable substitution, skip over
3996 * the variable and continue with the substitution. Otherwise, 3999 * the variable and continue with the substitution. Otherwise,
3997 * store the dollar sign and advance str so we continue with 4000 * store the dollar sign and advance str so we continue with
3998 * the string... 4001 * the string...
3999 */ 4002 */
4000 if (oldVars) { 4003 if (oldVars) {
4001 p = nested_p; 4004 p = nested_p;
4002 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 4005 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
4003 /* 4006 /*
4004 * If variable is undefined, complain and skip the 4007 * If variable is undefined, complain and skip the
4005 * variable. The complaint will stop us from doing anything 4008 * variable. The complaint will stop us from doing anything
4006 * when the file is parsed. 4009 * when the file is parsed.
4007 */ 4010 */
4008 if (!errorReported) { 4011 if (!errorReported) {
4009 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 4012 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
4010 (int)(size_t)(nested_p - p), p); 4013 (int)(size_t)(nested_p - p), p);
4011 } 4014 }
4012 p = nested_p; 4015 p = nested_p;
4013 errorReported = TRUE; 4016 errorReported = TRUE;
4014 } else { 4017 } else {
4015 /* Copy the initial '$' of the undefined expression, 4018 /* Copy the initial '$' of the undefined expression,
4016 * thereby deferring expansion of the expression, but 4019 * thereby deferring expansion of the expression, but
4017 * expand nested expressions if already possible. 4020 * expand nested expressions if already possible.
4018 * See unit-tests/varparse-undef-partial.mk. */ 4021 * See unit-tests/varparse-undef-partial.mk. */
4019 Buf_AddByte(&buf, *p); 4022 Buf_AddByte(&buf, *p);
4020 p++; 4023 p++;
4021 } 4024 }
4022 } else { 4025 } else {
4023 p = nested_p; 4026 p = nested_p;
4024 Buf_AddStr(&buf, val); 4027 Buf_AddStr(&buf, val);
4025 } 4028 }
4026 free(freeIt); 4029 free(freeIt);
4027 freeIt = NULL; 4030 freeIt = NULL;
4028 } 4031 }
4029 } 4032 }
4030 4033
4031 *out_res = Buf_DestroyCompact(&buf); 4034 *out_res = Buf_DestroyCompact(&buf);
4032 return VPR_OK; 4035 return VPR_OK;
4033} 4036}
4034 4037
4035/* Initialize the variables module. */ 4038/* Initialize the variables module. */
4036void 4039void
4037Var_Init(void) 4040Var_Init(void)
4038{ 4041{
4039 VAR_INTERNAL = Targ_NewGN("Internal"); 4042 VAR_INTERNAL = Targ_NewGN("Internal");
4040 VAR_GLOBAL = Targ_NewGN("Global"); 4043 VAR_GLOBAL = Targ_NewGN("Global");
4041 VAR_CMDLINE = Targ_NewGN("Command"); 4044 VAR_CMDLINE = Targ_NewGN("Command");
4042} 4045}
4043 4046
4044/* Clean up the variables module. */ 4047/* Clean up the variables module. */
4045void 4048void
4046Var_End(void) 4049Var_End(void)
4047{ 4050{
4048 Var_Stats(); 4051 Var_Stats();
4049} 4052}
4050 4053
4051void 4054void
4052Var_Stats(void) 4055Var_Stats(void)
4053{ 4056{
4054 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 4057 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
4055} 4058}
4056 4059
4057/* Print all variables in a context, sorted by name. */ 4060/* Print all variables in a context, sorted by name. */
4058void 4061void
4059Var_Dump(GNode *ctxt) 4062Var_Dump(GNode *ctxt)
4060{ 4063{
4061 Vector /* of const char * */ vec; 4064 Vector /* of const char * */ vec;
4062 HashIter hi; 4065 HashIter hi;
4063 size_t i; 4066 size_t i;
4064 const char **varnames; 4067 const char **varnames;
4065 4068
4066 Vector_Init(&vec, sizeof(const char *)); 4069 Vector_Init(&vec, sizeof(const char *));
4067 4070
4068 HashIter_Init(&hi, &ctxt->context); 4071 HashIter_Init(&hi, &ctxt->context);
4069 while (HashIter_Next(&hi) != NULL) 4072 while (HashIter_Next(&hi) != NULL)
4070 *(const char **)Vector_Push(&vec) = hi.entry->key; 4073 *(const char **)Vector_Push(&vec) = hi.entry->key;
4071 varnames = vec.items; 4074 varnames = vec.items;
4072 4075
4073 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc); 4076 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
4074 4077
4075 for (i = 0; i < vec.len; i++) { 4078 for (i = 0; i < vec.len; i++) {
4076 const char *varname = varnames[i]; 4079 const char *varname = varnames[i];
4077 Var *var = HashTable_FindValue(&ctxt->context, varname); 4080 Var *var = HashTable_FindValue(&ctxt->context, varname);
4078 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL)); 4081 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
4079 } 4082 }
4080 4083
4081 Vector_Done(&vec); 4084 Vector_Done(&vec);
4082} 4085}