Sat Oct 31 15:23:52 2020 UTC ()
make(1): rewrite VarIsDynamic to VarnameIsDynamic

The condition for the context is the same for both short and long names,
therefore move that condition to the only caller.

Clean up the comment and move its parts to the appropriate places.  The
"with the dollar sign escaped" part had been wrong already in 1993, and
it didn't get better over time.


(rillig)
diff -r1.625 -r1.626 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/31 14:55:33 1.625
+++ src/usr.bin/make/var.c 2020/10/31 15:23:52 1.626
@@ -1,1131 +1,1131 @@ @@ -1,1131 +1,1131 @@
1/* $NetBSD: var.c,v 1.625 2020/10/31 14:55:33 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.626 2020/10/31 15:23:52 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.625 2020/10/31 14:55:33 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.626 2020/10/31 15:23:52 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)
@@ -2330,1643 +2330,1634 @@ ApplyModifier_Match(const char **pp, App @@ -2330,1643 +2330,1634 @@ ApplyModifier_Match(const char **pp, App
2330 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2330 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2331 char *old_pattern = pattern; 2331 char *old_pattern = pattern;
2332 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2332 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2333 /* TODO: handle errors */ 2333 /* TODO: handle errors */
2334 free(old_pattern); 2334 free(old_pattern);
2335 } 2335 }
2336 2336
2337 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2337 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2338 2338
2339 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2339 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2340 st->newVal = ModifyWords(st->val, callback, pattern, 2340 st->newVal = ModifyWords(st->val, callback, pattern,
2341 st->oneBigWord, st->sep); 2341 st->oneBigWord, st->sep);
2342 free(pattern); 2342 free(pattern);
2343 return AMR_OK; 2343 return AMR_OK;
2344} 2344}
2345 2345
2346/* :S,from,to, */ 2346/* :S,from,to, */
2347static ApplyModifierResult 2347static ApplyModifierResult
2348ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2348ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2349{ 2349{
2350 struct ModifyWord_SubstArgs args; 2350 struct ModifyWord_SubstArgs args;
2351 char *lhs, *rhs; 2351 char *lhs, *rhs;
2352 Boolean oneBigWord; 2352 Boolean oneBigWord;
2353 VarParseResult res; 2353 VarParseResult res;
2354 2354
2355 char delim = (*pp)[1]; 2355 char delim = (*pp)[1];
2356 if (delim == '\0') { 2356 if (delim == '\0') {
2357 Error("Missing delimiter for :S modifier"); 2357 Error("Missing delimiter for :S modifier");
2358 (*pp)++; 2358 (*pp)++;
2359 return AMR_CLEANUP; 2359 return AMR_CLEANUP;
2360 } 2360 }
2361 2361
2362 *pp += 2; 2362 *pp += 2;
2363 2363
2364 args.pflags = 0; 2364 args.pflags = 0;
2365 args.matched = FALSE; 2365 args.matched = FALSE;
2366 2366
2367 /* 2367 /*
2368 * If pattern begins with '^', it is anchored to the 2368 * If pattern begins with '^', it is anchored to the
2369 * start of the word -- skip over it and flag pattern. 2369 * start of the word -- skip over it and flag pattern.
2370 */ 2370 */
2371 if (**pp == '^') { 2371 if (**pp == '^') {
2372 args.pflags |= VARP_ANCHOR_START; 2372 args.pflags |= VARP_ANCHOR_START;
2373 (*pp)++; 2373 (*pp)++;
2374 } 2374 }
2375 2375
2376 res = ParseModifierPart(pp, delim, st->eflags, st, 2376 res = ParseModifierPart(pp, delim, st->eflags, st,
2377 &lhs, &args.lhsLen, &args.pflags, NULL); 2377 &lhs, &args.lhsLen, &args.pflags, NULL);
2378 if (res != VPR_OK) 2378 if (res != VPR_OK)
2379 return AMR_CLEANUP; 2379 return AMR_CLEANUP;
2380 args.lhs = lhs; 2380 args.lhs = lhs;
2381 2381
2382 res = ParseModifierPart(pp, delim, st->eflags, st, 2382 res = ParseModifierPart(pp, delim, st->eflags, st,
2383 &rhs, &args.rhsLen, NULL, &args); 2383 &rhs, &args.rhsLen, NULL, &args);
2384 if (res != VPR_OK) 2384 if (res != VPR_OK)
2385 return AMR_CLEANUP; 2385 return AMR_CLEANUP;
2386 args.rhs = rhs; 2386 args.rhs = rhs;
2387 2387
2388 oneBigWord = st->oneBigWord; 2388 oneBigWord = st->oneBigWord;
2389 for (;; (*pp)++) { 2389 for (;; (*pp)++) {
2390 switch (**pp) { 2390 switch (**pp) {
2391 case 'g': 2391 case 'g':
2392 args.pflags |= VARP_SUB_GLOBAL; 2392 args.pflags |= VARP_SUB_GLOBAL;
2393 continue; 2393 continue;
2394 case '1': 2394 case '1':
2395 args.pflags |= VARP_SUB_ONE; 2395 args.pflags |= VARP_SUB_ONE;
2396 continue; 2396 continue;
2397 case 'W': 2397 case 'W':
2398 oneBigWord = TRUE; 2398 oneBigWord = TRUE;
2399 continue; 2399 continue;
2400 } 2400 }
2401 break; 2401 break;
2402 } 2402 }
2403 2403
2404 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args, 2404 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
2405 oneBigWord, st->sep); 2405 oneBigWord, st->sep);
2406 2406
2407 free(lhs); 2407 free(lhs);
2408 free(rhs); 2408 free(rhs);
2409 return AMR_OK; 2409 return AMR_OK;
2410} 2410}
2411 2411
2412#ifndef NO_REGEX 2412#ifndef NO_REGEX
2413 2413
2414/* :C,from,to, */ 2414/* :C,from,to, */
2415static ApplyModifierResult 2415static ApplyModifierResult
2416ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2416ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2417{ 2417{
2418 char *re; 2418 char *re;
2419 struct ModifyWord_SubstRegexArgs args; 2419 struct ModifyWord_SubstRegexArgs args;
2420 Boolean oneBigWord; 2420 Boolean oneBigWord;
2421 int error; 2421 int error;
2422 VarParseResult res; 2422 VarParseResult res;
2423 2423
2424 char delim = (*pp)[1]; 2424 char delim = (*pp)[1];
2425 if (delim == '\0') { 2425 if (delim == '\0') {
2426 Error("Missing delimiter for :C modifier"); 2426 Error("Missing delimiter for :C modifier");
2427 (*pp)++; 2427 (*pp)++;
2428 return AMR_CLEANUP; 2428 return AMR_CLEANUP;
2429 } 2429 }
2430 2430
2431 *pp += 2; 2431 *pp += 2;
2432 2432
2433 res = ParseModifierPart(pp, delim, st->eflags, st, 2433 res = ParseModifierPart(pp, delim, st->eflags, st,
2434 &re, NULL, NULL, NULL); 2434 &re, NULL, NULL, NULL);
2435 if (res != VPR_OK) 2435 if (res != VPR_OK)
2436 return AMR_CLEANUP; 2436 return AMR_CLEANUP;
2437 2437
2438 res = ParseModifierPart(pp, delim, st->eflags, st, 2438 res = ParseModifierPart(pp, delim, st->eflags, st,
2439 &args.replace, NULL, NULL, NULL); 2439 &args.replace, NULL, NULL, NULL);
2440 if (args.replace == NULL) { 2440 if (args.replace == NULL) {
2441 free(re); 2441 free(re);
2442 return AMR_CLEANUP; 2442 return AMR_CLEANUP;
2443 } 2443 }
2444 2444
2445 args.pflags = 0; 2445 args.pflags = 0;
2446 args.matched = FALSE; 2446 args.matched = FALSE;
2447 oneBigWord = st->oneBigWord; 2447 oneBigWord = st->oneBigWord;
2448 for (;; (*pp)++) { 2448 for (;; (*pp)++) {
2449 switch (**pp) { 2449 switch (**pp) {
2450 case 'g': 2450 case 'g':
2451 args.pflags |= VARP_SUB_GLOBAL; 2451 args.pflags |= VARP_SUB_GLOBAL;
2452 continue; 2452 continue;
2453 case '1': 2453 case '1':
2454 args.pflags |= VARP_SUB_ONE; 2454 args.pflags |= VARP_SUB_ONE;
2455 continue; 2455 continue;
2456 case 'W': 2456 case 'W':
2457 oneBigWord = TRUE; 2457 oneBigWord = TRUE;
2458 continue; 2458 continue;
2459 } 2459 }
2460 break; 2460 break;
2461 } 2461 }
2462 2462
2463 error = regcomp(&args.re, re, REG_EXTENDED); 2463 error = regcomp(&args.re, re, REG_EXTENDED);
2464 free(re); 2464 free(re);
2465 if (error) { 2465 if (error) {
2466 VarREError(error, &args.re, "Regex compilation error"); 2466 VarREError(error, &args.re, "Regex compilation error");
2467 free(args.replace); 2467 free(args.replace);
2468 return AMR_CLEANUP; 2468 return AMR_CLEANUP;
2469 } 2469 }
2470 2470
2471 args.nsub = args.re.re_nsub + 1; 2471 args.nsub = args.re.re_nsub + 1;
2472 if (args.nsub > 10) 2472 if (args.nsub > 10)
2473 args.nsub = 10; 2473 args.nsub = 10;
2474 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args, 2474 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
2475 oneBigWord, st->sep); 2475 oneBigWord, st->sep);
2476 regfree(&args.re); 2476 regfree(&args.re);
2477 free(args.replace); 2477 free(args.replace);
2478 return AMR_OK; 2478 return AMR_OK;
2479} 2479}
2480#endif 2480#endif
2481 2481
2482/* :Q, :q */ 2482/* :Q, :q */
2483static ApplyModifierResult 2483static ApplyModifierResult
2484ApplyModifier_Quote(const char **pp, ApplyModifiersState *st) 2484ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
2485{ 2485{
2486 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2486 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2487 st->newVal = VarQuote(st->val, **pp == 'q'); 2487 st->newVal = VarQuote(st->val, **pp == 'q');
2488 (*pp)++; 2488 (*pp)++;
2489 return AMR_OK; 2489 return AMR_OK;
2490 } else 2490 } else
2491 return AMR_UNKNOWN; 2491 return AMR_UNKNOWN;
2492} 2492}
2493 2493
2494static void 2494static void
2495ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2495ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2496{ 2496{
2497 SepBuf_AddStr(buf, word); 2497 SepBuf_AddStr(buf, word);
2498} 2498}
2499 2499
2500/* :ts<separator> */ 2500/* :ts<separator> */
2501static ApplyModifierResult 2501static ApplyModifierResult
2502ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2502ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2503{ 2503{
2504 const char *sep = *pp + 2; 2504 const char *sep = *pp + 2;
2505 2505
2506 /* ":ts<any><endc>" or ":ts<any>:" */ 2506 /* ":ts<any><endc>" or ":ts<any>:" */
2507 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2507 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2508 st->sep = sep[0]; 2508 st->sep = sep[0];
2509 *pp = sep + 1; 2509 *pp = sep + 1;
2510 goto ok; 2510 goto ok;
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
 3329/* Only four of the local variables are treated specially as they are the
 3330 * only four that will be set when dynamic sources are expanded. */
3329static Boolean 3331static Boolean
3330VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) 3332VarnameIsDynamic(const char *name, size_t len)
3331{ 3333{
3332 if ((namelen == 1 || 3334 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3333 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && 3335 switch (name[0]) {
3334 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)) 
3335 { 
3336 /* 
3337 * If substituting a local variable in a non-local context, 
3338 * assume it's for dynamic source stuff. We have to handle 
3339 * this specially and return the longhand for the variable 
3340 * with the dollar sign escaped so it makes it back to the 
3341 * caller. Only four of the local variables are treated 
3342 * specially as they are the only four that will be set 
3343 * when dynamic sources are expanded. 
3344 */ 
3345 switch (varname[0]) { 
3346 case '@': 3336 case '@':
3347 case '%': 3337 case '%':
3348 case '*': 3338 case '*':
3349 case '!': 3339 case '!':
3350 return TRUE; 3340 return TRUE;
3351 } 3341 }
3352 return FALSE; 3342 return FALSE;
3353 } 3343 }
3354 3344
3355 if ((namelen == 7 || namelen == 8) && varname[0] == '.' && 3345 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3356 ch_isupper(varname[1]) && (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)) 3346 return strcmp(name, ".TARGET") == 0 ||
3357 { 3347 strcmp(name, ".ARCHIVE") == 0 ||
3358 return strcmp(varname, ".TARGET") == 0 || 3348 strcmp(name, ".PREFIX") == 0 ||
3359 strcmp(varname, ".ARCHIVE") == 0 || 3349 strcmp(name, ".MEMBER") == 0;
3360 strcmp(varname, ".PREFIX") == 0 || 
3361 strcmp(varname, ".MEMBER") == 0; 
3362 } 3350 }
3363 3351
3364 return FALSE; 3352 return FALSE;
3365} 3353}
3366 3354
3367static const char * 3355static const char *
3368UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3356UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3369{ 3357{
3370 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3358 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3371 /* 3359 /*
3372 * If substituting a local variable in a non-local context, 3360 * If substituting a local variable in a non-local context,
3373 * assume it's for dynamic source stuff. We have to handle 3361 * assume it's for dynamic source stuff. We have to handle
3374 * this specially and return the longhand for the variable 3362 * this specially and return the longhand for the variable
3375 * with the dollar sign escaped so it makes it back to the 3363 * with the dollar sign escaped so it makes it back to the
3376 * caller. Only four of the local variables are treated 3364 * caller. Only four of the local variables are treated
3377 * specially as they are the only four that will be set 3365 * specially as they are the only four that will be set
3378 * when dynamic sources are expanded. 3366 * when dynamic sources are expanded.
3379 */ 3367 */
3380 switch (varname) { 3368 switch (varname) {
3381 case '@': 3369 case '@':
3382 return "$(.TARGET)"; 3370 return "$(.TARGET)";
3383 case '%': 3371 case '%':
3384 return "$(.MEMBER)"; 3372 return "$(.MEMBER)";
3385 case '*': 3373 case '*':
3386 return "$(.PREFIX)"; 3374 return "$(.PREFIX)";
3387 case '!': 3375 case '!':
3388 return "$(.ARCHIVE)"; 3376 return "$(.ARCHIVE)";
3389 } 3377 }
3390 } 3378 }
3391 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3379 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3392} 3380}
3393 3381
3394/* Parse a variable name, until the end character or a colon, whichever 3382/* Parse a variable name, until the end character or a colon, whichever
3395 * comes first. */ 3383 * comes first. */
3396static char * 3384static char *
3397ParseVarname(const char **pp, char startc, char endc, 3385ParseVarname(const char **pp, char startc, char endc,
3398 GNode *ctxt, VarEvalFlags eflags, 3386 GNode *ctxt, VarEvalFlags eflags,
3399 size_t *out_varname_len) 3387 size_t *out_varname_len)
3400{ 3388{
3401 Buffer buf; 3389 Buffer buf;
3402 const char *p = *pp; 3390 const char *p = *pp;
3403 int depth = 1; 3391 int depth = 1;
3404 3392
3405 Buf_Init(&buf, 0); 3393 Buf_Init(&buf, 0);
3406 3394
3407 while (*p != '\0') { 3395 while (*p != '\0') {
3408 /* Track depth so we can spot parse errors. */ 3396 /* Track depth so we can spot parse errors. */
3409 if (*p == startc) 3397 if (*p == startc)
3410 depth++; 3398 depth++;
3411 if (*p == endc) { 3399 if (*p == endc) {
3412 if (--depth == 0) 3400 if (--depth == 0)
3413 break; 3401 break;
3414 } 3402 }
3415 if (*p == ':' && depth == 1) 3403 if (*p == ':' && depth == 1)
3416 break; 3404 break;
3417 3405
3418 /* A variable inside a variable, expand. */ 3406 /* A variable inside a variable, expand. */
3419 if (*p == '$') { 3407 if (*p == '$') {
3420 void *freeIt; 3408 void *freeIt;
3421 const char *rval; 3409 const char *rval;
3422 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3410 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3423 /* TODO: handle errors */ 3411 /* TODO: handle errors */
3424 Buf_AddStr(&buf, rval); 3412 Buf_AddStr(&buf, rval);
3425 free(freeIt); 3413 free(freeIt);
3426 } else { 3414 } else {
3427 Buf_AddByte(&buf, *p); 3415 Buf_AddByte(&buf, *p);
3428 p++; 3416 p++;
3429 } 3417 }
3430 } 3418 }
3431 *pp = p; 3419 *pp = p;
3432 *out_varname_len = Buf_Len(&buf); 3420 *out_varname_len = Buf_Len(&buf);
3433 return Buf_Destroy(&buf, FALSE); 3421 return Buf_Destroy(&buf, FALSE);
3434} 3422}
3435 3423
3436static Boolean 3424static Boolean
3437ValidShortVarname(char varname, const char *start) 3425ValidShortVarname(char varname, const char *start)
3438{ 3426{
3439 switch (varname) { 3427 switch (varname) {
3440 case '\0': 3428 case '\0':
3441 case ')': 3429 case ')':
3442 case '}': 3430 case '}':
3443 case ':': 3431 case ':':
3444 case '$': 3432 case '$':
3445 break; /* and continue below */ 3433 break; /* and continue below */
3446 default: 3434 default:
3447 return TRUE; 3435 return TRUE;
3448 } 3436 }
3449 3437
3450 if (!DEBUG(LINT)) 3438 if (!DEBUG(LINT))
3451 return FALSE; 3439 return FALSE;
3452 3440
3453 if (varname == '$') 3441 if (varname == '$')
3454 Parse_Error(PARSE_FATAL, 3442 Parse_Error(PARSE_FATAL,
3455 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3443 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3456 else if (varname == '\0') 3444 else if (varname == '\0')
3457 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3445 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3458 else 3446 else
3459 Parse_Error(PARSE_FATAL, 3447 Parse_Error(PARSE_FATAL,
3460 "Invalid variable name '%c', at \"%s\"", varname, start); 3448 "Invalid variable name '%c', at \"%s\"", varname, start);
3461 3449
3462 return FALSE; 3450 return FALSE;
3463} 3451}
3464 3452
3465/* Parse a single-character variable name such as $V or $@. 3453/* Parse a single-character variable name such as $V or $@.
3466 * Return whether to continue parsing. */ 3454 * Return whether to continue parsing. */
3467static Boolean 3455static Boolean
3468ParseVarnameShort( 3456ParseVarnameShort(
3469 char startc, 3457 char startc,
3470 const char **pp, 3458 const char **pp,
3471 GNode *ctxt, 3459 GNode *ctxt,
3472 VarEvalFlags eflags, 3460 VarEvalFlags eflags,
3473 VarParseResult *out_FALSE_res, 3461 VarParseResult *out_FALSE_res,
3474 const char **out_FALSE_val, 3462 const char **out_FALSE_val,
3475 Var **out_TRUE_var 3463 Var **out_TRUE_var
3476) { 3464) {
3477 char name[2]; 3465 char name[2];
3478 Var *v; 3466 Var *v;
3479 3467
3480 /* 3468 /*
3481 * If it's not bounded by braces of some sort, life is much simpler. 3469 * If it's not bounded by braces of some sort, life is much simpler.
3482 * We just need to check for the first character and return the 3470 * We just need to check for the first character and return the
3483 * value if it exists. 3471 * value if it exists.
3484 */ 3472 */
3485 3473
3486 if (!ValidShortVarname(startc, *pp)) { 3474 if (!ValidShortVarname(startc, *pp)) {
3487 (*pp)++; 3475 (*pp)++;
3488 *out_FALSE_val = var_Error; 3476 *out_FALSE_val = var_Error;
3489 *out_FALSE_res = VPR_PARSE_MSG; 3477 *out_FALSE_res = VPR_PARSE_MSG;
3490 return FALSE; 3478 return FALSE;
3491 } 3479 }
3492 3480
3493 name[0] = startc; 3481 name[0] = startc;
3494 name[1] = '\0'; 3482 name[1] = '\0';
3495 v = VarFind(name, ctxt, TRUE); 3483 v = VarFind(name, ctxt, TRUE);
3496 if (v == NULL) { 3484 if (v == NULL) {
3497 *pp += 2; 3485 *pp += 2;
3498 3486
3499 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3487 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3500 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3488 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3501 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3489 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3502 *out_FALSE_res = VPR_UNDEF_MSG; 3490 *out_FALSE_res = VPR_UNDEF_MSG;
3503 return FALSE; 3491 return FALSE;
3504 } 3492 }
3505 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3493 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3506 return FALSE; 3494 return FALSE;
3507 } 3495 }
3508 3496
3509 *out_TRUE_var = v; 3497 *out_TRUE_var = v;
3510 return TRUE; 3498 return TRUE;
3511} 3499}
3512 3500
3513/* Parse a long variable name enclosed in braces or parentheses such as $(VAR) 3501/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3514 * or ${VAR}, up to the closing brace or parenthesis, or in the case of 3502 * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3515 * ${VAR:Modifiers}, up to the ':' that starts the modifiers. 3503 * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3516 * Return whether to continue parsing. */ 3504 * Return whether to continue parsing. */
3517static Boolean 3505static Boolean
3518ParseVarnameLong( 3506ParseVarnameLong(
3519 const char **pp, 3507 const char **pp,
3520 char startc, 3508 char startc,
3521 GNode *ctxt, 3509 GNode *ctxt,
3522 VarEvalFlags eflags, 3510 VarEvalFlags eflags,
3523 3511
3524 VarParseResult *out_FALSE_res, 3512 VarParseResult *out_FALSE_res,
3525 const char **out_FALSE_val, 3513 const char **out_FALSE_val,
3526 void **out_FALSE_freePtr, 3514 void **out_FALSE_freePtr,
3527 3515
3528 char *out_TRUE_endc, 3516 char *out_TRUE_endc,
3529 const char **out_TRUE_p, 3517 const char **out_TRUE_p,
3530 Var **out_TRUE_v, 3518 Var **out_TRUE_v,
3531 Boolean *out_TRUE_haveModifier, 3519 Boolean *out_TRUE_haveModifier,
3532 const char **out_TRUE_extraModifiers, 3520 const char **out_TRUE_extraModifiers,
3533 Boolean *out_TRUE_dynamic, 3521 Boolean *out_TRUE_dynamic,
3534 VarExprFlags *out_TRUE_exprFlags 3522 VarExprFlags *out_TRUE_exprFlags
3535) { 3523) {
3536 size_t namelen; 3524 size_t namelen;
3537 char *varname; 3525 char *varname;
3538 Var *v; 3526 Var *v;
3539 Boolean haveModifier; 3527 Boolean haveModifier;
3540 Boolean dynamic = FALSE; 3528 Boolean dynamic = FALSE;
3541 3529
3542 const char *const start = *pp; 3530 const char *const start = *pp;
3543 char endc = startc == '(' ? ')' : '}'; 3531 char endc = startc == '(' ? ')' : '}';
3544 3532
3545 const char *p = start + 2; 3533 const char *p = start + 2;
3546 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3534 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3547 3535
3548 if (*p == ':') { 3536 if (*p == ':') {
3549 haveModifier = TRUE; 3537 haveModifier = TRUE;
3550 } else if (*p == endc) { 3538 } else if (*p == endc) {
3551 haveModifier = FALSE; 3539 haveModifier = FALSE;
3552 } else { 3540 } else {
3553 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3541 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3554 *pp = p; 3542 *pp = p;
3555 free(varname); 3543 free(varname);
3556 *out_FALSE_val = var_Error; 3544 *out_FALSE_val = var_Error;
3557 *out_FALSE_res = VPR_PARSE_MSG; 3545 *out_FALSE_res = VPR_PARSE_MSG;
3558 return FALSE; 3546 return FALSE;
3559 } 3547 }
3560 3548
3561 v = VarFind(varname, ctxt, TRUE); 3549 v = VarFind(varname, ctxt, TRUE);
3562 3550
3563 /* At this point, p points just after the variable name, 3551 /* At this point, p points just after the variable name,
3564 * either at ':' or at endc. */ 3552 * either at ':' or at endc. */
3565 3553
3566 /* 3554 /*
3567 * Check also for bogus D and F forms of local variables since we're 3555 * Check also for bogus D and F forms of local variables since we're
3568 * in a local context and the name is the right length. 3556 * in a local context and the name is the right length.
3569 */ 3557 */
3570 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3558 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3571 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3559 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3572 strchr("@%?*!<>", varname[0]) != NULL) 3560 strchr("@%?*!<>", varname[0]) != NULL)
3573 { 3561 {
3574 /* 3562 /*
3575 * Well, it's local -- go look for it. 3563 * Well, it's local -- go look for it.
3576 */ 3564 */
3577 char name[] = { varname[0], '\0' }; 3565 char name[] = { varname[0], '\0' };
3578 v = VarFind(name, ctxt, 0); 3566 v = VarFind(name, ctxt, 0);
3579 3567
3580 if (v != NULL) { 3568 if (v != NULL) {
3581 if (varname[1] == 'D') { 3569 if (varname[1] == 'D') {
3582 *out_TRUE_extraModifiers = "H:"; 3570 *out_TRUE_extraModifiers = "H:";
3583 } else { /* F */ 3571 } else { /* F */
3584 *out_TRUE_extraModifiers = "T:"; 3572 *out_TRUE_extraModifiers = "T:";
3585 } 3573 }
3586 } 3574 }
3587 } 3575 }
3588 3576
3589 if (v == NULL) { 3577 if (v == NULL) {
3590 dynamic = VarIsDynamic(ctxt, varname, namelen); 3578 /* Defer expansion of dynamic variables if they appear in non-local
 3579 * context since they are not defined there. */
 3580 dynamic = VarnameIsDynamic(varname, namelen) &&
 3581 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
3591 3582
3592 if (!haveModifier) { 3583 if (!haveModifier) {
3593 p++; /* skip endc */ 3584 p++; /* skip endc */
3594 *pp = p; 3585 *pp = p;
3595 if (dynamic) { 3586 if (dynamic) {
3596 char *pstr = bmake_strsedup(start, p); 3587 char *pstr = bmake_strsedup(start, p);
3597 free(varname); 3588 free(varname);
3598 *out_FALSE_res = VPR_OK; 3589 *out_FALSE_res = VPR_OK;
3599 *out_FALSE_freePtr = pstr; 3590 *out_FALSE_freePtr = pstr;
3600 *out_FALSE_val = pstr; 3591 *out_FALSE_val = pstr;
3601 return FALSE; 3592 return FALSE;
3602 } 3593 }
3603 3594
3604 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3595 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3605 DEBUG(LINT)) 3596 DEBUG(LINT))
3606 { 3597 {
3607 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3598 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3608 varname); 3599 varname);
3609 free(varname); 3600 free(varname);
3610 *out_FALSE_res = VPR_UNDEF_MSG; 3601 *out_FALSE_res = VPR_UNDEF_MSG;
3611 *out_FALSE_val = var_Error; 3602 *out_FALSE_val = var_Error;
3612 return FALSE; 3603 return FALSE;
3613 } 3604 }
3614 3605
3615 if (eflags & VARE_UNDEFERR) { 3606 if (eflags & VARE_UNDEFERR) {
3616 free(varname); 3607 free(varname);
3617 *out_FALSE_res = VPR_UNDEF_SILENT; 3608 *out_FALSE_res = VPR_UNDEF_SILENT;
3618 *out_FALSE_val = var_Error; 3609 *out_FALSE_val = var_Error;
3619 return FALSE; 3610 return FALSE;
3620 } 3611 }
3621 3612
3622 free(varname); 3613 free(varname);
3623 *out_FALSE_res = VPR_OK; 3614 *out_FALSE_res = VPR_OK;
3624 *out_FALSE_val = varUndefined; 3615 *out_FALSE_val = varUndefined;
3625 return FALSE; 3616 return FALSE;
3626 } 3617 }
3627 3618
3628 /* The variable expression is based on an undefined variable. 3619 /* The variable expression is based on an undefined variable.
3629 * Nevertheless it needs a Var, for modifiers that access the 3620 * Nevertheless it needs a Var, for modifiers that access the
3630 * variable name, such as :L or :?. 3621 * variable name, such as :L or :?.
3631 * 3622 *
3632 * Most modifiers leave this expression in the "undefined" state 3623 * Most modifiers leave this expression in the "undefined" state
3633 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3624 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3634 * undefined expression into a defined expression (VEF_DEF). 3625 * undefined expression into a defined expression (VEF_DEF).
3635 * 3626 *
3636 * At the end, after applying all modifiers, if the expression 3627 * At the end, after applying all modifiers, if the expression
3637 * is still undefined, Var_Parse will return an empty string 3628 * is still undefined, Var_Parse will return an empty string
3638 * instead of the actually computed value. */ 3629 * instead of the actually computed value. */
3639 v = VarNew(varname, varname, "", 0); 3630 v = VarNew(varname, varname, "", 0);
3640 *out_TRUE_exprFlags = VEF_UNDEF; 3631 *out_TRUE_exprFlags = VEF_UNDEF;
3641 } else 3632 } else
3642 free(varname); 3633 free(varname);
3643 3634
3644 *out_TRUE_endc = endc; 3635 *out_TRUE_endc = endc;
3645 *out_TRUE_p = p; 3636 *out_TRUE_p = p;
3646 *out_TRUE_v = v; 3637 *out_TRUE_v = v;
3647 *out_TRUE_haveModifier = haveModifier; 3638 *out_TRUE_haveModifier = haveModifier;
3648 *out_TRUE_dynamic = dynamic; 3639 *out_TRUE_dynamic = dynamic;
3649 return TRUE; 3640 return TRUE;
3650} 3641}
3651 3642
3652/*- 3643/*-
3653 *----------------------------------------------------------------------- 3644 *-----------------------------------------------------------------------
3654 * Var_Parse -- 3645 * Var_Parse --
3655 * Given the start of a variable expression (such as $v, $(VAR), 3646 * Given the start of a variable expression (such as $v, $(VAR),
3656 * ${VAR:Mpattern}), extract the variable name, possibly some 3647 * ${VAR:Mpattern}), extract the variable name, possibly some
3657 * modifiers and find its value by applying the modifiers to the 3648 * modifiers and find its value by applying the modifiers to the
3658 * original value. 3649 * original value.
3659 * 3650 *
3660 * When parsing a condition in ParseEmptyArg, pp may also point to 3651 * When parsing a condition in ParseEmptyArg, pp may also point to
3661 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3652 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3662 * identical. 3653 * identical.
3663 * 3654 *
3664 * Input: 3655 * Input:
3665 * str The string to parse 3656 * str The string to parse
3666 * ctxt The context for the variable 3657 * ctxt The context for the variable
3667 * flags Select the exact details of parsing 3658 * flags Select the exact details of parsing
3668 * out_val_freeIt Must be freed by the caller after using out_val 3659 * out_val_freeIt Must be freed by the caller after using out_val
3669 * 3660 *
3670 * Results: 3661 * Results:
3671 * Returns the value of the variable expression, never NULL. 3662 * Returns the value of the variable expression, never NULL.
3672 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3663 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3673 * set. 3664 * set.
3674 * Returns varUndefined if there was an undefined variable and 3665 * Returns varUndefined if there was an undefined variable and
3675 * VARE_UNDEFERR was not set. 3666 * VARE_UNDEFERR was not set.
3676 * 3667 *
3677 * Parsing should continue at *pp. 3668 * Parsing should continue at *pp.
3678 * TODO: Document the value of *pp on parse errors. It might be advanced 3669 * TODO: Document the value of *pp on parse errors. It might be advanced
3679 * by 0, or +1, or the index of the parse error, or the guessed end of the 3670 * by 0, or +1, or the index of the parse error, or the guessed end of the
3680 * variable expression. 3671 * variable expression.
3681 * 3672 *
3682 * If var_Error is returned, a diagnostic may or may not have been 3673 * If var_Error is returned, a diagnostic may or may not have been
3683 * printed. XXX: This is inconsistent. 3674 * printed. XXX: This is inconsistent.
3684 * 3675 *
3685 * If varUndefined is returned, a diagnostic may or may not have been 3676 * If varUndefined is returned, a diagnostic may or may not have been
3686 * printed. XXX: This is inconsistent. 3677 * printed. XXX: This is inconsistent.
3687 * 3678 *
3688 * After using the returned value, *out_val_freeIt must be freed, 3679 * After using the returned value, *out_val_freeIt must be freed,
3689 * preferably using bmake_free since it is NULL in most cases. 3680 * preferably using bmake_free since it is NULL in most cases.
3690 * 3681 *
3691 * Side Effects: 3682 * Side Effects:
3692 * Any effects from the modifiers, such as :!cmd! or ::=value. 3683 * Any effects from the modifiers, such as :!cmd! or ::=value.
3693 *----------------------------------------------------------------------- 3684 *-----------------------------------------------------------------------
3694 */ 3685 */
3695/* coverity[+alloc : arg-*4] */ 3686/* coverity[+alloc : arg-*4] */
3696VarParseResult 3687VarParseResult
3697Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3688Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3698 const char **out_val, void **out_val_freeIt) 3689 const char **out_val, void **out_val_freeIt)
3699{ 3690{
3700 const char *const start = *pp; 3691 const char *const start = *pp;
3701 const char *p; 3692 const char *p;
3702 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3693 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3703 char startc; /* Starting character if variable in parens 3694 char startc; /* Starting character if variable in parens
3704 * or braces */ 3695 * or braces */
3705 char endc; /* Ending character if variable in parens 3696 char endc; /* Ending character if variable in parens
3706 * or braces */ 3697 * or braces */
3707 Boolean dynamic; /* TRUE if the variable is local and we're 3698 Boolean dynamic; /* TRUE if the variable is local and we're
3708 * expanding it in a non-local context. This 3699 * expanding it in a non-local context. This
3709 * is done to support dynamic sources. The 3700 * is done to support dynamic sources. The
3710 * result is just the expression, unaltered */ 3701 * result is just the expression, unaltered */
3711 const char *extramodifiers; 3702 const char *extramodifiers;
3712 Var *v; 3703 Var *v;
3713 char *nstr; 3704 char *nstr;
3714 char eflags_str[VarEvalFlags_ToStringSize]; 3705 char eflags_str[VarEvalFlags_ToStringSize];
3715 VarExprFlags exprFlags = 0; 3706 VarExprFlags exprFlags = 0;
3716 3707
3717 VAR_DEBUG3("%s: %s with %s\n", __func__, start, 3708 VAR_DEBUG2("Var_Parse: %s with %s\n", start,
3718 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3709 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3719 VarEvalFlags_ToStringSpecs)); 3710 VarEvalFlags_ToStringSpecs));
3720 3711
3721 *out_val_freeIt = NULL; 3712 *out_val_freeIt = NULL;
3722 extramodifiers = NULL; /* extra modifiers to apply first */ 3713 extramodifiers = NULL; /* extra modifiers to apply first */
3723 dynamic = FALSE; 3714 dynamic = FALSE;
3724 3715
3725 /* Appease GCC, which thinks that the variable might not be 3716 /* Appease GCC, which thinks that the variable might not be
3726 * initialized. */ 3717 * initialized. */
3727 endc = '\0'; 3718 endc = '\0';
3728 3719
3729 startc = start[1]; 3720 startc = start[1];
3730 if (startc != '(' && startc != '{') { 3721 if (startc != '(' && startc != '{') {
3731 VarParseResult res; 3722 VarParseResult res;
3732 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v)) 3723 if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res, out_val, &v))
3733 return res; 3724 return res;
3734 haveModifier = FALSE; 3725 haveModifier = FALSE;
3735 p = start + 1; 3726 p = start + 1;
3736 } else { 3727 } else {
3737 VarParseResult res; 3728 VarParseResult res;
3738 if (!ParseVarnameLong(pp, startc, ctxt, eflags, 3729 if (!ParseVarnameLong(pp, startc, ctxt, eflags,
3739 &res, out_val, out_val_freeIt, 3730 &res, out_val, out_val_freeIt,
3740 &endc, &p, &v, &haveModifier, &extramodifiers, 3731 &endc, &p, &v, &haveModifier, &extramodifiers,
3741 &dynamic, &exprFlags)) 3732 &dynamic, &exprFlags))
3742 return res; 3733 return res;
3743 } 3734 }
3744 3735
3745 if (v->flags & VAR_IN_USE) 3736 if (v->flags & VAR_IN_USE)
3746 Fatal("Variable %s is recursive.", v->name); 3737 Fatal("Variable %s is recursive.", v->name);
3747 3738
3748 /* 3739 /*
3749 * Before doing any modification, we have to make sure the value 3740 * Before doing any modification, we have to make sure the value
3750 * has been fully expanded. If it looks like recursion might be 3741 * has been fully expanded. If it looks like recursion might be
3751 * necessary (there's a dollar sign somewhere in the variable's value) 3742 * necessary (there's a dollar sign somewhere in the variable's value)
3752 * we just call Var_Subst to do any other substitutions that are 3743 * we just call Var_Subst to do any other substitutions that are
3753 * necessary. Note that the value returned by Var_Subst will have 3744 * necessary. Note that the value returned by Var_Subst will have
3754 * been dynamically-allocated, so it will need freeing when we 3745 * been dynamically-allocated, so it will need freeing when we
3755 * return. 3746 * return.
3756 */ 3747 */
3757 nstr = Buf_GetAll(&v->val, NULL); 3748 nstr = Buf_GetAll(&v->val, NULL);
3758 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) { 3749 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES)) {
3759 VarEvalFlags nested_eflags = eflags; 3750 VarEvalFlags nested_eflags = eflags;
3760 if (DEBUG(LINT)) 3751 if (DEBUG(LINT))
3761 nested_eflags &= ~(unsigned)VARE_UNDEFERR; 3752 nested_eflags &= ~(unsigned)VARE_UNDEFERR;
3762 v->flags |= VAR_IN_USE; 3753 v->flags |= VAR_IN_USE;
3763 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr); 3754 (void)Var_Subst(nstr, ctxt, nested_eflags, &nstr);
3764 v->flags &= ~(unsigned)VAR_IN_USE; 3755 v->flags &= ~(unsigned)VAR_IN_USE;
3765 /* TODO: handle errors */ 3756 /* TODO: handle errors */
3766 *out_val_freeIt = nstr; 3757 *out_val_freeIt = nstr;
3767 } 3758 }
3768 3759
3769 if (haveModifier || extramodifiers != NULL) { 3760 if (haveModifier || extramodifiers != NULL) {
3770 void *extraFree; 3761 void *extraFree;
3771 3762
3772 extraFree = NULL; 3763 extraFree = NULL;
3773 if (extramodifiers != NULL) { 3764 if (extramodifiers != NULL) {
3774 const char *em = extramodifiers; 3765 const char *em = extramodifiers;
3775 nstr = ApplyModifiers(&em, nstr, '(', ')', 3766 nstr = ApplyModifiers(&em, nstr, '(', ')',
3776 v, &exprFlags, ctxt, eflags, &extraFree); 3767 v, &exprFlags, ctxt, eflags, &extraFree);
3777 } 3768 }
3778 3769
3779 if (haveModifier) { 3770 if (haveModifier) {
3780 /* Skip initial colon. */ 3771 /* Skip initial colon. */
3781 p++; 3772 p++;
3782 3773
3783 nstr = ApplyModifiers(&p, nstr, startc, endc, 3774 nstr = ApplyModifiers(&p, nstr, startc, endc,
3784 v, &exprFlags, ctxt, eflags, out_val_freeIt); 3775 v, &exprFlags, ctxt, eflags, out_val_freeIt);
3785 free(extraFree); 3776 free(extraFree);
3786 } else { 3777 } else {
3787 *out_val_freeIt = extraFree; 3778 *out_val_freeIt = extraFree;
3788 } 3779 }
3789 } 3780 }
3790 3781
3791 if (*p != '\0') /* Skip past endc if possible. */ 3782 if (*p != '\0') /* Skip past endc if possible. */
3792 p++; 3783 p++;
3793 3784
3794 *pp = p; 3785 *pp = p;
3795 3786
3796 if (v->flags & VAR_FROM_ENV) { 3787 if (v->flags & VAR_FROM_ENV) {
3797 /* Free the environment variable now since we own it, 3788 /* Free the environment variable now since we own it,
3798 * but don't free the variable value if it will be returned. */ 3789 * but don't free the variable value if it will be returned. */
3799 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL); 3790 Boolean keepValue = nstr == Buf_GetAll(&v->val, NULL);
3800 if (keepValue) 3791 if (keepValue)
3801 *out_val_freeIt = nstr; 3792 *out_val_freeIt = nstr;
3802 (void)VarFreeEnv(v, !keepValue); 3793 (void)VarFreeEnv(v, !keepValue);
3803 3794
3804 } else if (exprFlags & VEF_UNDEF) { 3795 } else if (exprFlags & VEF_UNDEF) {
3805 if (!(exprFlags & VEF_DEF)) { 3796 if (!(exprFlags & VEF_DEF)) {
3806 if (*out_val_freeIt != NULL) { 3797 if (*out_val_freeIt != NULL) {
3807 free(*out_val_freeIt); 3798 free(*out_val_freeIt);
3808 *out_val_freeIt = NULL; 3799 *out_val_freeIt = NULL;
3809 } 3800 }
3810 if (dynamic) { 3801 if (dynamic) {
3811 nstr = bmake_strsedup(start, p); 3802 nstr = bmake_strsedup(start, p);
3812 *out_val_freeIt = nstr; 3803 *out_val_freeIt = nstr;
3813 } else { 3804 } else {
3814 /* The expression is still undefined, therefore discard the 3805 /* The expression is still undefined, therefore discard the
3815 * actual value and return an error marker instead. */ 3806 * actual value and return an error marker instead. */
3816 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined; 3807 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varUndefined;
3817 } 3808 }
3818 } 3809 }
3819 if (nstr != Buf_GetAll(&v->val, NULL)) 3810 if (nstr != Buf_GetAll(&v->val, NULL))
3820 Buf_Destroy(&v->val, TRUE); 3811 Buf_Destroy(&v->val, TRUE);
3821 free(v->name_freeIt); 3812 free(v->name_freeIt);
3822 free(v); 3813 free(v);
3823 } 3814 }
3824 *out_val = nstr; 3815 *out_val = nstr;
3825 return VPR_UNKNOWN; 3816 return VPR_UNKNOWN;
3826} 3817}
3827 3818
3828/* Substitute for all variables in the given string in the given context. 3819/* Substitute for all variables in the given string in the given context.
3829 * 3820 *
3830 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3821 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3831 * variable is encountered. 3822 * variable is encountered.
3832 * 3823 *
3833 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=, 3824 * If eflags & VARE_WANTRES, any effects from the modifiers, such as ::=,
3834 * :sh or !cmd! take place. 3825 * :sh or !cmd! take place.
3835 * 3826 *
3836 * Input: 3827 * Input:
3837 * str the string which to substitute 3828 * str the string which to substitute
3838 * ctxt the context wherein to find variables 3829 * ctxt the context wherein to find variables
3839 * eflags VARE_UNDEFERR if undefineds are an error 3830 * eflags VARE_UNDEFERR if undefineds are an error
3840 * VARE_WANTRES if we actually want the result 3831 * VARE_WANTRES if we actually want the result
3841 * VARE_ASSIGN if we are in a := assignment 3832 * VARE_ASSIGN if we are in a := assignment
3842 * 3833 *
3843 * Results: 3834 * Results:
3844 * The resulting string. 3835 * The resulting string.
3845 */ 3836 */
3846VarParseResult 3837VarParseResult
3847Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res) 3838Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
3848{ 3839{
3849 const char *p = str; 3840 const char *p = str;
3850 Buffer buf; /* Buffer for forming things */ 3841 Buffer buf; /* Buffer for forming things */
3851 3842
3852 /* Set true if an error has already been reported, 3843 /* Set true if an error has already been reported,
3853 * to prevent a plethora of messages when recursing */ 3844 * to prevent a plethora of messages when recursing */
3854 static Boolean errorReported; 3845 static Boolean errorReported;
3855 3846
3856 Buf_Init(&buf, 0); 3847 Buf_Init(&buf, 0);
3857 errorReported = FALSE; 3848 errorReported = FALSE;
3858 3849
3859 while (*p != '\0') { 3850 while (*p != '\0') {
3860 if (p[0] == '$' && p[1] == '$') { 3851 if (p[0] == '$' && p[1] == '$') {
3861 /* A dollar sign may be escaped with another dollar sign. */ 3852 /* A dollar sign may be escaped with another dollar sign. */
3862 if (save_dollars && (eflags & VARE_ASSIGN)) 3853 if (save_dollars && (eflags & VARE_ASSIGN))
3863 Buf_AddByte(&buf, '$'); 3854 Buf_AddByte(&buf, '$');
3864 Buf_AddByte(&buf, '$'); 3855 Buf_AddByte(&buf, '$');
3865 p += 2; 3856 p += 2;
3866 } else if (*p != '$') { 3857 } else if (*p != '$') {
3867 /* 3858 /*
3868 * Skip as many characters as possible -- either to the end of 3859 * Skip as many characters as possible -- either to the end of
3869 * the string or to the next dollar sign (variable expression). 3860 * the string or to the next dollar sign (variable expression).
3870 */ 3861 */
3871 const char *plainStart = p; 3862 const char *plainStart = p;
3872 3863
3873 for (p++; *p != '$' && *p != '\0'; p++) 3864 for (p++; *p != '$' && *p != '\0'; p++)
3874 continue; 3865 continue;
3875 Buf_AddBytesBetween(&buf, plainStart, p); 3866 Buf_AddBytesBetween(&buf, plainStart, p);
3876 } else { 3867 } else {
3877 const char *nested_p = p; 3868 const char *nested_p = p;
3878 void *freeIt; 3869 void *freeIt;
3879 const char *val; 3870 const char *val;
3880 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt); 3871 (void)Var_Parse(&nested_p, ctxt, eflags, &val, &freeIt);
3881 /* TODO: handle errors */ 3872 /* TODO: handle errors */
3882 3873
3883 if (val == var_Error || val == varUndefined) { 3874 if (val == var_Error || val == varUndefined) {
3884 /* 3875 /*
3885 * If performing old-time variable substitution, skip over 3876 * If performing old-time variable substitution, skip over
3886 * the variable and continue with the substitution. Otherwise, 3877 * the variable and continue with the substitution. Otherwise,
3887 * store the dollar sign and advance str so we continue with 3878 * store the dollar sign and advance str so we continue with
3888 * the string... 3879 * the string...
3889 */ 3880 */
3890 if (oldVars) { 3881 if (oldVars) {
3891 p = nested_p; 3882 p = nested_p;
3892 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 3883 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
3893 /* 3884 /*
3894 * If variable is undefined, complain and skip the 3885 * If variable is undefined, complain and skip the
3895 * variable. The complaint will stop us from doing anything 3886 * variable. The complaint will stop us from doing anything
3896 * when the file is parsed. 3887 * when the file is parsed.
3897 */ 3888 */
3898 if (!errorReported) { 3889 if (!errorReported) {
3899 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 3890 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
3900 (int)(size_t)(nested_p - p), p); 3891 (int)(size_t)(nested_p - p), p);
3901 } 3892 }
3902 p = nested_p; 3893 p = nested_p;
3903 errorReported = TRUE; 3894 errorReported = TRUE;
3904 } else { 3895 } else {
3905 /* Copy the initial '$' of the undefined expression, 3896 /* Copy the initial '$' of the undefined expression,
3906 * thereby deferring expansion of the expression, but 3897 * thereby deferring expansion of the expression, but
3907 * expand nested expressions if already possible. 3898 * expand nested expressions if already possible.
3908 * See unit-tests/varparse-undef-partial.mk. */ 3899 * See unit-tests/varparse-undef-partial.mk. */
3909 Buf_AddByte(&buf, *p); 3900 Buf_AddByte(&buf, *p);
3910 p++; 3901 p++;
3911 } 3902 }
3912 } else { 3903 } else {
3913 p = nested_p; 3904 p = nested_p;
3914 Buf_AddStr(&buf, val); 3905 Buf_AddStr(&buf, val);
3915 } 3906 }
3916 free(freeIt); 3907 free(freeIt);
3917 freeIt = NULL; 3908 freeIt = NULL;
3918 } 3909 }
3919 } 3910 }
3920 3911
3921 *out_res = Buf_DestroyCompact(&buf); 3912 *out_res = Buf_DestroyCompact(&buf);
3922 return VPR_OK; 3913 return VPR_OK;
3923} 3914}
3924 3915
3925/* Initialize the variables module. */ 3916/* Initialize the variables module. */
3926void 3917void
3927Var_Init(void) 3918Var_Init(void)
3928{ 3919{
3929 VAR_INTERNAL = Targ_NewGN("Internal"); 3920 VAR_INTERNAL = Targ_NewGN("Internal");
3930 VAR_GLOBAL = Targ_NewGN("Global"); 3921 VAR_GLOBAL = Targ_NewGN("Global");
3931 VAR_CMDLINE = Targ_NewGN("Command"); 3922 VAR_CMDLINE = Targ_NewGN("Command");
3932} 3923}
3933 3924
3934/* Clean up the variables module. */ 3925/* Clean up the variables module. */
3935void 3926void
3936Var_End(void) 3927Var_End(void)
3937{ 3928{
3938 Var_Stats(); 3929 Var_Stats();
3939} 3930}
3940 3931
3941void 3932void
3942Var_Stats(void) 3933Var_Stats(void)
3943{ 3934{
3944 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 3935 HashTable_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
3945} 3936}
3946 3937
3947/* Print all variables in a context, sorted by name. */ 3938/* Print all variables in a context, sorted by name. */
3948void 3939void
3949Var_Dump(GNode *ctxt) 3940Var_Dump(GNode *ctxt)
3950{ 3941{
3951 Vector /* of const char * */ vec; 3942 Vector /* of const char * */ vec;
3952 HashIter hi; 3943 HashIter hi;
3953 size_t i; 3944 size_t i;
3954 const char **varnames; 3945 const char **varnames;
3955 3946
3956 Vector_Init(&vec, sizeof(const char *)); 3947 Vector_Init(&vec, sizeof(const char *));
3957 3948
3958 HashIter_Init(&hi, &ctxt->context); 3949 HashIter_Init(&hi, &ctxt->context);
3959 while (HashIter_Next(&hi) != NULL) 3950 while (HashIter_Next(&hi) != NULL)
3960 *(const char **)Vector_Push(&vec) = hi.entry->key; 3951 *(const char **)Vector_Push(&vec) = hi.entry->key;
3961 varnames = vec.items; 3952 varnames = vec.items;
3962 3953
3963 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc); 3954 qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
3964 3955
3965 for (i = 0; i < vec.len; i++) { 3956 for (i = 0; i < vec.len; i++) {
3966 const char *varname = varnames[i]; 3957 const char *varname = varnames[i];
3967 Var *var = HashTable_FindValue(&ctxt->context, varname); 3958 Var *var = HashTable_FindValue(&ctxt->context, varname);
3968 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL)); 3959 debug_printf("%-16s = %s\n", varname, Buf_GetAll(&var->val, NULL));
3969 } 3960 }
3970 3961
3971 Vector_Done(&vec); 3962 Vector_Done(&vec);
3972} 3963}