Sat Oct 31 18:14:59 2020 UTC ()
make(1): remove debug logging for the :Q variable modifier

The same information is already logged in LogAfterApply.


(rillig)
diff -r1.627 -r1.628 src/usr.bin/make/var.c
diff -r1.11 -r1.12 src/usr.bin/make/unit-tests/vardebug.exp

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

--- src/usr.bin/make/var.c 2020/10/31 18:05:16 1.627
+++ src/usr.bin/make/var.c 2020/10/31 18:14:59 1.628
@@ -1,2659 +1,2656 @@ @@ -1,2659 +1,2656 @@
1/* $NetBSD: var.c,v 1.627 2020/10/31 18:05:16 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.628 2020/10/31 18:14:59 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/* 71/*
72 * Handling of variables and the expressions formed from them. 72 * Handling of variables and the expressions formed from them.
73 * 73 *
74 * Variables are set using lines of the form VAR=value. Both the variable 74 * Variables are set using lines of the form VAR=value. Both the variable
75 * name and the value can contain references to other variables, by using 75 * name and the value can contain references to other variables, by using
76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. 76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77 * 77 *
78 * Interface: 78 * Interface:
79 * Var_Init Initialize this module. 79 * Var_Init Initialize this module.
80 * 80 *
81 * Var_End Clean up the module. 81 * Var_End Clean up the module.
82 * 82 *
83 * Var_Set Set the value of the variable, creating it if 83 * Var_Set Set the value of the variable, creating it if
84 * necessary. 84 * necessary.
85 * 85 *
86 * Var_Append Append more characters to the variable, creating it if 86 * Var_Append Append more characters to the variable, creating it if
87 * necessary. A space is placed between the old value and 87 * necessary. A space is placed between the old value and
88 * the new one. 88 * the new one.
89 * 89 *
90 * Var_Exists See if a variable exists. 90 * Var_Exists See if a variable exists.
91 * 91 *
92 * Var_Value Return the unexpanded value of a variable, or NULL if 92 * Var_Value Return the unexpanded value of a variable, or NULL if
93 * the variable is undefined. 93 * the variable is undefined.
94 * 94 *
95 * Var_Subst Substitute all variable expressions in a string. 95 * Var_Subst Substitute all variable expressions in a string.
96 * 96 *
97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}. 97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
98 * 98 *
99 * Var_Delete Delete a variable. 99 * Var_Delete Delete a variable.
100 * 100 *
101 * Var_ExportVars Export some or even all variables to the environment 101 * Var_ExportVars Export some or even all variables to the environment
102 * of this process and its child processes. 102 * of this process and its child processes.
103 * 103 *
104 * Var_Export Export the variable to the environment of this process 104 * Var_Export Export the variable to the environment of this process
105 * and its child processes. 105 * and its child processes.
106 * 106 *
107 * Var_UnExport Don't export the variable anymore. 107 * Var_UnExport Don't export the variable anymore.
108 * 108 *
109 * Debugging: 109 * Debugging:
110 * Var_Stats Print out hashing statistics if in -dh mode. 110 * Var_Stats Print out hashing statistics if in -dh mode.
111 * 111 *
112 * Var_Dump Print out all variables defined in the given context. 112 * Var_Dump Print out all variables defined in the given context.
113 * 113 *
114 * XXX: There's a lot of duplication in these functions. 114 * XXX: There's a lot of duplication in these functions.
115 */ 115 */
116 116
117#include <sys/stat.h> 117#include <sys/stat.h>
118#ifndef NO_REGEX 118#ifndef NO_REGEX
119#include <sys/types.h> 119#include <sys/types.h>
120#include <regex.h> 120#include <regex.h>
121#endif 121#endif
122#include <inttypes.h> 122#include <inttypes.h>
123#include <limits.h> 123#include <limits.h>
124#include <time.h> 124#include <time.h>
125 125
126#include "make.h" 126#include "make.h"
127#include "dir.h" 127#include "dir.h"
128#include "job.h" 128#include "job.h"
129#include "metachar.h" 129#include "metachar.h"
130 130
131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
132MAKE_RCSID("$NetBSD: var.c,v 1.627 2020/10/31 18:05:16 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.628 2020/10/31 18:14:59 rillig Exp $");
133 133
134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
138 138
139ENUM_FLAGS_RTTI_3(VarEvalFlags, 139ENUM_FLAGS_RTTI_3(VarEvalFlags,
140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
141 141
142/* 142/*
143 * This lets us tell if we have replaced the original environ 143 * This lets us tell if we have replaced the original environ
144 * (which we cannot free). 144 * (which we cannot free).
145 */ 145 */
146char **savedEnv = NULL; 146char **savedEnv = NULL;
147 147
148/* Special return value for Var_Parse, indicating a parse error. It may be 148/* Special return value for Var_Parse, indicating a parse error. It may be
149 * caused by an undefined variable, a syntax error in a modifier or 149 * caused by an undefined variable, a syntax error in a modifier or
150 * something entirely different. */ 150 * something entirely different. */
151char var_Error[] = ""; 151char var_Error[] = "";
152 152
153/* Special return value for Var_Parse, indicating an undefined variable in 153/* Special return value for Var_Parse, indicating an undefined variable in
154 * a case where VARE_UNDEFERR is not set. This undefined variable is 154 * a case where VARE_UNDEFERR is not set. This undefined variable is
155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
156 * be deferred until it is defined in an actual target. */ 156 * be deferred until it is defined in an actual target. */
157static char varUndefined[] = ""; 157static char varUndefined[] = "";
158 158
159/* Special return value for Var_Parse, just to avoid allocating empty strings. 159/* Special return value for Var_Parse, just to avoid allocating empty strings.
160 * In contrast to var_Error and varUndefined, this is not an error marker but 160 * In contrast to var_Error and varUndefined, this is not an error marker but
161 * just an ordinary successful return value. */ 161 * just an ordinary successful return value. */
162static char emptyString[] = ""; 162static char emptyString[] = "";
163 163
164/* 164/*
165 * Traditionally this make consumed $$ during := like any other expansion. 165 * Traditionally this make consumed $$ during := like any other expansion.
166 * Other make's do not, and this make follows straight since 2016-01-09. 166 * Other make's do not, and this make follows straight since 2016-01-09.
167 * 167 *
168 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
169 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
170 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
171 */ 171 */
172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
173static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
174 174
175/* 175/*
176 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
177 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
178 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
179 * context. 179 * context.
180 * 2) the global context. Variables set in the makefiles are located 180 * 2) the global context. Variables set in the makefiles are located
181 * here. 181 * here.
182 * 3) the command-line context. All variables set on the command line 182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. 183 * are placed in this context.
184 * 4) the local context. Each target has associated with it a context 184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are 187 * The four contexts are searched in the reverse order from which they are
188 * listed (but see opts.checkEnvFirst). 188 * listed (but see opts.checkEnvFirst).
189 */ 189 */
190GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
191GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
192GNode *VAR_CMDLINE; /* variables defined on the command-line */ 192GNode *VAR_CMDLINE; /* variables defined on the command-line */
193 193
194typedef enum VarFlags { 194typedef enum VarFlags {
195 195
196 /* The variable's value is currently being used by Var_Parse or Var_Subst. 196 /* The variable's value is currently being used by Var_Parse or Var_Subst.
197 * This marker is used to avoid endless recursion. */ 197 * This marker is used to avoid endless recursion. */
198 VAR_IN_USE = 0x01, 198 VAR_IN_USE = 0x01,
199 199
200 /* The variable comes from the environment. 200 /* The variable comes from the environment.
201 * These variables are not registered in any GNode, therefore they must 201 * These variables are not registered in any GNode, therefore they must
202 * be freed as soon as they are not used anymore. */ 202 * be freed as soon as they are not used anymore. */
203 VAR_FROM_ENV = 0x02, 203 VAR_FROM_ENV = 0x02,
204 204
205 /* The variable is exported to the environment, to be used by child 205 /* The variable is exported to the environment, to be used by child
206 * processes. */ 206 * processes. */
207 VAR_EXPORTED = 0x10, 207 VAR_EXPORTED = 0x10,
208 208
209 /* At the point where this variable was exported, it contained an 209 /* At the point where this variable was exported, it contained an
210 * unresolved reference to another variable. Before any child process is 210 * unresolved reference to another variable. Before any child process is
211 * started, it needs to be exported again, in the hope that the referenced 211 * started, it needs to be exported again, in the hope that the referenced
212 * variable can then be resolved. */ 212 * variable can then be resolved. */
213 VAR_REEXPORT = 0x20, 213 VAR_REEXPORT = 0x20,
214 214
215 /* The variable came from the command line. */ 215 /* The variable came from the command line. */
216 VAR_FROM_CMD = 0x40, 216 VAR_FROM_CMD = 0x40,
217 217
218 /* The variable value cannot be changed anymore, and the variable cannot 218 /* The variable value cannot be changed anymore, and the variable cannot
219 * be deleted. Any attempts to do so are ignored. */ 219 * be deleted. Any attempts to do so are ignored. */
220 VAR_READONLY = 0x80 220 VAR_READONLY = 0x80
221} VarFlags; 221} VarFlags;
222 222
223ENUM_FLAGS_RTTI_6(VarFlags, 223ENUM_FLAGS_RTTI_6(VarFlags,
224 VAR_IN_USE, VAR_FROM_ENV, 224 VAR_IN_USE, VAR_FROM_ENV,
225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
226 226
227/* Variables are defined using one of the VAR=value assignments. Their 227/* Variables are defined using one of the VAR=value assignments. Their
228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
229 * such as ${VAR:S,from,to,g:Q}. 229 * such as ${VAR:S,from,to,g:Q}.
230 * 230 *
231 * There are 3 kinds of variables: context variables, environment variables, 231 * There are 3 kinds of variables: context variables, environment variables,
232 * undefined variables. 232 * undefined variables.
233 * 233 *
234 * Context variables are stored in a GNode.context. The only way to undefine 234 * Context variables are stored in a GNode.context. The only way to undefine
235 * a context variable is using the .undef directive. In particular, it must 235 * a context variable is using the .undef directive. In particular, it must
236 * not be possible to undefine a variable during the evaluation of an 236 * not be possible to undefine a variable during the evaluation of an
237 * expression, or Var.name might point nowhere. 237 * expression, or Var.name might point nowhere.
238 * 238 *
239 * Environment variables are temporary. They are returned by VarFind, and 239 * Environment variables are temporary. They are returned by VarFind, and
240 * after using them, they must be freed using VarFreeEnv. 240 * after using them, they must be freed using VarFreeEnv.
241 * 241 *
242 * Undefined variables occur during evaluation of variable expressions such 242 * Undefined variables occur during evaluation of variable expressions such
243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
244 */ 244 */
245typedef struct Var { 245typedef struct Var {
246 /* The name of the variable, once set, doesn't change anymore. 246 /* The name of the variable, once set, doesn't change anymore.
247 * For context variables, it aliases the corresponding HashEntry name. 247 * For context variables, it aliases the corresponding HashEntry name.
248 * For environment and undefined variables, it is allocated. */ 248 * For environment and undefined variables, it is allocated. */
249 const char *name; 249 const char *name;
250 void *name_freeIt; 250 void *name_freeIt;
251 251
252 Buffer val; /* its value */ 252 Buffer val; /* its value */
253 VarFlags flags; /* miscellaneous status flags */ 253 VarFlags flags; /* miscellaneous status flags */
254} Var; 254} Var;
255 255
256/* 256/*
257 * Exporting vars is expensive so skip it if we can 257 * Exporting vars is expensive so skip it if we can
258 */ 258 */
259typedef enum VarExportedMode { 259typedef enum VarExportedMode {
260 VAR_EXPORTED_NONE, 260 VAR_EXPORTED_NONE,
261 VAR_EXPORTED_SOME, 261 VAR_EXPORTED_SOME,
262 VAR_EXPORTED_ALL 262 VAR_EXPORTED_ALL
263} VarExportedMode; 263} VarExportedMode;
264 264
265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
266 266
267typedef enum VarExportFlags { 267typedef enum VarExportFlags {
268 /* 268 /*
269 * We pass this to Var_Export when doing the initial export 269 * We pass this to Var_Export when doing the initial export
270 * or after updating an exported var. 270 * or after updating an exported var.
271 */ 271 */
272 VAR_EXPORT_PARENT = 0x01, 272 VAR_EXPORT_PARENT = 0x01,
273 /* 273 /*
274 * We pass this to Var_Export1 to tell it to leave the value alone. 274 * We pass this to Var_Export1 to tell it to leave the value alone.
275 */ 275 */
276 VAR_EXPORT_LITERAL = 0x02 276 VAR_EXPORT_LITERAL = 0x02
277} VarExportFlags; 277} VarExportFlags;
278 278
279/* Flags for pattern matching in the :S and :C modifiers */ 279/* Flags for pattern matching in the :S and :C modifiers */
280typedef enum VarPatternFlags { 280typedef enum VarPatternFlags {
281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */ 281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */ 282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */ 283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */ 284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
285} VarPatternFlags; 285} VarPatternFlags;
286 286
287static Var * 287static Var *
288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
289{ 289{
290 size_t value_len = strlen(value); 290 size_t value_len = strlen(value);
291 Var *var = bmake_malloc(sizeof *var); 291 Var *var = bmake_malloc(sizeof *var);
292 var->name = name; 292 var->name = name;
293 var->name_freeIt = name_freeIt; 293 var->name_freeIt = name_freeIt;
294 Buf_Init(&var->val, value_len + 1); 294 Buf_Init(&var->val, value_len + 1);
295 Buf_AddBytes(&var->val, value, value_len); 295 Buf_AddBytes(&var->val, value, value_len);
296 var->flags = flags; 296 var->flags = flags;
297 return var; 297 return var;
298} 298}
299 299
300static const char * 300static const char *
301CanonicalVarname(const char *name) 301CanonicalVarname(const char *name)
302{ 302{
303 if (*name == '.' && ch_isupper(name[1])) { 303 if (*name == '.' && ch_isupper(name[1])) {
304 switch (name[1]) { 304 switch (name[1]) {
305 case 'A': 305 case 'A':
306 if (strcmp(name, ".ALLSRC") == 0) 306 if (strcmp(name, ".ALLSRC") == 0)
307 name = ALLSRC; 307 name = ALLSRC;
308 if (strcmp(name, ".ARCHIVE") == 0) 308 if (strcmp(name, ".ARCHIVE") == 0)
309 name = ARCHIVE; 309 name = ARCHIVE;
310 break; 310 break;
311 case 'I': 311 case 'I':
312 if (strcmp(name, ".IMPSRC") == 0) 312 if (strcmp(name, ".IMPSRC") == 0)
313 name = IMPSRC; 313 name = IMPSRC;
314 break; 314 break;
315 case 'M': 315 case 'M':
316 if (strcmp(name, ".MEMBER") == 0) 316 if (strcmp(name, ".MEMBER") == 0)
317 name = MEMBER; 317 name = MEMBER;
318 break; 318 break;
319 case 'O': 319 case 'O':
320 if (strcmp(name, ".OODATE") == 0) 320 if (strcmp(name, ".OODATE") == 0)
321 name = OODATE; 321 name = OODATE;
322 break; 322 break;
323 case 'P': 323 case 'P':
324 if (strcmp(name, ".PREFIX") == 0) 324 if (strcmp(name, ".PREFIX") == 0)
325 name = PREFIX; 325 name = PREFIX;
326 break; 326 break;
327 case 'S': 327 case 'S':
328 if (strcmp(name, ".SHELL") == 0) { 328 if (strcmp(name, ".SHELL") == 0) {
329 if (!shellPath) 329 if (!shellPath)
330 Shell_Init(); 330 Shell_Init();
331 } 331 }
332 break; 332 break;
333 case 'T': 333 case 'T':
334 if (strcmp(name, ".TARGET") == 0) 334 if (strcmp(name, ".TARGET") == 0)
335 name = TARGET; 335 name = TARGET;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 339
340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
341 341
342 return name; 342 return name;
343} 343}
344 344
345static Var * 345static Var *
346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
347{ 347{
348 return HashTable_FindValueHash(&ctxt->context, varname, hash); 348 return HashTable_FindValueHash(&ctxt->context, varname, hash);
349} 349}
350 350
351/* Find the variable in the context, and maybe in other contexts as well. 351/* Find the variable in the context, and maybe in other contexts as well.
352 * 352 *
353 * Input: 353 * Input:
354 * name name to find, is not expanded any further 354 * name name to find, is not expanded any further
355 * ctxt context in which to look first 355 * ctxt context in which to look first
356 * elsewhere TRUE to look in other contexts as well 356 * elsewhere TRUE to look in other contexts as well
357 * 357 *
358 * Results: 358 * Results:
359 * The found variable, or NULL if the variable does not exist. 359 * The found variable, or NULL if the variable does not exist.
360 * If the variable is an environment variable, it must be freed using 360 * If the variable is an environment variable, it must be freed using
361 * VarFreeEnv after use. 361 * VarFreeEnv after use.
362 */ 362 */
363static Var * 363static Var *
364VarFind(const char *name, GNode *ctxt, Boolean elsewhere) 364VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
365{ 365{
366 Var *var; 366 Var *var;
367 unsigned int nameHash; 367 unsigned int nameHash;
368 368
369 /* 369 /*
370 * If the variable name begins with a '.', it could very well be one of 370 * If the variable name begins with a '.', it could very well be one of
371 * the local ones. We check the name against all the local variables 371 * the local ones. We check the name against all the local variables
372 * and substitute the short version in for 'name' if it matches one of 372 * and substitute the short version in for 'name' if it matches one of
373 * them. 373 * them.
374 */ 374 */
375 name = CanonicalVarname(name); 375 name = CanonicalVarname(name);
376 nameHash = Hash_Hash(name); 376 nameHash = Hash_Hash(name);
377 377
378 /* First look for the variable in the given context. */ 378 /* First look for the variable in the given context. */
379 var = GNode_FindVar(ctxt, name, nameHash); 379 var = GNode_FindVar(ctxt, name, nameHash);
380 if (!elsewhere) 380 if (!elsewhere)
381 return var; 381 return var;
382 382
383 /* The variable was not found in the given context. Now look for it in 383 /* The variable was not found in the given context. Now look for it in
384 * the other contexts as well. */ 384 * the other contexts as well. */
385 if (var == NULL && ctxt != VAR_CMDLINE) 385 if (var == NULL && ctxt != VAR_CMDLINE)
386 var = GNode_FindVar(VAR_CMDLINE, name, nameHash); 386 var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
387 387
388 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { 388 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
389 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 389 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
390 if (var == NULL && ctxt != VAR_INTERNAL) { 390 if (var == NULL && ctxt != VAR_INTERNAL) {
391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
392 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 392 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
393 } 393 }
394 } 394 }
395 395
396 if (var == NULL) { 396 if (var == NULL) {
397 char *env; 397 char *env;
398 398
399 if ((env = getenv(name)) != NULL) { 399 if ((env = getenv(name)) != NULL) {
400 char *varname = bmake_strdup(name); 400 char *varname = bmake_strdup(name);
401 return VarNew(varname, varname, env, VAR_FROM_ENV); 401 return VarNew(varname, varname, env, VAR_FROM_ENV);
402 } 402 }
403 403
404 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { 404 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
405 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 405 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
406 if (var == NULL && ctxt != VAR_INTERNAL) 406 if (var == NULL && ctxt != VAR_INTERNAL)
407 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 407 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
408 return var; 408 return var;
409 } 409 }
410 410
411 return NULL; 411 return NULL;
412 } 412 }
413 413
414 return var; 414 return var;
415} 415}
416 416
417/* If the variable is an environment variable, free it. 417/* If the variable is an environment variable, free it.
418 * 418 *
419 * Input: 419 * Input:
420 * v the variable 420 * v the variable
421 * freeValue true if the variable value should be freed as well 421 * freeValue true if the variable value should be freed as well
422 * 422 *
423 * Results: 423 * Results:
424 * TRUE if it is an environment variable, FALSE otherwise. 424 * TRUE if it is an environment variable, FALSE otherwise.
425 */ 425 */
426static Boolean 426static Boolean
427VarFreeEnv(Var *v, Boolean freeValue) 427VarFreeEnv(Var *v, Boolean freeValue)
428{ 428{
429 if (!(v->flags & VAR_FROM_ENV)) 429 if (!(v->flags & VAR_FROM_ENV))
430 return FALSE; 430 return FALSE;
431 431
432 free(v->name_freeIt); 432 free(v->name_freeIt);
433 Buf_Destroy(&v->val, freeValue); 433 Buf_Destroy(&v->val, freeValue);
434 free(v); 434 free(v);
435 return TRUE; 435 return TRUE;
436} 436}
437 437
438/* Add a new variable of the given name and value to the given context. 438/* Add a new variable of the given name and value to the given context.
439 * The name and val arguments are duplicated so they may safely be freed. */ 439 * The name and val arguments are duplicated so they may safely be freed. */
440static void 440static void
441VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 441VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
442{ 442{
443 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 443 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
444 Var *v = VarNew(he->key /* aliased */, NULL, val, 444 Var *v = VarNew(he->key /* aliased */, NULL, val,
445 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 445 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
446 HashEntry_Set(he, v); 446 HashEntry_Set(he, v);
447 if (!(ctxt->flags & INTERNAL)) { 447 if (!(ctxt->flags & INTERNAL)) {
448 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 448 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
449 } 449 }
450} 450}
451 451
452/* Remove a variable from a context, freeing all related memory as well. 452/* Remove a variable from a context, freeing all related memory as well.
453 * The variable name is expanded once. */ 453 * The variable name is expanded once. */
454void 454void
455Var_Delete(const char *name, GNode *ctxt) 455Var_Delete(const char *name, GNode *ctxt)
456{ 456{
457 char *name_freeIt = NULL; 457 char *name_freeIt = NULL;
458 HashEntry *he; 458 HashEntry *he;
459 459
460 if (strchr(name, '$') != NULL) { 460 if (strchr(name, '$') != NULL) {
461 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 461 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
462 /* TODO: handle errors */ 462 /* TODO: handle errors */
463 name = name_freeIt; 463 name = name_freeIt;
464 } 464 }
465 he = HashTable_FindEntry(&ctxt->context, name); 465 he = HashTable_FindEntry(&ctxt->context, name);
466 VAR_DEBUG3("%s:delete %s%s\n", 466 VAR_DEBUG3("%s:delete %s%s\n",
467 ctxt->name, name, he != NULL ? "" : " (not found)"); 467 ctxt->name, name, he != NULL ? "" : " (not found)");
468 free(name_freeIt); 468 free(name_freeIt);
469 469
470 if (he != NULL) { 470 if (he != NULL) {
471 Var *v = HashEntry_Get(he); 471 Var *v = HashEntry_Get(he);
472 if (v->flags & VAR_EXPORTED) 472 if (v->flags & VAR_EXPORTED)
473 unsetenv(v->name); 473 unsetenv(v->name);
474 if (strcmp(v->name, MAKE_EXPORTED) == 0) 474 if (strcmp(v->name, MAKE_EXPORTED) == 0)
475 var_exportedVars = VAR_EXPORTED_NONE; 475 var_exportedVars = VAR_EXPORTED_NONE;
476 assert(v->name_freeIt == NULL); 476 assert(v->name_freeIt == NULL);
477 HashTable_DeleteEntry(&ctxt->context, he); 477 HashTable_DeleteEntry(&ctxt->context, he);
478 Buf_Destroy(&v->val, TRUE); 478 Buf_Destroy(&v->val, TRUE);
479 free(v); 479 free(v);
480 } 480 }
481} 481}
482 482
483static Boolean 483static Boolean
484MayExport(const char *name) 484MayExport(const char *name)
485{ 485{
486 if (name[0] == '.') 486 if (name[0] == '.')
487 return FALSE; /* skip internals */ 487 return FALSE; /* skip internals */
488 if (name[0] == '-') 488 if (name[0] == '-')
489 return FALSE; /* skip misnamed variables */ 489 return FALSE; /* skip misnamed variables */
490 if (name[1] == '\0') { 490 if (name[1] == '\0') {
491 /* 491 /*
492 * A single char. 492 * A single char.
493 * If it is one of the vars that should only appear in 493 * If it is one of the vars that should only appear in
494 * local context, skip it, else we can get Var_Subst 494 * local context, skip it, else we can get Var_Subst
495 * into a loop. 495 * into a loop.
496 */ 496 */
497 switch (name[0]) { 497 switch (name[0]) {
498 case '@': 498 case '@':
499 case '%': 499 case '%':
500 case '*': 500 case '*':
501 case '!': 501 case '!':
502 return FALSE; 502 return FALSE;
503 } 503 }
504 } 504 }
505 return TRUE; 505 return TRUE;
506} 506}
507 507
508/* 508/*
509 * Export a single variable. 509 * Export a single variable.
510 * We ignore make internal variables (those which start with '.'). 510 * We ignore make internal variables (those which start with '.').
511 * Also we jump through some hoops to avoid calling setenv 511 * Also we jump through some hoops to avoid calling setenv
512 * more than necessary since it can leak. 512 * more than necessary since it can leak.
513 * We only manipulate flags of vars if 'parent' is set. 513 * We only manipulate flags of vars if 'parent' is set.
514 */ 514 */
515static Boolean 515static Boolean
516Var_Export1(const char *name, VarExportFlags flags) 516Var_Export1(const char *name, VarExportFlags flags)
517{ 517{
518 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 518 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
519 Var *v; 519 Var *v;
520 char *val; 520 char *val;
521 521
522 if (!MayExport(name)) 522 if (!MayExport(name))
523 return FALSE; 523 return FALSE;
524 524
525 v = VarFind(name, VAR_GLOBAL, 0); 525 v = VarFind(name, VAR_GLOBAL, 0);
526 if (v == NULL) 526 if (v == NULL)
527 return FALSE; 527 return FALSE;
528 528
529 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 529 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
530 return FALSE; /* nothing to do */ 530 return FALSE; /* nothing to do */
531 531
532 val = Buf_GetAll(&v->val, NULL); 532 val = Buf_GetAll(&v->val, NULL);
533 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 533 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
534 char *expr; 534 char *expr;
535 535
536 if (parent) { 536 if (parent) {
537 /* 537 /*
538 * Flag the variable as something we need to re-export. 538 * Flag the variable as something we need to re-export.
539 * No point actually exporting it now though, 539 * No point actually exporting it now though,
540 * the child process can do it at the last minute. 540 * the child process can do it at the last minute.
541 */ 541 */
542 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 542 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
543 return TRUE; 543 return TRUE;
544 } 544 }
545 if (v->flags & VAR_IN_USE) { 545 if (v->flags & VAR_IN_USE) {
546 /* 546 /*
547 * We recursed while exporting in a child. 547 * We recursed while exporting in a child.
548 * This isn't going to end well, just skip it. 548 * This isn't going to end well, just skip it.
549 */ 549 */
550 return FALSE; 550 return FALSE;
551 } 551 }
552 552
553 /* XXX: name is injected without escaping it */ 553 /* XXX: name is injected without escaping it */
554 expr = str_concat3("${", name, "}"); 554 expr = str_concat3("${", name, "}");
555 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 555 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
556 /* TODO: handle errors */ 556 /* TODO: handle errors */
557 setenv(name, val, 1); 557 setenv(name, val, 1);
558 free(val); 558 free(val);
559 free(expr); 559 free(expr);
560 } else { 560 } else {
561 if (parent) 561 if (parent)
562 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 562 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
563 if (parent || !(v->flags & VAR_EXPORTED)) 563 if (parent || !(v->flags & VAR_EXPORTED))
564 setenv(name, val, 1); 564 setenv(name, val, 1);
565 } 565 }
566 566
567 /* 567 /*
568 * This is so Var_Set knows to call Var_Export again... 568 * This is so Var_Set knows to call Var_Export again...
569 */ 569 */
570 if (parent) { 570 if (parent) {
571 v->flags |= VAR_EXPORTED; 571 v->flags |= VAR_EXPORTED;
572 } 572 }
573 return TRUE; 573 return TRUE;
574} 574}
575 575
576/* 576/*
577 * This gets called from our child processes. 577 * This gets called from our child processes.
578 */ 578 */
579void 579void
580Var_ExportVars(void) 580Var_ExportVars(void)
581{ 581{
582 char *val; 582 char *val;
583 583
584 /* 584 /*
585 * Several make's support this sort of mechanism for tracking 585 * Several make's support this sort of mechanism for tracking
586 * recursion - but each uses a different name. 586 * recursion - but each uses a different name.
587 * We allow the makefiles to update MAKELEVEL and ensure 587 * We allow the makefiles to update MAKELEVEL and ensure
588 * children see a correctly incremented value. 588 * children see a correctly incremented value.
589 */ 589 */
590 char tmp[BUFSIZ]; 590 char tmp[BUFSIZ];
591 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 591 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
592 setenv(MAKE_LEVEL_ENV, tmp, 1); 592 setenv(MAKE_LEVEL_ENV, tmp, 1);
593 593
594 if (var_exportedVars == VAR_EXPORTED_NONE) 594 if (var_exportedVars == VAR_EXPORTED_NONE)
595 return; 595 return;
596 596
597 if (var_exportedVars == VAR_EXPORTED_ALL) { 597 if (var_exportedVars == VAR_EXPORTED_ALL) {
598 HashIter hi; 598 HashIter hi;
599 599
600 /* Ouch! Exporting all variables at once is crazy... */ 600 /* Ouch! Exporting all variables at once is crazy... */
601 HashIter_Init(&hi, &VAR_GLOBAL->context); 601 HashIter_Init(&hi, &VAR_GLOBAL->context);
602 while (HashIter_Next(&hi) != NULL) { 602 while (HashIter_Next(&hi) != NULL) {
603 Var *var = hi.entry->value; 603 Var *var = hi.entry->value;
604 Var_Export1(var->name, 0); 604 Var_Export1(var->name, 0);
605 } 605 }
606 return; 606 return;
607 } 607 }
608 608
609 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 609 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
610 /* TODO: handle errors */ 610 /* TODO: handle errors */
611 if (*val) { 611 if (*val) {
612 Words words = Str_Words(val, FALSE); 612 Words words = Str_Words(val, FALSE);
613 size_t i; 613 size_t i;
614 614
615 for (i = 0; i < words.len; i++) 615 for (i = 0; i < words.len; i++)
616 Var_Export1(words.words[i], 0); 616 Var_Export1(words.words[i], 0);
617 Words_Free(words); 617 Words_Free(words);
618 } 618 }
619 free(val); 619 free(val);
620} 620}
621 621
622/* 622/*
623 * This is called when .export is seen or .MAKE.EXPORTED is modified. 623 * This is called when .export is seen or .MAKE.EXPORTED is modified.
624 * 624 *
625 * It is also called when any exported variable is modified. 625 * It is also called when any exported variable is modified.
626 * XXX: Is it really? 626 * XXX: Is it really?
627 * 627 *
628 * str has the format "[-env|-literal] varname...". 628 * str has the format "[-env|-literal] varname...".
629 */ 629 */
630void 630void
631Var_Export(const char *str, Boolean isExport) 631Var_Export(const char *str, Boolean isExport)
632{ 632{
633 VarExportFlags flags; 633 VarExportFlags flags;
634 char *val; 634 char *val;
635 635
636 if (isExport && str[0] == '\0') { 636 if (isExport && str[0] == '\0') {
637 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 637 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
638 return; 638 return;
639 } 639 }
640 640
641 if (isExport && strncmp(str, "-env", 4) == 0) { 641 if (isExport && strncmp(str, "-env", 4) == 0) {
642 str += 4; 642 str += 4;
643 flags = 0; 643 flags = 0;
644 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 644 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
645 str += 8; 645 str += 8;
646 flags = VAR_EXPORT_LITERAL; 646 flags = VAR_EXPORT_LITERAL;
647 } else { 647 } else {
648 flags = VAR_EXPORT_PARENT; 648 flags = VAR_EXPORT_PARENT;
649 } 649 }
650 650
651 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 651 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
652 /* TODO: handle errors */ 652 /* TODO: handle errors */
653 if (val[0] != '\0') { 653 if (val[0] != '\0') {
654 Words words = Str_Words(val, FALSE); 654 Words words = Str_Words(val, FALSE);
655 655
656 size_t i; 656 size_t i;
657 for (i = 0; i < words.len; i++) { 657 for (i = 0; i < words.len; i++) {
658 const char *name = words.words[i]; 658 const char *name = words.words[i];
659 if (Var_Export1(name, flags)) { 659 if (Var_Export1(name, flags)) {
660 if (var_exportedVars == VAR_EXPORTED_NONE) 660 if (var_exportedVars == VAR_EXPORTED_NONE)
661 var_exportedVars = VAR_EXPORTED_SOME; 661 var_exportedVars = VAR_EXPORTED_SOME;
662 if (isExport && (flags & VAR_EXPORT_PARENT)) { 662 if (isExport && (flags & VAR_EXPORT_PARENT)) {
663 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 663 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
664 } 664 }
665 } 665 }
666 } 666 }
667 Words_Free(words); 667 Words_Free(words);
668 } 668 }
669 free(val); 669 free(val);
670} 670}
671 671
672 672
673extern char **environ; 673extern char **environ;
674 674
675/* 675/*
676 * This is called when .unexport[-env] is seen. 676 * This is called when .unexport[-env] is seen.
677 * 677 *
678 * str must have the form "unexport[-env] varname...". 678 * str must have the form "unexport[-env] varname...".
679 */ 679 */
680void 680void
681Var_UnExport(const char *str) 681Var_UnExport(const char *str)
682{ 682{
683 const char *varnames; 683 const char *varnames;
684 char *varnames_freeIt; 684 char *varnames_freeIt;
685 Boolean unexport_env; 685 Boolean unexport_env;
686 686
687 varnames = NULL; 687 varnames = NULL;
688 varnames_freeIt = NULL; 688 varnames_freeIt = NULL;
689 689
690 str += strlen("unexport"); 690 str += strlen("unexport");
691 unexport_env = strncmp(str, "-env", 4) == 0; 691 unexport_env = strncmp(str, "-env", 4) == 0;
692 if (unexport_env) { 692 if (unexport_env) {
693 const char *cp; 693 const char *cp;
694 char **newenv; 694 char **newenv;
695 695
696 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 696 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
697 if (environ == savedEnv) { 697 if (environ == savedEnv) {
698 /* we have been here before! */ 698 /* we have been here before! */
699 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 699 newenv = bmake_realloc(environ, 2 * sizeof(char *));
700 } else { 700 } else {
701 if (savedEnv) { 701 if (savedEnv) {
702 free(savedEnv); 702 free(savedEnv);
703 savedEnv = NULL; 703 savedEnv = NULL;
704 } 704 }
705 newenv = bmake_malloc(2 * sizeof(char *)); 705 newenv = bmake_malloc(2 * sizeof(char *));
706 } 706 }
707 707
708 /* Note: we cannot safely free() the original environ. */ 708 /* Note: we cannot safely free() the original environ. */
709 environ = savedEnv = newenv; 709 environ = savedEnv = newenv;
710 newenv[0] = NULL; 710 newenv[0] = NULL;
711 newenv[1] = NULL; 711 newenv[1] = NULL;
712 if (cp && *cp) 712 if (cp && *cp)
713 setenv(MAKE_LEVEL_ENV, cp, 1); 713 setenv(MAKE_LEVEL_ENV, cp, 1);
714 } else { 714 } else {
715 cpp_skip_whitespace(&str); 715 cpp_skip_whitespace(&str);
716 if (str[0] != '\0') 716 if (str[0] != '\0')
717 varnames = str; 717 varnames = str;
718 } 718 }
719 719
720 if (varnames == NULL) { 720 if (varnames == NULL) {
721 /* Using .MAKE.EXPORTED */ 721 /* Using .MAKE.EXPORTED */
722 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 722 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
723 &varnames_freeIt); 723 &varnames_freeIt);
724 /* TODO: handle errors */ 724 /* TODO: handle errors */
725 varnames = varnames_freeIt; 725 varnames = varnames_freeIt;
726 } 726 }
727 727
728 { 728 {
729 Var *v; 729 Var *v;
730 size_t i; 730 size_t i;
731 731
732 Words words = Str_Words(varnames, FALSE); 732 Words words = Str_Words(varnames, FALSE);
733 for (i = 0; i < words.len; i++) { 733 for (i = 0; i < words.len; i++) {
734 const char *varname = words.words[i]; 734 const char *varname = words.words[i];
735 v = VarFind(varname, VAR_GLOBAL, 0); 735 v = VarFind(varname, VAR_GLOBAL, 0);
736 if (v == NULL) { 736 if (v == NULL) {
737 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 737 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
738 continue; 738 continue;
739 } 739 }
740 740
741 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 741 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
742 if (!unexport_env && (v->flags & VAR_EXPORTED) && 742 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
743 !(v->flags & VAR_REEXPORT)) 743 !(v->flags & VAR_REEXPORT))
744 unsetenv(v->name); 744 unsetenv(v->name);
745 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 745 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
746 746
747 /* 747 /*
748 * If we are unexporting a list, 748 * If we are unexporting a list,
749 * remove each one from .MAKE.EXPORTED. 749 * remove each one from .MAKE.EXPORTED.
750 * If we are removing them all, 750 * If we are removing them all,
751 * just delete .MAKE.EXPORTED below. 751 * just delete .MAKE.EXPORTED below.
752 */ 752 */
753 if (varnames == str) { 753 if (varnames == str) {
754 /* XXX: v->name is injected without escaping it */ 754 /* XXX: v->name is injected without escaping it */
755 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 755 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
756 char *cp; 756 char *cp;
757 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 757 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
758 /* TODO: handle errors */ 758 /* TODO: handle errors */
759 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 759 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
760 free(cp); 760 free(cp);
761 free(expr); 761 free(expr);
762 } 762 }
763 } 763 }
764 Words_Free(words); 764 Words_Free(words);
765 if (varnames != str) { 765 if (varnames != str) {
766 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 766 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
767 free(varnames_freeIt); 767 free(varnames_freeIt);
768 } 768 }
769 } 769 }
770} 770}
771 771
772/* See Var_Set for documentation. */ 772/* See Var_Set for documentation. */
773void 773void
774Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 774Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
775 VarSet_Flags flags) 775 VarSet_Flags flags)
776{ 776{
777 const char *unexpanded_name = name; 777 const char *unexpanded_name = name;
778 char *name_freeIt = NULL; 778 char *name_freeIt = NULL;
779 Var *v; 779 Var *v;
780 780
781 assert(val != NULL); 781 assert(val != NULL);
782 782
783 if (strchr(name, '$') != NULL) { 783 if (strchr(name, '$') != NULL) {
784 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 784 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
785 /* TODO: handle errors */ 785 /* TODO: handle errors */
786 name = name_freeIt; 786 name = name_freeIt;
787 } 787 }
788 788
789 if (name[0] == '\0') { 789 if (name[0] == '\0') {
790 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 790 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
791 "name expands to empty string - ignored\n", 791 "name expands to empty string - ignored\n",
792 unexpanded_name, val); 792 unexpanded_name, val);
793 free(name_freeIt); 793 free(name_freeIt);
794 return; 794 return;
795 } 795 }
796 796
797 if (ctxt == VAR_GLOBAL) { 797 if (ctxt == VAR_GLOBAL) {
798 v = VarFind(name, VAR_CMDLINE, 0); 798 v = VarFind(name, VAR_CMDLINE, 0);
799 if (v != NULL) { 799 if (v != NULL) {
800 if (v->flags & VAR_FROM_CMD) { 800 if (v->flags & VAR_FROM_CMD) {
801 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 801 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
802 goto out; 802 goto out;
803 } 803 }
804 VarFreeEnv(v, TRUE); 804 VarFreeEnv(v, TRUE);
805 } 805 }
806 } 806 }
807 807
808 /* 808 /*
809 * We only look for a variable in the given context since anything set 809 * We only look for a variable in the given context since anything set
810 * here will override anything in a lower context, so there's not much 810 * here will override anything in a lower context, so there's not much
811 * point in searching them all just to save a bit of memory... 811 * point in searching them all just to save a bit of memory...
812 */ 812 */
813 v = VarFind(name, ctxt, 0); 813 v = VarFind(name, ctxt, 0);
814 if (v == NULL) { 814 if (v == NULL) {
815 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 815 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
816 /* 816 /*
817 * This var would normally prevent the same name being added 817 * This var would normally prevent the same name being added
818 * to VAR_GLOBAL, so delete it from there if needed. 818 * to VAR_GLOBAL, so delete it from there if needed.
819 * Otherwise -V name may show the wrong value. 819 * Otherwise -V name may show the wrong value.
820 */ 820 */
821 /* XXX: name is expanded for the second time */ 821 /* XXX: name is expanded for the second time */
822 Var_Delete(name, VAR_GLOBAL); 822 Var_Delete(name, VAR_GLOBAL);
823 } 823 }
824 VarAdd(name, val, ctxt, flags); 824 VarAdd(name, val, ctxt, flags);
825 } else { 825 } else {
826 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 826 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
827 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 827 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
828 ctxt->name, name, val); 828 ctxt->name, name, val);
829 goto out; 829 goto out;
830 } 830 }
831 Buf_Empty(&v->val); 831 Buf_Empty(&v->val);
832 Buf_AddStr(&v->val, val); 832 Buf_AddStr(&v->val, val);
833 833
834 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 834 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
835 if (v->flags & VAR_EXPORTED) { 835 if (v->flags & VAR_EXPORTED) {
836 Var_Export1(name, VAR_EXPORT_PARENT); 836 Var_Export1(name, VAR_EXPORT_PARENT);
837 } 837 }
838 } 838 }
839 /* 839 /*
840 * Any variables given on the command line are automatically exported 840 * Any variables given on the command line are automatically exported
841 * to the environment (as per POSIX standard) 841 * to the environment (as per POSIX standard)
842 * Other than internals. 842 * Other than internals.
843 */ 843 */
844 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 844 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
845 if (v == NULL) 845 if (v == NULL)
846 v = VarFind(name, ctxt, 0); /* we just added it */ 846 v = VarFind(name, ctxt, 0); /* we just added it */
847 v->flags |= VAR_FROM_CMD; 847 v->flags |= VAR_FROM_CMD;
848 848
849 /* 849 /*
850 * If requested, don't export these in the environment 850 * If requested, don't export these in the environment
851 * individually. We still put them in MAKEOVERRIDES so 851 * individually. We still put them in MAKEOVERRIDES so
852 * that the command-line settings continue to override 852 * that the command-line settings continue to override
853 * Makefile settings. 853 * Makefile settings.
854 */ 854 */
855 if (!opts.varNoExportEnv) 855 if (!opts.varNoExportEnv)
856 setenv(name, val, 1); 856 setenv(name, val, 1);
857 857
858 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 858 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
859 } 859 }
860 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 860 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
861 save_dollars = s2Boolean(val, save_dollars); 861 save_dollars = s2Boolean(val, save_dollars);
862 862
863out: 863out:
864 free(name_freeIt); 864 free(name_freeIt);
865 if (v != NULL) 865 if (v != NULL)
866 VarFreeEnv(v, TRUE); 866 VarFreeEnv(v, TRUE);
867} 867}
868 868
869/*- 869/*-
870 *----------------------------------------------------------------------- 870 *-----------------------------------------------------------------------
871 * Var_Set -- 871 * Var_Set --
872 * Set the variable name to the value val in the given context. 872 * Set the variable name to the value val in the given context.
873 * 873 *
874 * If the variable doesn't yet exist, it is created. 874 * If the variable doesn't yet exist, it is created.
875 * Otherwise the new value overwrites and replaces the old value. 875 * Otherwise the new value overwrites and replaces the old value.
876 * 876 *
877 * Input: 877 * Input:
878 * name name of the variable to set, is expanded once 878 * name name of the variable to set, is expanded once
879 * val value to give to the variable 879 * val value to give to the variable
880 * ctxt context in which to set it 880 * ctxt context in which to set it
881 * 881 *
882 * Notes: 882 * Notes:
883 * The variable is searched for only in its context before being 883 * The variable is searched for only in its context before being
884 * created in that context. I.e. if the context is VAR_GLOBAL, 884 * created in that context. I.e. if the context is VAR_GLOBAL,
885 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 885 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
886 * only VAR_CMDLINE->context is searched. This is done to avoid the 886 * only VAR_CMDLINE->context is searched. This is done to avoid the
887 * literally thousands of unnecessary strcmp's that used to be done to 887 * literally thousands of unnecessary strcmp's that used to be done to
888 * set, say, $(@) or $(<). 888 * set, say, $(@) or $(<).
889 * If the context is VAR_GLOBAL though, we check if the variable 889 * If the context is VAR_GLOBAL though, we check if the variable
890 * was set in VAR_CMDLINE from the command line and skip it if so. 890 * was set in VAR_CMDLINE from the command line and skip it if so.
891 *----------------------------------------------------------------------- 891 *-----------------------------------------------------------------------
892 */ 892 */
893void 893void
894Var_Set(const char *name, const char *val, GNode *ctxt) 894Var_Set(const char *name, const char *val, GNode *ctxt)
895{ 895{
896 Var_Set_with_flags(name, val, ctxt, 0); 896 Var_Set_with_flags(name, val, ctxt, 0);
897} 897}
898 898
899/*- 899/*-
900 *----------------------------------------------------------------------- 900 *-----------------------------------------------------------------------
901 * Var_Append -- 901 * Var_Append --
902 * The variable of the given name has the given value appended to it in 902 * The variable of the given name has the given value appended to it in
903 * the given context. 903 * the given context.
904 * 904 *
905 * If the variable doesn't exist, it is created. Otherwise the strings 905 * If the variable doesn't exist, it is created. Otherwise the strings
906 * are concatenated, with a space in between. 906 * are concatenated, with a space in between.
907 * 907 *
908 * Input: 908 * Input:
909 * name name of the variable to modify, is expanded once 909 * name name of the variable to modify, is expanded once
910 * val string to append to it 910 * val string to append to it
911 * ctxt context in which this should occur 911 * ctxt context in which this should occur
912 * 912 *
913 * Notes: 913 * Notes:
914 * Only if the variable is being sought in the global context is the 914 * Only if the variable is being sought in the global context is the
915 * environment searched. 915 * environment searched.
916 * XXX: Knows its calling circumstances in that if called with ctxt 916 * XXX: Knows its calling circumstances in that if called with ctxt
917 * an actual target, it will only search that context since only 917 * an actual target, it will only search that context since only
918 * a local variable could be being appended to. This is actually 918 * a local variable could be being appended to. This is actually
919 * a big win and must be tolerated. 919 * a big win and must be tolerated.
920 *----------------------------------------------------------------------- 920 *-----------------------------------------------------------------------
921 */ 921 */
922void 922void
923Var_Append(const char *name, const char *val, GNode *ctxt) 923Var_Append(const char *name, const char *val, GNode *ctxt)
924{ 924{
925 char *name_freeIt = NULL; 925 char *name_freeIt = NULL;
926 Var *v; 926 Var *v;
927 927
928 assert(val != NULL); 928 assert(val != NULL);
929 929
930 if (strchr(name, '$') != NULL) { 930 if (strchr(name, '$') != NULL) {
931 const char *unexpanded_name = name; 931 const char *unexpanded_name = name;
932 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 932 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
933 /* TODO: handle errors */ 933 /* TODO: handle errors */
934 name = name_freeIt; 934 name = name_freeIt;
935 if (name[0] == '\0') { 935 if (name[0] == '\0') {
936 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 936 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
937 "name expands to empty string - ignored\n", 937 "name expands to empty string - ignored\n",
938 unexpanded_name, val); 938 unexpanded_name, val);
939 free(name_freeIt); 939 free(name_freeIt);
940 return; 940 return;
941 } 941 }
942 } 942 }
943 943
944 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 944 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
945 945
946 if (v == NULL) { 946 if (v == NULL) {
947 /* XXX: name is expanded for the second time */ 947 /* XXX: name is expanded for the second time */
948 Var_Set(name, val, ctxt); 948 Var_Set(name, val, ctxt);
949 } else if (v->flags & VAR_READONLY) { 949 } else if (v->flags & VAR_READONLY) {
950 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 950 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
951 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 951 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
952 Buf_AddByte(&v->val, ' '); 952 Buf_AddByte(&v->val, ' ');
953 Buf_AddStr(&v->val, val); 953 Buf_AddStr(&v->val, val);
954 954
955 VAR_DEBUG3("%s:%s = %s\n", 955 VAR_DEBUG3("%s:%s = %s\n",
956 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 956 ctxt->name, name, Buf_GetAll(&v->val, NULL));
957 957
958 if (v->flags & VAR_FROM_ENV) { 958 if (v->flags & VAR_FROM_ENV) {
959 HashEntry *h; 959 HashEntry *h;
960 960
961 /* 961 /*
962 * If the original variable came from the environment, we 962 * If the original variable came from the environment, we
963 * have to install it in the global context (we could place 963 * have to install it in the global context (we could place
964 * it in the environment, but then we should provide a way to 964 * it in the environment, but then we should provide a way to
965 * export other variables...) 965 * export other variables...)
966 */ 966 */
967 v->flags &= ~(unsigned)VAR_FROM_ENV; 967 v->flags &= ~(unsigned)VAR_FROM_ENV;
968 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 968 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
969 HashEntry_Set(h, v); 969 HashEntry_Set(h, v);
970 } 970 }
971 } 971 }
972 free(name_freeIt); 972 free(name_freeIt);
973} 973}
974 974
975/* See if the given variable exists, in the given context or in other 975/* See if the given variable exists, in the given context or in other
976 * fallback contexts. 976 * fallback contexts.
977 * 977 *
978 * Input: 978 * Input:
979 * name Variable to find, is expanded once 979 * name Variable to find, is expanded once
980 * ctxt Context in which to start search 980 * ctxt Context in which to start search
981 */ 981 */
982Boolean 982Boolean
983Var_Exists(const char *name, GNode *ctxt) 983Var_Exists(const char *name, GNode *ctxt)
984{ 984{
985 char *name_freeIt = NULL; 985 char *name_freeIt = NULL;
986 Var *v; 986 Var *v;
987 987
988 if (strchr(name, '$') != NULL) { 988 if (strchr(name, '$') != NULL) {
989 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 989 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
990 /* TODO: handle errors */ 990 /* TODO: handle errors */
991 name = name_freeIt; 991 name = name_freeIt;
992 } 992 }
993 993
994 v = VarFind(name, ctxt, TRUE); 994 v = VarFind(name, ctxt, TRUE);
995 free(name_freeIt); 995 free(name_freeIt);
996 if (v == NULL) 996 if (v == NULL)
997 return FALSE; 997 return FALSE;
998 998
999 (void)VarFreeEnv(v, TRUE); 999 (void)VarFreeEnv(v, TRUE);
1000 return TRUE; 1000 return TRUE;
1001} 1001}
1002 1002
1003/*- 1003/*-
1004 *----------------------------------------------------------------------- 1004 *-----------------------------------------------------------------------
1005 * Var_Value -- 1005 * Var_Value --
1006 * Return the unexpanded value of the given variable in the given 1006 * Return the unexpanded value of the given variable in the given
1007 * context, or the usual contexts. 1007 * context, or the usual contexts.
1008 * 1008 *
1009 * Input: 1009 * Input:
1010 * name name to find, is not expanded any further 1010 * name name to find, is not expanded any further
1011 * ctxt context in which to search for it 1011 * ctxt context in which to search for it
1012 * 1012 *
1013 * Results: 1013 * Results:
1014 * The value if the variable exists, NULL if it doesn't. 1014 * The value if the variable exists, NULL if it doesn't.
1015 * If the returned value is not NULL, the caller must free *freeIt 1015 * If the returned value is not NULL, the caller must free *freeIt
1016 * as soon as the returned value is no longer needed. 1016 * as soon as the returned value is no longer needed.
1017 *----------------------------------------------------------------------- 1017 *-----------------------------------------------------------------------
1018 */ 1018 */
1019const char * 1019const char *
1020Var_Value(const char *name, GNode *ctxt, void **freeIt) 1020Var_Value(const char *name, GNode *ctxt, void **freeIt)
1021{ 1021{
1022 Var *v = VarFind(name, ctxt, TRUE); 1022 Var *v = VarFind(name, ctxt, TRUE);
1023 char *value; 1023 char *value;
1024 1024
1025 *freeIt = NULL; 1025 *freeIt = NULL;
1026 if (v == NULL) 1026 if (v == NULL)
1027 return NULL; 1027 return NULL;
1028 1028
1029 value = Buf_GetAll(&v->val, NULL); 1029 value = Buf_GetAll(&v->val, NULL);
1030 if (VarFreeEnv(v, FALSE)) 1030 if (VarFreeEnv(v, FALSE))
1031 *freeIt = value; 1031 *freeIt = value;
1032 return value; 1032 return value;
1033} 1033}
1034 1034
1035/* Return the unexpanded variable value from this node, without trying to look 1035/* Return the unexpanded variable value from this node, without trying to look
1036 * up the variable in any other context. */ 1036 * up the variable in any other context. */
1037const char * 1037const char *
1038Var_ValueDirect(const char *name, GNode *ctxt) 1038Var_ValueDirect(const char *name, GNode *ctxt)
1039{ 1039{
1040 Var *v = VarFind(name, ctxt, FALSE); 1040 Var *v = VarFind(name, ctxt, FALSE);
1041 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL; 1041 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
1042} 1042}
1043 1043
1044 1044
1045/* SepBuf is a string being built from words, interleaved with separators. */ 1045/* SepBuf is a string being built from words, interleaved with separators. */
1046typedef struct SepBuf { 1046typedef struct SepBuf {
1047 Buffer buf; 1047 Buffer buf;
1048 Boolean needSep; 1048 Boolean needSep;
1049 char sep; /* usually ' ', but see the :ts modifier */ 1049 char sep; /* usually ' ', but see the :ts modifier */
1050} SepBuf; 1050} SepBuf;
1051 1051
1052static void 1052static void
1053SepBuf_Init(SepBuf *buf, char sep) 1053SepBuf_Init(SepBuf *buf, char sep)
1054{ 1054{
1055 Buf_Init(&buf->buf, 32 /* bytes */); 1055 Buf_Init(&buf->buf, 32 /* bytes */);
1056 buf->needSep = FALSE; 1056 buf->needSep = FALSE;
1057 buf->sep = sep; 1057 buf->sep = sep;
1058} 1058}
1059 1059
1060static void 1060static void
1061SepBuf_Sep(SepBuf *buf) 1061SepBuf_Sep(SepBuf *buf)
1062{ 1062{
1063 buf->needSep = TRUE; 1063 buf->needSep = TRUE;
1064} 1064}
1065 1065
1066static void 1066static void
1067SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1067SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1068{ 1068{
1069 if (mem_size == 0) 1069 if (mem_size == 0)
1070 return; 1070 return;
1071 if (buf->needSep && buf->sep != '\0') { 1071 if (buf->needSep && buf->sep != '\0') {
1072 Buf_AddByte(&buf->buf, buf->sep); 1072 Buf_AddByte(&buf->buf, buf->sep);
1073 buf->needSep = FALSE; 1073 buf->needSep = FALSE;
1074 } 1074 }
1075 Buf_AddBytes(&buf->buf, mem, mem_size); 1075 Buf_AddBytes(&buf->buf, mem, mem_size);
1076} 1076}
1077 1077
1078static void 1078static void
1079SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1079SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1080{ 1080{
1081 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1081 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1082} 1082}
1083 1083
1084static void 1084static void
1085SepBuf_AddStr(SepBuf *buf, const char *str) 1085SepBuf_AddStr(SepBuf *buf, const char *str)
1086{ 1086{
1087 SepBuf_AddBytes(buf, str, strlen(str)); 1087 SepBuf_AddBytes(buf, str, strlen(str));
1088} 1088}
1089 1089
1090static char * 1090static char *
1091SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1091SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1092{ 1092{
1093 return Buf_Destroy(&buf->buf, free_buf); 1093 return Buf_Destroy(&buf->buf, free_buf);
1094} 1094}
1095 1095
1096 1096
1097/* This callback for ModifyWords gets a single word from a variable expression 1097/* This callback for ModifyWords gets a single word from a variable expression
1098 * and typically adds a modification of this word to the buffer. It may also 1098 * and typically adds a modification of this word to the buffer. It may also
1099 * do nothing or add several words. 1099 * do nothing or add several words.
1100 * 1100 *
1101 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for 1101 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1102 * each word of "a b c". */ 1102 * each word of "a b c". */
1103typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1103typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1104 1104
1105 1105
1106/* Callback for ModifyWords to implement the :H modifier. 1106/* Callback for ModifyWords to implement the :H modifier.
1107 * Add the dirname of the given word to the buffer. */ 1107 * Add the dirname of the given word to the buffer. */
1108static void 1108static void
1109ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1109ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1110{ 1110{
1111 const char *slash = strrchr(word, '/'); 1111 const char *slash = strrchr(word, '/');
1112 if (slash != NULL) 1112 if (slash != NULL)
1113 SepBuf_AddBytesBetween(buf, word, slash); 1113 SepBuf_AddBytesBetween(buf, word, slash);
1114 else 1114 else
1115 SepBuf_AddStr(buf, "."); 1115 SepBuf_AddStr(buf, ".");
1116} 1116}
1117 1117
1118/* Callback for ModifyWords to implement the :T modifier. 1118/* Callback for ModifyWords to implement the :T modifier.
1119 * Add the basename of the given word to the buffer. */ 1119 * Add the basename of the given word to the buffer. */
1120static void 1120static void
1121ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1121ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1122{ 1122{
1123 const char *slash = strrchr(word, '/'); 1123 const char *slash = strrchr(word, '/');
1124 const char *base = slash != NULL ? slash + 1 : word; 1124 const char *base = slash != NULL ? slash + 1 : word;
1125 SepBuf_AddStr(buf, base); 1125 SepBuf_AddStr(buf, base);
1126} 1126}
1127 1127
1128/* Callback for ModifyWords to implement the :E modifier. 1128/* Callback for ModifyWords to implement the :E modifier.
1129 * Add the filename suffix of the given word to the buffer, if it exists. */ 1129 * Add the filename suffix of the given word to the buffer, if it exists. */
1130static void 1130static void
1131ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1131ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1132{ 1132{
1133 const char *dot = strrchr(word, '.'); 1133 const char *dot = strrchr(word, '.');
1134 if (dot != NULL) 1134 if (dot != NULL)
1135 SepBuf_AddStr(buf, dot + 1); 1135 SepBuf_AddStr(buf, dot + 1);
1136} 1136}
1137 1137
1138/* Callback for ModifyWords to implement the :R modifier. 1138/* Callback for ModifyWords to implement the :R modifier.
1139 * Add the basename of the given word to the buffer. */ 1139 * Add the basename of the given word to the buffer. */
1140static void 1140static void
1141ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1141ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1142{ 1142{
1143 const char *dot = strrchr(word, '.'); 1143 const char *dot = strrchr(word, '.');
1144 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1144 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1145 SepBuf_AddBytes(buf, word, len); 1145 SepBuf_AddBytes(buf, word, len);
1146} 1146}
1147 1147
1148/* Callback for ModifyWords to implement the :M modifier. 1148/* Callback for ModifyWords to implement the :M modifier.
1149 * Place the word in the buffer if it matches the given pattern. */ 1149 * Place the word in the buffer if it matches the given pattern. */
1150static void 1150static void
1151ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1151ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1152{ 1152{
1153 const char *pattern = data; 1153 const char *pattern = data;
1154 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1154 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1155 if (Str_Match(word, pattern)) 1155 if (Str_Match(word, pattern))
1156 SepBuf_AddStr(buf, word); 1156 SepBuf_AddStr(buf, word);
1157} 1157}
1158 1158
1159/* Callback for ModifyWords to implement the :N modifier. 1159/* Callback for ModifyWords to implement the :N modifier.
1160 * Place the word in the buffer if it doesn't match the given pattern. */ 1160 * Place the word in the buffer if it doesn't match the given pattern. */
1161static void 1161static void
1162ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1162ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1163{ 1163{
1164 const char *pattern = data; 1164 const char *pattern = data;
1165 if (!Str_Match(word, pattern)) 1165 if (!Str_Match(word, pattern))
1166 SepBuf_AddStr(buf, word); 1166 SepBuf_AddStr(buf, word);
1167} 1167}
1168 1168
1169#ifdef SYSVVARSUB 1169#ifdef SYSVVARSUB
1170/* Check word against pattern for a match (% is a wildcard). 1170/* Check word against pattern for a match (% is a wildcard).
1171 * 1171 *
1172 * Input: 1172 * Input:
1173 * word Word to examine 1173 * word Word to examine
1174 * pattern Pattern to examine against 1174 * pattern Pattern to examine against
1175 * 1175 *
1176 * Results: 1176 * Results:
1177 * Returns the start of the match, or NULL. 1177 * Returns the start of the match, or NULL.
1178 * out_match_len returns the length of the match, if any. 1178 * out_match_len returns the length of the match, if any.
1179 * out_hasPercent returns whether the pattern contains a percent. 1179 * out_hasPercent returns whether the pattern contains a percent.
1180 */ 1180 */
1181static const char * 1181static const char *
1182SysVMatch(const char *word, const char *pattern, 1182SysVMatch(const char *word, const char *pattern,
1183 size_t *out_match_len, Boolean *out_hasPercent) 1183 size_t *out_match_len, Boolean *out_hasPercent)
1184{ 1184{
1185 const char *p = pattern; 1185 const char *p = pattern;
1186 const char *w = word; 1186 const char *w = word;
1187 const char *percent; 1187 const char *percent;
1188 size_t w_len; 1188 size_t w_len;
1189 size_t p_len; 1189 size_t p_len;
1190 const char *w_tail; 1190 const char *w_tail;
1191 1191
1192 *out_hasPercent = FALSE; 1192 *out_hasPercent = FALSE;
1193 percent = strchr(p, '%'); 1193 percent = strchr(p, '%');
1194 if (percent != NULL) { /* ${VAR:...%...=...} */ 1194 if (percent != NULL) { /* ${VAR:...%...=...} */
1195 *out_hasPercent = TRUE; 1195 *out_hasPercent = TRUE;
1196 if (*w == '\0') 1196 if (*w == '\0')
1197 return NULL; /* empty word does not match pattern */ 1197 return NULL; /* empty word does not match pattern */
1198 1198
1199 /* check that the prefix matches */ 1199 /* check that the prefix matches */
1200 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1200 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1201 continue; 1201 continue;
1202 if (p != percent) 1202 if (p != percent)
1203 return NULL; /* No match */ 1203 return NULL; /* No match */
1204 1204
1205 p++; /* Skip the percent */ 1205 p++; /* Skip the percent */
1206 if (*p == '\0') { 1206 if (*p == '\0') {
1207 /* No more pattern, return the rest of the string */ 1207 /* No more pattern, return the rest of the string */
1208 *out_match_len = strlen(w); 1208 *out_match_len = strlen(w);
1209 return w; 1209 return w;
1210 } 1210 }
1211 } 1211 }
1212 1212
1213 /* Test whether the tail matches */ 1213 /* Test whether the tail matches */
1214 w_len = strlen(w); 1214 w_len = strlen(w);
1215 p_len = strlen(p); 1215 p_len = strlen(p);
1216 if (w_len < p_len) 1216 if (w_len < p_len)
1217 return NULL; 1217 return NULL;
1218 1218
1219 w_tail = w + w_len - p_len; 1219 w_tail = w + w_len - p_len;
1220 if (memcmp(p, w_tail, p_len) != 0) 1220 if (memcmp(p, w_tail, p_len) != 0)
1221 return NULL; 1221 return NULL;
1222 1222
1223 *out_match_len = (size_t)(w_tail - w); 1223 *out_match_len = (size_t)(w_tail - w);
1224 return w; 1224 return w;
1225} 1225}
1226 1226
1227struct ModifyWord_SYSVSubstArgs { 1227struct ModifyWord_SYSVSubstArgs {
1228 GNode *ctx; 1228 GNode *ctx;
1229 const char *lhs; 1229 const char *lhs;
1230 const char *rhs; 1230 const char *rhs;
1231}; 1231};
1232 1232
1233/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1233/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1234static void 1234static void
1235ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1235ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1236{ 1236{
1237 const struct ModifyWord_SYSVSubstArgs *args = data; 1237 const struct ModifyWord_SYSVSubstArgs *args = data;
1238 char *rhs_expanded; 1238 char *rhs_expanded;
1239 const char *rhs; 1239 const char *rhs;
1240 const char *percent; 1240 const char *percent;
1241 1241
1242 size_t match_len; 1242 size_t match_len;
1243 Boolean lhsPercent; 1243 Boolean lhsPercent;
1244 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent); 1244 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
1245 if (match == NULL) { 1245 if (match == NULL) {
1246 SepBuf_AddStr(buf, word); 1246 SepBuf_AddStr(buf, word);
1247 return; 1247 return;
1248 } 1248 }
1249 1249
1250 /* Append rhs to the buffer, substituting the first '%' with the 1250 /* Append rhs to the buffer, substituting the first '%' with the
1251 * match, but only if the lhs had a '%' as well. */ 1251 * match, but only if the lhs had a '%' as well. */
1252 1252
1253 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1253 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1254 /* TODO: handle errors */ 1254 /* TODO: handle errors */
1255 1255
1256 rhs = rhs_expanded; 1256 rhs = rhs_expanded;
1257 percent = strchr(rhs, '%'); 1257 percent = strchr(rhs, '%');
1258 1258
1259 if (percent != NULL && lhsPercent) { 1259 if (percent != NULL && lhsPercent) {
1260 /* Copy the prefix of the replacement pattern */ 1260 /* Copy the prefix of the replacement pattern */
1261 SepBuf_AddBytesBetween(buf, rhs, percent); 1261 SepBuf_AddBytesBetween(buf, rhs, percent);
1262 rhs = percent + 1; 1262 rhs = percent + 1;
1263 } 1263 }
1264 if (percent != NULL || !lhsPercent) 1264 if (percent != NULL || !lhsPercent)
1265 SepBuf_AddBytes(buf, match, match_len); 1265 SepBuf_AddBytes(buf, match, match_len);
1266 1266
1267 /* Append the suffix of the replacement pattern */ 1267 /* Append the suffix of the replacement pattern */
1268 SepBuf_AddStr(buf, rhs); 1268 SepBuf_AddStr(buf, rhs);
1269 1269
1270 free(rhs_expanded); 1270 free(rhs_expanded);
1271} 1271}
1272#endif 1272#endif
1273 1273
1274 1274
1275struct ModifyWord_SubstArgs { 1275struct ModifyWord_SubstArgs {
1276 const char *lhs; 1276 const char *lhs;
1277 size_t lhsLen; 1277 size_t lhsLen;
1278 const char *rhs; 1278 const char *rhs;
1279 size_t rhsLen; 1279 size_t rhsLen;
1280 VarPatternFlags pflags; 1280 VarPatternFlags pflags;
1281 Boolean matched; 1281 Boolean matched;
1282}; 1282};
1283 1283
1284/* Callback for ModifyWords to implement the :S,from,to, modifier. 1284/* Callback for ModifyWords to implement the :S,from,to, modifier.
1285 * Perform a string substitution on the given word. */ 1285 * Perform a string substitution on the given word. */
1286static void 1286static void
1287ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1287ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1288{ 1288{
1289 size_t wordLen = strlen(word); 1289 size_t wordLen = strlen(word);
1290 struct ModifyWord_SubstArgs *args = data; 1290 struct ModifyWord_SubstArgs *args = data;
1291 const char *match; 1291 const char *match;
1292 1292
1293 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1293 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1294 goto nosub; 1294 goto nosub;
1295 1295
1296 if (args->pflags & VARP_ANCHOR_START) { 1296 if (args->pflags & VARP_ANCHOR_START) {
1297 if (wordLen < args->lhsLen || 1297 if (wordLen < args->lhsLen ||
1298 memcmp(word, args->lhs, args->lhsLen) != 0) 1298 memcmp(word, args->lhs, args->lhsLen) != 0)
1299 goto nosub; 1299 goto nosub;
1300 1300
1301 if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen) 1301 if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
1302 goto nosub; 1302 goto nosub;
1303 1303
1304 /* :S,^prefix,replacement, or :S,^whole$,replacement, */ 1304 /* :S,^prefix,replacement, or :S,^whole$,replacement, */
1305 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1305 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1306 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1306 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1307 args->matched = TRUE; 1307 args->matched = TRUE;
1308 return; 1308 return;
1309 } 1309 }
1310 1310
1311 if (args->pflags & VARP_ANCHOR_END) { 1311 if (args->pflags & VARP_ANCHOR_END) {
1312 const char *start; 1312 const char *start;
1313 1313
1314 if (wordLen < args->lhsLen) 1314 if (wordLen < args->lhsLen)
1315 goto nosub; 1315 goto nosub;
1316 1316
1317 start = word + (wordLen - args->lhsLen); 1317 start = word + (wordLen - args->lhsLen);
1318 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1318 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1319 goto nosub; 1319 goto nosub;
1320 1320
1321 /* :S,suffix$,replacement, */ 1321 /* :S,suffix$,replacement, */
1322 SepBuf_AddBytesBetween(buf, word, start); 1322 SepBuf_AddBytesBetween(buf, word, start);
1323 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1323 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1324 args->matched = TRUE; 1324 args->matched = TRUE;
1325 return; 1325 return;
1326 } 1326 }
1327 1327
1328 if (args->lhs[0] == '\0') 1328 if (args->lhs[0] == '\0')
1329 goto nosub; 1329 goto nosub;
1330 1330
1331 /* unanchored case, may match more than once */ 1331 /* unanchored case, may match more than once */
1332 while ((match = strstr(word, args->lhs)) != NULL) { 1332 while ((match = strstr(word, args->lhs)) != NULL) {
1333 SepBuf_AddBytesBetween(buf, word, match); 1333 SepBuf_AddBytesBetween(buf, word, match);
1334 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1334 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1335 args->matched = TRUE; 1335 args->matched = TRUE;
1336 wordLen -= (size_t)(match - word) + args->lhsLen; 1336 wordLen -= (size_t)(match - word) + args->lhsLen;
1337 word += (size_t)(match - word) + args->lhsLen; 1337 word += (size_t)(match - word) + args->lhsLen;
1338 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1338 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1339 break; 1339 break;
1340 } 1340 }
1341nosub: 1341nosub:
1342 SepBuf_AddBytes(buf, word, wordLen); 1342 SepBuf_AddBytes(buf, word, wordLen);
1343} 1343}
1344 1344
1345#ifndef NO_REGEX 1345#ifndef NO_REGEX
1346/* Print the error caused by a regcomp or regexec call. */ 1346/* Print the error caused by a regcomp or regexec call. */
1347static void 1347static void
1348VarREError(int reerr, regex_t *pat, const char *str) 1348VarREError(int reerr, regex_t *pat, const char *str)
1349{ 1349{
1350 size_t errlen = regerror(reerr, pat, 0, 0); 1350 size_t errlen = regerror(reerr, pat, 0, 0);
1351 char *errbuf = bmake_malloc(errlen); 1351 char *errbuf = bmake_malloc(errlen);
1352 regerror(reerr, pat, errbuf, errlen); 1352 regerror(reerr, pat, errbuf, errlen);
1353 Error("%s: %s", str, errbuf); 1353 Error("%s: %s", str, errbuf);
1354 free(errbuf); 1354 free(errbuf);
1355} 1355}
1356 1356
1357struct ModifyWord_SubstRegexArgs { 1357struct ModifyWord_SubstRegexArgs {
1358 regex_t re; 1358 regex_t re;
1359 size_t nsub; 1359 size_t nsub;
1360 char *replace; 1360 char *replace;
1361 VarPatternFlags pflags; 1361 VarPatternFlags pflags;
1362 Boolean matched; 1362 Boolean matched;
1363}; 1363};
1364 1364
1365/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1365/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1366 * Perform a regex substitution on the given word. */ 1366 * Perform a regex substitution on the given word. */
1367static void 1367static void
1368ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1368ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1369{ 1369{
1370 struct ModifyWord_SubstRegexArgs *args = data; 1370 struct ModifyWord_SubstRegexArgs *args = data;
1371 int xrv; 1371 int xrv;
1372 const char *wp = word; 1372 const char *wp = word;
1373 char *rp; 1373 char *rp;
1374 int flags = 0; 1374 int flags = 0;
1375 regmatch_t m[10]; 1375 regmatch_t m[10];
1376 1376
1377 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1377 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1378 goto nosub; 1378 goto nosub;
1379 1379
1380tryagain: 1380tryagain:
1381 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1381 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1382 1382
1383 switch (xrv) { 1383 switch (xrv) {
1384 case 0: 1384 case 0:
1385 args->matched = TRUE; 1385 args->matched = TRUE;
1386 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1386 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1387 1387
1388 for (rp = args->replace; *rp; rp++) { 1388 for (rp = args->replace; *rp; rp++) {
1389 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1389 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1390 SepBuf_AddBytes(buf, rp + 1, 1); 1390 SepBuf_AddBytes(buf, rp + 1, 1);
1391 rp++; 1391 rp++;
1392 continue; 1392 continue;
1393 } 1393 }
1394 1394
1395 if (*rp == '&') { 1395 if (*rp == '&') {
1396 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1396 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1397 continue; 1397 continue;
1398 } 1398 }
1399 1399
1400 if (*rp != '\\' || !ch_isdigit(rp[1])) { 1400 if (*rp != '\\' || !ch_isdigit(rp[1])) {
1401 SepBuf_AddBytes(buf, rp, 1); 1401 SepBuf_AddBytes(buf, rp, 1);
1402 continue; 1402 continue;
1403 } 1403 }
1404 1404
1405 { /* \0 to \9 backreference */ 1405 { /* \0 to \9 backreference */
1406 size_t n = (size_t)(rp[1] - '0'); 1406 size_t n = (size_t)(rp[1] - '0');
1407 rp++; 1407 rp++;
1408 1408
1409 if (n >= args->nsub) { 1409 if (n >= args->nsub) {
1410 Error("No subexpression \\%zu", n); 1410 Error("No subexpression \\%zu", n);
1411 } else if (m[n].rm_so == -1) { 1411 } else if (m[n].rm_so == -1) {
1412 Error("No match for subexpression \\%zu", n); 1412 Error("No match for subexpression \\%zu", n);
1413 } else { 1413 } else {
1414 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1414 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1415 wp + m[n].rm_eo); 1415 wp + m[n].rm_eo);
1416 } 1416 }
1417 } 1417 }
1418 } 1418 }
1419 1419
1420 wp += m[0].rm_eo; 1420 wp += m[0].rm_eo;
1421 if (args->pflags & VARP_SUB_GLOBAL) { 1421 if (args->pflags & VARP_SUB_GLOBAL) {
1422 flags |= REG_NOTBOL; 1422 flags |= REG_NOTBOL;
1423 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1423 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1424 SepBuf_AddBytes(buf, wp, 1); 1424 SepBuf_AddBytes(buf, wp, 1);
1425 wp++; 1425 wp++;
1426 } 1426 }
1427 if (*wp) 1427 if (*wp)
1428 goto tryagain; 1428 goto tryagain;
1429 } 1429 }
1430 if (*wp) { 1430 if (*wp) {
1431 SepBuf_AddStr(buf, wp); 1431 SepBuf_AddStr(buf, wp);
1432 } 1432 }
1433 break; 1433 break;
1434 default: 1434 default:
1435 VarREError(xrv, &args->re, "Unexpected regex error"); 1435 VarREError(xrv, &args->re, "Unexpected regex error");
1436 /* FALLTHROUGH */ 1436 /* FALLTHROUGH */
1437 case REG_NOMATCH: 1437 case REG_NOMATCH:
1438 nosub: 1438 nosub:
1439 SepBuf_AddStr(buf, wp); 1439 SepBuf_AddStr(buf, wp);
1440 break; 1440 break;
1441 } 1441 }
1442} 1442}
1443#endif 1443#endif
1444 1444
1445 1445
1446struct ModifyWord_LoopArgs { 1446struct ModifyWord_LoopArgs {
1447 GNode *ctx; 1447 GNode *ctx;
1448 char *tvar; /* name of temporary variable */ 1448 char *tvar; /* name of temporary variable */
1449 char *str; /* string to expand */ 1449 char *str; /* string to expand */
1450 VarEvalFlags eflags; 1450 VarEvalFlags eflags;
1451}; 1451};
1452 1452
1453/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1453/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1454static void 1454static void
1455ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1455ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1456{ 1456{
1457 const struct ModifyWord_LoopArgs *args; 1457 const struct ModifyWord_LoopArgs *args;
1458 char *s; 1458 char *s;
1459 1459
1460 if (word[0] == '\0') 1460 if (word[0] == '\0')
1461 return; 1461 return;
1462 1462
1463 args = data; 1463 args = data;
1464 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1464 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1465 (void)Var_Subst(args->str, args->ctx, args->eflags, &s); 1465 (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1466 /* TODO: handle errors */ 1466 /* TODO: handle errors */
1467 1467
1468 VAR_DEBUG4("ModifyWord_Loop: " 1468 VAR_DEBUG4("ModifyWord_Loop: "
1469 "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n", 1469 "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
1470 word, args->tvar, args->str, s); 1470 word, args->tvar, args->str, s);
1471 1471
1472 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n')) 1472 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1473 buf->needSep = FALSE; 1473 buf->needSep = FALSE;
1474 SepBuf_AddStr(buf, s); 1474 SepBuf_AddStr(buf, s);
1475 free(s); 1475 free(s);
1476} 1476}
1477 1477
1478 1478
1479/* The :[first..last] modifier selects words from the expression. 1479/* The :[first..last] modifier selects words from the expression.
1480 * It can also reverse the words. */ 1480 * It can also reverse the words. */
1481static char * 1481static char *
1482VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1482VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1483 int last) 1483 int last)
1484{ 1484{
1485 Words words; 1485 Words words;
1486 int len, start, end, step; 1486 int len, start, end, step;
1487 int i; 1487 int i;
1488 1488
1489 SepBuf buf; 1489 SepBuf buf;
1490 SepBuf_Init(&buf, sep); 1490 SepBuf_Init(&buf, sep);
1491 1491
1492 if (oneBigWord) { 1492 if (oneBigWord) {
1493 /* fake what Str_Words() would do if there were only one word */ 1493 /* fake what Str_Words() would do if there were only one word */
1494 words.len = 1; 1494 words.len = 1;
1495 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1495 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1496 words.freeIt = bmake_strdup(str); 1496 words.freeIt = bmake_strdup(str);
1497 words.words[0] = words.freeIt; 1497 words.words[0] = words.freeIt;
1498 words.words[1] = NULL; 1498 words.words[1] = NULL;
1499 } else { 1499 } else {
1500 words = Str_Words(str, FALSE); 1500 words = Str_Words(str, FALSE);
1501 } 1501 }
1502 1502
1503 /* 1503 /*
1504 * Now sanitize the given range. 1504 * Now sanitize the given range.
1505 * If first or last are negative, convert them to the positive equivalents 1505 * If first or last are negative, convert them to the positive equivalents
1506 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1506 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1507 */ 1507 */
1508 len = (int)words.len; 1508 len = (int)words.len;
1509 if (first < 0) 1509 if (first < 0)
1510 first += len + 1; 1510 first += len + 1;
1511 if (last < 0) 1511 if (last < 0)
1512 last += len + 1; 1512 last += len + 1;
1513 1513
1514 /* 1514 /*
1515 * We avoid scanning more of the list than we need to. 1515 * We avoid scanning more of the list than we need to.
1516 */ 1516 */
1517 if (first > last) { 1517 if (first > last) {
1518 start = (first > len ? len : first) - 1; 1518 start = (first > len ? len : first) - 1;
1519 end = last < 1 ? 0 : last - 1; 1519 end = last < 1 ? 0 : last - 1;
1520 step = -1; 1520 step = -1;
1521 } else { 1521 } else {
1522 start = first < 1 ? 0 : first - 1; 1522 start = first < 1 ? 0 : first - 1;
1523 end = last > len ? len : last; 1523 end = last > len ? len : last;
1524 step = 1; 1524 step = 1;
1525 } 1525 }
1526 1526
1527 for (i = start; (step < 0) == (i >= end); i += step) { 1527 for (i = start; (step < 0) == (i >= end); i += step) {
1528 SepBuf_AddStr(&buf, words.words[i]); 1528 SepBuf_AddStr(&buf, words.words[i]);
1529 SepBuf_Sep(&buf); 1529 SepBuf_Sep(&buf);
1530 } 1530 }
1531 1531
1532 Words_Free(words); 1532 Words_Free(words);
1533 1533
1534 return SepBuf_Destroy(&buf, FALSE); 1534 return SepBuf_Destroy(&buf, FALSE);
1535} 1535}
1536 1536
1537 1537
1538/* Callback for ModifyWords to implement the :tA modifier. 1538/* Callback for ModifyWords to implement the :tA modifier.
1539 * Replace each word with the result of realpath() if successful. */ 1539 * Replace each word with the result of realpath() if successful. */
1540static void 1540static void
1541ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1541ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1542{ 1542{
1543 struct stat st; 1543 struct stat st;
1544 char rbuf[MAXPATHLEN]; 1544 char rbuf[MAXPATHLEN];
1545 1545
1546 const char *rp = cached_realpath(word, rbuf); 1546 const char *rp = cached_realpath(word, rbuf);
1547 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1547 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1548 word = rp; 1548 word = rp;
1549 1549
1550 SepBuf_AddStr(buf, word); 1550 SepBuf_AddStr(buf, word);
1551} 1551}
1552 1552
1553/* Modify each of the words of the passed string using the given function. 1553/* Modify each of the words of the passed string using the given function.
1554 * 1554 *
1555 * Input: 1555 * Input:
1556 * str String whose words should be modified 1556 * str String whose words should be modified
1557 * modifyWord Function that modifies a single word 1557 * modifyWord Function that modifies a single word
1558 * modifyWord_args Custom arguments for modifyWord 1558 * modifyWord_args Custom arguments for modifyWord
1559 * 1559 *
1560 * Results: 1560 * Results:
1561 * A string of all the words modified appropriately. 1561 * A string of all the words modified appropriately.
1562 *----------------------------------------------------------------------- 1562 *-----------------------------------------------------------------------
1563 */ 1563 */
1564static char * 1564static char *
1565ModifyWords(const char *str, 1565ModifyWords(const char *str,
1566 ModifyWordsCallback modifyWord, void *modifyWord_args, 1566 ModifyWordsCallback modifyWord, void *modifyWord_args,
1567 Boolean oneBigWord, char sep) 1567 Boolean oneBigWord, char sep)
1568{ 1568{
1569 SepBuf result; 1569 SepBuf result;
1570 Words words; 1570 Words words;
1571 size_t i; 1571 size_t i;
1572 1572
1573 if (oneBigWord) { 1573 if (oneBigWord) {
1574 SepBuf_Init(&result, sep); 1574 SepBuf_Init(&result, sep);
1575 modifyWord(str, &result, modifyWord_args); 1575 modifyWord(str, &result, modifyWord_args);
1576 return SepBuf_Destroy(&result, FALSE); 1576 return SepBuf_Destroy(&result, FALSE);
1577 } 1577 }
1578 1578
1579 SepBuf_Init(&result, sep); 1579 SepBuf_Init(&result, sep);
1580 1580
1581 words = Str_Words(str, FALSE); 1581 words = Str_Words(str, FALSE);
1582 1582
1583 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1583 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1584 1584
1585 for (i = 0; i < words.len; i++) { 1585 for (i = 0; i < words.len; i++) {
1586 modifyWord(words.words[i], &result, modifyWord_args); 1586 modifyWord(words.words[i], &result, modifyWord_args);
1587 if (Buf_Len(&result.buf) > 0) 1587 if (Buf_Len(&result.buf) > 0)
1588 SepBuf_Sep(&result); 1588 SepBuf_Sep(&result);
1589 } 1589 }
1590 1590
1591 Words_Free(words); 1591 Words_Free(words);
1592 1592
1593 return SepBuf_Destroy(&result, FALSE); 1593 return SepBuf_Destroy(&result, FALSE);
1594} 1594}
1595 1595
1596 1596
1597static char * 1597static char *
1598Words_JoinFree(Words words) 1598Words_JoinFree(Words words)
1599{ 1599{
1600 Buffer buf; 1600 Buffer buf;
1601 size_t i; 1601 size_t i;
1602 1602
1603 Buf_Init(&buf, 0); 1603 Buf_Init(&buf, 0);
1604 1604
1605 for (i = 0; i < words.len; i++) { 1605 for (i = 0; i < words.len; i++) {
1606 if (i != 0) 1606 if (i != 0)
1607 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1607 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1608 Buf_AddStr(&buf, words.words[i]); 1608 Buf_AddStr(&buf, words.words[i]);
1609 } 1609 }
1610 1610
1611 Words_Free(words); 1611 Words_Free(words);
1612 1612
1613 return Buf_Destroy(&buf, FALSE); 1613 return Buf_Destroy(&buf, FALSE);
1614} 1614}
1615 1615
1616/* Remove adjacent duplicate words. */ 1616/* Remove adjacent duplicate words. */
1617static char * 1617static char *
1618VarUniq(const char *str) 1618VarUniq(const char *str)
1619{ 1619{
1620 Words words = Str_Words(str, FALSE); 1620 Words words = Str_Words(str, FALSE);
1621 1621
1622 if (words.len > 1) { 1622 if (words.len > 1) {
1623 size_t i, j; 1623 size_t i, j;
1624 for (j = 0, i = 1; i < words.len; i++) 1624 for (j = 0, i = 1; i < words.len; i++)
1625 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i)) 1625 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1626 words.words[j] = words.words[i]; 1626 words.words[j] = words.words[i];
1627 words.len = j + 1; 1627 words.len = j + 1;
1628 } 1628 }
1629 1629
1630 return Words_JoinFree(words); 1630 return Words_JoinFree(words);
1631} 1631}
1632 1632
1633 1633
1634/* Quote shell meta-characters and space characters in the string. 1634/* Quote shell meta-characters and space characters in the string.
1635 * If quoteDollar is set, also quote and double any '$' characters. */ 1635 * If quoteDollar is set, also quote and double any '$' characters. */
1636static char * 1636static char *
1637VarQuote(const char *str, Boolean quoteDollar) 1637VarQuote(const char *str, Boolean quoteDollar)
1638{ 1638{
1639 char *res; 
1640 Buffer buf; 1639 Buffer buf;
1641 Buf_Init(&buf, 0); 1640 Buf_Init(&buf, 0);
1642 1641
1643 for (; *str != '\0'; str++) { 1642 for (; *str != '\0'; str++) {
1644 if (*str == '\n') { 1643 if (*str == '\n') {
1645 const char *newline = Shell_GetNewline(); 1644 const char *newline = Shell_GetNewline();
1646 if (newline == NULL) 1645 if (newline == NULL)
1647 newline = "\\\n"; 1646 newline = "\\\n";
1648 Buf_AddStr(&buf, newline); 1647 Buf_AddStr(&buf, newline);
1649 continue; 1648 continue;
1650 } 1649 }
1651 if (ch_isspace(*str) || ismeta((unsigned char)*str)) 1650 if (ch_isspace(*str) || ismeta((unsigned char)*str))
1652 Buf_AddByte(&buf, '\\'); 1651 Buf_AddByte(&buf, '\\');
1653 Buf_AddByte(&buf, *str); 1652 Buf_AddByte(&buf, *str);
1654 if (quoteDollar && *str == '$') 1653 if (quoteDollar && *str == '$')
1655 Buf_AddStr(&buf, "\\$"); 1654 Buf_AddStr(&buf, "\\$");
1656 } 1655 }
1657 1656
1658 res = Buf_Destroy(&buf, FALSE); 1657 return Buf_Destroy(&buf, FALSE);
1659 VAR_DEBUG1("QuoteMeta: [%s]\n", res); 
1660 return res; 
1661} 1658}
1662 1659
1663/* Compute the 32-bit hash of the given string, using the MurmurHash3 1660/* Compute the 32-bit hash of the given string, using the MurmurHash3
1664 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1661 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1665static char * 1662static char *
1666VarHash(const char *str) 1663VarHash(const char *str)
1667{ 1664{
1668 static const char hexdigits[16] = "0123456789abcdef"; 1665 static const char hexdigits[16] = "0123456789abcdef";
1669 const unsigned char *ustr = (const unsigned char *)str; 1666 const unsigned char *ustr = (const unsigned char *)str;
1670 1667
1671 uint32_t h = 0x971e137bU; 1668 uint32_t h = 0x971e137bU;
1672 uint32_t c1 = 0x95543787U; 1669 uint32_t c1 = 0x95543787U;
1673 uint32_t c2 = 0x2ad7eb25U; 1670 uint32_t c2 = 0x2ad7eb25U;
1674 size_t len2 = strlen(str); 1671 size_t len2 = strlen(str);
1675 1672
1676 char *buf; 1673 char *buf;
1677 size_t i; 1674 size_t i;
1678 1675
1679 size_t len; 1676 size_t len;
1680 for (len = len2; len; ) { 1677 for (len = len2; len; ) {
1681 uint32_t k = 0; 1678 uint32_t k = 0;
1682 switch (len) { 1679 switch (len) {
1683 default: 1680 default:
1684 k = ((uint32_t)ustr[3] << 24) | 1681 k = ((uint32_t)ustr[3] << 24) |
1685 ((uint32_t)ustr[2] << 16) | 1682 ((uint32_t)ustr[2] << 16) |
1686 ((uint32_t)ustr[1] << 8) | 1683 ((uint32_t)ustr[1] << 8) |
1687 (uint32_t)ustr[0]; 1684 (uint32_t)ustr[0];
1688 len -= 4; 1685 len -= 4;
1689 ustr += 4; 1686 ustr += 4;
1690 break; 1687 break;
1691 case 3: 1688 case 3:
1692 k |= (uint32_t)ustr[2] << 16; 1689 k |= (uint32_t)ustr[2] << 16;
1693 /* FALLTHROUGH */ 1690 /* FALLTHROUGH */
1694 case 2: 1691 case 2:
1695 k |= (uint32_t)ustr[1] << 8; 1692 k |= (uint32_t)ustr[1] << 8;
1696 /* FALLTHROUGH */ 1693 /* FALLTHROUGH */
1697 case 1: 1694 case 1:
1698 k |= (uint32_t)ustr[0]; 1695 k |= (uint32_t)ustr[0];
1699 len = 0; 1696 len = 0;
1700 } 1697 }
1701 c1 = c1 * 5 + 0x7b7d159cU; 1698 c1 = c1 * 5 + 0x7b7d159cU;
1702 c2 = c2 * 5 + 0x6bce6396U; 1699 c2 = c2 * 5 + 0x6bce6396U;
1703 k *= c1; 1700 k *= c1;
1704 k = (k << 11) ^ (k >> 21); 1701 k = (k << 11) ^ (k >> 21);
1705 k *= c2; 1702 k *= c2;
1706 h = (h << 13) ^ (h >> 19); 1703 h = (h << 13) ^ (h >> 19);
1707 h = h * 5 + 0x52dce729U; 1704 h = h * 5 + 0x52dce729U;
1708 h ^= k; 1705 h ^= k;
1709 } 1706 }
1710 h ^= (uint32_t)len2; 1707 h ^= (uint32_t)len2;
1711 h *= 0x85ebca6b; 1708 h *= 0x85ebca6b;
1712 h ^= h >> 13; 1709 h ^= h >> 13;
1713 h *= 0xc2b2ae35; 1710 h *= 0xc2b2ae35;
1714 h ^= h >> 16; 1711 h ^= h >> 16;
1715 1712
1716 buf = bmake_malloc(9); 1713 buf = bmake_malloc(9);
1717 for (i = 0; i < 8; i++) { 1714 for (i = 0; i < 8; i++) {
1718 buf[i] = hexdigits[h & 0x0f]; 1715 buf[i] = hexdigits[h & 0x0f];
1719 h >>= 4; 1716 h >>= 4;
1720 } 1717 }
1721 buf[8] = '\0'; 1718 buf[8] = '\0';
1722 return buf; 1719 return buf;
1723} 1720}
1724 1721
1725static char * 1722static char *
1726VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1723VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1727{ 1724{
1728 char buf[BUFSIZ]; 1725 char buf[BUFSIZ];
1729 1726
1730 if (!tim) 1727 if (!tim)
1731 time(&tim); 1728 time(&tim);
1732 if (!*fmt) 1729 if (!*fmt)
1733 fmt = "%c"; 1730 fmt = "%c";
1734 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1731 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1735 1732
1736 buf[sizeof(buf) - 1] = '\0'; 1733 buf[sizeof(buf) - 1] = '\0';
1737 return bmake_strdup(buf); 1734 return bmake_strdup(buf);
1738} 1735}
1739 1736
1740/* The ApplyModifier functions all work in the same way. They get the 1737/* The ApplyModifier functions all work in the same way. They get the
1741 * current parsing position (pp) and parse the modifier from there. The 1738 * current parsing position (pp) and parse the modifier from there. The
1742 * modifier typically lasts until the next ':', or a closing '}' or ')' 1739 * modifier typically lasts until the next ':', or a closing '}' or ')'
1743 * (taken from st->endc), or the end of the string (parse error). 1740 * (taken from st->endc), or the end of the string (parse error).
1744 * 1741 *
1745 * The high-level behavior of these functions is: 1742 * The high-level behavior of these functions is:
1746 * 1743 *
1747 * 1. parse the modifier 1744 * 1. parse the modifier
1748 * 2. evaluate the modifier 1745 * 2. evaluate the modifier
1749 * 3. housekeeping 1746 * 3. housekeeping
1750 * 1747 *
1751 * Parsing the modifier 1748 * Parsing the modifier
1752 * 1749 *
1753 * If parsing succeeds, the parsing position *pp is updated to point to the 1750 * If parsing succeeds, the parsing position *pp is updated to point to the
1754 * first character following the modifier, which typically is either ':' or 1751 * first character following the modifier, which typically is either ':' or
1755 * st->endc. 1752 * st->endc.
1756 * 1753 *
1757 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1754 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1758 * modifiers), return AMR_CLEANUP. 1755 * modifiers), return AMR_CLEANUP.
1759 * 1756 *
1760 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1757 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1761 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1758 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1762 * done as long as there have been no side effects from evaluating nested 1759 * done as long as there have been no side effects from evaluating nested
1763 * variables, to avoid evaluating them more than once. In this case, the 1760 * variables, to avoid evaluating them more than once. In this case, the
1764 * parsing position must not be updated. (XXX: Why not? The original parsing 1761 * parsing position must not be updated. (XXX: Why not? The original parsing
1765 * position is well-known in ApplyModifiers.) 1762 * position is well-known in ApplyModifiers.)
1766 * 1763 *
1767 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1764 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1768 * as a fallback, either issue an error message using Error or Parse_Error 1765 * as a fallback, either issue an error message using Error or Parse_Error
1769 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1766 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1770 * message. Both of these return values will stop processing the variable 1767 * message. Both of these return values will stop processing the variable
1771 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1768 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1772 * continues nevertheless after skipping a few bytes, which essentially is 1769 * continues nevertheless after skipping a few bytes, which essentially is
1773 * undefined behavior. Not in the sense of C, but still it's impossible to 1770 * undefined behavior. Not in the sense of C, but still it's impossible to
1774 * predict what happens in the parser.) 1771 * predict what happens in the parser.)
1775 * 1772 *
1776 * Evaluating the modifier 1773 * Evaluating the modifier
1777 * 1774 *
1778 * After parsing, the modifier is evaluated. The side effects from evaluating 1775 * After parsing, the modifier is evaluated. The side effects from evaluating
1779 * nested variable expressions in the modifier text often already happen 1776 * nested variable expressions in the modifier text often already happen
1780 * during parsing though. 1777 * during parsing though.
1781 * 1778 *
1782 * Evaluating the modifier usually takes the current value of the variable 1779 * Evaluating the modifier usually takes the current value of the variable
1783 * expression from st->val, or the variable name from st->v->name and stores 1780 * expression from st->val, or the variable name from st->v->name and stores
1784 * the result in st->newVal. 1781 * the result in st->newVal.
1785 * 1782 *
1786 * If evaluating fails (as of 2020-08-23), an error message is printed using 1783 * If evaluating fails (as of 2020-08-23), an error message is printed using
1787 * Error. This function has no side-effects, it really just prints the error 1784 * Error. This function has no side-effects, it really just prints the error
1788 * message. Processing the expression continues as if everything were ok. 1785 * message. Processing the expression continues as if everything were ok.
1789 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1786 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1790 * Var_Parse, ApplyModifiers and ModifyWords. 1787 * Var_Parse, ApplyModifiers and ModifyWords.
1791 * 1788 *
1792 * Housekeeping 1789 * Housekeeping
1793 * 1790 *
1794 * Some modifiers such as :D and :U turn undefined expressions into defined 1791 * Some modifiers such as :D and :U turn undefined expressions into defined
1795 * expressions (see VEF_UNDEF, VEF_DEF). 1792 * expressions (see VEF_UNDEF, VEF_DEF).
1796 * 1793 *
1797 * Some modifiers need to free some memory. 1794 * Some modifiers need to free some memory.
1798 */ 1795 */
1799 1796
1800typedef enum VarExprFlags { 1797typedef enum VarExprFlags {
1801 /* The variable expression is based on an undefined variable. */ 1798 /* The variable expression is based on an undefined variable. */
1802 VEF_UNDEF = 0x01, 1799 VEF_UNDEF = 0x01,
1803 /* The variable expression started as an undefined expression, but one 1800 /* The variable expression started as an undefined expression, but one
1804 * of the modifiers (such as :D or :U) has turned the expression from 1801 * of the modifiers (such as :D or :U) has turned the expression from
1805 * undefined to defined. */ 1802 * undefined to defined. */
1806 VEF_DEF = 0x02 1803 VEF_DEF = 0x02
1807} VarExprFlags; 1804} VarExprFlags;
1808 1805
1809ENUM_FLAGS_RTTI_2(VarExprFlags, 1806ENUM_FLAGS_RTTI_2(VarExprFlags,
1810 VEF_UNDEF, VEF_DEF); 1807 VEF_UNDEF, VEF_DEF);
1811 1808
1812 1809
1813typedef struct ApplyModifiersState { 1810typedef struct ApplyModifiersState {
1814 const char startc; /* '\0' or '{' or '(' */ 1811 const char startc; /* '\0' or '{' or '(' */
1815 const char endc; /* '\0' or '}' or ')' */ 1812 const char endc; /* '\0' or '}' or ')' */
1816 Var * const v; 1813 Var * const v;
1817 GNode * const ctxt; 1814 GNode * const ctxt;
1818 const VarEvalFlags eflags; 1815 const VarEvalFlags eflags;
1819 1816
1820 char *val; /* The old value of the expression, 1817 char *val; /* The old value of the expression,
1821 * before applying the modifier, never NULL */ 1818 * before applying the modifier, never NULL */
1822 char *newVal; /* The new value of the expression, 1819 char *newVal; /* The new value of the expression,
1823 * after applying the modifier, never NULL */ 1820 * after applying the modifier, never NULL */
1824 char sep; /* Word separator in expansions 1821 char sep; /* Word separator in expansions
1825 * (see the :ts modifier) */ 1822 * (see the :ts modifier) */
1826 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1823 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1827 * the variable value into words, like :S and 1824 * the variable value into words, like :S and
1828 * :C, treat the variable value as a single big 1825 * :C, treat the variable value as a single big
1829 * word, possibly containing spaces. */ 1826 * word, possibly containing spaces. */
1830 VarExprFlags exprFlags; 1827 VarExprFlags exprFlags;
1831} ApplyModifiersState; 1828} ApplyModifiersState;
1832 1829
1833static void 1830static void
1834ApplyModifiersState_Define(ApplyModifiersState *st) 1831ApplyModifiersState_Define(ApplyModifiersState *st)
1835{ 1832{
1836 if (st->exprFlags & VEF_UNDEF) 1833 if (st->exprFlags & VEF_UNDEF)
1837 st->exprFlags |= VEF_DEF; 1834 st->exprFlags |= VEF_DEF;
1838} 1835}
1839 1836
1840typedef enum ApplyModifierResult { 1837typedef enum ApplyModifierResult {
1841 AMR_OK, /* Continue parsing */ 1838 AMR_OK, /* Continue parsing */
1842 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1839 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1843 AMR_BAD, /* Error out with "Bad modifier" message */ 1840 AMR_BAD, /* Error out with "Bad modifier" message */
1844 AMR_CLEANUP /* Error out without error message */ 1841 AMR_CLEANUP /* Error out without error message */
1845} ApplyModifierResult; 1842} ApplyModifierResult;
1846 1843
1847/* Allow backslashes to escape the delimiter, $, and \, but don't touch other 1844/* Allow backslashes to escape the delimiter, $, and \, but don't touch other
1848 * backslashes. */ 1845 * backslashes. */
1849static Boolean 1846static Boolean
1850IsEscapedModifierPart(const char *p, char delim, 1847IsEscapedModifierPart(const char *p, char delim,
1851 struct ModifyWord_SubstArgs *subst) 1848 struct ModifyWord_SubstArgs *subst)
1852{ 1849{
1853 if (p[0] != '\\') 1850 if (p[0] != '\\')
1854 return FALSE; 1851 return FALSE;
1855 if (p[1] == delim || p[1] == '\\' || p[1] == '$') 1852 if (p[1] == delim || p[1] == '\\' || p[1] == '$')
1856 return TRUE; 1853 return TRUE;
1857 return p[1] == '&' && subst != NULL; 1854 return p[1] == '&' && subst != NULL;
1858} 1855}
1859 1856
1860/* 1857/*
1861 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or 1858 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
1862 * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and 1859 * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
1863 * including the next unescaped delimiter. The delimiter, as well as the 1860 * including the next unescaped delimiter. The delimiter, as well as the
1864 * backslash or the dollar, can be escaped with a backslash. 1861 * backslash or the dollar, can be escaped with a backslash.
1865 * 1862 *
1866 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1863 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1867 * was found. On successful return, the parsing position pp points right 1864 * was found. On successful return, the parsing position pp points right
1868 * after the delimiter. The delimiter is not included in the returned 1865 * after the delimiter. The delimiter is not included in the returned
1869 * value though. 1866 * value though.
1870 */ 1867 */
1871static VarParseResult 1868static VarParseResult
1872ParseModifierPart( 1869ParseModifierPart(
1873 const char **pp, /* The parsing position, updated upon return */ 1870 const char **pp, /* The parsing position, updated upon return */
1874 char delim, /* Parsing stops at this delimiter */ 1871 char delim, /* Parsing stops at this delimiter */
1875 VarEvalFlags eflags, /* Flags for evaluating nested variables; 1872 VarEvalFlags eflags, /* Flags for evaluating nested variables;
1876 * if VARE_WANTRES is not set, the text is 1873 * if VARE_WANTRES is not set, the text is
1877 * only parsed */ 1874 * only parsed */
1878 ApplyModifiersState *st, 1875 ApplyModifiersState *st,
1879 char **out_part, 1876 char **out_part,
1880 size_t *out_length, /* Optionally stores the length of the returned 1877 size_t *out_length, /* Optionally stores the length of the returned
1881 * string, just to save another strlen call. */ 1878 * string, just to save another strlen call. */
1882 VarPatternFlags *out_pflags,/* For the first part of the :S modifier, 1879 VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
1883 * sets the VARP_ANCHOR_END flag if the last 1880 * sets the VARP_ANCHOR_END flag if the last
1884 * character of the pattern is a $. */ 1881 * character of the pattern is a $. */
1885 struct ModifyWord_SubstArgs *subst 1882 struct ModifyWord_SubstArgs *subst
1886 /* For the second part of the :S modifier, 1883 /* For the second part of the :S modifier,
1887 * allow ampersands to be escaped and replace 1884 * allow ampersands to be escaped and replace
1888 * unescaped ampersands with subst->lhs. */ 1885 * unescaped ampersands with subst->lhs. */
1889) { 1886) {
1890 Buffer buf; 1887 Buffer buf;
1891 const char *p; 1888 const char *p;
1892 1889
1893 Buf_Init(&buf, 0); 1890 Buf_Init(&buf, 0);
1894 1891
1895 /* 1892 /*
1896 * Skim through until the matching delimiter is found; pick up variable 1893 * Skim through until the matching delimiter is found; pick up variable
1897 * expressions on the way. 1894 * expressions on the way.
1898 */ 1895 */
1899 p = *pp; 1896 p = *pp;
1900 while (*p != '\0' && *p != delim) { 1897 while (*p != '\0' && *p != delim) {
1901 const char *varstart; 1898 const char *varstart;
1902 1899
1903 if (IsEscapedModifierPart(p, delim, subst)) { 1900 if (IsEscapedModifierPart(p, delim, subst)) {
1904 Buf_AddByte(&buf, p[1]); 1901 Buf_AddByte(&buf, p[1]);
1905 p += 2; 1902 p += 2;
1906 continue; 1903 continue;
1907 } 1904 }
1908 1905
1909 if (*p != '$') { /* Unescaped, simple text */ 1906 if (*p != '$') { /* Unescaped, simple text */
1910 if (subst != NULL && *p == '&') 1907 if (subst != NULL && *p == '&')
1911 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen); 1908 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
1912 else 1909 else
1913 Buf_AddByte(&buf, *p); 1910 Buf_AddByte(&buf, *p);
1914 p++; 1911 p++;
1915 continue; 1912 continue;
1916 } 1913 }
1917 1914
1918 if (p[1] == delim) { /* Unescaped $ at end of pattern */ 1915 if (p[1] == delim) { /* Unescaped $ at end of pattern */
1919 if (out_pflags != NULL) 1916 if (out_pflags != NULL)
1920 *out_pflags |= VARP_ANCHOR_END; 1917 *out_pflags |= VARP_ANCHOR_END;
1921 else 1918 else
1922 Buf_AddByte(&buf, *p); 1919 Buf_AddByte(&buf, *p);
1923 p++; 1920 p++;
1924 continue; 1921 continue;
1925 } 1922 }
1926 1923
1927 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */ 1924 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
1928 const char *nested_p = p; 1925 const char *nested_p = p;
1929 const char *nested_val; 1926 const char *nested_val;
1930 void *nested_val_freeIt; 1927 void *nested_val_freeIt;
1931 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN; 1928 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
1932 1929
1933 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags, 1930 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
1934 &nested_val, &nested_val_freeIt); 1931 &nested_val, &nested_val_freeIt);
1935 /* TODO: handle errors */ 1932 /* TODO: handle errors */
1936 Buf_AddStr(&buf, nested_val); 1933 Buf_AddStr(&buf, nested_val);
1937 free(nested_val_freeIt); 1934 free(nested_val_freeIt);
1938 p += nested_p - p; 1935 p += nested_p - p;
1939 continue; 1936 continue;
1940 } 1937 }
1941 1938
1942 /* XXX: This whole block is very similar to Var_Parse without 1939 /* XXX: This whole block is very similar to Var_Parse without
1943 * VARE_WANTRES. There may be subtle edge cases though that are 1940 * VARE_WANTRES. There may be subtle edge cases though that are
1944 * not yet covered in the unit tests and that are parsed differently, 1941 * not yet covered in the unit tests and that are parsed differently,
1945 * depending on whether they are evaluated or not. 1942 * depending on whether they are evaluated or not.
1946 * 1943 *
1947 * This subtle difference is not documented in the manual page, 1944 * This subtle difference is not documented in the manual page,
1948 * neither is the difference between parsing :D and :M documented. 1945 * neither is the difference between parsing :D and :M documented.
1949 * No code should ever depend on these details, but who knows. */ 1946 * No code should ever depend on these details, but who knows. */
1950 1947
1951 varstart = p; /* Nested variable, only parsed */ 1948 varstart = p; /* Nested variable, only parsed */
1952 if (p[1] == '(' || p[1] == '{') { 1949 if (p[1] == '(' || p[1] == '{') {
1953 /* 1950 /*
1954 * Find the end of this variable reference 1951 * Find the end of this variable reference
1955 * and suck it in without further ado. 1952 * and suck it in without further ado.
1956 * It will be interpreted later. 1953 * It will be interpreted later.
1957 */ 1954 */
1958 char startc = p[1]; 1955 char startc = p[1];
1959 int endc = startc == '(' ? ')' : '}'; 1956 int endc = startc == '(' ? ')' : '}';
1960 int depth = 1; 1957 int depth = 1;
1961 1958
1962 for (p += 2; *p != '\0' && depth > 0; p++) { 1959 for (p += 2; *p != '\0' && depth > 0; p++) {
1963 if (p[-1] != '\\') { 1960 if (p[-1] != '\\') {
1964 if (*p == startc) 1961 if (*p == startc)
1965 depth++; 1962 depth++;
1966 if (*p == endc) 1963 if (*p == endc)
1967 depth--; 1964 depth--;
1968 } 1965 }
1969 } 1966 }
1970 Buf_AddBytesBetween(&buf, varstart, p); 1967 Buf_AddBytesBetween(&buf, varstart, p);
1971 } else { 1968 } else {
1972 Buf_AddByte(&buf, *varstart); 1969 Buf_AddByte(&buf, *varstart);
1973 p++; 1970 p++;
1974 } 1971 }
1975 } 1972 }
1976 1973
1977 if (*p != delim) { 1974 if (*p != delim) {
1978 *pp = p; 1975 *pp = p;
1979 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim); 1976 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim);
1980 *out_part = NULL; 1977 *out_part = NULL;
1981 return VPR_PARSE_MSG; 1978 return VPR_PARSE_MSG;
1982 } 1979 }
1983 1980
1984 *pp = ++p; 1981 *pp = ++p;
1985 if (out_length != NULL) 1982 if (out_length != NULL)
1986 *out_length = Buf_Len(&buf); 1983 *out_length = Buf_Len(&buf);
1987 1984
1988 *out_part = Buf_Destroy(&buf, FALSE); 1985 *out_part = Buf_Destroy(&buf, FALSE);
1989 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part); 1986 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part);
1990 return VPR_OK; 1987 return VPR_OK;
1991} 1988}
1992 1989
1993/* Test whether mod starts with modname, followed by a delimiter. */ 1990/* Test whether mod starts with modname, followed by a delimiter. */
1994static Boolean 1991static Boolean
1995ModMatch(const char *mod, const char *modname, char endc) 1992ModMatch(const char *mod, const char *modname, char endc)
1996{ 1993{
1997 size_t n = strlen(modname); 1994 size_t n = strlen(modname);
1998 return strncmp(mod, modname, n) == 0 && 1995 return strncmp(mod, modname, n) == 0 &&
1999 (mod[n] == endc || mod[n] == ':'); 1996 (mod[n] == endc || mod[n] == ':');
2000} 1997}
2001 1998
2002/* Test whether mod starts with modname, followed by a delimiter or '='. */ 1999/* Test whether mod starts with modname, followed by a delimiter or '='. */
2003static inline Boolean 2000static inline Boolean
2004ModMatchEq(const char *mod, const char *modname, char endc) 2001ModMatchEq(const char *mod, const char *modname, char endc)
2005{ 2002{
2006 size_t n = strlen(modname); 2003 size_t n = strlen(modname);
2007 return strncmp(mod, modname, n) == 0 && 2004 return strncmp(mod, modname, n) == 0 &&
2008 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2005 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2009} 2006}
2010 2007
2011/* :@var@...${var}...@ */ 2008/* :@var@...${var}...@ */
2012static ApplyModifierResult 2009static ApplyModifierResult
2013ApplyModifier_Loop(const char **pp, ApplyModifiersState *st) 2010ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
2014{ 2011{
2015 struct ModifyWord_LoopArgs args; 2012 struct ModifyWord_LoopArgs args;
2016 char prev_sep; 2013 char prev_sep;
2017 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2014 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2018 VarParseResult res; 2015 VarParseResult res;
2019 2016
2020 args.ctx = st->ctxt; 2017 args.ctx = st->ctxt;
2021 2018
2022 (*pp)++; /* Skip the first '@' */ 2019 (*pp)++; /* Skip the first '@' */
2023 res = ParseModifierPart(pp, '@', eflags, st, 2020 res = ParseModifierPart(pp, '@', eflags, st,
2024 &args.tvar, NULL, NULL, NULL); 2021 &args.tvar, NULL, NULL, NULL);
2025 if (res != VPR_OK) 2022 if (res != VPR_OK)
2026 return AMR_CLEANUP; 2023 return AMR_CLEANUP;
2027 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) { 2024 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) {
2028 Parse_Error(PARSE_FATAL, 2025 Parse_Error(PARSE_FATAL,
2029 "In the :@ modifier of \"%s\", the variable name \"%s\" " 2026 "In the :@ modifier of \"%s\", the variable name \"%s\" "
2030 "must not contain a dollar.", 2027 "must not contain a dollar.",
2031 st->v->name, args.tvar); 2028 st->v->name, args.tvar);
2032 return AMR_CLEANUP; 2029 return AMR_CLEANUP;
2033 } 2030 }
2034 2031
2035 res = ParseModifierPart(pp, '@', eflags, st, 2032 res = ParseModifierPart(pp, '@', eflags, st,
2036 &args.str, NULL, NULL, NULL); 2033 &args.str, NULL, NULL, NULL);
2037 if (res != VPR_OK) 2034 if (res != VPR_OK)
2038 return AMR_CLEANUP; 2035 return AMR_CLEANUP;
2039 2036
2040 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2037 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2041 prev_sep = st->sep; 2038 prev_sep = st->sep;
2042 st->sep = ' '; /* XXX: should be st->sep for consistency */ 2039 st->sep = ' '; /* XXX: should be st->sep for consistency */
2043 st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args, 2040 st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args,
2044 st->oneBigWord, st->sep); 2041 st->oneBigWord, st->sep);
2045 st->sep = prev_sep; 2042 st->sep = prev_sep;
2046 Var_Delete(args.tvar, st->ctxt); 2043 Var_Delete(args.tvar, st->ctxt);
2047 free(args.tvar); 2044 free(args.tvar);
2048 free(args.str); 2045 free(args.str);
2049 return AMR_OK; 2046 return AMR_OK;
2050} 2047}
2051 2048
2052/* :Ddefined or :Uundefined */ 2049/* :Ddefined or :Uundefined */
2053static ApplyModifierResult 2050static ApplyModifierResult
2054ApplyModifier_Defined(const char **pp, ApplyModifiersState *st) 2051ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
2055{ 2052{
2056 Buffer buf; 2053 Buffer buf;
2057 const char *p; 2054 const char *p;
2058 2055
2059 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2056 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2060 if (st->eflags & VARE_WANTRES) { 2057 if (st->eflags & VARE_WANTRES) {
2061 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF)) 2058 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
2062 eflags |= VARE_WANTRES; 2059 eflags |= VARE_WANTRES;
2063 } 2060 }
2064 2061
2065 Buf_Init(&buf, 0); 2062 Buf_Init(&buf, 0);
2066 p = *pp + 1; 2063 p = *pp + 1;
2067 while (*p != st->endc && *p != ':' && *p != '\0') { 2064 while (*p != st->endc && *p != ':' && *p != '\0') {
2068 2065
2069 /* Escaped delimiter or other special character */ 2066 /* Escaped delimiter or other special character */
2070 if (*p == '\\') { 2067 if (*p == '\\') {
2071 char c = p[1]; 2068 char c = p[1];
2072 if (c == st->endc || c == ':' || c == '$' || c == '\\') { 2069 if (c == st->endc || c == ':' || c == '$' || c == '\\') {
2073 Buf_AddByte(&buf, c); 2070 Buf_AddByte(&buf, c);
2074 p += 2; 2071 p += 2;
2075 continue; 2072 continue;
2076 } 2073 }
2077 } 2074 }
2078 2075
2079 /* Nested variable expression */ 2076 /* Nested variable expression */
2080 if (*p == '$') { 2077 if (*p == '$') {
2081 const char *nested_val; 2078 const char *nested_val;
2082 void *nested_val_freeIt; 2079 void *nested_val_freeIt;
2083 2080
2084 (void)Var_Parse(&p, st->ctxt, eflags, 2081 (void)Var_Parse(&p, st->ctxt, eflags,
2085 &nested_val, &nested_val_freeIt); 2082 &nested_val, &nested_val_freeIt);
2086 /* TODO: handle errors */ 2083 /* TODO: handle errors */
2087 Buf_AddStr(&buf, nested_val); 2084 Buf_AddStr(&buf, nested_val);
2088 free(nested_val_freeIt); 2085 free(nested_val_freeIt);
2089 continue; 2086 continue;
2090 } 2087 }
2091 2088
2092 /* Ordinary text */ 2089 /* Ordinary text */
2093 Buf_AddByte(&buf, *p); 2090 Buf_AddByte(&buf, *p);
2094 p++; 2091 p++;
2095 } 2092 }
2096 *pp = p; 2093 *pp = p;
2097 2094
2098 ApplyModifiersState_Define(st); 2095 ApplyModifiersState_Define(st);
2099 2096
2100 if (eflags & VARE_WANTRES) { 2097 if (eflags & VARE_WANTRES) {
2101 st->newVal = Buf_Destroy(&buf, FALSE); 2098 st->newVal = Buf_Destroy(&buf, FALSE);
2102 } else { 2099 } else {
2103 st->newVal = st->val; 2100 st->newVal = st->val;
2104 Buf_Destroy(&buf, TRUE); 2101 Buf_Destroy(&buf, TRUE);
2105 } 2102 }
2106 return AMR_OK; 2103 return AMR_OK;
2107} 2104}
2108 2105
2109/* :L */ 2106/* :L */
2110static ApplyModifierResult 2107static ApplyModifierResult
2111ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) 2108ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2112{ 2109{
2113 ApplyModifiersState_Define(st); 2110 ApplyModifiersState_Define(st);
2114 st->newVal = bmake_strdup(st->v->name); 2111 st->newVal = bmake_strdup(st->v->name);
2115 (*pp)++; 2112 (*pp)++;
2116 return AMR_OK; 2113 return AMR_OK;
2117} 2114}
2118 2115
2119/* :gmtime */ 2116/* :gmtime */
2120static ApplyModifierResult 2117static ApplyModifierResult
2121ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st) 2118ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
2122{ 2119{
2123 time_t utc; 2120 time_t utc;
2124 2121
2125 const char *mod = *pp; 2122 const char *mod = *pp;
2126 if (!ModMatchEq(mod, "gmtime", st->endc)) 2123 if (!ModMatchEq(mod, "gmtime", st->endc))
2127 return AMR_UNKNOWN; 2124 return AMR_UNKNOWN;
2128 2125
2129 if (mod[6] == '=') { 2126 if (mod[6] == '=') {
2130 char *ep; 2127 char *ep;
2131 utc = (time_t)strtoul(mod + 7, &ep, 10); 2128 utc = (time_t)strtoul(mod + 7, &ep, 10);
2132 *pp = ep; 2129 *pp = ep;
2133 } else { 2130 } else {
2134 utc = 0; 2131 utc = 0;
2135 *pp = mod + 6; 2132 *pp = mod + 6;
2136 } 2133 }
2137 st->newVal = VarStrftime(st->val, TRUE, utc); 2134 st->newVal = VarStrftime(st->val, TRUE, utc);
2138 return AMR_OK; 2135 return AMR_OK;
2139} 2136}
2140 2137
2141/* :localtime */ 2138/* :localtime */
2142static ApplyModifierResult 2139static ApplyModifierResult
2143ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) 2140ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
2144{ 2141{
2145 time_t utc; 2142 time_t utc;
2146 2143
2147 const char *mod = *pp; 2144 const char *mod = *pp;
2148 if (!ModMatchEq(mod, "localtime", st->endc)) 2145 if (!ModMatchEq(mod, "localtime", st->endc))
2149 return AMR_UNKNOWN; 2146 return AMR_UNKNOWN;
2150 2147
2151 if (mod[9] == '=') { 2148 if (mod[9] == '=') {
2152 char *ep; 2149 char *ep;
2153 utc = (time_t)strtoul(mod + 10, &ep, 10); 2150 utc = (time_t)strtoul(mod + 10, &ep, 10);
2154 *pp = ep; 2151 *pp = ep;
2155 } else { 2152 } else {
2156 utc = 0; 2153 utc = 0;
2157 *pp = mod + 9; 2154 *pp = mod + 9;
2158 } 2155 }
2159 st->newVal = VarStrftime(st->val, FALSE, utc); 2156 st->newVal = VarStrftime(st->val, FALSE, utc);
2160 return AMR_OK; 2157 return AMR_OK;
2161} 2158}
2162 2159
2163/* :hash */ 2160/* :hash */
2164static ApplyModifierResult 2161static ApplyModifierResult
2165ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) 2162ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
2166{ 2163{
2167 if (!ModMatch(*pp, "hash", st->endc)) 2164 if (!ModMatch(*pp, "hash", st->endc))
2168 return AMR_UNKNOWN; 2165 return AMR_UNKNOWN;
2169 2166
2170 st->newVal = VarHash(st->val); 2167 st->newVal = VarHash(st->val);
2171 *pp += 4; 2168 *pp += 4;
2172 return AMR_OK; 2169 return AMR_OK;
2173} 2170}
2174 2171
2175/* :P */ 2172/* :P */
2176static ApplyModifierResult 2173static ApplyModifierResult
2177ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2174ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2178{ 2175{
2179 GNode *gn; 2176 GNode *gn;
2180 char *path; 2177 char *path;
2181 2178
2182 ApplyModifiersState_Define(st); 2179 ApplyModifiersState_Define(st);
2183 2180
2184 gn = Targ_FindNode(st->v->name); 2181 gn = Targ_FindNode(st->v->name);
2185 if (gn == NULL || gn->type & OP_NOPATH) { 2182 if (gn == NULL || gn->type & OP_NOPATH) {
2186 path = NULL; 2183 path = NULL;
2187 } else if (gn->path != NULL) { 2184 } else if (gn->path != NULL) {
2188 path = bmake_strdup(gn->path); 2185 path = bmake_strdup(gn->path);
2189 } else { 2186 } else {
2190 SearchPath *searchPath = Suff_FindPath(gn); 2187 SearchPath *searchPath = Suff_FindPath(gn);
2191 path = Dir_FindFile(st->v->name, searchPath); 2188 path = Dir_FindFile(st->v->name, searchPath);
2192 } 2189 }
2193 if (path == NULL) 2190 if (path == NULL)
2194 path = bmake_strdup(st->v->name); 2191 path = bmake_strdup(st->v->name);
2195 st->newVal = path; 2192 st->newVal = path;
2196 2193
2197 (*pp)++; 2194 (*pp)++;
2198 return AMR_OK; 2195 return AMR_OK;
2199} 2196}
2200 2197
2201/* :!cmd! */ 2198/* :!cmd! */
2202static ApplyModifierResult 2199static ApplyModifierResult
2203ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2200ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2204{ 2201{
2205 char *cmd; 2202 char *cmd;
2206 const char *errfmt; 2203 const char *errfmt;
2207 VarParseResult res; 2204 VarParseResult res;
2208 2205
2209 (*pp)++; 2206 (*pp)++;
2210 res = ParseModifierPart(pp, '!', st->eflags, st, 2207 res = ParseModifierPart(pp, '!', st->eflags, st,
2211 &cmd, NULL, NULL, NULL); 2208 &cmd, NULL, NULL, NULL);
2212 if (res != VPR_OK) 2209 if (res != VPR_OK)
2213 return AMR_CLEANUP; 2210 return AMR_CLEANUP;
2214 2211
2215 errfmt = NULL; 2212 errfmt = NULL;
2216 if (st->eflags & VARE_WANTRES) 2213 if (st->eflags & VARE_WANTRES)
2217 st->newVal = Cmd_Exec(cmd, &errfmt); 2214 st->newVal = Cmd_Exec(cmd, &errfmt);
2218 else 2215 else
2219 st->newVal = emptyString; 2216 st->newVal = emptyString;
2220 free(cmd); 2217 free(cmd);
2221 2218
2222 if (errfmt != NULL) 2219 if (errfmt != NULL)
2223 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2220 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2224 2221
2225 ApplyModifiersState_Define(st); 2222 ApplyModifiersState_Define(st);
2226 return AMR_OK; 2223 return AMR_OK;
2227} 2224}
2228 2225
2229/* The :range modifier generates an integer sequence as long as the words. 2226/* The :range modifier generates an integer sequence as long as the words.
2230 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2227 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2231static ApplyModifierResult 2228static ApplyModifierResult
2232ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2229ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2233{ 2230{
2234 size_t n; 2231 size_t n;
2235 Buffer buf; 2232 Buffer buf;
2236 size_t i; 2233 size_t i;
2237 2234
2238 const char *mod = *pp; 2235 const char *mod = *pp;
2239 if (!ModMatchEq(mod, "range", st->endc)) 2236 if (!ModMatchEq(mod, "range", st->endc))
2240 return AMR_UNKNOWN; 2237 return AMR_UNKNOWN;
2241 2238
2242 if (mod[5] == '=') { 2239 if (mod[5] == '=') {
2243 char *ep; 2240 char *ep;
2244 n = (size_t)strtoul(mod + 6, &ep, 10); 2241 n = (size_t)strtoul(mod + 6, &ep, 10);
2245 *pp = ep; 2242 *pp = ep;
2246 } else { 2243 } else {
2247 n = 0; 2244 n = 0;
2248 *pp = mod + 5; 2245 *pp = mod + 5;
2249 } 2246 }
2250 2247
2251 if (n == 0) { 2248 if (n == 0) {
2252 Words words = Str_Words(st->val, FALSE); 2249 Words words = Str_Words(st->val, FALSE);
2253 n = words.len; 2250 n = words.len;
2254 Words_Free(words); 2251 Words_Free(words);
2255 } 2252 }
2256 2253
2257 Buf_Init(&buf, 0); 2254 Buf_Init(&buf, 0);
2258 2255
2259 for (i = 0; i < n; i++) { 2256 for (i = 0; i < n; i++) {
2260 if (i != 0) 2257 if (i != 0)
2261 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2258 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2262 Buf_AddInt(&buf, 1 + (int)i); 2259 Buf_AddInt(&buf, 1 + (int)i);
2263 } 2260 }
2264 2261
2265 st->newVal = Buf_Destroy(&buf, FALSE); 2262 st->newVal = Buf_Destroy(&buf, FALSE);
2266 return AMR_OK; 2263 return AMR_OK;
2267} 2264}
2268 2265
2269/* :Mpattern or :Npattern */ 2266/* :Mpattern or :Npattern */
2270static ApplyModifierResult 2267static ApplyModifierResult
2271ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2268ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2272{ 2269{
2273 const char *mod = *pp; 2270 const char *mod = *pp;
2274 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2271 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2275 Boolean needSubst = FALSE; 2272 Boolean needSubst = FALSE;
2276 const char *endpat; 2273 const char *endpat;
2277 char *pattern; 2274 char *pattern;
2278 ModifyWordsCallback callback; 2275 ModifyWordsCallback callback;
2279 2276
2280 /* 2277 /*
2281 * In the loop below, ignore ':' unless we are at (or back to) the 2278 * In the loop below, ignore ':' unless we are at (or back to) the
2282 * original brace level. 2279 * original brace level.
2283 * XXX This will likely not work right if $() and ${} are intermixed. 2280 * XXX This will likely not work right if $() and ${} are intermixed.
2284 */ 2281 */
2285 int nest = 0; 2282 int nest = 0;
2286 const char *p; 2283 const char *p;
2287 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2284 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2288 if (*p == '\\' && 2285 if (*p == '\\' &&
2289 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2286 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2290 if (!needSubst) 2287 if (!needSubst)
2291 copy = TRUE; 2288 copy = TRUE;
2292 p++; 2289 p++;
2293 continue; 2290 continue;
2294 } 2291 }
2295 if (*p == '$') 2292 if (*p == '$')
2296 needSubst = TRUE; 2293 needSubst = TRUE;
2297 if (*p == '(' || *p == '{') 2294 if (*p == '(' || *p == '{')
2298 nest++; 2295 nest++;
2299 if (*p == ')' || *p == '}') { 2296 if (*p == ')' || *p == '}') {
2300 nest--; 2297 nest--;
2301 if (nest < 0) 2298 if (nest < 0)
2302 break; 2299 break;
2303 } 2300 }
2304 } 2301 }
2305 *pp = p; 2302 *pp = p;
2306 endpat = p; 2303 endpat = p;
2307 2304
2308 if (copy) { 2305 if (copy) {
2309 char *dst; 2306 char *dst;
2310 const char *src; 2307 const char *src;
2311 2308
2312 /* Compress the \:'s out of the pattern. */ 2309 /* Compress the \:'s out of the pattern. */
2313 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2310 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2314 dst = pattern; 2311 dst = pattern;
2315 src = mod + 1; 2312 src = mod + 1;
2316 for (; src < endpat; src++, dst++) { 2313 for (; src < endpat; src++, dst++) {
2317 if (src[0] == '\\' && src + 1 < endpat && 2314 if (src[0] == '\\' && src + 1 < endpat &&
2318 /* XXX: st->startc is missing here; see above */ 2315 /* XXX: st->startc is missing here; see above */
2319 (src[1] == ':' || src[1] == st->endc)) 2316 (src[1] == ':' || src[1] == st->endc))
2320 src++; 2317 src++;
2321 *dst = *src; 2318 *dst = *src;
2322 } 2319 }
2323 *dst = '\0'; 2320 *dst = '\0';
2324 endpat = dst; 2321 endpat = dst;
2325 } else { 2322 } else {
2326 pattern = bmake_strsedup(mod + 1, endpat); 2323 pattern = bmake_strsedup(mod + 1, endpat);
2327 } 2324 }
2328 2325
2329 if (needSubst) { 2326 if (needSubst) {
2330 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2327 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2331 char *old_pattern = pattern; 2328 char *old_pattern = pattern;
2332 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2329 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2333 /* TODO: handle errors */ 2330 /* TODO: handle errors */
2334 free(old_pattern); 2331 free(old_pattern);
2335 } 2332 }
2336 2333
2337 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2334 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2338 2335
2339 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2336 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2340 st->newVal = ModifyWords(st->val, callback, pattern, 2337 st->newVal = ModifyWords(st->val, callback, pattern,
2341 st->oneBigWord, st->sep); 2338 st->oneBigWord, st->sep);
2342 free(pattern); 2339 free(pattern);
2343 return AMR_OK; 2340 return AMR_OK;
2344} 2341}
2345 2342
2346/* :S,from,to, */ 2343/* :S,from,to, */
2347static ApplyModifierResult 2344static ApplyModifierResult
2348ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2345ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2349{ 2346{
2350 struct ModifyWord_SubstArgs args; 2347 struct ModifyWord_SubstArgs args;
2351 char *lhs, *rhs; 2348 char *lhs, *rhs;
2352 Boolean oneBigWord; 2349 Boolean oneBigWord;
2353 VarParseResult res; 2350 VarParseResult res;
2354 2351
2355 char delim = (*pp)[1]; 2352 char delim = (*pp)[1];
2356 if (delim == '\0') { 2353 if (delim == '\0') {
2357 Error("Missing delimiter for :S modifier"); 2354 Error("Missing delimiter for :S modifier");
2358 (*pp)++; 2355 (*pp)++;
2359 return AMR_CLEANUP; 2356 return AMR_CLEANUP;
2360 } 2357 }
2361 2358
2362 *pp += 2; 2359 *pp += 2;
2363 2360
2364 args.pflags = 0; 2361 args.pflags = 0;
2365 args.matched = FALSE; 2362 args.matched = FALSE;
2366 2363
2367 /* 2364 /*
2368 * If pattern begins with '^', it is anchored to the 2365 * If pattern begins with '^', it is anchored to the
2369 * start of the word -- skip over it and flag pattern. 2366 * start of the word -- skip over it and flag pattern.
2370 */ 2367 */
2371 if (**pp == '^') { 2368 if (**pp == '^') {
2372 args.pflags |= VARP_ANCHOR_START; 2369 args.pflags |= VARP_ANCHOR_START;
2373 (*pp)++; 2370 (*pp)++;
2374 } 2371 }
2375 2372
2376 res = ParseModifierPart(pp, delim, st->eflags, st, 2373 res = ParseModifierPart(pp, delim, st->eflags, st,
2377 &lhs, &args.lhsLen, &args.pflags, NULL); 2374 &lhs, &args.lhsLen, &args.pflags, NULL);
2378 if (res != VPR_OK) 2375 if (res != VPR_OK)
2379 return AMR_CLEANUP; 2376 return AMR_CLEANUP;
2380 args.lhs = lhs; 2377 args.lhs = lhs;
2381 2378
2382 res = ParseModifierPart(pp, delim, st->eflags, st, 2379 res = ParseModifierPart(pp, delim, st->eflags, st,
2383 &rhs, &args.rhsLen, NULL, &args); 2380 &rhs, &args.rhsLen, NULL, &args);
2384 if (res != VPR_OK) 2381 if (res != VPR_OK)
2385 return AMR_CLEANUP; 2382 return AMR_CLEANUP;
2386 args.rhs = rhs; 2383 args.rhs = rhs;
2387 2384
2388 oneBigWord = st->oneBigWord; 2385 oneBigWord = st->oneBigWord;
2389 for (;; (*pp)++) { 2386 for (;; (*pp)++) {
2390 switch (**pp) { 2387 switch (**pp) {
2391 case 'g': 2388 case 'g':
2392 args.pflags |= VARP_SUB_GLOBAL; 2389 args.pflags |= VARP_SUB_GLOBAL;
2393 continue; 2390 continue;
2394 case '1': 2391 case '1':
2395 args.pflags |= VARP_SUB_ONE; 2392 args.pflags |= VARP_SUB_ONE;
2396 continue; 2393 continue;
2397 case 'W': 2394 case 'W':
2398 oneBigWord = TRUE; 2395 oneBigWord = TRUE;
2399 continue; 2396 continue;
2400 } 2397 }
2401 break; 2398 break;
2402 } 2399 }
2403 2400
2404 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args, 2401 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
2405 oneBigWord, st->sep); 2402 oneBigWord, st->sep);
2406 2403
2407 free(lhs); 2404 free(lhs);
2408 free(rhs); 2405 free(rhs);
2409 return AMR_OK; 2406 return AMR_OK;
2410} 2407}
2411 2408
2412#ifndef NO_REGEX 2409#ifndef NO_REGEX
2413 2410
2414/* :C,from,to, */ 2411/* :C,from,to, */
2415static ApplyModifierResult 2412static ApplyModifierResult
2416ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2413ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2417{ 2414{
2418 char *re; 2415 char *re;
2419 struct ModifyWord_SubstRegexArgs args; 2416 struct ModifyWord_SubstRegexArgs args;
2420 Boolean oneBigWord; 2417 Boolean oneBigWord;
2421 int error; 2418 int error;
2422 VarParseResult res; 2419 VarParseResult res;
2423 2420
2424 char delim = (*pp)[1]; 2421 char delim = (*pp)[1];
2425 if (delim == '\0') { 2422 if (delim == '\0') {
2426 Error("Missing delimiter for :C modifier"); 2423 Error("Missing delimiter for :C modifier");
2427 (*pp)++; 2424 (*pp)++;
2428 return AMR_CLEANUP; 2425 return AMR_CLEANUP;
2429 } 2426 }
2430 2427
2431 *pp += 2; 2428 *pp += 2;
2432 2429
2433 res = ParseModifierPart(pp, delim, st->eflags, st, 2430 res = ParseModifierPart(pp, delim, st->eflags, st,
2434 &re, NULL, NULL, NULL); 2431 &re, NULL, NULL, NULL);
2435 if (res != VPR_OK) 2432 if (res != VPR_OK)
2436 return AMR_CLEANUP; 2433 return AMR_CLEANUP;
2437 2434
2438 res = ParseModifierPart(pp, delim, st->eflags, st, 2435 res = ParseModifierPart(pp, delim, st->eflags, st,
2439 &args.replace, NULL, NULL, NULL); 2436 &args.replace, NULL, NULL, NULL);
2440 if (args.replace == NULL) { 2437 if (args.replace == NULL) {
2441 free(re); 2438 free(re);
2442 return AMR_CLEANUP; 2439 return AMR_CLEANUP;
2443 } 2440 }
2444 2441
2445 args.pflags = 0; 2442 args.pflags = 0;
2446 args.matched = FALSE; 2443 args.matched = FALSE;
2447 oneBigWord = st->oneBigWord; 2444 oneBigWord = st->oneBigWord;
2448 for (;; (*pp)++) { 2445 for (;; (*pp)++) {
2449 switch (**pp) { 2446 switch (**pp) {
2450 case 'g': 2447 case 'g':
2451 args.pflags |= VARP_SUB_GLOBAL; 2448 args.pflags |= VARP_SUB_GLOBAL;
2452 continue; 2449 continue;
2453 case '1': 2450 case '1':
2454 args.pflags |= VARP_SUB_ONE; 2451 args.pflags |= VARP_SUB_ONE;
2455 continue; 2452 continue;
2456 case 'W': 2453 case 'W':
2457 oneBigWord = TRUE; 2454 oneBigWord = TRUE;
2458 continue; 2455 continue;
2459 } 2456 }
2460 break; 2457 break;
2461 } 2458 }
2462 2459
2463 error = regcomp(&args.re, re, REG_EXTENDED); 2460 error = regcomp(&args.re, re, REG_EXTENDED);
2464 free(re); 2461 free(re);
2465 if (error) { 2462 if (error) {
2466 VarREError(error, &args.re, "Regex compilation error"); 2463 VarREError(error, &args.re, "Regex compilation error");
2467 free(args.replace); 2464 free(args.replace);
2468 return AMR_CLEANUP; 2465 return AMR_CLEANUP;
2469 } 2466 }
2470 2467
2471 args.nsub = args.re.re_nsub + 1; 2468 args.nsub = args.re.re_nsub + 1;
2472 if (args.nsub > 10) 2469 if (args.nsub > 10)
2473 args.nsub = 10; 2470 args.nsub = 10;
2474 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args, 2471 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
2475 oneBigWord, st->sep); 2472 oneBigWord, st->sep);
2476 regfree(&args.re); 2473 regfree(&args.re);
2477 free(args.replace); 2474 free(args.replace);
2478 return AMR_OK; 2475 return AMR_OK;
2479} 2476}
2480#endif 2477#endif
2481 2478
2482/* :Q, :q */ 2479/* :Q, :q */
2483static ApplyModifierResult 2480static ApplyModifierResult
2484ApplyModifier_Quote(const char **pp, ApplyModifiersState *st) 2481ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
2485{ 2482{
2486 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2483 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2487 st->newVal = VarQuote(st->val, **pp == 'q'); 2484 st->newVal = VarQuote(st->val, **pp == 'q');
2488 (*pp)++; 2485 (*pp)++;
2489 return AMR_OK; 2486 return AMR_OK;
2490 } else 2487 } else
2491 return AMR_UNKNOWN; 2488 return AMR_UNKNOWN;
2492} 2489}
2493 2490
2494static void 2491static void
2495ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2492ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2496{ 2493{
2497 SepBuf_AddStr(buf, word); 2494 SepBuf_AddStr(buf, word);
2498} 2495}
2499 2496
2500/* :ts<separator> */ 2497/* :ts<separator> */
2501static ApplyModifierResult 2498static ApplyModifierResult
2502ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2499ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2503{ 2500{
2504 const char *sep = *pp + 2; 2501 const char *sep = *pp + 2;
2505 2502
2506 /* ":ts<any><endc>" or ":ts<any>:" */ 2503 /* ":ts<any><endc>" or ":ts<any>:" */
2507 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2504 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2508 st->sep = sep[0]; 2505 st->sep = sep[0];
2509 *pp = sep + 1; 2506 *pp = sep + 1;
2510 goto ok; 2507 goto ok;
2511 } 2508 }
2512 2509
2513 /* ":ts<endc>" or ":ts:" */ 2510 /* ":ts<endc>" or ":ts:" */
2514 if (sep[0] == st->endc || sep[0] == ':') { 2511 if (sep[0] == st->endc || sep[0] == ':') {
2515 st->sep = '\0'; /* no separator */ 2512 st->sep = '\0'; /* no separator */
2516 *pp = sep; 2513 *pp = sep;
2517 goto ok; 2514 goto ok;
2518 } 2515 }
2519 2516
2520 /* ":ts<unrecognised><unrecognised>". */ 2517 /* ":ts<unrecognised><unrecognised>". */
2521 if (sep[0] != '\\') { 2518 if (sep[0] != '\\') {
2522 (*pp)++; /* just for backwards compatibility */ 2519 (*pp)++; /* just for backwards compatibility */
2523 return AMR_BAD; 2520 return AMR_BAD;
2524 } 2521 }
2525 2522
2526 /* ":ts\n" */ 2523 /* ":ts\n" */
2527 if (sep[1] == 'n') { 2524 if (sep[1] == 'n') {
2528 st->sep = '\n'; 2525 st->sep = '\n';
2529 *pp = sep + 2; 2526 *pp = sep + 2;
2530 goto ok; 2527 goto ok;
2531 } 2528 }
2532 2529
2533 /* ":ts\t" */ 2530 /* ":ts\t" */
2534 if (sep[1] == 't') { 2531 if (sep[1] == 't') {
2535 st->sep = '\t'; 2532 st->sep = '\t';
2536 *pp = sep + 2; 2533 *pp = sep + 2;
2537 goto ok; 2534 goto ok;
2538 } 2535 }
2539 2536
2540 /* ":ts\x40" or ":ts\100" */ 2537 /* ":ts\x40" or ":ts\100" */
2541 { 2538 {
2542 const char *numStart = sep + 1; 2539 const char *numStart = sep + 1;
2543 int base = 8; /* assume octal */ 2540 int base = 8; /* assume octal */
2544 char *end; 2541 char *end;
2545 2542
2546 if (sep[1] == 'x') { 2543 if (sep[1] == 'x') {
2547 base = 16; 2544 base = 16;
2548 numStart++; 2545 numStart++;
2549 } else if (!ch_isdigit(sep[1])) { 2546 } else if (!ch_isdigit(sep[1])) {
2550 (*pp)++; /* just for backwards compatibility */ 2547 (*pp)++; /* just for backwards compatibility */
2551 return AMR_BAD; /* ":ts<backslash><unrecognised>". */ 2548 return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2552 } 2549 }
2553 2550
2554 st->sep = (char)strtoul(numStart, &end, base); 2551 st->sep = (char)strtoul(numStart, &end, base);
2555 if (*end != ':' && *end != st->endc) { 2552 if (*end != ':' && *end != st->endc) {
2556 (*pp)++; /* just for backwards compatibility */ 2553 (*pp)++; /* just for backwards compatibility */
2557 return AMR_BAD; 2554 return AMR_BAD;
2558 } 2555 }
2559 *pp = end; 2556 *pp = end;
2560 } 2557 }
2561 2558
2562ok: 2559ok:
2563 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL, 2560 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
2564 st->oneBigWord, st->sep); 2561 st->oneBigWord, st->sep);
2565 return AMR_OK; 2562 return AMR_OK;
2566} 2563}
2567 2564
2568/* :tA, :tu, :tl, :ts<separator>, etc. */ 2565/* :tA, :tu, :tl, :ts<separator>, etc. */
2569static ApplyModifierResult 2566static ApplyModifierResult
2570ApplyModifier_To(const char **pp, ApplyModifiersState *st) 2567ApplyModifier_To(const char **pp, ApplyModifiersState *st)
2571{ 2568{
2572 const char *mod = *pp; 2569 const char *mod = *pp;
2573 assert(mod[0] == 't'); 2570 assert(mod[0] == 't');
2574 2571
2575 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { 2572 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2576 *pp = mod + 1; 2573 *pp = mod + 1;
2577 return AMR_BAD; /* Found ":t<endc>" or ":t:". */ 2574 return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2578 } 2575 }
2579 2576
2580 if (mod[1] == 's') 2577 if (mod[1] == 's')
2581 return ApplyModifier_ToSep(pp, st); 2578 return ApplyModifier_ToSep(pp, st);
2582 2579
2583 if (mod[2] != st->endc && mod[2] != ':') { 2580 if (mod[2] != st->endc && mod[2] != ':') {
2584 *pp = mod + 1; 2581 *pp = mod + 1;
2585 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ 2582 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2586 } 2583 }
2587 2584
2588 /* Check for two-character options: ":tu", ":tl" */ 2585 /* Check for two-character options: ":tu", ":tl" */
2589 if (mod[1] == 'A') { /* absolute path */ 2586 if (mod[1] == 'A') { /* absolute path */
2590 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL, 2587 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
2591 st->oneBigWord, st->sep); 2588 st->oneBigWord, st->sep);
2592 *pp = mod + 2; 2589 *pp = mod + 2;
2593 return AMR_OK; 2590 return AMR_OK;
2594 } 2591 }
2595 2592
2596 if (mod[1] == 'u') { /* :tu */ 2593 if (mod[1] == 'u') { /* :tu */
2597 size_t i; 2594 size_t i;
2598 size_t len = strlen(st->val); 2595 size_t len = strlen(st->val);
2599 st->newVal = bmake_malloc(len + 1); 2596 st->newVal = bmake_malloc(len + 1);
2600 for (i = 0; i < len + 1; i++) 2597 for (i = 0; i < len + 1; i++)
2601 st->newVal[i] = ch_toupper(st->val[i]); 2598 st->newVal[i] = ch_toupper(st->val[i]);
2602 *pp = mod + 2; 2599 *pp = mod + 2;
2603 return AMR_OK; 2600 return AMR_OK;
2604 } 2601 }
2605 2602
2606 if (mod[1] == 'l') { /* :tl */ 2603 if (mod[1] == 'l') { /* :tl */
2607 size_t i; 2604 size_t i;
2608 size_t len = strlen(st->val); 2605 size_t len = strlen(st->val);
2609 st->newVal = bmake_malloc(len + 1); 2606 st->newVal = bmake_malloc(len + 1);
2610 for (i = 0; i < len + 1; i++) 2607 for (i = 0; i < len + 1; i++)
2611 st->newVal[i] = ch_tolower(st->val[i]); 2608 st->newVal[i] = ch_tolower(st->val[i]);
2612 *pp = mod + 2; 2609 *pp = mod + 2;
2613 return AMR_OK; 2610 return AMR_OK;
2614 } 2611 }
2615 2612
2616 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ 2613 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2617 st->oneBigWord = mod[1] == 'W'; 2614 st->oneBigWord = mod[1] == 'W';
2618 st->newVal = st->val; 2615 st->newVal = st->val;
2619 *pp = mod + 2; 2616 *pp = mod + 2;
2620 return AMR_OK; 2617 return AMR_OK;
2621 } 2618 }
2622 2619
2623 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2620 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2624 *pp = mod + 1; 2621 *pp = mod + 1;
2625 return AMR_BAD; 2622 return AMR_BAD;
2626} 2623}
2627 2624
2628/* :[#], :[1], etc. */ 2625/* :[#], :[1], etc. */
2629static ApplyModifierResult 2626static ApplyModifierResult
2630ApplyModifier_Words(const char **pp, ApplyModifiersState *st) 2627ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
2631{ 2628{
2632 char *estr; 2629 char *estr;
2633 char *ep; 2630 char *ep;
2634 int first, last; 2631 int first, last;
2635 VarParseResult res; 2632 VarParseResult res;
2636 2633
2637 (*pp)++; /* skip the '[' */ 2634 (*pp)++; /* skip the '[' */
2638 res = ParseModifierPart(pp, ']', st->eflags, st, 2635 res = ParseModifierPart(pp, ']', st->eflags, st,
2639 &estr, NULL, NULL, NULL); 2636 &estr, NULL, NULL, NULL);
2640 if (res != VPR_OK) 2637 if (res != VPR_OK)
2641 return AMR_CLEANUP; 2638 return AMR_CLEANUP;
2642 2639
2643 /* now *pp points just after the closing ']' */ 2640 /* now *pp points just after the closing ']' */
2644 if (**pp != ':' && **pp != st->endc) 2641 if (**pp != ':' && **pp != st->endc)
2645 goto bad_modifier; /* Found junk after ']' */ 2642 goto bad_modifier; /* Found junk after ']' */
2646 2643
2647 if (estr[0] == '\0') 2644 if (estr[0] == '\0')
2648 goto bad_modifier; /* empty square brackets in ":[]". */ 2645 goto bad_modifier; /* empty square brackets in ":[]". */
2649 2646
2650 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2647 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2651 if (st->oneBigWord) { 2648 if (st->oneBigWord) {
2652 st->newVal = bmake_strdup("1"); 2649 st->newVal = bmake_strdup("1");
2653 } else { 2650 } else {
2654 Buffer buf; 2651 Buffer buf;
2655 2652
2656 Words words = Str_Words(st->val, FALSE); 2653 Words words = Str_Words(st->val, FALSE);
2657 size_t ac = words.len; 2654 size_t ac = words.len;
2658 Words_Free(words); 2655 Words_Free(words);
2659 2656

cvs diff -r1.11 -r1.12 src/usr.bin/make/unit-tests/vardebug.exp (switch to unified diff)

--- src/usr.bin/make/unit-tests/vardebug.exp 2020/10/29 18:38:24 1.11
+++ src/usr.bin/make/unit-tests/vardebug.exp 2020/10/31 18:14:59 1.12
@@ -1,88 +1,86 @@ @@ -1,88 +1,86 @@
1Global:delete FROM_CMDLINE (not found) 1Global:delete FROM_CMDLINE (not found)
2Command:FROM_CMDLINE =  2Command:FROM_CMDLINE =
3Global:.MAKEOVERRIDES = FROM_CMDLINE 3Global:.MAKEOVERRIDES = FROM_CMDLINE
4Global:VAR = added 4Global:VAR = added
5Global:VAR = overwritten 5Global:VAR = overwritten
6Global:delete VAR 6Global:delete VAR
7Global:delete VAR (not found) 7Global:delete VAR (not found)
8Var_Parse: ${:U} with VARE_WANTRES 8Var_Parse: ${:U} with VARE_WANTRES
9Applying ${:U} to "" (VARE_WANTRES, none, VEF_UNDEF) 9Applying ${:U} to "" (VARE_WANTRES, none, VEF_UNDEF)
10Result of ${:U} is "" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 10Result of ${:U} is "" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
11Var_Set("${:U}", "empty name", ...) name expands to empty string - ignored 11Var_Set("${:U}", "empty name", ...) name expands to empty string - ignored
12Var_Parse: ${:U} with VARE_WANTRES 12Var_Parse: ${:U} with VARE_WANTRES
13Applying ${:U} to "" (VARE_WANTRES, none, VEF_UNDEF) 13Applying ${:U} to "" (VARE_WANTRES, none, VEF_UNDEF)
14Result of ${:U} is "" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 14Result of ${:U} is "" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
15Var_Append("${:U}", "empty name", ...) name expands to empty string - ignored 15Var_Append("${:U}", "empty name", ...) name expands to empty string - ignored
16Global:FROM_CMDLINE = overwritten ignored! 16Global:FROM_CMDLINE = overwritten ignored!
17Global:VAR = 1 17Global:VAR = 1
18Global:VAR = 1 2 18Global:VAR = 1 2
19Global:VAR = 1 2 3 19Global:VAR = 1 2 3
20Var_Parse: ${VAR:M[2]} with VARE_UNDEFERR|VARE_WANTRES 20Var_Parse: ${VAR:M[2]} with VARE_UNDEFERR|VARE_WANTRES
21Applying ${VAR:M...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 21Applying ${VAR:M...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
22Pattern[VAR] for [1 2 3] is [[2]] 22Pattern[VAR] for [1 2 3] is [[2]]
23ModifyWords: split "1 2 3" into 3 words 23ModifyWords: split "1 2 3" into 3 words
24VarMatch [1] [[2]] 24VarMatch [1] [[2]]
25VarMatch [2] [[2]] 25VarMatch [2] [[2]]
26VarMatch [3] [[2]] 26VarMatch [3] [[2]]
27Result of ${VAR:M[2]} is "2" (VARE_UNDEFERR|VARE_WANTRES, none, none) 27Result of ${VAR:M[2]} is "2" (VARE_UNDEFERR|VARE_WANTRES, none, none)
28Var_Parse: ${VAR:N[2]} with VARE_UNDEFERR|VARE_WANTRES 28Var_Parse: ${VAR:N[2]} with VARE_UNDEFERR|VARE_WANTRES
29Applying ${VAR:N...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 29Applying ${VAR:N...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
30Pattern[VAR] for [1 2 3] is [[2]] 30Pattern[VAR] for [1 2 3] is [[2]]
31ModifyWords: split "1 2 3" into 3 words 31ModifyWords: split "1 2 3" into 3 words
32Result of ${VAR:N[2]} is "1 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 32Result of ${VAR:N[2]} is "1 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
33Var_Parse: ${VAR:S,2,two,} with VARE_UNDEFERR|VARE_WANTRES 33Var_Parse: ${VAR:S,2,two,} with VARE_UNDEFERR|VARE_WANTRES
34Applying ${VAR:S...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 34Applying ${VAR:S...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
35Modifier part: "2" 35Modifier part: "2"
36Modifier part: "two" 36Modifier part: "two"
37ModifyWords: split "1 2 3" into 3 words 37ModifyWords: split "1 2 3" into 3 words
38Result of ${VAR:S,2,two,} is "1 two 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 38Result of ${VAR:S,2,two,} is "1 two 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
39Var_Parse: ${VAR:Q} with VARE_UNDEFERR|VARE_WANTRES 39Var_Parse: ${VAR:Q} with VARE_UNDEFERR|VARE_WANTRES
40Applying ${VAR:Q} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 40Applying ${VAR:Q} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
41QuoteMeta: [1\ 2\ 3] 
42Result of ${VAR:Q} is "1\ 2\ 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 41Result of ${VAR:Q} is "1\ 2\ 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
43Var_Parse: ${VAR:tu:tl:Q} with VARE_UNDEFERR|VARE_WANTRES 42Var_Parse: ${VAR:tu:tl:Q} with VARE_UNDEFERR|VARE_WANTRES
44Applying ${VAR:t...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 43Applying ${VAR:t...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
45Result of ${VAR:tu} is "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 44Result of ${VAR:tu} is "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
46Applying ${VAR:t...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 45Applying ${VAR:t...} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
47Result of ${VAR:tl} is "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 46Result of ${VAR:tl} is "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
48Applying ${VAR:Q} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 47Applying ${VAR:Q} to "1 2 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
49QuoteMeta: [1\ 2\ 3] 
50Result of ${VAR:Q} is "1\ 2\ 3" (VARE_UNDEFERR|VARE_WANTRES, none, none) 48Result of ${VAR:Q} is "1\ 2\ 3" (VARE_UNDEFERR|VARE_WANTRES, none, none)
51Var_Parse: ${:Uvalue:${:UM*e}:Mvalu[e]} with VARE_UNDEFERR|VARE_WANTRES 49Var_Parse: ${:Uvalue:${:UM*e}:Mvalu[e]} with VARE_UNDEFERR|VARE_WANTRES
52Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF) 50Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF)
53Result of ${:Uvalue} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 51Result of ${:Uvalue} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
54Var_Parse: ${:UM*e}:Mvalu[e]} with VARE_UNDEFERR|VARE_WANTRES 52Var_Parse: ${:UM*e}:Mvalu[e]} with VARE_UNDEFERR|VARE_WANTRES
55Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF) 53Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF)
56Result of ${:UM*e} is "M*e" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 54Result of ${:UM*e} is "M*e" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
57Indirect modifier "M*e" from "${:UM*e}" 55Indirect modifier "M*e" from "${:UM*e}"
58Applying ${:M...} to "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 56Applying ${:M...} to "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
59Pattern[] for [value] is [*e] 57Pattern[] for [value] is [*e]
60ModifyWords: split "value" into 1 words 58ModifyWords: split "value" into 1 words
61VarMatch [value] [*e] 59VarMatch [value] [*e]
62Result of ${:M*e} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 60Result of ${:M*e} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
63Applying ${:M...} to "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 61Applying ${:M...} to "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
64Pattern[] for [value] is [valu[e]] 62Pattern[] for [value] is [valu[e]]
65ModifyWords: split "value" into 1 words 63ModifyWords: split "value" into 1 words
66VarMatch [value] [valu[e]] 64VarMatch [value] [valu[e]]
67Result of ${:Mvalu[e]} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 65Result of ${:Mvalu[e]} is "value" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
68Var_Parse: ${:UVAR} with VARE_WANTRES 66Var_Parse: ${:UVAR} with VARE_WANTRES
69Applying ${:U...} to "" (VARE_WANTRES, none, VEF_UNDEF) 67Applying ${:U...} to "" (VARE_WANTRES, none, VEF_UNDEF)
70Result of ${:UVAR} is "VAR" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 68Result of ${:UVAR} is "VAR" (VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
71Global:delete VAR 69Global:delete VAR
72Var_Parse: ${:Uvariable:unknown} with VARE_UNDEFERR|VARE_WANTRES 70Var_Parse: ${:Uvariable:unknown} with VARE_UNDEFERR|VARE_WANTRES
73Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF) 71Applying ${:U...} to "" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF)
74Result of ${:Uvariable} is "variable" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 72Result of ${:Uvariable} is "variable" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
75Applying ${:u...} to "variable" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 73Applying ${:u...} to "variable" (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
76make: Unknown modifier 'u' 74make: Unknown modifier 'u'
77Result of ${:unknown} is error (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF) 75Result of ${:unknown} is error (VARE_UNDEFERR|VARE_WANTRES, none, VEF_UNDEF|VEF_DEF)
78make: "vardebug.mk" line 44: Malformed conditional (${:Uvariable:unknown}) 76make: "vardebug.mk" line 44: Malformed conditional (${:Uvariable:unknown})
79Var_Parse: ${UNDEFINED} with VARE_UNDEFERR|VARE_WANTRES 77Var_Parse: ${UNDEFINED} with VARE_UNDEFERR|VARE_WANTRES
80make: "vardebug.mk" line 53: Malformed conditional (${UNDEFINED}) 78make: "vardebug.mk" line 53: Malformed conditional (${UNDEFINED})
81Global:delete .SHELL (not found) 79Global:delete .SHELL (not found)
82Command:.SHELL = /bin/sh 80Command:.SHELL = /bin/sh
83Command:.SHELL = overwritten ignored (read-only) 81Command:.SHELL = overwritten ignored (read-only)
84Global:.MAKEFLAGS = -r -k -d v -d 82Global:.MAKEFLAGS = -r -k -d v -d
85Global:.MAKEFLAGS = -r -k -d v -d 0 83Global:.MAKEFLAGS = -r -k -d v -d 0
86make: Fatal errors encountered -- cannot continue 84make: Fatal errors encountered -- cannot continue
87make: stopped in unit-tests 85make: stopped in unit-tests
88exit status 1 86exit status 1