Sat Oct 31 12:22:43 2020 UTC ()
make(1): remove redundant condition for regmatch_t.rm_eo being -1

If rm_so is -1, rm_eo is guaranteed to be -1 as well.


(rillig)
diff -r1.616 -r1.617 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/31 11:54:33 1.616
+++ src/usr.bin/make/var.c 2020/10/31 12:22:43 1.617
@@ -1,2410 +1,2410 @@ @@ -1,2410 +1,2410 @@
1/* $NetBSD: var.c,v 1.616 2020/10/31 11:54:33 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.617 2020/10/31 12:22:43 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.616 2020/10/31 11:54:33 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.617 2020/10/31 12:22:43 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 && m[n].rm_eo == -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: in \"%s\", replace \"%s\" with \"%s\" " 1468 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1469 "to \"%s\"\n", 1469 "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/*- 1479/*-
1480 * Implements the :[first..last] modifier. 1480 * Implements the :[first..last] modifier.
1481 * This is a special case of ModifyWords since we want to be able 1481 * This is a special case of ModifyWords since we want to be able
1482 * to scan the list backwards if first > last. 1482 * to scan the list backwards if first > last.
1483 */ 1483 */
1484static char * 1484static char *
1485VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1485VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1486 int last) 1486 int last)
1487{ 1487{
1488 Words words; 1488 Words words;
1489 int len, start, end, step; 1489 int len, start, end, step;
1490 int i; 1490 int i;
1491 1491
1492 SepBuf buf; 1492 SepBuf buf;
1493 SepBuf_Init(&buf, sep); 1493 SepBuf_Init(&buf, sep);
1494 1494
1495 if (oneBigWord) { 1495 if (oneBigWord) {
1496 /* fake what Str_Words() would do if there were only one word */ 1496 /* fake what Str_Words() would do if there were only one word */
1497 words.len = 1; 1497 words.len = 1;
1498 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1498 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1499 words.freeIt = bmake_strdup(str); 1499 words.freeIt = bmake_strdup(str);
1500 words.words[0] = words.freeIt; 1500 words.words[0] = words.freeIt;
1501 words.words[1] = NULL; 1501 words.words[1] = NULL;
1502 } else { 1502 } else {
1503 words = Str_Words(str, FALSE); 1503 words = Str_Words(str, FALSE);
1504 } 1504 }
1505 1505
1506 /* 1506 /*
1507 * Now sanitize the given range. 1507 * Now sanitize the given range.
1508 * If first or last are negative, convert them to the positive equivalents 1508 * If first or last are negative, convert them to the positive equivalents
1509 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1509 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1510 */ 1510 */
1511 len = (int)words.len; 1511 len = (int)words.len;
1512 if (first < 0) 1512 if (first < 0)
1513 first += len + 1; 1513 first += len + 1;
1514 if (last < 0) 1514 if (last < 0)
1515 last += len + 1; 1515 last += len + 1;
1516 1516
1517 /* 1517 /*
1518 * We avoid scanning more of the list than we need to. 1518 * We avoid scanning more of the list than we need to.
1519 */ 1519 */
1520 if (first > last) { 1520 if (first > last) {
1521 start = (first > len ? len : first) - 1; 1521 start = (first > len ? len : first) - 1;
1522 end = last < 1 ? 0 : last - 1; 1522 end = last < 1 ? 0 : last - 1;
1523 step = -1; 1523 step = -1;
1524 } else { 1524 } else {
1525 start = first < 1 ? 0 : first - 1; 1525 start = first < 1 ? 0 : first - 1;
1526 end = last > len ? len : last; 1526 end = last > len ? len : last;
1527 step = 1; 1527 step = 1;
1528 } 1528 }
1529 1529
1530 for (i = start; (step < 0) == (i >= end); i += step) { 1530 for (i = start; (step < 0) == (i >= end); i += step) {
1531 SepBuf_AddStr(&buf, words.words[i]); 1531 SepBuf_AddStr(&buf, words.words[i]);
1532 SepBuf_Sep(&buf); 1532 SepBuf_Sep(&buf);
1533 } 1533 }
1534 1534
1535 Words_Free(words); 1535 Words_Free(words);
1536 1536
1537 return SepBuf_Destroy(&buf, FALSE); 1537 return SepBuf_Destroy(&buf, FALSE);
1538} 1538}
1539 1539
1540 1540
1541/* Callback for ModifyWords to implement the :tA modifier. 1541/* Callback for ModifyWords to implement the :tA modifier.
1542 * Replace each word with the result of realpath() if successful. */ 1542 * Replace each word with the result of realpath() if successful. */
1543static void 1543static void
1544ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1544ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1545{ 1545{
1546 struct stat st; 1546 struct stat st;
1547 char rbuf[MAXPATHLEN]; 1547 char rbuf[MAXPATHLEN];
1548 1548
1549 const char *rp = cached_realpath(word, rbuf); 1549 const char *rp = cached_realpath(word, rbuf);
1550 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1550 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1551 word = rp; 1551 word = rp;
1552 1552
1553 SepBuf_AddStr(buf, word); 1553 SepBuf_AddStr(buf, word);
1554} 1554}
1555 1555
1556/*- 1556/*-
1557 *----------------------------------------------------------------------- 1557 *-----------------------------------------------------------------------
1558 * Modify each of the words of the passed string using the given function. 1558 * Modify each of the words of the passed string using the given function.
1559 * 1559 *
1560 * Input: 1560 * Input:
1561 * str String whose words should be modified 1561 * str String whose words should be modified
1562 * modifyWord Function that modifies a single word 1562 * modifyWord Function that modifies a single word
1563 * modifyWord_args Custom arguments for modifyWord 1563 * modifyWord_args Custom arguments for modifyWord
1564 * 1564 *
1565 * Results: 1565 * Results:
1566 * A string of all the words modified appropriately. 1566 * A string of all the words modified appropriately.
1567 *----------------------------------------------------------------------- 1567 *-----------------------------------------------------------------------
1568 */ 1568 */
1569static char * 1569static char *
1570ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1570ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str,
1571 ModifyWordsCallback modifyWord, void *modifyWord_args) 1571 ModifyWordsCallback modifyWord, void *modifyWord_args)
1572{ 1572{
1573 SepBuf result; 1573 SepBuf result;
1574 Words words; 1574 Words words;
1575 size_t i; 1575 size_t i;
1576 1576
1577 if (oneBigWord) { 1577 if (oneBigWord) {
1578 SepBuf_Init(&result, sep); 1578 SepBuf_Init(&result, sep);
1579 modifyWord(str, &result, modifyWord_args); 1579 modifyWord(str, &result, modifyWord_args);
1580 return SepBuf_Destroy(&result, FALSE); 1580 return SepBuf_Destroy(&result, FALSE);
1581 } 1581 }
1582 1582
1583 SepBuf_Init(&result, sep); 1583 SepBuf_Init(&result, sep);
1584 1584
1585 words = Str_Words(str, FALSE); 1585 words = Str_Words(str, FALSE);
1586 1586
1587 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1587 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1588 1588
1589 for (i = 0; i < words.len; i++) { 1589 for (i = 0; i < words.len; i++) {
1590 modifyWord(words.words[i], &result, modifyWord_args); 1590 modifyWord(words.words[i], &result, modifyWord_args);
1591 if (Buf_Len(&result.buf) > 0) 1591 if (Buf_Len(&result.buf) > 0)
1592 SepBuf_Sep(&result); 1592 SepBuf_Sep(&result);
1593 } 1593 }
1594 1594
1595 Words_Free(words); 1595 Words_Free(words);
1596 1596
1597 return SepBuf_Destroy(&result, FALSE); 1597 return SepBuf_Destroy(&result, FALSE);
1598} 1598}
1599 1599
1600 1600
1601static char * 1601static char *
1602Words_JoinFree(Words words) 1602Words_JoinFree(Words words)
1603{ 1603{
1604 Buffer buf; 1604 Buffer buf;
1605 size_t i; 1605 size_t i;
1606 1606
1607 Buf_Init(&buf, 0); 1607 Buf_Init(&buf, 0);
1608 1608
1609 for (i = 0; i < words.len; i++) { 1609 for (i = 0; i < words.len; i++) {
1610 if (i != 0) 1610 if (i != 0)
1611 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1611 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1612 Buf_AddStr(&buf, words.words[i]); 1612 Buf_AddStr(&buf, words.words[i]);
1613 } 1613 }
1614 1614
1615 Words_Free(words); 1615 Words_Free(words);
1616 1616
1617 return Buf_Destroy(&buf, FALSE); 1617 return Buf_Destroy(&buf, FALSE);
1618} 1618}
1619 1619
1620/* Remove adjacent duplicate words. */ 1620/* Remove adjacent duplicate words. */
1621static char * 1621static char *
1622VarUniq(const char *str) 1622VarUniq(const char *str)
1623{ 1623{
1624 Words words = Str_Words(str, FALSE); 1624 Words words = Str_Words(str, FALSE);
1625 1625
1626 if (words.len > 1) { 1626 if (words.len > 1) {
1627 size_t i, j; 1627 size_t i, j;
1628 for (j = 0, i = 1; i < words.len; i++) 1628 for (j = 0, i = 1; i < words.len; i++)
1629 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i)) 1629 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1630 words.words[j] = words.words[i]; 1630 words.words[j] = words.words[i];
1631 words.len = j + 1; 1631 words.len = j + 1;
1632 } 1632 }
1633 1633
1634 return Words_JoinFree(words); 1634 return Words_JoinFree(words);
1635} 1635}
1636 1636
1637 1637
1638/* Quote shell meta-characters and space characters in the string. 1638/* Quote shell meta-characters and space characters in the string.
1639 * If quoteDollar is set, also quote and double any '$' characters. */ 1639 * If quoteDollar is set, also quote and double any '$' characters. */
1640static char * 1640static char *
1641VarQuote(const char *str, Boolean quoteDollar) 1641VarQuote(const char *str, Boolean quoteDollar)
1642{ 1642{
1643 char *res; 1643 char *res;
1644 Buffer buf; 1644 Buffer buf;
1645 Buf_Init(&buf, 0); 1645 Buf_Init(&buf, 0);
1646 1646
1647 for (; *str != '\0'; str++) { 1647 for (; *str != '\0'; str++) {
1648 if (*str == '\n') { 1648 if (*str == '\n') {
1649 const char *newline = Shell_GetNewline(); 1649 const char *newline = Shell_GetNewline();
1650 if (newline == NULL) 1650 if (newline == NULL)
1651 newline = "\\\n"; 1651 newline = "\\\n";
1652 Buf_AddStr(&buf, newline); 1652 Buf_AddStr(&buf, newline);
1653 continue; 1653 continue;
1654 } 1654 }
1655 if (ch_isspace(*str) || ismeta((unsigned char)*str)) 1655 if (ch_isspace(*str) || ismeta((unsigned char)*str))
1656 Buf_AddByte(&buf, '\\'); 1656 Buf_AddByte(&buf, '\\');
1657 Buf_AddByte(&buf, *str); 1657 Buf_AddByte(&buf, *str);
1658 if (quoteDollar && *str == '$') 1658 if (quoteDollar && *str == '$')
1659 Buf_AddStr(&buf, "\\$"); 1659 Buf_AddStr(&buf, "\\$");
1660 } 1660 }
1661 1661
1662 res = Buf_Destroy(&buf, FALSE); 1662 res = Buf_Destroy(&buf, FALSE);
1663 VAR_DEBUG1("QuoteMeta: [%s]\n", res); 1663 VAR_DEBUG1("QuoteMeta: [%s]\n", res);
1664 return res; 1664 return res;
1665} 1665}
1666 1666
1667/* Compute the 32-bit hash of the given string, using the MurmurHash3 1667/* Compute the 32-bit hash of the given string, using the MurmurHash3
1668 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1668 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1669static char * 1669static char *
1670VarHash(const char *str) 1670VarHash(const char *str)
1671{ 1671{
1672 static const char hexdigits[16] = "0123456789abcdef"; 1672 static const char hexdigits[16] = "0123456789abcdef";
1673 const unsigned char *ustr = (const unsigned char *)str; 1673 const unsigned char *ustr = (const unsigned char *)str;
1674 1674
1675 uint32_t h = 0x971e137bU; 1675 uint32_t h = 0x971e137bU;
1676 uint32_t c1 = 0x95543787U; 1676 uint32_t c1 = 0x95543787U;
1677 uint32_t c2 = 0x2ad7eb25U; 1677 uint32_t c2 = 0x2ad7eb25U;
1678 size_t len2 = strlen(str); 1678 size_t len2 = strlen(str);
1679 1679
1680 char *buf; 1680 char *buf;
1681 size_t i; 1681 size_t i;
1682 1682
1683 size_t len; 1683 size_t len;
1684 for (len = len2; len; ) { 1684 for (len = len2; len; ) {
1685 uint32_t k = 0; 1685 uint32_t k = 0;
1686 switch (len) { 1686 switch (len) {
1687 default: 1687 default:
1688 k = ((uint32_t)ustr[3] << 24) | 1688 k = ((uint32_t)ustr[3] << 24) |
1689 ((uint32_t)ustr[2] << 16) | 1689 ((uint32_t)ustr[2] << 16) |
1690 ((uint32_t)ustr[1] << 8) | 1690 ((uint32_t)ustr[1] << 8) |
1691 (uint32_t)ustr[0]; 1691 (uint32_t)ustr[0];
1692 len -= 4; 1692 len -= 4;
1693 ustr += 4; 1693 ustr += 4;
1694 break; 1694 break;
1695 case 3: 1695 case 3:
1696 k |= (uint32_t)ustr[2] << 16; 1696 k |= (uint32_t)ustr[2] << 16;
1697 /* FALLTHROUGH */ 1697 /* FALLTHROUGH */
1698 case 2: 1698 case 2:
1699 k |= (uint32_t)ustr[1] << 8; 1699 k |= (uint32_t)ustr[1] << 8;
1700 /* FALLTHROUGH */ 1700 /* FALLTHROUGH */
1701 case 1: 1701 case 1:
1702 k |= (uint32_t)ustr[0]; 1702 k |= (uint32_t)ustr[0];
1703 len = 0; 1703 len = 0;
1704 } 1704 }
1705 c1 = c1 * 5 + 0x7b7d159cU; 1705 c1 = c1 * 5 + 0x7b7d159cU;
1706 c2 = c2 * 5 + 0x6bce6396U; 1706 c2 = c2 * 5 + 0x6bce6396U;
1707 k *= c1; 1707 k *= c1;
1708 k = (k << 11) ^ (k >> 21); 1708 k = (k << 11) ^ (k >> 21);
1709 k *= c2; 1709 k *= c2;
1710 h = (h << 13) ^ (h >> 19); 1710 h = (h << 13) ^ (h >> 19);
1711 h = h * 5 + 0x52dce729U; 1711 h = h * 5 + 0x52dce729U;
1712 h ^= k; 1712 h ^= k;
1713 } 1713 }
1714 h ^= (uint32_t)len2; 1714 h ^= (uint32_t)len2;
1715 h *= 0x85ebca6b; 1715 h *= 0x85ebca6b;
1716 h ^= h >> 13; 1716 h ^= h >> 13;
1717 h *= 0xc2b2ae35; 1717 h *= 0xc2b2ae35;
1718 h ^= h >> 16; 1718 h ^= h >> 16;
1719 1719
1720 buf = bmake_malloc(9); 1720 buf = bmake_malloc(9);
1721 for (i = 0; i < 8; i++) { 1721 for (i = 0; i < 8; i++) {
1722 buf[i] = hexdigits[h & 0x0f]; 1722 buf[i] = hexdigits[h & 0x0f];
1723 h >>= 4; 1723 h >>= 4;
1724 } 1724 }
1725 buf[8] = '\0'; 1725 buf[8] = '\0';
1726 return buf; 1726 return buf;
1727} 1727}
1728 1728
1729static char * 1729static char *
1730VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1730VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1731{ 1731{
1732 char buf[BUFSIZ]; 1732 char buf[BUFSIZ];
1733 1733
1734 if (!tim) 1734 if (!tim)
1735 time(&tim); 1735 time(&tim);
1736 if (!*fmt) 1736 if (!*fmt)
1737 fmt = "%c"; 1737 fmt = "%c";
1738 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1738 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1739 1739
1740 buf[sizeof(buf) - 1] = '\0'; 1740 buf[sizeof(buf) - 1] = '\0';
1741 return bmake_strdup(buf); 1741 return bmake_strdup(buf);
1742} 1742}
1743 1743
1744/* The ApplyModifier functions all work in the same way. They get the 1744/* The ApplyModifier functions all work in the same way. They get the
1745 * current parsing position (pp) and parse the modifier from there. The 1745 * current parsing position (pp) and parse the modifier from there. The
1746 * modifier typically lasts until the next ':', or a closing '}' or ')' 1746 * modifier typically lasts until the next ':', or a closing '}' or ')'
1747 * (taken from st->endc), or the end of the string (parse error). 1747 * (taken from st->endc), or the end of the string (parse error).
1748 * 1748 *
1749 * The high-level behavior of these functions is: 1749 * The high-level behavior of these functions is:
1750 * 1750 *
1751 * 1. parse the modifier 1751 * 1. parse the modifier
1752 * 2. evaluate the modifier 1752 * 2. evaluate the modifier
1753 * 3. housekeeping 1753 * 3. housekeeping
1754 * 1754 *
1755 * Parsing the modifier 1755 * Parsing the modifier
1756 * 1756 *
1757 * If parsing succeeds, the parsing position *pp is updated to point to the 1757 * If parsing succeeds, the parsing position *pp is updated to point to the
1758 * first character following the modifier, which typically is either ':' or 1758 * first character following the modifier, which typically is either ':' or
1759 * st->endc. 1759 * st->endc.
1760 * 1760 *
1761 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1761 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1762 * modifiers), return AMR_CLEANUP. 1762 * modifiers), return AMR_CLEANUP.
1763 * 1763 *
1764 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1764 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1765 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1765 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1766 * done as long as there have been no side effects from evaluating nested 1766 * done as long as there have been no side effects from evaluating nested
1767 * variables, to avoid evaluating them more than once. In this case, the 1767 * variables, to avoid evaluating them more than once. In this case, the
1768 * parsing position must not be updated. (XXX: Why not? The original parsing 1768 * parsing position must not be updated. (XXX: Why not? The original parsing
1769 * position is well-known in ApplyModifiers.) 1769 * position is well-known in ApplyModifiers.)
1770 * 1770 *
1771 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1771 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1772 * as a fallback, either issue an error message using Error or Parse_Error 1772 * as a fallback, either issue an error message using Error or Parse_Error
1773 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1773 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1774 * message. Both of these return values will stop processing the variable 1774 * message. Both of these return values will stop processing the variable
1775 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1775 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1776 * continues nevertheless after skipping a few bytes, which essentially is 1776 * continues nevertheless after skipping a few bytes, which essentially is
1777 * undefined behavior. Not in the sense of C, but still it's impossible to 1777 * undefined behavior. Not in the sense of C, but still it's impossible to
1778 * predict what happens in the parser.) 1778 * predict what happens in the parser.)
1779 * 1779 *
1780 * Evaluating the modifier 1780 * Evaluating the modifier
1781 * 1781 *
1782 * After parsing, the modifier is evaluated. The side effects from evaluating 1782 * After parsing, the modifier is evaluated. The side effects from evaluating
1783 * nested variable expressions in the modifier text often already happen 1783 * nested variable expressions in the modifier text often already happen
1784 * during parsing though. 1784 * during parsing though.
1785 * 1785 *
1786 * Evaluating the modifier usually takes the current value of the variable 1786 * Evaluating the modifier usually takes the current value of the variable
1787 * expression from st->val, or the variable name from st->v->name and stores 1787 * expression from st->val, or the variable name from st->v->name and stores
1788 * the result in st->newVal. 1788 * the result in st->newVal.
1789 * 1789 *
1790 * If evaluating fails (as of 2020-08-23), an error message is printed using 1790 * If evaluating fails (as of 2020-08-23), an error message is printed using
1791 * Error. This function has no side-effects, it really just prints the error 1791 * Error. This function has no side-effects, it really just prints the error
1792 * message. Processing the expression continues as if everything were ok. 1792 * message. Processing the expression continues as if everything were ok.
1793 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1793 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1794 * Var_Parse, ApplyModifiers and ModifyWords. 1794 * Var_Parse, ApplyModifiers and ModifyWords.
1795 * 1795 *
1796 * Housekeeping 1796 * Housekeeping
1797 * 1797 *
1798 * Some modifiers such as :D and :U turn undefined expressions into defined 1798 * Some modifiers such as :D and :U turn undefined expressions into defined
1799 * expressions (see VEF_UNDEF, VEF_DEF). 1799 * expressions (see VEF_UNDEF, VEF_DEF).
1800 * 1800 *
1801 * Some modifiers need to free some memory. 1801 * Some modifiers need to free some memory.
1802 */ 1802 */
1803 1803
1804typedef enum VarExprFlags { 1804typedef enum VarExprFlags {
1805 /* The variable expression is based on an undefined variable. */ 1805 /* The variable expression is based on an undefined variable. */
1806 VEF_UNDEF = 0x01, 1806 VEF_UNDEF = 0x01,
1807 /* The variable expression started as an undefined expression, but one 1807 /* The variable expression started as an undefined expression, but one
1808 * of the modifiers (such as :D or :U) has turned the expression from 1808 * of the modifiers (such as :D or :U) has turned the expression from
1809 * undefined to defined. */ 1809 * undefined to defined. */
1810 VEF_DEF = 0x02 1810 VEF_DEF = 0x02
1811} VarExprFlags; 1811} VarExprFlags;
1812 1812
1813ENUM_FLAGS_RTTI_2(VarExprFlags, 1813ENUM_FLAGS_RTTI_2(VarExprFlags,
1814 VEF_UNDEF, VEF_DEF); 1814 VEF_UNDEF, VEF_DEF);
1815 1815
1816 1816
1817typedef struct ApplyModifiersState { 1817typedef struct ApplyModifiersState {
1818 const char startc; /* '\0' or '{' or '(' */ 1818 const char startc; /* '\0' or '{' or '(' */
1819 const char endc; /* '\0' or '}' or ')' */ 1819 const char endc; /* '\0' or '}' or ')' */
1820 Var * const v; 1820 Var * const v;
1821 GNode * const ctxt; 1821 GNode * const ctxt;
1822 const VarEvalFlags eflags; 1822 const VarEvalFlags eflags;
1823 1823
1824 char *val; /* The old value of the expression, 1824 char *val; /* The old value of the expression,
1825 * before applying the modifier, never NULL */ 1825 * before applying the modifier, never NULL */
1826 char *newVal; /* The new value of the expression, 1826 char *newVal; /* The new value of the expression,
1827 * after applying the modifier, never NULL */ 1827 * after applying the modifier, never NULL */
1828 char sep; /* Word separator in expansions 1828 char sep; /* Word separator in expansions
1829 * (see the :ts modifier) */ 1829 * (see the :ts modifier) */
1830 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1830 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1831 * the variable value into words, like :S and 1831 * the variable value into words, like :S and
1832 * :C, treat the variable value as a single big 1832 * :C, treat the variable value as a single big
1833 * word, possibly containing spaces. */ 1833 * word, possibly containing spaces. */
1834 VarExprFlags exprFlags; 1834 VarExprFlags exprFlags;
1835} ApplyModifiersState; 1835} ApplyModifiersState;
1836 1836
1837static void 1837static void
1838ApplyModifiersState_Define(ApplyModifiersState *st) 1838ApplyModifiersState_Define(ApplyModifiersState *st)
1839{ 1839{
1840 if (st->exprFlags & VEF_UNDEF) 1840 if (st->exprFlags & VEF_UNDEF)
1841 st->exprFlags |= VEF_DEF; 1841 st->exprFlags |= VEF_DEF;
1842} 1842}
1843 1843
1844typedef enum ApplyModifierResult { 1844typedef enum ApplyModifierResult {
1845 AMR_OK, /* Continue parsing */ 1845 AMR_OK, /* Continue parsing */
1846 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1846 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1847 AMR_BAD, /* Error out with "Bad modifier" message */ 1847 AMR_BAD, /* Error out with "Bad modifier" message */
1848 AMR_CLEANUP /* Error out without error message */ 1848 AMR_CLEANUP /* Error out without error message */
1849} ApplyModifierResult; 1849} ApplyModifierResult;
1850 1850
1851/*- 1851/*-
1852 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ 1852 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
1853 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and 1853 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
1854 * including the next unescaped delimiter. The delimiter, as well as the 1854 * including the next unescaped delimiter. The delimiter, as well as the
1855 * backslash or the dollar, can be escaped with a backslash. 1855 * backslash or the dollar, can be escaped with a backslash.
1856 * 1856 *
1857 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1857 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1858 * was found. On successful return, the parsing position pp points right 1858 * was found. On successful return, the parsing position pp points right
1859 * after the delimiter. The delimiter is not included in the returned 1859 * after the delimiter. The delimiter is not included in the returned
1860 * value though. 1860 * value though.
1861 */ 1861 */
1862static VarParseResult 1862static VarParseResult
1863ParseModifierPart( 1863ParseModifierPart(
1864 const char **pp, /* The parsing position, updated upon return */ 1864 const char **pp, /* The parsing position, updated upon return */
1865 int delim, /* Parsing stops at this delimiter */ 1865 int delim, /* Parsing stops at this delimiter */
1866 VarEvalFlags eflags, /* Flags for evaluating nested variables; 1866 VarEvalFlags eflags, /* Flags for evaluating nested variables;
1867 * if VARE_WANTRES is not set, the text is 1867 * if VARE_WANTRES is not set, the text is
1868 * only parsed */ 1868 * only parsed */
1869 ApplyModifiersState *st, 1869 ApplyModifiersState *st,
1870 char **out_part, 1870 char **out_part,
1871 size_t *out_length, /* Optionally stores the length of the returned 1871 size_t *out_length, /* Optionally stores the length of the returned
1872 * string, just to save another strlen call. */ 1872 * string, just to save another strlen call. */
1873 VarPatternFlags *out_pflags,/* For the first part of the :S modifier, 1873 VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
1874 * sets the VARP_ANCHOR_END flag if the last 1874 * sets the VARP_ANCHOR_END flag if the last
1875 * character of the pattern is a $. */ 1875 * character of the pattern is a $. */
1876 struct ModifyWord_SubstArgs *subst 1876 struct ModifyWord_SubstArgs *subst
1877 /* For the second part of the :S modifier, 1877 /* For the second part of the :S modifier,
1878 * allow ampersands to be escaped and replace 1878 * allow ampersands to be escaped and replace
1879 * unescaped ampersands with subst->lhs. */ 1879 * unescaped ampersands with subst->lhs. */
1880) { 1880) {
1881 Buffer buf; 1881 Buffer buf;
1882 const char *p; 1882 const char *p;
1883 1883
1884 Buf_Init(&buf, 0); 1884 Buf_Init(&buf, 0);
1885 1885
1886 /* 1886 /*
1887 * Skim through until the matching delimiter is found; 1887 * Skim through until the matching delimiter is found;
1888 * pick up variable substitutions on the way. Also allow 1888 * pick up variable substitutions on the way. Also allow
1889 * backslashes to quote the delimiter, $, and \, but don't 1889 * backslashes to quote the delimiter, $, and \, but don't
1890 * touch other backslashes. 1890 * touch other backslashes.
1891 */ 1891 */
1892 p = *pp; 1892 p = *pp;
1893 while (*p != '\0' && *p != delim) { 1893 while (*p != '\0' && *p != delim) {
1894 const char *varstart; 1894 const char *varstart;
1895 1895
1896 Boolean is_escaped = p[0] == '\\' && ( 1896 Boolean is_escaped = p[0] == '\\' && (
1897 p[1] == delim || p[1] == '\\' || p[1] == '$' || 1897 p[1] == delim || p[1] == '\\' || p[1] == '$' ||
1898 (p[1] == '&' && subst != NULL)); 1898 (p[1] == '&' && subst != NULL));
1899 if (is_escaped) { 1899 if (is_escaped) {
1900 Buf_AddByte(&buf, p[1]); 1900 Buf_AddByte(&buf, p[1]);
1901 p += 2; 1901 p += 2;
1902 continue; 1902 continue;
1903 } 1903 }
1904 1904
1905 if (*p != '$') { /* Unescaped, simple text */ 1905 if (*p != '$') { /* Unescaped, simple text */
1906 if (subst != NULL && *p == '&') 1906 if (subst != NULL && *p == '&')
1907 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen); 1907 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
1908 else 1908 else
1909 Buf_AddByte(&buf, *p); 1909 Buf_AddByte(&buf, *p);
1910 p++; 1910 p++;
1911 continue; 1911 continue;
1912 } 1912 }
1913 1913
1914 if (p[1] == delim) { /* Unescaped $ at end of pattern */ 1914 if (p[1] == delim) { /* Unescaped $ at end of pattern */
1915 if (out_pflags != NULL) 1915 if (out_pflags != NULL)
1916 *out_pflags |= VARP_ANCHOR_END; 1916 *out_pflags |= VARP_ANCHOR_END;
1917 else 1917 else
1918 Buf_AddByte(&buf, *p); 1918 Buf_AddByte(&buf, *p);
1919 p++; 1919 p++;
1920 continue; 1920 continue;
1921 } 1921 }
1922 1922
1923 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */ 1923 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
1924 const char *nested_p = p; 1924 const char *nested_p = p;
1925 const char *nested_val; 1925 const char *nested_val;
1926 void *nested_val_freeIt; 1926 void *nested_val_freeIt;
1927 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN; 1927 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
1928 1928
1929 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags, 1929 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
1930 &nested_val, &nested_val_freeIt); 1930 &nested_val, &nested_val_freeIt);
1931 /* TODO: handle errors */ 1931 /* TODO: handle errors */
1932 Buf_AddStr(&buf, nested_val); 1932 Buf_AddStr(&buf, nested_val);
1933 free(nested_val_freeIt); 1933 free(nested_val_freeIt);
1934 p += nested_p - p; 1934 p += nested_p - p;
1935 continue; 1935 continue;
1936 } 1936 }
1937 1937
1938 /* XXX: This whole block is very similar to Var_Parse without 1938 /* XXX: This whole block is very similar to Var_Parse without
1939 * VARE_WANTRES. There may be subtle edge cases though that are 1939 * VARE_WANTRES. There may be subtle edge cases though that are
1940 * not yet covered in the unit tests and that are parsed differently, 1940 * not yet covered in the unit tests and that are parsed differently,
1941 * depending on whether they are evaluated or not. 1941 * depending on whether they are evaluated or not.
1942 * 1942 *
1943 * This subtle difference is not documented in the manual page, 1943 * This subtle difference is not documented in the manual page,
1944 * neither is the difference between parsing :D and :M documented. 1944 * neither is the difference between parsing :D and :M documented.
1945 * No code should ever depend on these details, but who knows. */ 1945 * No code should ever depend on these details, but who knows. */
1946 1946
1947 varstart = p; /* Nested variable, only parsed */ 1947 varstart = p; /* Nested variable, only parsed */
1948 if (p[1] == '(' || p[1] == '{') { 1948 if (p[1] == '(' || p[1] == '{') {
1949 /* 1949 /*
1950 * Find the end of this variable reference 1950 * Find the end of this variable reference
1951 * and suck it in without further ado. 1951 * and suck it in without further ado.
1952 * It will be interpreted later. 1952 * It will be interpreted later.
1953 */ 1953 */
1954 char have = p[1]; 1954 char have = p[1];
1955 int want = have == '(' ? ')' : '}'; 1955 int want = have == '(' ? ')' : '}';
1956 int depth = 1; 1956 int depth = 1;
1957 1957
1958 for (p += 2; *p != '\0' && depth > 0; p++) { 1958 for (p += 2; *p != '\0' && depth > 0; p++) {
1959 if (p[-1] != '\\') { 1959 if (p[-1] != '\\') {
1960 if (*p == have) 1960 if (*p == have)
1961 depth++; 1961 depth++;
1962 if (*p == want) 1962 if (*p == want)
1963 depth--; 1963 depth--;
1964 } 1964 }
1965 } 1965 }
1966 Buf_AddBytesBetween(&buf, varstart, p); 1966 Buf_AddBytesBetween(&buf, varstart, p);
1967 } else { 1967 } else {
1968 Buf_AddByte(&buf, *varstart); 1968 Buf_AddByte(&buf, *varstart);
1969 p++; 1969 p++;
1970 } 1970 }
1971 } 1971 }
1972 1972
1973 if (*p != delim) { 1973 if (*p != delim) {
1974 *pp = p; 1974 *pp = p;
1975 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim); 1975 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim);
1976 *out_part = NULL; 1976 *out_part = NULL;
1977 return VPR_PARSE_MSG; 1977 return VPR_PARSE_MSG;
1978 } 1978 }
1979 1979
1980 *pp = ++p; 1980 *pp = ++p;
1981 if (out_length != NULL) 1981 if (out_length != NULL)
1982 *out_length = Buf_Len(&buf); 1982 *out_length = Buf_Len(&buf);
1983 1983
1984 *out_part = Buf_Destroy(&buf, FALSE); 1984 *out_part = Buf_Destroy(&buf, FALSE);
1985 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part); 1985 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part);
1986 return VPR_OK; 1986 return VPR_OK;
1987} 1987}
1988 1988
1989/* Test whether mod starts with modname, followed by a delimiter. */ 1989/* Test whether mod starts with modname, followed by a delimiter. */
1990static Boolean 1990static Boolean
1991ModMatch(const char *mod, const char *modname, char endc) 1991ModMatch(const char *mod, const char *modname, char endc)
1992{ 1992{
1993 size_t n = strlen(modname); 1993 size_t n = strlen(modname);
1994 return strncmp(mod, modname, n) == 0 && 1994 return strncmp(mod, modname, n) == 0 &&
1995 (mod[n] == endc || mod[n] == ':'); 1995 (mod[n] == endc || mod[n] == ':');
1996} 1996}
1997 1997
1998/* Test whether mod starts with modname, followed by a delimiter or '='. */ 1998/* Test whether mod starts with modname, followed by a delimiter or '='. */
1999static inline Boolean 1999static inline Boolean
2000ModMatchEq(const char *mod, const char *modname, char endc) 2000ModMatchEq(const char *mod, const char *modname, char endc)
2001{ 2001{
2002 size_t n = strlen(modname); 2002 size_t n = strlen(modname);
2003 return strncmp(mod, modname, n) == 0 && 2003 return strncmp(mod, modname, n) == 0 &&
2004 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2004 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2005} 2005}
2006 2006
2007/* :@var@...${var}...@ */ 2007/* :@var@...${var}...@ */
2008static ApplyModifierResult 2008static ApplyModifierResult
2009ApplyModifier_Loop(const char **pp, ApplyModifiersState *st) 2009ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
2010{ 2010{
2011 struct ModifyWord_LoopArgs args; 2011 struct ModifyWord_LoopArgs args;
2012 char prev_sep; 2012 char prev_sep;
2013 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2013 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2014 VarParseResult res; 2014 VarParseResult res;
2015 2015
2016 args.ctx = st->ctxt; 2016 args.ctx = st->ctxt;
2017 2017
2018 (*pp)++; /* Skip the first '@' */ 2018 (*pp)++; /* Skip the first '@' */
2019 res = ParseModifierPart(pp, '@', eflags, st, 2019 res = ParseModifierPart(pp, '@', eflags, st,
2020 &args.tvar, NULL, NULL, NULL); 2020 &args.tvar, NULL, NULL, NULL);
2021 if (res != VPR_OK) 2021 if (res != VPR_OK)
2022 return AMR_CLEANUP; 2022 return AMR_CLEANUP;
2023 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) { 2023 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) {
2024 Parse_Error(PARSE_FATAL, 2024 Parse_Error(PARSE_FATAL,
2025 "In the :@ modifier of \"%s\", the variable name \"%s\" " 2025 "In the :@ modifier of \"%s\", the variable name \"%s\" "
2026 "must not contain a dollar.", 2026 "must not contain a dollar.",
2027 st->v->name, args.tvar); 2027 st->v->name, args.tvar);
2028 return AMR_CLEANUP; 2028 return AMR_CLEANUP;
2029 } 2029 }
2030 2030
2031 res = ParseModifierPart(pp, '@', eflags, st, 2031 res = ParseModifierPart(pp, '@', eflags, st,
2032 &args.str, NULL, NULL, NULL); 2032 &args.str, NULL, NULL, NULL);
2033 if (res != VPR_OK) 2033 if (res != VPR_OK)
2034 return AMR_CLEANUP; 2034 return AMR_CLEANUP;
2035 2035
2036 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2036 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2037 prev_sep = st->sep; 2037 prev_sep = st->sep;
2038 st->sep = ' '; /* XXX: should be st->sep for consistency */ 2038 st->sep = ' '; /* XXX: should be st->sep for consistency */
2039 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2039 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2040 ModifyWord_Loop, &args); 2040 ModifyWord_Loop, &args);
2041 st->sep = prev_sep; 2041 st->sep = prev_sep;
2042 Var_Delete(args.tvar, st->ctxt); 2042 Var_Delete(args.tvar, st->ctxt);
2043 free(args.tvar); 2043 free(args.tvar);
2044 free(args.str); 2044 free(args.str);
2045 return AMR_OK; 2045 return AMR_OK;
2046} 2046}
2047 2047
2048/* :Ddefined or :Uundefined */ 2048/* :Ddefined or :Uundefined */
2049static ApplyModifierResult 2049static ApplyModifierResult
2050ApplyModifier_Defined(const char **pp, ApplyModifiersState *st) 2050ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
2051{ 2051{
2052 Buffer buf; 2052 Buffer buf;
2053 const char *p; 2053 const char *p;
2054 2054
2055 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2055 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2056 if (st->eflags & VARE_WANTRES) { 2056 if (st->eflags & VARE_WANTRES) {
2057 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF)) 2057 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
2058 eflags |= VARE_WANTRES; 2058 eflags |= VARE_WANTRES;
2059 } 2059 }
2060 2060
2061 Buf_Init(&buf, 0); 2061 Buf_Init(&buf, 0);
2062 p = *pp + 1; 2062 p = *pp + 1;
2063 while (*p != st->endc && *p != ':' && *p != '\0') { 2063 while (*p != st->endc && *p != ':' && *p != '\0') {
2064 2064
2065 /* Escaped delimiter or other special character */ 2065 /* Escaped delimiter or other special character */
2066 if (*p == '\\') { 2066 if (*p == '\\') {
2067 char c = p[1]; 2067 char c = p[1];
2068 if (c == st->endc || c == ':' || c == '$' || c == '\\') { 2068 if (c == st->endc || c == ':' || c == '$' || c == '\\') {
2069 Buf_AddByte(&buf, c); 2069 Buf_AddByte(&buf, c);
2070 p += 2; 2070 p += 2;
2071 continue; 2071 continue;
2072 } 2072 }
2073 } 2073 }
2074 2074
2075 /* Nested variable expression */ 2075 /* Nested variable expression */
2076 if (*p == '$') { 2076 if (*p == '$') {
2077 const char *nested_val; 2077 const char *nested_val;
2078 void *nested_val_freeIt; 2078 void *nested_val_freeIt;
2079 2079
2080 (void)Var_Parse(&p, st->ctxt, eflags, 2080 (void)Var_Parse(&p, st->ctxt, eflags,
2081 &nested_val, &nested_val_freeIt); 2081 &nested_val, &nested_val_freeIt);
2082 /* TODO: handle errors */ 2082 /* TODO: handle errors */
2083 Buf_AddStr(&buf, nested_val); 2083 Buf_AddStr(&buf, nested_val);
2084 free(nested_val_freeIt); 2084 free(nested_val_freeIt);
2085 continue; 2085 continue;
2086 } 2086 }
2087 2087
2088 /* Ordinary text */ 2088 /* Ordinary text */
2089 Buf_AddByte(&buf, *p); 2089 Buf_AddByte(&buf, *p);
2090 p++; 2090 p++;
2091 } 2091 }
2092 *pp = p; 2092 *pp = p;
2093 2093
2094 ApplyModifiersState_Define(st); 2094 ApplyModifiersState_Define(st);
2095 2095
2096 if (eflags & VARE_WANTRES) { 2096 if (eflags & VARE_WANTRES) {
2097 st->newVal = Buf_Destroy(&buf, FALSE); 2097 st->newVal = Buf_Destroy(&buf, FALSE);
2098 } else { 2098 } else {
2099 st->newVal = st->val; 2099 st->newVal = st->val;
2100 Buf_Destroy(&buf, TRUE); 2100 Buf_Destroy(&buf, TRUE);
2101 } 2101 }
2102 return AMR_OK; 2102 return AMR_OK;
2103} 2103}
2104 2104
2105/* :L */ 2105/* :L */
2106static ApplyModifierResult 2106static ApplyModifierResult
2107ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) 2107ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2108{ 2108{
2109 ApplyModifiersState_Define(st); 2109 ApplyModifiersState_Define(st);
2110 st->newVal = bmake_strdup(st->v->name); 2110 st->newVal = bmake_strdup(st->v->name);
2111 (*pp)++; 2111 (*pp)++;
2112 return AMR_OK; 2112 return AMR_OK;
2113} 2113}
2114 2114
2115/* :gmtime */ 2115/* :gmtime */
2116static ApplyModifierResult 2116static ApplyModifierResult
2117ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st) 2117ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
2118{ 2118{
2119 time_t utc; 2119 time_t utc;
2120 2120
2121 const char *mod = *pp; 2121 const char *mod = *pp;
2122 if (!ModMatchEq(mod, "gmtime", st->endc)) 2122 if (!ModMatchEq(mod, "gmtime", st->endc))
2123 return AMR_UNKNOWN; 2123 return AMR_UNKNOWN;
2124 2124
2125 if (mod[6] == '=') { 2125 if (mod[6] == '=') {
2126 char *ep; 2126 char *ep;
2127 utc = (time_t)strtoul(mod + 7, &ep, 10); 2127 utc = (time_t)strtoul(mod + 7, &ep, 10);
2128 *pp = ep; 2128 *pp = ep;
2129 } else { 2129 } else {
2130 utc = 0; 2130 utc = 0;
2131 *pp = mod + 6; 2131 *pp = mod + 6;
2132 } 2132 }
2133 st->newVal = VarStrftime(st->val, TRUE, utc); 2133 st->newVal = VarStrftime(st->val, TRUE, utc);
2134 return AMR_OK; 2134 return AMR_OK;
2135} 2135}
2136 2136
2137/* :localtime */ 2137/* :localtime */
2138static ApplyModifierResult 2138static ApplyModifierResult
2139ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) 2139ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
2140{ 2140{
2141 time_t utc; 2141 time_t utc;
2142 2142
2143 const char *mod = *pp; 2143 const char *mod = *pp;
2144 if (!ModMatchEq(mod, "localtime", st->endc)) 2144 if (!ModMatchEq(mod, "localtime", st->endc))
2145 return AMR_UNKNOWN; 2145 return AMR_UNKNOWN;
2146 2146
2147 if (mod[9] == '=') { 2147 if (mod[9] == '=') {
2148 char *ep; 2148 char *ep;
2149 utc = (time_t)strtoul(mod + 10, &ep, 10); 2149 utc = (time_t)strtoul(mod + 10, &ep, 10);
2150 *pp = ep; 2150 *pp = ep;
2151 } else { 2151 } else {
2152 utc = 0; 2152 utc = 0;
2153 *pp = mod + 9; 2153 *pp = mod + 9;
2154 } 2154 }
2155 st->newVal = VarStrftime(st->val, FALSE, utc); 2155 st->newVal = VarStrftime(st->val, FALSE, utc);
2156 return AMR_OK; 2156 return AMR_OK;
2157} 2157}
2158 2158
2159/* :hash */ 2159/* :hash */
2160static ApplyModifierResult 2160static ApplyModifierResult
2161ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) 2161ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
2162{ 2162{
2163 if (!ModMatch(*pp, "hash", st->endc)) 2163 if (!ModMatch(*pp, "hash", st->endc))
2164 return AMR_UNKNOWN; 2164 return AMR_UNKNOWN;
2165 2165
2166 st->newVal = VarHash(st->val); 2166 st->newVal = VarHash(st->val);
2167 *pp += 4; 2167 *pp += 4;
2168 return AMR_OK; 2168 return AMR_OK;
2169} 2169}
2170 2170
2171/* :P */ 2171/* :P */
2172static ApplyModifierResult 2172static ApplyModifierResult
2173ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2173ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2174{ 2174{
2175 GNode *gn; 2175 GNode *gn;
2176 char *path; 2176 char *path;
2177 2177
2178 ApplyModifiersState_Define(st); 2178 ApplyModifiersState_Define(st);
2179 2179
2180 gn = Targ_FindNode(st->v->name); 2180 gn = Targ_FindNode(st->v->name);
2181 if (gn == NULL || gn->type & OP_NOPATH) { 2181 if (gn == NULL || gn->type & OP_NOPATH) {
2182 path = NULL; 2182 path = NULL;
2183 } else if (gn->path != NULL) { 2183 } else if (gn->path != NULL) {
2184 path = bmake_strdup(gn->path); 2184 path = bmake_strdup(gn->path);
2185 } else { 2185 } else {
2186 SearchPath *searchPath = Suff_FindPath(gn); 2186 SearchPath *searchPath = Suff_FindPath(gn);
2187 path = Dir_FindFile(st->v->name, searchPath); 2187 path = Dir_FindFile(st->v->name, searchPath);
2188 } 2188 }
2189 if (path == NULL) 2189 if (path == NULL)
2190 path = bmake_strdup(st->v->name); 2190 path = bmake_strdup(st->v->name);
2191 st->newVal = path; 2191 st->newVal = path;
2192 2192
2193 (*pp)++; 2193 (*pp)++;
2194 return AMR_OK; 2194 return AMR_OK;
2195} 2195}
2196 2196
2197/* :!cmd! */ 2197/* :!cmd! */
2198static ApplyModifierResult 2198static ApplyModifierResult
2199ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2199ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2200{ 2200{
2201 char *cmd; 2201 char *cmd;
2202 const char *errfmt; 2202 const char *errfmt;
2203 VarParseResult res; 2203 VarParseResult res;
2204 2204
2205 (*pp)++; 2205 (*pp)++;
2206 res = ParseModifierPart(pp, '!', st->eflags, st, 2206 res = ParseModifierPart(pp, '!', st->eflags, st,
2207 &cmd, NULL, NULL, NULL); 2207 &cmd, NULL, NULL, NULL);
2208 if (res != VPR_OK) 2208 if (res != VPR_OK)
2209 return AMR_CLEANUP; 2209 return AMR_CLEANUP;
2210 2210
2211 errfmt = NULL; 2211 errfmt = NULL;
2212 if (st->eflags & VARE_WANTRES) 2212 if (st->eflags & VARE_WANTRES)
2213 st->newVal = Cmd_Exec(cmd, &errfmt); 2213 st->newVal = Cmd_Exec(cmd, &errfmt);
2214 else 2214 else
2215 st->newVal = emptyString; 2215 st->newVal = emptyString;
2216 free(cmd); 2216 free(cmd);
2217 2217
2218 if (errfmt != NULL) 2218 if (errfmt != NULL)
2219 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2219 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2220 2220
2221 ApplyModifiersState_Define(st); 2221 ApplyModifiersState_Define(st);
2222 return AMR_OK; 2222 return AMR_OK;
2223} 2223}
2224 2224
2225/* The :range modifier generates an integer sequence as long as the words. 2225/* The :range modifier generates an integer sequence as long as the words.
2226 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2226 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2227static ApplyModifierResult 2227static ApplyModifierResult
2228ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2228ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2229{ 2229{
2230 size_t n; 2230 size_t n;
2231 Buffer buf; 2231 Buffer buf;
2232 size_t i; 2232 size_t i;
2233 2233
2234 const char *mod = *pp; 2234 const char *mod = *pp;
2235 if (!ModMatchEq(mod, "range", st->endc)) 2235 if (!ModMatchEq(mod, "range", st->endc))
2236 return AMR_UNKNOWN; 2236 return AMR_UNKNOWN;
2237 2237
2238 if (mod[5] == '=') { 2238 if (mod[5] == '=') {
2239 char *ep; 2239 char *ep;
2240 n = (size_t)strtoul(mod + 6, &ep, 10); 2240 n = (size_t)strtoul(mod + 6, &ep, 10);
2241 *pp = ep; 2241 *pp = ep;
2242 } else { 2242 } else {
2243 n = 0; 2243 n = 0;
2244 *pp = mod + 5; 2244 *pp = mod + 5;
2245 } 2245 }
2246 2246
2247 if (n == 0) { 2247 if (n == 0) {
2248 Words words = Str_Words(st->val, FALSE); 2248 Words words = Str_Words(st->val, FALSE);
2249 n = words.len; 2249 n = words.len;
2250 Words_Free(words); 2250 Words_Free(words);
2251 } 2251 }
2252 2252
2253 Buf_Init(&buf, 0); 2253 Buf_Init(&buf, 0);
2254 2254
2255 for (i = 0; i < n; i++) { 2255 for (i = 0; i < n; i++) {
2256 if (i != 0) 2256 if (i != 0)
2257 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2257 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2258 Buf_AddInt(&buf, 1 + (int)i); 2258 Buf_AddInt(&buf, 1 + (int)i);
2259 } 2259 }
2260 2260
2261 st->newVal = Buf_Destroy(&buf, FALSE); 2261 st->newVal = Buf_Destroy(&buf, FALSE);
2262 return AMR_OK; 2262 return AMR_OK;
2263} 2263}
2264 2264
2265/* :Mpattern or :Npattern */ 2265/* :Mpattern or :Npattern */
2266static ApplyModifierResult 2266static ApplyModifierResult
2267ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2267ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2268{ 2268{
2269 const char *mod = *pp; 2269 const char *mod = *pp;
2270 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2270 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2271 Boolean needSubst = FALSE; 2271 Boolean needSubst = FALSE;
2272 const char *endpat; 2272 const char *endpat;
2273 char *pattern; 2273 char *pattern;
2274 ModifyWordsCallback callback; 2274 ModifyWordsCallback callback;
2275 2275
2276 /* 2276 /*
2277 * In the loop below, ignore ':' unless we are at (or back to) the 2277 * In the loop below, ignore ':' unless we are at (or back to) the
2278 * original brace level. 2278 * original brace level.
2279 * XXX This will likely not work right if $() and ${} are intermixed. 2279 * XXX This will likely not work right if $() and ${} are intermixed.
2280 */ 2280 */
2281 int nest = 0; 2281 int nest = 0;
2282 const char *p; 2282 const char *p;
2283 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2283 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2284 if (*p == '\\' && 2284 if (*p == '\\' &&
2285 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2285 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2286 if (!needSubst) 2286 if (!needSubst)
2287 copy = TRUE; 2287 copy = TRUE;
2288 p++; 2288 p++;
2289 continue; 2289 continue;
2290 } 2290 }
2291 if (*p == '$') 2291 if (*p == '$')
2292 needSubst = TRUE; 2292 needSubst = TRUE;
2293 if (*p == '(' || *p == '{') 2293 if (*p == '(' || *p == '{')
2294 nest++; 2294 nest++;
2295 if (*p == ')' || *p == '}') { 2295 if (*p == ')' || *p == '}') {
2296 nest--; 2296 nest--;
2297 if (nest < 0) 2297 if (nest < 0)
2298 break; 2298 break;
2299 } 2299 }
2300 } 2300 }
2301 *pp = p; 2301 *pp = p;
2302 endpat = p; 2302 endpat = p;
2303 2303
2304 if (copy) { 2304 if (copy) {
2305 char *dst; 2305 char *dst;
2306 const char *src; 2306 const char *src;
2307 2307
2308 /* Compress the \:'s out of the pattern. */ 2308 /* Compress the \:'s out of the pattern. */
2309 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2309 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2310 dst = pattern; 2310 dst = pattern;
2311 src = mod + 1; 2311 src = mod + 1;
2312 for (; src < endpat; src++, dst++) { 2312 for (; src < endpat; src++, dst++) {
2313 if (src[0] == '\\' && src + 1 < endpat && 2313 if (src[0] == '\\' && src + 1 < endpat &&
2314 /* XXX: st->startc is missing here; see above */ 2314 /* XXX: st->startc is missing here; see above */
2315 (src[1] == ':' || src[1] == st->endc)) 2315 (src[1] == ':' || src[1] == st->endc))
2316 src++; 2316 src++;
2317 *dst = *src; 2317 *dst = *src;
2318 } 2318 }
2319 *dst = '\0'; 2319 *dst = '\0';
2320 endpat = dst; 2320 endpat = dst;
2321 } else { 2321 } else {
2322 pattern = bmake_strsedup(mod + 1, endpat); 2322 pattern = bmake_strsedup(mod + 1, endpat);
2323 } 2323 }
2324 2324
2325 if (needSubst) { 2325 if (needSubst) {
2326 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2326 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2327 char *old_pattern = pattern; 2327 char *old_pattern = pattern;
2328 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2328 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2329 /* TODO: handle errors */ 2329 /* TODO: handle errors */
2330 free(old_pattern); 2330 free(old_pattern);
2331 } 2331 }
2332 2332
2333 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2333 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2334 2334
2335 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2335 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2336 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2336 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2337 callback, pattern); 2337 callback, pattern);
2338 free(pattern); 2338 free(pattern);
2339 return AMR_OK; 2339 return AMR_OK;
2340} 2340}
2341 2341
2342/* :S,from,to, */ 2342/* :S,from,to, */
2343static ApplyModifierResult 2343static ApplyModifierResult
2344ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2344ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2345{ 2345{
2346 struct ModifyWord_SubstArgs args; 2346 struct ModifyWord_SubstArgs args;
2347 char *lhs, *rhs; 2347 char *lhs, *rhs;
2348 Boolean oneBigWord; 2348 Boolean oneBigWord;
2349 VarParseResult res; 2349 VarParseResult res;
2350 2350
2351 char delim = (*pp)[1]; 2351 char delim = (*pp)[1];
2352 if (delim == '\0') { 2352 if (delim == '\0') {
2353 Error("Missing delimiter for :S modifier"); 2353 Error("Missing delimiter for :S modifier");
2354 (*pp)++; 2354 (*pp)++;
2355 return AMR_CLEANUP; 2355 return AMR_CLEANUP;
2356 } 2356 }
2357 2357
2358 *pp += 2; 2358 *pp += 2;
2359 2359
2360 args.pflags = 0; 2360 args.pflags = 0;
2361 args.matched = FALSE; 2361 args.matched = FALSE;
2362 2362
2363 /* 2363 /*
2364 * If pattern begins with '^', it is anchored to the 2364 * If pattern begins with '^', it is anchored to the
2365 * start of the word -- skip over it and flag pattern. 2365 * start of the word -- skip over it and flag pattern.
2366 */ 2366 */
2367 if (**pp == '^') { 2367 if (**pp == '^') {
2368 args.pflags |= VARP_ANCHOR_START; 2368 args.pflags |= VARP_ANCHOR_START;
2369 (*pp)++; 2369 (*pp)++;
2370 } 2370 }
2371 2371
2372 res = ParseModifierPart(pp, delim, st->eflags, st, 2372 res = ParseModifierPart(pp, delim, st->eflags, st,
2373 &lhs, &args.lhsLen, &args.pflags, NULL); 2373 &lhs, &args.lhsLen, &args.pflags, NULL);
2374 if (res != VPR_OK) 2374 if (res != VPR_OK)
2375 return AMR_CLEANUP; 2375 return AMR_CLEANUP;
2376 args.lhs = lhs; 2376 args.lhs = lhs;
2377 2377
2378 res = ParseModifierPart(pp, delim, st->eflags, st, 2378 res = ParseModifierPart(pp, delim, st->eflags, st,
2379 &rhs, &args.rhsLen, NULL, &args); 2379 &rhs, &args.rhsLen, NULL, &args);
2380 if (res != VPR_OK) 2380 if (res != VPR_OK)
2381 return AMR_CLEANUP; 2381 return AMR_CLEANUP;
2382 args.rhs = rhs; 2382 args.rhs = rhs;
2383 2383
2384 oneBigWord = st->oneBigWord; 2384 oneBigWord = st->oneBigWord;
2385 for (;; (*pp)++) { 2385 for (;; (*pp)++) {
2386 switch (**pp) { 2386 switch (**pp) {
2387 case 'g': 2387 case 'g':
2388 args.pflags |= VARP_SUB_GLOBAL; 2388 args.pflags |= VARP_SUB_GLOBAL;
2389 continue; 2389 continue;
2390 case '1': 2390 case '1':
2391 args.pflags |= VARP_SUB_ONE; 2391 args.pflags |= VARP_SUB_ONE;
2392 continue; 2392 continue;
2393 case 'W': 2393 case 'W':
2394 oneBigWord = TRUE; 2394 oneBigWord = TRUE;
2395 continue; 2395 continue;
2396 } 2396 }
2397 break; 2397 break;
2398 } 2398 }
2399 2399
2400 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val, 2400 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val,
2401 ModifyWord_Subst, &args); 2401 ModifyWord_Subst, &args);
2402 2402
2403 free(lhs); 2403 free(lhs);
2404 free(rhs); 2404 free(rhs);
2405 return AMR_OK; 2405 return AMR_OK;
2406} 2406}
2407 2407
2408#ifndef NO_REGEX 2408#ifndef NO_REGEX
2409 2409
2410/* :C,from,to, */ 2410/* :C,from,to, */