Sat Oct 31 14:40:35 2020 UTC ()
make(1): extract ParseVarnameLong from Var_Parse


(rillig)
diff -r1.622 -r1.623 src/usr.bin/make/var.c

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

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