Fri Oct 30 06:59:12 2020 UTC ()
make(1): rename SAVE_DOLLARS to follow the naming conventions


(rillig)
diff -r1.592 -r1.593 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/30 06:44:57 1.592
+++ src/usr.bin/make/var.c 2020/10/30 06:59:12 1.593
@@ -1,1859 +1,1860 @@ @@ -1,1859 +1,1860 @@
1/* $NetBSD: var.c,v 1.592 2020/10/30 06:44:57 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.593 2020/10/30 06:59:12 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.592 2020/10/30 06:44:57 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.593 2020/10/30 06:59:12 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 we consume $$ during := like any other expansion. 165 * Traditionally this make consumed $$ during := like any other expansion.
166 * Other make's do not. 166 * Other make's do not, and this make follows straight since 2016-01-09.
 167 *
167 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
168 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
169 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
170 */ 171 */
171#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
172static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
173 174
174/* 175/*
175 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
176 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
177 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
178 * context. 179 * context.
179 * 2) the global context. Variables set in the Makefile are located in 180 * 2) the global context. Variables set in the Makefile are located in
180 * the global context. 181 * the global context.
181 * 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
182 * are placed in this context. They are UNALTERABLE once placed here. 183 * are placed in this context. They are UNALTERABLE once placed here.
183 * 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
184 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
185 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
186 * 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
187 * listed (but see opts.checkEnvFirst). 188 * listed (but see opts.checkEnvFirst).
188 */ 189 */
189GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
190GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
191GNode *VAR_CMD; /* variables defined on the command-line */ 192GNode *VAR_CMD; /* variables defined on the command-line */
192 193
193typedef enum VarFindFlags { 194typedef enum VarFindFlags {
194 FIND_CMD = 0x01, /* look in VAR_CMD when searching */ 195 FIND_CMD = 0x01, /* look in VAR_CMD when searching */
195 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ 196 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */
196 FIND_ENV = 0x04 /* look in the environment also */ 197 FIND_ENV = 0x04 /* look in the environment also */
197} VarFindFlags; 198} VarFindFlags;
198 199
199typedef enum VarFlags { 200typedef enum VarFlags {
200 /* The variable's value is currently being used by Var_Parse or Var_Subst. 201 /* The variable's value is currently being used by Var_Parse or Var_Subst.
201 * This marker is used to avoid endless recursion. */ 202 * This marker is used to avoid endless recursion. */
202 VAR_IN_USE = 0x01, 203 VAR_IN_USE = 0x01,
203 /* The variable comes from the environment. 204 /* The variable comes from the environment.
204 * These variables are not registered in any GNode, therefore they must 205 * These variables are not registered in any GNode, therefore they must
205 * be freed as soon as they are not used anymore. */ 206 * be freed as soon as they are not used anymore. */
206 VAR_FROM_ENV = 0x02, 207 VAR_FROM_ENV = 0x02,
207 /* The variable is exported to the environment, to be used by child 208 /* The variable is exported to the environment, to be used by child
208 * processes. */ 209 * processes. */
209 VAR_EXPORTED = 0x10, 210 VAR_EXPORTED = 0x10,
210 /* At the point where this variable was exported, it contained an 211 /* At the point where this variable was exported, it contained an
211 * unresolved reference to another variable. Before any child process is 212 * unresolved reference to another variable. Before any child process is
212 * started, it needs to be exported again, in the hope that the referenced 213 * started, it needs to be exported again, in the hope that the referenced
213 * variable can then be resolved. */ 214 * variable can then be resolved. */
214 VAR_REEXPORT = 0x20, 215 VAR_REEXPORT = 0x20,
215 /* The variable came from command line. */ 216 /* The variable came from command line. */
216 VAR_FROM_CMD = 0x40, 217 VAR_FROM_CMD = 0x40,
217 VAR_READONLY = 0x80 218 VAR_READONLY = 0x80
218} VarFlags; 219} VarFlags;
219 220
220ENUM_FLAGS_RTTI_6(VarFlags, 221ENUM_FLAGS_RTTI_6(VarFlags,
221 VAR_IN_USE, VAR_FROM_ENV, 222 VAR_IN_USE, VAR_FROM_ENV,
222 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 223 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
223 224
224/* Variables are defined using one of the VAR=value assignments. Their 225/* Variables are defined using one of the VAR=value assignments. Their
225 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 226 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
226 * such as ${VAR:S,from,to,g:Q}. 227 * such as ${VAR:S,from,to,g:Q}.
227 * 228 *
228 * There are 3 kinds of variables: context variables, environment variables, 229 * There are 3 kinds of variables: context variables, environment variables,
229 * undefined variables. 230 * undefined variables.
230 * 231 *
231 * Context variables are stored in a GNode.context. The only way to undefine 232 * Context variables are stored in a GNode.context. The only way to undefine
232 * a context variable is using the .undef directive. In particular, it must 233 * a context variable is using the .undef directive. In particular, it must
233 * not be possible to undefine a variable during the evaluation of an 234 * not be possible to undefine a variable during the evaluation of an
234 * expression, or Var.name might point nowhere. 235 * expression, or Var.name might point nowhere.
235 * 236 *
236 * Environment variables are temporary. They are returned by VarFind, and 237 * Environment variables are temporary. They are returned by VarFind, and
237 * after using them, they must be freed using VarFreeEnv. 238 * after using them, they must be freed using VarFreeEnv.
238 * 239 *
239 * Undefined variables occur during evaluation of variable expressions such 240 * Undefined variables occur during evaluation of variable expressions such
240 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 241 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
241 */ 242 */
242typedef struct Var { 243typedef struct Var {
243 /* The name of the variable, once set, doesn't change anymore. 244 /* The name of the variable, once set, doesn't change anymore.
244 * For context variables, it aliases the corresponding HashEntry name. 245 * For context variables, it aliases the corresponding HashEntry name.
245 * For environment and undefined variables, it is allocated. */ 246 * For environment and undefined variables, it is allocated. */
246 const char *name; 247 const char *name;
247 void *name_freeIt; 248 void *name_freeIt;
248 249
249 Buffer val; /* its value */ 250 Buffer val; /* its value */
250 VarFlags flags; /* miscellaneous status flags */ 251 VarFlags flags; /* miscellaneous status flags */
251} Var; 252} Var;
252 253
253/* 254/*
254 * Exporting vars is expensive so skip it if we can 255 * Exporting vars is expensive so skip it if we can
255 */ 256 */
256typedef enum VarExportedMode { 257typedef enum VarExportedMode {
257 VAR_EXPORTED_NONE, 258 VAR_EXPORTED_NONE,
258 VAR_EXPORTED_YES, 259 VAR_EXPORTED_YES,
259 VAR_EXPORTED_ALL 260 VAR_EXPORTED_ALL
260} VarExportedMode; 261} VarExportedMode;
261 262
262static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 263static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
263 264
264typedef enum VarExportFlags { 265typedef enum VarExportFlags {
265 /* 266 /*
266 * We pass this to Var_Export when doing the initial export 267 * We pass this to Var_Export when doing the initial export
267 * or after updating an exported var. 268 * or after updating an exported var.
268 */ 269 */
269 VAR_EXPORT_PARENT = 0x01, 270 VAR_EXPORT_PARENT = 0x01,
270 /* 271 /*
271 * We pass this to Var_Export1 to tell it to leave the value alone. 272 * We pass this to Var_Export1 to tell it to leave the value alone.
272 */ 273 */
273 VAR_EXPORT_LITERAL = 0x02 274 VAR_EXPORT_LITERAL = 0x02
274} VarExportFlags; 275} VarExportFlags;
275 276
276/* Flags for pattern matching in the :S and :C modifiers */ 277/* Flags for pattern matching in the :S and :C modifiers */
277typedef enum VarPatternFlags { 278typedef enum VarPatternFlags {
278 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */ 279 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */
279 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */ 280 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */
280 VARP_ANCHOR_START = 0x04, /* Match at start of word */ 281 VARP_ANCHOR_START = 0x04, /* Match at start of word */
281 VARP_ANCHOR_END = 0x08 /* Match at end of word */ 282 VARP_ANCHOR_END = 0x08 /* Match at end of word */
282} VarPatternFlags; 283} VarPatternFlags;
283 284
284static Var * 285static Var *
285VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 286VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
286{ 287{
287 size_t value_len = strlen(value); 288 size_t value_len = strlen(value);
288 Var *var = bmake_malloc(sizeof *var); 289 Var *var = bmake_malloc(sizeof *var);
289 var->name = name; 290 var->name = name;
290 var->name_freeIt = name_freeIt; 291 var->name_freeIt = name_freeIt;
291 Buf_Init(&var->val, value_len + 1); 292 Buf_Init(&var->val, value_len + 1);
292 Buf_AddBytes(&var->val, value, value_len); 293 Buf_AddBytes(&var->val, value, value_len);
293 var->flags = flags; 294 var->flags = flags;
294 return var; 295 return var;
295} 296}
296 297
297static const char * 298static const char *
298CanonicalVarname(const char *name) 299CanonicalVarname(const char *name)
299{ 300{
300 if (*name == '.' && ch_isupper(name[1])) { 301 if (*name == '.' && ch_isupper(name[1])) {
301 switch (name[1]) { 302 switch (name[1]) {
302 case 'A': 303 case 'A':
303 if (strcmp(name, ".ALLSRC") == 0) 304 if (strcmp(name, ".ALLSRC") == 0)
304 name = ALLSRC; 305 name = ALLSRC;
305 if (strcmp(name, ".ARCHIVE") == 0) 306 if (strcmp(name, ".ARCHIVE") == 0)
306 name = ARCHIVE; 307 name = ARCHIVE;
307 break; 308 break;
308 case 'I': 309 case 'I':
309 if (strcmp(name, ".IMPSRC") == 0) 310 if (strcmp(name, ".IMPSRC") == 0)
310 name = IMPSRC; 311 name = IMPSRC;
311 break; 312 break;
312 case 'M': 313 case 'M':
313 if (strcmp(name, ".MEMBER") == 0) 314 if (strcmp(name, ".MEMBER") == 0)
314 name = MEMBER; 315 name = MEMBER;
315 break; 316 break;
316 case 'O': 317 case 'O':
317 if (strcmp(name, ".OODATE") == 0) 318 if (strcmp(name, ".OODATE") == 0)
318 name = OODATE; 319 name = OODATE;
319 break; 320 break;
320 case 'P': 321 case 'P':
321 if (strcmp(name, ".PREFIX") == 0) 322 if (strcmp(name, ".PREFIX") == 0)
322 name = PREFIX; 323 name = PREFIX;
323 break; 324 break;
324 case 'S': 325 case 'S':
325 if (strcmp(name, ".SHELL") == 0) { 326 if (strcmp(name, ".SHELL") == 0) {
326 if (!shellPath) 327 if (!shellPath)
327 Shell_Init(); 328 Shell_Init();
328 } 329 }
329 break; 330 break;
330 case 'T': 331 case 'T':
331 if (strcmp(name, ".TARGET") == 0) 332 if (strcmp(name, ".TARGET") == 0)
332 name = TARGET; 333 name = TARGET;
333 break; 334 break;
334 } 335 }
335 } 336 }
336 337
337 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 338 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
338 339
339 return name; 340 return name;
340} 341}
341 342
342static Var * 343static Var *
343GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 344GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
344{ 345{
345 return HashTable_FindValueHash(&ctxt->context, varname, hash); 346 return HashTable_FindValueHash(&ctxt->context, varname, hash);
346} 347}
347 348
348/*- 349/*-
349 *----------------------------------------------------------------------- 350 *-----------------------------------------------------------------------
350 * VarFind -- 351 * VarFind --
351 * Find the given variable in the given context and any other contexts 352 * Find the given variable in the given context and any other contexts
352 * indicated. 353 * indicated.
353 * 354 *
354 * Input: 355 * Input:
355 * name name to find 356 * name name to find
356 * ctxt context in which to find it 357 * ctxt context in which to find it
357 * flags FIND_GLOBAL look in VAR_GLOBAL as well 358 * flags FIND_GLOBAL look in VAR_GLOBAL as well
358 * FIND_CMD look in VAR_CMD as well 359 * FIND_CMD look in VAR_CMD as well
359 * FIND_ENV look in the environment as well 360 * FIND_ENV look in the environment as well
360 * 361 *
361 * Results: 362 * Results:
362 * A pointer to the structure describing the desired variable or 363 * A pointer to the structure describing the desired variable or
363 * NULL if the variable does not exist. 364 * NULL if the variable does not exist.
364 *----------------------------------------------------------------------- 365 *-----------------------------------------------------------------------
365 */ 366 */
366static Var * 367static Var *
367VarFind(const char *name, GNode *ctxt, VarFindFlags flags) 368VarFind(const char *name, GNode *ctxt, VarFindFlags flags)
368{ 369{
369 Var *var; 370 Var *var;
370 unsigned int nameHash; 371 unsigned int nameHash;
371 372
372 /* 373 /*
373 * If the variable name begins with a '.', it could very well be one of 374 * If the variable name begins with a '.', it could very well be one of
374 * the local ones. We check the name against all the local variables 375 * the local ones. We check the name against all the local variables
375 * and substitute the short version in for 'name' if it matches one of 376 * and substitute the short version in for 'name' if it matches one of
376 * them. 377 * them.
377 */ 378 */
378 name = CanonicalVarname(name); 379 name = CanonicalVarname(name);
379 nameHash = Hash_Hash(name); 380 nameHash = Hash_Hash(name);
380 381
381 /* 382 /*
382 * First look for the variable in the given context. If it's not there, 383 * First look for the variable in the given context. If it's not there,
383 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 384 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
384 * depending on the FIND_* flags in 'flags' 385 * depending on the FIND_* flags in 'flags'
385 */ 386 */
386 var = GNode_FindVar(ctxt, name, nameHash); 387 var = GNode_FindVar(ctxt, name, nameHash);
387 388
388 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) 389 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD)
389 var = GNode_FindVar(VAR_CMD, name, nameHash); 390 var = GNode_FindVar(VAR_CMD, name, nameHash);
390 391
391 if (!opts.checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && 392 if (!opts.checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
392 ctxt != VAR_GLOBAL) 393 ctxt != VAR_GLOBAL)
393 { 394 {
394 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 395 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
395 if (var == NULL && ctxt != VAR_INTERNAL) { 396 if (var == NULL && ctxt != VAR_INTERNAL) {
396 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 397 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
397 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 398 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
398 } 399 }
399 } 400 }
400 401
401 if (var == NULL && (flags & FIND_ENV)) { 402 if (var == NULL && (flags & FIND_ENV)) {
402 char *env; 403 char *env;
403 404
404 if ((env = getenv(name)) != NULL) { 405 if ((env = getenv(name)) != NULL) {
405 char *varname = bmake_strdup(name); 406 char *varname = bmake_strdup(name);
406 return VarNew(varname, varname, env, VAR_FROM_ENV); 407 return VarNew(varname, varname, env, VAR_FROM_ENV);
407 } 408 }
408 409
409 if (opts.checkEnvFirst && (flags & FIND_GLOBAL) && ctxt != VAR_GLOBAL) { 410 if (opts.checkEnvFirst && (flags & FIND_GLOBAL) && ctxt != VAR_GLOBAL) {
410 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 411 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
411 if (var == NULL && ctxt != VAR_INTERNAL) 412 if (var == NULL && ctxt != VAR_INTERNAL)
412 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 413 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
413 return var; 414 return var;
414 } 415 }
415 416
416 return NULL; 417 return NULL;
417 } 418 }
418 419
419 return var; 420 return var;
420} 421}
421 422
422/*- 423/*-
423 *----------------------------------------------------------------------- 424 *-----------------------------------------------------------------------
424 * VarFreeEnv -- 425 * VarFreeEnv --
425 * If the variable is an environment variable, free it 426 * If the variable is an environment variable, free it
426 * 427 *
427 * Input: 428 * Input:
428 * v the variable 429 * v the variable
429 * destroy true if the value buffer should be destroyed. 430 * destroy true if the value buffer should be destroyed.
430 * 431 *
431 * Results: 432 * Results:
432 * TRUE if it is an environment variable, FALSE otherwise. 433 * TRUE if it is an environment variable, FALSE otherwise.
433 *----------------------------------------------------------------------- 434 *-----------------------------------------------------------------------
434 */ 435 */
435static Boolean 436static Boolean
436VarFreeEnv(Var *v, Boolean destroy) 437VarFreeEnv(Var *v, Boolean destroy)
437{ 438{
438 if (!(v->flags & VAR_FROM_ENV)) 439 if (!(v->flags & VAR_FROM_ENV))
439 return FALSE; 440 return FALSE;
440 free(v->name_freeIt); 441 free(v->name_freeIt);
441 Buf_Destroy(&v->val, destroy); 442 Buf_Destroy(&v->val, destroy);
442 free(v); 443 free(v);
443 return TRUE; 444 return TRUE;
444} 445}
445 446
446/* Add a new variable of the given name and value to the given context. 447/* Add a new variable of the given name and value to the given context.
447 * The name and val arguments are duplicated so they may safely be freed. */ 448 * The name and val arguments are duplicated so they may safely be freed. */
448static void 449static void
449VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 450VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
450{ 451{
451 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 452 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
452 Var *v = VarNew(he->key, NULL, val, 453 Var *v = VarNew(he->key, NULL, val,
453 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 454 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
454 HashEntry_Set(he, v); 455 HashEntry_Set(he, v);
455 if (!(ctxt->flags & INTERNAL)) { 456 if (!(ctxt->flags & INTERNAL)) {
456 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 457 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
457 } 458 }
458} 459}
459 460
460/* Remove a variable from a context, freeing the Var structure as well. */ 461/* Remove a variable from a context, freeing the Var structure as well. */
461void 462void
462Var_Delete(const char *name, GNode *ctxt) 463Var_Delete(const char *name, GNode *ctxt)
463{ 464{
464 char *name_freeIt = NULL; 465 char *name_freeIt = NULL;
465 HashEntry *he; 466 HashEntry *he;
466 467
467 if (strchr(name, '$') != NULL) { 468 if (strchr(name, '$') != NULL) {
468 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 469 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
469 /* TODO: handle errors */ 470 /* TODO: handle errors */
470 name = name_freeIt; 471 name = name_freeIt;
471 } 472 }
472 he = HashTable_FindEntry(&ctxt->context, name); 473 he = HashTable_FindEntry(&ctxt->context, name);
473 VAR_DEBUG3("%s:delete %s%s\n", 474 VAR_DEBUG3("%s:delete %s%s\n",
474 ctxt->name, name, he != NULL ? "" : " (not found)"); 475 ctxt->name, name, he != NULL ? "" : " (not found)");
475 free(name_freeIt); 476 free(name_freeIt);
476 477
477 if (he != NULL) { 478 if (he != NULL) {
478 Var *v = HashEntry_Get(he); 479 Var *v = HashEntry_Get(he);
479 if (v->flags & VAR_EXPORTED) 480 if (v->flags & VAR_EXPORTED)
480 unsetenv(v->name); 481 unsetenv(v->name);
481 if (strcmp(v->name, MAKE_EXPORTED) == 0) 482 if (strcmp(v->name, MAKE_EXPORTED) == 0)
482 var_exportedVars = VAR_EXPORTED_NONE; 483 var_exportedVars = VAR_EXPORTED_NONE;
483 assert(v->name_freeIt == NULL); 484 assert(v->name_freeIt == NULL);
484 HashTable_DeleteEntry(&ctxt->context, he); 485 HashTable_DeleteEntry(&ctxt->context, he);
485 Buf_Destroy(&v->val, TRUE); 486 Buf_Destroy(&v->val, TRUE);
486 free(v); 487 free(v);
487 } 488 }
488} 489}
489 490
490 491
491/* 492/*
492 * Export a single variable. 493 * Export a single variable.
493 * We ignore make internal variables (those which start with '.'). 494 * We ignore make internal variables (those which start with '.').
494 * Also we jump through some hoops to avoid calling setenv 495 * Also we jump through some hoops to avoid calling setenv
495 * more than necessary since it can leak. 496 * more than necessary since it can leak.
496 * We only manipulate flags of vars if 'parent' is set. 497 * We only manipulate flags of vars if 'parent' is set.
497 */ 498 */
498static Boolean 499static Boolean
499Var_Export1(const char *name, VarExportFlags flags) 500Var_Export1(const char *name, VarExportFlags flags)
500{ 501{
501 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 502 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
502 Var *v; 503 Var *v;
503 char *val; 504 char *val;
504 505
505 if (name[0] == '.') 506 if (name[0] == '.')
506 return FALSE; /* skip internals */ 507 return FALSE; /* skip internals */
507 if (name[0] == '-') 508 if (name[0] == '-')
508 return FALSE; /* skip misnamed variables */ 509 return FALSE; /* skip misnamed variables */
509 if (name[1] == '\0') { 510 if (name[1] == '\0') {
510 /* 511 /*
511 * A single char. 512 * A single char.
512 * If it is one of the vars that should only appear in 513 * If it is one of the vars that should only appear in
513 * local context, skip it, else we can get Var_Subst 514 * local context, skip it, else we can get Var_Subst
514 * into a loop. 515 * into a loop.
515 */ 516 */
516 switch (name[0]) { 517 switch (name[0]) {
517 case '@': 518 case '@':
518 case '%': 519 case '%':
519 case '*': 520 case '*':
520 case '!': 521 case '!':
521 return FALSE; 522 return FALSE;
522 } 523 }
523 } 524 }
524 525
525 v = VarFind(name, VAR_GLOBAL, 0); 526 v = VarFind(name, VAR_GLOBAL, 0);
526 if (v == NULL) 527 if (v == NULL)
527 return FALSE; 528 return FALSE;
528 529
529 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 530 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
530 return FALSE; /* nothing to do */ 531 return FALSE; /* nothing to do */
531 532
532 val = Buf_GetAll(&v->val, NULL); 533 val = Buf_GetAll(&v->val, NULL);
533 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 534 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
534 char *expr; 535 char *expr;
535 536
536 if (parent) { 537 if (parent) {
537 /* 538 /*
538 * Flag this as something we need to re-export. 539 * Flag this as something we need to re-export.
539 * No point actually exporting it now though, 540 * No point actually exporting it now though,
540 * the child can do it at the last minute. 541 * the child can do it at the last minute.
541 */ 542 */
542 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 543 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
543 return TRUE; 544 return TRUE;
544 } 545 }
545 if (v->flags & VAR_IN_USE) { 546 if (v->flags & VAR_IN_USE) {
546 /* 547 /*
547 * We recursed while exporting in a child. 548 * We recursed while exporting in a child.
548 * This isn't going to end well, just skip it. 549 * This isn't going to end well, just skip it.
549 */ 550 */
550 return FALSE; 551 return FALSE;
551 } 552 }
552 553
553 expr = str_concat3("${", name, "}"); 554 expr = str_concat3("${", name, "}");
554 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 555 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
555 /* TODO: handle errors */ 556 /* TODO: handle errors */
556 setenv(name, val, 1); 557 setenv(name, val, 1);
557 free(val); 558 free(val);
558 free(expr); 559 free(expr);
559 } else { 560 } else {
560 if (parent) 561 if (parent)
561 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 562 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
562 if (parent || !(v->flags & VAR_EXPORTED)) 563 if (parent || !(v->flags & VAR_EXPORTED))
563 setenv(name, val, 1); 564 setenv(name, val, 1);
564 } 565 }
565 /* 566 /*
566 * This is so Var_Set knows to call Var_Export again... 567 * This is so Var_Set knows to call Var_Export again...
567 */ 568 */
568 if (parent) { 569 if (parent) {
569 v->flags |= VAR_EXPORTED; 570 v->flags |= VAR_EXPORTED;
570 } 571 }
571 return TRUE; 572 return TRUE;
572} 573}
573 574
574/* 575/*
575 * This gets called from our children. 576 * This gets called from our children.
576 */ 577 */
577void 578void
578Var_ExportVars(void) 579Var_ExportVars(void)
579{ 580{
580 char *val; 581 char *val;
581 582
582 /* 583 /*
583 * Several make's support this sort of mechanism for tracking 584 * Several make's support this sort of mechanism for tracking
584 * recursion - but each uses a different name. 585 * recursion - but each uses a different name.
585 * We allow the makefiles to update MAKELEVEL and ensure 586 * We allow the makefiles to update MAKELEVEL and ensure
586 * children see a correctly incremented value. 587 * children see a correctly incremented value.
587 */ 588 */
588 char tmp[BUFSIZ]; 589 char tmp[BUFSIZ];
589 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 590 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
590 setenv(MAKE_LEVEL_ENV, tmp, 1); 591 setenv(MAKE_LEVEL_ENV, tmp, 1);
591 592
592 if (var_exportedVars == VAR_EXPORTED_NONE) 593 if (var_exportedVars == VAR_EXPORTED_NONE)
593 return; 594 return;
594 595
595 if (var_exportedVars == VAR_EXPORTED_ALL) { 596 if (var_exportedVars == VAR_EXPORTED_ALL) {
596 HashIter hi; 597 HashIter hi;
597 HashEntry *he; 598 HashEntry *he;
598 599
599 /* Ouch! Exporting all variables at once is crazy... */ 600 /* Ouch! Exporting all variables at once is crazy... */
600 HashIter_Init(&hi, &VAR_GLOBAL->context); 601 HashIter_Init(&hi, &VAR_GLOBAL->context);
601 while ((he = HashIter_Next(&hi)) != NULL) { 602 while ((he = HashIter_Next(&hi)) != NULL) {
602 Var *var = HashEntry_Get(he); 603 Var *var = HashEntry_Get(he);
603 Var_Export1(var->name, 0); 604 Var_Export1(var->name, 0);
604 } 605 }
605 return; 606 return;
606 } 607 }
607 608
608 (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);
609 /* TODO: handle errors */ 610 /* TODO: handle errors */
610 if (*val) { 611 if (*val) {
611 Words words = Str_Words(val, FALSE); 612 Words words = Str_Words(val, FALSE);
612 size_t i; 613 size_t i;
613 614
614 for (i = 0; i < words.len; i++) 615 for (i = 0; i < words.len; i++)
615 Var_Export1(words.words[i], 0); 616 Var_Export1(words.words[i], 0);
616 Words_Free(words); 617 Words_Free(words);
617 } 618 }
618 free(val); 619 free(val);
619} 620}
620 621
621/* 622/*
622 * 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.
623 * 624 *
624 * It is also called when any exported variable is modified. 625 * It is also called when any exported variable is modified.
625 * XXX: Is it really? 626 * XXX: Is it really?
626 * 627 *
627 * str has the format "[-env|-literal] varname...". 628 * str has the format "[-env|-literal] varname...".
628 */ 629 */
629void 630void
630Var_Export(const char *str, Boolean isExport) 631Var_Export(const char *str, Boolean isExport)
631{ 632{
632 VarExportFlags flags; 633 VarExportFlags flags;
633 char *val; 634 char *val;
634 635
635 if (isExport && str[0] == '\0') { 636 if (isExport && str[0] == '\0') {
636 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 637 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
637 return; 638 return;
638 } 639 }
639 640
640 if (isExport && strncmp(str, "-env", 4) == 0) { 641 if (isExport && strncmp(str, "-env", 4) == 0) {
641 str += 4; 642 str += 4;
642 flags = 0; 643 flags = 0;
643 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 644 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
644 str += 8; 645 str += 8;
645 flags = VAR_EXPORT_LITERAL; 646 flags = VAR_EXPORT_LITERAL;
646 } else { 647 } else {
647 flags = VAR_EXPORT_PARENT; 648 flags = VAR_EXPORT_PARENT;
648 } 649 }
649 650
650 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 651 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
651 /* TODO: handle errors */ 652 /* TODO: handle errors */
652 if (val[0] != '\0') { 653 if (val[0] != '\0') {
653 Words words = Str_Words(val, FALSE); 654 Words words = Str_Words(val, FALSE);
654 655
655 size_t i; 656 size_t i;
656 for (i = 0; i < words.len; i++) { 657 for (i = 0; i < words.len; i++) {
657 const char *name = words.words[i]; 658 const char *name = words.words[i];
658 if (Var_Export1(name, flags)) { 659 if (Var_Export1(name, flags)) {
659 if (var_exportedVars != VAR_EXPORTED_ALL) 660 if (var_exportedVars != VAR_EXPORTED_ALL)
660 var_exportedVars = VAR_EXPORTED_YES; 661 var_exportedVars = VAR_EXPORTED_YES;
661 if (isExport && (flags & VAR_EXPORT_PARENT)) { 662 if (isExport && (flags & VAR_EXPORT_PARENT)) {
662 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 663 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
663 } 664 }
664 } 665 }
665 } 666 }
666 Words_Free(words); 667 Words_Free(words);
667 } 668 }
668 free(val); 669 free(val);
669} 670}
670 671
671 672
672extern char **environ; 673extern char **environ;
673 674
674/* 675/*
675 * This is called when .unexport[-env] is seen. 676 * This is called when .unexport[-env] is seen.
676 * 677 *
677 * str must have the form "unexport[-env] varname...". 678 * str must have the form "unexport[-env] varname...".
678 */ 679 */
679void 680void
680Var_UnExport(const char *str) 681Var_UnExport(const char *str)
681{ 682{
682 const char *varnames; 683 const char *varnames;
683 char *varnames_freeIt; 684 char *varnames_freeIt;
684 Boolean unexport_env; 685 Boolean unexport_env;
685 686
686 varnames = NULL; 687 varnames = NULL;
687 varnames_freeIt = NULL; 688 varnames_freeIt = NULL;
688 689
689 str += strlen("unexport"); 690 str += strlen("unexport");
690 unexport_env = strncmp(str, "-env", 4) == 0; 691 unexport_env = strncmp(str, "-env", 4) == 0;
691 if (unexport_env) { 692 if (unexport_env) {
692 const char *cp; 693 const char *cp;
693 char **newenv; 694 char **newenv;
694 695
695 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 696 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
696 if (environ == savedEnv) { 697 if (environ == savedEnv) {
697 /* we have been here before! */ 698 /* we have been here before! */
698 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 699 newenv = bmake_realloc(environ, 2 * sizeof(char *));
699 } else { 700 } else {
700 if (savedEnv) { 701 if (savedEnv) {
701 free(savedEnv); 702 free(savedEnv);
702 savedEnv = NULL; 703 savedEnv = NULL;
703 } 704 }
704 newenv = bmake_malloc(2 * sizeof(char *)); 705 newenv = bmake_malloc(2 * sizeof(char *));
705 } 706 }
706 707
707 /* Note: we cannot safely free() the original environ. */ 708 /* Note: we cannot safely free() the original environ. */
708 environ = savedEnv = newenv; 709 environ = savedEnv = newenv;
709 newenv[0] = NULL; 710 newenv[0] = NULL;
710 newenv[1] = NULL; 711 newenv[1] = NULL;
711 if (cp && *cp) 712 if (cp && *cp)
712 setenv(MAKE_LEVEL_ENV, cp, 1); 713 setenv(MAKE_LEVEL_ENV, cp, 1);
713 } else { 714 } else {
714 cpp_skip_whitespace(&str); 715 cpp_skip_whitespace(&str);
715 if (str[0] != '\0') 716 if (str[0] != '\0')
716 varnames = str; 717 varnames = str;
717 } 718 }
718 719
719 if (varnames == NULL) { 720 if (varnames == NULL) {
720 /* Using .MAKE.EXPORTED */ 721 /* Using .MAKE.EXPORTED */
721 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 722 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
722 &varnames_freeIt); 723 &varnames_freeIt);
723 /* TODO: handle errors */ 724 /* TODO: handle errors */
724 varnames = varnames_freeIt; 725 varnames = varnames_freeIt;
725 } 726 }
726 727
727 { 728 {
728 Var *v; 729 Var *v;
729 size_t i; 730 size_t i;
730 731
731 Words words = Str_Words(varnames, FALSE); 732 Words words = Str_Words(varnames, FALSE);
732 for (i = 0; i < words.len; i++) { 733 for (i = 0; i < words.len; i++) {
733 const char *varname = words.words[i]; 734 const char *varname = words.words[i];
734 v = VarFind(varname, VAR_GLOBAL, 0); 735 v = VarFind(varname, VAR_GLOBAL, 0);
735 if (v == NULL) { 736 if (v == NULL) {
736 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 737 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
737 continue; 738 continue;
738 } 739 }
739 740
740 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 741 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
741 if (!unexport_env && (v->flags & VAR_EXPORTED) && 742 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
742 !(v->flags & VAR_REEXPORT)) 743 !(v->flags & VAR_REEXPORT))
743 unsetenv(v->name); 744 unsetenv(v->name);
744 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 745 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
745 746
746 /* 747 /*
747 * If we are unexporting a list, 748 * If we are unexporting a list,
748 * remove each one from .MAKE.EXPORTED. 749 * remove each one from .MAKE.EXPORTED.
749 * If we are removing them all, 750 * If we are removing them all,
750 * just delete .MAKE.EXPORTED below. 751 * just delete .MAKE.EXPORTED below.
751 */ 752 */
752 if (varnames == str) { 753 if (varnames == str) {
753 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 754 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
754 char *cp; 755 char *cp;
755 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 756 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
756 /* TODO: handle errors */ 757 /* TODO: handle errors */
757 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 758 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
758 free(cp); 759 free(cp);
759 free(expr); 760 free(expr);
760 } 761 }
761 } 762 }
762 Words_Free(words); 763 Words_Free(words);
763 if (varnames != str) { 764 if (varnames != str) {
764 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 765 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
765 free(varnames_freeIt); 766 free(varnames_freeIt);
766 } 767 }
767 } 768 }
768} 769}
769 770
770/* See Var_Set for documentation. */ 771/* See Var_Set for documentation. */
771void 772void
772Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 773Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
773 VarSet_Flags flags) 774 VarSet_Flags flags)
774{ 775{
775 const char *unexpanded_name = name; 776 const char *unexpanded_name = name;
776 char *name_freeIt = NULL; 777 char *name_freeIt = NULL;
777 Var *v; 778 Var *v;
778 779
779 assert(val != NULL); 780 assert(val != NULL);
780 781
781 if (strchr(name, '$') != NULL) { 782 if (strchr(name, '$') != NULL) {
782 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 783 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
783 /* TODO: handle errors */ 784 /* TODO: handle errors */
784 name = name_freeIt; 785 name = name_freeIt;
785 } 786 }
786 787
787 if (name[0] == '\0') { 788 if (name[0] == '\0') {
788 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 789 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
789 "name expands to empty string - ignored\n", 790 "name expands to empty string - ignored\n",
790 unexpanded_name, val); 791 unexpanded_name, val);
791 free(name_freeIt); 792 free(name_freeIt);
792 return; 793 return;
793 } 794 }
794 795
795 if (ctxt == VAR_GLOBAL) { 796 if (ctxt == VAR_GLOBAL) {
796 v = VarFind(name, VAR_CMD, 0); 797 v = VarFind(name, VAR_CMD, 0);
797 if (v != NULL) { 798 if (v != NULL) {
798 if (v->flags & VAR_FROM_CMD) { 799 if (v->flags & VAR_FROM_CMD) {
799 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 800 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
800 goto out; 801 goto out;
801 } 802 }
802 VarFreeEnv(v, TRUE); 803 VarFreeEnv(v, TRUE);
803 } 804 }
804 } 805 }
805 806
806 /* 807 /*
807 * We only look for a variable in the given context since anything set 808 * We only look for a variable in the given context since anything set
808 * here will override anything in a lower context, so there's not much 809 * here will override anything in a lower context, so there's not much
809 * point in searching them all just to save a bit of memory... 810 * point in searching them all just to save a bit of memory...
810 */ 811 */
811 v = VarFind(name, ctxt, 0); 812 v = VarFind(name, ctxt, 0);
812 if (v == NULL) { 813 if (v == NULL) {
813 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT)) { 814 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT)) {
814 /* 815 /*
815 * This var would normally prevent the same name being added 816 * This var would normally prevent the same name being added
816 * to VAR_GLOBAL, so delete it from there if needed. 817 * to VAR_GLOBAL, so delete it from there if needed.
817 * Otherwise -V name may show the wrong value. 818 * Otherwise -V name may show the wrong value.
818 */ 819 */
819 Var_Delete(name, VAR_GLOBAL); 820 Var_Delete(name, VAR_GLOBAL);
820 } 821 }
821 VarAdd(name, val, ctxt, flags); 822 VarAdd(name, val, ctxt, flags);
822 } else { 823 } else {
823 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 824 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
824 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 825 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
825 ctxt->name, name, val); 826 ctxt->name, name, val);
826 goto out; 827 goto out;
827 }  828 }
828 Buf_Empty(&v->val); 829 Buf_Empty(&v->val);
829 if (val) 830 if (val)
830 Buf_AddStr(&v->val, val); 831 Buf_AddStr(&v->val, val);
831 832
832 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 833 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
833 if (v->flags & VAR_EXPORTED) { 834 if (v->flags & VAR_EXPORTED) {
834 Var_Export1(name, VAR_EXPORT_PARENT); 835 Var_Export1(name, VAR_EXPORT_PARENT);
835 } 836 }
836 } 837 }
837 /* 838 /*
838 * Any variables given on the command line are automatically exported 839 * Any variables given on the command line are automatically exported
839 * to the environment (as per POSIX standard) 840 * to the environment (as per POSIX standard)
840 * Other than internals. 841 * Other than internals.
841 */ 842 */
842 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 843 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
843 if (v == NULL) { 844 if (v == NULL) {
844 /* we just added it */ 845 /* we just added it */
845 v = VarFind(name, ctxt, 0); 846 v = VarFind(name, ctxt, 0);
846 } 847 }
847 if (v != NULL) 848 if (v != NULL)
848 v->flags |= VAR_FROM_CMD; 849 v->flags |= VAR_FROM_CMD;
849 /* 850 /*
850 * If requested, don't export these in the environment 851 * If requested, don't export these in the environment
851 * individually. We still put them in MAKEOVERRIDES so 852 * individually. We still put them in MAKEOVERRIDES so
852 * that the command-line settings continue to override 853 * that the command-line settings continue to override
853 * Makefile settings. 854 * Makefile settings.
854 */ 855 */
855 if (!opts.varNoExportEnv) 856 if (!opts.varNoExportEnv)
856 setenv(name, val ? val : "", 1); 857 setenv(name, val ? val : "", 1);
857 858
858 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 859 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
859 } 860 }
860 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0) 861 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
861 save_dollars = s2Boolean(val, save_dollars); 862 save_dollars = s2Boolean(val, save_dollars);
862 863
863out: 864out:
864 free(name_freeIt); 865 free(name_freeIt);
865 if (v != NULL) 866 if (v != NULL)
866 VarFreeEnv(v, TRUE); 867 VarFreeEnv(v, TRUE);
867} 868}
868 869
869/*- 870/*-
870 *----------------------------------------------------------------------- 871 *-----------------------------------------------------------------------
871 * Var_Set -- 872 * Var_Set --
872 * Set the variable name to the value val in the given context. 873 * Set the variable name to the value val in the given context.
873 * 874 *
874 * If the variable doesn't yet exist, it is created. 875 * If the variable doesn't yet exist, it is created.
875 * Otherwise the new value overwrites and replaces the old value. 876 * Otherwise the new value overwrites and replaces the old value.
876 * 877 *
877 * Input: 878 * Input:
878 * name name of variable to set 879 * name name of variable to set
879 * val value to give to the variable 880 * val value to give to the variable
880 * ctxt context in which to set it 881 * ctxt context in which to set it
881 * 882 *
882 * Notes: 883 * Notes:
883 * The variable is searched for only in its context before being 884 * The variable is searched for only in its context before being
884 * created in that context. I.e. if the context is VAR_GLOBAL, 885 * created in that context. I.e. if the context is VAR_GLOBAL,
885 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 886 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
886 * VAR_CMD->context is searched. This is done to avoid the literally 887 * VAR_CMD->context is searched. This is done to avoid the literally
887 * thousands of unnecessary strcmp's that used to be done to 888 * thousands of unnecessary strcmp's that used to be done to
888 * set, say, $(@) or $(<). 889 * set, say, $(@) or $(<).
889 * If the context is VAR_GLOBAL though, we check if the variable 890 * If the context is VAR_GLOBAL though, we check if the variable
890 * was set in VAR_CMD from the command line and skip it if so. 891 * was set in VAR_CMD from the command line and skip it if so.
891 *----------------------------------------------------------------------- 892 *-----------------------------------------------------------------------
892 */ 893 */
893void 894void
894Var_Set(const char *name, const char *val, GNode *ctxt) 895Var_Set(const char *name, const char *val, GNode *ctxt)
895{ 896{
896 Var_Set_with_flags(name, val, ctxt, 0); 897 Var_Set_with_flags(name, val, ctxt, 0);
897} 898}
898 899
899/*- 900/*-
900 *----------------------------------------------------------------------- 901 *-----------------------------------------------------------------------
901 * Var_Append -- 902 * Var_Append --
902 * The variable of the given name has the given value appended to it in 903 * The variable of the given name has the given value appended to it in
903 * the given context. 904 * the given context.
904 * 905 *
905 * If the variable doesn't exist, it is created. Otherwise the strings 906 * If the variable doesn't exist, it is created. Otherwise the strings
906 * are concatenated, with a space in between. 907 * are concatenated, with a space in between.
907 * 908 *
908 * Input: 909 * Input:
909 * name name of variable to modify 910 * name name of variable to modify
910 * val string to append to it 911 * val string to append to it
911 * ctxt context in which this should occur 912 * ctxt context in which this should occur
912 * 913 *
913 * Notes: 914 * Notes:
914 * Only if the variable is being sought in the global context is the 915 * Only if the variable is being sought in the global context is the
915 * environment searched. 916 * environment searched.
916 * XXX: Knows its calling circumstances in that if called with ctxt 917 * XXX: Knows its calling circumstances in that if called with ctxt
917 * an actual target, it will only search that context since only 918 * an actual target, it will only search that context since only
918 * a local variable could be being appended to. This is actually 919 * a local variable could be being appended to. This is actually
919 * a big win and must be tolerated. 920 * a big win and must be tolerated.
920 *----------------------------------------------------------------------- 921 *-----------------------------------------------------------------------
921 */ 922 */
922void 923void
923Var_Append(const char *name, const char *val, GNode *ctxt) 924Var_Append(const char *name, const char *val, GNode *ctxt)
924{ 925{
925 char *name_freeIt = NULL; 926 char *name_freeIt = NULL;
926 Var *v; 927 Var *v;
927 928
928 assert(val != NULL); 929 assert(val != NULL);
929 930
930 if (strchr(name, '$') != NULL) { 931 if (strchr(name, '$') != NULL) {
931 const char *unexpanded_name = name; 932 const char *unexpanded_name = name;
932 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 933 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
933 /* TODO: handle errors */ 934 /* TODO: handle errors */
934 name = name_freeIt; 935 name = name_freeIt;
935 if (name[0] == '\0') { 936 if (name[0] == '\0') {
936 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 937 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
937 "name expands to empty string - ignored\n", 938 "name expands to empty string - ignored\n",
938 unexpanded_name, val); 939 unexpanded_name, val);
939 free(name_freeIt); 940 free(name_freeIt);
940 return; 941 return;
941 } 942 }
942 } 943 }
943 944
944 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); 945 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0);
945 946
946 if (v == NULL) { 947 if (v == NULL) {
947 Var_Set(name, val, ctxt); 948 Var_Set(name, val, ctxt);
948 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { 949 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
949 Buf_AddByte(&v->val, ' '); 950 Buf_AddByte(&v->val, ' ');
950 Buf_AddStr(&v->val, val); 951 Buf_AddStr(&v->val, val);
951 952
952 VAR_DEBUG3("%s:%s = %s\n", 953 VAR_DEBUG3("%s:%s = %s\n",
953 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 954 ctxt->name, name, Buf_GetAll(&v->val, NULL));
954 955
955 if (v->flags & VAR_FROM_ENV) { 956 if (v->flags & VAR_FROM_ENV) {
956 HashEntry *h; 957 HashEntry *h;
957 958
958 /* 959 /*
959 * If the original variable came from the environment, we 960 * If the original variable came from the environment, we
960 * have to install it in the global context (we could place 961 * have to install it in the global context (we could place
961 * it in the environment, but then we should provide a way to 962 * it in the environment, but then we should provide a way to
962 * export other variables...) 963 * export other variables...)
963 */ 964 */
964 v->flags &= ~(unsigned)VAR_FROM_ENV; 965 v->flags &= ~(unsigned)VAR_FROM_ENV;
965 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 966 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
966 HashEntry_Set(h, v); 967 HashEntry_Set(h, v);
967 } 968 }
968 } 969 }
969 free(name_freeIt); 970 free(name_freeIt);
970} 971}
971 972
972/* See if the given variable exists, in the given context or in other 973/* See if the given variable exists, in the given context or in other
973 * fallback contexts. 974 * fallback contexts.
974 * 975 *
975 * Input: 976 * Input:
976 * name Variable to find 977 * name Variable to find
977 * ctxt Context in which to start search 978 * ctxt Context in which to start search
978 */ 979 */
979Boolean 980Boolean
980Var_Exists(const char *name, GNode *ctxt) 981Var_Exists(const char *name, GNode *ctxt)
981{ 982{
982 char *name_freeIt = NULL; 983 char *name_freeIt = NULL;
983 Var *v; 984 Var *v;
984 985
985 if (strchr(name, '$') != NULL) { 986 if (strchr(name, '$') != NULL) {
986 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 987 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
987 /* TODO: handle errors */ 988 /* TODO: handle errors */
988 name = name_freeIt; 989 name = name_freeIt;
989 } 990 }
990 991
991 v = VarFind(name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); 992 v = VarFind(name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV);
992 free(name_freeIt); 993 free(name_freeIt);
993 if (v == NULL) 994 if (v == NULL)
994 return FALSE; 995 return FALSE;
995 996
996 (void)VarFreeEnv(v, TRUE); 997 (void)VarFreeEnv(v, TRUE);
997 return TRUE; 998 return TRUE;
998} 999}
999 1000
1000/*- 1001/*-
1001 *----------------------------------------------------------------------- 1002 *-----------------------------------------------------------------------
1002 * Var_Value -- 1003 * Var_Value --
1003 * Return the unexpanded value of the given variable in the given 1004 * Return the unexpanded value of the given variable in the given
1004 * context, or the usual contexts. 1005 * context, or the usual contexts.
1005 * 1006 *
1006 * Input: 1007 * Input:
1007 * name name to find 1008 * name name to find
1008 * ctxt context in which to search for it 1009 * ctxt context in which to search for it
1009 * 1010 *
1010 * Results: 1011 * Results:
1011 * The value if the variable exists, NULL if it doesn't. 1012 * The value if the variable exists, NULL if it doesn't.
1012 * If the returned value is not NULL, the caller must free *freeIt 1013 * If the returned value is not NULL, the caller must free *freeIt
1013 * as soon as the returned value is no longer needed. 1014 * as soon as the returned value is no longer needed.
1014 *----------------------------------------------------------------------- 1015 *-----------------------------------------------------------------------
1015 */ 1016 */
1016const char * 1017const char *
1017Var_Value(const char *name, GNode *ctxt, char **freeIt) 1018Var_Value(const char *name, GNode *ctxt, char **freeIt)
1018{ 1019{
1019 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1020 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1020 char *p; 1021 char *p;
1021 1022
1022 *freeIt = NULL; 1023 *freeIt = NULL;
1023 if (v == NULL) 1024 if (v == NULL)
1024 return NULL; 1025 return NULL;
1025 1026
1026 p = Buf_GetAll(&v->val, NULL); 1027 p = Buf_GetAll(&v->val, NULL);
1027 if (VarFreeEnv(v, FALSE)) 1028 if (VarFreeEnv(v, FALSE))
1028 *freeIt = p; 1029 *freeIt = p;
1029 return p; 1030 return p;
1030} 1031}
1031 1032
1032 1033
1033/* SepBuf is a string being built from "words", interleaved with separators. */ 1034/* SepBuf is a string being built from "words", interleaved with separators. */
1034typedef struct SepBuf { 1035typedef struct SepBuf {
1035 Buffer buf; 1036 Buffer buf;
1036 Boolean needSep; 1037 Boolean needSep;
1037 char sep; /* usually ' ', but see the :ts modifier */ 1038 char sep; /* usually ' ', but see the :ts modifier */
1038} SepBuf; 1039} SepBuf;
1039 1040
1040static void 1041static void
1041SepBuf_Init(SepBuf *buf, char sep) 1042SepBuf_Init(SepBuf *buf, char sep)
1042{ 1043{
1043 Buf_Init(&buf->buf, 32 /* bytes */); 1044 Buf_Init(&buf->buf, 32 /* bytes */);
1044 buf->needSep = FALSE; 1045 buf->needSep = FALSE;
1045 buf->sep = sep; 1046 buf->sep = sep;
1046} 1047}
1047 1048
1048static void 1049static void
1049SepBuf_Sep(SepBuf *buf) 1050SepBuf_Sep(SepBuf *buf)
1050{ 1051{
1051 buf->needSep = TRUE; 1052 buf->needSep = TRUE;
1052} 1053}
1053 1054
1054static void 1055static void
1055SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1056SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1056{ 1057{
1057 if (mem_size == 0) 1058 if (mem_size == 0)
1058 return; 1059 return;
1059 if (buf->needSep && buf->sep != '\0') { 1060 if (buf->needSep && buf->sep != '\0') {
1060 Buf_AddByte(&buf->buf, buf->sep); 1061 Buf_AddByte(&buf->buf, buf->sep);
1061 buf->needSep = FALSE; 1062 buf->needSep = FALSE;
1062 } 1063 }
1063 Buf_AddBytes(&buf->buf, mem, mem_size); 1064 Buf_AddBytes(&buf->buf, mem, mem_size);
1064} 1065}
1065 1066
1066static void 1067static void
1067SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1068SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1068{ 1069{
1069 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1070 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1070} 1071}
1071 1072
1072static void 1073static void
1073SepBuf_AddStr(SepBuf *buf, const char *str) 1074SepBuf_AddStr(SepBuf *buf, const char *str)
1074{ 1075{
1075 SepBuf_AddBytes(buf, str, strlen(str)); 1076 SepBuf_AddBytes(buf, str, strlen(str));
1076} 1077}
1077 1078
1078static char * 1079static char *
1079SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1080SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1080{ 1081{
1081 return Buf_Destroy(&buf->buf, free_buf); 1082 return Buf_Destroy(&buf->buf, free_buf);
1082} 1083}
1083 1084
1084 1085
1085/* This callback for ModifyWords gets a single word from an expression and 1086/* This callback for ModifyWords gets a single word from an expression and
1086 * typically adds a modification of this word to the buffer. It may also do 1087 * typically adds a modification of this word to the buffer. It may also do
1087 * nothing or add several words. */ 1088 * nothing or add several words. */
1088typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1089typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1089 1090
1090 1091
1091/* Callback for ModifyWords to implement the :H modifier. 1092/* Callback for ModifyWords to implement the :H modifier.
1092 * Add the dirname of the given word to the buffer. */ 1093 * Add the dirname of the given word to the buffer. */
1093static void 1094static void
1094ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1095ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1095{ 1096{
1096 const char *slash = strrchr(word, '/'); 1097 const char *slash = strrchr(word, '/');
1097 if (slash != NULL) 1098 if (slash != NULL)
1098 SepBuf_AddBytesBetween(buf, word, slash); 1099 SepBuf_AddBytesBetween(buf, word, slash);
1099 else 1100 else
1100 SepBuf_AddStr(buf, "."); 1101 SepBuf_AddStr(buf, ".");
1101} 1102}
1102 1103
1103/* Callback for ModifyWords to implement the :T modifier. 1104/* Callback for ModifyWords to implement the :T modifier.
1104 * Add the basename of the given word to the buffer. */ 1105 * Add the basename of the given word to the buffer. */
1105static void 1106static void
1106ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1107ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1107{ 1108{
1108 const char *slash = strrchr(word, '/'); 1109 const char *slash = strrchr(word, '/');
1109 const char *base = slash != NULL ? slash + 1 : word; 1110 const char *base = slash != NULL ? slash + 1 : word;
1110 SepBuf_AddStr(buf, base); 1111 SepBuf_AddStr(buf, base);
1111} 1112}
1112 1113
1113/* Callback for ModifyWords to implement the :E modifier. 1114/* Callback for ModifyWords to implement the :E modifier.
1114 * Add the filename suffix of the given word to the buffer, if it exists. */ 1115 * Add the filename suffix of the given word to the buffer, if it exists. */
1115static void 1116static void
1116ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1117ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1117{ 1118{
1118 const char *dot = strrchr(word, '.'); 1119 const char *dot = strrchr(word, '.');
1119 if (dot != NULL) 1120 if (dot != NULL)
1120 SepBuf_AddStr(buf, dot + 1); 1121 SepBuf_AddStr(buf, dot + 1);
1121} 1122}
1122 1123
1123/* Callback for ModifyWords to implement the :R modifier. 1124/* Callback for ModifyWords to implement the :R modifier.
1124 * Add the basename of the given word to the buffer. */ 1125 * Add the basename of the given word to the buffer. */
1125static void 1126static void
1126ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1127ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1127{ 1128{
1128 const char *dot = strrchr(word, '.'); 1129 const char *dot = strrchr(word, '.');
1129 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1130 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1130 SepBuf_AddBytes(buf, word, len); 1131 SepBuf_AddBytes(buf, word, len);
1131} 1132}
1132 1133
1133/* Callback for ModifyWords to implement the :M modifier. 1134/* Callback for ModifyWords to implement the :M modifier.
1134 * Place the word in the buffer if it matches the given pattern. */ 1135 * Place the word in the buffer if it matches the given pattern. */
1135static void 1136static void
1136ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1137ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1137{ 1138{
1138 const char *pattern = data; 1139 const char *pattern = data;
1139 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1140 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1140 if (Str_Match(word, pattern)) 1141 if (Str_Match(word, pattern))
1141 SepBuf_AddStr(buf, word); 1142 SepBuf_AddStr(buf, word);
1142} 1143}
1143 1144
1144/* Callback for ModifyWords to implement the :N modifier. 1145/* Callback for ModifyWords to implement the :N modifier.
1145 * Place the word in the buffer if it doesn't match the given pattern. */ 1146 * Place the word in the buffer if it doesn't match the given pattern. */
1146static void 1147static void
1147ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1148ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1148{ 1149{
1149 const char *pattern = data; 1150 const char *pattern = data;
1150 if (!Str_Match(word, pattern)) 1151 if (!Str_Match(word, pattern))
1151 SepBuf_AddStr(buf, word); 1152 SepBuf_AddStr(buf, word);
1152} 1153}
1153 1154
1154#ifdef SYSVVARSUB 1155#ifdef SYSVVARSUB
1155/*- 1156/*-
1156 *----------------------------------------------------------------------- 1157 *-----------------------------------------------------------------------
1157 * Str_SYSVMatch -- 1158 * Str_SYSVMatch --
1158 * Check word against pattern for a match (% is wild), 1159 * Check word against pattern for a match (% is wild),
1159 * 1160 *
1160 * Input: 1161 * Input:
1161 * word Word to examine 1162 * word Word to examine
1162 * pattern Pattern to examine against 1163 * pattern Pattern to examine against
1163 * 1164 *
1164 * Results: 1165 * Results:
1165 * Returns the start of the match, or NULL. 1166 * Returns the start of the match, or NULL.
1166 * *match_len returns the length of the match, if any. 1167 * *match_len returns the length of the match, if any.
1167 * *hasPercent returns whether the pattern contains a percent. 1168 * *hasPercent returns whether the pattern contains a percent.
1168 *----------------------------------------------------------------------- 1169 *-----------------------------------------------------------------------
1169 */ 1170 */
1170static const char * 1171static const char *
1171Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len, 1172Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len,
1172 Boolean *hasPercent) 1173 Boolean *hasPercent)
1173{ 1174{
1174 const char *p = pattern; 1175 const char *p = pattern;
1175 const char *w = word; 1176 const char *w = word;
1176 const char *percent; 1177 const char *percent;
1177 size_t w_len; 1178 size_t w_len;
1178 size_t p_len; 1179 size_t p_len;
1179 const char *w_tail; 1180 const char *w_tail;
1180 1181
1181 *hasPercent = FALSE; 1182 *hasPercent = FALSE;
1182 if (*p == '\0') { /* ${VAR:=suffix} */ 1183 if (*p == '\0') { /* ${VAR:=suffix} */
1183 *match_len = strlen(w); /* Null pattern is the whole string */ 1184 *match_len = strlen(w); /* Null pattern is the whole string */
1184 return w; 1185 return w;
1185 } 1186 }
1186 1187
1187 percent = strchr(p, '%'); 1188 percent = strchr(p, '%');
1188 if (percent != NULL) { /* ${VAR:...%...=...} */ 1189 if (percent != NULL) { /* ${VAR:...%...=...} */
1189 *hasPercent = TRUE; 1190 *hasPercent = TRUE;
1190 if (*w == '\0') 1191 if (*w == '\0')
1191 return NULL; /* empty word does not match pattern */ 1192 return NULL; /* empty word does not match pattern */
1192 1193
1193 /* check that the prefix matches */ 1194 /* check that the prefix matches */
1194 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1195 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1195 continue; 1196 continue;
1196 if (p != percent) 1197 if (p != percent)
1197 return NULL; /* No match */ 1198 return NULL; /* No match */
1198 1199
1199 p++; /* Skip the percent */ 1200 p++; /* Skip the percent */
1200 if (*p == '\0') { 1201 if (*p == '\0') {
1201 /* No more pattern, return the rest of the string */ 1202 /* No more pattern, return the rest of the string */
1202 *match_len = strlen(w); 1203 *match_len = strlen(w);
1203 return w; 1204 return w;
1204 } 1205 }
1205 } 1206 }
1206 1207
1207 /* Test whether the tail matches */ 1208 /* Test whether the tail matches */
1208 w_len = strlen(w); 1209 w_len = strlen(w);
1209 p_len = strlen(p); 1210 p_len = strlen(p);
1210 if (w_len < p_len) 1211 if (w_len < p_len)
1211 return NULL; 1212 return NULL;
1212 1213
1213 w_tail = w + w_len - p_len; 1214 w_tail = w + w_len - p_len;
1214 if (memcmp(p, w_tail, p_len) != 0) 1215 if (memcmp(p, w_tail, p_len) != 0)
1215 return NULL; 1216 return NULL;
1216 1217
1217 *match_len = (size_t)(w_tail - w); 1218 *match_len = (size_t)(w_tail - w);
1218 return w; 1219 return w;
1219} 1220}
1220 1221
1221struct ModifyWord_SYSVSubstArgs { 1222struct ModifyWord_SYSVSubstArgs {
1222 GNode *ctx; 1223 GNode *ctx;
1223 const char *lhs; 1224 const char *lhs;
1224 const char *rhs; 1225 const char *rhs;
1225}; 1226};
1226 1227
1227/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1228/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1228static void 1229static void
1229ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1230ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1230{ 1231{
1231 const struct ModifyWord_SYSVSubstArgs *args = data; 1232 const struct ModifyWord_SYSVSubstArgs *args = data;
1232 char *rhs_expanded; 1233 char *rhs_expanded;
1233 const char *rhs; 1234 const char *rhs;
1234 const char *percent; 1235 const char *percent;
1235 1236
1236 size_t match_len; 1237 size_t match_len;
1237 Boolean lhsPercent; 1238 Boolean lhsPercent;
1238 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent); 1239 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent);
1239 if (match == NULL) { 1240 if (match == NULL) {
1240 SepBuf_AddStr(buf, word); 1241 SepBuf_AddStr(buf, word);
1241 return; 1242 return;
1242 } 1243 }
1243 1244
1244 /* Append rhs to the buffer, substituting the first '%' with the 1245 /* Append rhs to the buffer, substituting the first '%' with the
1245 * match, but only if the lhs had a '%' as well. */ 1246 * match, but only if the lhs had a '%' as well. */
1246 1247
1247 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1248 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1248 /* TODO: handle errors */ 1249 /* TODO: handle errors */
1249 1250
1250 rhs = rhs_expanded; 1251 rhs = rhs_expanded;
1251 percent = strchr(rhs, '%'); 1252 percent = strchr(rhs, '%');
1252 1253
1253 if (percent != NULL && lhsPercent) { 1254 if (percent != NULL && lhsPercent) {
1254 /* Copy the prefix of the replacement pattern */ 1255 /* Copy the prefix of the replacement pattern */
1255 SepBuf_AddBytesBetween(buf, rhs, percent); 1256 SepBuf_AddBytesBetween(buf, rhs, percent);
1256 rhs = percent + 1; 1257 rhs = percent + 1;
1257 } 1258 }
1258 if (percent != NULL || !lhsPercent) 1259 if (percent != NULL || !lhsPercent)
1259 SepBuf_AddBytes(buf, match, match_len); 1260 SepBuf_AddBytes(buf, match, match_len);
1260 1261
1261 /* Append the suffix of the replacement pattern */ 1262 /* Append the suffix of the replacement pattern */
1262 SepBuf_AddStr(buf, rhs); 1263 SepBuf_AddStr(buf, rhs);
1263 1264
1264 free(rhs_expanded); 1265 free(rhs_expanded);
1265} 1266}
1266#endif 1267#endif
1267 1268
1268 1269
1269struct ModifyWord_SubstArgs { 1270struct ModifyWord_SubstArgs {
1270 const char *lhs; 1271 const char *lhs;
1271 size_t lhsLen; 1272 size_t lhsLen;
1272 const char *rhs; 1273 const char *rhs;
1273 size_t rhsLen; 1274 size_t rhsLen;
1274 VarPatternFlags pflags; 1275 VarPatternFlags pflags;
1275 Boolean matched; 1276 Boolean matched;
1276}; 1277};
1277 1278
1278/* Callback for ModifyWords to implement the :S,from,to, modifier. 1279/* Callback for ModifyWords to implement the :S,from,to, modifier.
1279 * Perform a string substitution on the given word. */ 1280 * Perform a string substitution on the given word. */
1280static void 1281static void
1281ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1282ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1282{ 1283{
1283 size_t wordLen = strlen(word); 1284 size_t wordLen = strlen(word);
1284 struct ModifyWord_SubstArgs *args = data; 1285 struct ModifyWord_SubstArgs *args = data;
1285 const char *match; 1286 const char *match;
1286 1287
1287 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1288 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1288 goto nosub; 1289 goto nosub;
1289 1290
1290 if (args->pflags & VARP_ANCHOR_START) { 1291 if (args->pflags & VARP_ANCHOR_START) {
1291 if (wordLen < args->lhsLen || 1292 if (wordLen < args->lhsLen ||
1292 memcmp(word, args->lhs, args->lhsLen) != 0) 1293 memcmp(word, args->lhs, args->lhsLen) != 0)
1293 goto nosub; 1294 goto nosub;
1294 1295
1295 if (args->pflags & VARP_ANCHOR_END) { 1296 if (args->pflags & VARP_ANCHOR_END) {
1296 if (wordLen != args->lhsLen) 1297 if (wordLen != args->lhsLen)
1297 goto nosub; 1298 goto nosub;
1298 1299
1299 /* :S,^whole$,replacement, */ 1300 /* :S,^whole$,replacement, */
1300 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1301 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1301 args->matched = TRUE; 1302 args->matched = TRUE;
1302 } else { 1303 } else {
1303 /* :S,^prefix,replacement, */ 1304 /* :S,^prefix,replacement, */
1304 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1305 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1305 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1306 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1306 args->matched = TRUE; 1307 args->matched = TRUE;
1307 } 1308 }
1308 return; 1309 return;
1309 } 1310 }
1310 1311
1311 if (args->pflags & VARP_ANCHOR_END) { 1312 if (args->pflags & VARP_ANCHOR_END) {
1312 const char *start; 1313 const char *start;
1313 1314
1314 if (wordLen < args->lhsLen) 1315 if (wordLen < args->lhsLen)
1315 goto nosub; 1316 goto nosub;
1316 1317
1317 start = word + (wordLen - args->lhsLen); 1318 start = word + (wordLen - args->lhsLen);
1318 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1319 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1319 goto nosub; 1320 goto nosub;
1320 1321
1321 /* :S,suffix$,replacement, */ 1322 /* :S,suffix$,replacement, */
1322 SepBuf_AddBytesBetween(buf, word, start); 1323 SepBuf_AddBytesBetween(buf, word, start);
1323 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1324 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1324 args->matched = TRUE; 1325 args->matched = TRUE;
1325 return; 1326 return;
1326 } 1327 }
1327 1328
1328 if (args->lhs[0] == '\0') 1329 if (args->lhs[0] == '\0')
1329 goto nosub; 1330 goto nosub;
1330 1331
1331 /* unanchored case, may match more than once */ 1332 /* unanchored case, may match more than once */
1332 while ((match = strstr(word, args->lhs)) != NULL) { 1333 while ((match = strstr(word, args->lhs)) != NULL) {
1333 SepBuf_AddBytesBetween(buf, word, match); 1334 SepBuf_AddBytesBetween(buf, word, match);
1334 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1335 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1335 args->matched = TRUE; 1336 args->matched = TRUE;
1336 wordLen -= (size_t)(match - word) + args->lhsLen; 1337 wordLen -= (size_t)(match - word) + args->lhsLen;
1337 word += (size_t)(match - word) + args->lhsLen; 1338 word += (size_t)(match - word) + args->lhsLen;
1338 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1339 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1339 break; 1340 break;
1340 } 1341 }
1341nosub: 1342nosub:
1342 SepBuf_AddBytes(buf, word, wordLen); 1343 SepBuf_AddBytes(buf, word, wordLen);
1343} 1344}
1344 1345
1345#ifndef NO_REGEX 1346#ifndef NO_REGEX
1346/* Print the error caused by a regcomp or regexec call. */ 1347/* Print the error caused by a regcomp or regexec call. */
1347static void 1348static void
1348VarREError(int reerr, regex_t *pat, const char *str) 1349VarREError(int reerr, regex_t *pat, const char *str)
1349{ 1350{
1350 size_t errlen = regerror(reerr, pat, 0, 0); 1351 size_t errlen = regerror(reerr, pat, 0, 0);
1351 char *errbuf = bmake_malloc(errlen); 1352 char *errbuf = bmake_malloc(errlen);
1352 regerror(reerr, pat, errbuf, errlen); 1353 regerror(reerr, pat, errbuf, errlen);
1353 Error("%s: %s", str, errbuf); 1354 Error("%s: %s", str, errbuf);
1354 free(errbuf); 1355 free(errbuf);
1355} 1356}
1356 1357
1357struct ModifyWord_SubstRegexArgs { 1358struct ModifyWord_SubstRegexArgs {
1358 regex_t re; 1359 regex_t re;
1359 size_t nsub; 1360 size_t nsub;
1360 char *replace; 1361 char *replace;
1361 VarPatternFlags pflags; 1362 VarPatternFlags pflags;
1362 Boolean matched; 1363 Boolean matched;
1363}; 1364};
1364 1365
1365/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1366/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1366 * Perform a regex substitution on the given word. */ 1367 * Perform a regex substitution on the given word. */
1367static void 1368static void
1368ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1369ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1369{ 1370{
1370 struct ModifyWord_SubstRegexArgs *args = data; 1371 struct ModifyWord_SubstRegexArgs *args = data;
1371 int xrv; 1372 int xrv;
1372 const char *wp = word; 1373 const char *wp = word;
1373 char *rp; 1374 char *rp;
1374 int flags = 0; 1375 int flags = 0;
1375 regmatch_t m[10]; 1376 regmatch_t m[10];
1376 1377
1377 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1378 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1378 goto nosub; 1379 goto nosub;
1379 1380
1380tryagain: 1381tryagain:
1381 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1382 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1382 1383
1383 switch (xrv) { 1384 switch (xrv) {
1384 case 0: 1385 case 0:
1385 args->matched = TRUE; 1386 args->matched = TRUE;
1386 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1387 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1387 1388
1388 for (rp = args->replace; *rp; rp++) { 1389 for (rp = args->replace; *rp; rp++) {
1389 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1390 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1390 SepBuf_AddBytes(buf, rp + 1, 1); 1391 SepBuf_AddBytes(buf, rp + 1, 1);
1391 rp++; 1392 rp++;
1392 continue; 1393 continue;
1393 } 1394 }
1394 1395
1395 if (*rp == '&') { 1396 if (*rp == '&') {
1396 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1397 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1397 continue; 1398 continue;
1398 } 1399 }
1399 1400
1400 if (*rp != '\\' || !ch_isdigit(rp[1])) { 1401 if (*rp != '\\' || !ch_isdigit(rp[1])) {
1401 SepBuf_AddBytes(buf, rp, 1); 1402 SepBuf_AddBytes(buf, rp, 1);
1402 continue; 1403 continue;
1403 } 1404 }
1404 1405
1405 { /* \0 to \9 backreference */ 1406 { /* \0 to \9 backreference */
1406 size_t n = (size_t)(rp[1] - '0'); 1407 size_t n = (size_t)(rp[1] - '0');
1407 rp++; 1408 rp++;
1408 1409
1409 if (n >= args->nsub) { 1410 if (n >= args->nsub) {
1410 Error("No subexpression \\%zu", n); 1411 Error("No subexpression \\%zu", n);
1411 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1412 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1412 Error("No match for subexpression \\%zu", n); 1413 Error("No match for subexpression \\%zu", n);
1413 } else { 1414 } else {
1414 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1415 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1415 wp + m[n].rm_eo); 1416 wp + m[n].rm_eo);
1416 } 1417 }
1417 } 1418 }
1418 } 1419 }
1419 1420
1420 wp += m[0].rm_eo; 1421 wp += m[0].rm_eo;
1421 if (args->pflags & VARP_SUB_GLOBAL) { 1422 if (args->pflags & VARP_SUB_GLOBAL) {
1422 flags |= REG_NOTBOL; 1423 flags |= REG_NOTBOL;
1423 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1424 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1424 SepBuf_AddBytes(buf, wp, 1); 1425 SepBuf_AddBytes(buf, wp, 1);
1425 wp++; 1426 wp++;
1426 } 1427 }
1427 if (*wp) 1428 if (*wp)
1428 goto tryagain; 1429 goto tryagain;
1429 } 1430 }
1430 if (*wp) { 1431 if (*wp) {
1431 SepBuf_AddStr(buf, wp); 1432 SepBuf_AddStr(buf, wp);
1432 } 1433 }
1433 break; 1434 break;
1434 default: 1435 default:
1435 VarREError(xrv, &args->re, "Unexpected regex error"); 1436 VarREError(xrv, &args->re, "Unexpected regex error");
1436 /* FALLTHROUGH */ 1437 /* FALLTHROUGH */
1437 case REG_NOMATCH: 1438 case REG_NOMATCH:
1438 nosub: 1439 nosub:
1439 SepBuf_AddStr(buf, wp); 1440 SepBuf_AddStr(buf, wp);
1440 break; 1441 break;
1441 } 1442 }
1442} 1443}
1443#endif 1444#endif
1444 1445
1445 1446
1446struct ModifyWord_LoopArgs { 1447struct ModifyWord_LoopArgs {
1447 GNode *ctx; 1448 GNode *ctx;
1448 char *tvar; /* name of temporary variable */ 1449 char *tvar; /* name of temporary variable */
1449 char *str; /* string to expand */ 1450 char *str; /* string to expand */
1450 VarEvalFlags eflags; 1451 VarEvalFlags eflags;
1451}; 1452};
1452 1453
1453/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1454/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1454static void 1455static void
1455ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1456ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1456{ 1457{
1457 const struct ModifyWord_LoopArgs *args; 1458 const struct ModifyWord_LoopArgs *args;
1458 char *s; 1459 char *s;
1459 1460
1460 if (word[0] == '\0') 1461 if (word[0] == '\0')
1461 return; 1462 return;
1462 1463
1463 args = data; 1464 args = data;
1464 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1465 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1465 (void)Var_Subst(args->str, args->ctx, args->eflags, &s); 1466 (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1466 /* TODO: handle errors */ 1467 /* TODO: handle errors */
1467 1468
1468 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1469 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1469 "to \"%s\"\n", 1470 "to \"%s\"\n",
1470 word, args->tvar, args->str, s); 1471 word, args->tvar, args->str, s);
1471 1472
1472 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n')) 1473 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1473 buf->needSep = FALSE; 1474 buf->needSep = FALSE;
1474 SepBuf_AddStr(buf, s); 1475 SepBuf_AddStr(buf, s);
1475 free(s); 1476 free(s);
1476} 1477}
1477 1478
1478 1479
1479/*- 1480/*-
1480 * Implements the :[first..last] modifier. 1481 * Implements the :[first..last] modifier.
1481 * This is a special case of ModifyWords since we want to be able 1482 * This is a special case of ModifyWords since we want to be able
1482 * to scan the list backwards if first > last. 1483 * to scan the list backwards if first > last.
1483 */ 1484 */
1484static char * 1485static char *
1485VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1486VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1486 int last) 1487 int last)
1487{ 1488{
1488 Words words; 1489 Words words;
1489 int len, start, end, step; 1490 int len, start, end, step;
1490 int i; 1491 int i;
1491 1492
1492 SepBuf buf; 1493 SepBuf buf;
1493 SepBuf_Init(&buf, sep); 1494 SepBuf_Init(&buf, sep);
1494 1495
1495 if (oneBigWord) { 1496 if (oneBigWord) {
1496 /* fake what Str_Words() would do if there were only one word */ 1497 /* fake what Str_Words() would do if there were only one word */
1497 words.len = 1; 1498 words.len = 1;
1498 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1499 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1499 words.freeIt = bmake_strdup(str); 1500 words.freeIt = bmake_strdup(str);
1500 words.words[0] = words.freeIt; 1501 words.words[0] = words.freeIt;
1501 words.words[1] = NULL; 1502 words.words[1] = NULL;
1502 } else { 1503 } else {
1503 words = Str_Words(str, FALSE); 1504 words = Str_Words(str, FALSE);
1504 } 1505 }
1505 1506
1506 /* 1507 /*
1507 * Now sanitize the given range. 1508 * Now sanitize the given range.
1508 * If first or last are negative, convert them to the positive equivalents 1509 * If first or last are negative, convert them to the positive equivalents
1509 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1510 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1510 */ 1511 */
1511 len = (int)words.len; 1512 len = (int)words.len;
1512 if (first < 0) 1513 if (first < 0)
1513 first += len + 1; 1514 first += len + 1;
1514 if (last < 0) 1515 if (last < 0)
1515 last += len + 1; 1516 last += len + 1;
1516 1517
1517 /* 1518 /*
1518 * We avoid scanning more of the list than we need to. 1519 * We avoid scanning more of the list than we need to.
1519 */ 1520 */
1520 if (first > last) { 1521 if (first > last) {
1521 start = (first > len ? len : first) - 1; 1522 start = (first > len ? len : first) - 1;
1522 end = last < 1 ? 0 : last - 1; 1523 end = last < 1 ? 0 : last - 1;
1523 step = -1; 1524 step = -1;
1524 } else { 1525 } else {
1525 start = first < 1 ? 0 : first - 1; 1526 start = first < 1 ? 0 : first - 1;
1526 end = last > len ? len : last; 1527 end = last > len ? len : last;
1527 step = 1; 1528 step = 1;
1528 } 1529 }
1529 1530
1530 for (i = start; (step < 0) == (i >= end); i += step) { 1531 for (i = start; (step < 0) == (i >= end); i += step) {
1531 SepBuf_AddStr(&buf, words.words[i]); 1532 SepBuf_AddStr(&buf, words.words[i]);
1532 SepBuf_Sep(&buf); 1533 SepBuf_Sep(&buf);
1533 } 1534 }
1534 1535
1535 Words_Free(words); 1536 Words_Free(words);
1536 1537
1537 return SepBuf_Destroy(&buf, FALSE); 1538 return SepBuf_Destroy(&buf, FALSE);
1538} 1539}
1539 1540
1540 1541
1541/* Callback for ModifyWords to implement the :tA modifier. 1542/* Callback for ModifyWords to implement the :tA modifier.
1542 * Replace each word with the result of realpath() if successful. */ 1543 * Replace each word with the result of realpath() if successful. */
1543static void 1544static void
1544ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1545ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1545{ 1546{
1546 struct stat st; 1547 struct stat st;
1547 char rbuf[MAXPATHLEN]; 1548 char rbuf[MAXPATHLEN];
1548 1549
1549 const char *rp = cached_realpath(word, rbuf); 1550 const char *rp = cached_realpath(word, rbuf);
1550 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1551 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1551 word = rp; 1552 word = rp;
1552 1553
1553 SepBuf_AddStr(buf, word); 1554 SepBuf_AddStr(buf, word);
1554} 1555}
1555 1556
1556/*- 1557/*-
1557 *----------------------------------------------------------------------- 1558 *-----------------------------------------------------------------------
1558 * Modify each of the words of the passed string using the given function. 1559 * Modify each of the words of the passed string using the given function.
1559 * 1560 *
1560 * Input: 1561 * Input:
1561 * str String whose words should be modified 1562 * str String whose words should be modified
1562 * modifyWord Function that modifies a single word 1563 * modifyWord Function that modifies a single word
1563 * modifyWord_args Custom arguments for modifyWord 1564 * modifyWord_args Custom arguments for modifyWord
1564 * 1565 *
1565 * Results: 1566 * Results:
1566 * A string of all the words modified appropriately. 1567 * A string of all the words modified appropriately.
1567 *----------------------------------------------------------------------- 1568 *-----------------------------------------------------------------------
1568 */ 1569 */
1569static char * 1570static char *
1570ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1571ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str,
1571 ModifyWordsCallback modifyWord, void *modifyWord_args) 1572 ModifyWordsCallback modifyWord, void *modifyWord_args)
1572{ 1573{
1573 SepBuf result; 1574 SepBuf result;
1574 Words words; 1575 Words words;
1575 size_t i; 1576 size_t i;
1576 1577
1577 if (oneBigWord) { 1578 if (oneBigWord) {
1578 SepBuf_Init(&result, sep); 1579 SepBuf_Init(&result, sep);
1579 modifyWord(str, &result, modifyWord_args); 1580 modifyWord(str, &result, modifyWord_args);
1580 return SepBuf_Destroy(&result, FALSE); 1581 return SepBuf_Destroy(&result, FALSE);
1581 } 1582 }
1582 1583
1583 SepBuf_Init(&result, sep); 1584 SepBuf_Init(&result, sep);
1584 1585
1585 words = Str_Words(str, FALSE); 1586 words = Str_Words(str, FALSE);
1586 1587
1587 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1588 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1588 1589
1589 for (i = 0; i < words.len; i++) { 1590 for (i = 0; i < words.len; i++) {
1590 modifyWord(words.words[i], &result, modifyWord_args); 1591 modifyWord(words.words[i], &result, modifyWord_args);
1591 if (Buf_Len(&result.buf) > 0) 1592 if (Buf_Len(&result.buf) > 0)
1592 SepBuf_Sep(&result); 1593 SepBuf_Sep(&result);
1593 } 1594 }
1594 1595
1595 Words_Free(words); 1596 Words_Free(words);
1596 1597
1597 return SepBuf_Destroy(&result, FALSE); 1598 return SepBuf_Destroy(&result, FALSE);
1598} 1599}
1599 1600
1600 1601
1601static char * 1602static char *
1602Words_JoinFree(Words words) 1603Words_JoinFree(Words words)
1603{ 1604{
1604 Buffer buf; 1605 Buffer buf;
1605 size_t i; 1606 size_t i;
1606 1607
1607 Buf_Init(&buf, 0); 1608 Buf_Init(&buf, 0);
1608 1609
1609 for (i = 0; i < words.len; i++) { 1610 for (i = 0; i < words.len; i++) {
1610 if (i != 0) 1611 if (i != 0)
1611 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1612 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1612 Buf_AddStr(&buf, words.words[i]); 1613 Buf_AddStr(&buf, words.words[i]);
1613 } 1614 }
1614 1615
1615 Words_Free(words); 1616 Words_Free(words);
1616 1617
1617 return Buf_Destroy(&buf, FALSE); 1618 return Buf_Destroy(&buf, FALSE);
1618} 1619}
1619 1620
1620/* Remove adjacent duplicate words. */ 1621/* Remove adjacent duplicate words. */
1621static char * 1622static char *
1622VarUniq(const char *str) 1623VarUniq(const char *str)
1623{ 1624{
1624 Words words = Str_Words(str, FALSE); 1625 Words words = Str_Words(str, FALSE);
1625 1626
1626 if (words.len > 1) { 1627 if (words.len > 1) {
1627 size_t i, j; 1628 size_t i, j;
1628 for (j = 0, i = 1; i < words.len; i++) 1629 for (j = 0, i = 1; i < words.len; i++)
1629 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i)) 1630 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1630 words.words[j] = words.words[i]; 1631 words.words[j] = words.words[i];
1631 words.len = j + 1; 1632 words.len = j + 1;
1632 } 1633 }
1633 1634
1634 return Words_JoinFree(words); 1635 return Words_JoinFree(words);
1635} 1636}
1636 1637
1637 1638
1638/* Quote shell meta-characters and space characters in the string. 1639/* Quote shell meta-characters and space characters in the string.
1639 * If quoteDollar is set, also quote and double any '$' characters. */ 1640 * If quoteDollar is set, also quote and double any '$' characters. */
1640static char * 1641static char *
1641VarQuote(const char *str, Boolean quoteDollar) 1642VarQuote(const char *str, Boolean quoteDollar)
1642{ 1643{
1643 char *res; 1644 char *res;
1644 Buffer buf; 1645 Buffer buf;
1645 Buf_Init(&buf, 0); 1646 Buf_Init(&buf, 0);
1646 1647
1647 for (; *str != '\0'; str++) { 1648 for (; *str != '\0'; str++) {
1648 if (*str == '\n') { 1649 if (*str == '\n') {
1649 const char *newline = Shell_GetNewline(); 1650 const char *newline = Shell_GetNewline();
1650 if (newline == NULL) 1651 if (newline == NULL)
1651 newline = "\\\n"; 1652 newline = "\\\n";
1652 Buf_AddStr(&buf, newline); 1653 Buf_AddStr(&buf, newline);
1653 continue; 1654 continue;
1654 } 1655 }
1655 if (ch_isspace(*str) || ismeta((unsigned char)*str)) 1656 if (ch_isspace(*str) || ismeta((unsigned char)*str))
1656 Buf_AddByte(&buf, '\\'); 1657 Buf_AddByte(&buf, '\\');
1657 Buf_AddByte(&buf, *str); 1658 Buf_AddByte(&buf, *str);
1658 if (quoteDollar && *str == '$') 1659 if (quoteDollar && *str == '$')
1659 Buf_AddStr(&buf, "\\$"); 1660 Buf_AddStr(&buf, "\\$");
1660 } 1661 }
1661 1662
1662 res = Buf_Destroy(&buf, FALSE); 1663 res = Buf_Destroy(&buf, FALSE);
1663 VAR_DEBUG1("QuoteMeta: [%s]\n", res); 1664 VAR_DEBUG1("QuoteMeta: [%s]\n", res);
1664 return res; 1665 return res;
1665} 1666}
1666 1667
1667/* Compute the 32-bit hash of the given string, using the MurmurHash3 1668/* Compute the 32-bit hash of the given string, using the MurmurHash3
1668 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1669 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1669static char * 1670static char *
1670VarHash(const char *str) 1671VarHash(const char *str)
1671{ 1672{
1672 static const char hexdigits[16] = "0123456789abcdef"; 1673 static const char hexdigits[16] = "0123456789abcdef";
1673 const unsigned char *ustr = (const unsigned char *)str; 1674 const unsigned char *ustr = (const unsigned char *)str;
1674 1675
1675 uint32_t h = 0x971e137bU; 1676 uint32_t h = 0x971e137bU;
1676 uint32_t c1 = 0x95543787U; 1677 uint32_t c1 = 0x95543787U;
1677 uint32_t c2 = 0x2ad7eb25U; 1678 uint32_t c2 = 0x2ad7eb25U;
1678 size_t len2 = strlen(str); 1679 size_t len2 = strlen(str);
1679 1680
1680 char *buf; 1681 char *buf;
1681 size_t i; 1682 size_t i;
1682 1683
1683 size_t len; 1684 size_t len;
1684 for (len = len2; len; ) { 1685 for (len = len2; len; ) {
1685 uint32_t k = 0; 1686 uint32_t k = 0;
1686 switch (len) { 1687 switch (len) {
1687 default: 1688 default:
1688 k = ((uint32_t)ustr[3] << 24) | 1689 k = ((uint32_t)ustr[3] << 24) |
1689 ((uint32_t)ustr[2] << 16) | 1690 ((uint32_t)ustr[2] << 16) |
1690 ((uint32_t)ustr[1] << 8) | 1691 ((uint32_t)ustr[1] << 8) |
1691 (uint32_t)ustr[0]; 1692 (uint32_t)ustr[0];
1692 len -= 4; 1693 len -= 4;
1693 ustr += 4; 1694 ustr += 4;
1694 break; 1695 break;
1695 case 3: 1696 case 3:
1696 k |= (uint32_t)ustr[2] << 16; 1697 k |= (uint32_t)ustr[2] << 16;
1697 /* FALLTHROUGH */ 1698 /* FALLTHROUGH */
1698 case 2: 1699 case 2:
1699 k |= (uint32_t)ustr[1] << 8; 1700 k |= (uint32_t)ustr[1] << 8;
1700 /* FALLTHROUGH */ 1701 /* FALLTHROUGH */
1701 case 1: 1702 case 1:
1702 k |= (uint32_t)ustr[0]; 1703 k |= (uint32_t)ustr[0];
1703 len = 0; 1704 len = 0;
1704 } 1705 }
1705 c1 = c1 * 5 + 0x7b7d159cU; 1706 c1 = c1 * 5 + 0x7b7d159cU;
1706 c2 = c2 * 5 + 0x6bce6396U; 1707 c2 = c2 * 5 + 0x6bce6396U;
1707 k *= c1; 1708 k *= c1;
1708 k = (k << 11) ^ (k >> 21); 1709 k = (k << 11) ^ (k >> 21);
1709 k *= c2; 1710 k *= c2;
1710 h = (h << 13) ^ (h >> 19); 1711 h = (h << 13) ^ (h >> 19);
1711 h = h * 5 + 0x52dce729U; 1712 h = h * 5 + 0x52dce729U;
1712 h ^= k; 1713 h ^= k;
1713 } 1714 }
1714 h ^= (uint32_t)len2; 1715 h ^= (uint32_t)len2;
1715 h *= 0x85ebca6b; 1716 h *= 0x85ebca6b;
1716 h ^= h >> 13; 1717 h ^= h >> 13;
1717 h *= 0xc2b2ae35; 1718 h *= 0xc2b2ae35;
1718 h ^= h >> 16; 1719 h ^= h >> 16;
1719 1720
1720 buf = bmake_malloc(9); 1721 buf = bmake_malloc(9);
1721 for (i = 0; i < 8; i++) { 1722 for (i = 0; i < 8; i++) {
1722 buf[i] = hexdigits[h & 0x0f]; 1723 buf[i] = hexdigits[h & 0x0f];
1723 h >>= 4; 1724 h >>= 4;
1724 } 1725 }
1725 buf[8] = '\0'; 1726 buf[8] = '\0';
1726 return buf; 1727 return buf;
1727} 1728}
1728 1729
1729static char * 1730static char *
1730VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1731VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1731{ 1732{
1732 char buf[BUFSIZ]; 1733 char buf[BUFSIZ];
1733 1734
1734 if (!tim) 1735 if (!tim)
1735 time(&tim); 1736 time(&tim);
1736 if (!*fmt) 1737 if (!*fmt)
1737 fmt = "%c"; 1738 fmt = "%c";
1738 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1739 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1739 1740
1740 buf[sizeof(buf) - 1] = '\0'; 1741 buf[sizeof(buf) - 1] = '\0';
1741 return bmake_strdup(buf); 1742 return bmake_strdup(buf);
1742} 1743}
1743 1744
1744/* The ApplyModifier functions all work in the same way. They get the 1745/* The ApplyModifier functions all work in the same way. They get the
1745 * current parsing position (pp) and parse the modifier from there. The 1746 * current parsing position (pp) and parse the modifier from there. The
1746 * modifier typically lasts until the next ':', or a closing '}' or ')' 1747 * modifier typically lasts until the next ':', or a closing '}' or ')'
1747 * (taken from st->endc), or the end of the string (parse error). 1748 * (taken from st->endc), or the end of the string (parse error).
1748 * 1749 *
1749 * The high-level behavior of these functions is: 1750 * The high-level behavior of these functions is:
1750 * 1751 *
1751 * 1. parse the modifier 1752 * 1. parse the modifier
1752 * 2. evaluate the modifier 1753 * 2. evaluate the modifier
1753 * 3. housekeeping 1754 * 3. housekeeping
1754 * 1755 *
1755 * Parsing the modifier 1756 * Parsing the modifier
1756 * 1757 *
1757 * If parsing succeeds, the parsing position *pp is updated to point to the 1758 * If parsing succeeds, the parsing position *pp is updated to point to the
1758 * first character following the modifier, which typically is either ':' or 1759 * first character following the modifier, which typically is either ':' or
1759 * st->endc. 1760 * st->endc.
1760 * 1761 *
1761 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1762 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1762 * modifiers), return AMR_CLEANUP. 1763 * modifiers), return AMR_CLEANUP.
1763 * 1764 *
1764 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1765 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1765 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1766 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1766 * done as long as there have been no side effects from evaluating nested 1767 * done as long as there have been no side effects from evaluating nested
1767 * variables, to avoid evaluating them more than once. In this case, the 1768 * variables, to avoid evaluating them more than once. In this case, the
1768 * parsing position must not be updated. (XXX: Why not? The original parsing 1769 * parsing position must not be updated. (XXX: Why not? The original parsing
1769 * position is well-known in ApplyModifiers.) 1770 * position is well-known in ApplyModifiers.)
1770 * 1771 *
1771 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1772 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1772 * as a fallback, either issue an error message using Error or Parse_Error 1773 * as a fallback, either issue an error message using Error or Parse_Error
1773 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1774 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1774 * message. Both of these return values will stop processing the variable 1775 * message. Both of these return values will stop processing the variable
1775 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1776 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1776 * continues nevertheless after skipping a few bytes, which essentially is 1777 * continues nevertheless after skipping a few bytes, which essentially is
1777 * undefined behavior. Not in the sense of C, but still it's impossible to 1778 * undefined behavior. Not in the sense of C, but still it's impossible to
1778 * predict what happens in the parser.) 1779 * predict what happens in the parser.)
1779 * 1780 *
1780 * Evaluating the modifier 1781 * Evaluating the modifier
1781 * 1782 *
1782 * After parsing, the modifier is evaluated. The side effects from evaluating 1783 * After parsing, the modifier is evaluated. The side effects from evaluating
1783 * nested variable expressions in the modifier text often already happen 1784 * nested variable expressions in the modifier text often already happen
1784 * during parsing though. 1785 * during parsing though.
1785 * 1786 *
1786 * Evaluating the modifier usually takes the current value of the variable 1787 * Evaluating the modifier usually takes the current value of the variable
1787 * expression from st->val, or the variable name from st->v->name and stores 1788 * expression from st->val, or the variable name from st->v->name and stores
1788 * the result in st->newVal. 1789 * the result in st->newVal.
1789 * 1790 *
1790 * If evaluating fails (as of 2020-08-23), an error message is printed using 1791 * If evaluating fails (as of 2020-08-23), an error message is printed using
1791 * Error. This function has no side-effects, it really just prints the error 1792 * Error. This function has no side-effects, it really just prints the error
1792 * message. Processing the expression continues as if everything were ok. 1793 * message. Processing the expression continues as if everything were ok.
1793 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1794 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1794 * Var_Parse, ApplyModifiers and ModifyWords. 1795 * Var_Parse, ApplyModifiers and ModifyWords.
1795 * 1796 *
1796 * Housekeeping 1797 * Housekeeping
1797 * 1798 *
1798 * Some modifiers such as :D and :U turn undefined expressions into defined 1799 * Some modifiers such as :D and :U turn undefined expressions into defined
1799 * expressions (see VEF_UNDEF, VEF_DEF). 1800 * expressions (see VEF_UNDEF, VEF_DEF).
1800 * 1801 *
1801 * Some modifiers need to free some memory. 1802 * Some modifiers need to free some memory.
1802 */ 1803 */
1803 1804
1804typedef enum VarExprFlags { 1805typedef enum VarExprFlags {
1805 /* The variable expression is based on an undefined variable. */ 1806 /* The variable expression is based on an undefined variable. */
1806 VEF_UNDEF = 0x01, 1807 VEF_UNDEF = 0x01,
1807 /* The variable expression started as an undefined expression, but one 1808 /* The variable expression started as an undefined expression, but one
1808 * of the modifiers (such as :D or :U) has turned the expression from 1809 * of the modifiers (such as :D or :U) has turned the expression from
1809 * undefined to defined. */ 1810 * undefined to defined. */
1810 VEF_DEF = 0x02 1811 VEF_DEF = 0x02
1811} VarExprFlags; 1812} VarExprFlags;
1812 1813
1813ENUM_FLAGS_RTTI_2(VarExprFlags, 1814ENUM_FLAGS_RTTI_2(VarExprFlags,
1814 VEF_UNDEF, VEF_DEF); 1815 VEF_UNDEF, VEF_DEF);
1815 1816
1816 1817
1817typedef struct ApplyModifiersState { 1818typedef struct ApplyModifiersState {
1818 const char startc; /* '\0' or '{' or '(' */ 1819 const char startc; /* '\0' or '{' or '(' */
1819 const char endc; /* '\0' or '}' or ')' */ 1820 const char endc; /* '\0' or '}' or ')' */
1820 Var * const v; 1821 Var * const v;
1821 GNode * const ctxt; 1822 GNode * const ctxt;
1822 const VarEvalFlags eflags; 1823 const VarEvalFlags eflags;
1823 1824
1824 char *val; /* The old value of the expression, 1825 char *val; /* The old value of the expression,
1825 * before applying the modifier, never NULL */ 1826 * before applying the modifier, never NULL */
1826 char *newVal; /* The new value of the expression, 1827 char *newVal; /* The new value of the expression,
1827 * after applying the modifier, never NULL */ 1828 * after applying the modifier, never NULL */
1828 char sep; /* Word separator in expansions 1829 char sep; /* Word separator in expansions
1829 * (see the :ts modifier) */ 1830 * (see the :ts modifier) */
1830 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1831 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1831 * the variable value into words, like :S and 1832 * the variable value into words, like :S and
1832 * :C, treat the variable value as a single big 1833 * :C, treat the variable value as a single big
1833 * word, possibly containing spaces. */ 1834 * word, possibly containing spaces. */
1834 VarExprFlags exprFlags; 1835 VarExprFlags exprFlags;
1835} ApplyModifiersState; 1836} ApplyModifiersState;
1836 1837
1837static void 1838static void
1838ApplyModifiersState_Define(ApplyModifiersState *st) 1839ApplyModifiersState_Define(ApplyModifiersState *st)
1839{ 1840{
1840 if (st->exprFlags & VEF_UNDEF) 1841 if (st->exprFlags & VEF_UNDEF)
1841 st->exprFlags |= VEF_DEF; 1842 st->exprFlags |= VEF_DEF;
1842} 1843}
1843 1844
1844typedef enum ApplyModifierResult { 1845typedef enum ApplyModifierResult {
1845 AMR_OK, /* Continue parsing */ 1846 AMR_OK, /* Continue parsing */
1846 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1847 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1847 AMR_BAD, /* Error out with "Bad modifier" message */ 1848 AMR_BAD, /* Error out with "Bad modifier" message */
1848 AMR_CLEANUP /* Error out without error message */ 1849 AMR_CLEANUP /* Error out without error message */
1849} ApplyModifierResult; 1850} ApplyModifierResult;
1850 1851
1851/*- 1852/*-
1852 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ 1853 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
1853 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and 1854 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
1854 * including the next unescaped delimiter. The delimiter, as well as the 1855 * including the next unescaped delimiter. The delimiter, as well as the
1855 * backslash or the dollar, can be escaped with a backslash. 1856 * backslash or the dollar, can be escaped with a backslash.
1856 * 1857 *
1857 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1858 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1858 * was found. On successful return, the parsing position pp points right 1859 * was found. On successful return, the parsing position pp points right
1859 * after the delimiter. The delimiter is not included in the returned 1860 * after the delimiter. The delimiter is not included in the returned