Mon Nov 2 21:34:40 2020 UTC ()
make(1): fix error handling on parse errors in variable expressions

This change doesn't change any of the unit tests since the error
handling code is not yet complete, see the many "handle errors" in the
code.  Nevertheless, the "out_FALSE_res = VPR_PARSE_MSG" was wrong since
the error message was only printed in lint mode, not in default mode.


(rillig)
diff -r1.651 -r1.652 src/usr.bin/make/var.c

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

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