Fri Oct 30 16:45:37 2020 UTC ()
make(1): rename VAR_EXPORTED_YES to VAR_EXPORTED_SOME

The "yes" sounded too much like "all".


(rillig)
diff -r1.601 -r1.602 src/usr.bin/make/var.c

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

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