Sat Oct 31 08:40:54 2020 UTC ()
make(1): merge duplicate code in ModifyWord_Subst


(rillig)
diff -r1.610 -r1.611 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/30 22:55:34 1.610
+++ src/usr.bin/make/var.c 2020/10/31 08:40:54 1.611
@@ -1,2308 +1,2302 @@ @@ -1,2308 +1,2302 @@
1/* $NetBSD: var.c,v 1.610 2020/10/30 22:55:34 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.611 2020/10/31 08:40:54 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.610 2020/10/30 22:55:34 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.611 2020/10/31 08:40:54 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 ? val : "", 1); 856 setenv(name, val ? 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 1035
1036/* SepBuf is a string being built from words, interleaved with separators. */ 1036/* SepBuf is a string being built from words, interleaved with separators. */
1037typedef struct SepBuf { 1037typedef struct SepBuf {
1038 Buffer buf; 1038 Buffer buf;
1039 Boolean needSep; 1039 Boolean needSep;
1040 char sep; /* usually ' ', but see the :ts modifier */ 1040 char sep; /* usually ' ', but see the :ts modifier */
1041} SepBuf; 1041} SepBuf;
1042 1042
1043static void 1043static void
1044SepBuf_Init(SepBuf *buf, char sep) 1044SepBuf_Init(SepBuf *buf, char sep)
1045{ 1045{
1046 Buf_Init(&buf->buf, 32 /* bytes */); 1046 Buf_Init(&buf->buf, 32 /* bytes */);
1047 buf->needSep = FALSE; 1047 buf->needSep = FALSE;
1048 buf->sep = sep; 1048 buf->sep = sep;
1049} 1049}
1050 1050
1051static void 1051static void
1052SepBuf_Sep(SepBuf *buf) 1052SepBuf_Sep(SepBuf *buf)
1053{ 1053{
1054 buf->needSep = TRUE; 1054 buf->needSep = TRUE;
1055} 1055}
1056 1056
1057static void 1057static void
1058SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1058SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1059{ 1059{
1060 if (mem_size == 0) 1060 if (mem_size == 0)
1061 return; 1061 return;
1062 if (buf->needSep && buf->sep != '\0') { 1062 if (buf->needSep && buf->sep != '\0') {
1063 Buf_AddByte(&buf->buf, buf->sep); 1063 Buf_AddByte(&buf->buf, buf->sep);
1064 buf->needSep = FALSE; 1064 buf->needSep = FALSE;
1065 } 1065 }
1066 Buf_AddBytes(&buf->buf, mem, mem_size); 1066 Buf_AddBytes(&buf->buf, mem, mem_size);
1067} 1067}
1068 1068
1069static void 1069static void
1070SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1070SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1071{ 1071{
1072 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1072 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1073} 1073}
1074 1074
1075static void 1075static void
1076SepBuf_AddStr(SepBuf *buf, const char *str) 1076SepBuf_AddStr(SepBuf *buf, const char *str)
1077{ 1077{
1078 SepBuf_AddBytes(buf, str, strlen(str)); 1078 SepBuf_AddBytes(buf, str, strlen(str));
1079} 1079}
1080 1080
1081static char * 1081static char *
1082SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1082SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1083{ 1083{
1084 return Buf_Destroy(&buf->buf, free_buf); 1084 return Buf_Destroy(&buf->buf, free_buf);
1085} 1085}
1086 1086
1087 1087
1088/* This callback for ModifyWords gets a single word from a variable expression 1088/* This callback for ModifyWords gets a single word from a variable expression
1089 * and typically adds a modification of this word to the buffer. It may also 1089 * and typically adds a modification of this word to the buffer. It may also
1090 * do nothing or add several words. 1090 * do nothing or add several words.
1091 * 1091 *
1092 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for 1092 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1093 * each word of "a b c". */ 1093 * each word of "a b c". */
1094typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1094typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1095 1095
1096 1096
1097/* Callback for ModifyWords to implement the :H modifier. 1097/* Callback for ModifyWords to implement the :H modifier.
1098 * Add the dirname of the given word to the buffer. */ 1098 * Add the dirname of the given word to the buffer. */
1099static void 1099static void
1100ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1100ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1101{ 1101{
1102 const char *slash = strrchr(word, '/'); 1102 const char *slash = strrchr(word, '/');
1103 if (slash != NULL) 1103 if (slash != NULL)
1104 SepBuf_AddBytesBetween(buf, word, slash); 1104 SepBuf_AddBytesBetween(buf, word, slash);
1105 else 1105 else
1106 SepBuf_AddStr(buf, "."); 1106 SepBuf_AddStr(buf, ".");
1107} 1107}
1108 1108
1109/* Callback for ModifyWords to implement the :T modifier. 1109/* Callback for ModifyWords to implement the :T modifier.
1110 * Add the basename of the given word to the buffer. */ 1110 * Add the basename of the given word to the buffer. */
1111static void 1111static void
1112ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1112ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1113{ 1113{
1114 const char *slash = strrchr(word, '/'); 1114 const char *slash = strrchr(word, '/');
1115 const char *base = slash != NULL ? slash + 1 : word; 1115 const char *base = slash != NULL ? slash + 1 : word;
1116 SepBuf_AddStr(buf, base); 1116 SepBuf_AddStr(buf, base);
1117} 1117}
1118 1118
1119/* Callback for ModifyWords to implement the :E modifier. 1119/* Callback for ModifyWords to implement the :E modifier.
1120 * Add the filename suffix of the given word to the buffer, if it exists. */ 1120 * Add the filename suffix of the given word to the buffer, if it exists. */
1121static void 1121static void
1122ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1122ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1123{ 1123{
1124 const char *dot = strrchr(word, '.'); 1124 const char *dot = strrchr(word, '.');
1125 if (dot != NULL) 1125 if (dot != NULL)
1126 SepBuf_AddStr(buf, dot + 1); 1126 SepBuf_AddStr(buf, dot + 1);
1127} 1127}
1128 1128
1129/* Callback for ModifyWords to implement the :R modifier. 1129/* Callback for ModifyWords to implement the :R modifier.
1130 * Add the basename of the given word to the buffer. */ 1130 * Add the basename of the given word to the buffer. */
1131static void 1131static void
1132ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1132ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1133{ 1133{
1134 const char *dot = strrchr(word, '.'); 1134 const char *dot = strrchr(word, '.');
1135 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1135 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1136 SepBuf_AddBytes(buf, word, len); 1136 SepBuf_AddBytes(buf, word, len);
1137} 1137}
1138 1138
1139/* Callback for ModifyWords to implement the :M modifier. 1139/* Callback for ModifyWords to implement the :M modifier.
1140 * Place the word in the buffer if it matches the given pattern. */ 1140 * Place the word in the buffer if it matches the given pattern. */
1141static void 1141static void
1142ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1142ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1143{ 1143{
1144 const char *pattern = data; 1144 const char *pattern = data;
1145 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1145 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1146 if (Str_Match(word, pattern)) 1146 if (Str_Match(word, pattern))
1147 SepBuf_AddStr(buf, word); 1147 SepBuf_AddStr(buf, word);
1148} 1148}
1149 1149
1150/* Callback for ModifyWords to implement the :N modifier. 1150/* Callback for ModifyWords to implement the :N modifier.
1151 * Place the word in the buffer if it doesn't match the given pattern. */ 1151 * Place the word in the buffer if it doesn't match the given pattern. */
1152static void 1152static void
1153ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1153ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1154{ 1154{
1155 const char *pattern = data; 1155 const char *pattern = data;
1156 if (!Str_Match(word, pattern)) 1156 if (!Str_Match(word, pattern))
1157 SepBuf_AddStr(buf, word); 1157 SepBuf_AddStr(buf, word);
1158} 1158}
1159 1159
1160#ifdef SYSVVARSUB 1160#ifdef SYSVVARSUB
1161/* Check word against pattern for a match (% is a wildcard). 1161/* Check word against pattern for a match (% is a wildcard).
1162 * 1162 *
1163 * Input: 1163 * Input:
1164 * word Word to examine 1164 * word Word to examine
1165 * pattern Pattern to examine against 1165 * pattern Pattern to examine against
1166 * 1166 *
1167 * Results: 1167 * Results:
1168 * Returns the start of the match, or NULL. 1168 * Returns the start of the match, or NULL.
1169 * out_match_len returns the length of the match, if any. 1169 * out_match_len returns the length of the match, if any.
1170 * out_hasPercent returns whether the pattern contains a percent. 1170 * out_hasPercent returns whether the pattern contains a percent.
1171 */ 1171 */
1172static const char * 1172static const char *
1173SysVMatch(const char *word, const char *pattern, 1173SysVMatch(const char *word, const char *pattern,
1174 size_t *out_match_len, Boolean *out_hasPercent) 1174 size_t *out_match_len, Boolean *out_hasPercent)
1175{ 1175{
1176 const char *p = pattern; 1176 const char *p = pattern;
1177 const char *w = word; 1177 const char *w = word;
1178 const char *percent; 1178 const char *percent;
1179 size_t w_len; 1179 size_t w_len;
1180 size_t p_len; 1180 size_t p_len;
1181 const char *w_tail; 1181 const char *w_tail;
1182 1182
1183 *out_hasPercent = FALSE; 1183 *out_hasPercent = FALSE;
1184 if (*p == '\0') { /* ${VAR:=suffix} */ 1184 if (*p == '\0') { /* ${VAR:=suffix} */
1185 *out_match_len = strlen(w); /* Null pattern is the whole string */ 1185 *out_match_len = strlen(w); /* Null pattern is the whole string */
1186 return w; 1186 return w;
1187 } 1187 }
1188 1188
1189 percent = strchr(p, '%'); 1189 percent = strchr(p, '%');
1190 if (percent != NULL) { /* ${VAR:...%...=...} */ 1190 if (percent != NULL) { /* ${VAR:...%...=...} */
1191 *out_hasPercent = TRUE; 1191 *out_hasPercent = TRUE;
1192 if (*w == '\0') 1192 if (*w == '\0')
1193 return NULL; /* empty word does not match pattern */ 1193 return NULL; /* empty word does not match pattern */
1194 1194
1195 /* check that the prefix matches */ 1195 /* check that the prefix matches */
1196 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1196 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1197 continue; 1197 continue;
1198 if (p != percent) 1198 if (p != percent)
1199 return NULL; /* No match */ 1199 return NULL; /* No match */
1200 1200
1201 p++; /* Skip the percent */ 1201 p++; /* Skip the percent */
1202 if (*p == '\0') { 1202 if (*p == '\0') {
1203 /* No more pattern, return the rest of the string */ 1203 /* No more pattern, return the rest of the string */
1204 *out_match_len = strlen(w); 1204 *out_match_len = strlen(w);
1205 return w; 1205 return w;
1206 } 1206 }
1207 } 1207 }
1208 1208
1209 /* Test whether the tail matches */ 1209 /* Test whether the tail matches */
1210 w_len = strlen(w); 1210 w_len = strlen(w);
1211 p_len = strlen(p); 1211 p_len = strlen(p);
1212 if (w_len < p_len) 1212 if (w_len < p_len)
1213 return NULL; 1213 return NULL;
1214 1214
1215 w_tail = w + w_len - p_len; 1215 w_tail = w + w_len - p_len;
1216 if (memcmp(p, w_tail, p_len) != 0) 1216 if (memcmp(p, w_tail, p_len) != 0)
1217 return NULL; 1217 return NULL;
1218 1218
1219 *out_match_len = (size_t)(w_tail - w); 1219 *out_match_len = (size_t)(w_tail - w);
1220 return w; 1220 return w;
1221} 1221}
1222 1222
1223struct ModifyWord_SYSVSubstArgs { 1223struct ModifyWord_SYSVSubstArgs {
1224 GNode *ctx; 1224 GNode *ctx;
1225 const char *lhs; 1225 const char *lhs;
1226 const char *rhs; 1226 const char *rhs;
1227}; 1227};
1228 1228
1229/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1229/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1230static void 1230static void
1231ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1231ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1232{ 1232{
1233 const struct ModifyWord_SYSVSubstArgs *args = data; 1233 const struct ModifyWord_SYSVSubstArgs *args = data;
1234 char *rhs_expanded; 1234 char *rhs_expanded;
1235 const char *rhs; 1235 const char *rhs;
1236 const char *percent; 1236 const char *percent;
1237 1237
1238 size_t match_len; 1238 size_t match_len;
1239 Boolean lhsPercent; 1239 Boolean lhsPercent;
1240 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent); 1240 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
1241 if (match == NULL) { 1241 if (match == NULL) {
1242 SepBuf_AddStr(buf, word); 1242 SepBuf_AddStr(buf, word);
1243 return; 1243 return;
1244 } 1244 }
1245 1245
1246 /* Append rhs to the buffer, substituting the first '%' with the 1246 /* Append rhs to the buffer, substituting the first '%' with the
1247 * match, but only if the lhs had a '%' as well. */ 1247 * match, but only if the lhs had a '%' as well. */
1248 1248
1249 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1249 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1250 /* TODO: handle errors */ 1250 /* TODO: handle errors */
1251 1251
1252 rhs = rhs_expanded; 1252 rhs = rhs_expanded;
1253 percent = strchr(rhs, '%'); 1253 percent = strchr(rhs, '%');
1254 1254
1255 if (percent != NULL && lhsPercent) { 1255 if (percent != NULL && lhsPercent) {
1256 /* Copy the prefix of the replacement pattern */ 1256 /* Copy the prefix of the replacement pattern */
1257 SepBuf_AddBytesBetween(buf, rhs, percent); 1257 SepBuf_AddBytesBetween(buf, rhs, percent);
1258 rhs = percent + 1; 1258 rhs = percent + 1;
1259 } 1259 }
1260 if (percent != NULL || !lhsPercent) 1260 if (percent != NULL || !lhsPercent)
1261 SepBuf_AddBytes(buf, match, match_len); 1261 SepBuf_AddBytes(buf, match, match_len);
1262 1262
1263 /* Append the suffix of the replacement pattern */ 1263 /* Append the suffix of the replacement pattern */
1264 SepBuf_AddStr(buf, rhs); 1264 SepBuf_AddStr(buf, rhs);
1265 1265
1266 free(rhs_expanded); 1266 free(rhs_expanded);
1267} 1267}
1268#endif 1268#endif
1269 1269
1270 1270
1271struct ModifyWord_SubstArgs { 1271struct ModifyWord_SubstArgs {
1272 const char *lhs; 1272 const char *lhs;
1273 size_t lhsLen; 1273 size_t lhsLen;
1274 const char *rhs; 1274 const char *rhs;
1275 size_t rhsLen; 1275 size_t rhsLen;
1276 VarPatternFlags pflags; 1276 VarPatternFlags pflags;
1277 Boolean matched; 1277 Boolean matched;
1278}; 1278};
1279 1279
1280/* Callback for ModifyWords to implement the :S,from,to, modifier. 1280/* Callback for ModifyWords to implement the :S,from,to, modifier.
1281 * Perform a string substitution on the given word. */ 1281 * Perform a string substitution on the given word. */
1282static void 1282static void
1283ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1283ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1284{ 1284{
1285 size_t wordLen = strlen(word); 1285 size_t wordLen = strlen(word);
1286 struct ModifyWord_SubstArgs *args = data; 1286 struct ModifyWord_SubstArgs *args = data;
1287 const char *match; 1287 const char *match;
1288 1288
1289 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1289 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1290 goto nosub; 1290 goto nosub;
1291 1291
1292 if (args->pflags & VARP_ANCHOR_START) { 1292 if (args->pflags & VARP_ANCHOR_START) {
1293 if (wordLen < args->lhsLen || 1293 if (wordLen < args->lhsLen ||
1294 memcmp(word, args->lhs, args->lhsLen) != 0) 1294 memcmp(word, args->lhs, args->lhsLen) != 0)
1295 goto nosub; 1295 goto nosub;
1296 1296
1297 if (args->pflags & VARP_ANCHOR_END) { 1297 if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
1298 if (wordLen != args->lhsLen) 1298 goto nosub;
1299 goto nosub; 1299
1300 1300 /* :S,^prefix,replacement, or :S,^whole$,replacement, */
1301 /* :S,^whole$,replacement, */ 1301 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1302 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1302 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1303 args->matched = TRUE; 1303 args->matched = TRUE;
1304 } else { 
1305 /* :S,^prefix,replacement, */ 
1306 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 
1307 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 
1308 args->matched = TRUE; 
1309 } 
1310 return; 1304 return;
1311 } 1305 }
1312 1306
1313 if (args->pflags & VARP_ANCHOR_END) { 1307 if (args->pflags & VARP_ANCHOR_END) {
1314 const char *start; 1308 const char *start;
1315 1309
1316 if (wordLen < args->lhsLen) 1310 if (wordLen < args->lhsLen)
1317 goto nosub; 1311 goto nosub;
1318 1312
1319 start = word + (wordLen - args->lhsLen); 1313 start = word + (wordLen - args->lhsLen);
1320 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1314 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1321 goto nosub; 1315 goto nosub;
1322 1316
1323 /* :S,suffix$,replacement, */ 1317 /* :S,suffix$,replacement, */
1324 SepBuf_AddBytesBetween(buf, word, start); 1318 SepBuf_AddBytesBetween(buf, word, start);
1325 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1319 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1326 args->matched = TRUE; 1320 args->matched = TRUE;
1327 return; 1321 return;
1328 } 1322 }
1329 1323
1330 if (args->lhs[0] == '\0') 1324 if (args->lhs[0] == '\0')
1331 goto nosub; 1325 goto nosub;
1332 1326
1333 /* unanchored case, may match more than once */ 1327 /* unanchored case, may match more than once */
1334 while ((match = strstr(word, args->lhs)) != NULL) { 1328 while ((match = strstr(word, args->lhs)) != NULL) {
1335 SepBuf_AddBytesBetween(buf, word, match); 1329 SepBuf_AddBytesBetween(buf, word, match);
1336 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1330 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1337 args->matched = TRUE; 1331 args->matched = TRUE;
1338 wordLen -= (size_t)(match - word) + args->lhsLen; 1332 wordLen -= (size_t)(match - word) + args->lhsLen;
1339 word += (size_t)(match - word) + args->lhsLen; 1333 word += (size_t)(match - word) + args->lhsLen;
1340 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1334 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1341 break; 1335 break;
1342 } 1336 }
1343nosub: 1337nosub:
1344 SepBuf_AddBytes(buf, word, wordLen); 1338 SepBuf_AddBytes(buf, word, wordLen);
1345} 1339}
1346 1340
1347#ifndef NO_REGEX 1341#ifndef NO_REGEX
1348/* Print the error caused by a regcomp or regexec call. */ 1342/* Print the error caused by a regcomp or regexec call. */
1349static void 1343static void
1350VarREError(int reerr, regex_t *pat, const char *str) 1344VarREError(int reerr, regex_t *pat, const char *str)
1351{ 1345{
1352 size_t errlen = regerror(reerr, pat, 0, 0); 1346 size_t errlen = regerror(reerr, pat, 0, 0);
1353 char *errbuf = bmake_malloc(errlen); 1347 char *errbuf = bmake_malloc(errlen);
1354 regerror(reerr, pat, errbuf, errlen); 1348 regerror(reerr, pat, errbuf, errlen);
1355 Error("%s: %s", str, errbuf); 1349 Error("%s: %s", str, errbuf);
1356 free(errbuf); 1350 free(errbuf);
1357} 1351}
1358 1352
1359struct ModifyWord_SubstRegexArgs { 1353struct ModifyWord_SubstRegexArgs {
1360 regex_t re; 1354 regex_t re;
1361 size_t nsub; 1355 size_t nsub;
1362 char *replace; 1356 char *replace;
1363 VarPatternFlags pflags; 1357 VarPatternFlags pflags;
1364 Boolean matched; 1358 Boolean matched;
1365}; 1359};
1366 1360
1367/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1361/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1368 * Perform a regex substitution on the given word. */ 1362 * Perform a regex substitution on the given word. */
1369static void 1363static void
1370ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1364ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1371{ 1365{
1372 struct ModifyWord_SubstRegexArgs *args = data; 1366 struct ModifyWord_SubstRegexArgs *args = data;
1373 int xrv; 1367 int xrv;
1374 const char *wp = word; 1368 const char *wp = word;
1375 char *rp; 1369 char *rp;
1376 int flags = 0; 1370 int flags = 0;
1377 regmatch_t m[10]; 1371 regmatch_t m[10];
1378 1372
1379 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1373 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1380 goto nosub; 1374 goto nosub;
1381 1375
1382tryagain: 1376tryagain:
1383 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1377 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1384 1378
1385 switch (xrv) { 1379 switch (xrv) {
1386 case 0: 1380 case 0:
1387 args->matched = TRUE; 1381 args->matched = TRUE;
1388 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1382 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1389 1383
1390 for (rp = args->replace; *rp; rp++) { 1384 for (rp = args->replace; *rp; rp++) {
1391 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1385 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1392 SepBuf_AddBytes(buf, rp + 1, 1); 1386 SepBuf_AddBytes(buf, rp + 1, 1);
1393 rp++; 1387 rp++;
1394 continue; 1388 continue;
1395 } 1389 }
1396 1390
1397 if (*rp == '&') { 1391 if (*rp == '&') {
1398 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1392 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1399 continue; 1393 continue;
1400 } 1394 }
1401 1395
1402 if (*rp != '\\' || !ch_isdigit(rp[1])) { 1396 if (*rp != '\\' || !ch_isdigit(rp[1])) {
1403 SepBuf_AddBytes(buf, rp, 1); 1397 SepBuf_AddBytes(buf, rp, 1);
1404 continue; 1398 continue;
1405 } 1399 }
1406 1400
1407 { /* \0 to \9 backreference */ 1401 { /* \0 to \9 backreference */
1408 size_t n = (size_t)(rp[1] - '0'); 1402 size_t n = (size_t)(rp[1] - '0');
1409 rp++; 1403 rp++;
1410 1404
1411 if (n >= args->nsub) { 1405 if (n >= args->nsub) {
1412 Error("No subexpression \\%zu", n); 1406 Error("No subexpression \\%zu", n);
1413 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1407 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1414 Error("No match for subexpression \\%zu", n); 1408 Error("No match for subexpression \\%zu", n);
1415 } else { 1409 } else {
1416 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1410 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1417 wp + m[n].rm_eo); 1411 wp + m[n].rm_eo);
1418 } 1412 }
1419 } 1413 }
1420 } 1414 }
1421 1415
1422 wp += m[0].rm_eo; 1416 wp += m[0].rm_eo;
1423 if (args->pflags & VARP_SUB_GLOBAL) { 1417 if (args->pflags & VARP_SUB_GLOBAL) {
1424 flags |= REG_NOTBOL; 1418 flags |= REG_NOTBOL;
1425 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1419 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1426 SepBuf_AddBytes(buf, wp, 1); 1420 SepBuf_AddBytes(buf, wp, 1);
1427 wp++; 1421 wp++;
1428 } 1422 }
1429 if (*wp) 1423 if (*wp)
1430 goto tryagain; 1424 goto tryagain;
1431 } 1425 }
1432 if (*wp) { 1426 if (*wp) {
1433 SepBuf_AddStr(buf, wp); 1427 SepBuf_AddStr(buf, wp);
1434 } 1428 }
1435 break; 1429 break;
1436 default: 1430 default:
1437 VarREError(xrv, &args->re, "Unexpected regex error"); 1431 VarREError(xrv, &args->re, "Unexpected regex error");
1438 /* FALLTHROUGH */ 1432 /* FALLTHROUGH */
1439 case REG_NOMATCH: 1433 case REG_NOMATCH:
1440 nosub: 1434 nosub:
1441 SepBuf_AddStr(buf, wp); 1435 SepBuf_AddStr(buf, wp);
1442 break; 1436 break;
1443 } 1437 }
1444} 1438}
1445#endif 1439#endif
1446 1440
1447 1441
1448struct ModifyWord_LoopArgs { 1442struct ModifyWord_LoopArgs {
1449 GNode *ctx; 1443 GNode *ctx;
1450 char *tvar; /* name of temporary variable */ 1444 char *tvar; /* name of temporary variable */
1451 char *str; /* string to expand */ 1445 char *str; /* string to expand */
1452 VarEvalFlags eflags; 1446 VarEvalFlags eflags;
1453}; 1447};
1454 1448
1455/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1449/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1456static void 1450static void
1457ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1451ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1458{ 1452{
1459 const struct ModifyWord_LoopArgs *args; 1453 const struct ModifyWord_LoopArgs *args;
1460 char *s; 1454 char *s;
1461 1455
1462 if (word[0] == '\0') 1456 if (word[0] == '\0')
1463 return; 1457 return;
1464 1458
1465 args = data; 1459 args = data;
1466 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1460 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1467 (void)Var_Subst(args->str, args->ctx, args->eflags, &s); 1461 (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1468 /* TODO: handle errors */ 1462 /* TODO: handle errors */
1469 1463
1470 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1464 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1471 "to \"%s\"\n", 1465 "to \"%s\"\n",
1472 word, args->tvar, args->str, s); 1466 word, args->tvar, args->str, s);
1473 1467
1474 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n')) 1468 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1475 buf->needSep = FALSE; 1469 buf->needSep = FALSE;
1476 SepBuf_AddStr(buf, s); 1470 SepBuf_AddStr(buf, s);
1477 free(s); 1471 free(s);
1478} 1472}
1479 1473
1480 1474
1481/*- 1475/*-
1482 * Implements the :[first..last] modifier. 1476 * Implements the :[first..last] modifier.
1483 * This is a special case of ModifyWords since we want to be able 1477 * This is a special case of ModifyWords since we want to be able
1484 * to scan the list backwards if first > last. 1478 * to scan the list backwards if first > last.
1485 */ 1479 */
1486static char * 1480static char *
1487VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1481VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1488 int last) 1482 int last)
1489{ 1483{
1490 Words words; 1484 Words words;
1491 int len, start, end, step; 1485 int len, start, end, step;
1492 int i; 1486 int i;
1493 1487
1494 SepBuf buf; 1488 SepBuf buf;
1495 SepBuf_Init(&buf, sep); 1489 SepBuf_Init(&buf, sep);
1496 1490
1497 if (oneBigWord) { 1491 if (oneBigWord) {
1498 /* fake what Str_Words() would do if there were only one word */ 1492 /* fake what Str_Words() would do if there were only one word */
1499 words.len = 1; 1493 words.len = 1;
1500 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1494 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1501 words.freeIt = bmake_strdup(str); 1495 words.freeIt = bmake_strdup(str);
1502 words.words[0] = words.freeIt; 1496 words.words[0] = words.freeIt;
1503 words.words[1] = NULL; 1497 words.words[1] = NULL;
1504 } else { 1498 } else {
1505 words = Str_Words(str, FALSE); 1499 words = Str_Words(str, FALSE);
1506 } 1500 }
1507 1501
1508 /* 1502 /*
1509 * Now sanitize the given range. 1503 * Now sanitize the given range.
1510 * If first or last are negative, convert them to the positive equivalents 1504 * If first or last are negative, convert them to the positive equivalents
1511 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1505 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1512 */ 1506 */
1513 len = (int)words.len; 1507 len = (int)words.len;
1514 if (first < 0) 1508 if (first < 0)
1515 first += len + 1; 1509 first += len + 1;
1516 if (last < 0) 1510 if (last < 0)
1517 last += len + 1; 1511 last += len + 1;
1518 1512
1519 /* 1513 /*
1520 * We avoid scanning more of the list than we need to. 1514 * We avoid scanning more of the list than we need to.
1521 */ 1515 */
1522 if (first > last) { 1516 if (first > last) {
1523 start = (first > len ? len : first) - 1; 1517 start = (first > len ? len : first) - 1;
1524 end = last < 1 ? 0 : last - 1; 1518 end = last < 1 ? 0 : last - 1;
1525 step = -1; 1519 step = -1;
1526 } else { 1520 } else {
1527 start = first < 1 ? 0 : first - 1; 1521 start = first < 1 ? 0 : first - 1;
1528 end = last > len ? len : last; 1522 end = last > len ? len : last;
1529 step = 1; 1523 step = 1;
1530 } 1524 }
1531 1525
1532 for (i = start; (step < 0) == (i >= end); i += step) { 1526 for (i = start; (step < 0) == (i >= end); i += step) {
1533 SepBuf_AddStr(&buf, words.words[i]); 1527 SepBuf_AddStr(&buf, words.words[i]);
1534 SepBuf_Sep(&buf); 1528 SepBuf_Sep(&buf);
1535 } 1529 }
1536 1530
1537 Words_Free(words); 1531 Words_Free(words);
1538 1532
1539 return SepBuf_Destroy(&buf, FALSE); 1533 return SepBuf_Destroy(&buf, FALSE);
1540} 1534}
1541 1535
1542 1536
1543/* Callback for ModifyWords to implement the :tA modifier. 1537/* Callback for ModifyWords to implement the :tA modifier.
1544 * Replace each word with the result of realpath() if successful. */ 1538 * Replace each word with the result of realpath() if successful. */
1545static void 1539static void
1546ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1540ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1547{ 1541{
1548 struct stat st; 1542 struct stat st;
1549 char rbuf[MAXPATHLEN]; 1543 char rbuf[MAXPATHLEN];
1550 1544
1551 const char *rp = cached_realpath(word, rbuf); 1545 const char *rp = cached_realpath(word, rbuf);
1552 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1546 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1553 word = rp; 1547 word = rp;
1554 1548
1555 SepBuf_AddStr(buf, word); 1549 SepBuf_AddStr(buf, word);
1556} 1550}
1557 1551
1558/*- 1552/*-
1559 *----------------------------------------------------------------------- 1553 *-----------------------------------------------------------------------
1560 * Modify each of the words of the passed string using the given function. 1554 * Modify each of the words of the passed string using the given function.
1561 * 1555 *
1562 * Input: 1556 * Input:
1563 * str String whose words should be modified 1557 * str String whose words should be modified
1564 * modifyWord Function that modifies a single word 1558 * modifyWord Function that modifies a single word
1565 * modifyWord_args Custom arguments for modifyWord 1559 * modifyWord_args Custom arguments for modifyWord
1566 * 1560 *
1567 * Results: 1561 * Results:
1568 * A string of all the words modified appropriately. 1562 * A string of all the words modified appropriately.
1569 *----------------------------------------------------------------------- 1563 *-----------------------------------------------------------------------
1570 */ 1564 */
1571static char * 1565static char *
1572ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1566ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str,
1573 ModifyWordsCallback modifyWord, void *modifyWord_args) 1567 ModifyWordsCallback modifyWord, void *modifyWord_args)
1574{ 1568{
1575 SepBuf result; 1569 SepBuf result;
1576 Words words; 1570 Words words;
1577 size_t i; 1571 size_t i;
1578 1572
1579 if (oneBigWord) { 1573 if (oneBigWord) {
1580 SepBuf_Init(&result, sep); 1574 SepBuf_Init(&result, sep);
1581 modifyWord(str, &result, modifyWord_args); 1575 modifyWord(str, &result, modifyWord_args);
1582 return SepBuf_Destroy(&result, FALSE); 1576 return SepBuf_Destroy(&result, FALSE);
1583 } 1577 }
1584 1578
1585 SepBuf_Init(&result, sep); 1579 SepBuf_Init(&result, sep);
1586 1580
1587 words = Str_Words(str, FALSE); 1581 words = Str_Words(str, FALSE);
1588 1582
1589 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1583 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1590 1584
1591 for (i = 0; i < words.len; i++) { 1585 for (i = 0; i < words.len; i++) {
1592 modifyWord(words.words[i], &result, modifyWord_args); 1586 modifyWord(words.words[i], &result, modifyWord_args);
1593 if (Buf_Len(&result.buf) > 0) 1587 if (Buf_Len(&result.buf) > 0)
1594 SepBuf_Sep(&result); 1588 SepBuf_Sep(&result);
1595 } 1589 }
1596 1590
1597 Words_Free(words); 1591 Words_Free(words);
1598 1592
1599 return SepBuf_Destroy(&result, FALSE); 1593 return SepBuf_Destroy(&result, FALSE);
1600} 1594}
1601 1595
1602 1596
1603static char * 1597static char *
1604Words_JoinFree(Words words) 1598Words_JoinFree(Words words)
1605{ 1599{
1606 Buffer buf; 1600 Buffer buf;
1607 size_t i; 1601 size_t i;
1608 1602
1609 Buf_Init(&buf, 0); 1603 Buf_Init(&buf, 0);
1610 1604
1611 for (i = 0; i < words.len; i++) { 1605 for (i = 0; i < words.len; i++) {
1612 if (i != 0) 1606 if (i != 0)
1613 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1607 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1614 Buf_AddStr(&buf, words.words[i]); 1608 Buf_AddStr(&buf, words.words[i]);
1615 } 1609 }
1616 1610
1617 Words_Free(words); 1611 Words_Free(words);
1618 1612
1619 return Buf_Destroy(&buf, FALSE); 1613 return Buf_Destroy(&buf, FALSE);
1620} 1614}
1621 1615
1622/* Remove adjacent duplicate words. */ 1616/* Remove adjacent duplicate words. */
1623static char * 1617static char *
1624VarUniq(const char *str) 1618VarUniq(const char *str)
1625{ 1619{
1626 Words words = Str_Words(str, FALSE); 1620 Words words = Str_Words(str, FALSE);
1627 1621
1628 if (words.len > 1) { 1622 if (words.len > 1) {
1629 size_t i, j; 1623 size_t i, j;
1630 for (j = 0, i = 1; i < words.len; i++) 1624 for (j = 0, i = 1; i < words.len; i++)
1631 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i)) 1625 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1632 words.words[j] = words.words[i]; 1626 words.words[j] = words.words[i];
1633 words.len = j + 1; 1627 words.len = j + 1;
1634 } 1628 }
1635 1629
1636 return Words_JoinFree(words); 1630 return Words_JoinFree(words);
1637} 1631}
1638 1632
1639 1633
1640/* Quote shell meta-characters and space characters in the string. 1634/* Quote shell meta-characters and space characters in the string.
1641 * If quoteDollar is set, also quote and double any '$' characters. */ 1635 * If quoteDollar is set, also quote and double any '$' characters. */
1642static char * 1636static char *
1643VarQuote(const char *str, Boolean quoteDollar) 1637VarQuote(const char *str, Boolean quoteDollar)
1644{ 1638{
1645 char *res; 1639 char *res;
1646 Buffer buf; 1640 Buffer buf;
1647 Buf_Init(&buf, 0); 1641 Buf_Init(&buf, 0);
1648 1642
1649 for (; *str != '\0'; str++) { 1643 for (; *str != '\0'; str++) {
1650 if (*str == '\n') { 1644 if (*str == '\n') {
1651 const char *newline = Shell_GetNewline(); 1645 const char *newline = Shell_GetNewline();
1652 if (newline == NULL) 1646 if (newline == NULL)
1653 newline = "\\\n"; 1647 newline = "\\\n";
1654 Buf_AddStr(&buf, newline); 1648 Buf_AddStr(&buf, newline);
1655 continue; 1649 continue;
1656 } 1650 }
1657 if (ch_isspace(*str) || ismeta((unsigned char)*str)) 1651 if (ch_isspace(*str) || ismeta((unsigned char)*str))
1658 Buf_AddByte(&buf, '\\'); 1652 Buf_AddByte(&buf, '\\');
1659 Buf_AddByte(&buf, *str); 1653 Buf_AddByte(&buf, *str);
1660 if (quoteDollar && *str == '$') 1654 if (quoteDollar && *str == '$')
1661 Buf_AddStr(&buf, "\\$"); 1655 Buf_AddStr(&buf, "\\$");
1662 } 1656 }
1663 1657
1664 res = Buf_Destroy(&buf, FALSE); 1658 res = Buf_Destroy(&buf, FALSE);
1665 VAR_DEBUG1("QuoteMeta: [%s]\n", res); 1659 VAR_DEBUG1("QuoteMeta: [%s]\n", res);
1666 return res; 1660 return res;
1667} 1661}
1668 1662
1669/* Compute the 32-bit hash of the given string, using the MurmurHash3 1663/* Compute the 32-bit hash of the given string, using the MurmurHash3
1670 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1664 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1671static char * 1665static char *
1672VarHash(const char *str) 1666VarHash(const char *str)
1673{ 1667{
1674 static const char hexdigits[16] = "0123456789abcdef"; 1668 static const char hexdigits[16] = "0123456789abcdef";
1675 const unsigned char *ustr = (const unsigned char *)str; 1669 const unsigned char *ustr = (const unsigned char *)str;
1676 1670
1677 uint32_t h = 0x971e137bU; 1671 uint32_t h = 0x971e137bU;
1678 uint32_t c1 = 0x95543787U; 1672 uint32_t c1 = 0x95543787U;
1679 uint32_t c2 = 0x2ad7eb25U; 1673 uint32_t c2 = 0x2ad7eb25U;
1680 size_t len2 = strlen(str); 1674 size_t len2 = strlen(str);
1681 1675
1682 char *buf; 1676 char *buf;
1683 size_t i; 1677 size_t i;
1684 1678
1685 size_t len; 1679 size_t len;
1686 for (len = len2; len; ) { 1680 for (len = len2; len; ) {
1687 uint32_t k = 0; 1681 uint32_t k = 0;
1688 switch (len) { 1682 switch (len) {
1689 default: 1683 default:
1690 k = ((uint32_t)ustr[3] << 24) | 1684 k = ((uint32_t)ustr[3] << 24) |
1691 ((uint32_t)ustr[2] << 16) | 1685 ((uint32_t)ustr[2] << 16) |
1692 ((uint32_t)ustr[1] << 8) | 1686 ((uint32_t)ustr[1] << 8) |
1693 (uint32_t)ustr[0]; 1687 (uint32_t)ustr[0];
1694 len -= 4; 1688 len -= 4;
1695 ustr += 4; 1689 ustr += 4;
1696 break; 1690 break;
1697 case 3: 1691 case 3:
1698 k |= (uint32_t)ustr[2] << 16; 1692 k |= (uint32_t)ustr[2] << 16;
1699 /* FALLTHROUGH */ 1693 /* FALLTHROUGH */
1700 case 2: 1694 case 2:
1701 k |= (uint32_t)ustr[1] << 8; 1695 k |= (uint32_t)ustr[1] << 8;
1702 /* FALLTHROUGH */ 1696 /* FALLTHROUGH */
1703 case 1: 1697 case 1:
1704 k |= (uint32_t)ustr[0]; 1698 k |= (uint32_t)ustr[0];
1705 len = 0; 1699 len = 0;
1706 } 1700 }
1707 c1 = c1 * 5 + 0x7b7d159cU; 1701 c1 = c1 * 5 + 0x7b7d159cU;
1708 c2 = c2 * 5 + 0x6bce6396U; 1702 c2 = c2 * 5 + 0x6bce6396U;
1709 k *= c1; 1703 k *= c1;
1710 k = (k << 11) ^ (k >> 21); 1704 k = (k << 11) ^ (k >> 21);
1711 k *= c2; 1705 k *= c2;
1712 h = (h << 13) ^ (h >> 19); 1706 h = (h << 13) ^ (h >> 19);
1713 h = h * 5 + 0x52dce729U; 1707 h = h * 5 + 0x52dce729U;
1714 h ^= k; 1708 h ^= k;
1715 } 1709 }
1716 h ^= (uint32_t)len2; 1710 h ^= (uint32_t)len2;
1717 h *= 0x85ebca6b; 1711 h *= 0x85ebca6b;
1718 h ^= h >> 13; 1712 h ^= h >> 13;
1719 h *= 0xc2b2ae35; 1713 h *= 0xc2b2ae35;
1720 h ^= h >> 16; 1714 h ^= h >> 16;
1721 1715
1722 buf = bmake_malloc(9); 1716 buf = bmake_malloc(9);
1723 for (i = 0; i < 8; i++) { 1717 for (i = 0; i < 8; i++) {
1724 buf[i] = hexdigits[h & 0x0f]; 1718 buf[i] = hexdigits[h & 0x0f];
1725 h >>= 4; 1719 h >>= 4;
1726 } 1720 }
1727 buf[8] = '\0'; 1721 buf[8] = '\0';
1728 return buf; 1722 return buf;
1729} 1723}
1730 1724
1731static char * 1725static char *
1732VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1726VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1733{ 1727{
1734 char buf[BUFSIZ]; 1728 char buf[BUFSIZ];
1735 1729
1736 if (!tim) 1730 if (!tim)
1737 time(&tim); 1731 time(&tim);
1738 if (!*fmt) 1732 if (!*fmt)
1739 fmt = "%c"; 1733 fmt = "%c";
1740 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1734 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1741 1735
1742 buf[sizeof(buf) - 1] = '\0'; 1736 buf[sizeof(buf) - 1] = '\0';
1743 return bmake_strdup(buf); 1737 return bmake_strdup(buf);
1744} 1738}
1745 1739
1746/* The ApplyModifier functions all work in the same way. They get the 1740/* The ApplyModifier functions all work in the same way. They get the
1747 * current parsing position (pp) and parse the modifier from there. The 1741 * current parsing position (pp) and parse the modifier from there. The
1748 * modifier typically lasts until the next ':', or a closing '}' or ')' 1742 * modifier typically lasts until the next ':', or a closing '}' or ')'
1749 * (taken from st->endc), or the end of the string (parse error). 1743 * (taken from st->endc), or the end of the string (parse error).
1750 * 1744 *
1751 * The high-level behavior of these functions is: 1745 * The high-level behavior of these functions is:
1752 * 1746 *
1753 * 1. parse the modifier 1747 * 1. parse the modifier
1754 * 2. evaluate the modifier 1748 * 2. evaluate the modifier
1755 * 3. housekeeping 1749 * 3. housekeeping
1756 * 1750 *
1757 * Parsing the modifier 1751 * Parsing the modifier
1758 * 1752 *
1759 * If parsing succeeds, the parsing position *pp is updated to point to the 1753 * If parsing succeeds, the parsing position *pp is updated to point to the
1760 * first character following the modifier, which typically is either ':' or 1754 * first character following the modifier, which typically is either ':' or
1761 * st->endc. 1755 * st->endc.
1762 * 1756 *
1763 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1757 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1764 * modifiers), return AMR_CLEANUP. 1758 * modifiers), return AMR_CLEANUP.
1765 * 1759 *
1766 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1760 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1767 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1761 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1768 * done as long as there have been no side effects from evaluating nested 1762 * done as long as there have been no side effects from evaluating nested
1769 * variables, to avoid evaluating them more than once. In this case, the 1763 * variables, to avoid evaluating them more than once. In this case, the
1770 * parsing position must not be updated. (XXX: Why not? The original parsing 1764 * parsing position must not be updated. (XXX: Why not? The original parsing
1771 * position is well-known in ApplyModifiers.) 1765 * position is well-known in ApplyModifiers.)
1772 * 1766 *
1773 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1767 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1774 * as a fallback, either issue an error message using Error or Parse_Error 1768 * as a fallback, either issue an error message using Error or Parse_Error
1775 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1769 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1776 * message. Both of these return values will stop processing the variable 1770 * message. Both of these return values will stop processing the variable
1777 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1771 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1778 * continues nevertheless after skipping a few bytes, which essentially is 1772 * continues nevertheless after skipping a few bytes, which essentially is
1779 * undefined behavior. Not in the sense of C, but still it's impossible to 1773 * undefined behavior. Not in the sense of C, but still it's impossible to
1780 * predict what happens in the parser.) 1774 * predict what happens in the parser.)
1781 * 1775 *
1782 * Evaluating the modifier 1776 * Evaluating the modifier
1783 * 1777 *
1784 * After parsing, the modifier is evaluated. The side effects from evaluating 1778 * After parsing, the modifier is evaluated. The side effects from evaluating
1785 * nested variable expressions in the modifier text often already happen 1779 * nested variable expressions in the modifier text often already happen
1786 * during parsing though. 1780 * during parsing though.
1787 * 1781 *
1788 * Evaluating the modifier usually takes the current value of the variable 1782 * Evaluating the modifier usually takes the current value of the variable
1789 * expression from st->val, or the variable name from st->v->name and stores 1783 * expression from st->val, or the variable name from st->v->name and stores
1790 * the result in st->newVal. 1784 * the result in st->newVal.
1791 * 1785 *
1792 * If evaluating fails (as of 2020-08-23), an error message is printed using 1786 * If evaluating fails (as of 2020-08-23), an error message is printed using
1793 * Error. This function has no side-effects, it really just prints the error 1787 * Error. This function has no side-effects, it really just prints the error
1794 * message. Processing the expression continues as if everything were ok. 1788 * message. Processing the expression continues as if everything were ok.
1795 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1789 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1796 * Var_Parse, ApplyModifiers and ModifyWords. 1790 * Var_Parse, ApplyModifiers and ModifyWords.
1797 * 1791 *
1798 * Housekeeping 1792 * Housekeeping
1799 * 1793 *
1800 * Some modifiers such as :D and :U turn undefined expressions into defined 1794 * Some modifiers such as :D and :U turn undefined expressions into defined
1801 * expressions (see VEF_UNDEF, VEF_DEF). 1795 * expressions (see VEF_UNDEF, VEF_DEF).
1802 * 1796 *
1803 * Some modifiers need to free some memory. 1797 * Some modifiers need to free some memory.
1804 */ 1798 */
1805 1799
1806typedef enum VarExprFlags { 1800typedef enum VarExprFlags {
1807 /* The variable expression is based on an undefined variable. */ 1801 /* The variable expression is based on an undefined variable. */
1808 VEF_UNDEF = 0x01, 1802 VEF_UNDEF = 0x01,
1809 /* The variable expression started as an undefined expression, but one 1803 /* The variable expression started as an undefined expression, but one
1810 * of the modifiers (such as :D or :U) has turned the expression from 1804 * of the modifiers (such as :D or :U) has turned the expression from
1811 * undefined to defined. */ 1805 * undefined to defined. */
1812 VEF_DEF = 0x02 1806 VEF_DEF = 0x02
1813} VarExprFlags; 1807} VarExprFlags;
1814 1808
1815ENUM_FLAGS_RTTI_2(VarExprFlags, 1809ENUM_FLAGS_RTTI_2(VarExprFlags,
1816 VEF_UNDEF, VEF_DEF); 1810 VEF_UNDEF, VEF_DEF);
1817 1811
1818 1812
1819typedef struct ApplyModifiersState { 1813typedef struct ApplyModifiersState {
1820 const char startc; /* '\0' or '{' or '(' */ 1814 const char startc; /* '\0' or '{' or '(' */
1821 const char endc; /* '\0' or '}' or ')' */ 1815 const char endc; /* '\0' or '}' or ')' */
1822 Var * const v; 1816 Var * const v;
1823 GNode * const ctxt; 1817 GNode * const ctxt;
1824 const VarEvalFlags eflags; 1818 const VarEvalFlags eflags;
1825 1819
1826 char *val; /* The old value of the expression, 1820 char *val; /* The old value of the expression,
1827 * before applying the modifier, never NULL */ 1821 * before applying the modifier, never NULL */
1828 char *newVal; /* The new value of the expression, 1822 char *newVal; /* The new value of the expression,
1829 * after applying the modifier, never NULL */ 1823 * after applying the modifier, never NULL */
1830 char sep; /* Word separator in expansions 1824 char sep; /* Word separator in expansions
1831 * (see the :ts modifier) */ 1825 * (see the :ts modifier) */
1832 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1826 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1833 * the variable value into words, like :S and 1827 * the variable value into words, like :S and
1834 * :C, treat the variable value as a single big 1828 * :C, treat the variable value as a single big
1835 * word, possibly containing spaces. */ 1829 * word, possibly containing spaces. */
1836 VarExprFlags exprFlags; 1830 VarExprFlags exprFlags;
1837} ApplyModifiersState; 1831} ApplyModifiersState;
1838 1832
1839static void 1833static void
1840ApplyModifiersState_Define(ApplyModifiersState *st) 1834ApplyModifiersState_Define(ApplyModifiersState *st)
1841{ 1835{
1842 if (st->exprFlags & VEF_UNDEF) 1836 if (st->exprFlags & VEF_UNDEF)
1843 st->exprFlags |= VEF_DEF; 1837 st->exprFlags |= VEF_DEF;
1844} 1838}
1845 1839
1846typedef enum ApplyModifierResult { 1840typedef enum ApplyModifierResult {
1847 AMR_OK, /* Continue parsing */ 1841 AMR_OK, /* Continue parsing */
1848 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1842 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1849 AMR_BAD, /* Error out with "Bad modifier" message */ 1843 AMR_BAD, /* Error out with "Bad modifier" message */
1850 AMR_CLEANUP /* Error out without error message */ 1844 AMR_CLEANUP /* Error out without error message */
1851} ApplyModifierResult; 1845} ApplyModifierResult;
1852 1846
1853/*- 1847/*-
1854 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ 1848 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
1855 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and 1849 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
1856 * including the next unescaped delimiter. The delimiter, as well as the 1850 * including the next unescaped delimiter. The delimiter, as well as the
1857 * backslash or the dollar, can be escaped with a backslash. 1851 * backslash or the dollar, can be escaped with a backslash.
1858 * 1852 *
1859 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1853 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1860 * was found. On successful return, the parsing position pp points right 1854 * was found. On successful return, the parsing position pp points right
1861 * after the delimiter. The delimiter is not included in the returned 1855 * after the delimiter. The delimiter is not included in the returned
1862 * value though. 1856 * value though.
1863 */ 1857 */
1864static VarParseResult 1858static VarParseResult
1865ParseModifierPart( 1859ParseModifierPart(
1866 const char **pp, /* The parsing position, updated upon return */ 1860 const char **pp, /* The parsing position, updated upon return */
1867 int delim, /* Parsing stops at this delimiter */ 1861 int delim, /* Parsing stops at this delimiter */
1868 VarEvalFlags eflags, /* Flags for evaluating nested variables; 1862 VarEvalFlags eflags, /* Flags for evaluating nested variables;
1869 * if VARE_WANTRES is not set, the text is 1863 * if VARE_WANTRES is not set, the text is
1870 * only parsed */ 1864 * only parsed */
1871 ApplyModifiersState *st, 1865 ApplyModifiersState *st,
1872 char **out_part, 1866 char **out_part,
1873 size_t *out_length, /* Optionally stores the length of the returned 1867 size_t *out_length, /* Optionally stores the length of the returned
1874 * string, just to save another strlen call. */ 1868 * string, just to save another strlen call. */
1875 VarPatternFlags *out_pflags,/* For the first part of the :S modifier, 1869 VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
1876 * sets the VARP_ANCHOR_END flag if the last 1870 * sets the VARP_ANCHOR_END flag if the last
1877 * character of the pattern is a $. */ 1871 * character of the pattern is a $. */
1878 struct ModifyWord_SubstArgs *subst 1872 struct ModifyWord_SubstArgs *subst
1879 /* For the second part of the :S modifier, 1873 /* For the second part of the :S modifier,
1880 * allow ampersands to be escaped and replace 1874 * allow ampersands to be escaped and replace
1881 * unescaped ampersands with subst->lhs. */ 1875 * unescaped ampersands with subst->lhs. */
1882) { 1876) {
1883 Buffer buf; 1877 Buffer buf;
1884 const char *p; 1878 const char *p;
1885 1879
1886 Buf_Init(&buf, 0); 1880 Buf_Init(&buf, 0);
1887 1881
1888 /* 1882 /*
1889 * Skim through until the matching delimiter is found; 1883 * Skim through until the matching delimiter is found;
1890 * pick up variable substitutions on the way. Also allow 1884 * pick up variable substitutions on the way. Also allow
1891 * backslashes to quote the delimiter, $, and \, but don't 1885 * backslashes to quote the delimiter, $, and \, but don't
1892 * touch other backslashes. 1886 * touch other backslashes.
1893 */ 1887 */
1894 p = *pp; 1888 p = *pp;
1895 while (*p != '\0' && *p != delim) { 1889 while (*p != '\0' && *p != delim) {
1896 const char *varstart; 1890 const char *varstart;
1897 1891
1898 Boolean is_escaped = p[0] == '\\' && ( 1892 Boolean is_escaped = p[0] == '\\' && (
1899 p[1] == delim || p[1] == '\\' || p[1] == '$' || 1893 p[1] == delim || p[1] == '\\' || p[1] == '$' ||
1900 (p[1] == '&' && subst != NULL)); 1894 (p[1] == '&' && subst != NULL));
1901 if (is_escaped) { 1895 if (is_escaped) {
1902 Buf_AddByte(&buf, p[1]); 1896 Buf_AddByte(&buf, p[1]);
1903 p += 2; 1897 p += 2;
1904 continue; 1898 continue;
1905 } 1899 }
1906 1900
1907 if (*p != '$') { /* Unescaped, simple text */ 1901 if (*p != '$') { /* Unescaped, simple text */
1908 if (subst != NULL && *p == '&') 1902 if (subst != NULL && *p == '&')
1909 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen); 1903 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
1910 else 1904 else
1911 Buf_AddByte(&buf, *p); 1905 Buf_AddByte(&buf, *p);
1912 p++; 1906 p++;
1913 continue; 1907 continue;
1914 } 1908 }
1915 1909
1916 if (p[1] == delim) { /* Unescaped $ at end of pattern */ 1910 if (p[1] == delim) { /* Unescaped $ at end of pattern */
1917 if (out_pflags != NULL) 1911 if (out_pflags != NULL)
1918 *out_pflags |= VARP_ANCHOR_END; 1912 *out_pflags |= VARP_ANCHOR_END;
1919 else 1913 else
1920 Buf_AddByte(&buf, *p); 1914 Buf_AddByte(&buf, *p);
1921 p++; 1915 p++;
1922 continue; 1916 continue;
1923 } 1917 }
1924 1918
1925 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */ 1919 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
1926 const char *nested_p = p; 1920 const char *nested_p = p;
1927 const char *nested_val; 1921 const char *nested_val;
1928 void *nested_val_freeIt; 1922 void *nested_val_freeIt;
1929 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN; 1923 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
1930 1924
1931 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags, 1925 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
1932 &nested_val, &nested_val_freeIt); 1926 &nested_val, &nested_val_freeIt);
1933 /* TODO: handle errors */ 1927 /* TODO: handle errors */
1934 Buf_AddStr(&buf, nested_val); 1928 Buf_AddStr(&buf, nested_val);
1935 free(nested_val_freeIt); 1929 free(nested_val_freeIt);
1936 p += nested_p - p; 1930 p += nested_p - p;
1937 continue; 1931 continue;
1938 } 1932 }
1939 1933
1940 /* XXX: This whole block is very similar to Var_Parse without 1934 /* XXX: This whole block is very similar to Var_Parse without
1941 * VARE_WANTRES. There may be subtle edge cases though that are 1935 * VARE_WANTRES. There may be subtle edge cases though that are
1942 * not yet covered in the unit tests and that are parsed differently, 1936 * not yet covered in the unit tests and that are parsed differently,
1943 * depending on whether they are evaluated or not. 1937 * depending on whether they are evaluated or not.
1944 * 1938 *
1945 * This subtle difference is not documented in the manual page, 1939 * This subtle difference is not documented in the manual page,
1946 * neither is the difference between parsing :D and :M documented. 1940 * neither is the difference between parsing :D and :M documented.
1947 * No code should ever depend on these details, but who knows. */ 1941 * No code should ever depend on these details, but who knows. */
1948 1942
1949 varstart = p; /* Nested variable, only parsed */ 1943 varstart = p; /* Nested variable, only parsed */
1950 if (p[1] == '(' || p[1] == '{') { 1944 if (p[1] == '(' || p[1] == '{') {
1951 /* 1945 /*
1952 * Find the end of this variable reference 1946 * Find the end of this variable reference
1953 * and suck it in without further ado. 1947 * and suck it in without further ado.
1954 * It will be interpreted later. 1948 * It will be interpreted later.
1955 */ 1949 */
1956 char have = p[1]; 1950 char have = p[1];
1957 int want = have == '(' ? ')' : '}'; 1951 int want = have == '(' ? ')' : '}';
1958 int depth = 1; 1952 int depth = 1;
1959 1953
1960 for (p += 2; *p != '\0' && depth > 0; p++) { 1954 for (p += 2; *p != '\0' && depth > 0; p++) {
1961 if (p[-1] != '\\') { 1955 if (p[-1] != '\\') {
1962 if (*p == have) 1956 if (*p == have)
1963 depth++; 1957 depth++;
1964 if (*p == want) 1958 if (*p == want)
1965 depth--; 1959 depth--;
1966 } 1960 }
1967 } 1961 }
1968 Buf_AddBytesBetween(&buf, varstart, p); 1962 Buf_AddBytesBetween(&buf, varstart, p);
1969 } else { 1963 } else {
1970 Buf_AddByte(&buf, *varstart); 1964 Buf_AddByte(&buf, *varstart);
1971 p++; 1965 p++;
1972 } 1966 }
1973 } 1967 }
1974 1968
1975 if (*p != delim) { 1969 if (*p != delim) {
1976 *pp = p; 1970 *pp = p;
1977 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim); 1971 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim);
1978 *out_part = NULL; 1972 *out_part = NULL;
1979 return VPR_PARSE_MSG; 1973 return VPR_PARSE_MSG;
1980 } 1974 }
1981 1975
1982 *pp = ++p; 1976 *pp = ++p;
1983 if (out_length != NULL) 1977 if (out_length != NULL)
1984 *out_length = Buf_Len(&buf); 1978 *out_length = Buf_Len(&buf);
1985 1979
1986 *out_part = Buf_Destroy(&buf, FALSE); 1980 *out_part = Buf_Destroy(&buf, FALSE);
1987 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part); 1981 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part);
1988 return VPR_OK; 1982 return VPR_OK;
1989} 1983}
1990 1984
1991/* Test whether mod starts with modname, followed by a delimiter. */ 1985/* Test whether mod starts with modname, followed by a delimiter. */
1992static Boolean 1986static Boolean
1993ModMatch(const char *mod, const char *modname, char endc) 1987ModMatch(const char *mod, const char *modname, char endc)
1994{ 1988{
1995 size_t n = strlen(modname); 1989 size_t n = strlen(modname);
1996 return strncmp(mod, modname, n) == 0 && 1990 return strncmp(mod, modname, n) == 0 &&
1997 (mod[n] == endc || mod[n] == ':'); 1991 (mod[n] == endc || mod[n] == ':');
1998} 1992}
1999 1993
2000/* Test whether mod starts with modname, followed by a delimiter or '='. */ 1994/* Test whether mod starts with modname, followed by a delimiter or '='. */
2001static inline Boolean 1995static inline Boolean
2002ModMatchEq(const char *mod, const char *modname, char endc) 1996ModMatchEq(const char *mod, const char *modname, char endc)
2003{ 1997{
2004 size_t n = strlen(modname); 1998 size_t n = strlen(modname);
2005 return strncmp(mod, modname, n) == 0 && 1999 return strncmp(mod, modname, n) == 0 &&
2006 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2000 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2007} 2001}
2008 2002
2009/* :@var@...${var}...@ */ 2003/* :@var@...${var}...@ */
2010static ApplyModifierResult 2004static ApplyModifierResult
2011ApplyModifier_Loop(const char **pp, ApplyModifiersState *st) 2005ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
2012{ 2006{
2013 struct ModifyWord_LoopArgs args; 2007 struct ModifyWord_LoopArgs args;
2014 char prev_sep; 2008 char prev_sep;
2015 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2009 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2016 VarParseResult res; 2010 VarParseResult res;
2017 2011
2018 args.ctx = st->ctxt; 2012 args.ctx = st->ctxt;
2019 2013
2020 (*pp)++; /* Skip the first '@' */ 2014 (*pp)++; /* Skip the first '@' */
2021 res = ParseModifierPart(pp, '@', eflags, st, 2015 res = ParseModifierPart(pp, '@', eflags, st,
2022 &args.tvar, NULL, NULL, NULL); 2016 &args.tvar, NULL, NULL, NULL);
2023 if (res != VPR_OK) 2017 if (res != VPR_OK)
2024 return AMR_CLEANUP; 2018 return AMR_CLEANUP;
2025 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) { 2019 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) {
2026 Parse_Error(PARSE_FATAL, 2020 Parse_Error(PARSE_FATAL,
2027 "In the :@ modifier of \"%s\", the variable name \"%s\" " 2021 "In the :@ modifier of \"%s\", the variable name \"%s\" "
2028 "must not contain a dollar.", 2022 "must not contain a dollar.",
2029 st->v->name, args.tvar); 2023 st->v->name, args.tvar);
2030 return AMR_CLEANUP; 2024 return AMR_CLEANUP;
2031 } 2025 }
2032 2026
2033 res = ParseModifierPart(pp, '@', eflags, st, 2027 res = ParseModifierPart(pp, '@', eflags, st,
2034 &args.str, NULL, NULL, NULL); 2028 &args.str, NULL, NULL, NULL);
2035 if (res != VPR_OK) 2029 if (res != VPR_OK)
2036 return AMR_CLEANUP; 2030 return AMR_CLEANUP;
2037 2031
2038 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2032 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2039 prev_sep = st->sep; 2033 prev_sep = st->sep;
2040 st->sep = ' '; /* XXX: should be st->sep for consistency */ 2034 st->sep = ' '; /* XXX: should be st->sep for consistency */
2041 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2035 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2042 ModifyWord_Loop, &args); 2036 ModifyWord_Loop, &args);
2043 st->sep = prev_sep; 2037 st->sep = prev_sep;
2044 Var_Delete(args.tvar, st->ctxt); 2038 Var_Delete(args.tvar, st->ctxt);
2045 free(args.tvar); 2039 free(args.tvar);
2046 free(args.str); 2040 free(args.str);
2047 return AMR_OK; 2041 return AMR_OK;
2048} 2042}
2049 2043
2050/* :Ddefined or :Uundefined */ 2044/* :Ddefined or :Uundefined */
2051static ApplyModifierResult 2045static ApplyModifierResult
2052ApplyModifier_Defined(const char **pp, ApplyModifiersState *st) 2046ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
2053{ 2047{
2054 Buffer buf; 2048 Buffer buf;
2055 const char *p; 2049 const char *p;
2056 2050
2057 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2051 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2058 if (st->eflags & VARE_WANTRES) { 2052 if (st->eflags & VARE_WANTRES) {
2059 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF)) 2053 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
2060 eflags |= VARE_WANTRES; 2054 eflags |= VARE_WANTRES;
2061 } 2055 }
2062 2056
2063 Buf_Init(&buf, 0); 2057 Buf_Init(&buf, 0);
2064 p = *pp + 1; 2058 p = *pp + 1;
2065 while (*p != st->endc && *p != ':' && *p != '\0') { 2059 while (*p != st->endc && *p != ':' && *p != '\0') {
2066 2060
2067 /* Escaped delimiter or other special character */ 2061 /* Escaped delimiter or other special character */
2068 if (*p == '\\') { 2062 if (*p == '\\') {
2069 char c = p[1]; 2063 char c = p[1];
2070 if (c == st->endc || c == ':' || c == '$' || c == '\\') { 2064 if (c == st->endc || c == ':' || c == '$' || c == '\\') {
2071 Buf_AddByte(&buf, c); 2065 Buf_AddByte(&buf, c);
2072 p += 2; 2066 p += 2;
2073 continue; 2067 continue;
2074 } 2068 }
2075 } 2069 }
2076 2070
2077 /* Nested variable expression */ 2071 /* Nested variable expression */
2078 if (*p == '$') { 2072 if (*p == '$') {
2079 const char *nested_val; 2073 const char *nested_val;
2080 void *nested_val_freeIt; 2074 void *nested_val_freeIt;
2081 2075
2082 (void)Var_Parse(&p, st->ctxt, eflags, 2076 (void)Var_Parse(&p, st->ctxt, eflags,
2083 &nested_val, &nested_val_freeIt); 2077 &nested_val, &nested_val_freeIt);
2084 /* TODO: handle errors */ 2078 /* TODO: handle errors */
2085 Buf_AddStr(&buf, nested_val); 2079 Buf_AddStr(&buf, nested_val);
2086 free(nested_val_freeIt); 2080 free(nested_val_freeIt);
2087 continue; 2081 continue;
2088 } 2082 }
2089 2083
2090 /* Ordinary text */ 2084 /* Ordinary text */
2091 Buf_AddByte(&buf, *p); 2085 Buf_AddByte(&buf, *p);
2092 p++; 2086 p++;
2093 } 2087 }
2094 *pp = p; 2088 *pp = p;
2095 2089
2096 ApplyModifiersState_Define(st); 2090 ApplyModifiersState_Define(st);
2097 2091
2098 if (eflags & VARE_WANTRES) { 2092 if (eflags & VARE_WANTRES) {
2099 st->newVal = Buf_Destroy(&buf, FALSE); 2093 st->newVal = Buf_Destroy(&buf, FALSE);
2100 } else { 2094 } else {
2101 st->newVal = st->val; 2095 st->newVal = st->val;
2102 Buf_Destroy(&buf, TRUE); 2096 Buf_Destroy(&buf, TRUE);
2103 } 2097 }
2104 return AMR_OK; 2098 return AMR_OK;
2105} 2099}
2106 2100
2107/* :L */ 2101/* :L */
2108static ApplyModifierResult 2102static ApplyModifierResult
2109ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) 2103ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2110{ 2104{
2111 ApplyModifiersState_Define(st); 2105 ApplyModifiersState_Define(st);
2112 st->newVal = bmake_strdup(st->v->name); 2106 st->newVal = bmake_strdup(st->v->name);
2113 (*pp)++; 2107 (*pp)++;
2114 return AMR_OK; 2108 return AMR_OK;
2115} 2109}
2116 2110
2117/* :gmtime */ 2111/* :gmtime */
2118static ApplyModifierResult 2112static ApplyModifierResult
2119ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st) 2113ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
2120{ 2114{
2121 time_t utc; 2115 time_t utc;
2122 2116
2123 const char *mod = *pp; 2117 const char *mod = *pp;
2124 if (!ModMatchEq(mod, "gmtime", st->endc)) 2118 if (!ModMatchEq(mod, "gmtime", st->endc))
2125 return AMR_UNKNOWN; 2119 return AMR_UNKNOWN;
2126 2120
2127 if (mod[6] == '=') { 2121 if (mod[6] == '=') {
2128 char *ep; 2122 char *ep;
2129 utc = (time_t)strtoul(mod + 7, &ep, 10); 2123 utc = (time_t)strtoul(mod + 7, &ep, 10);
2130 *pp = ep; 2124 *pp = ep;
2131 } else { 2125 } else {
2132 utc = 0; 2126 utc = 0;
2133 *pp = mod + 6; 2127 *pp = mod + 6;
2134 } 2128 }
2135 st->newVal = VarStrftime(st->val, TRUE, utc); 2129 st->newVal = VarStrftime(st->val, TRUE, utc);
2136 return AMR_OK; 2130 return AMR_OK;
2137} 2131}
2138 2132
2139/* :localtime */ 2133/* :localtime */
2140static ApplyModifierResult 2134static ApplyModifierResult
2141ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) 2135ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
2142{ 2136{
2143 time_t utc; 2137 time_t utc;
2144 2138
2145 const char *mod = *pp; 2139 const char *mod = *pp;
2146 if (!ModMatchEq(mod, "localtime", st->endc)) 2140 if (!ModMatchEq(mod, "localtime", st->endc))
2147 return AMR_UNKNOWN; 2141 return AMR_UNKNOWN;
2148 2142
2149 if (mod[9] == '=') { 2143 if (mod[9] == '=') {
2150 char *ep; 2144 char *ep;
2151 utc = (time_t)strtoul(mod + 10, &ep, 10); 2145 utc = (time_t)strtoul(mod + 10, &ep, 10);
2152 *pp = ep; 2146 *pp = ep;
2153 } else { 2147 } else {
2154 utc = 0; 2148 utc = 0;
2155 *pp = mod + 9; 2149 *pp = mod + 9;
2156 } 2150 }
2157 st->newVal = VarStrftime(st->val, FALSE, utc); 2151 st->newVal = VarStrftime(st->val, FALSE, utc);
2158 return AMR_OK; 2152 return AMR_OK;
2159} 2153}
2160 2154
2161/* :hash */ 2155/* :hash */
2162static ApplyModifierResult 2156static ApplyModifierResult
2163ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) 2157ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
2164{ 2158{
2165 if (!ModMatch(*pp, "hash", st->endc)) 2159 if (!ModMatch(*pp, "hash", st->endc))
2166 return AMR_UNKNOWN; 2160 return AMR_UNKNOWN;
2167 2161
2168 st->newVal = VarHash(st->val); 2162 st->newVal = VarHash(st->val);
2169 *pp += 4; 2163 *pp += 4;
2170 return AMR_OK; 2164 return AMR_OK;
2171} 2165}
2172 2166
2173/* :P */ 2167/* :P */
2174static ApplyModifierResult 2168static ApplyModifierResult
2175ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2169ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2176{ 2170{
2177 GNode *gn; 2171 GNode *gn;
2178 char *path; 2172 char *path;
2179 2173
2180 ApplyModifiersState_Define(st); 2174 ApplyModifiersState_Define(st);
2181 2175
2182 gn = Targ_FindNode(st->v->name); 2176 gn = Targ_FindNode(st->v->name);
2183 if (gn == NULL || gn->type & OP_NOPATH) { 2177 if (gn == NULL || gn->type & OP_NOPATH) {
2184 path = NULL; 2178 path = NULL;
2185 } else if (gn->path != NULL) { 2179 } else if (gn->path != NULL) {
2186 path = bmake_strdup(gn->path); 2180 path = bmake_strdup(gn->path);
2187 } else { 2181 } else {
2188 SearchPath *searchPath = Suff_FindPath(gn); 2182 SearchPath *searchPath = Suff_FindPath(gn);
2189 path = Dir_FindFile(st->v->name, searchPath); 2183 path = Dir_FindFile(st->v->name, searchPath);
2190 } 2184 }
2191 if (path == NULL) 2185 if (path == NULL)
2192 path = bmake_strdup(st->v->name); 2186 path = bmake_strdup(st->v->name);
2193 st->newVal = path; 2187 st->newVal = path;
2194 2188
2195 (*pp)++; 2189 (*pp)++;
2196 return AMR_OK; 2190 return AMR_OK;
2197} 2191}
2198 2192
2199/* :!cmd! */ 2193/* :!cmd! */
2200static ApplyModifierResult 2194static ApplyModifierResult
2201ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2195ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2202{ 2196{
2203 char *cmd; 2197 char *cmd;
2204 const char *errfmt; 2198 const char *errfmt;
2205 VarParseResult res; 2199 VarParseResult res;
2206 2200
2207 (*pp)++; 2201 (*pp)++;
2208 res = ParseModifierPart(pp, '!', st->eflags, st, 2202 res = ParseModifierPart(pp, '!', st->eflags, st,
2209 &cmd, NULL, NULL, NULL); 2203 &cmd, NULL, NULL, NULL);
2210 if (res != VPR_OK) 2204 if (res != VPR_OK)
2211 return AMR_CLEANUP; 2205 return AMR_CLEANUP;
2212 2206
2213 errfmt = NULL; 2207 errfmt = NULL;
2214 if (st->eflags & VARE_WANTRES) 2208 if (st->eflags & VARE_WANTRES)
2215 st->newVal = Cmd_Exec(cmd, &errfmt); 2209 st->newVal = Cmd_Exec(cmd, &errfmt);
2216 else 2210 else
2217 st->newVal = emptyString; 2211 st->newVal = emptyString;
2218 free(cmd); 2212 free(cmd);
2219 2213
2220 if (errfmt != NULL) 2214 if (errfmt != NULL)
2221 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2215 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2222 2216
2223 ApplyModifiersState_Define(st); 2217 ApplyModifiersState_Define(st);
2224 return AMR_OK; 2218 return AMR_OK;
2225} 2219}
2226 2220
2227/* The :range modifier generates an integer sequence as long as the words. 2221/* The :range modifier generates an integer sequence as long as the words.
2228 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2222 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2229static ApplyModifierResult 2223static ApplyModifierResult
2230ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2224ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2231{ 2225{
2232 size_t n; 2226 size_t n;
2233 Buffer buf; 2227 Buffer buf;
2234 size_t i; 2228 size_t i;
2235 2229
2236 const char *mod = *pp; 2230 const char *mod = *pp;
2237 if (!ModMatchEq(mod, "range", st->endc)) 2231 if (!ModMatchEq(mod, "range", st->endc))
2238 return AMR_UNKNOWN; 2232 return AMR_UNKNOWN;
2239 2233
2240 if (mod[5] == '=') { 2234 if (mod[5] == '=') {
2241 char *ep; 2235 char *ep;
2242 n = (size_t)strtoul(mod + 6, &ep, 10); 2236 n = (size_t)strtoul(mod + 6, &ep, 10);
2243 *pp = ep; 2237 *pp = ep;
2244 } else { 2238 } else {
2245 n = 0; 2239 n = 0;
2246 *pp = mod + 5; 2240 *pp = mod + 5;
2247 } 2241 }
2248 2242
2249 if (n == 0) { 2243 if (n == 0) {
2250 Words words = Str_Words(st->val, FALSE); 2244 Words words = Str_Words(st->val, FALSE);
2251 n = words.len; 2245 n = words.len;
2252 Words_Free(words); 2246 Words_Free(words);
2253 } 2247 }
2254 2248
2255 Buf_Init(&buf, 0); 2249 Buf_Init(&buf, 0);
2256 2250
2257 for (i = 0; i < n; i++) { 2251 for (i = 0; i < n; i++) {
2258 if (i != 0) 2252 if (i != 0)
2259 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2253 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2260 Buf_AddInt(&buf, 1 + (int)i); 2254 Buf_AddInt(&buf, 1 + (int)i);
2261 } 2255 }
2262 2256
2263 st->newVal = Buf_Destroy(&buf, FALSE); 2257 st->newVal = Buf_Destroy(&buf, FALSE);
2264 return AMR_OK; 2258 return AMR_OK;
2265} 2259}
2266 2260
2267/* :Mpattern or :Npattern */ 2261/* :Mpattern or :Npattern */
2268static ApplyModifierResult 2262static ApplyModifierResult
2269ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2263ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2270{ 2264{
2271 const char *mod = *pp; 2265 const char *mod = *pp;
2272 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2266 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2273 Boolean needSubst = FALSE; 2267 Boolean needSubst = FALSE;
2274 const char *endpat; 2268 const char *endpat;
2275 char *pattern; 2269 char *pattern;
2276 ModifyWordsCallback callback; 2270 ModifyWordsCallback callback;
2277 2271
2278 /* 2272 /*
2279 * In the loop below, ignore ':' unless we are at (or back to) the 2273 * In the loop below, ignore ':' unless we are at (or back to) the
2280 * original brace level. 2274 * original brace level.
2281 * XXX This will likely not work right if $() and ${} are intermixed. 2275 * XXX This will likely not work right if $() and ${} are intermixed.
2282 */ 2276 */
2283 int nest = 0; 2277 int nest = 0;
2284 const char *p; 2278 const char *p;
2285 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2279 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2286 if (*p == '\\' && 2280 if (*p == '\\' &&
2287 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2281 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2288 if (!needSubst) 2282 if (!needSubst)
2289 copy = TRUE; 2283 copy = TRUE;
2290 p++; 2284 p++;
2291 continue; 2285 continue;
2292 } 2286 }
2293 if (*p == '$') 2287 if (*p == '$')
2294 needSubst = TRUE; 2288 needSubst = TRUE;
2295 if (*p == '(' || *p == '{') 2289 if (*p == '(' || *p == '{')
2296 nest++; 2290 nest++;
2297 if (*p == ')' || *p == '}') { 2291 if (*p == ')' || *p == '}') {
2298 nest--; 2292 nest--;
2299 if (nest < 0) 2293 if (nest < 0)
2300 break; 2294 break;
2301 } 2295 }
2302 } 2296 }
2303 *pp = p; 2297 *pp = p;
2304 endpat = p; 2298 endpat = p;
2305 2299
2306 if (copy) { 2300 if (copy) {
2307 char *dst; 2301 char *dst;
2308 const char *src; 2302 const char *src;