Fri Oct 30 16:54:38 2020 UTC ()
make(1): fix documentation for VARP_SUB_ONE

The pattern is only replaced a single time, not everywhere in the first
matching word.


(rillig)
diff -r1.603 -r1.604 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/30 16:48:58 1.603
+++ src/usr.bin/make/var.c 2020/10/30 16:54:38 1.604
@@ -1,1283 +1,1283 @@ @@ -1,1283 +1,1283 @@
1/* $NetBSD: var.c,v 1.603 2020/10/30 16:48:58 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.604 2020/10/30 16:54:38 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.603 2020/10/30 16:48:58 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.604 2020/10/30 16:54:38 rillig Exp $");
133 133
134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
138 138
139ENUM_FLAGS_RTTI_3(VarEvalFlags, 139ENUM_FLAGS_RTTI_3(VarEvalFlags,
140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
141 141
142/* 142/*
143 * This lets us tell if we have replaced the original environ 143 * This lets us tell if we have replaced the original environ
144 * (which we cannot free). 144 * (which we cannot free).
145 */ 145 */
146char **savedEnv = NULL; 146char **savedEnv = NULL;
147 147
148/* Special return value for Var_Parse, indicating a parse error. It may be 148/* Special return value for Var_Parse, indicating a parse error. It may be
149 * caused by an undefined variable, a syntax error in a modifier or 149 * caused by an undefined variable, a syntax error in a modifier or
150 * something entirely different. */ 150 * something entirely different. */
151char var_Error[] = ""; 151char var_Error[] = "";
152 152
153/* Special return value for Var_Parse, indicating an undefined variable in 153/* Special return value for Var_Parse, indicating an undefined variable in
154 * a case where VARE_UNDEFERR is not set. This undefined variable is 154 * a case where VARE_UNDEFERR is not set. This undefined variable is
155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
156 * be deferred until it is defined in an actual target. */ 156 * be deferred until it is defined in an actual target. */
157static char varUndefined[] = ""; 157static char varUndefined[] = "";
158 158
159/* Special return value for Var_Parse, just to avoid allocating empty strings. 159/* Special return value for Var_Parse, just to avoid allocating empty strings.
160 * In contrast to var_Error and varUndefined, this is not an error marker but 160 * In contrast to var_Error and varUndefined, this is not an error marker but
161 * just an ordinary successful return value. */ 161 * just an ordinary successful return value. */
162static char emptyString[] = ""; 162static char emptyString[] = "";
163 163
164/* 164/*
165 * Traditionally this make consumed $$ during := like any other expansion. 165 * Traditionally this make consumed $$ during := like any other expansion.
166 * Other make's do not, and this make follows straight since 2016-01-09. 166 * Other make's do not, and this make follows straight since 2016-01-09.
167 * 167 *
168 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
169 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
170 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
171 */ 171 */
172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
173static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
174 174
175/* 175/*
176 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
177 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
178 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
179 * context. 179 * context.
180 * 2) the global context. Variables set in the makefiles are located 180 * 2) the global context. Variables set in the makefiles are located
181 * here. 181 * here.
182 * 3) the command-line context. All variables set on the command line 182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. 183 * are placed in this context.
184 * 4) the local context. Each target has associated with it a context 184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are 187 * The four contexts are searched in the reverse order from which they are
188 * listed (but see opts.checkEnvFirst). 188 * listed (but see opts.checkEnvFirst).
189 */ 189 */
190GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
191GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
192GNode *VAR_CMDLINE; /* variables defined on the command-line */ 192GNode *VAR_CMDLINE; /* variables defined on the command-line */
193 193
194typedef enum VarFlags { 194typedef enum VarFlags {
195 195
196 /* The variable's value is currently being used by Var_Parse or Var_Subst. 196 /* The variable's value is currently being used by Var_Parse or Var_Subst.
197 * This marker is used to avoid endless recursion. */ 197 * This marker is used to avoid endless recursion. */
198 VAR_IN_USE = 0x01, 198 VAR_IN_USE = 0x01,
199 199
200 /* The variable comes from the environment. 200 /* The variable comes from the environment.
201 * These variables are not registered in any GNode, therefore they must 201 * These variables are not registered in any GNode, therefore they must
202 * be freed as soon as they are not used anymore. */ 202 * be freed as soon as they are not used anymore. */
203 VAR_FROM_ENV = 0x02, 203 VAR_FROM_ENV = 0x02,
204 204
205 /* The variable is exported to the environment, to be used by child 205 /* The variable is exported to the environment, to be used by child
206 * processes. */ 206 * processes. */
207 VAR_EXPORTED = 0x10, 207 VAR_EXPORTED = 0x10,
208 208
209 /* At the point where this variable was exported, it contained an 209 /* At the point where this variable was exported, it contained an
210 * unresolved reference to another variable. Before any child process is 210 * unresolved reference to another variable. Before any child process is
211 * started, it needs to be exported again, in the hope that the referenced 211 * started, it needs to be exported again, in the hope that the referenced
212 * variable can then be resolved. */ 212 * variable can then be resolved. */
213 VAR_REEXPORT = 0x20, 213 VAR_REEXPORT = 0x20,
214 214
215 /* The variable came from the command line. */ 215 /* The variable came from the command line. */
216 VAR_FROM_CMD = 0x40, 216 VAR_FROM_CMD = 0x40,
217 217
218 /* The variable value cannot be changed anymore, and the variable cannot 218 /* The variable value cannot be changed anymore, and the variable cannot
219 * be deleted. Any attempts to do so are ignored. */ 219 * be deleted. Any attempts to do so are ignored. */
220 VAR_READONLY = 0x80 220 VAR_READONLY = 0x80
221} VarFlags; 221} VarFlags;
222 222
223ENUM_FLAGS_RTTI_6(VarFlags, 223ENUM_FLAGS_RTTI_6(VarFlags,
224 VAR_IN_USE, VAR_FROM_ENV, 224 VAR_IN_USE, VAR_FROM_ENV,
225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
226 226
227/* Variables are defined using one of the VAR=value assignments. Their 227/* Variables are defined using one of the VAR=value assignments. Their
228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
229 * such as ${VAR:S,from,to,g:Q}. 229 * such as ${VAR:S,from,to,g:Q}.
230 * 230 *
231 * There are 3 kinds of variables: context variables, environment variables, 231 * There are 3 kinds of variables: context variables, environment variables,
232 * undefined variables. 232 * undefined variables.
233 * 233 *
234 * Context variables are stored in a GNode.context. The only way to undefine 234 * Context variables are stored in a GNode.context. The only way to undefine
235 * a context variable is using the .undef directive. In particular, it must 235 * a context variable is using the .undef directive. In particular, it must
236 * not be possible to undefine a variable during the evaluation of an 236 * not be possible to undefine a variable during the evaluation of an
237 * expression, or Var.name might point nowhere. 237 * expression, or Var.name might point nowhere.
238 * 238 *
239 * Environment variables are temporary. They are returned by VarFind, and 239 * Environment variables are temporary. They are returned by VarFind, and
240 * after using them, they must be freed using VarFreeEnv. 240 * after using them, they must be freed using VarFreeEnv.
241 * 241 *
242 * Undefined variables occur during evaluation of variable expressions such 242 * Undefined variables occur during evaluation of variable expressions such
243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
244 */ 244 */
245typedef struct Var { 245typedef struct Var {
246 /* The name of the variable, once set, doesn't change anymore. 246 /* The name of the variable, once set, doesn't change anymore.
247 * For context variables, it aliases the corresponding HashEntry name. 247 * For context variables, it aliases the corresponding HashEntry name.
248 * For environment and undefined variables, it is allocated. */ 248 * For environment and undefined variables, it is allocated. */
249 const char *name; 249 const char *name;
250 void *name_freeIt; 250 void *name_freeIt;
251 251
252 Buffer val; /* its value */ 252 Buffer val; /* its value */
253 VarFlags flags; /* miscellaneous status flags */ 253 VarFlags flags; /* miscellaneous status flags */
254} Var; 254} Var;
255 255
256/* 256/*
257 * Exporting vars is expensive so skip it if we can 257 * Exporting vars is expensive so skip it if we can
258 */ 258 */
259typedef enum VarExportedMode { 259typedef enum VarExportedMode {
260 VAR_EXPORTED_NONE, 260 VAR_EXPORTED_NONE,
261 VAR_EXPORTED_SOME, 261 VAR_EXPORTED_SOME,
262 VAR_EXPORTED_ALL 262 VAR_EXPORTED_ALL
263} VarExportedMode; 263} VarExportedMode;
264 264
265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
266 266
267typedef enum VarExportFlags { 267typedef enum VarExportFlags {
268 /* 268 /*
269 * We pass this to Var_Export when doing the initial export 269 * We pass this to Var_Export when doing the initial export
270 * or after updating an exported var. 270 * or after updating an exported var.
271 */ 271 */
272 VAR_EXPORT_PARENT = 0x01, 272 VAR_EXPORT_PARENT = 0x01,
273 /* 273 /*
274 * We pass this to Var_Export1 to tell it to leave the value alone. 274 * We pass this to Var_Export1 to tell it to leave the value alone.
275 */ 275 */
276 VAR_EXPORT_LITERAL = 0x02 276 VAR_EXPORT_LITERAL = 0x02
277} VarExportFlags; 277} VarExportFlags;
278 278
279/* Flags for pattern matching in the :S and :C modifiers */ 279/* Flags for pattern matching in the :S and :C modifiers */
280typedef enum VarPatternFlags { 280typedef enum VarPatternFlags {
281 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */ 281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
282 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */ 282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
283 VARP_ANCHOR_START = 0x04, /* Match at start of word */ 283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
284 VARP_ANCHOR_END = 0x08 /* Match at end of word */ 284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
285} VarPatternFlags; 285} VarPatternFlags;
286 286
287static Var * 287static Var *
288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
289{ 289{
290 size_t value_len = strlen(value); 290 size_t value_len = strlen(value);
291 Var *var = bmake_malloc(sizeof *var); 291 Var *var = bmake_malloc(sizeof *var);
292 var->name = name; 292 var->name = name;
293 var->name_freeIt = name_freeIt; 293 var->name_freeIt = name_freeIt;
294 Buf_Init(&var->val, value_len + 1); 294 Buf_Init(&var->val, value_len + 1);
295 Buf_AddBytes(&var->val, value, value_len); 295 Buf_AddBytes(&var->val, value, value_len);
296 var->flags = flags; 296 var->flags = flags;
297 return var; 297 return var;
298} 298}
299 299
300static const char * 300static const char *
301CanonicalVarname(const char *name) 301CanonicalVarname(const char *name)
302{ 302{
303 if (*name == '.' && ch_isupper(name[1])) { 303 if (*name == '.' && ch_isupper(name[1])) {
304 switch (name[1]) { 304 switch (name[1]) {
305 case 'A': 305 case 'A':
306 if (strcmp(name, ".ALLSRC") == 0) 306 if (strcmp(name, ".ALLSRC") == 0)
307 name = ALLSRC; 307 name = ALLSRC;
308 if (strcmp(name, ".ARCHIVE") == 0) 308 if (strcmp(name, ".ARCHIVE") == 0)
309 name = ARCHIVE; 309 name = ARCHIVE;
310 break; 310 break;
311 case 'I': 311 case 'I':
312 if (strcmp(name, ".IMPSRC") == 0) 312 if (strcmp(name, ".IMPSRC") == 0)
313 name = IMPSRC; 313 name = IMPSRC;
314 break; 314 break;
315 case 'M': 315 case 'M':
316 if (strcmp(name, ".MEMBER") == 0) 316 if (strcmp(name, ".MEMBER") == 0)
317 name = MEMBER; 317 name = MEMBER;
318 break; 318 break;
319 case 'O': 319 case 'O':
320 if (strcmp(name, ".OODATE") == 0) 320 if (strcmp(name, ".OODATE") == 0)
321 name = OODATE; 321 name = OODATE;
322 break; 322 break;
323 case 'P': 323 case 'P':
324 if (strcmp(name, ".PREFIX") == 0) 324 if (strcmp(name, ".PREFIX") == 0)
325 name = PREFIX; 325 name = PREFIX;
326 break; 326 break;
327 case 'S': 327 case 'S':
328 if (strcmp(name, ".SHELL") == 0) { 328 if (strcmp(name, ".SHELL") == 0) {
329 if (!shellPath) 329 if (!shellPath)
330 Shell_Init(); 330 Shell_Init();
331 } 331 }
332 break; 332 break;
333 case 'T': 333 case 'T':
334 if (strcmp(name, ".TARGET") == 0) 334 if (strcmp(name, ".TARGET") == 0)
335 name = TARGET; 335 name = TARGET;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 339
340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
341 341
342 return name; 342 return name;
343} 343}
344 344
345static Var * 345static Var *
346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
347{ 347{
348 return HashTable_FindValueHash(&ctxt->context, varname, hash); 348 return HashTable_FindValueHash(&ctxt->context, varname, hash);
349} 349}
350 350
351/*- 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 605
606 /* Ouch! Exporting all variables at once is crazy... */ 606 /* Ouch! Exporting all variables at once is crazy... */
607 HashIter_Init(&hi, &VAR_GLOBAL->context); 607 HashIter_Init(&hi, &VAR_GLOBAL->context);
608 while (HashIter_Next(&hi) != NULL) { 608 while (HashIter_Next(&hi) != NULL) {
609 Var *var = hi.entry->value; 609 Var *var = hi.entry->value;
610 Var_Export1(var->name, 0); 610 Var_Export1(var->name, 0);
611 } 611 }
612 return; 612 return;
613 } 613 }
614 614
615 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 615 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
616 /* TODO: handle errors */ 616 /* TODO: handle errors */
617 if (*val) { 617 if (*val) {
618 Words words = Str_Words(val, FALSE); 618 Words words = Str_Words(val, FALSE);
619 size_t i; 619 size_t i;
620 620
621 for (i = 0; i < words.len; i++) 621 for (i = 0; i < words.len; i++)
622 Var_Export1(words.words[i], 0); 622 Var_Export1(words.words[i], 0);
623 Words_Free(words); 623 Words_Free(words);
624 } 624 }
625 free(val); 625 free(val);
626} 626}
627 627
628/* 628/*
629 * This is called when .export is seen or .MAKE.EXPORTED is modified. 629 * This is called when .export is seen or .MAKE.EXPORTED is modified.
630 * 630 *
631 * It is also called when any exported variable is modified. 631 * It is also called when any exported variable is modified.
632 * XXX: Is it really? 632 * XXX: Is it really?
633 * 633 *
634 * str has the format "[-env|-literal] varname...". 634 * str has the format "[-env|-literal] varname...".
635 */ 635 */
636void 636void
637Var_Export(const char *str, Boolean isExport) 637Var_Export(const char *str, Boolean isExport)
638{ 638{
639 VarExportFlags flags; 639 VarExportFlags flags;
640 char *val; 640 char *val;
641 641
642 if (isExport && str[0] == '\0') { 642 if (isExport && str[0] == '\0') {
643 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 643 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
644 return; 644 return;
645 } 645 }
646 646
647 if (isExport && strncmp(str, "-env", 4) == 0) { 647 if (isExport && strncmp(str, "-env", 4) == 0) {
648 str += 4; 648 str += 4;
649 flags = 0; 649 flags = 0;
650 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 650 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
651 str += 8; 651 str += 8;
652 flags = VAR_EXPORT_LITERAL; 652 flags = VAR_EXPORT_LITERAL;
653 } else { 653 } else {
654 flags = VAR_EXPORT_PARENT; 654 flags = VAR_EXPORT_PARENT;
655 } 655 }
656 656
657 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 657 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
658 /* TODO: handle errors */ 658 /* TODO: handle errors */
659 if (val[0] != '\0') { 659 if (val[0] != '\0') {
660 Words words = Str_Words(val, FALSE); 660 Words words = Str_Words(val, FALSE);
661 661
662 size_t i; 662 size_t i;
663 for (i = 0; i < words.len; i++) { 663 for (i = 0; i < words.len; i++) {
664 const char *name = words.words[i]; 664 const char *name = words.words[i];
665 if (Var_Export1(name, flags)) { 665 if (Var_Export1(name, flags)) {
666 if (var_exportedVars == VAR_EXPORTED_NONE) 666 if (var_exportedVars == VAR_EXPORTED_NONE)
667 var_exportedVars = VAR_EXPORTED_SOME; 667 var_exportedVars = VAR_EXPORTED_SOME;
668 if (isExport && (flags & VAR_EXPORT_PARENT)) { 668 if (isExport && (flags & VAR_EXPORT_PARENT)) {
669 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 669 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
670 } 670 }
671 } 671 }
672 } 672 }
673 Words_Free(words); 673 Words_Free(words);
674 } 674 }
675 free(val); 675 free(val);
676} 676}
677 677
678 678
679extern char **environ; 679extern char **environ;
680 680
681/* 681/*
682 * This is called when .unexport[-env] is seen. 682 * This is called when .unexport[-env] is seen.
683 * 683 *
684 * str must have the form "unexport[-env] varname...". 684 * str must have the form "unexport[-env] varname...".
685 */ 685 */
686void 686void
687Var_UnExport(const char *str) 687Var_UnExport(const char *str)
688{ 688{
689 const char *varnames; 689 const char *varnames;
690 char *varnames_freeIt; 690 char *varnames_freeIt;
691 Boolean unexport_env; 691 Boolean unexport_env;
692 692
693 varnames = NULL; 693 varnames = NULL;
694 varnames_freeIt = NULL; 694 varnames_freeIt = NULL;
695 695
696 str += strlen("unexport"); 696 str += strlen("unexport");
697 unexport_env = strncmp(str, "-env", 4) == 0; 697 unexport_env = strncmp(str, "-env", 4) == 0;
698 if (unexport_env) { 698 if (unexport_env) {
699 const char *cp; 699 const char *cp;
700 char **newenv; 700 char **newenv;
701 701
702 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 702 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
703 if (environ == savedEnv) { 703 if (environ == savedEnv) {
704 /* we have been here before! */ 704 /* we have been here before! */
705 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 705 newenv = bmake_realloc(environ, 2 * sizeof(char *));
706 } else { 706 } else {
707 if (savedEnv) { 707 if (savedEnv) {
708 free(savedEnv); 708 free(savedEnv);
709 savedEnv = NULL; 709 savedEnv = NULL;
710 } 710 }
711 newenv = bmake_malloc(2 * sizeof(char *)); 711 newenv = bmake_malloc(2 * sizeof(char *));
712 } 712 }
713 713
714 /* Note: we cannot safely free() the original environ. */ 714 /* Note: we cannot safely free() the original environ. */
715 environ = savedEnv = newenv; 715 environ = savedEnv = newenv;
716 newenv[0] = NULL; 716 newenv[0] = NULL;
717 newenv[1] = NULL; 717 newenv[1] = NULL;
718 if (cp && *cp) 718 if (cp && *cp)
719 setenv(MAKE_LEVEL_ENV, cp, 1); 719 setenv(MAKE_LEVEL_ENV, cp, 1);
720 } else { 720 } else {
721 cpp_skip_whitespace(&str); 721 cpp_skip_whitespace(&str);
722 if (str[0] != '\0') 722 if (str[0] != '\0')
723 varnames = str; 723 varnames = str;
724 } 724 }
725 725
726 if (varnames == NULL) { 726 if (varnames == NULL) {
727 /* Using .MAKE.EXPORTED */ 727 /* Using .MAKE.EXPORTED */
728 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 728 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
729 &varnames_freeIt); 729 &varnames_freeIt);
730 /* TODO: handle errors */ 730 /* TODO: handle errors */
731 varnames = varnames_freeIt; 731 varnames = varnames_freeIt;
732 } 732 }
733 733
734 { 734 {
735 Var *v; 735 Var *v;
736 size_t i; 736 size_t i;
737 737
738 Words words = Str_Words(varnames, FALSE); 738 Words words = Str_Words(varnames, FALSE);
739 for (i = 0; i < words.len; i++) { 739 for (i = 0; i < words.len; i++) {
740 const char *varname = words.words[i]; 740 const char *varname = words.words[i];
741 v = VarFind(varname, VAR_GLOBAL, 0); 741 v = VarFind(varname, VAR_GLOBAL, 0);
742 if (v == NULL) { 742 if (v == NULL) {
743 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 743 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
744 continue; 744 continue;
745 } 745 }
746 746
747 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 747 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
748 if (!unexport_env && (v->flags & VAR_EXPORTED) && 748 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
749 !(v->flags & VAR_REEXPORT)) 749 !(v->flags & VAR_REEXPORT))
750 unsetenv(v->name); 750 unsetenv(v->name);
751 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 751 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
752 752
753 /* 753 /*
754 * If we are unexporting a list, 754 * If we are unexporting a list,
755 * remove each one from .MAKE.EXPORTED. 755 * remove each one from .MAKE.EXPORTED.
756 * If we are removing them all, 756 * If we are removing them all,
757 * just delete .MAKE.EXPORTED below. 757 * just delete .MAKE.EXPORTED below.
758 */ 758 */
759 if (varnames == str) { 759 if (varnames == str) {
760 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 760 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
761 char *cp; 761 char *cp;
762 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 762 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
763 /* TODO: handle errors */ 763 /* TODO: handle errors */
764 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 764 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
765 free(cp); 765 free(cp);
766 free(expr); 766 free(expr);
767 } 767 }
768 } 768 }
769 Words_Free(words); 769 Words_Free(words);
770 if (varnames != str) { 770 if (varnames != str) {
771 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 771 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
772 free(varnames_freeIt); 772 free(varnames_freeIt);
773 } 773 }
774 } 774 }
775} 775}
776 776
777/* See Var_Set for documentation. */ 777/* See Var_Set for documentation. */
778void 778void
779Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 779Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
780 VarSet_Flags flags) 780 VarSet_Flags flags)
781{ 781{
782 const char *unexpanded_name = name; 782 const char *unexpanded_name = name;
783 char *name_freeIt = NULL; 783 char *name_freeIt = NULL;
784 Var *v; 784 Var *v;
785 785
786 assert(val != NULL); 786 assert(val != NULL);
787 787
788 if (strchr(name, '$') != NULL) { 788 if (strchr(name, '$') != NULL) {
789 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 789 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
790 /* TODO: handle errors */ 790 /* TODO: handle errors */
791 name = name_freeIt; 791 name = name_freeIt;
792 } 792 }
793 793
794 if (name[0] == '\0') { 794 if (name[0] == '\0') {
795 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 795 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
796 "name expands to empty string - ignored\n", 796 "name expands to empty string - ignored\n",
797 unexpanded_name, val); 797 unexpanded_name, val);
798 free(name_freeIt); 798 free(name_freeIt);
799 return; 799 return;
800 } 800 }
801 801
802 if (ctxt == VAR_GLOBAL) { 802 if (ctxt == VAR_GLOBAL) {
803 v = VarFind(name, VAR_CMDLINE, 0); 803 v = VarFind(name, VAR_CMDLINE, 0);
804 if (v != NULL) { 804 if (v != NULL) {
805 if (v->flags & VAR_FROM_CMD) { 805 if (v->flags & VAR_FROM_CMD) {
806 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 806 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
807 goto out; 807 goto out;
808 } 808 }
809 VarFreeEnv(v, TRUE); 809 VarFreeEnv(v, TRUE);
810 } 810 }
811 } 811 }
812 812
813 /* 813 /*
814 * We only look for a variable in the given context since anything set 814 * We only look for a variable in the given context since anything set
815 * here will override anything in a lower context, so there's not much 815 * here will override anything in a lower context, so there's not much
816 * point in searching them all just to save a bit of memory... 816 * point in searching them all just to save a bit of memory...
817 */ 817 */
818 v = VarFind(name, ctxt, 0); 818 v = VarFind(name, ctxt, 0);
819 if (v == NULL) { 819 if (v == NULL) {
820 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 820 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
821 /* 821 /*
822 * This var would normally prevent the same name being added 822 * This var would normally prevent the same name being added
823 * to VAR_GLOBAL, so delete it from there if needed. 823 * to VAR_GLOBAL, so delete it from there if needed.
824 * Otherwise -V name may show the wrong value. 824 * Otherwise -V name may show the wrong value.
825 */ 825 */
826 Var_Delete(name, VAR_GLOBAL); 826 Var_Delete(name, VAR_GLOBAL);
827 } 827 }
828 VarAdd(name, val, ctxt, flags); 828 VarAdd(name, val, ctxt, flags);
829 } else { 829 } else {
830 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 830 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
831 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 831 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
832 ctxt->name, name, val); 832 ctxt->name, name, val);
833 goto out; 833 goto out;
834 } 834 }
835 Buf_Empty(&v->val); 835 Buf_Empty(&v->val);
836 if (val) 836 if (val)
837 Buf_AddStr(&v->val, val); 837 Buf_AddStr(&v->val, val);
838 838
839 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 839 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
840 if (v->flags & VAR_EXPORTED) { 840 if (v->flags & VAR_EXPORTED) {
841 Var_Export1(name, VAR_EXPORT_PARENT); 841 Var_Export1(name, VAR_EXPORT_PARENT);
842 } 842 }
843 } 843 }
844 /* 844 /*
845 * Any variables given on the command line are automatically exported 845 * Any variables given on the command line are automatically exported
846 * to the environment (as per POSIX standard) 846 * to the environment (as per POSIX standard)
847 * Other than internals. 847 * Other than internals.
848 */ 848 */
849 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 849 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
850 if (v == NULL) { 850 if (v == NULL) {
851 /* we just added it */ 851 /* we just added it */
852 v = VarFind(name, ctxt, 0); 852 v = VarFind(name, ctxt, 0);
853 } 853 }
854 if (v != NULL) 854 if (v != NULL)
855 v->flags |= VAR_FROM_CMD; 855 v->flags |= VAR_FROM_CMD;
856 /* 856 /*
857 * If requested, don't export these in the environment 857 * If requested, don't export these in the environment
858 * individually. We still put them in MAKEOVERRIDES so 858 * individually. We still put them in MAKEOVERRIDES so
859 * that the command-line settings continue to override 859 * that the command-line settings continue to override
860 * Makefile settings. 860 * Makefile settings.
861 */ 861 */
862 if (!opts.varNoExportEnv) 862 if (!opts.varNoExportEnv)
863 setenv(name, val ? val : "", 1); 863 setenv(name, val ? val : "", 1);
864 864
865 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 865 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
866 } 866 }
867 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 867 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
868 save_dollars = s2Boolean(val, save_dollars); 868 save_dollars = s2Boolean(val, save_dollars);
869 869
870out: 870out:
871 free(name_freeIt); 871 free(name_freeIt);
872 if (v != NULL) 872 if (v != NULL)
873 VarFreeEnv(v, TRUE); 873 VarFreeEnv(v, TRUE);
874} 874}
875 875
876/*- 876/*-
877 *----------------------------------------------------------------------- 877 *-----------------------------------------------------------------------
878 * Var_Set -- 878 * Var_Set --
879 * Set the variable name to the value val in the given context. 879 * Set the variable name to the value val in the given context.
880 * 880 *
881 * If the variable doesn't yet exist, it is created. 881 * If the variable doesn't yet exist, it is created.
882 * Otherwise the new value overwrites and replaces the old value. 882 * Otherwise the new value overwrites and replaces the old value.
883 * 883 *
884 * Input: 884 * Input:
885 * name name of variable to set 885 * name name of variable to set
886 * val value to give to the variable 886 * val value to give to the variable
887 * ctxt context in which to set it 887 * ctxt context in which to set it
888 * 888 *
889 * Notes: 889 * Notes:
890 * The variable is searched for only in its context before being 890 * The variable is searched for only in its context before being
891 * created in that context. I.e. if the context is VAR_GLOBAL, 891 * created in that context. I.e. if the context is VAR_GLOBAL,
892 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 892 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
893 * only VAR_CMDLINE->context is searched. This is done to avoid the 893 * only VAR_CMDLINE->context is searched. This is done to avoid the
894 * literally thousands of unnecessary strcmp's that used to be done to 894 * literally thousands of unnecessary strcmp's that used to be done to
895 * set, say, $(@) or $(<). 895 * set, say, $(@) or $(<).
896 * If the context is VAR_GLOBAL though, we check if the variable 896 * If the context is VAR_GLOBAL though, we check if the variable
897 * was set in VAR_CMDLINE from the command line and skip it if so. 897 * was set in VAR_CMDLINE from the command line and skip it if so.
898 *----------------------------------------------------------------------- 898 *-----------------------------------------------------------------------
899 */ 899 */
900void 900void
901Var_Set(const char *name, const char *val, GNode *ctxt) 901Var_Set(const char *name, const char *val, GNode *ctxt)
902{ 902{
903 Var_Set_with_flags(name, val, ctxt, 0); 903 Var_Set_with_flags(name, val, ctxt, 0);
904} 904}
905 905
906/*- 906/*-
907 *----------------------------------------------------------------------- 907 *-----------------------------------------------------------------------
908 * Var_Append -- 908 * Var_Append --
909 * The variable of the given name has the given value appended to it in 909 * The variable of the given name has the given value appended to it in
910 * the given context. 910 * the given context.
911 * 911 *
912 * If the variable doesn't exist, it is created. Otherwise the strings 912 * If the variable doesn't exist, it is created. Otherwise the strings
913 * are concatenated, with a space in between. 913 * are concatenated, with a space in between.
914 * 914 *
915 * Input: 915 * Input:
916 * name name of variable to modify 916 * name name of variable to modify
917 * val string to append to it 917 * val string to append to it
918 * ctxt context in which this should occur 918 * ctxt context in which this should occur
919 * 919 *
920 * Notes: 920 * Notes:
921 * Only if the variable is being sought in the global context is the 921 * Only if the variable is being sought in the global context is the
922 * environment searched. 922 * environment searched.
923 * XXX: Knows its calling circumstances in that if called with ctxt 923 * XXX: Knows its calling circumstances in that if called with ctxt
924 * an actual target, it will only search that context since only 924 * an actual target, it will only search that context since only
925 * a local variable could be being appended to. This is actually 925 * a local variable could be being appended to. This is actually
926 * a big win and must be tolerated. 926 * a big win and must be tolerated.
927 *----------------------------------------------------------------------- 927 *-----------------------------------------------------------------------
928 */ 928 */
929void 929void
930Var_Append(const char *name, const char *val, GNode *ctxt) 930Var_Append(const char *name, const char *val, GNode *ctxt)
931{ 931{
932 char *name_freeIt = NULL; 932 char *name_freeIt = NULL;
933 Var *v; 933 Var *v;
934 934
935 assert(val != NULL); 935 assert(val != NULL);
936 936
937 if (strchr(name, '$') != NULL) { 937 if (strchr(name, '$') != NULL) {
938 const char *unexpanded_name = name; 938 const char *unexpanded_name = name;
939 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 939 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
940 /* TODO: handle errors */ 940 /* TODO: handle errors */
941 name = name_freeIt; 941 name = name_freeIt;
942 if (name[0] == '\0') { 942 if (name[0] == '\0') {
943 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 943 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
944 "name expands to empty string - ignored\n", 944 "name expands to empty string - ignored\n",
945 unexpanded_name, val); 945 unexpanded_name, val);
946 free(name_freeIt); 946 free(name_freeIt);
947 return; 947 return;
948 } 948 }
949 } 949 }
950 950
951 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 951 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
952 952
953 if (v == NULL) { 953 if (v == NULL) {
954 Var_Set(name, val, ctxt); 954 Var_Set(name, val, ctxt);
955 } else if (v->flags & VAR_READONLY) { 955 } else if (v->flags & VAR_READONLY) {
956 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 956 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
957 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 957 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
958 Buf_AddByte(&v->val, ' '); 958 Buf_AddByte(&v->val, ' ');
959 Buf_AddStr(&v->val, val); 959 Buf_AddStr(&v->val, val);
960 960
961 VAR_DEBUG3("%s:%s = %s\n", 961 VAR_DEBUG3("%s:%s = %s\n",
962 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 962 ctxt->name, name, Buf_GetAll(&v->val, NULL));
963 963
964 if (v->flags & VAR_FROM_ENV) { 964 if (v->flags & VAR_FROM_ENV) {
965 HashEntry *h; 965 HashEntry *h;
966 966
967 /* 967 /*
968 * If the original variable came from the environment, we 968 * If the original variable came from the environment, we
969 * have to install it in the global context (we could place 969 * have to install it in the global context (we could place
970 * it in the environment, but then we should provide a way to 970 * it in the environment, but then we should provide a way to
971 * export other variables...) 971 * export other variables...)
972 */ 972 */
973 v->flags &= ~(unsigned)VAR_FROM_ENV; 973 v->flags &= ~(unsigned)VAR_FROM_ENV;
974 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 974 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
975 HashEntry_Set(h, v); 975 HashEntry_Set(h, v);
976 } 976 }
977 } 977 }
978 free(name_freeIt); 978 free(name_freeIt);
979} 979}
980 980
981/* See if the given variable exists, in the given context or in other 981/* See if the given variable exists, in the given context or in other
982 * fallback contexts. 982 * fallback contexts.
983 * 983 *
984 * Input: 984 * Input:
985 * name Variable to find 985 * name Variable to find
986 * ctxt Context in which to start search 986 * ctxt Context in which to start search
987 */ 987 */
988Boolean 988Boolean
989Var_Exists(const char *name, GNode *ctxt) 989Var_Exists(const char *name, GNode *ctxt)
990{ 990{
991 char *name_freeIt = NULL; 991 char *name_freeIt = NULL;
992 Var *v; 992 Var *v;
993 993
994 if (strchr(name, '$') != NULL) { 994 if (strchr(name, '$') != NULL) {
995 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 995 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
996 /* TODO: handle errors */ 996 /* TODO: handle errors */
997 name = name_freeIt; 997 name = name_freeIt;
998 } 998 }
999 999
1000 v = VarFind(name, ctxt, TRUE); 1000 v = VarFind(name, ctxt, TRUE);
1001 free(name_freeIt); 1001 free(name_freeIt);
1002 if (v == NULL) 1002 if (v == NULL)
1003 return FALSE; 1003 return FALSE;
1004 1004
1005 (void)VarFreeEnv(v, TRUE); 1005 (void)VarFreeEnv(v, TRUE);
1006 return TRUE; 1006 return TRUE;
1007} 1007}
1008 1008
1009/*- 1009/*-
1010 *----------------------------------------------------------------------- 1010 *-----------------------------------------------------------------------
1011 * Var_Value -- 1011 * Var_Value --
1012 * Return the unexpanded value of the given variable in the given 1012 * Return the unexpanded value of the given variable in the given
1013 * context, or the usual contexts. 1013 * context, or the usual contexts.
1014 * 1014 *
1015 * Input: 1015 * Input:
1016 * name name to find 1016 * name name to find
1017 * ctxt context in which to search for it 1017 * ctxt context in which to search for it
1018 * 1018 *
1019 * Results: 1019 * Results:
1020 * The value if the variable exists, NULL if it doesn't. 1020 * The value if the variable exists, NULL if it doesn't.
1021 * If the returned value is not NULL, the caller must free *freeIt 1021 * If the returned value is not NULL, the caller must free *freeIt
1022 * as soon as the returned value is no longer needed. 1022 * as soon as the returned value is no longer needed.
1023 *----------------------------------------------------------------------- 1023 *-----------------------------------------------------------------------
1024 */ 1024 */
1025const char * 1025const char *
1026Var_Value(const char *name, GNode *ctxt, char **freeIt) 1026Var_Value(const char *name, GNode *ctxt, char **freeIt)
1027{ 1027{
1028 Var *v = VarFind(name, ctxt, TRUE); 1028 Var *v = VarFind(name, ctxt, TRUE);
1029 char *p; 1029 char *p;
1030 1030
1031 *freeIt = NULL; 1031 *freeIt = NULL;
1032 if (v == NULL) 1032 if (v == NULL)
1033 return NULL; 1033 return NULL;
1034 1034
1035 p = Buf_GetAll(&v->val, NULL); 1035 p = Buf_GetAll(&v->val, NULL);
1036 if (VarFreeEnv(v, FALSE)) 1036 if (VarFreeEnv(v, FALSE))
1037 *freeIt = p; 1037 *freeIt = p;
1038 return p; 1038 return p;
1039} 1039}
1040 1040
1041 1041
1042/* SepBuf is a string being built from "words", interleaved with separators. */ 1042/* SepBuf is a string being built from "words", interleaved with separators. */
1043typedef struct SepBuf { 1043typedef struct SepBuf {
1044 Buffer buf; 1044 Buffer buf;
1045 Boolean needSep; 1045 Boolean needSep;
1046 char sep; /* usually ' ', but see the :ts modifier */ 1046 char sep; /* usually ' ', but see the :ts modifier */
1047} SepBuf; 1047} SepBuf;
1048 1048
1049static void 1049static void
1050SepBuf_Init(SepBuf *buf, char sep) 1050SepBuf_Init(SepBuf *buf, char sep)
1051{ 1051{
1052 Buf_Init(&buf->buf, 32 /* bytes */); 1052 Buf_Init(&buf->buf, 32 /* bytes */);
1053 buf->needSep = FALSE; 1053 buf->needSep = FALSE;
1054 buf->sep = sep; 1054 buf->sep = sep;
1055} 1055}
1056 1056
1057static void 1057static void
1058SepBuf_Sep(SepBuf *buf) 1058SepBuf_Sep(SepBuf *buf)
1059{ 1059{
1060 buf->needSep = TRUE; 1060 buf->needSep = TRUE;
1061} 1061}
1062 1062
1063static void 1063static void
1064SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1064SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1065{ 1065{
1066 if (mem_size == 0) 1066 if (mem_size == 0)
1067 return; 1067 return;
1068 if (buf->needSep && buf->sep != '\0') { 1068 if (buf->needSep && buf->sep != '\0') {
1069 Buf_AddByte(&buf->buf, buf->sep); 1069 Buf_AddByte(&buf->buf, buf->sep);
1070 buf->needSep = FALSE; 1070 buf->needSep = FALSE;
1071 } 1071 }
1072 Buf_AddBytes(&buf->buf, mem, mem_size); 1072 Buf_AddBytes(&buf->buf, mem, mem_size);
1073} 1073}
1074 1074
1075static void 1075static void
1076SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1076SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1077{ 1077{
1078 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1078 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1079} 1079}
1080 1080
1081static void 1081static void
1082SepBuf_AddStr(SepBuf *buf, const char *str) 1082SepBuf_AddStr(SepBuf *buf, const char *str)
1083{ 1083{
1084 SepBuf_AddBytes(buf, str, strlen(str)); 1084 SepBuf_AddBytes(buf, str, strlen(str));
1085} 1085}
1086 1086
1087static char * 1087static char *
1088SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1088SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1089{ 1089{
1090 return Buf_Destroy(&buf->buf, free_buf); 1090 return Buf_Destroy(&buf->buf, free_buf);
1091} 1091}
1092 1092
1093 1093
1094/* This callback for ModifyWords gets a single word from an expression and 1094/* This callback for ModifyWords gets a single word from an expression and
1095 * typically adds a modification of this word to the buffer. It may also do 1095 * typically adds a modification of this word to the buffer. It may also do
1096 * nothing or add several words. */ 1096 * nothing or add several words. */
1097typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1097typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1098 1098
1099 1099
1100/* Callback for ModifyWords to implement the :H modifier. 1100/* Callback for ModifyWords to implement the :H modifier.
1101 * Add the dirname of the given word to the buffer. */ 1101 * Add the dirname of the given word to the buffer. */
1102static void 1102static void
1103ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1103ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1104{ 1104{
1105 const char *slash = strrchr(word, '/'); 1105 const char *slash = strrchr(word, '/');
1106 if (slash != NULL) 1106 if (slash != NULL)
1107 SepBuf_AddBytesBetween(buf, word, slash); 1107 SepBuf_AddBytesBetween(buf, word, slash);
1108 else 1108 else
1109 SepBuf_AddStr(buf, "."); 1109 SepBuf_AddStr(buf, ".");
1110} 1110}
1111 1111
1112/* Callback for ModifyWords to implement the :T modifier. 1112/* Callback for ModifyWords to implement the :T modifier.
1113 * Add the basename of the given word to the buffer. */ 1113 * Add the basename of the given word to the buffer. */
1114static void 1114static void
1115ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1115ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1116{ 1116{
1117 const char *slash = strrchr(word, '/'); 1117 const char *slash = strrchr(word, '/');
1118 const char *base = slash != NULL ? slash + 1 : word; 1118 const char *base = slash != NULL ? slash + 1 : word;
1119 SepBuf_AddStr(buf, base); 1119 SepBuf_AddStr(buf, base);
1120} 1120}
1121 1121
1122/* Callback for ModifyWords to implement the :E modifier. 1122/* Callback for ModifyWords to implement the :E modifier.
1123 * Add the filename suffix of the given word to the buffer, if it exists. */ 1123 * Add the filename suffix of the given word to the buffer, if it exists. */
1124static void 1124static void
1125ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1125ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1126{ 1126{
1127 const char *dot = strrchr(word, '.'); 1127 const char *dot = strrchr(word, '.');
1128 if (dot != NULL) 1128 if (dot != NULL)
1129 SepBuf_AddStr(buf, dot + 1); 1129 SepBuf_AddStr(buf, dot + 1);
1130} 1130}
1131 1131
1132/* Callback for ModifyWords to implement the :R modifier. 1132/* Callback for ModifyWords to implement the :R modifier.
1133 * Add the basename of the given word to the buffer. */ 1133 * Add the basename of the given word to the buffer. */
1134static void 1134static void
1135ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1135ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1136{ 1136{
1137 const char *dot = strrchr(word, '.'); 1137 const char *dot = strrchr(word, '.');
1138 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1138 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1139 SepBuf_AddBytes(buf, word, len); 1139 SepBuf_AddBytes(buf, word, len);
1140} 1140}
1141 1141
1142/* Callback for ModifyWords to implement the :M modifier. 1142/* Callback for ModifyWords to implement the :M modifier.
1143 * Place the word in the buffer if it matches the given pattern. */ 1143 * Place the word in the buffer if it matches the given pattern. */
1144static void 1144static void
1145ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1145ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1146{ 1146{
1147 const char *pattern = data; 1147 const char *pattern = data;
1148 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1148 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1149 if (Str_Match(word, pattern)) 1149 if (Str_Match(word, pattern))
1150 SepBuf_AddStr(buf, word); 1150 SepBuf_AddStr(buf, word);
1151} 1151}
1152 1152
1153/* Callback for ModifyWords to implement the :N modifier. 1153/* Callback for ModifyWords to implement the :N modifier.
1154 * Place the word in the buffer if it doesn't match the given pattern. */ 1154 * Place the word in the buffer if it doesn't match the given pattern. */
1155static void 1155static void
1156ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1156ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1157{ 1157{
1158 const char *pattern = data; 1158 const char *pattern = data;
1159 if (!Str_Match(word, pattern)) 1159 if (!Str_Match(word, pattern))
1160 SepBuf_AddStr(buf, word); 1160 SepBuf_AddStr(buf, word);
1161} 1161}
1162 1162
1163#ifdef SYSVVARSUB 1163#ifdef SYSVVARSUB
1164/*- 1164/*-
1165 *----------------------------------------------------------------------- 1165 *-----------------------------------------------------------------------
1166 * Str_SYSVMatch -- 1166 * Str_SYSVMatch --
1167 * Check word against pattern for a match (% is wild), 1167 * Check word against pattern for a match (% is wild),
1168 * 1168 *
1169 * Input: 1169 * Input:
1170 * word Word to examine 1170 * word Word to examine
1171 * pattern Pattern to examine against 1171 * pattern Pattern to examine against
1172 * 1172 *
1173 * Results: 1173 * Results:
1174 * Returns the start of the match, or NULL. 1174 * Returns the start of the match, or NULL.
1175 * *match_len returns the length of the match, if any. 1175 * *match_len returns the length of the match, if any.
1176 * *hasPercent returns whether the pattern contains a percent. 1176 * *hasPercent returns whether the pattern contains a percent.
1177 *----------------------------------------------------------------------- 1177 *-----------------------------------------------------------------------
1178 */ 1178 */
1179static const char * 1179static const char *
1180Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len, 1180Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len,
1181 Boolean *hasPercent) 1181 Boolean *hasPercent)
1182{ 1182{
1183 const char *p = pattern; 1183 const char *p = pattern;
1184 const char *w = word; 1184 const char *w = word;
1185 const char *percent; 1185 const char *percent;
1186 size_t w_len; 1186 size_t w_len;
1187 size_t p_len; 1187 size_t p_len;
1188 const char *w_tail; 1188 const char *w_tail;
1189 1189
1190 *hasPercent = FALSE; 1190 *hasPercent = FALSE;
1191 if (*p == '\0') { /* ${VAR:=suffix} */ 1191 if (*p == '\0') { /* ${VAR:=suffix} */
1192 *match_len = strlen(w); /* Null pattern is the whole string */ 1192 *match_len = strlen(w); /* Null pattern is the whole string */
1193 return w; 1193 return w;
1194 } 1194 }
1195 1195
1196 percent = strchr(p, '%'); 1196 percent = strchr(p, '%');
1197 if (percent != NULL) { /* ${VAR:...%...=...} */ 1197 if (percent != NULL) { /* ${VAR:...%...=...} */
1198 *hasPercent = TRUE; 1198 *hasPercent = TRUE;
1199 if (*w == '\0') 1199 if (*w == '\0')
1200 return NULL; /* empty word does not match pattern */ 1200 return NULL; /* empty word does not match pattern */
1201 1201
1202 /* check that the prefix matches */ 1202 /* check that the prefix matches */
1203 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1203 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1204 continue; 1204 continue;
1205 if (p != percent) 1205 if (p != percent)
1206 return NULL; /* No match */ 1206 return NULL; /* No match */
1207 1207
1208 p++; /* Skip the percent */ 1208 p++; /* Skip the percent */
1209 if (*p == '\0') { 1209 if (*p == '\0') {
1210 /* No more pattern, return the rest of the string */ 1210 /* No more pattern, return the rest of the string */
1211 *match_len = strlen(w); 1211 *match_len = strlen(w);
1212 return w; 1212 return w;
1213 } 1213 }
1214 } 1214 }
1215 1215
1216 /* Test whether the tail matches */ 1216 /* Test whether the tail matches */
1217 w_len = strlen(w); 1217 w_len = strlen(w);
1218 p_len = strlen(p); 1218 p_len = strlen(p);
1219 if (w_len < p_len) 1219 if (w_len < p_len)
1220 return NULL; 1220 return NULL;
1221 1221
1222 w_tail = w + w_len - p_len; 1222 w_tail = w + w_len - p_len;
1223 if (memcmp(p, w_tail, p_len) != 0) 1223 if (memcmp(p, w_tail, p_len) != 0)
1224 return NULL; 1224 return NULL;
1225 1225
1226 *match_len = (size_t)(w_tail - w); 1226 *match_len = (size_t)(w_tail - w);
1227 return w; 1227 return w;
1228} 1228}
1229 1229
1230struct ModifyWord_SYSVSubstArgs { 1230struct ModifyWord_SYSVSubstArgs {
1231 GNode *ctx; 1231 GNode *ctx;
1232 const char *lhs; 1232 const char *lhs;
1233 const char *rhs; 1233 const char *rhs;
1234}; 1234};
1235 1235
1236/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1236/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1237static void 1237static void
1238ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1238ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1239{ 1239{
1240 const struct ModifyWord_SYSVSubstArgs *args = data; 1240 const struct ModifyWord_SYSVSubstArgs *args = data;
1241 char *rhs_expanded; 1241 char *rhs_expanded;
1242 const char *rhs; 1242 const char *rhs;
1243 const char *percent; 1243 const char *percent;
1244 1244
1245 size_t match_len; 1245 size_t match_len;
1246 Boolean lhsPercent; 1246 Boolean lhsPercent;
1247 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent); 1247 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent);
1248 if (match == NULL) { 1248 if (match == NULL) {
1249 SepBuf_AddStr(buf, word); 1249 SepBuf_AddStr(buf, word);
1250 return; 1250 return;
1251 } 1251 }
1252 1252
1253 /* Append rhs to the buffer, substituting the first '%' with the 1253 /* Append rhs to the buffer, substituting the first '%' with the
1254 * match, but only if the lhs had a '%' as well. */ 1254 * match, but only if the lhs had a '%' as well. */
1255 1255
1256 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1256 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1257 /* TODO: handle errors */ 1257 /* TODO: handle errors */
1258 1258
1259 rhs = rhs_expanded; 1259 rhs = rhs_expanded;
1260 percent = strchr(rhs, '%'); 1260 percent = strchr(rhs, '%');
1261 1261
1262 if (percent != NULL && lhsPercent) { 1262 if (percent != NULL && lhsPercent) {
1263 /* Copy the prefix of the replacement pattern */ 1263 /* Copy the prefix of the replacement pattern */
1264 SepBuf_AddBytesBetween(buf, rhs, percent); 1264 SepBuf_AddBytesBetween(buf, rhs, percent);
1265 rhs = percent + 1; 1265 rhs = percent + 1;
1266 } 1266 }
1267 if (percent != NULL || !lhsPercent) 1267 if (percent != NULL || !lhsPercent)
1268 SepBuf_AddBytes(buf, match, match_len); 1268 SepBuf_AddBytes(buf, match, match_len);
1269 1269
1270 /* Append the suffix of the replacement pattern */ 1270 /* Append the suffix of the replacement pattern */
1271 SepBuf_AddStr(buf, rhs); 1271 SepBuf_AddStr(buf, rhs);
1272 1272
1273 free(rhs_expanded); 1273 free(rhs_expanded);
1274} 1274}
1275#endif 1275#endif
1276 1276
1277 1277
1278struct ModifyWord_SubstArgs { 1278struct ModifyWord_SubstArgs {
1279 const char *lhs; 1279 const char *lhs;
1280 size_t lhsLen; 1280 size_t lhsLen;
1281 const char *rhs; 1281 const char *rhs;
1282 size_t rhsLen; 1282 size_t rhsLen;
1283 VarPatternFlags pflags; 1283 VarPatternFlags pflags;