Sun Nov 1 23:17:40 2020 UTC ()
make(1): extract ApplyModifiersIndirect from ApplyModifiers


(rillig)
diff -r1.640 -r1.641 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/11/01 22:48:41 1.640
+++ src/usr.bin/make/var.c 2020/11/01 23:17:40 1.641
@@ -1,1132 +1,1132 @@ @@ -1,1132 +1,1132 @@
1/* $NetBSD: var.c,v 1.640 2020/11/01 22:48:41 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.641 2020/11/01 23:17:40 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.640 2020/11/01 22:48:41 rillig Exp $"); 133MAKE_RCSID("$NetBSD: var.c,v 1.641 2020/11/01 23:17:40 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)
@@ -2258,1795 +2258,1821 @@ ApplyModifier_Hash(const char **pp, Appl @@ -2258,1795 +2258,1821 @@ ApplyModifier_Hash(const char **pp, Appl
2258/* :P */ 2258/* :P */
2259static ApplyModifierResult 2259static ApplyModifierResult
2260ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2260ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2261{ 2261{
2262 GNode *gn; 2262 GNode *gn;
2263 char *path; 2263 char *path;
2264 2264
2265 ApplyModifiersState_Define(st); 2265 ApplyModifiersState_Define(st);
2266 2266
2267 gn = Targ_FindNode(st->v->name); 2267 gn = Targ_FindNode(st->v->name);
2268 if (gn == NULL || gn->type & OP_NOPATH) { 2268 if (gn == NULL || gn->type & OP_NOPATH) {
2269 path = NULL; 2269 path = NULL;
2270 } else if (gn->path != NULL) { 2270 } else if (gn->path != NULL) {
2271 path = bmake_strdup(gn->path); 2271 path = bmake_strdup(gn->path);
2272 } else { 2272 } else {
2273 SearchPath *searchPath = Suff_FindPath(gn); 2273 SearchPath *searchPath = Suff_FindPath(gn);
2274 path = Dir_FindFile(st->v->name, searchPath); 2274 path = Dir_FindFile(st->v->name, searchPath);
2275 } 2275 }
2276 if (path == NULL) 2276 if (path == NULL)
2277 path = bmake_strdup(st->v->name); 2277 path = bmake_strdup(st->v->name);
2278 st->newVal = path; 2278 st->newVal = path;
2279 2279
2280 (*pp)++; 2280 (*pp)++;
2281 return AMR_OK; 2281 return AMR_OK;
2282} 2282}
2283 2283
2284/* :!cmd! */ 2284/* :!cmd! */
2285static ApplyModifierResult 2285static ApplyModifierResult
2286ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2286ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2287{ 2287{
2288 char *cmd; 2288 char *cmd;
2289 const char *errfmt; 2289 const char *errfmt;
2290 VarParseResult res; 2290 VarParseResult res;
2291 2291
2292 (*pp)++; 2292 (*pp)++;
2293 res = ParseModifierPart(pp, '!', st->eflags, st, 2293 res = ParseModifierPart(pp, '!', st->eflags, st,
2294 &cmd, NULL, NULL, NULL); 2294 &cmd, NULL, NULL, NULL);
2295 if (res != VPR_OK) 2295 if (res != VPR_OK)
2296 return AMR_CLEANUP; 2296 return AMR_CLEANUP;
2297 2297
2298 errfmt = NULL; 2298 errfmt = NULL;
2299 if (st->eflags & VARE_WANTRES) 2299 if (st->eflags & VARE_WANTRES)
2300 st->newVal = Cmd_Exec(cmd, &errfmt); 2300 st->newVal = Cmd_Exec(cmd, &errfmt);
2301 else 2301 else
2302 st->newVal = emptyString; 2302 st->newVal = emptyString;
2303 free(cmd); 2303 free(cmd);
2304 2304
2305 if (errfmt != NULL) 2305 if (errfmt != NULL)
2306 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2306 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2307 2307
2308 ApplyModifiersState_Define(st); 2308 ApplyModifiersState_Define(st);
2309 return AMR_OK; 2309 return AMR_OK;
2310} 2310}
2311 2311
2312/* The :range modifier generates an integer sequence as long as the words. 2312/* The :range modifier generates an integer sequence as long as the words.
2313 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2313 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2314static ApplyModifierResult 2314static ApplyModifierResult
2315ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2315ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2316{ 2316{
2317 size_t n; 2317 size_t n;
2318 Buffer buf; 2318 Buffer buf;
2319 size_t i; 2319 size_t i;
2320 2320
2321 const char *mod = *pp; 2321 const char *mod = *pp;
2322 if (!ModMatchEq(mod, "range", st->endc)) 2322 if (!ModMatchEq(mod, "range", st->endc))
2323 return AMR_UNKNOWN; 2323 return AMR_UNKNOWN;
2324 2324
2325 if (mod[5] == '=') { 2325 if (mod[5] == '=') {
2326 const char *p = mod + 6; 2326 const char *p = mod + 6;
2327 if (!TryParseSize(&p, &n)) { 2327 if (!TryParseSize(&p, &n)) {
2328 Parse_Error(PARSE_FATAL, "Invalid number: %s\n", mod + 6); 2328 Parse_Error(PARSE_FATAL, "Invalid number: %s\n", mod + 6);
2329 return AMR_CLEANUP; 2329 return AMR_CLEANUP;
2330 } 2330 }
2331 *pp = p; 2331 *pp = p;
2332 } else { 2332 } else {
2333 n = 0; 2333 n = 0;
2334 *pp = mod + 5; 2334 *pp = mod + 5;
2335 } 2335 }
2336 2336
2337 if (n == 0) { 2337 if (n == 0) {
2338 Words words = Str_Words(st->val, FALSE); 2338 Words words = Str_Words(st->val, FALSE);
2339 n = words.len; 2339 n = words.len;
2340 Words_Free(words); 2340 Words_Free(words);
2341 } 2341 }
2342 2342
2343 Buf_Init(&buf, 0); 2343 Buf_Init(&buf, 0);
2344 2344
2345 for (i = 0; i < n; i++) { 2345 for (i = 0; i < n; i++) {
2346 if (i != 0) 2346 if (i != 0)
2347 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2347 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2348 Buf_AddInt(&buf, 1 + (int)i); 2348 Buf_AddInt(&buf, 1 + (int)i);
2349 } 2349 }
2350 2350
2351 st->newVal = Buf_Destroy(&buf, FALSE); 2351 st->newVal = Buf_Destroy(&buf, FALSE);
2352 return AMR_OK; 2352 return AMR_OK;
2353} 2353}
2354 2354
2355/* :Mpattern or :Npattern */ 2355/* :Mpattern or :Npattern */
2356static ApplyModifierResult 2356static ApplyModifierResult
2357ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2357ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2358{ 2358{
2359 const char *mod = *pp; 2359 const char *mod = *pp;
2360 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2360 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2361 Boolean needSubst = FALSE; 2361 Boolean needSubst = FALSE;
2362 const char *endpat; 2362 const char *endpat;
2363 char *pattern; 2363 char *pattern;
2364 ModifyWordsCallback callback; 2364 ModifyWordsCallback callback;
2365 2365
2366 /* 2366 /*
2367 * In the loop below, ignore ':' unless we are at (or back to) the 2367 * In the loop below, ignore ':' unless we are at (or back to) the
2368 * original brace level. 2368 * original brace level.
2369 * XXX This will likely not work right if $() and ${} are intermixed. 2369 * XXX This will likely not work right if $() and ${} are intermixed.
2370 */ 2370 */
2371 int nest = 0; 2371 int nest = 0;
2372 const char *p; 2372 const char *p;
2373 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2373 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2374 if (*p == '\\' && 2374 if (*p == '\\' &&
2375 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2375 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2376 if (!needSubst) 2376 if (!needSubst)
2377 copy = TRUE; 2377 copy = TRUE;
2378 p++; 2378 p++;
2379 continue; 2379 continue;
2380 } 2380 }
2381 if (*p == '$') 2381 if (*p == '$')
2382 needSubst = TRUE; 2382 needSubst = TRUE;
2383 if (*p == '(' || *p == '{') 2383 if (*p == '(' || *p == '{')
2384 nest++; 2384 nest++;
2385 if (*p == ')' || *p == '}') { 2385 if (*p == ')' || *p == '}') {
2386 nest--; 2386 nest--;
2387 if (nest < 0) 2387 if (nest < 0)
2388 break; 2388 break;
2389 } 2389 }
2390 } 2390 }
2391 *pp = p; 2391 *pp = p;
2392 endpat = p; 2392 endpat = p;
2393 2393
2394 if (copy) { 2394 if (copy) {
2395 char *dst; 2395 char *dst;
2396 const char *src; 2396 const char *src;
2397 2397
2398 /* Compress the \:'s out of the pattern. */ 2398 /* Compress the \:'s out of the pattern. */
2399 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2399 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2400 dst = pattern; 2400 dst = pattern;
2401 src = mod + 1; 2401 src = mod + 1;
2402 for (; src < endpat; src++, dst++) { 2402 for (; src < endpat; src++, dst++) {
2403 if (src[0] == '\\' && src + 1 < endpat && 2403 if (src[0] == '\\' && src + 1 < endpat &&
2404 /* XXX: st->startc is missing here; see above */ 2404 /* XXX: st->startc is missing here; see above */
2405 (src[1] == ':' || src[1] == st->endc)) 2405 (src[1] == ':' || src[1] == st->endc))
2406 src++; 2406 src++;
2407 *dst = *src; 2407 *dst = *src;
2408 } 2408 }
2409 *dst = '\0'; 2409 *dst = '\0';
2410 endpat = dst; 2410 endpat = dst;
2411 } else { 2411 } else {
2412 pattern = bmake_strsedup(mod + 1, endpat); 2412 pattern = bmake_strsedup(mod + 1, endpat);
2413 } 2413 }
2414 2414
2415 if (needSubst) { 2415 if (needSubst) {
2416 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2416 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2417 char *old_pattern = pattern; 2417 char *old_pattern = pattern;
2418 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2418 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2419 /* TODO: handle errors */ 2419 /* TODO: handle errors */
2420 free(old_pattern); 2420 free(old_pattern);
2421 } 2421 }
2422 2422
2423 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2423 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2424 2424
2425 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2425 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2426 st->newVal = ModifyWords(st->val, callback, pattern, 2426 st->newVal = ModifyWords(st->val, callback, pattern,
2427 st->oneBigWord, st->sep); 2427 st->oneBigWord, st->sep);
2428 free(pattern); 2428 free(pattern);
2429 return AMR_OK; 2429 return AMR_OK;
2430} 2430}
2431 2431
2432/* :S,from,to, */ 2432/* :S,from,to, */
2433static ApplyModifierResult 2433static ApplyModifierResult
2434ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2434ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2435{ 2435{
2436 struct ModifyWord_SubstArgs args; 2436 struct ModifyWord_SubstArgs args;
2437 char *lhs, *rhs; 2437 char *lhs, *rhs;
2438 Boolean oneBigWord; 2438 Boolean oneBigWord;
2439 VarParseResult res; 2439 VarParseResult res;
2440 2440
2441 char delim = (*pp)[1]; 2441 char delim = (*pp)[1];
2442 if (delim == '\0') { 2442 if (delim == '\0') {
2443 Error("Missing delimiter for :S modifier"); 2443 Error("Missing delimiter for :S modifier");
2444 (*pp)++; 2444 (*pp)++;
2445 return AMR_CLEANUP; 2445 return AMR_CLEANUP;
2446 } 2446 }
2447 2447
2448 *pp += 2; 2448 *pp += 2;
2449 2449
2450 args.pflags = 0; 2450 args.pflags = 0;
2451 args.matched = FALSE; 2451 args.matched = FALSE;
2452 2452
2453 /* 2453 /*
2454 * If pattern begins with '^', it is anchored to the 2454 * If pattern begins with '^', it is anchored to the
2455 * start of the word -- skip over it and flag pattern. 2455 * start of the word -- skip over it and flag pattern.
2456 */ 2456 */
2457 if (**pp == '^') { 2457 if (**pp == '^') {
2458 args.pflags |= VARP_ANCHOR_START; 2458 args.pflags |= VARP_ANCHOR_START;
2459 (*pp)++; 2459 (*pp)++;
2460 } 2460 }
2461 2461
2462 res = ParseModifierPart(pp, delim, st->eflags, st, 2462 res = ParseModifierPart(pp, delim, st->eflags, st,
2463 &lhs, &args.lhsLen, &args.pflags, NULL); 2463 &lhs, &args.lhsLen, &args.pflags, NULL);
2464 if (res != VPR_OK) 2464 if (res != VPR_OK)
2465 return AMR_CLEANUP; 2465 return AMR_CLEANUP;
2466 args.lhs = lhs; 2466 args.lhs = lhs;
2467 2467
2468 res = ParseModifierPart(pp, delim, st->eflags, st, 2468 res = ParseModifierPart(pp, delim, st->eflags, st,
2469 &rhs, &args.rhsLen, NULL, &args); 2469 &rhs, &args.rhsLen, NULL, &args);
2470 if (res != VPR_OK) 2470 if (res != VPR_OK)
2471 return AMR_CLEANUP; 2471 return AMR_CLEANUP;
2472 args.rhs = rhs; 2472 args.rhs = rhs;
2473 2473
2474 oneBigWord = st->oneBigWord; 2474 oneBigWord = st->oneBigWord;
2475 for (;; (*pp)++) { 2475 for (;; (*pp)++) {
2476 switch (**pp) { 2476 switch (**pp) {
2477 case 'g': 2477 case 'g':
2478 args.pflags |= VARP_SUB_GLOBAL; 2478 args.pflags |= VARP_SUB_GLOBAL;
2479 continue; 2479 continue;
2480 case '1': 2480 case '1':
2481 args.pflags |= VARP_SUB_ONE; 2481 args.pflags |= VARP_SUB_ONE;
2482 continue; 2482 continue;
2483 case 'W': 2483 case 'W':
2484 oneBigWord = TRUE; 2484 oneBigWord = TRUE;
2485 continue; 2485 continue;
2486 } 2486 }
2487 break; 2487 break;
2488 } 2488 }
2489 2489
2490 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args, 2490 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
2491 oneBigWord, st->sep); 2491 oneBigWord, st->sep);
2492 2492
2493 free(lhs); 2493 free(lhs);
2494 free(rhs); 2494 free(rhs);
2495 return AMR_OK; 2495 return AMR_OK;
2496} 2496}
2497 2497
2498#ifndef NO_REGEX 2498#ifndef NO_REGEX
2499 2499
2500/* :C,from,to, */ 2500/* :C,from,to, */
2501static ApplyModifierResult 2501static ApplyModifierResult
2502ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2502ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2503{ 2503{
2504 char *re; 2504 char *re;
2505 struct ModifyWord_SubstRegexArgs args; 2505 struct ModifyWord_SubstRegexArgs args;
2506 Boolean oneBigWord; 2506 Boolean oneBigWord;
2507 int error; 2507 int error;
2508 VarParseResult res; 2508 VarParseResult res;
2509 2509
2510 char delim = (*pp)[1]; 2510 char delim = (*pp)[1];
2511 if (delim == '\0') { 2511 if (delim == '\0') {
2512 Error("Missing delimiter for :C modifier"); 2512 Error("Missing delimiter for :C modifier");
2513 (*pp)++; 2513 (*pp)++;
2514 return AMR_CLEANUP; 2514 return AMR_CLEANUP;
2515 } 2515 }
2516 2516
2517 *pp += 2; 2517 *pp += 2;
2518 2518
2519 res = ParseModifierPart(pp, delim, st->eflags, st, 2519 res = ParseModifierPart(pp, delim, st->eflags, st,
2520 &re, NULL, NULL, NULL); 2520 &re, NULL, NULL, NULL);
2521 if (res != VPR_OK) 2521 if (res != VPR_OK)
2522 return AMR_CLEANUP; 2522 return AMR_CLEANUP;
2523 2523
2524 res = ParseModifierPart(pp, delim, st->eflags, st, 2524 res = ParseModifierPart(pp, delim, st->eflags, st,
2525 &args.replace, NULL, NULL, NULL); 2525 &args.replace, NULL, NULL, NULL);
2526 if (args.replace == NULL) { 2526 if (args.replace == NULL) {
2527 free(re); 2527 free(re);
2528 return AMR_CLEANUP; 2528 return AMR_CLEANUP;
2529 } 2529 }
2530 2530
2531 args.pflags = 0; 2531 args.pflags = 0;
2532 args.matched = FALSE; 2532 args.matched = FALSE;
2533 oneBigWord = st->oneBigWord; 2533 oneBigWord = st->oneBigWord;
2534 for (;; (*pp)++) { 2534 for (;; (*pp)++) {
2535 switch (**pp) { 2535 switch (**pp) {
2536 case 'g': 2536 case 'g':
2537 args.pflags |= VARP_SUB_GLOBAL; 2537 args.pflags |= VARP_SUB_GLOBAL;
2538 continue; 2538 continue;
2539 case '1': 2539 case '1':
2540 args.pflags |= VARP_SUB_ONE; 2540 args.pflags |= VARP_SUB_ONE;
2541 continue; 2541 continue;
2542 case 'W': 2542 case 'W':
2543 oneBigWord = TRUE; 2543 oneBigWord = TRUE;
2544 continue; 2544 continue;
2545 } 2545 }
2546 break; 2546 break;
2547 } 2547 }
2548 2548
2549 error = regcomp(&args.re, re, REG_EXTENDED); 2549 error = regcomp(&args.re, re, REG_EXTENDED);
2550 free(re); 2550 free(re);
2551 if (error) { 2551 if (error) {
2552 VarREError(error, &args.re, "Regex compilation error"); 2552 VarREError(error, &args.re, "Regex compilation error");
2553 free(args.replace); 2553 free(args.replace);
2554 return AMR_CLEANUP; 2554 return AMR_CLEANUP;
2555 } 2555 }
2556 2556
2557 args.nsub = args.re.re_nsub + 1; 2557 args.nsub = args.re.re_nsub + 1;
2558 if (args.nsub > 10) 2558 if (args.nsub > 10)
2559 args.nsub = 10; 2559 args.nsub = 10;
2560 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args, 2560 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
2561 oneBigWord, st->sep); 2561 oneBigWord, st->sep);
2562 regfree(&args.re); 2562 regfree(&args.re);
2563 free(args.replace); 2563 free(args.replace);
2564 return AMR_OK; 2564 return AMR_OK;
2565} 2565}
2566#endif 2566#endif
2567 2567
2568/* :Q, :q */ 2568/* :Q, :q */
2569static ApplyModifierResult 2569static ApplyModifierResult
2570ApplyModifier_Quote(const char **pp, ApplyModifiersState *st) 2570ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
2571{ 2571{
2572 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2572 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2573 st->newVal = VarQuote(st->val, **pp == 'q'); 2573 st->newVal = VarQuote(st->val, **pp == 'q');
2574 (*pp)++; 2574 (*pp)++;
2575 return AMR_OK; 2575 return AMR_OK;
2576 } else 2576 } else
2577 return AMR_UNKNOWN; 2577 return AMR_UNKNOWN;
2578} 2578}
2579 2579
2580static void 2580static void
2581ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2581ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2582{ 2582{
2583 SepBuf_AddStr(buf, word); 2583 SepBuf_AddStr(buf, word);
2584} 2584}
2585 2585
2586/* :ts<separator> */ 2586/* :ts<separator> */
2587static ApplyModifierResult 2587static ApplyModifierResult
2588ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2588ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2589{ 2589{
2590 const char *sep = *pp + 2; 2590 const char *sep = *pp + 2;
2591 2591
2592 /* ":ts<any><endc>" or ":ts<any>:" */ 2592 /* ":ts<any><endc>" or ":ts<any>:" */
2593 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2593 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2594 st->sep = sep[0]; 2594 st->sep = sep[0];
2595 *pp = sep + 1; 2595 *pp = sep + 1;
2596 goto ok; 2596 goto ok;
2597 } 2597 }
2598 2598
2599 /* ":ts<endc>" or ":ts:" */ 2599 /* ":ts<endc>" or ":ts:" */
2600 if (sep[0] == st->endc || sep[0] == ':') { 2600 if (sep[0] == st->endc || sep[0] == ':') {
2601 st->sep = '\0'; /* no separator */ 2601 st->sep = '\0'; /* no separator */
2602 *pp = sep; 2602 *pp = sep;
2603 goto ok; 2603 goto ok;
2604 } 2604 }
2605 2605
2606 /* ":ts<unrecognised><unrecognised>". */ 2606 /* ":ts<unrecognised><unrecognised>". */
2607 if (sep[0] != '\\') { 2607 if (sep[0] != '\\') {
2608 (*pp)++; /* just for backwards compatibility */ 2608 (*pp)++; /* just for backwards compatibility */
2609 return AMR_BAD; 2609 return AMR_BAD;
2610 } 2610 }
2611 2611
2612 /* ":ts\n" */ 2612 /* ":ts\n" */
2613 if (sep[1] == 'n') { 2613 if (sep[1] == 'n') {
2614 st->sep = '\n'; 2614 st->sep = '\n';
2615 *pp = sep + 2; 2615 *pp = sep + 2;
2616 goto ok; 2616 goto ok;
2617 } 2617 }
2618 2618
2619 /* ":ts\t" */ 2619 /* ":ts\t" */
2620 if (sep[1] == 't') { 2620 if (sep[1] == 't') {
2621 st->sep = '\t'; 2621 st->sep = '\t';
2622 *pp = sep + 2; 2622 *pp = sep + 2;
2623 goto ok; 2623 goto ok;
2624 } 2624 }
2625 2625
2626 /* ":ts\x40" or ":ts\100" */ 2626 /* ":ts\x40" or ":ts\100" */
2627 { 2627 {
2628 const char *p = sep + 1; 2628 const char *p = sep + 1;
2629 int base = 8; /* assume octal */ 2629 int base = 8; /* assume octal */
2630 2630
2631 if (sep[1] == 'x') { 2631 if (sep[1] == 'x') {
2632 base = 16; 2632 base = 16;
2633 p++; 2633 p++;
2634 } else if (!ch_isdigit(sep[1])) { 2634 } else if (!ch_isdigit(sep[1])) {
2635 (*pp)++; /* just for backwards compatibility */ 2635 (*pp)++; /* just for backwards compatibility */
2636 return AMR_BAD; /* ":ts<backslash><unrecognised>". */ 2636 return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2637 } 2637 }
2638 2638
2639 if (!TryParseChar(&p, base, &st->sep)) { 2639 if (!TryParseChar(&p, base, &st->sep)) {
2640 Parse_Error(PARSE_FATAL, "Invalid character number: %s\n", p); 2640 Parse_Error(PARSE_FATAL, "Invalid character number: %s\n", p);
2641 return AMR_CLEANUP; 2641 return AMR_CLEANUP;
2642 } 2642 }
2643 if (*p != ':' && *p != st->endc) { 2643 if (*p != ':' && *p != st->endc) {
2644 (*pp)++; /* just for backwards compatibility */ 2644 (*pp)++; /* just for backwards compatibility */
2645 return AMR_BAD; 2645 return AMR_BAD;
2646 } 2646 }
2647 2647
2648 *pp = p; 2648 *pp = p;
2649 } 2649 }
2650 2650
2651ok: 2651ok:
2652 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL, 2652 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
2653 st->oneBigWord, st->sep); 2653 st->oneBigWord, st->sep);
2654 return AMR_OK; 2654 return AMR_OK;
2655} 2655}
2656 2656
2657/* :tA, :tu, :tl, :ts<separator>, etc. */ 2657/* :tA, :tu, :tl, :ts<separator>, etc. */
2658static ApplyModifierResult 2658static ApplyModifierResult
2659ApplyModifier_To(const char **pp, ApplyModifiersState *st) 2659ApplyModifier_To(const char **pp, ApplyModifiersState *st)
2660{ 2660{
2661 const char *mod = *pp; 2661 const char *mod = *pp;
2662 assert(mod[0] == 't'); 2662 assert(mod[0] == 't');
2663 2663
2664 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { 2664 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2665 *pp = mod + 1; 2665 *pp = mod + 1;
2666 return AMR_BAD; /* Found ":t<endc>" or ":t:". */ 2666 return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2667 } 2667 }
2668 2668
2669 if (mod[1] == 's') 2669 if (mod[1] == 's')
2670 return ApplyModifier_ToSep(pp, st); 2670 return ApplyModifier_ToSep(pp, st);
2671 2671
2672 if (mod[2] != st->endc && mod[2] != ':') { 2672 if (mod[2] != st->endc && mod[2] != ':') {
2673 *pp = mod + 1; 2673 *pp = mod + 1;
2674 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ 2674 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2675 } 2675 }
2676 2676
2677 /* Check for two-character options: ":tu", ":tl" */ 2677 /* Check for two-character options: ":tu", ":tl" */
2678 if (mod[1] == 'A') { /* absolute path */ 2678 if (mod[1] == 'A') { /* absolute path */
2679 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL, 2679 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
2680 st->oneBigWord, st->sep); 2680 st->oneBigWord, st->sep);
2681 *pp = mod + 2; 2681 *pp = mod + 2;
2682 return AMR_OK; 2682 return AMR_OK;
2683 } 2683 }
2684 2684
2685 if (mod[1] == 'u') { /* :tu */ 2685 if (mod[1] == 'u') { /* :tu */
2686 size_t i; 2686 size_t i;
2687 size_t len = strlen(st->val); 2687 size_t len = strlen(st->val);
2688 st->newVal = bmake_malloc(len + 1); 2688 st->newVal = bmake_malloc(len + 1);
2689 for (i = 0; i < len + 1; i++) 2689 for (i = 0; i < len + 1; i++)
2690 st->newVal[i] = ch_toupper(st->val[i]); 2690 st->newVal[i] = ch_toupper(st->val[i]);
2691 *pp = mod + 2; 2691 *pp = mod + 2;
2692 return AMR_OK; 2692 return AMR_OK;
2693 } 2693 }
2694 2694
2695 if (mod[1] == 'l') { /* :tl */ 2695 if (mod[1] == 'l') { /* :tl */
2696 size_t i; 2696 size_t i;
2697 size_t len = strlen(st->val); 2697 size_t len = strlen(st->val);
2698 st->newVal = bmake_malloc(len + 1); 2698 st->newVal = bmake_malloc(len + 1);
2699 for (i = 0; i < len + 1; i++) 2699 for (i = 0; i < len + 1; i++)
2700 st->newVal[i] = ch_tolower(st->val[i]); 2700 st->newVal[i] = ch_tolower(st->val[i]);
2701 *pp = mod + 2; 2701 *pp = mod + 2;
2702 return AMR_OK; 2702 return AMR_OK;
2703 } 2703 }
2704 2704
2705 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ 2705 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2706 st->oneBigWord = mod[1] == 'W'; 2706 st->oneBigWord = mod[1] == 'W';
2707 st->newVal = st->val; 2707 st->newVal = st->val;
2708 *pp = mod + 2; 2708 *pp = mod + 2;
2709 return AMR_OK; 2709 return AMR_OK;
2710 } 2710 }
2711 2711
2712 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2712 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2713 *pp = mod + 1; 2713 *pp = mod + 1;
2714 return AMR_BAD; 2714 return AMR_BAD;
2715} 2715}
2716 2716
2717/* :[#], :[1], :[-1..1], etc. */ 2717/* :[#], :[1], :[-1..1], etc. */
2718static ApplyModifierResult 2718static ApplyModifierResult
2719ApplyModifier_Words(const char **pp, ApplyModifiersState *st) 2719ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
2720{ 2720{
2721 char *estr; 2721 char *estr;
2722 int first, last; 2722 int first, last;
2723 VarParseResult res; 2723 VarParseResult res;
2724 const char *p; 2724 const char *p;
2725 2725
2726 (*pp)++; /* skip the '[' */ 2726 (*pp)++; /* skip the '[' */
2727 res = ParseModifierPart(pp, ']', st->eflags, st, 2727 res = ParseModifierPart(pp, ']', st->eflags, st,
2728 &estr, NULL, NULL, NULL); 2728 &estr, NULL, NULL, NULL);
2729 if (res != VPR_OK) 2729 if (res != VPR_OK)
2730 return AMR_CLEANUP; 2730 return AMR_CLEANUP;
2731 2731
2732 /* now *pp points just after the closing ']' */ 2732 /* now *pp points just after the closing ']' */
2733 if (**pp != ':' && **pp != st->endc) 2733 if (**pp != ':' && **pp != st->endc)
2734 goto bad_modifier; /* Found junk after ']' */ 2734 goto bad_modifier; /* Found junk after ']' */
2735 2735
2736 if (estr[0] == '\0') 2736 if (estr[0] == '\0')
2737 goto bad_modifier; /* empty square brackets in ":[]". */ 2737 goto bad_modifier; /* empty square brackets in ":[]". */
2738 2738
2739 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2739 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2740 if (st->oneBigWord) { 2740 if (st->oneBigWord) {
2741 st->newVal = bmake_strdup("1"); 2741 st->newVal = bmake_strdup("1");
2742 } else { 2742 } else {
2743 Buffer buf; 2743 Buffer buf;
2744 2744
2745 Words words = Str_Words(st->val, FALSE); 2745 Words words = Str_Words(st->val, FALSE);
2746 size_t ac = words.len; 2746 size_t ac = words.len;
2747 Words_Free(words); 2747 Words_Free(words);
2748 2748
2749 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */ 2749 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */
2750 Buf_AddInt(&buf, (int)ac); 2750 Buf_AddInt(&buf, (int)ac);
2751 st->newVal = Buf_Destroy(&buf, FALSE); 2751 st->newVal = Buf_Destroy(&buf, FALSE);
2752 } 2752 }
2753 goto ok; 2753 goto ok;
2754 } 2754 }
2755 2755
2756 if (estr[0] == '*' && estr[1] == '\0') { 2756 if (estr[0] == '*' && estr[1] == '\0') {
2757 /* Found ":[*]" */ 2757 /* Found ":[*]" */
2758 st->oneBigWord = TRUE; 2758 st->oneBigWord = TRUE;
2759 st->newVal = st->val; 2759 st->newVal = st->val;
2760 goto ok; 2760 goto ok;
2761 } 2761 }
2762 2762
2763 if (estr[0] == '@' && estr[1] == '\0') { 2763 if (estr[0] == '@' && estr[1] == '\0') {
2764 /* Found ":[@]" */ 2764 /* Found ":[@]" */
2765 st->oneBigWord = FALSE; 2765 st->oneBigWord = FALSE;
2766 st->newVal = st->val; 2766 st->newVal = st->val;
2767 goto ok; 2767 goto ok;
2768 } 2768 }
2769 2769
2770 /* 2770 /*
2771 * We expect estr to contain a single integer for :[N], or two integers 2771 * We expect estr to contain a single integer for :[N], or two integers
2772 * separated by ".." for :[start..end]. 2772 * separated by ".." for :[start..end].
2773 */ 2773 */
2774 p = estr; 2774 p = estr;
2775 if (!TryParseIntBase0(&p, &first)) 2775 if (!TryParseIntBase0(&p, &first))
2776 goto bad_modifier; /* Found junk instead of a number */ 2776 goto bad_modifier; /* Found junk instead of a number */
2777 2777
2778 if (p[0] == '\0') { /* Found only one integer in :[N] */ 2778 if (p[0] == '\0') { /* Found only one integer in :[N] */
2779 last = first; 2779 last = first;
2780 } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') { 2780 } else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
2781 /* Expecting another integer after ".." */ 2781 /* Expecting another integer after ".." */
2782 p += 2; 2782 p += 2;
2783 if (!TryParseIntBase0(&p, &last) || *p != '\0') 2783 if (!TryParseIntBase0(&p, &last) || *p != '\0')
2784 goto bad_modifier; /* Found junk after ".." */ 2784 goto bad_modifier; /* Found junk after ".." */
2785 } else 2785 } else
2786 goto bad_modifier; /* Found junk instead of ".." */ 2786 goto bad_modifier; /* Found junk instead of ".." */
2787 2787
2788 /* 2788 /*
2789 * Now first and last are properly filled in, but we still have to check 2789 * Now first and last are properly filled in, but we still have to check
2790 * for 0 as a special case. 2790 * for 0 as a special case.
2791 */ 2791 */
2792 if (first == 0 && last == 0) { 2792 if (first == 0 && last == 0) {
2793 /* ":[0]" or perhaps ":[0..0]" */ 2793 /* ":[0]" or perhaps ":[0..0]" */
2794 st->oneBigWord = TRUE; 2794 st->oneBigWord = TRUE;
2795 st->newVal = st->val; 2795 st->newVal = st->val;
2796 goto ok; 2796 goto ok;
2797 } 2797 }
2798 2798
2799 /* ":[0..N]" or ":[N..0]" */ 2799 /* ":[0..N]" or ":[N..0]" */
2800 if (first == 0 || last == 0) 2800 if (first == 0 || last == 0)
2801 goto bad_modifier; 2801 goto bad_modifier;
2802 2802
2803 /* Normal case: select the words described by first and last. */ 2803 /* Normal case: select the words described by first and last. */
2804 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last); 2804 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last);
2805 2805
2806ok: 2806ok:
2807 free(estr); 2807 free(estr);
2808 return AMR_OK; 2808 return AMR_OK;
2809 2809
2810bad_modifier: 2810bad_modifier:
2811 free(estr); 2811 free(estr);
2812 return AMR_BAD; 2812 return AMR_BAD;
2813} 2813}
2814 2814
2815static int 2815static int
2816str_cmp_asc(const void *a, const void *b) 2816str_cmp_asc(const void *a, const void *b)
2817{ 2817{
2818 return strcmp(*(const char * const *)a, *(const char * const *)b); 2818 return strcmp(*(const char * const *)a, *(const char * const *)b);
2819} 2819}
2820 2820
2821static int 2821static int
2822str_cmp_desc(const void *a, const void *b) 2822str_cmp_desc(const void *a, const void *b)
2823{ 2823{
2824 return strcmp(*(const char * const *)b, *(const char * const *)a); 2824 return strcmp(*(const char * const *)b, *(const char * const *)a);
2825} 2825}
2826 2826
2827/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ 2827/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
2828static ApplyModifierResult 2828static ApplyModifierResult
2829ApplyModifier_Order(const char **pp, ApplyModifiersState *st) 2829ApplyModifier_Order(const char **pp, ApplyModifiersState *st)
2830{ 2830{
2831 const char *mod = (*pp)++; /* skip past the 'O' in any case */ 2831 const char *mod = (*pp)++; /* skip past the 'O' in any case */
2832 2832
2833 Words words = Str_Words(st->val, FALSE); 2833 Words words = Str_Words(st->val, FALSE);
2834 2834
2835 if (mod[1] == st->endc || mod[1] == ':') { 2835 if (mod[1] == st->endc || mod[1] == ':') {
2836 /* :O sorts ascending */ 2836 /* :O sorts ascending */
2837 qsort(words.words, words.len, sizeof(char *), str_cmp_asc); 2837 qsort(words.words, words.len, sizeof(char *), str_cmp_asc);
2838 2838
2839 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2839 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2840 (mod[2] == st->endc || mod[2] == ':')) { 2840 (mod[2] == st->endc || mod[2] == ':')) {
2841 (*pp)++; 2841 (*pp)++;
2842 2842
2843 if (mod[1] == 'r') { 2843 if (mod[1] == 'r') {
2844 /* :Or sorts descending */ 2844 /* :Or sorts descending */
2845 qsort(words.words, words.len, sizeof(char *), str_cmp_desc); 2845 qsort(words.words, words.len, sizeof(char *), str_cmp_desc);
2846 2846
2847 } else { 2847 } else {
2848 /* :Ox shuffles 2848 /* :Ox shuffles
2849 * 2849 *
2850 * We will use [ac..2] range for mod factors. This will produce 2850 * We will use [ac..2] range for mod factors. This will produce
2851 * random numbers in [(ac-1)..0] interval, and minimal 2851 * random numbers in [(ac-1)..0] interval, and minimal
2852 * reasonable value for mod factor is 2 (the mod 1 will produce 2852 * reasonable value for mod factor is 2 (the mod 1 will produce
2853 * 0 with probability 1). 2853 * 0 with probability 1).
2854 */ 2854 */
2855 size_t i; 2855 size_t i;
2856 for (i = words.len - 1; i > 0; i--) { 2856 for (i = words.len - 1; i > 0; i--) {
2857 size_t rndidx = (size_t)random() % (i + 1); 2857 size_t rndidx = (size_t)random() % (i + 1);
2858 char *t = words.words[i]; 2858 char *t = words.words[i];
2859 words.words[i] = words.words[rndidx]; 2859 words.words[i] = words.words[rndidx];
2860 words.words[rndidx] = t; 2860 words.words[rndidx] = t;
2861 } 2861 }
2862 } 2862 }
2863 } else { 2863 } else {
2864 Words_Free(words); 2864 Words_Free(words);
2865 return AMR_BAD; 2865 return AMR_BAD;
2866 } 2866 }
2867 2867
2868 st->newVal = Words_JoinFree(words); 2868 st->newVal = Words_JoinFree(words);
2869 return AMR_OK; 2869 return AMR_OK;
2870} 2870}
2871 2871
2872/* :? then : else */ 2872/* :? then : else */
2873static ApplyModifierResult 2873static ApplyModifierResult
2874ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) 2874ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
2875{ 2875{
2876 char *then_expr, *else_expr; 2876 char *then_expr, *else_expr;
2877 VarParseResult res; 2877 VarParseResult res;
2878 2878
2879 Boolean value = FALSE; 2879 Boolean value = FALSE;
2880 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2880 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2881 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2881 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2882 2882
2883 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */ 2883 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
2884 if (st->eflags & VARE_WANTRES) { 2884 if (st->eflags & VARE_WANTRES) {
2885 cond_rc = Cond_EvalCondition(st->v->name, &value); 2885 cond_rc = Cond_EvalCondition(st->v->name, &value);
2886 if (cond_rc != COND_INVALID && value) 2886 if (cond_rc != COND_INVALID && value)
2887 then_eflags |= VARE_WANTRES; 2887 then_eflags |= VARE_WANTRES;
2888 if (cond_rc != COND_INVALID && !value) 2888 if (cond_rc != COND_INVALID && !value)
2889 else_eflags |= VARE_WANTRES; 2889 else_eflags |= VARE_WANTRES;
2890 } 2890 }
2891 2891
2892 (*pp)++; /* skip past the '?' */ 2892 (*pp)++; /* skip past the '?' */
2893 res = ParseModifierPart(pp, ':', then_eflags, st, 2893 res = ParseModifierPart(pp, ':', then_eflags, st,
2894 &then_expr, NULL, NULL, NULL); 2894 &then_expr, NULL, NULL, NULL);
2895 if (res != VPR_OK) 2895 if (res != VPR_OK)
2896 return AMR_CLEANUP; 2896 return AMR_CLEANUP;
2897 2897
2898 res = ParseModifierPart(pp, st->endc, else_eflags, st, 2898 res = ParseModifierPart(pp, st->endc, else_eflags, st,
2899 &else_expr, NULL, NULL, NULL); 2899 &else_expr, NULL, NULL, NULL);
2900 if (res != VPR_OK) 2900 if (res != VPR_OK)
2901 return AMR_CLEANUP; 2901 return AMR_CLEANUP;
2902 2902
2903 (*pp)--; 2903 (*pp)--;
2904 if (cond_rc == COND_INVALID) { 2904 if (cond_rc == COND_INVALID) {
2905 Error("Bad conditional expression `%s' in %s?%s:%s", 2905 Error("Bad conditional expression `%s' in %s?%s:%s",
2906 st->v->name, st->v->name, then_expr, else_expr); 2906 st->v->name, st->v->name, then_expr, else_expr);
2907 return AMR_CLEANUP; 2907 return AMR_CLEANUP;
2908 } 2908 }
2909 2909
2910 if (value) { 2910 if (value) {
2911 st->newVal = then_expr; 2911 st->newVal = then_expr;
2912 free(else_expr); 2912 free(else_expr);
2913 } else { 2913 } else {
2914 st->newVal = else_expr; 2914 st->newVal = else_expr;
2915 free(then_expr); 2915 free(then_expr);
2916 } 2916 }
2917 ApplyModifiersState_Define(st); 2917 ApplyModifiersState_Define(st);
2918 return AMR_OK; 2918 return AMR_OK;
2919} 2919}
2920 2920
2921/* 2921/*
2922 * The ::= modifiers actually assign a value to the variable. 2922 * The ::= modifiers actually assign a value to the variable.
2923 * Their main purpose is in supporting modifiers of .for loop 2923 * Their main purpose is in supporting modifiers of .for loop
2924 * iterators and other obscure uses. They always expand to 2924 * iterators and other obscure uses. They always expand to
2925 * nothing. In a target rule that would otherwise expand to an 2925 * nothing. In a target rule that would otherwise expand to an
2926 * empty line they can be preceded with @: to keep make happy. 2926 * empty line they can be preceded with @: to keep make happy.
2927 * Eg. 2927 * Eg.
2928 * 2928 *
2929 * foo: .USE 2929 * foo: .USE
2930 * .for i in ${.TARGET} ${.TARGET:R}.gz 2930 * .for i in ${.TARGET} ${.TARGET:R}.gz
2931 * @: ${t::=$i} 2931 * @: ${t::=$i}
2932 * @echo blah ${t:T} 2932 * @echo blah ${t:T}
2933 * .endfor 2933 * .endfor
2934 * 2934 *
2935 * ::=<str> Assigns <str> as the new value of variable. 2935 * ::=<str> Assigns <str> as the new value of variable.
2936 * ::?=<str> Assigns <str> as value of variable if 2936 * ::?=<str> Assigns <str> as value of variable if
2937 * it was not already set. 2937 * it was not already set.
2938 * ::+=<str> Appends <str> to variable. 2938 * ::+=<str> Appends <str> to variable.
2939 * ::!=<cmd> Assigns output of <cmd> as the new value of 2939 * ::!=<cmd> Assigns output of <cmd> as the new value of
2940 * variable. 2940 * variable.
2941 */ 2941 */
2942static ApplyModifierResult 2942static ApplyModifierResult
2943ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) 2943ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
2944{ 2944{
2945 GNode *v_ctxt; 2945 GNode *v_ctxt;
2946 char delim; 2946 char delim;
2947 char *val; 2947 char *val;
2948 VarParseResult res; 2948 VarParseResult res;
2949 2949
2950 const char *mod = *pp; 2950 const char *mod = *pp;
2951 const char *op = mod + 1; 2951 const char *op = mod + 1;
2952 2952
2953 if (op[0] == '=') 2953 if (op[0] == '=')
2954 goto ok; 2954 goto ok;
2955 if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=') 2955 if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
2956 goto ok; 2956 goto ok;
2957 return AMR_UNKNOWN; /* "::<unrecognised>" */ 2957 return AMR_UNKNOWN; /* "::<unrecognised>" */
2958ok: 2958ok:
2959 2959
2960 if (st->v->name[0] == '\0') { 2960 if (st->v->name[0] == '\0') {
2961 *pp = mod + 1; 2961 *pp = mod + 1;
2962 return AMR_BAD; 2962 return AMR_BAD;
2963 } 2963 }
2964 2964
2965 v_ctxt = st->ctxt; /* context where v belongs */ 2965 v_ctxt = st->ctxt; /* context where v belongs */
2966 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) { 2966 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
2967 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2967 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2968 if (gv == NULL) 2968 if (gv == NULL)
2969 v_ctxt = VAR_GLOBAL; 2969 v_ctxt = VAR_GLOBAL;
2970 else 2970 else
2971 VarFreeEnv(gv, TRUE); 2971 VarFreeEnv(gv, TRUE);
2972 } 2972 }
2973 2973
2974 switch (op[0]) { 2974 switch (op[0]) {
2975 case '+': 2975 case '+':
2976 case '?': 2976 case '?':
2977 case '!': 2977 case '!':
2978 *pp = mod + 3; 2978 *pp = mod + 3;
2979 break; 2979 break;
2980 default: 2980 default:
2981 *pp = mod + 2; 2981 *pp = mod + 2;
2982 break; 2982 break;
2983 } 2983 }
2984 2984
2985 delim = st->startc == '(' ? ')' : '}'; 2985 delim = st->startc == '(' ? ')' : '}';
2986 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL); 2986 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL);
2987 if (res != VPR_OK) 2987 if (res != VPR_OK)
2988 return AMR_CLEANUP; 2988 return AMR_CLEANUP;
2989 2989
2990 (*pp)--; 2990 (*pp)--;
2991 2991
2992 if (st->eflags & VARE_WANTRES) { 2992 if (st->eflags & VARE_WANTRES) {
2993 switch (op[0]) { 2993 switch (op[0]) {
2994 case '+': 2994 case '+':
2995 Var_Append(st->v->name, val, v_ctxt); 2995 Var_Append(st->v->name, val, v_ctxt);
2996 break; 2996 break;
2997 case '!': { 2997 case '!': {
2998 const char *errfmt; 2998 const char *errfmt;
2999 char *cmd_output = Cmd_Exec(val, &errfmt); 2999 char *cmd_output = Cmd_Exec(val, &errfmt);
3000 if (errfmt) 3000 if (errfmt)
3001 Error(errfmt, val); 3001 Error(errfmt, val);
3002 else 3002 else
3003 Var_Set(st->v->name, cmd_output, v_ctxt); 3003 Var_Set(st->v->name, cmd_output, v_ctxt);
3004 free(cmd_output); 3004 free(cmd_output);
3005 break; 3005 break;
3006 } 3006 }
3007 case '?': 3007 case '?':
3008 if (!(st->exprFlags & VEF_UNDEF)) 3008 if (!(st->exprFlags & VEF_UNDEF))
3009 break; 3009 break;
3010 /* FALLTHROUGH */ 3010 /* FALLTHROUGH */
3011 default: 3011 default:
3012 Var_Set(st->v->name, val, v_ctxt); 3012 Var_Set(st->v->name, val, v_ctxt);
3013 break; 3013 break;
3014 } 3014 }
3015 } 3015 }
3016 free(val); 3016 free(val);
3017 st->newVal = emptyString; 3017 st->newVal = emptyString;
3018 return AMR_OK; 3018 return AMR_OK;
3019} 3019}
3020 3020
3021/* :_=... 3021/* :_=...
3022 * remember current value */ 3022 * remember current value */
3023static ApplyModifierResult 3023static ApplyModifierResult
3024ApplyModifier_Remember(const char **pp, ApplyModifiersState *st) 3024ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
3025{ 3025{
3026 const char *mod = *pp; 3026 const char *mod = *pp;
3027 if (!ModMatchEq(mod, "_", st->endc)) 3027 if (!ModMatchEq(mod, "_", st->endc))
3028 return AMR_UNKNOWN; 3028 return AMR_UNKNOWN;
3029 3029
3030 if (mod[1] == '=') { 3030 if (mod[1] == '=') {
3031 size_t n = strcspn(mod + 2, ":)}"); 3031 size_t n = strcspn(mod + 2, ":)}");
3032 char *name = bmake_strldup(mod + 2, n); 3032 char *name = bmake_strldup(mod + 2, n);
3033 Var_Set(name, st->val, st->ctxt); 3033 Var_Set(name, st->val, st->ctxt);
3034 free(name); 3034 free(name);
3035 *pp = mod + 2 + n; 3035 *pp = mod + 2 + n;
3036 } else { 3036 } else {
3037 Var_Set("_", st->val, st->ctxt); 3037 Var_Set("_", st->val, st->ctxt);
3038 *pp = mod + 1; 3038 *pp = mod + 1;
3039 } 3039 }
3040 st->newVal = st->val; 3040 st->newVal = st->val;
3041 return AMR_OK; 3041 return AMR_OK;
3042} 3042}
3043 3043
3044/* Apply the given function to each word of the variable value, 3044/* Apply the given function to each word of the variable value,
3045 * for a single-letter modifier such as :H, :T. */ 3045 * for a single-letter modifier such as :H, :T. */
3046static ApplyModifierResult 3046static ApplyModifierResult
3047ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, 3047ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
3048 ModifyWordsCallback modifyWord) 3048 ModifyWordsCallback modifyWord)
3049{ 3049{
3050 char delim = (*pp)[1]; 3050 char delim = (*pp)[1];
3051 if (delim != st->endc && delim != ':') 3051 if (delim != st->endc && delim != ':')
3052 return AMR_UNKNOWN; 3052 return AMR_UNKNOWN;
3053 3053
3054 st->newVal = ModifyWords(st->val, modifyWord, NULL, 3054 st->newVal = ModifyWords(st->val, modifyWord, NULL,
3055 st->oneBigWord, st->sep); 3055 st->oneBigWord, st->sep);
3056 (*pp)++; 3056 (*pp)++;
3057 return AMR_OK; 3057 return AMR_OK;
3058} 3058}
3059 3059
3060static ApplyModifierResult 3060static ApplyModifierResult
3061ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) 3061ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
3062{ 3062{
3063 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 3063 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
3064 st->newVal = VarUniq(st->val); 3064 st->newVal = VarUniq(st->val);
3065 (*pp)++; 3065 (*pp)++;
3066 return AMR_OK; 3066 return AMR_OK;
3067 } else 3067 } else
3068 return AMR_UNKNOWN; 3068 return AMR_UNKNOWN;
3069} 3069}
3070 3070
3071#ifdef SYSVVARSUB 3071#ifdef SYSVVARSUB
3072/* :from=to */ 3072/* :from=to */
3073static ApplyModifierResult 3073static ApplyModifierResult
3074ApplyModifier_SysV(const char **pp, ApplyModifiersState *st) 3074ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
3075{ 3075{
3076 char *lhs, *rhs; 3076 char *lhs, *rhs;
3077 VarParseResult res; 3077 VarParseResult res;
3078 3078
3079 const char *mod = *pp; 3079 const char *mod = *pp;
3080 Boolean eqFound = FALSE; 3080 Boolean eqFound = FALSE;
3081 3081
3082 /* 3082 /*
3083 * First we make a pass through the string trying to verify it is a 3083 * First we make a pass through the string trying to verify it is a
3084 * SysV-make-style translation. It must be: <lhs>=<rhs> 3084 * SysV-make-style translation. It must be: <lhs>=<rhs>
3085 */ 3085 */
3086 int depth = 1; 3086 int depth = 1;
3087 const char *p = mod; 3087 const char *p = mod;
3088 while (*p != '\0' && depth > 0) { 3088 while (*p != '\0' && depth > 0) {
3089 if (*p == '=') { /* XXX: should also test depth == 1 */ 3089 if (*p == '=') { /* XXX: should also test depth == 1 */
3090 eqFound = TRUE; 3090 eqFound = TRUE;
3091 /* continue looking for st->endc */ 3091 /* continue looking for st->endc */
3092 } else if (*p == st->endc) 3092 } else if (*p == st->endc)
3093 depth--; 3093 depth--;
3094 else if (*p == st->startc) 3094 else if (*p == st->startc)
3095 depth++; 3095 depth++;
3096 if (depth > 0) 3096 if (depth > 0)
3097 p++; 3097 p++;
3098 } 3098 }
3099 if (*p != st->endc || !eqFound) 3099 if (*p != st->endc || !eqFound)
3100 return AMR_UNKNOWN; 3100 return AMR_UNKNOWN;
3101 3101
3102 *pp = mod; 3102 *pp = mod;
3103 res = ParseModifierPart(pp, '=', st->eflags, st, 3103 res = ParseModifierPart(pp, '=', st->eflags, st,
3104 &lhs, NULL, NULL, NULL); 3104 &lhs, NULL, NULL, NULL);
3105 if (res != VPR_OK) 3105 if (res != VPR_OK)
3106 return AMR_CLEANUP; 3106 return AMR_CLEANUP;
3107 3107
3108 /* The SysV modifier lasts until the end of the variable expression. */ 3108 /* The SysV modifier lasts until the end of the variable expression. */
3109 res = ParseModifierPart(pp, st->endc, st->eflags, st, 3109 res = ParseModifierPart(pp, st->endc, st->eflags, st,
3110 &rhs, NULL, NULL, NULL); 3110 &rhs, NULL, NULL, NULL);
3111 if (res != VPR_OK) 3111 if (res != VPR_OK)
3112 return AMR_CLEANUP; 3112 return AMR_CLEANUP;
3113 3113
3114 (*pp)--; 3114 (*pp)--;
3115 if (lhs[0] == '\0' && st->val[0] == '\0') { 3115 if (lhs[0] == '\0' && st->val[0] == '\0') {
3116 st->newVal = st->val; /* special case */ 3116 st->newVal = st->val; /* special case */
3117 } else { 3117 } else {
3118 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs}; 3118 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs};
3119 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args, 3119 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args,
3120 st->oneBigWord, st->sep); 3120 st->oneBigWord, st->sep);
3121 } 3121 }
3122 free(lhs); 3122 free(lhs);
3123 free(rhs); 3123 free(rhs);
3124 return AMR_OK; 3124 return AMR_OK;
3125} 3125}
3126#endif 3126#endif
3127 3127
3128#ifdef SUNSHCMD 3128#ifdef SUNSHCMD
3129/* :sh */ 3129/* :sh */
3130static ApplyModifierResult 3130static ApplyModifierResult
3131ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) 3131ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
3132{ 3132{
3133 const char *p = *pp; 3133 const char *p = *pp;
3134 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) { 3134 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3135 if (st->eflags & VARE_WANTRES) { 3135 if (st->eflags & VARE_WANTRES) {
3136 const char *errfmt; 3136 const char *errfmt;
3137 st->newVal = Cmd_Exec(st->val, &errfmt); 3137 st->newVal = Cmd_Exec(st->val, &errfmt);
3138 if (errfmt) 3138 if (errfmt)
3139 Error(errfmt, st->val); 3139 Error(errfmt, st->val);
3140 } else 3140 } else
3141 st->newVal = emptyString; 3141 st->newVal = emptyString;
3142 *pp = p + 2; 3142 *pp = p + 2;
3143 return AMR_OK; 3143 return AMR_OK;
3144 } else 3144 } else
3145 return AMR_UNKNOWN; 3145 return AMR_UNKNOWN;
3146} 3146}
3147#endif 3147#endif
3148 3148
3149static void 3149static void
3150LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc) 3150LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc)
3151{ 3151{
3152 char eflags_str[VarEvalFlags_ToStringSize]; 3152 char eflags_str[VarEvalFlags_ToStringSize];
3153 char vflags_str[VarFlags_ToStringSize]; 3153 char vflags_str[VarFlags_ToStringSize];
3154 char exprflags_str[VarExprFlags_ToStringSize]; 3154 char exprflags_str[VarExprFlags_ToStringSize];
3155 Boolean is_single_char = mod[0] != '\0' && 3155 Boolean is_single_char = mod[0] != '\0' &&
3156 (mod[1] == endc || mod[1] == ':'); 3156 (mod[1] == endc || mod[1] == ':');
3157 3157
3158 /* At this point, only the first character of the modifier can 3158 /* At this point, only the first character of the modifier can
3159 * be used since the end of the modifier is not yet known. */ 3159 * be used since the end of the modifier is not yet known. */
3160 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n", 3160 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
3161 st->v->name, mod[0], is_single_char ? "" : "...", st->val, 3161 st->v->name, mod[0], is_single_char ? "" : "...", st->val,
3162 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3162 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3163 st->eflags, VarEvalFlags_ToStringSpecs), 3163 st->eflags, VarEvalFlags_ToStringSpecs),
3164 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3164 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3165 st->v->flags, VarFlags_ToStringSpecs), 3165 st->v->flags, VarFlags_ToStringSpecs),
3166 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3166 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3167 st->exprFlags, 3167 st->exprFlags,
3168 VarExprFlags_ToStringSpecs)); 3168 VarExprFlags_ToStringSpecs));
3169} 3169}
3170 3170
3171static void 3171static void
3172LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod) 3172LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3173{ 3173{
3174 char eflags_str[VarEvalFlags_ToStringSize]; 3174 char eflags_str[VarEvalFlags_ToStringSize];
3175 char vflags_str[VarFlags_ToStringSize]; 3175 char vflags_str[VarFlags_ToStringSize];
3176 char exprflags_str[VarExprFlags_ToStringSize]; 3176 char exprflags_str[VarExprFlags_ToStringSize];
3177 const char *quot = st->newVal == var_Error ? "" : "\""; 3177 const char *quot = st->newVal == var_Error ? "" : "\"";
3178 const char *newVal = st->newVal == var_Error ? "error" : st->newVal; 3178 const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
3179 3179
3180 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n", 3180 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
3181 st->v->name, (int)(p - mod), mod, quot, newVal, quot, 3181 st->v->name, (int)(p - mod), mod, quot, newVal, quot,
3182 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3182 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3183 st->eflags, VarEvalFlags_ToStringSpecs), 3183 st->eflags, VarEvalFlags_ToStringSpecs),
3184 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3184 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3185 st->v->flags, VarFlags_ToStringSpecs), 3185 st->v->flags, VarFlags_ToStringSpecs),
3186 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3186 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3187 st->exprFlags, 3187 st->exprFlags,
3188 VarExprFlags_ToStringSpecs)); 3188 VarExprFlags_ToStringSpecs));
3189} 3189}
3190 3190
3191static ApplyModifierResult 3191static ApplyModifierResult
3192ApplyModifier(const char **pp, ApplyModifiersState *st) 3192ApplyModifier(const char **pp, ApplyModifiersState *st)
3193{ 3193{
3194 switch (**pp) { 3194 switch (**pp) {
3195 case ':': 3195 case ':':
3196 return ApplyModifier_Assign(pp, st); 3196 return ApplyModifier_Assign(pp, st);
3197 case '@': 3197 case '@':
3198 return ApplyModifier_Loop(pp, st); 3198 return ApplyModifier_Loop(pp, st);
3199 case '_': 3199 case '_':
3200 return ApplyModifier_Remember(pp, st); 3200 return ApplyModifier_Remember(pp, st);
3201 case 'D': 3201 case 'D':
3202 case 'U': 3202 case 'U':
3203 return ApplyModifier_Defined(pp, st); 3203 return ApplyModifier_Defined(pp, st);
3204 case 'L': 3204 case 'L':
3205 return ApplyModifier_Literal(pp, st); 3205 return ApplyModifier_Literal(pp, st);
3206 case 'P': 3206 case 'P':
3207 return ApplyModifier_Path(pp, st); 3207 return ApplyModifier_Path(pp, st);
3208 case '!': 3208 case '!':
3209 return ApplyModifier_ShellCommand(pp, st); 3209 return ApplyModifier_ShellCommand(pp, st);
3210 case '[': 3210 case '[':
3211 return ApplyModifier_Words(pp, st); 3211 return ApplyModifier_Words(pp, st);
3212 case 'g': 3212 case 'g':
3213 return ApplyModifier_Gmtime(pp, st); 3213 return ApplyModifier_Gmtime(pp, st);
3214 case 'h': 3214 case 'h':
3215 return ApplyModifier_Hash(pp, st); 3215 return ApplyModifier_Hash(pp, st);
3216 case 'l': 3216 case 'l':
3217 return ApplyModifier_Localtime(pp, st); 3217 return ApplyModifier_Localtime(pp, st);
3218 case 't': 3218 case 't':
3219 return ApplyModifier_To(pp, st); 3219 return ApplyModifier_To(pp, st);
3220 case 'N': 3220 case 'N':
3221 case 'M': 3221 case 'M':
3222 return ApplyModifier_Match(pp, st); 3222 return ApplyModifier_Match(pp, st);
3223 case 'S': 3223 case 'S':
3224 return ApplyModifier_Subst(pp, st); 3224 return ApplyModifier_Subst(pp, st);
3225 case '?': 3225 case '?':
3226 return ApplyModifier_IfElse(pp, st); 3226 return ApplyModifier_IfElse(pp, st);
3227#ifndef NO_REGEX 3227#ifndef NO_REGEX
3228 case 'C': 3228 case 'C':
3229 return ApplyModifier_Regex(pp, st); 3229 return ApplyModifier_Regex(pp, st);
3230#endif 3230#endif
3231 case 'q': 3231 case 'q':
3232 case 'Q': 3232 case 'Q':
3233 return ApplyModifier_Quote(pp, st); 3233 return ApplyModifier_Quote(pp, st);
3234 case 'T': 3234 case 'T':
3235 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail); 3235 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
3236 case 'H': 3236 case 'H':
3237 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head); 3237 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
3238 case 'E': 3238 case 'E':
3239 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix); 3239 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
3240 case 'R': 3240 case 'R':
3241 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root); 3241 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
3242 case 'r': 3242 case 'r':
3243 return ApplyModifier_Range(pp, st); 3243 return ApplyModifier_Range(pp, st);
3244 case 'O': 3244 case 'O':
3245 return ApplyModifier_Order(pp, st); 3245 return ApplyModifier_Order(pp, st);
3246 case 'u': 3246 case 'u':
3247 return ApplyModifier_Unique(pp, st); 3247 return ApplyModifier_Unique(pp, st);
3248#ifdef SUNSHCMD 3248#ifdef SUNSHCMD
3249 case 's': 3249 case 's':
3250 return ApplyModifier_SunShell(pp, st); 3250 return ApplyModifier_SunShell(pp, st);
3251#endif 3251#endif
3252 default: 3252 default:
3253 return AMR_UNKNOWN; 3253 return AMR_UNKNOWN;
3254 } 3254 }
3255} 3255}
3256 3256
 3257static char *ApplyModifiers(const char **, char *, char, char, Var *,
 3258 VarExprFlags *, GNode *, VarEvalFlags, void **);
 3259
 3260typedef enum ApplyModifiersIndirectResult {
 3261 AMIR_CONTINUE,
 3262 AMIR_APPLY_MODS,
 3263 AMIR_OUT
 3264} ApplyModifiersIndirectResult;
 3265
 3266/* While expanding a variable expression, expand and apply indirect
 3267 * modifiers. */
 3268static ApplyModifiersIndirectResult
 3269ApplyModifiersIndirect(
 3270 ApplyModifiersState *const st,
 3271 const char **inout_p,
 3272 void **const out_freeIt
 3273) {
 3274 const char *p = *inout_p;
 3275 const char *nested_p = p;
 3276 void *freeIt;
 3277 const char *rval;
 3278 char c;
 3279
 3280 (void)Var_Parse(&nested_p, st->ctxt, st->eflags, &rval, &freeIt);
 3281 /* TODO: handle errors */
 3282
 3283 /*
 3284 * If we have not parsed up to st->endc or ':', we are not
 3285 * interested. This means the expression ${VAR:${M_1}${M_2}}
 3286 * is not accepted, but ${VAR:${M_1}:${M_2}} is.
 3287 */
 3288 if (rval[0] != '\0' &&
 3289 (c = *nested_p) != '\0' && c != ':' && c != st->endc) {
 3290 if (DEBUG(LINT))
 3291 Parse_Error(PARSE_FATAL,
 3292 "Missing delimiter ':' after indirect modifier \"%.*s\"",
 3293 (int)(nested_p - p), p);
 3294
 3295 free(freeIt);
 3296 /* XXX: apply_mods doesn't sound like "not interested". */
 3297 /* XXX: Why is the indirect modifier parsed again by
 3298 * apply_mods? If any, p should be advanced to nested_p. */
 3299 return AMIR_APPLY_MODS;
 3300 }
 3301
 3302 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
 3303 rval, (int)(size_t)(nested_p - p), p);
 3304
 3305 p = nested_p;
 3306
 3307 if (rval[0] != '\0') {
 3308 const char *rval_pp = rval;
 3309 st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v,
 3310 &st->exprFlags, st->ctxt, st->eflags, out_freeIt);
 3311 if (st->val == var_Error
 3312 || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR))
 3313 || *rval_pp != '\0') {
 3314 free(freeIt);
 3315 *inout_p = p;
 3316 return AMIR_OUT; /* error already reported */
 3317 }
 3318 }
 3319 free(freeIt);
 3320
 3321 if (*p == ':')
 3322 p++;
 3323 else if (*p == '\0' && st->endc != '\0') {
 3324 Error("Unclosed variable specification after complex "
 3325 "modifier (expecting '%c') for %s", st->endc, st->v->name);
 3326 *inout_p = p;
 3327 return AMIR_OUT;
 3328 }
 3329
 3330 *inout_p = p;
 3331 return AMIR_CONTINUE;
 3332}
 3333
3257/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ 3334/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3258static char * 3335static char *
3259ApplyModifiers( 3336ApplyModifiers(
3260 const char **pp, /* the parsing position, updated upon return */ 3337 const char **pp, /* the parsing position, updated upon return */
3261 char *const val, /* the current value of the expression */ 3338 char *const val, /* the current value of the expression */
3262 char const startc, /* '(' or '{', or '\0' for indirect modifiers */ 3339 char const startc, /* '(' or '{', or '\0' for indirect modifiers */
3263 char const endc, /* ')' or '}', or '\0' for indirect modifiers */ 3340 char const endc, /* ')' or '}', or '\0' for indirect modifiers */
3264 Var * const v, 3341 Var * const v,
3265 VarExprFlags *exprFlags, 3342 VarExprFlags *exprFlags,
3266 GNode * const ctxt, /* for looking up and modifying variables */ 3343 GNode * const ctxt, /* for looking up and modifying variables */
3267 VarEvalFlags const eflags, 3344 VarEvalFlags const eflags,
3268 void ** const out_freeIt /* free this after using the return value */ 3345 void ** const out_freeIt /* free this after using the return value */
3269) { 3346) {
3270 ApplyModifiersState st = { 3347 ApplyModifiersState st = {
3271 startc, endc, v, ctxt, eflags, 3348 startc, endc, v, ctxt, eflags,
3272 val, /* .val */ 3349 val, /* .val */
3273 var_Error, /* .newVal */ 3350 var_Error, /* .newVal */
3274 ' ', /* .sep */ 3351 ' ', /* .sep */
3275 FALSE, /* .oneBigWord */ 3352 FALSE, /* .oneBigWord */
3276 *exprFlags /* .exprFlags */ 3353 *exprFlags /* .exprFlags */
3277 }; 3354 };
3278 const char *p; 3355 const char *p;
3279 const char *mod; 3356 const char *mod;
3280 ApplyModifierResult res; 3357 ApplyModifierResult res;
3281 3358
3282 assert(startc == '(' || startc == '{' || startc == '\0'); 3359 assert(startc == '(' || startc == '{' || startc == '\0');
3283 assert(endc == ')' || endc == '}' || endc == '\0'); 3360 assert(endc == ')' || endc == '}' || endc == '\0');
3284 assert(val != NULL); 3361 assert(val != NULL);
3285 3362
3286 p = *pp; 3363 p = *pp;
3287 while (*p != '\0' && *p != endc) { 3364 while (*p != '\0' && *p != endc) {
3288 3365
3289 if (*p == '$') { 3366 if (*p == '$') {
3290 /* 3367 ApplyModifiersIndirectResult amir;
3291 * We may have some complex modifiers in a variable. 3368 amir = ApplyModifiersIndirect(&st, &p, out_freeIt);
3292 */ 3369 if (amir == AMIR_CONTINUE)
3293 const char *nested_p = p; 3370 continue;
3294 void *freeIt; 3371 if (amir == AMIR_OUT)
3295 const char *rval; 3372 goto out;
3296 char c; 
3297 
3298 (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt); 
3299 /* TODO: handle errors */ 
3300 
3301 /* 
3302 * If we have not parsed up to st.endc or ':', we are not 
3303 * interested. This means the expression ${VAR:${M_1}${M_2}} 
3304 * is not accepted, but ${VAR:${M_1}:${M_2}} is. 
3305 */ 
3306 if (rval[0] != '\0' && 
3307 (c = *nested_p) != '\0' && c != ':' && c != st.endc) { 
3308 if (DEBUG(LINT)) 
3309 Parse_Error(PARSE_FATAL, 
3310 "Missing delimiter ':' after indirect modifier \"%.*s\"", 
3311 (int)(nested_p - p), p); 
3312 
3313 free(freeIt); 
3314 /* XXX: apply_mods doesn't sound like "not interested". */ 
3315 /* XXX: Why is the indirect modifier parsed again by 
3316 * apply_mods? If any, p should be advanced to nested_p. */ 
3317 goto apply_mods; 
3318 } 
3319 
3320 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", 
3321 rval, (int)(size_t)(nested_p - p), p); 
3322 
3323 p = nested_p; 
3324 
3325 if (rval[0] != '\0') { 
3326 const char *rval_pp = rval; 
3327 st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v, 
3328 &st.exprFlags, ctxt, eflags, out_freeIt); 
3329 if (st.val == var_Error 
3330 || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR)) 
3331 || *rval_pp != '\0') { 
3332 free(freeIt); 
3333 goto out; /* error already reported */ 
3334 } 
3335 } 
3336 free(freeIt); 
3337 
3338 if (*p == ':') 
3339 p++; 
3340 else if (*p == '\0' && endc != '\0') { 
3341 Error("Unclosed variable specification after complex " 
3342 "modifier (expecting '%c') for %s", st.endc, st.v->name); 
3343 goto out; 
3344 } 
3345 continue; 
3346 } 3373 }
3347 apply_mods: 
3348 st.newVal = var_Error; /* default value, in case of errors */ 3374 st.newVal = var_Error; /* default value, in case of errors */
3349 mod = p; 3375 mod = p;
3350 3376
3351 if (DEBUG(VAR)) 3377 if (DEBUG(VAR))
3352 LogBeforeApply(&st, mod, endc); 3378 LogBeforeApply(&st, mod, endc);
3353 3379
3354 res = ApplyModifier(&p, &st); 3380 res = ApplyModifier(&p, &st);
3355 3381
3356#ifdef SYSVVARSUB 3382#ifdef SYSVVARSUB
3357 if (res == AMR_UNKNOWN) { 3383 if (res == AMR_UNKNOWN) {
3358 assert(p == mod); 3384 assert(p == mod);
3359 res = ApplyModifier_SysV(&p, &st); 3385 res = ApplyModifier_SysV(&p, &st);
3360 } 3386 }
3361#endif 3387#endif
3362 3388
3363 if (res == AMR_UNKNOWN) { 3389 if (res == AMR_UNKNOWN) {
3364 Error("Unknown modifier '%c'", *mod); 3390 Error("Unknown modifier '%c'", *mod);
3365 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++) 3391 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
3366 continue; 3392 continue;
3367 st.newVal = var_Error; 3393 st.newVal = var_Error;
3368 } 3394 }
3369 if (res == AMR_CLEANUP) 3395 if (res == AMR_CLEANUP)
3370 goto cleanup; 3396 goto cleanup;
3371 if (res == AMR_BAD) 3397 if (res == AMR_BAD)
3372 goto bad_modifier; 3398 goto bad_modifier;
3373 3399
3374 if (DEBUG(VAR)) 3400 if (DEBUG(VAR))
3375 LogAfterApply(&st, p, mod); 3401 LogAfterApply(&st, p, mod);
3376 3402
3377 if (st.newVal != st.val) { 3403 if (st.newVal != st.val) {
3378 if (*out_freeIt) { 3404 if (*out_freeIt) {
3379 free(st.val); 3405 free(st.val);
3380 *out_freeIt = NULL; 3406 *out_freeIt = NULL;
3381 } 3407 }
3382 st.val = st.newVal; 3408 st.val = st.newVal;
3383 if (st.val != var_Error && st.val != varUndefined && 3409 if (st.val != var_Error && st.val != varUndefined &&
3384 st.val != emptyString) { 3410 st.val != emptyString) {
3385 *out_freeIt = st.val; 3411 *out_freeIt = st.val;
3386 } 3412 }
3387 } 3413 }
3388 if (*p == '\0' && st.endc != '\0') { 3414 if (*p == '\0' && st.endc != '\0') {
3389 Error("Unclosed variable specification (expecting '%c') " 3415 Error("Unclosed variable specification (expecting '%c') "
3390 "for \"%s\" (value \"%s\") modifier %c", 3416 "for \"%s\" (value \"%s\") modifier %c",
3391 st.endc, st.v->name, st.val, *mod); 3417 st.endc, st.v->name, st.val, *mod);
3392 } else if (*p == ':') { 3418 } else if (*p == ':') {
3393 p++; 3419 p++;
3394 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) { 3420 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) {
3395 Parse_Error(PARSE_FATAL, 3421 Parse_Error(PARSE_FATAL,
3396 "Missing delimiter ':' after modifier \"%.*s\"", 3422 "Missing delimiter ':' after modifier \"%.*s\"",
3397 (int)(p - mod), mod); 3423 (int)(p - mod), mod);
3398 } 3424 }
3399 } 3425 }
3400out: 3426out:
3401 *pp = p; 3427 *pp = p;
3402 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */ 3428 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
3403 *exprFlags = st.exprFlags; 3429 *exprFlags = st.exprFlags;
3404 return st.val; 3430 return st.val;
3405 3431
3406bad_modifier: 3432bad_modifier:
3407 Error("Bad modifier `:%.*s' for %s", 3433 Error("Bad modifier `:%.*s' for %s",
3408 (int)strcspn(mod, ":)}"), mod, st.v->name); 3434 (int)strcspn(mod, ":)}"), mod, st.v->name);
3409 3435
3410cleanup: 3436cleanup:
3411 *pp = p; 3437 *pp = p;
3412 free(*out_freeIt); 3438 free(*out_freeIt);
3413 *out_freeIt = NULL; 3439 *out_freeIt = NULL;
3414 *exprFlags = st.exprFlags; 3440 *exprFlags = st.exprFlags;
3415 return var_Error; 3441 return var_Error;
3416} 3442}
3417 3443
3418/* Only four of the local variables are treated specially as they are the 3444/* Only four of the local variables are treated specially as they are the
3419 * only four that will be set when dynamic sources are expanded. */ 3445 * only four that will be set when dynamic sources are expanded. */
3420static Boolean 3446static Boolean
3421VarnameIsDynamic(const char *name, size_t len) 3447VarnameIsDynamic(const char *name, size_t len)
3422{ 3448{
3423 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) { 3449 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3424 switch (name[0]) { 3450 switch (name[0]) {
3425 case '@': 3451 case '@':
3426 case '%': 3452 case '%':
3427 case '*': 3453 case '*':
3428 case '!': 3454 case '!':
3429 return TRUE; 3455 return TRUE;
3430 } 3456 }
3431 return FALSE; 3457 return FALSE;
3432 } 3458 }
3433 3459
3434 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) { 3460 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3435 return strcmp(name, ".TARGET") == 0 || 3461 return strcmp(name, ".TARGET") == 0 ||
3436 strcmp(name, ".ARCHIVE") == 0 || 3462 strcmp(name, ".ARCHIVE") == 0 ||
3437 strcmp(name, ".PREFIX") == 0 || 3463 strcmp(name, ".PREFIX") == 0 ||
3438 strcmp(name, ".MEMBER") == 0; 3464 strcmp(name, ".MEMBER") == 0;
3439 } 3465 }
3440 3466
3441 return FALSE; 3467 return FALSE;
3442} 3468}
3443 3469
3444static const char * 3470static const char *
3445UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3471UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3446{ 3472{
3447 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3473 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3448 /* 3474 /*
3449 * If substituting a local variable in a non-local context, 3475 * If substituting a local variable in a non-local context,
3450 * assume it's for dynamic source stuff. We have to handle 3476 * assume it's for dynamic source stuff. We have to handle
3451 * this specially and return the longhand for the variable 3477 * this specially and return the longhand for the variable
3452 * with the dollar sign escaped so it makes it back to the 3478 * with the dollar sign escaped so it makes it back to the
3453 * caller. Only four of the local variables are treated 3479 * caller. Only four of the local variables are treated
3454 * specially as they are the only four that will be set 3480 * specially as they are the only four that will be set
3455 * when dynamic sources are expanded. 3481 * when dynamic sources are expanded.
3456 */ 3482 */
3457 switch (varname) { 3483 switch (varname) {
3458 case '@': 3484 case '@':
3459 return "$(.TARGET)"; 3485 return "$(.TARGET)";
3460 case '%': 3486 case '%':
3461 return "$(.MEMBER)"; 3487 return "$(.MEMBER)";
3462 case '*': 3488 case '*':
3463 return "$(.PREFIX)"; 3489 return "$(.PREFIX)";
3464 case '!': 3490 case '!':
3465 return "$(.ARCHIVE)"; 3491 return "$(.ARCHIVE)";
3466 } 3492 }
3467 } 3493 }
3468 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3494 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3469} 3495}
3470 3496
3471/* Parse a variable name, until the end character or a colon, whichever 3497/* Parse a variable name, until the end character or a colon, whichever
3472 * comes first. */ 3498 * comes first. */
3473static char * 3499static char *
3474ParseVarname(const char **pp, char startc, char endc, 3500ParseVarname(const char **pp, char startc, char endc,
3475 GNode *ctxt, VarEvalFlags eflags, 3501 GNode *ctxt, VarEvalFlags eflags,
3476 size_t *out_varname_len) 3502 size_t *out_varname_len)
3477{ 3503{
3478 Buffer buf; 3504 Buffer buf;
3479 const char *p = *pp; 3505 const char *p = *pp;
3480 int depth = 1; 3506 int depth = 1;
3481 3507
3482 Buf_Init(&buf, 0); 3508 Buf_Init(&buf, 0);
3483 3509
3484 while (*p != '\0') { 3510 while (*p != '\0') {
3485 /* Track depth so we can spot parse errors. */ 3511 /* Track depth so we can spot parse errors. */
3486 if (*p == startc) 3512 if (*p == startc)
3487 depth++; 3513 depth++;
3488 if (*p == endc) { 3514 if (*p == endc) {
3489 if (--depth == 0) 3515 if (--depth == 0)
3490 break; 3516 break;
3491 } 3517 }
3492 if (*p == ':' && depth == 1) 3518 if (*p == ':' && depth == 1)
3493 break; 3519 break;
3494 3520
3495 /* A variable inside a variable, expand. */ 3521 /* A variable inside a variable, expand. */
3496 if (*p == '$') { 3522 if (*p == '$') {
3497 void *freeIt; 3523 void *freeIt;
3498 const char *rval; 3524 const char *rval;
3499 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3525 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3500 /* TODO: handle errors */ 3526 /* TODO: handle errors */
3501 Buf_AddStr(&buf, rval); 3527 Buf_AddStr(&buf, rval);
3502 free(freeIt); 3528 free(freeIt);
3503 } else { 3529 } else {
3504 Buf_AddByte(&buf, *p); 3530 Buf_AddByte(&buf, *p);
3505 p++; 3531 p++;
3506 } 3532 }
3507 } 3533 }
3508 *pp = p; 3534 *pp = p;
3509 *out_varname_len = Buf_Len(&buf); 3535 *out_varname_len = Buf_Len(&buf);
3510 return Buf_Destroy(&buf, FALSE); 3536 return Buf_Destroy(&buf, FALSE);
3511} 3537}
3512 3538
3513static Boolean 3539static Boolean
3514ValidShortVarname(char varname, const char *start) 3540ValidShortVarname(char varname, const char *start)
3515{ 3541{
3516 switch (varname) { 3542 switch (varname) {
3517 case '\0': 3543 case '\0':
3518 case ')': 3544 case ')':
3519 case '}': 3545 case '}':
3520 case ':': 3546 case ':':
3521 case '$': 3547 case '$':
3522 break; /* and continue below */ 3548 break; /* and continue below */
3523 default: 3549 default:
3524 return TRUE; 3550 return TRUE;
3525 } 3551 }
3526 3552
3527 if (!DEBUG(LINT)) 3553 if (!DEBUG(LINT))
3528 return FALSE; 3554 return FALSE;
3529 3555
3530 if (varname == '$') 3556 if (varname == '$')
3531 Parse_Error(PARSE_FATAL, 3557 Parse_Error(PARSE_FATAL,
3532 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3558 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3533 else if (varname == '\0') 3559 else if (varname == '\0')
3534 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3560 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3535 else 3561 else
3536 Parse_Error(PARSE_FATAL, 3562 Parse_Error(PARSE_FATAL,
3537 "Invalid variable name '%c', at \"%s\"", varname, start); 3563 "Invalid variable name '%c', at \"%s\"", varname, start);
3538 3564
3539 return FALSE; 3565 return FALSE;
3540} 3566}
3541 3567
3542/* Parse a single-character variable name such as $V or $@. 3568/* Parse a single-character variable name such as $V or $@.
3543 * Return whether to continue parsing. */ 3569 * Return whether to continue parsing. */
3544static Boolean 3570static Boolean
3545ParseVarnameShort( 3571ParseVarnameShort(
3546 char startc, 3572 char startc,
3547 const char **pp, 3573 const char **pp,
3548 GNode *ctxt, 3574 GNode *ctxt,
3549 VarEvalFlags eflags, 3575 VarEvalFlags eflags,
3550 VarParseResult *out_FALSE_res, 3576 VarParseResult *out_FALSE_res,
3551 const char **out_FALSE_val, 3577 const char **out_FALSE_val,
3552 Var **out_TRUE_var 3578 Var **out_TRUE_var
3553) { 3579) {
3554 char name[2]; 3580 char name[2];
3555 Var *v; 3581 Var *v;
3556 3582
3557 /* 3583 /*
3558 * If it's not bounded by braces of some sort, life is much simpler. 3584 * If it's not bounded by braces of some sort, life is much simpler.
3559 * We just need to check for the first character and return the 3585 * We just need to check for the first character and return the
3560 * value if it exists. 3586 * value if it exists.
3561 */ 3587 */
3562 3588
3563 if (!ValidShortVarname(startc, *pp)) { 3589 if (!ValidShortVarname(startc, *pp)) {
3564 (*pp)++; 3590 (*pp)++;
3565 *out_FALSE_val = var_Error; 3591 *out_FALSE_val = var_Error;
3566 *out_FALSE_res = VPR_PARSE_MSG; 3592 *out_FALSE_res = VPR_PARSE_MSG;
3567 return FALSE; 3593 return FALSE;
3568 } 3594 }
3569 3595
3570 name[0] = startc; 3596 name[0] = startc;
3571 name[1] = '\0'; 3597 name[1] = '\0';
3572 v = VarFind(name, ctxt, TRUE); 3598 v = VarFind(name, ctxt, TRUE);
3573 if (v == NULL) { 3599 if (v == NULL) {
3574 *pp += 2; 3600 *pp += 2;
3575 3601
3576 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3602 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3577 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3603 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3578 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3604 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3579 *out_FALSE_res = VPR_UNDEF_MSG; 3605 *out_FALSE_res = VPR_UNDEF_MSG;
3580 return FALSE; 3606 return FALSE;
3581 } 3607 }
3582 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3608 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3583 return FALSE; 3609 return FALSE;
3584 } 3610 }
3585 3611
3586 *out_TRUE_var = v; 3612 *out_TRUE_var = v;
3587 return TRUE; 3613 return TRUE;
3588} 3614}
3589 3615
3590/* Parse a long variable name enclosed in braces or parentheses such as $(VAR) 3616/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3591 * or ${VAR}, up to the closing brace or parenthesis, or in the case of 3617 * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3592 * ${VAR:Modifiers}, up to the ':' that starts the modifiers. 3618 * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3593 * Return whether to continue parsing. */ 3619 * Return whether to continue parsing. */
3594static Boolean 3620static Boolean
3595ParseVarnameLong( 3621ParseVarnameLong(
3596 const char **pp, 3622 const char **pp,
3597 char startc, 3623 char startc,
3598 GNode *ctxt, 3624 GNode *ctxt,
3599 VarEvalFlags eflags, 3625 VarEvalFlags eflags,
3600 3626
3601 VarParseResult *out_FALSE_res, 3627 VarParseResult *out_FALSE_res,
3602 const char **out_FALSE_val, 3628 const char **out_FALSE_val,
3603 void **out_FALSE_freePtr, 3629 void **out_FALSE_freePtr,
3604 3630
3605 char *out_TRUE_endc, 3631 char *out_TRUE_endc,
3606 const char **out_TRUE_p, 3632 const char **out_TRUE_p,
3607 Var **out_TRUE_v, 3633 Var **out_TRUE_v,
3608 Boolean *out_TRUE_haveModifier, 3634 Boolean *out_TRUE_haveModifier,
3609 const char **out_TRUE_extraModifiers, 3635 const char **out_TRUE_extraModifiers,
3610 Boolean *out_TRUE_dynamic, 3636 Boolean *out_TRUE_dynamic,
3611 VarExprFlags *out_TRUE_exprFlags 3637 VarExprFlags *out_TRUE_exprFlags
3612) { 3638) {
3613 size_t namelen; 3639 size_t namelen;
3614 char *varname; 3640 char *varname;
3615 Var *v; 3641 Var *v;
3616 Boolean haveModifier; 3642 Boolean haveModifier;
3617 Boolean dynamic = FALSE; 3643 Boolean dynamic = FALSE;
3618 3644
3619 const char *const start = *pp; 3645 const char *const start = *pp;
3620 char endc = startc == '(' ? ')' : '}'; 3646 char endc = startc == '(' ? ')' : '}';
3621 3647
3622 const char *p = start + 2; 3648 const char *p = start + 2;
3623 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3649 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3624 3650
3625 if (*p == ':') { 3651 if (*p == ':') {
3626 haveModifier = TRUE; 3652 haveModifier = TRUE;
3627 } else if (*p == endc) { 3653 } else if (*p == endc) {
3628 haveModifier = FALSE; 3654 haveModifier = FALSE;
3629 } else { 3655 } else {
3630 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3656 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3631 *pp = p; 3657 *pp = p;
3632 free(varname); 3658 free(varname);
3633 *out_FALSE_val = var_Error; 3659 *out_FALSE_val = var_Error;
3634 *out_FALSE_res = VPR_PARSE_MSG; 3660 *out_FALSE_res = VPR_PARSE_MSG;
3635 return FALSE; 3661 return FALSE;
3636 } 3662 }
3637 3663
3638 v = VarFind(varname, ctxt, TRUE); 3664 v = VarFind(varname, ctxt, TRUE);
3639 3665
3640 /* At this point, p points just after the variable name, 3666 /* At this point, p points just after the variable name,
3641 * either at ':' or at endc. */ 3667 * either at ':' or at endc. */
3642 3668
3643 /* 3669 /*
3644 * Check also for bogus D and F forms of local variables since we're 3670 * Check also for bogus D and F forms of local variables since we're
3645 * in a local context and the name is the right length. 3671 * in a local context and the name is the right length.
3646 */ 3672 */
3647 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3673 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3648 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3674 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3649 strchr("@%?*!<>", varname[0]) != NULL) 3675 strchr("@%?*!<>", varname[0]) != NULL)
3650 { 3676 {
3651 /* 3677 /*
3652 * Well, it's local -- go look for it. 3678 * Well, it's local -- go look for it.
3653 */ 3679 */
3654 char name[] = { varname[0], '\0' }; 3680 char name[] = { varname[0], '\0' };
3655 v = VarFind(name, ctxt, 0); 3681 v = VarFind(name, ctxt, 0);
3656 3682
3657 if (v != NULL) { 3683 if (v != NULL) {
3658 if (varname[1] == 'D') { 3684 if (varname[1] == 'D') {
3659 *out_TRUE_extraModifiers = "H:"; 3685 *out_TRUE_extraModifiers = "H:";
3660 } else { /* F */ 3686 } else { /* F */
3661 *out_TRUE_extraModifiers = "T:"; 3687 *out_TRUE_extraModifiers = "T:";
3662 } 3688 }
3663 } 3689 }
3664 } 3690 }
3665 3691
3666 if (v == NULL) { 3692 if (v == NULL) {
3667 /* Defer expansion of dynamic variables if they appear in non-local 3693 /* Defer expansion of dynamic variables if they appear in non-local
3668 * context since they are not defined there. */ 3694 * context since they are not defined there. */
3669 dynamic = VarnameIsDynamic(varname, namelen) && 3695 dynamic = VarnameIsDynamic(varname, namelen) &&
3670 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL); 3696 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
3671 3697
3672 if (!haveModifier) { 3698 if (!haveModifier) {
3673 p++; /* skip endc */ 3699 p++; /* skip endc */
3674 *pp = p; 3700 *pp = p;
3675 if (dynamic) { 3701 if (dynamic) {
3676 char *pstr = bmake_strsedup(start, p); 3702 char *pstr = bmake_strsedup(start, p);
3677 free(varname); 3703 free(varname);
3678 *out_FALSE_res = VPR_OK; 3704 *out_FALSE_res = VPR_OK;
3679 *out_FALSE_freePtr = pstr; 3705 *out_FALSE_freePtr = pstr;
3680 *out_FALSE_val = pstr; 3706 *out_FALSE_val = pstr;
3681 return FALSE; 3707 return FALSE;
3682 } 3708 }
3683 3709
3684 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3710 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3685 DEBUG(LINT)) 3711 DEBUG(LINT))
3686 { 3712 {
3687 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3713 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3688 varname); 3714 varname);
3689 free(varname); 3715 free(varname);
3690 *out_FALSE_res = VPR_UNDEF_MSG; 3716 *out_FALSE_res = VPR_UNDEF_MSG;
3691 *out_FALSE_val = var_Error; 3717 *out_FALSE_val = var_Error;
3692 return FALSE; 3718 return FALSE;
3693 } 3719 }
3694 3720
3695 if (eflags & VARE_UNDEFERR) { 3721 if (eflags & VARE_UNDEFERR) {
3696 free(varname); 3722 free(varname);
3697 *out_FALSE_res = VPR_UNDEF_SILENT; 3723 *out_FALSE_res = VPR_UNDEF_SILENT;
3698 *out_FALSE_val = var_Error; 3724 *out_FALSE_val = var_Error;
3699 return FALSE; 3725 return FALSE;
3700 } 3726 }
3701 3727
3702 free(varname); 3728 free(varname);
3703 *out_FALSE_res = VPR_OK; 3729 *out_FALSE_res = VPR_OK;
3704 *out_FALSE_val = varUndefined; 3730 *out_FALSE_val = varUndefined;
3705 return FALSE; 3731 return FALSE;
3706 } 3732 }
3707 3733
3708 /* The variable expression is based on an undefined variable. 3734 /* The variable expression is based on an undefined variable.
3709 * Nevertheless it needs a Var, for modifiers that access the 3735 * Nevertheless it needs a Var, for modifiers that access the
3710 * variable name, such as :L or :?. 3736 * variable name, such as :L or :?.
3711 * 3737 *
3712 * Most modifiers leave this expression in the "undefined" state 3738 * Most modifiers leave this expression in the "undefined" state
3713 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3739 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3714 * undefined expression into a defined expression (VEF_DEF). 3740 * undefined expression into a defined expression (VEF_DEF).
3715 * 3741 *
3716 * At the end, after applying all modifiers, if the expression 3742 * At the end, after applying all modifiers, if the expression
3717 * is still undefined, Var_Parse will return an empty string 3743 * is still undefined, Var_Parse will return an empty string
3718 * instead of the actually computed value. */ 3744 * instead of the actually computed value. */
3719 v = VarNew(varname, varname, "", 0); 3745 v = VarNew(varname, varname, "", 0);
3720 *out_TRUE_exprFlags = VEF_UNDEF; 3746 *out_TRUE_exprFlags = VEF_UNDEF;
3721 } else 3747 } else
3722 free(varname); 3748 free(varname);
3723 3749
3724 *out_TRUE_endc = endc; 3750 *out_TRUE_endc = endc;
3725 *out_TRUE_p = p; 3751 *out_TRUE_p = p;
3726 *out_TRUE_v = v; 3752 *out_TRUE_v = v;
3727 *out_TRUE_haveModifier = haveModifier; 3753 *out_TRUE_haveModifier = haveModifier;
3728 *out_TRUE_dynamic = dynamic; 3754 *out_TRUE_dynamic = dynamic;
3729 return TRUE; 3755 return TRUE;
3730} 3756}
3731 3757
3732/*- 3758/*-
3733 *----------------------------------------------------------------------- 3759 *-----------------------------------------------------------------------
3734 * Var_Parse -- 3760 * Var_Parse --
3735 * Given the start of a variable expression (such as $v, $(VAR), 3761 * Given the start of a variable expression (such as $v, $(VAR),
3736 * ${VAR:Mpattern}), extract the variable name, possibly some 3762 * ${VAR:Mpattern}), extract the variable name, possibly some
3737 * modifiers and find its value by applying the modifiers to the 3763 * modifiers and find its value by applying the modifiers to the
3738 * original value. 3764 * original value.
3739 * 3765 *
3740 * When parsing a condition in ParseEmptyArg, pp may also point to 3766 * When parsing a condition in ParseEmptyArg, pp may also point to
3741 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3767 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3742 * identical. 3768 * identical.
3743 * 3769 *
3744 * Input: 3770 * Input:
3745 * str The string to parse 3771 * str The string to parse
3746 * ctxt The context for the variable 3772 * ctxt The context for the variable
3747 * flags Select the exact details of parsing 3773 * flags Select the exact details of parsing
3748 * out_val_freeIt Must be freed by the caller after using out_val 3774 * out_val_freeIt Must be freed by the caller after using out_val
3749 * 3775 *
3750 * Results: 3776 * Results:
3751 * Returns the value of the variable expression, never NULL. 3777 * Returns the value of the variable expression, never NULL.
3752 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3778 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3753 * set. 3779 * set.
3754 * Returns varUndefined if there was an undefined variable and 3780 * Returns varUndefined if there was an undefined variable and
3755 * VARE_UNDEFERR was not set. 3781 * VARE_UNDEFERR was not set.
3756 * 3782 *
3757 * Parsing should continue at *pp. 3783 * Parsing should continue at *pp.
3758 * TODO: Document the value of *pp on parse errors. It might be advanced 3784 * TODO: Document the value of *pp on parse errors. It might be advanced
3759 * by 0, or +1, or the index of the parse error, or the guessed end of the 3785 * by 0, or +1, or the index of the parse error, or the guessed end of the
3760 * variable expression. 3786 * variable expression.
3761 * 3787 *
3762 * If var_Error is returned, a diagnostic may or may not have been 3788 * If var_Error is returned, a diagnostic may or may not have been
3763 * printed. XXX: This is inconsistent. 3789 * printed. XXX: This is inconsistent.
3764 * 3790 *
3765 * If varUndefined is returned, a diagnostic may or may not have been 3791 * If varUndefined is returned, a diagnostic may or may not have been
3766 * printed. XXX: This is inconsistent. 3792 * printed. XXX: This is inconsistent.
3767 * 3793 *
3768 * After using the returned value, *out_val_freeIt must be freed, 3794 * After using the returned value, *out_val_freeIt must be freed,
3769 * preferably using bmake_free since it is NULL in most cases. 3795 * preferably using bmake_free since it is NULL in most cases.
3770 * 3796 *
3771 * Side Effects: 3797 * Side Effects:
3772 * Any effects from the modifiers, such as :!cmd! or ::=value. 3798 * Any effects from the modifiers, such as :!cmd! or ::=value.
3773 *----------------------------------------------------------------------- 3799 *-----------------------------------------------------------------------
3774 */ 3800 */
3775/* coverity[+alloc : arg-*4] */ 3801/* coverity[+alloc : arg-*4] */
3776VarParseResult 3802VarParseResult
3777Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3803Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3778 const char **out_val, void **out_val_freeIt) 3804 const char **out_val, void **out_val_freeIt)
3779{ 3805{
3780 const char *const start = *pp; 3806 const char *const start = *pp;
3781 const char *p; 3807 const char *p;
3782 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3808 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3783 char startc; /* Starting character if variable in parens 3809 char startc; /* Starting character if variable in parens
3784 * or braces */ 3810 * or braces */
3785 char endc; /* Ending character if variable in parens 3811 char endc; /* Ending character if variable in parens
3786 * or braces */ 3812 * or braces */
3787 Boolean dynamic; /* TRUE if the variable is local and we're 3813 Boolean dynamic; /* TRUE if the variable is local and we're
3788 * expanding it in a non-local context. This 3814 * expanding it in a non-local context. This
3789 * is done to support dynamic sources. The 3815 * is done to support dynamic sources. The
3790 * result is just the expression, unaltered */ 3816 * result is just the expression, unaltered */
3791 const char *extramodifiers; 3817 const char *extramodifiers;
3792 Var *v; 3818 Var *v;
3793 char *nstr; 3819 char *nstr;
3794 char eflags_str[VarEvalFlags_ToStringSize]; 3820 char eflags_str[VarEvalFlags_ToStringSize];
3795 VarExprFlags exprFlags = 0; 3821 VarExprFlags exprFlags = 0;
3796 3822
3797 VAR_DEBUG2("Var_Parse: %s with %s\n", start, 3823 VAR_DEBUG2("Var_Parse: %s with %s\n", start,
3798 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3824 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3799 VarEvalFlags_ToStringSpecs)); 3825 VarEvalFlags_ToStringSpecs));
3800 3826
3801 *out_val_freeIt = NULL; 3827 *out_val_freeIt = NULL;
3802 extramodifiers = NULL; /* extra modifiers to apply first */ 3828 extramodifiers = NULL; /* extra modifiers to apply first */
3803 dynamic = FALSE; 3829 dynamic = FALSE;
3804 3830
3805 /* Appease GCC, which thinks that the variable might not be 3831 /* Appease GCC, which thinks that the variable might not be
3806 * initialized. */ 3832 * initialized. */
3807 endc = '\0'; 3833 endc = '\0';
3808 3834
3809 startc = start[1]; 3835 startc = start[1];
3810 if (startc != '(' && startc != '{') { 3836 if (startc != '(' && startc != '{') {
3811 VarParseResult res; 3837 VarParseResult res;
3812 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v)) 3838 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v))
3813 return res; 3839 return res;
3814 haveModifier = FALSE; 3840 haveModifier = FALSE;
3815 p = start + 1; 3841 p = start + 1;
3816 } else { 3842 } else {
3817 VarParseResult res; 3843 VarParseResult res;
3818 if (!ParseVarnameLong(pp, startc, ctxt, eflags, 3844 if (!ParseVarnameLong(pp, startc, ctxt, eflags,
3819 &res, out_val, out_val_freeIt, 3845 &res, out_val, out_val_freeIt,
3820 &endc, &p, &v, &haveModifier, &extramodifiers, 3846 &endc, &p, &v, &haveModifier, &extramodifiers,
3821 &dynamic, &exprFlags)) 3847 &dynamic, &exprFlags))
3822 return res; 3848 return res;
3823 } 3849 }
3824 3850
3825 if (v->flags & VAR_IN_USE) 3851 if (v->flags & VAR_IN_USE)
3826 Fatal("Variable %s is recursive.", v->name); 3852 Fatal("Variable %s is recursive.", v->name);
3827 3853
3828 /* 3854 /*
3829 * Before doing any modification, we have to make sure the value 3855 * Before doing any modification, we have to make sure the value
3830 * has been fully expanded. If it looks like recursion might be 3856 * has been fully expanded. If it looks like recursion might be
3831 * necessary (there's a dollar sign somewhere in the variable's value) 3857 * necessary (there's a dollar sign somewhere in the variable's value)
3832 * we just call Var_Subst to do any other substitutions that are 3858 * we just call Var_Subst to do any other substitutions that are
3833 * necessary. Note that the value returned by Var_Subst will have 3859 * necessary. Note that the value returned by Var_Subst will have
3834 * been dynamically-allocated, so it will need freeing when we 3860 * been dynamically-allocated, so it will need freeing when we
3835 * return. 3861 * return.
3836 */ 3862 */
3837 nstr = Buf_GetAll(&v->val, NULL); 3863 nstr = Buf_GetAll(&v->val, NULL);
3838 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) { 3864 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) {
3839 VarEvalFlags nested_eflags = eflags; 3865 VarEvalFlags nested_eflags = eflags;
3840 if (DEBUG(LINT)) 3866 if (DEBUG(LINT))
3841 nested_eflags &= ~(unsigned)VARE_UNDEFERR; 3867 nested_eflags &= ~(unsigned)VARE_UNDEFERR;
3842 v->flags |= VAR_IN_USE; 3868 v->flags |= VAR_IN_USE;
3843 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr); 3869 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr);
3844 v->flags &= ~(unsigned)VAR_IN_USE; 3870 v->flags &= ~(unsigned)VAR_IN_USE;
3845 /* TODO: handle errors */ 3871 /* TODO: handle errors */
3846 *out_val_freeIt = nstr; 3872 *out_val_freeIt = nstr;
3847 } 3873 }
3848 3874
3849 if (haveModifier || extramodifiers != NULL) { 3875 if (haveModifier || extramodifiers != NULL) {
3850 void *extraFree; 3876 void *extraFree;
3851 3877
3852 extraFree = NULL; 3878 extraFree = NULL;
3853 if (extramodifiers != NULL) { 3879 if (extramodifiers != NULL) {
3854 const char *em = extramodifiers; 3880 const char *em = extramodifiers;
3855 nstr = ApplyModifiers(&em, nstr, '(', ')', 3881 nstr = ApplyModifiers(&em, nstr, '(', ')',
3856 v, &exprFlags, ctxt, eflags, &extraFree); 3882 v, &exprFlags, ctxt, eflags, &extraFree);
3857 } 3883 }
3858 3884
3859 if (haveModifier) { 3885 if (haveModifier) {
3860 /* Skip initial colon. */ 3886 /* Skip initial colon. */
3861 p++; 3887 p++;
3862 3888
3863 nstr = ApplyModifiers(&p, nstr, startc, endc, 3889 nstr = ApplyModifiers(&p, nstr, startc, endc,
3864 v, &exprFlags, ctxt, eflags, out_val_freeIt); 3890 v, &exprFlags, ctxt, eflags, out_val_freeIt);
3865 free(extraFree); 3891 free(extraFree);
3866 } else { 3892 } else {
3867 *out_val_freeIt = extraFree; 3893 *out_val_freeIt = extraFree;
3868 } 3894 }
3869 } 3895 }
3870 3896
3871 if (*p != '\0') /* Skip past endc if possible. */ 3897 if (*p != '\0') /* Skip past endc if possible. */
3872 p++; 3898 p++;
3873 3899
3874 *pp = p; 3900 *pp = p;
3875 3901
3876 if (v->flags & VAR_FROM_ENV) { 3902 if (v->flags & VAR_FROM_ENV) {
3877 /* Free the environment variable now since we own it, 3903 /* Free the environment variable now since we own it,
3878 * but don't free the variable value if it will be returned. */ 3904 * but don't free the variable value if it will be returned. */
3879 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL); 3905 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL);
3880 if (keepValue) 3906 if (keepValue)
3881 *out_val_freeIt = nstr; 3907 *out_val_freeIt = nstr;
3882 (void)VarFreeEnv(v, !keepValue); 3908 (void)VarFreeEnv(v, !keepValue);
3883 3909
3884 } else if (exprFlags & VEF_UNDEF) { 3910 } else if (exprFlags & VEF_UNDEF) {
3885 if (!(exprFlags & VEF_DEF)) { 3911 if (!(exprFlags & VEF_DEF)) {
3886 if (*out_val_freeIt != NULL) { 3912 if (*out_val_freeIt != NULL) {
3887 free(*out_val_freeIt); 3913 free(*out_val_freeIt);
3888 *out_val_freeIt = NULL; 3914 *out_val_freeIt = NULL;
3889 } 3915 }
3890 if (dynamic) { 3916 if (dynamic) {
3891 nstr = bmake_strsedup(start, p); 3917 nstr = bmake_strsedup(start, p);
3892 *out_val_freeIt = nstr; 3918 *out_val_freeIt = nstr;
3893 } else { 3919 } else {
3894 /* The expression is still undefined, therefore discard the 3920 /* The expression is still undefined, therefore discard the
3895 * actual value and return an error marker instead. */ 3921 * actual value and return an error marker instead. */
3896 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined; 3922 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined;
3897 } 3923 }
3898 } 3924 }
3899 if (nstr != Buf_GetAll(&v->val, NULL)) 3925 if (nstr != Buf_GetAll(&v->val, NULL))
3900 Buf_Destroy(&v->val, TRUE); 3926 Buf_Destroy(&v->val, TRUE);
3901 free(v->name_freeIt); 3927 free(v->name_freeIt);
3902 free(v); 3928 free(v);
3903 } 3929 }
3904 *out_val = nstr; 3930 *out_val = nstr;
3905 return VPR_UNKNOWN; 3931 return VPR_UNKNOWN;
3906} 3932}
3907 3933
3908/* Substitute for all variables in the given string in the given context. 3934/* Substitute for all variables in the given string in the given context.
3909 * 3935 *
3910 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3936 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3911 * variable is encountered. 3937 * variable is encountered.
3912 * 3938 *
3913 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=, 3939 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=,
3914 * :sh or !cmd! take place. 3940 * :sh or !cmd! take place.
3915 * 3941 *
3916 * Input: 3942 * Input:
3917 * str the string which to substitute 3943 * str the string which to substitute
3918 * ctxt the context wherein to find variables 3944 * ctxt the context wherein to find variables
3919 * eflags VARE_UNDEFERR if undefineds are an error 3945 * eflags VARE_UNDEFERR if undefineds are an error
3920 * VARE_WANTRES if we actually want the result 3946 * VARE_WANTRES if we actually want the result
3921 * VARE_ASSIGN if we are in a := assignment 3947 * VARE_ASSIGN if we are in a := assignment
3922 * 3948 *
3923 * Results: 3949 * Results:
3924 * The resulting string. 3950 * The resulting string.
3925 */ 3951 */
3926VarParseResult 3952VarParseResult
3927Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res) 3953Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
3928{ 3954{
3929 const char *p = str; 3955 const char *p = str;
3930 Buffer buf; /* Buffer for forming things */ 3956 Buffer buf; /* Buffer for forming things */
3931 3957
3932 /* Set true if an error has already been reported, 3958 /* Set true if an error has already been reported,
3933 * to prevent a plethora of messages when recursing */ 3959 * to prevent a plethora of messages when recursing */
3934 static Boolean errorReported; 3960 static Boolean errorReported;
3935 3961
3936 Buf_Init(&buf, 0); 3962 Buf_Init(&buf, 0);
3937 errorReported = FALSE; 3963 errorReported = FALSE;
3938 3964
3939 while (*p != '\0') { 3965 while (*p != '\0') {
3940 if (p[0] == '$' && p[1] == '$') { 3966 if (p[0] == '$' && p[1] == '$') {
3941 /* A dollar sign may be escaped with another dollar sign. */ 3967 /* A dollar sign may be escaped with another dollar sign. */
3942 if (save_dollars && (eflags & VARE_ASSIGN)) 3968 if (save_dollars && (eflags & VARE_ASSIGN))
3943 Buf_AddByte(&buf, '$'); 3969 Buf_AddByte(&buf, '$');
3944 Buf_AddByte(&buf, '$'); 3970 Buf_AddByte(&buf, '$');
3945 p += 2; 3971 p += 2;
3946 } else if (*p != '$') { 3972 } else if (*p != '$') {
3947 /* 3973 /*
3948 * Skip as many characters as possible -- either to the end of 3974 * Skip as many characters as possible -- either to the end of
3949 * the string or to the next dollar sign (variable expression). 3975 * the string or to the next dollar sign (variable expression).
3950 */ 3976 */
3951 const char *plainStart = p; 3977 const char *plainStart = p;
3952 3978
3953 for (p++; *p != '$' && *p != '\0'; p++) 3979 for (p++; *p != '$' && *p != '\0'; p++)
3954 continue; 3980 continue;
3955 Buf_AddBytesBetween(&buf, plainStart, p); 3981 Buf_AddBytesBetween(&buf, plainStart, p);
3956 } else { 3982 } else {
3957 const char *nested_p = p; 3983 const char *nested_p = p;
3958 void *freeIt; 3984 void *freeIt;
3959 const char *val; 3985 const char *val;
3960 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt); 3986 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt);
3961 /* TODO: handle errors */ 3987 /* TODO: handle errors */
3962 3988
3963 if (val == var_Error || val == varUndefined) { 3989 if (val == var_Error || val == varUndefined) {
3964 /* 3990 /*
3965 * If performing old-time variable substitution, skip over 3991 * If performing old-time variable substitution, skip over
3966 * the variable and continue with the substitution. Otherwise, 3992 * the variable and continue with the substitution. Otherwise,
3967 * store the dollar sign and advance str so we continue with 3993 * store the dollar sign and advance str so we continue with
3968 * the string... 3994 * the string...
3969 */ 3995 */
3970 if (oldVars) { 3996 if (oldVars) {
3971 p = nested_p; 3997 p = nested_p;
3972 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 3998 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
3973 /* 3999 /*
3974 * If variable is undefined, complain and skip the 4000 * If variable is undefined, complain and skip the
3975 * variable. The complaint will stop us from doing anything 4001 * variable. The complaint will stop us from doing anything
3976 * when the file is parsed. 4002 * when the file is parsed.
3977 */ 4003 */
3978 if (!errorReported) { 4004 if (!errorReported) {
3979 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 4005 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
3980 (int)(size_t)(nested_p - p), p); 4006 (int)(size_t)(nested_p - p), p);
3981 } 4007 }
3982 p = nested_p; 4008 p = nested_p;
3983 errorReported = TRUE; 4009 errorReported = TRUE;
3984 } else { 4010 } else {
3985 /* Copy the initial '$' of the undefined expression, 4011 /* Copy the initial '$' of the undefined expression,
3986 * thereby deferring expansion of the expression, but 4012 * thereby deferring expansion of the expression, but
3987 * expand nested expressions if already possible. 4013 * expand nested expressions if already possible.
3988 * See unit-tests/varparse-undef-partial.mk. */ 4014 * See unit-tests/varparse-undef-partial.mk. */
3989 Buf_AddByte(&buf, *p); 4015 Buf_AddByte(&buf, *p);
3990 p++; 4016 p++;
3991 } 4017 }
3992 } else { 4018 } else {
3993 p = nested_p; 4019 p = nested_p;
3994 Buf_AddStr(&buf, val); 4020 Buf_AddStr(&buf, val);
3995 } 4021 }
3996 free(freeIt); 4022 free(freeIt);
3997 freeIt = NULL; 4023 freeIt = NULL;
3998 } 4024 }
3999 } 4025 }
4000 4026
4001 *out_res = Buf_DestroyCompact(&buf); 4027 *out_res = Buf_DestroyCompact(&buf);
4002 return VPR_OK; 4028 return VPR_OK;
4003} 4029}
4004 4030
4005/* Initialize the variables module. */ 4031/* Initialize the variables module. */
4006void 4032void
4007Var_Init(void) 4033Var_Init(void)
4008{ 4034{
4009 VAR_INTERNAL = Targ_NewGN("Internal"); 4035 VAR_INTERNAL = Targ_NewGN("Internal");
4010 VAR_GLOBAL = Targ_NewGN("Global"); 4036 VAR_GLOBAL = Targ_NewGN("Global");
4011 VAR_CMDLINE = Targ_NewGN("Command"); 4037 VAR_CMDLINE = Targ_NewGN("Command");
4012} 4038}
4013 4039
4014/* Clean up the variables module. */ 4040/* Clean up the variables module. */
4015void 4041void
4016Var_End(void) 4042Var_End(void)
4017{ 4043{
4018 Var_Stats(); 4044 Var_Stats();
4019} 4045}
4020 4046
4021void 4047void
4022Var_Stats(void) 4048Var_Stats(void)
4023{ 4049{
4024 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 4050 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
4025} 4051}
4026 4052
4027/* Print all variables in a context, sorted by name. */ 4053/* Print all variables in a context, sorted by name. */
4028void 4054void
4029Var_Dump(GNode *ctxt) 4055Var_Dump(GNode *ctxt)
4030{ 4056{
4031 Vector /* of const char * */ vec; 4057 Vector /* of const char * */ vec;
4032 HashIter hi; 4058 HashIter hi;
4033 size_t i; 4059 size_t i;
4034 const char **varnames; 4060 const char **varnames;
4035 4061
4036 Vector_Init(&vec, sizeof(const char *)); 4062 Vector_Init(&vec, sizeof(const char *));
4037 4063
4038 HashIter_Init(&hi, &ctxt->context); 4064 HashIter_Init(&hi, &ctxt->context);
4039 while (HashIter_Next(&hi) != NULL) 4065 while (HashIter_Next(&hi) != NULL)
4040 *(const char **)Vector_Push(&vec) = hi.entry->key; 4066 *(const char **)Vector_Push(&vec) = hi.entry->key;
4041 varnames = vec.items; 4067 varnames = vec.items;
4042 4068
4043 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc); 4069 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
4044 4070
4045 for (i = 0; i < vec.len; i++) { 4071 for (i = 0; i < vec.len; i++) {
4046 const char *varname = varnames[i]; 4072 const char *varname = varnames[i];
4047 Var *var = HashTable_FindValue(&ctxt->context, varname); 4073 Var *var = HashTable_FindValue(&ctxt->context, varname);
4048 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL)); 4074 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
4049 } 4075 }
4050 4076
4051 Vector_Done(&vec); 4077 Vector_Done(&vec);
4052} 4078}