Sun Mar 14 20:23:29 2021 UTC ()
make: fix documentation of VarFreeEnv

No functional change.


(rillig)
diff -r1.882 -r1.883 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2021/03/14 20:18:33 1.882
+++ src/usr.bin/make/var.c 2021/03/14 20:23:29 1.883
@@ -1,1469 +1,1463 @@ @@ -1,1469 +1,1463 @@
1/* $NetBSD: var.c,v 1.882 2021/03/14 20:18:33 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.883 2021/03/14 20:23:29 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 83 * Var_Set
84 * Var_SetExpand 84 * Var_SetExpand
85 * Set the value of the variable, creating it if 85 * Set the value of the variable, creating it if
86 * necessary. 86 * necessary.
87 * 87 *
88 * Var_Append 88 * Var_Append
89 * Var_AppendExpand 89 * Var_AppendExpand
90 * Append more characters to the variable, creating it if 90 * Append more characters to the variable, creating it if
91 * necessary. A space is placed between the old value and 91 * necessary. A space is placed between the old value and
92 * the new one. 92 * the new one.
93 * 93 *
94 * Var_Exists 94 * Var_Exists
95 * Var_ExistsExpand 95 * Var_ExistsExpand
96 * See if a variable exists. 96 * See if a variable exists.
97 * 97 *
98 * Var_Value Return the unexpanded value of a variable, or NULL if 98 * Var_Value Return the unexpanded value of a variable, or NULL if
99 * the variable is undefined. 99 * the variable is undefined.
100 * 100 *
101 * Var_Subst Substitute all variable expressions in a string. 101 * Var_Subst Substitute all variable expressions in a string.
102 * 102 *
103 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}. 103 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
104 * 104 *
105 * Var_Delete 105 * Var_Delete
106 * Var_DeleteExpand 106 * Var_DeleteExpand
107 * Delete a variable. 107 * Delete a variable.
108 * 108 *
109 * Var_ReexportVars 109 * Var_ReexportVars
110 * Export some or even all variables to the environment 110 * Export some or even all variables to the environment
111 * of this process and its child processes. 111 * of this process and its child processes.
112 * 112 *
113 * Var_Export Export the variable to the environment of this process 113 * Var_Export Export the variable to the environment of this process
114 * and its child processes. 114 * and its child processes.
115 * 115 *
116 * Var_UnExport Don't export the variable anymore. 116 * Var_UnExport Don't export the variable anymore.
117 * 117 *
118 * Debugging: 118 * Debugging:
119 * Var_Stats Print out hashing statistics if in -dh mode. 119 * Var_Stats Print out hashing statistics if in -dh mode.
120 * 120 *
121 * Var_Dump Print out all variables defined in the given scope. 121 * Var_Dump Print out all variables defined in the given scope.
122 * 122 *
123 * XXX: There's a lot of almost duplicate code in these functions that only 123 * XXX: There's a lot of almost duplicate code in these functions that only
124 * differs in subtle details that are not mentioned in the manual page. 124 * differs in subtle details that are not mentioned in the manual page.
125 */ 125 */
126 126
127#include <sys/stat.h> 127#include <sys/stat.h>
128#ifndef NO_REGEX 128#ifndef NO_REGEX
129#include <sys/types.h> 129#include <sys/types.h>
130#include <regex.h> 130#include <regex.h>
131#endif 131#endif
132#include <errno.h> 132#include <errno.h>
133#include <inttypes.h> 133#include <inttypes.h>
134#include <limits.h> 134#include <limits.h>
135#include <time.h> 135#include <time.h>
136 136
137#include "make.h" 137#include "make.h"
138#include "dir.h" 138#include "dir.h"
139#include "job.h" 139#include "job.h"
140#include "metachar.h" 140#include "metachar.h"
141 141
142/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 142/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
143MAKE_RCSID("$NetBSD: var.c,v 1.882 2021/03/14 20:18:33 rillig Exp $"); 143MAKE_RCSID("$NetBSD: var.c,v 1.883 2021/03/14 20:23:29 rillig Exp $");
144 144
145typedef enum VarFlags { 145typedef enum VarFlags {
146 VFL_NONE = 0, 146 VFL_NONE = 0,
147 147
148 /* 148 /*
149 * The variable's value is currently being used by Var_Parse or 149 * The variable's value is currently being used by Var_Parse or
150 * Var_Subst. This marker is used to avoid endless recursion. 150 * Var_Subst. This marker is used to avoid endless recursion.
151 */ 151 */
152 VFL_IN_USE = 1 << 0, 152 VFL_IN_USE = 1 << 0,
153 153
154 /* 154 /*
155 * The variable comes from the environment. 155 * The variable comes from the environment.
156 * These variables are not registered in any GNode, therefore they 156 * These variables are not registered in any GNode, therefore they
157 * must be freed as soon as they are not used anymore. 157 * must be freed as soon as they are not used anymore.
158 */ 158 */
159 VFL_FROM_ENV = 1 << 1, 159 VFL_FROM_ENV = 1 << 1,
160 160
161 /* 161 /*
162 * The variable is exported to the environment, to be used by child 162 * The variable is exported to the environment, to be used by child
163 * processes. 163 * processes.
164 */ 164 */
165 VFL_EXPORTED = 1 << 2, 165 VFL_EXPORTED = 1 << 2,
166 166
167 /* 167 /*
168 * At the point where this variable was exported, it contained an 168 * At the point where this variable was exported, it contained an
169 * unresolved reference to another variable. Before any child 169 * unresolved reference to another variable. Before any child
170 * process is started, it needs to be exported again, in the hope 170 * process is started, it needs to be exported again, in the hope
171 * that the referenced variable can then be resolved. 171 * that the referenced variable can then be resolved.
172 */ 172 */
173 VFL_REEXPORT = 1 << 3, 173 VFL_REEXPORT = 1 << 3,
174 174
175 /* The variable came from the command line. */ 175 /* The variable came from the command line. */
176 VFL_FROM_CMD = 1 << 4, 176 VFL_FROM_CMD = 1 << 4,
177 177
178 /* 178 /*
179 * The variable value cannot be changed anymore, and the variable 179 * The variable value cannot be changed anymore, and the variable
180 * cannot be deleted. Any attempts to do so are silently ignored, 180 * cannot be deleted. Any attempts to do so are silently ignored,
181 * they are logged with -dv though. 181 * they are logged with -dv though.
182 * 182 *
183 * See VAR_SET_READONLY. 183 * See VAR_SET_READONLY.
184 */ 184 */
185 VFL_READONLY = 1 << 5 185 VFL_READONLY = 1 << 5
186} VarFlags; 186} VarFlags;
187 187
188/* 188/*
189 * Variables are defined using one of the VAR=value assignments. Their 189 * Variables are defined using one of the VAR=value assignments. Their
190 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 190 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
191 * such as ${VAR:S,from,to,g:Q}. 191 * such as ${VAR:S,from,to,g:Q}.
192 * 192 *
193 * There are 3 kinds of variables: scope variables, environment variables, 193 * There are 3 kinds of variables: scope variables, environment variables,
194 * undefined variables. 194 * undefined variables.
195 * 195 *
196 * Scope variables are stored in a GNode.scope. The only way to undefine 196 * Scope variables are stored in a GNode.scope. The only way to undefine
197 * a scope variable is using the .undef directive. In particular, it must 197 * a scope variable is using the .undef directive. In particular, it must
198 * not be possible to undefine a variable during the evaluation of an 198 * not be possible to undefine a variable during the evaluation of an
199 * expression, or Var.name might point nowhere. 199 * expression, or Var.name might point nowhere.
200 * 200 *
201 * Environment variables are temporary. They are returned by VarFind, and 201 * Environment variables are temporary. They are returned by VarFind, and
202 * after using them, they must be freed using VarFreeEnv. 202 * after using them, they must be freed using VarFreeEnv.
203 * 203 *
204 * Undefined variables occur during evaluation of variable expressions such 204 * Undefined variables occur during evaluation of variable expressions such
205 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 205 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
206 */ 206 */
207typedef struct Var { 207typedef struct Var {
208 /* 208 /*
209 * The name of the variable, once set, doesn't change anymore. 209 * The name of the variable, once set, doesn't change anymore.
210 * For scope variables, it aliases the corresponding HashEntry name. 210 * For scope variables, it aliases the corresponding HashEntry name.
211 * For environment and undefined variables, it is allocated. 211 * For environment and undefined variables, it is allocated.
212 */ 212 */
213 FStr name; 213 FStr name;
214 214
215 /* The unexpanded value of the variable. */ 215 /* The unexpanded value of the variable. */
216 Buffer val; 216 Buffer val;
217 /* Miscellaneous status flags. */ 217 /* Miscellaneous status flags. */
218 VarFlags flags; 218 VarFlags flags;
219} Var; 219} Var;
220 220
221/* 221/*
222 * Exporting variables is expensive and may leak memory, so skip it if we 222 * Exporting variables is expensive and may leak memory, so skip it if we
223 * can. 223 * can.
224 * 224 *
225 * To avoid this, it might be worth encapsulating the environment variables 225 * To avoid this, it might be worth encapsulating the environment variables
226 * in a separate data structure called EnvVars. 226 * in a separate data structure called EnvVars.
227 */ 227 */
228typedef enum VarExportedMode { 228typedef enum VarExportedMode {
229 VAR_EXPORTED_NONE, 229 VAR_EXPORTED_NONE,
230 VAR_EXPORTED_SOME, 230 VAR_EXPORTED_SOME,
231 VAR_EXPORTED_ALL 231 VAR_EXPORTED_ALL
232} VarExportedMode; 232} VarExportedMode;
233 233
234typedef enum UnexportWhat { 234typedef enum UnexportWhat {
235 /* Unexport the variables given by name. */ 235 /* Unexport the variables given by name. */
236 UNEXPORT_NAMED, 236 UNEXPORT_NAMED,
237 /* 237 /*
238 * Unexport all globals previously exported, but keep the environment 238 * Unexport all globals previously exported, but keep the environment
239 * inherited from the parent. 239 * inherited from the parent.
240 */ 240 */
241 UNEXPORT_ALL, 241 UNEXPORT_ALL,
242 /* 242 /*
243 * Unexport all globals previously exported and clear the environment 243 * Unexport all globals previously exported and clear the environment
244 * inherited from the parent. 244 * inherited from the parent.
245 */ 245 */
246 UNEXPORT_ENV 246 UNEXPORT_ENV
247} UnexportWhat; 247} UnexportWhat;
248 248
249/* Flags for pattern matching in the :S and :C modifiers */ 249/* Flags for pattern matching in the :S and :C modifiers */
250typedef struct VarPatternFlags { 250typedef struct VarPatternFlags {
251 251
252 /* Replace as often as possible ('g') */ 252 /* Replace as often as possible ('g') */
253 Boolean subGlobal: 1; 253 Boolean subGlobal: 1;
254 /* Replace only once ('1') */ 254 /* Replace only once ('1') */
255 Boolean subOnce: 1; 255 Boolean subOnce: 1;
256 /* Match at start of word ('^') */ 256 /* Match at start of word ('^') */
257 Boolean anchorStart: 1; 257 Boolean anchorStart: 1;
258 /* Match at end of word ('$') */ 258 /* Match at end of word ('$') */
259 Boolean anchorEnd: 1; 259 Boolean anchorEnd: 1;
260} VarPatternFlags; 260} VarPatternFlags;
261 261
262/* SepBuf builds a string from words interleaved with separators. */ 262/* SepBuf builds a string from words interleaved with separators. */
263typedef struct SepBuf { 263typedef struct SepBuf {
264 Buffer buf; 264 Buffer buf;
265 Boolean needSep; 265 Boolean needSep;
266 /* Usually ' ', but see the ':ts' modifier. */ 266 /* Usually ' ', but see the ':ts' modifier. */
267 char sep; 267 char sep;
268} SepBuf; 268} SepBuf;
269 269
270 270
271ENUM_FLAGS_RTTI_4(VarEvalFlags, 271ENUM_FLAGS_RTTI_4(VarEvalFlags,
272 VARE_UNDEFERR, VARE_WANTRES, VARE_KEEP_DOLLAR, 272 VARE_UNDEFERR, VARE_WANTRES, VARE_KEEP_DOLLAR,
273 VARE_KEEP_UNDEF); 273 VARE_KEEP_UNDEF);
274 274
275/* 275/*
276 * This lets us tell if we have replaced the original environ 276 * This lets us tell if we have replaced the original environ
277 * (which we cannot free). 277 * (which we cannot free).
278 */ 278 */
279char **savedEnv = NULL; 279char **savedEnv = NULL;
280 280
281/* 281/*
282 * Special return value for Var_Parse, indicating a parse error. It may be 282 * Special return value for Var_Parse, indicating a parse error. It may be
283 * caused by an undefined variable, a syntax error in a modifier or 283 * caused by an undefined variable, a syntax error in a modifier or
284 * something entirely different. 284 * something entirely different.
285 */ 285 */
286char var_Error[] = ""; 286char var_Error[] = "";
287 287
288/* 288/*
289 * Special return value for Var_Parse, indicating an undefined variable in 289 * Special return value for Var_Parse, indicating an undefined variable in
290 * a case where VARE_UNDEFERR is not set. This undefined variable is 290 * a case where VARE_UNDEFERR is not set. This undefined variable is
291 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 291 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
292 * be deferred until it is defined in an actual target. 292 * be deferred until it is defined in an actual target.
293 * 293 *
294 * See VARE_KEEP_UNDEF. 294 * See VARE_KEEP_UNDEF.
295 */ 295 */
296static char varUndefined[] = ""; 296static char varUndefined[] = "";
297 297
298/* 298/*
299 * Traditionally this make consumed $$ during := like any other expansion. 299 * Traditionally this make consumed $$ during := like any other expansion.
300 * Other make's do not, and this make follows straight since 2016-01-09. 300 * Other make's do not, and this make follows straight since 2016-01-09.
301 * 301 *
302 * This knob allows controlling the behavior. 302 * This knob allows controlling the behavior.
303 * FALSE to consume $$ during := assignment. 303 * FALSE to consume $$ during := assignment.
304 * TRUE to preserve $$ during := assignment. 304 * TRUE to preserve $$ during := assignment.
305 */ 305 */
306#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 306#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
307static Boolean save_dollars = TRUE; 307static Boolean save_dollars = TRUE;
308 308
309/* 309/*
310 * A scope collects variable names and their values. 310 * A scope collects variable names and their values.
311 * 311 *
312 * The main scope is SCOPE_GLOBAL, which contains the variables that are set 312 * The main scope is SCOPE_GLOBAL, which contains the variables that are set
313 * in the makefiles. SCOPE_INTERNAL acts as a fallback for SCOPE_GLOBAL and 313 * in the makefiles. SCOPE_INTERNAL acts as a fallback for SCOPE_GLOBAL and
314 * contains some internal make variables. These internal variables can thus 314 * contains some internal make variables. These internal variables can thus
315 * be overridden, they can also be restored by undefining the overriding 315 * be overridden, they can also be restored by undefining the overriding
316 * variable. 316 * variable.
317 * 317 *
318 * SCOPE_CMDLINE contains variables from the command line arguments. These 318 * SCOPE_CMDLINE contains variables from the command line arguments. These
319 * override variables from SCOPE_GLOBAL. 319 * override variables from SCOPE_GLOBAL.
320 * 320 *
321 * There is no scope for environment variables, these are generated on-the-fly 321 * There is no scope for environment variables, these are generated on-the-fly
322 * whenever they are referenced. If there were such a scope, each change to 322 * whenever they are referenced. If there were such a scope, each change to
323 * environment variables would have to be reflected in that scope, which may 323 * environment variables would have to be reflected in that scope, which may
324 * be simpler or more complex than the current implementation. 324 * be simpler or more complex than the current implementation.
325 * 325 *
326 * Each target has its own scope, containing the 7 target-local variables 326 * Each target has its own scope, containing the 7 target-local variables
327 * .TARGET, .ALLSRC, etc. No other variables are in these scopes. 327 * .TARGET, .ALLSRC, etc. No other variables are in these scopes.
328 */ 328 */
329 329
330GNode *SCOPE_CMDLINE; 330GNode *SCOPE_CMDLINE;
331GNode *SCOPE_GLOBAL; 331GNode *SCOPE_GLOBAL;
332GNode *SCOPE_INTERNAL; 332GNode *SCOPE_INTERNAL;
333 333
334ENUM_FLAGS_RTTI_6(VarFlags, 334ENUM_FLAGS_RTTI_6(VarFlags,
335 VFL_IN_USE, VFL_FROM_ENV, 335 VFL_IN_USE, VFL_FROM_ENV,
336 VFL_EXPORTED, VFL_REEXPORT, VFL_FROM_CMD, VFL_READONLY); 336 VFL_EXPORTED, VFL_REEXPORT, VFL_FROM_CMD, VFL_READONLY);
337 337
338static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 338static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
339 339
340 340
341static Var * 341static Var *
342VarNew(FStr name, const char *value, VarFlags flags) 342VarNew(FStr name, const char *value, VarFlags flags)
343{ 343{
344 size_t value_len = strlen(value); 344 size_t value_len = strlen(value);
345 Var *var = bmake_malloc(sizeof *var); 345 Var *var = bmake_malloc(sizeof *var);
346 var->name = name; 346 var->name = name;
347 Buf_InitSize(&var->val, value_len + 1); 347 Buf_InitSize(&var->val, value_len + 1);
348 Buf_AddBytes(&var->val, value, value_len); 348 Buf_AddBytes(&var->val, value, value_len);
349 var->flags = flags; 349 var->flags = flags;
350 return var; 350 return var;
351} 351}
352 352
353static const char * 353static const char *
354CanonicalVarname(const char *name) 354CanonicalVarname(const char *name)
355{ 355{
356 if (*name == '.' && ch_isupper(name[1])) { 356 if (*name == '.' && ch_isupper(name[1])) {
357 switch (name[1]) { 357 switch (name[1]) {
358 case 'A': 358 case 'A':
359 if (strcmp(name, ".ALLSRC") == 0) 359 if (strcmp(name, ".ALLSRC") == 0)
360 name = ALLSRC; 360 name = ALLSRC;
361 if (strcmp(name, ".ARCHIVE") == 0) 361 if (strcmp(name, ".ARCHIVE") == 0)
362 name = ARCHIVE; 362 name = ARCHIVE;
363 break; 363 break;
364 case 'I': 364 case 'I':
365 if (strcmp(name, ".IMPSRC") == 0) 365 if (strcmp(name, ".IMPSRC") == 0)
366 name = IMPSRC; 366 name = IMPSRC;
367 break; 367 break;
368 case 'M': 368 case 'M':
369 if (strcmp(name, ".MEMBER") == 0) 369 if (strcmp(name, ".MEMBER") == 0)
370 name = MEMBER; 370 name = MEMBER;
371 break; 371 break;
372 case 'O': 372 case 'O':
373 if (strcmp(name, ".OODATE") == 0) 373 if (strcmp(name, ".OODATE") == 0)
374 name = OODATE; 374 name = OODATE;
375 break; 375 break;
376 case 'P': 376 case 'P':
377 if (strcmp(name, ".PREFIX") == 0) 377 if (strcmp(name, ".PREFIX") == 0)
378 name = PREFIX; 378 name = PREFIX;
379 break; 379 break;
380 case 'S': 380 case 'S':
381 if (strcmp(name, ".SHELL") == 0) { 381 if (strcmp(name, ".SHELL") == 0) {
382 if (shellPath == NULL) 382 if (shellPath == NULL)
383 Shell_Init(); 383 Shell_Init();
384 } 384 }
385 break; 385 break;
386 case 'T': 386 case 'T':
387 if (strcmp(name, ".TARGET") == 0) 387 if (strcmp(name, ".TARGET") == 0)
388 name = TARGET; 388 name = TARGET;
389 break; 389 break;
390 } 390 }
391 } 391 }
392 392
393 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 393 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
394 394
395 return name; 395 return name;
396} 396}
397 397
398static Var * 398static Var *
399GNode_FindVar(GNode *scope, const char *varname, unsigned int hash) 399GNode_FindVar(GNode *scope, const char *varname, unsigned int hash)
400{ 400{
401 return HashTable_FindValueHash(&scope->vars, varname, hash); 401 return HashTable_FindValueHash(&scope->vars, varname, hash);
402} 402}
403 403
404/* 404/*
405 * Find the variable in the scope, and maybe in other scopes as well. 405 * Find the variable in the scope, and maybe in other scopes as well.
406 * 406 *
407 * Input: 407 * Input:
408 * name name to find, is not expanded any further 408 * name name to find, is not expanded any further
409 * scope scope in which to look first 409 * scope scope in which to look first
410 * elsewhere TRUE to look in other scopes as well 410 * elsewhere TRUE to look in other scopes as well
411 * 411 *
412 * Results: 412 * Results:
413 * The found variable, or NULL if the variable does not exist. 413 * The found variable, or NULL if the variable does not exist.
414 * If the variable is an environment variable, it must be freed using 414 * If the variable is an environment variable, it must be freed using
415 * VarFreeEnv after use. 415 * VarFreeEnv after use.
416 */ 416 */
417static Var * 417static Var *
418VarFind(const char *name, GNode *scope, Boolean elsewhere) 418VarFind(const char *name, GNode *scope, Boolean elsewhere)
419{ 419{
420 Var *var; 420 Var *var;
421 unsigned int nameHash; 421 unsigned int nameHash;
422 422
423 /* Replace '.TARGET' with '@', likewise for other local variables. */ 423 /* Replace '.TARGET' with '@', likewise for other local variables. */
424 name = CanonicalVarname(name); 424 name = CanonicalVarname(name);
425 nameHash = Hash_Hash(name); 425 nameHash = Hash_Hash(name);
426 426
427 var = GNode_FindVar(scope, name, nameHash); 427 var = GNode_FindVar(scope, name, nameHash);
428 if (!elsewhere) 428 if (!elsewhere)
429 return var; 429 return var;
430 430
431 if (var == NULL && scope != SCOPE_CMDLINE) 431 if (var == NULL && scope != SCOPE_CMDLINE)
432 var = GNode_FindVar(SCOPE_CMDLINE, name, nameHash); 432 var = GNode_FindVar(SCOPE_CMDLINE, name, nameHash);
433 433
434 if (!opts.checkEnvFirst && var == NULL && scope != SCOPE_GLOBAL) { 434 if (!opts.checkEnvFirst && var == NULL && scope != SCOPE_GLOBAL) {
435 var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); 435 var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash);
436 if (var == NULL && scope != SCOPE_INTERNAL) { 436 if (var == NULL && scope != SCOPE_INTERNAL) {
437 /* SCOPE_INTERNAL is subordinate to SCOPE_GLOBAL */ 437 /* SCOPE_INTERNAL is subordinate to SCOPE_GLOBAL */
438 var = GNode_FindVar(SCOPE_INTERNAL, name, nameHash); 438 var = GNode_FindVar(SCOPE_INTERNAL, name, nameHash);
439 } 439 }
440 } 440 }
441 441
442 if (var == NULL) { 442 if (var == NULL) {
443 char *env; 443 char *env;
444 444
445 if ((env = getenv(name)) != NULL) { 445 if ((env = getenv(name)) != NULL) {
446 char *varname = bmake_strdup(name); 446 char *varname = bmake_strdup(name);
447 return VarNew(FStr_InitOwn(varname), env, VFL_FROM_ENV); 447 return VarNew(FStr_InitOwn(varname), env, VFL_FROM_ENV);
448 } 448 }
449 449
450 if (opts.checkEnvFirst && scope != SCOPE_GLOBAL) { 450 if (opts.checkEnvFirst && scope != SCOPE_GLOBAL) {
451 var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); 451 var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash);
452 if (var == NULL && scope != SCOPE_INTERNAL) 452 if (var == NULL && scope != SCOPE_INTERNAL)
453 var = GNode_FindVar(SCOPE_INTERNAL, name, 453 var = GNode_FindVar(SCOPE_INTERNAL, name,
454 nameHash); 454 nameHash);
455 return var; 455 return var;
456 } 456 }
457 457
458 return NULL; 458 return NULL;
459 } 459 }
460 460
461 return var; 461 return var;
462} 462}
463 463
464/* 464/* If the variable is an environment variable, free it, including its value. */
465 * If the variable is an environment variable, free it, including its value. 
466 * 
467 * Results: 
468 * TRUE if it was an environment variable, 
469 * FALSE if it is still a regular variable. 
470 */ 
471static void 465static void
472VarFreeEnv(Var *v) 466VarFreeEnv(Var *v)
473{ 467{
474 if (!(v->flags & VFL_FROM_ENV)) 468 if (!(v->flags & VFL_FROM_ENV))
475 return; 469 return;
476 470
477 FStr_Done(&v->name); 471 FStr_Done(&v->name);
478 Buf_Done(&v->val); 472 Buf_Done(&v->val);
479 free(v); 473 free(v);
480} 474}
481 475
482/* Add a new variable of the given name and value to the given scope. */ 476/* Add a new variable of the given name and value to the given scope. */
483static Var * 477static Var *
484VarAdd(const char *name, const char *value, GNode *scope, VarSetFlags flags) 478VarAdd(const char *name, const char *value, GNode *scope, VarSetFlags flags)
485{ 479{
486 HashEntry *he = HashTable_CreateEntry(&scope->vars, name, NULL); 480 HashEntry *he = HashTable_CreateEntry(&scope->vars, name, NULL);
487 Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), value, 481 Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), value,
488 flags & VAR_SET_READONLY ? VFL_READONLY : VFL_NONE); 482 flags & VAR_SET_READONLY ? VFL_READONLY : VFL_NONE);
489 HashEntry_Set(he, v); 483 HashEntry_Set(he, v);
490 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, value); 484 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, value);
491 return v; 485 return v;
492} 486}
493 487
494/* 488/*
495 * Remove a variable from a scope, freeing all related memory as well. 489 * Remove a variable from a scope, freeing all related memory as well.
496 * The variable name is kept as-is, it is not expanded. 490 * The variable name is kept as-is, it is not expanded.
497 */ 491 */
498void 492void
499Var_Delete(GNode *scope, const char *varname) 493Var_Delete(GNode *scope, const char *varname)
500{ 494{
501 HashEntry *he = HashTable_FindEntry(&scope->vars, varname); 495 HashEntry *he = HashTable_FindEntry(&scope->vars, varname);
502 Var *v; 496 Var *v;
503 497
504 if (he == NULL) { 498 if (he == NULL) {
505 DEBUG2(VAR, "%s:delete %s (not found)\n", scope->name, varname); 499 DEBUG2(VAR, "%s:delete %s (not found)\n", scope->name, varname);
506 return; 500 return;
507 } 501 }
508 502
509 DEBUG2(VAR, "%s:delete %s\n", scope->name, varname); 503 DEBUG2(VAR, "%s:delete %s\n", scope->name, varname);
510 v = he->value; 504 v = he->value;
511 if (v->flags & VFL_EXPORTED) 505 if (v->flags & VFL_EXPORTED)
512 unsetenv(v->name.str); 506 unsetenv(v->name.str);
513 if (strcmp(v->name.str, MAKE_EXPORTED) == 0) 507 if (strcmp(v->name.str, MAKE_EXPORTED) == 0)
514 var_exportedVars = VAR_EXPORTED_NONE; 508 var_exportedVars = VAR_EXPORTED_NONE;
515 assert(v->name.freeIt == NULL); 509 assert(v->name.freeIt == NULL);
516 HashTable_DeleteEntry(&scope->vars, he); 510 HashTable_DeleteEntry(&scope->vars, he);
517 Buf_Done(&v->val); 511 Buf_Done(&v->val);
518 free(v); 512 free(v);
519} 513}
520 514
521/* 515/*
522 * Remove a variable from a scope, freeing all related memory as well. 516 * Remove a variable from a scope, freeing all related memory as well.
523 * The variable name is expanded once. 517 * The variable name is expanded once.
524 */ 518 */
525void 519void
526Var_DeleteExpand(GNode *scope, const char *name) 520Var_DeleteExpand(GNode *scope, const char *name)
527{ 521{
528 FStr varname = FStr_InitRefer(name); 522 FStr varname = FStr_InitRefer(name);
529 523
530 if (strchr(varname.str, '$') != NULL) { 524 if (strchr(varname.str, '$') != NULL) {
531 char *expanded; 525 char *expanded;
532 (void)Var_Subst(varname.str, SCOPE_GLOBAL, VARE_WANTRES, 526 (void)Var_Subst(varname.str, SCOPE_GLOBAL, VARE_WANTRES,
533 &expanded); 527 &expanded);
534 /* TODO: handle errors */ 528 /* TODO: handle errors */
535 varname = FStr_InitOwn(expanded); 529 varname = FStr_InitOwn(expanded);
536 } 530 }
537 531
538 Var_Delete(scope, varname.str); 532 Var_Delete(scope, varname.str);
539 FStr_Done(&varname); 533 FStr_Done(&varname);
540} 534}
541 535
542/* 536/*
543 * Undefine one or more variables from the global scope. 537 * Undefine one or more variables from the global scope.
544 * The argument is expanded exactly once and then split into words. 538 * The argument is expanded exactly once and then split into words.
545 */ 539 */
546void 540void
547Var_Undef(const char *arg) 541Var_Undef(const char *arg)
548{ 542{
549 VarParseResult vpr; 543 VarParseResult vpr;
550 char *expanded; 544 char *expanded;
551 Words varnames; 545 Words varnames;
552 size_t i; 546 size_t i;
553 547
554 if (arg[0] == '\0') { 548 if (arg[0] == '\0') {
555 Parse_Error(PARSE_FATAL, 549 Parse_Error(PARSE_FATAL,
556 "The .undef directive requires an argument"); 550 "The .undef directive requires an argument");
557 return; 551 return;
558 } 552 }
559 553
560 vpr = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES, &expanded); 554 vpr = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES, &expanded);
561 if (vpr != VPR_OK) { 555 if (vpr != VPR_OK) {
562 Parse_Error(PARSE_FATAL, 556 Parse_Error(PARSE_FATAL,
563 "Error in variable names to be undefined"); 557 "Error in variable names to be undefined");
564 return; 558 return;
565 } 559 }
566 560
567 varnames = Str_Words(expanded, FALSE); 561 varnames = Str_Words(expanded, FALSE);
568 if (varnames.len == 1 && varnames.words[0][0] == '\0') 562 if (varnames.len == 1 && varnames.words[0][0] == '\0')
569 varnames.len = 0; 563 varnames.len = 0;
570 564
571 for (i = 0; i < varnames.len; i++) { 565 for (i = 0; i < varnames.len; i++) {
572 const char *varname = varnames.words[i]; 566 const char *varname = varnames.words[i];
573 Global_Delete(varname); 567 Global_Delete(varname);
574 } 568 }
575 569
576 Words_Free(varnames); 570 Words_Free(varnames);
577 free(expanded); 571 free(expanded);
578} 572}
579 573
580static Boolean 574static Boolean
581MayExport(const char *name) 575MayExport(const char *name)
582{ 576{
583 if (name[0] == '.') 577 if (name[0] == '.')
584 return FALSE; /* skip internals */ 578 return FALSE; /* skip internals */
585 if (name[0] == '-') 579 if (name[0] == '-')
586 return FALSE; /* skip misnamed variables */ 580 return FALSE; /* skip misnamed variables */
587 if (name[1] == '\0') { 581 if (name[1] == '\0') {
588 /* 582 /*
589 * A single char. 583 * A single char.
590 * If it is one of the variables that should only appear in 584 * If it is one of the variables that should only appear in
591 * local scope, skip it, else we can get Var_Subst 585 * local scope, skip it, else we can get Var_Subst
592 * into a loop. 586 * into a loop.
593 */ 587 */
594 switch (name[0]) { 588 switch (name[0]) {
595 case '@': 589 case '@':
596 case '%': 590 case '%':
597 case '*': 591 case '*':
598 case '!': 592 case '!':
599 return FALSE; 593 return FALSE;
600 } 594 }
601 } 595 }
602 return TRUE; 596 return TRUE;
603} 597}
604 598
605static Boolean 599static Boolean
606ExportVarEnv(Var *v) 600ExportVarEnv(Var *v)
607{ 601{
608 const char *name = v->name.str; 602 const char *name = v->name.str;
609 char *val = v->val.data; 603 char *val = v->val.data;
610 char *expr; 604 char *expr;
611 605
612 if ((v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT)) 606 if ((v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT))
613 return FALSE; /* nothing to do */ 607 return FALSE; /* nothing to do */
614 608
615 if (strchr(val, '$') == NULL) { 609 if (strchr(val, '$') == NULL) {
616 if (!(v->flags & VFL_EXPORTED)) 610 if (!(v->flags & VFL_EXPORTED))
617 setenv(name, val, 1); 611 setenv(name, val, 1);
618 return TRUE; 612 return TRUE;
619 } 613 }
620 614
621 if (v->flags & VFL_IN_USE) { 615 if (v->flags & VFL_IN_USE) {
622 /* 616 /*
623 * We recursed while exporting in a child. 617 * We recursed while exporting in a child.
624 * This isn't going to end well, just skip it. 618 * This isn't going to end well, just skip it.
625 */ 619 */
626 return FALSE; 620 return FALSE;
627 } 621 }
628 622
629 /* XXX: name is injected without escaping it */ 623 /* XXX: name is injected without escaping it */
630 expr = str_concat3("${", name, "}"); 624 expr = str_concat3("${", name, "}");
631 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &val); 625 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &val);
632 /* TODO: handle errors */ 626 /* TODO: handle errors */
633 setenv(name, val, 1); 627 setenv(name, val, 1);
634 free(val); 628 free(val);
635 free(expr); 629 free(expr);
636 return TRUE; 630 return TRUE;
637} 631}
638 632
639static Boolean 633static Boolean
640ExportVarPlain(Var *v) 634ExportVarPlain(Var *v)
641{ 635{
642 if (strchr(v->val.data, '$') == NULL) { 636 if (strchr(v->val.data, '$') == NULL) {
643 setenv(v->name.str, v->val.data, 1); 637 setenv(v->name.str, v->val.data, 1);
644 v->flags |= VFL_EXPORTED; 638 v->flags |= VFL_EXPORTED;
645 v->flags &= ~(unsigned)VFL_REEXPORT; 639 v->flags &= ~(unsigned)VFL_REEXPORT;
646 return TRUE; 640 return TRUE;
647 } 641 }
648 642
649 /* 643 /*
650 * Flag the variable as something we need to re-export. 644 * Flag the variable as something we need to re-export.
651 * No point actually exporting it now though, 645 * No point actually exporting it now though,
652 * the child process can do it at the last minute. 646 * the child process can do it at the last minute.
653 * Avoid calling setenv more often than necessary since it can leak. 647 * Avoid calling setenv more often than necessary since it can leak.
654 */ 648 */
655 v->flags |= VFL_EXPORTED | VFL_REEXPORT; 649 v->flags |= VFL_EXPORTED | VFL_REEXPORT;
656 return TRUE; 650 return TRUE;
657} 651}
658 652
659static Boolean 653static Boolean
660ExportVarLiteral(Var *v) 654ExportVarLiteral(Var *v)
661{ 655{
662 if ((v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT)) 656 if ((v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT))
663 return FALSE; 657 return FALSE;
664 658
665 if (!(v->flags & VFL_EXPORTED)) 659 if (!(v->flags & VFL_EXPORTED))
666 setenv(v->name.str, v->val.data, 1); 660 setenv(v->name.str, v->val.data, 1);
667 661
668 return TRUE; 662 return TRUE;
669} 663}
670 664
671/* 665/*
672 * Mark a single variable to be exported later for subprocesses. 666 * Mark a single variable to be exported later for subprocesses.
673 * 667 *
674 * Internal variables (those starting with '.') are not exported. 668 * Internal variables (those starting with '.') are not exported.
675 */ 669 */
676static Boolean 670static Boolean
677ExportVar(const char *name, VarExportMode mode) 671ExportVar(const char *name, VarExportMode mode)
678{ 672{
679 Var *v; 673 Var *v;
680 674
681 if (!MayExport(name)) 675 if (!MayExport(name))
682 return FALSE; 676 return FALSE;
683 677
684 v = VarFind(name, SCOPE_GLOBAL, FALSE); 678 v = VarFind(name, SCOPE_GLOBAL, FALSE);
685 if (v == NULL) 679 if (v == NULL)
686 return FALSE; 680 return FALSE;
687 681
688 if (mode == VEM_ENV) 682 if (mode == VEM_ENV)
689 return ExportVarEnv(v); 683 return ExportVarEnv(v);
690 else if (mode == VEM_PLAIN) 684 else if (mode == VEM_PLAIN)
691 return ExportVarPlain(v); 685 return ExportVarPlain(v);
692 else 686 else
693 return ExportVarLiteral(v); 687 return ExportVarLiteral(v);
694} 688}
695 689
696/* 690/*
697 * Actually export the variables that have been marked as needing to be 691 * Actually export the variables that have been marked as needing to be
698 * re-exported. 692 * re-exported.
699 */ 693 */
700void 694void
701Var_ReexportVars(void) 695Var_ReexportVars(void)
702{ 696{
703 char *xvarnames; 697 char *xvarnames;
704 698
705 /* 699 /*
706 * Several make implementations support this sort of mechanism for 700 * Several make implementations support this sort of mechanism for
707 * tracking recursion - but each uses a different name. 701 * tracking recursion - but each uses a different name.
708 * We allow the makefiles to update MAKELEVEL and ensure 702 * We allow the makefiles to update MAKELEVEL and ensure
709 * children see a correctly incremented value. 703 * children see a correctly incremented value.
710 */ 704 */
711 char tmp[21]; 705 char tmp[21];
712 snprintf(tmp, sizeof tmp, "%d", makelevel + 1); 706 snprintf(tmp, sizeof tmp, "%d", makelevel + 1);
713 setenv(MAKE_LEVEL_ENV, tmp, 1); 707 setenv(MAKE_LEVEL_ENV, tmp, 1);
714 708
715 if (var_exportedVars == VAR_EXPORTED_NONE) 709 if (var_exportedVars == VAR_EXPORTED_NONE)
716 return; 710 return;
717 711
718 if (var_exportedVars == VAR_EXPORTED_ALL) { 712 if (var_exportedVars == VAR_EXPORTED_ALL) {
719 HashIter hi; 713 HashIter hi;
720 714
721 /* Ouch! Exporting all variables at once is crazy. */ 715 /* Ouch! Exporting all variables at once is crazy. */
722 HashIter_Init(&hi, &SCOPE_GLOBAL->vars); 716 HashIter_Init(&hi, &SCOPE_GLOBAL->vars);
723 while (HashIter_Next(&hi) != NULL) { 717 while (HashIter_Next(&hi) != NULL) {
724 Var *var = hi.entry->value; 718 Var *var = hi.entry->value;
725 ExportVar(var->name.str, VEM_ENV); 719 ExportVar(var->name.str, VEM_ENV);
726 } 720 }
727 return; 721 return;
728 } 722 }
729 723
730 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, VARE_WANTRES, 724 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, VARE_WANTRES,
731 &xvarnames); 725 &xvarnames);
732 /* TODO: handle errors */ 726 /* TODO: handle errors */
733 if (xvarnames[0] != '\0') { 727 if (xvarnames[0] != '\0') {
734 Words varnames = Str_Words(xvarnames, FALSE); 728 Words varnames = Str_Words(xvarnames, FALSE);
735 size_t i; 729 size_t i;
736 730
737 for (i = 0; i < varnames.len; i++) 731 for (i = 0; i < varnames.len; i++)
738 ExportVar(varnames.words[i], VEM_ENV); 732 ExportVar(varnames.words[i], VEM_ENV);
739 Words_Free(varnames); 733 Words_Free(varnames);
740 } 734 }
741 free(xvarnames); 735 free(xvarnames);
742} 736}
743 737
744static void 738static void
745ExportVars(const char *varnames, Boolean isExport, VarExportMode mode) 739ExportVars(const char *varnames, Boolean isExport, VarExportMode mode)
746/* TODO: try to combine the parameters 'isExport' and 'mode'. */ 740/* TODO: try to combine the parameters 'isExport' and 'mode'. */
747{ 741{
748 Words words = Str_Words(varnames, FALSE); 742 Words words = Str_Words(varnames, FALSE);
749 size_t i; 743 size_t i;
750 744
751 if (words.len == 1 && words.words[0][0] == '\0') 745 if (words.len == 1 && words.words[0][0] == '\0')
752 words.len = 0; 746 words.len = 0;
753 747
754 for (i = 0; i < words.len; i++) { 748 for (i = 0; i < words.len; i++) {
755 const char *varname = words.words[i]; 749 const char *varname = words.words[i];
756 if (!ExportVar(varname, mode)) 750 if (!ExportVar(varname, mode))
757 continue; 751 continue;
758 752
759 if (var_exportedVars == VAR_EXPORTED_NONE) 753 if (var_exportedVars == VAR_EXPORTED_NONE)
760 var_exportedVars = VAR_EXPORTED_SOME; 754 var_exportedVars = VAR_EXPORTED_SOME;
761 755
762 if (isExport && mode == VEM_PLAIN) 756 if (isExport && mode == VEM_PLAIN)
763 Global_Append(MAKE_EXPORTED, varname); 757 Global_Append(MAKE_EXPORTED, varname);
764 } 758 }
765 Words_Free(words); 759 Words_Free(words);
766} 760}
767 761
768static void 762static void
769ExportVarsExpand(const char *uvarnames, Boolean isExport, VarExportMode mode) 763ExportVarsExpand(const char *uvarnames, Boolean isExport, VarExportMode mode)
770{ 764{
771 char *xvarnames; 765 char *xvarnames;
772 766
773 (void)Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES, &xvarnames); 767 (void)Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES, &xvarnames);
774 /* TODO: handle errors */ 768 /* TODO: handle errors */
775 ExportVars(xvarnames, isExport, mode); 769 ExportVars(xvarnames, isExport, mode);
776 free(xvarnames); 770 free(xvarnames);
777} 771}
778 772
779/* Export the named variables, or all variables. */ 773/* Export the named variables, or all variables. */
780void 774void
781Var_Export(VarExportMode mode, const char *varnames) 775Var_Export(VarExportMode mode, const char *varnames)
782{ 776{
783 if (mode == VEM_PLAIN && varnames[0] == '\0') { 777 if (mode == VEM_PLAIN && varnames[0] == '\0') {
784 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 778 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
785 return; 779 return;
786 } 780 }
787 781
788 ExportVarsExpand(varnames, TRUE, mode); 782 ExportVarsExpand(varnames, TRUE, mode);
789} 783}
790 784
791void 785void
792Var_ExportVars(const char *varnames) 786Var_ExportVars(const char *varnames)
793{ 787{
794 ExportVarsExpand(varnames, FALSE, VEM_PLAIN); 788 ExportVarsExpand(varnames, FALSE, VEM_PLAIN);
795} 789}
796 790
797 791
798extern char **environ; 792extern char **environ;
799 793
800static void 794static void
801ClearEnv(void) 795ClearEnv(void)
802{ 796{
803 const char *cp; 797 const char *cp;
804 char **newenv; 798 char **newenv;
805 799
806 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 800 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
807 if (environ == savedEnv) { 801 if (environ == savedEnv) {
808 /* we have been here before! */ 802 /* we have been here before! */
809 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 803 newenv = bmake_realloc(environ, 2 * sizeof(char *));
810 } else { 804 } else {
811 if (savedEnv != NULL) { 805 if (savedEnv != NULL) {
812 free(savedEnv); 806 free(savedEnv);
813 savedEnv = NULL; 807 savedEnv = NULL;
814 } 808 }
815 newenv = bmake_malloc(2 * sizeof(char *)); 809 newenv = bmake_malloc(2 * sizeof(char *));
816 } 810 }
817 811
818 /* Note: we cannot safely free() the original environ. */ 812 /* Note: we cannot safely free() the original environ. */
819 environ = savedEnv = newenv; 813 environ = savedEnv = newenv;
820 newenv[0] = NULL; 814 newenv[0] = NULL;
821 newenv[1] = NULL; 815 newenv[1] = NULL;
822 if (cp != NULL && *cp != '\0') 816 if (cp != NULL && *cp != '\0')
823 setenv(MAKE_LEVEL_ENV, cp, 1); 817 setenv(MAKE_LEVEL_ENV, cp, 1);
824} 818}
825 819
826static void 820static void
827GetVarnamesToUnexport(Boolean isEnv, const char *arg, 821GetVarnamesToUnexport(Boolean isEnv, const char *arg,
828 FStr *out_varnames, UnexportWhat *out_what) 822 FStr *out_varnames, UnexportWhat *out_what)
829{ 823{
830 UnexportWhat what; 824 UnexportWhat what;
831 FStr varnames = FStr_InitRefer(""); 825 FStr varnames = FStr_InitRefer("");
832 826
833 if (isEnv) { 827 if (isEnv) {
834 if (arg[0] != '\0') { 828 if (arg[0] != '\0') {
835 Parse_Error(PARSE_FATAL, 829 Parse_Error(PARSE_FATAL,
836 "The directive .unexport-env does not take " 830 "The directive .unexport-env does not take "
837 "arguments"); 831 "arguments");
838 /* continue anyway */ 832 /* continue anyway */
839 } 833 }
840 what = UNEXPORT_ENV; 834 what = UNEXPORT_ENV;
841 835
842 } else { 836 } else {
843 what = arg[0] != '\0' ? UNEXPORT_NAMED : UNEXPORT_ALL; 837 what = arg[0] != '\0' ? UNEXPORT_NAMED : UNEXPORT_ALL;
844 if (what == UNEXPORT_NAMED) 838 if (what == UNEXPORT_NAMED)
845 varnames = FStr_InitRefer(arg); 839 varnames = FStr_InitRefer(arg);
846 } 840 }
847 841
848 if (what != UNEXPORT_NAMED) { 842 if (what != UNEXPORT_NAMED) {
849 char *expanded; 843 char *expanded;
850 /* Using .MAKE.EXPORTED */ 844 /* Using .MAKE.EXPORTED */
851 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, 845 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL,
852 VARE_WANTRES, &expanded); 846 VARE_WANTRES, &expanded);
853 /* TODO: handle errors */ 847 /* TODO: handle errors */
854 varnames = FStr_InitOwn(expanded); 848 varnames = FStr_InitOwn(expanded);
855 } 849 }
856 850
857 *out_varnames = varnames; 851 *out_varnames = varnames;
858 *out_what = what; 852 *out_what = what;
859} 853}
860 854
861static void 855static void
862UnexportVar(const char *varname, UnexportWhat what) 856UnexportVar(const char *varname, UnexportWhat what)
863{ 857{
864 Var *v = VarFind(varname, SCOPE_GLOBAL, FALSE); 858 Var *v = VarFind(varname, SCOPE_GLOBAL, FALSE);
865 if (v == NULL) { 859 if (v == NULL) {
866 DEBUG1(VAR, "Not unexporting \"%s\" (not found)\n", varname); 860 DEBUG1(VAR, "Not unexporting \"%s\" (not found)\n", varname);
867 return; 861 return;
868 } 862 }
869 863
870 DEBUG1(VAR, "Unexporting \"%s\"\n", varname); 864 DEBUG1(VAR, "Unexporting \"%s\"\n", varname);
871 if (what != UNEXPORT_ENV && 865 if (what != UNEXPORT_ENV &&
872 (v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT)) 866 (v->flags & VFL_EXPORTED) && !(v->flags & VFL_REEXPORT))
873 unsetenv(v->name.str); 867 unsetenv(v->name.str);
874 v->flags &= ~(unsigned)(VFL_EXPORTED | VFL_REEXPORT); 868 v->flags &= ~(unsigned)(VFL_EXPORTED | VFL_REEXPORT);
875 869
876 if (what == UNEXPORT_NAMED) { 870 if (what == UNEXPORT_NAMED) {
877 /* Remove the variable names from .MAKE.EXPORTED. */ 871 /* Remove the variable names from .MAKE.EXPORTED. */
878 /* XXX: v->name is injected without escaping it */ 872 /* XXX: v->name is injected without escaping it */
879 char *expr = str_concat3("${" MAKE_EXPORTED ":N", 873 char *expr = str_concat3("${" MAKE_EXPORTED ":N",
880 v->name.str, "}"); 874 v->name.str, "}");
881 char *cp; 875 char *cp;
882 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &cp); 876 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &cp);
883 /* TODO: handle errors */ 877 /* TODO: handle errors */
884 Global_Set(MAKE_EXPORTED, cp); 878 Global_Set(MAKE_EXPORTED, cp);
885 free(cp); 879 free(cp);
886 free(expr); 880 free(expr);
887 } 881 }
888} 882}
889 883
890static void 884static void
891UnexportVars(FStr *varnames, UnexportWhat what) 885UnexportVars(FStr *varnames, UnexportWhat what)
892{ 886{
893 size_t i; 887 size_t i;
894 Words words; 888 Words words;
895 889
896 if (what == UNEXPORT_ENV) 890 if (what == UNEXPORT_ENV)
897 ClearEnv(); 891 ClearEnv();
898 892
899 words = Str_Words(varnames->str, FALSE); 893 words = Str_Words(varnames->str, FALSE);
900 for (i = 0; i < words.len; i++) { 894 for (i = 0; i < words.len; i++) {
901 const char *varname = words.words[i]; 895 const char *varname = words.words[i];
902 UnexportVar(varname, what); 896 UnexportVar(varname, what);
903 } 897 }
904 Words_Free(words); 898 Words_Free(words);
905 899
906 if (what != UNEXPORT_NAMED) 900 if (what != UNEXPORT_NAMED)
907 Global_Delete(MAKE_EXPORTED); 901 Global_Delete(MAKE_EXPORTED);
908} 902}
909 903
910/* 904/*
911 * This is called when .unexport[-env] is seen. 905 * This is called when .unexport[-env] is seen.
912 * 906 *
913 * str must have the form "unexport[-env] varname...". 907 * str must have the form "unexport[-env] varname...".
914 */ 908 */
915void 909void
916Var_UnExport(Boolean isEnv, const char *arg) 910Var_UnExport(Boolean isEnv, const char *arg)
917{ 911{
918 UnexportWhat what; 912 UnexportWhat what;
919 FStr varnames; 913 FStr varnames;
920 914
921 GetVarnamesToUnexport(isEnv, arg, &varnames, &what); 915 GetVarnamesToUnexport(isEnv, arg, &varnames, &what);
922 UnexportVars(&varnames, what); 916 UnexportVars(&varnames, what);
923 FStr_Done(&varnames); 917 FStr_Done(&varnames);
924} 918}
925 919
926/* 920/*
927 * When there is a variable of the same name in the command line scope, the 921 * When there is a variable of the same name in the command line scope, the
928 * global variable would not be visible anywhere. Therefore there is no 922 * global variable would not be visible anywhere. Therefore there is no
929 * point in setting it at all. 923 * point in setting it at all.
930 * 924 *
931 * See 'scope == SCOPE_CMDLINE' in Var_SetWithFlags. 925 * See 'scope == SCOPE_CMDLINE' in Var_SetWithFlags.
932 */ 926 */
933static Boolean 927static Boolean
934ExistsInCmdline(const char *name, const char *val) 928ExistsInCmdline(const char *name, const char *val)
935{ 929{
936 Var *v; 930 Var *v;
937 931
938 v = VarFind(name, SCOPE_CMDLINE, FALSE); 932 v = VarFind(name, SCOPE_CMDLINE, FALSE);
939 if (v == NULL) 933 if (v == NULL)
940 return FALSE; 934 return FALSE;
941 935
942 if (v->flags & VFL_FROM_CMD) { 936 if (v->flags & VFL_FROM_CMD) {
943 DEBUG3(VAR, "%s:%s = %s ignored!\n", 937 DEBUG3(VAR, "%s:%s = %s ignored!\n",
944 SCOPE_GLOBAL->name, name, val); 938 SCOPE_GLOBAL->name, name, val);
945 return TRUE; 939 return TRUE;
946 } 940 }
947 941
948 VarFreeEnv(v); 942 VarFreeEnv(v);
949 return FALSE; 943 return FALSE;
950} 944}
951 945
952/* Set the variable to the value; the name is not expanded. */ 946/* Set the variable to the value; the name is not expanded. */
953void 947void
954Var_SetWithFlags(GNode *scope, const char *name, const char *val, 948Var_SetWithFlags(GNode *scope, const char *name, const char *val,
955 VarSetFlags flags) 949 VarSetFlags flags)
956{ 950{
957 Var *v; 951 Var *v;
958 952
959 assert(val != NULL); 953 assert(val != NULL);
960 if (name[0] == '\0') { 954 if (name[0] == '\0') {
961 DEBUG0(VAR, "SetVar: variable name is empty - ignored\n"); 955 DEBUG0(VAR, "SetVar: variable name is empty - ignored\n");
962 return; 956 return;
963 } 957 }
964 958
965 if (scope == SCOPE_GLOBAL && ExistsInCmdline(name, val)) 959 if (scope == SCOPE_GLOBAL && ExistsInCmdline(name, val))
966 return; 960 return;
967 961
968 /* 962 /*
969 * Only look for a variable in the given scope since anything set 963 * Only look for a variable in the given scope since anything set
970 * here will override anything in a lower scope, so there's not much 964 * here will override anything in a lower scope, so there's not much
971 * point in searching them all. 965 * point in searching them all.
972 */ 966 */
973 v = VarFind(name, scope, FALSE); 967 v = VarFind(name, scope, FALSE);
974 if (v == NULL) { 968 if (v == NULL) {
975 if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) { 969 if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) {
976 /* 970 /*
977 * This var would normally prevent the same name being 971 * This var would normally prevent the same name being
978 * added to SCOPE_GLOBAL, so delete it from there if 972 * added to SCOPE_GLOBAL, so delete it from there if
979 * needed. Otherwise -V name may show the wrong value. 973 * needed. Otherwise -V name may show the wrong value.
980 * 974 *
981 * See ExistsInCmdline. 975 * See ExistsInCmdline.
982 */ 976 */
983 Var_Delete(SCOPE_GLOBAL, name); 977 Var_Delete(SCOPE_GLOBAL, name);
984 } 978 }
985 v = VarAdd(name, val, scope, flags); 979 v = VarAdd(name, val, scope, flags);
986 } else { 980 } else {
987 if ((v->flags & VFL_READONLY) && !(flags & VAR_SET_READONLY)) { 981 if ((v->flags & VFL_READONLY) && !(flags & VAR_SET_READONLY)) {
988 DEBUG3(VAR, "%s:%s = %s ignored (read-only)\n", 982 DEBUG3(VAR, "%s:%s = %s ignored (read-only)\n",
989 scope->name, name, val); 983 scope->name, name, val);
990 return; 984 return;
991 } 985 }
992 Buf_Empty(&v->val); 986 Buf_Empty(&v->val);
993 Buf_AddStr(&v->val, val); 987 Buf_AddStr(&v->val, val);
994 988
995 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, val); 989 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, val);
996 if (v->flags & VFL_EXPORTED) 990 if (v->flags & VFL_EXPORTED)
997 ExportVar(name, VEM_PLAIN); 991 ExportVar(name, VEM_PLAIN);
998 } 992 }
999 993
1000 /* 994 /*
1001 * Any variables given on the command line are automatically exported 995 * Any variables given on the command line are automatically exported
1002 * to the environment (as per POSIX standard), except for internals. 996 * to the environment (as per POSIX standard), except for internals.
1003 */ 997 */
1004 if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT) && 998 if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT) &&
1005 name[0] != '.') { 999 name[0] != '.') {
1006 v->flags |= VFL_FROM_CMD; 1000 v->flags |= VFL_FROM_CMD;
1007 1001
1008 /* 1002 /*
1009 * If requested, don't export these in the environment 1003 * If requested, don't export these in the environment
1010 * individually. We still put them in MAKEOVERRIDES so 1004 * individually. We still put them in MAKEOVERRIDES so
1011 * that the command-line settings continue to override 1005 * that the command-line settings continue to override
1012 * Makefile settings. 1006 * Makefile settings.
1013 */ 1007 */
1014 if (!opts.varNoExportEnv) 1008 if (!opts.varNoExportEnv)
1015 setenv(name, val, 1); 1009 setenv(name, val, 1);
1016 /* XXX: What about .MAKE.EXPORTED? */ 1010 /* XXX: What about .MAKE.EXPORTED? */
1017 /* XXX: Why not just mark the variable for needing export, 1011 /* XXX: Why not just mark the variable for needing export,
1018 * as in ExportVarPlain? */ 1012 * as in ExportVarPlain? */
1019 1013
1020 Global_Append(MAKEOVERRIDES, name); 1014 Global_Append(MAKEOVERRIDES, name);
1021 } 1015 }
1022 1016
1023 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 1017 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
1024 save_dollars = ParseBoolean(val, save_dollars); 1018 save_dollars = ParseBoolean(val, save_dollars);
1025 1019
1026 if (v != NULL) 1020 if (v != NULL)
1027 VarFreeEnv(v); 1021 VarFreeEnv(v);
1028} 1022}
1029 1023
1030/* See Var_Set for documentation. */ 1024/* See Var_Set for documentation. */
1031void 1025void
1032Var_SetExpandWithFlags(GNode *scope, const char *name, const char *val, 1026Var_SetExpandWithFlags(GNode *scope, const char *name, const char *val,
1033 VarSetFlags flags) 1027 VarSetFlags flags)
1034{ 1028{
1035 const char *unexpanded_name = name; 1029 const char *unexpanded_name = name;
1036 FStr varname = FStr_InitRefer(name); 1030 FStr varname = FStr_InitRefer(name);
1037 1031
1038 assert(val != NULL); 1032 assert(val != NULL);
1039 1033
1040 if (strchr(varname.str, '$') != NULL) { 1034 if (strchr(varname.str, '$') != NULL) {
1041 char *expanded; 1035 char *expanded;
1042 (void)Var_Subst(varname.str, scope, VARE_WANTRES, &expanded); 1036 (void)Var_Subst(varname.str, scope, VARE_WANTRES, &expanded);
1043 /* TODO: handle errors */ 1037 /* TODO: handle errors */
1044 varname = FStr_InitOwn(expanded); 1038 varname = FStr_InitOwn(expanded);
1045 } 1039 }
1046 1040
1047 if (varname.str[0] == '\0') { 1041 if (varname.str[0] == '\0') {
1048 DEBUG2(VAR, "Var_Set(\"%s\", \"%s\", ...) " 1042 DEBUG2(VAR, "Var_Set(\"%s\", \"%s\", ...) "
1049 "name expands to empty string - ignored\n", 1043 "name expands to empty string - ignored\n",
1050 unexpanded_name, val); 1044 unexpanded_name, val);
1051 } else 1045 } else
1052 Var_SetWithFlags(scope, varname.str, val, flags); 1046 Var_SetWithFlags(scope, varname.str, val, flags);
1053 1047
1054 FStr_Done(&varname); 1048 FStr_Done(&varname);
1055} 1049}
1056 1050
1057void 1051void
1058Var_Set(GNode *scope, const char *name, const char *val) 1052Var_Set(GNode *scope, const char *name, const char *val)
1059{ 1053{
1060 Var_SetWithFlags(scope, name, val, VAR_SET_NONE); 1054 Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
1061} 1055}
1062 1056
1063/* 1057/*
1064 * Set the variable name to the value val in the given scope. 1058 * Set the variable name to the value val in the given scope.
1065 * 1059 *
1066 * If the variable doesn't yet exist, it is created. 1060 * If the variable doesn't yet exist, it is created.
1067 * Otherwise the new value overwrites and replaces the old value. 1061 * Otherwise the new value overwrites and replaces the old value.
1068 * 1062 *
1069 * Input: 1063 * Input:
1070 * name name of the variable to set, is expanded once 1064 * name name of the variable to set, is expanded once
1071 * val value to give to the variable 1065 * val value to give to the variable
1072 * scope scope in which to set it 1066 * scope scope in which to set it
1073 */ 1067 */
1074void 1068void
1075Var_SetExpand(GNode *scope, const char *name, const char *val) 1069Var_SetExpand(GNode *scope, const char *name, const char *val)
1076{ 1070{
1077 Var_SetExpandWithFlags(scope, name, val, VAR_SET_NONE); 1071 Var_SetExpandWithFlags(scope, name, val, VAR_SET_NONE);
1078} 1072}
1079 1073
1080void 1074void
1081Global_Set(const char *name, const char *value) 1075Global_Set(const char *name, const char *value)
1082{ 1076{
1083 Var_Set(SCOPE_GLOBAL, name, value); 1077 Var_Set(SCOPE_GLOBAL, name, value);
1084} 1078}
1085 1079
1086void 1080void
1087Global_SetExpand(const char *name, const char *value) 1081Global_SetExpand(const char *name, const char *value)
1088{ 1082{
1089 Var_SetExpand(SCOPE_GLOBAL, name, value); 1083 Var_SetExpand(SCOPE_GLOBAL, name, value);
1090} 1084}
1091 1085
1092void 1086void
1093Global_Delete(const char *name) 1087Global_Delete(const char *name)
1094{ 1088{
1095 Var_Delete(SCOPE_GLOBAL, name); 1089 Var_Delete(SCOPE_GLOBAL, name);
1096} 1090}
1097 1091
1098/* 1092/*
1099 * Append the value to the named variable. 1093 * Append the value to the named variable.
1100 * 1094 *
1101 * If the variable doesn't exist, it is created. Otherwise a single space 1095 * If the variable doesn't exist, it is created. Otherwise a single space
1102 * and the given value are appended. 1096 * and the given value are appended.
1103 */ 1097 */
1104void 1098void
1105Var_Append(GNode *scope, const char *name, const char *val) 1099Var_Append(GNode *scope, const char *name, const char *val)
1106{ 1100{
1107 Var *v; 1101 Var *v;
1108 1102
1109 v = VarFind(name, scope, scope == SCOPE_GLOBAL); 1103 v = VarFind(name, scope, scope == SCOPE_GLOBAL);
1110 1104
1111 if (v == NULL) { 1105 if (v == NULL) {
1112 Var_SetWithFlags(scope, name, val, VAR_SET_NONE); 1106 Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
1113 } else if (v->flags & VFL_READONLY) { 1107 } else if (v->flags & VFL_READONLY) {
1114 DEBUG1(VAR, "Ignoring append to %s since it is read-only\n", 1108 DEBUG1(VAR, "Ignoring append to %s since it is read-only\n",
1115 name); 1109 name);
1116 } else if (scope == SCOPE_CMDLINE || !(v->flags & VFL_FROM_CMD)) { 1110 } else if (scope == SCOPE_CMDLINE || !(v->flags & VFL_FROM_CMD)) {
1117 Buf_AddByte(&v->val, ' '); 1111 Buf_AddByte(&v->val, ' ');
1118 Buf_AddStr(&v->val, val); 1112 Buf_AddStr(&v->val, val);
1119 1113
1120 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, v->val.data); 1114 DEBUG3(VAR, "%s:%s = %s\n", scope->name, name, v->val.data);
1121 1115
1122 if (v->flags & VFL_FROM_ENV) { 1116 if (v->flags & VFL_FROM_ENV) {
1123 /* 1117 /*
1124 * If the original variable came from the environment, 1118 * If the original variable came from the environment,
1125 * we have to install it in the global scope (we 1119 * we have to install it in the global scope (we
1126 * could place it in the environment, but then we 1120 * could place it in the environment, but then we
1127 * should provide a way to export other variables...) 1121 * should provide a way to export other variables...)
1128 */ 1122 */
1129 v->flags &= ~(unsigned)VFL_FROM_ENV; 1123 v->flags &= ~(unsigned)VFL_FROM_ENV;
1130 /* 1124 /*
1131 * This is the only place where a variable is 1125 * This is the only place where a variable is
1132 * created whose v->name is not the same as 1126 * created whose v->name is not the same as
1133 * scope->vars->key. 1127 * scope->vars->key.
1134 */ 1128 */
1135 HashTable_Set(&scope->vars, name, v); 1129 HashTable_Set(&scope->vars, name, v);
1136 } 1130 }
1137 } 1131 }
1138} 1132}
1139 1133
1140/* 1134/*
1141 * The variable of the given name has the given value appended to it in the 1135 * The variable of the given name has the given value appended to it in the
1142 * given scope. 1136 * given scope.
1143 * 1137 *
1144 * If the variable doesn't exist, it is created. Otherwise the strings are 1138 * If the variable doesn't exist, it is created. Otherwise the strings are
1145 * concatenated, with a space in between. 1139 * concatenated, with a space in between.
1146 * 1140 *
1147 * Input: 1141 * Input:
1148 * name name of the variable to modify, is expanded once 1142 * name name of the variable to modify, is expanded once
1149 * val string to append to it 1143 * val string to append to it
1150 * scope scope in which this should occur 1144 * scope scope in which this should occur
1151 * 1145 *
1152 * Notes: 1146 * Notes:
1153 * Only if the variable is being sought in the global scope is the 1147 * Only if the variable is being sought in the global scope is the
1154 * environment searched. 1148 * environment searched.
1155 * XXX: Knows its calling circumstances in that if called with scope 1149 * XXX: Knows its calling circumstances in that if called with scope
1156 * an actual target, it will only search that scope since only 1150 * an actual target, it will only search that scope since only
1157 * a local variable could be being appended to. This is actually 1151 * a local variable could be being appended to. This is actually
1158 * a big win and must be tolerated. 1152 * a big win and must be tolerated.
1159 */ 1153 */
1160void 1154void
1161Var_AppendExpand(GNode *scope, const char *name, const char *val) 1155Var_AppendExpand(GNode *scope, const char *name, const char *val)
1162{ 1156{
1163 FStr xname = FStr_InitRefer(name); 1157 FStr xname = FStr_InitRefer(name);
1164 1158
1165 assert(val != NULL); 1159 assert(val != NULL);
1166 1160
1167 if (strchr(name, '$') != NULL) { 1161 if (strchr(name, '$') != NULL) {
1168 char *expanded; 1162 char *expanded;
1169 (void)Var_Subst(name, scope, VARE_WANTRES, &expanded); 1163 (void)Var_Subst(name, scope, VARE_WANTRES, &expanded);
1170 /* TODO: handle errors */ 1164 /* TODO: handle errors */
1171 xname = FStr_InitOwn(expanded); 1165 xname = FStr_InitOwn(expanded);
1172 if (expanded[0] == '\0') { 1166 if (expanded[0] == '\0') {
1173 /* TODO: update function name in the debug message */ 1167 /* TODO: update function name in the debug message */
1174 DEBUG2(VAR, "Var_Append(\"%s\", \"%s\", ...) " 1168 DEBUG2(VAR, "Var_Append(\"%s\", \"%s\", ...) "
1175 "name expands to empty string - ignored\n", 1169 "name expands to empty string - ignored\n",
1176 name, val); 1170 name, val);
1177 FStr_Done(&xname); 1171 FStr_Done(&xname);
1178 return; 1172 return;
1179 } 1173 }
1180 } 1174 }
1181 1175
1182 Var_Append(scope, xname.str, val); 1176 Var_Append(scope, xname.str, val);
1183 1177
1184 FStr_Done(&xname); 1178 FStr_Done(&xname);
1185} 1179}
1186 1180
1187void 1181void
1188Global_Append(const char *name, const char *value) 1182Global_Append(const char *name, const char *value)
1189{ 1183{
1190 Var_Append(SCOPE_GLOBAL, name, value); 1184 Var_Append(SCOPE_GLOBAL, name, value);
1191} 1185}
1192 1186
1193Boolean 1187Boolean
1194Var_Exists(GNode *scope, const char *name) 1188Var_Exists(GNode *scope, const char *name)
1195{ 1189{
1196 Var *v = VarFind(name, scope, TRUE); 1190 Var *v = VarFind(name, scope, TRUE);
1197 if (v == NULL) 1191 if (v == NULL)
1198 return FALSE; 1192 return FALSE;
1199 1193
1200 VarFreeEnv(v); 1194 VarFreeEnv(v);
1201 return TRUE; 1195 return TRUE;
1202} 1196}
1203 1197
1204/* 1198/*
1205 * See if the given variable exists, in the given scope or in other 1199 * See if the given variable exists, in the given scope or in other
1206 * fallback scopes. 1200 * fallback scopes.
1207 * 1201 *
1208 * Input: 1202 * Input:
1209 * name Variable to find, is expanded once 1203 * name Variable to find, is expanded once
1210 * scope Scope in which to start search 1204 * scope Scope in which to start search
1211 */ 1205 */
1212Boolean 1206Boolean
1213Var_ExistsExpand(GNode *scope, const char *name) 1207Var_ExistsExpand(GNode *scope, const char *name)
1214{ 1208{
1215 FStr varname = FStr_InitRefer(name); 1209 FStr varname = FStr_InitRefer(name);
1216 Boolean exists; 1210 Boolean exists;
1217 1211
1218 if (strchr(varname.str, '$') != NULL) { 1212 if (strchr(varname.str, '$') != NULL) {
1219 char *expanded; 1213 char *expanded;
1220 (void)Var_Subst(varname.str, scope, VARE_WANTRES, &expanded); 1214 (void)Var_Subst(varname.str, scope, VARE_WANTRES, &expanded);
1221 /* TODO: handle errors */ 1215 /* TODO: handle errors */
1222 varname = FStr_InitOwn(expanded); 1216 varname = FStr_InitOwn(expanded);
1223 } 1217 }
1224 1218
1225 exists = Var_Exists(scope, varname.str); 1219 exists = Var_Exists(scope, varname.str);
1226 FStr_Done(&varname); 1220 FStr_Done(&varname);
1227 return exists; 1221 return exists;
1228} 1222}
1229 1223
1230/* 1224/*
1231 * Return the unexpanded value of the given variable in the given scope, 1225 * Return the unexpanded value of the given variable in the given scope,
1232 * or the usual scopes. 1226 * or the usual scopes.
1233 * 1227 *
1234 * Input: 1228 * Input:
1235 * name name to find, is not expanded any further 1229 * name name to find, is not expanded any further
1236 * scope scope in which to search for it 1230 * scope scope in which to search for it
1237 * 1231 *
1238 * Results: 1232 * Results:
1239 * The value if the variable exists, NULL if it doesn't. 1233 * The value if the variable exists, NULL if it doesn't.
1240 * The value is valid until the next modification to any variable. 1234 * The value is valid until the next modification to any variable.
1241 */ 1235 */
1242FStr 1236FStr
1243Var_Value(GNode *scope, const char *name) 1237Var_Value(GNode *scope, const char *name)
1244{ 1238{
1245 Var *v = VarFind(name, scope, TRUE); 1239 Var *v = VarFind(name, scope, TRUE);
1246 char *value; 1240 char *value;
1247 1241
1248 if (v == NULL) 1242 if (v == NULL)
1249 return FStr_InitRefer(NULL); 1243 return FStr_InitRefer(NULL);
1250 1244
1251 if (!(v->flags & VFL_FROM_ENV)) 1245 if (!(v->flags & VFL_FROM_ENV))
1252 return FStr_InitRefer(v->val.data); 1246 return FStr_InitRefer(v->val.data);
1253 1247
1254 /* Since environment variables are short-lived, free it now. */ 1248 /* Since environment variables are short-lived, free it now. */
1255 FStr_Done(&v->name); 1249 FStr_Done(&v->name);
1256 value = Buf_DoneData(&v->val); 1250 value = Buf_DoneData(&v->val);
1257 free(v); 1251 free(v);
1258 return FStr_InitOwn(value); 1252 return FStr_InitOwn(value);
1259} 1253}
1260 1254
1261/* 1255/*
1262 * Return the unexpanded variable value from this node, without trying to look 1256 * Return the unexpanded variable value from this node, without trying to look
1263 * up the variable in any other scope. 1257 * up the variable in any other scope.
1264 */ 1258 */
1265const char * 1259const char *
1266GNode_ValueDirect(GNode *gn, const char *name) 1260GNode_ValueDirect(GNode *gn, const char *name)
1267{ 1261{
1268 Var *v = VarFind(name, gn, FALSE); 1262 Var *v = VarFind(name, gn, FALSE);
1269 return v != NULL ? v->val.data : NULL; 1263 return v != NULL ? v->val.data : NULL;
1270} 1264}
1271 1265
1272 1266
1273static void 1267static void
1274SepBuf_Init(SepBuf *buf, char sep) 1268SepBuf_Init(SepBuf *buf, char sep)
1275{ 1269{
1276 Buf_InitSize(&buf->buf, 32); 1270 Buf_InitSize(&buf->buf, 32);
1277 buf->needSep = FALSE; 1271 buf->needSep = FALSE;
1278 buf->sep = sep; 1272 buf->sep = sep;
1279} 1273}
1280 1274
1281static void 1275static void
1282SepBuf_Sep(SepBuf *buf) 1276SepBuf_Sep(SepBuf *buf)
1283{ 1277{
1284 buf->needSep = TRUE; 1278 buf->needSep = TRUE;
1285} 1279}
1286 1280
1287static void 1281static void
1288SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1282SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1289{ 1283{
1290 if (mem_size == 0) 1284 if (mem_size == 0)
1291 return; 1285 return;
1292 if (buf->needSep && buf->sep != '\0') { 1286 if (buf->needSep && buf->sep != '\0') {
1293 Buf_AddByte(&buf->buf, buf->sep); 1287 Buf_AddByte(&buf->buf, buf->sep);
1294 buf->needSep = FALSE; 1288 buf->needSep = FALSE;
1295 } 1289 }
1296 Buf_AddBytes(&buf->buf, mem, mem_size); 1290 Buf_AddBytes(&buf->buf, mem, mem_size);
1297} 1291}
1298 1292
1299static void 1293static void
1300SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1294SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1301{ 1295{
1302 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1296 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1303} 1297}
1304 1298
1305static void 1299static void
1306SepBuf_AddStr(SepBuf *buf, const char *str) 1300SepBuf_AddStr(SepBuf *buf, const char *str)
1307{ 1301{
1308 SepBuf_AddBytes(buf, str, strlen(str)); 1302 SepBuf_AddBytes(buf, str, strlen(str));
1309} 1303}
1310 1304
1311static char * 1305static char *
1312SepBuf_DoneData(SepBuf *buf) 1306SepBuf_DoneData(SepBuf *buf)
1313{ 1307{
1314 return Buf_DoneData(&buf->buf); 1308 return Buf_DoneData(&buf->buf);
1315} 1309}
1316 1310
1317 1311
1318/* 1312/*
1319 * This callback for ModifyWords gets a single word from a variable expression 1313 * This callback for ModifyWords gets a single word from a variable expression
1320 * and typically adds a modification of this word to the buffer. It may also 1314 * and typically adds a modification of this word to the buffer. It may also
1321 * do nothing or add several words. 1315 * do nothing or add several words.
1322 * 1316 *
1323 * For example, when evaluating the modifier ':M*b' in ${:Ua b c:M*b}, the 1317 * For example, when evaluating the modifier ':M*b' in ${:Ua b c:M*b}, the
1324 * callback is called 3 times, once for "a", "b" and "c". 1318 * callback is called 3 times, once for "a", "b" and "c".
1325 */ 1319 */
1326typedef void (*ModifyWordProc)(const char *word, SepBuf *buf, void *data); 1320typedef void (*ModifyWordProc)(const char *word, SepBuf *buf, void *data);
1327 1321
1328 1322
1329/* 1323/*
1330 * Callback for ModifyWords to implement the :H modifier. 1324 * Callback for ModifyWords to implement the :H modifier.
1331 * Add the dirname of the given word to the buffer. 1325 * Add the dirname of the given word to the buffer.
1332 */ 1326 */
1333/*ARGSUSED*/ 1327/*ARGSUSED*/
1334static void 1328static void
1335ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1329ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1336{ 1330{
1337 const char *slash = strrchr(word, '/'); 1331 const char *slash = strrchr(word, '/');
1338 if (slash != NULL) 1332 if (slash != NULL)
1339 SepBuf_AddBytesBetween(buf, word, slash); 1333 SepBuf_AddBytesBetween(buf, word, slash);
1340 else 1334 else
1341 SepBuf_AddStr(buf, "."); 1335 SepBuf_AddStr(buf, ".");
1342} 1336}
1343 1337
1344/* 1338/*
1345 * Callback for ModifyWords to implement the :T modifier. 1339 * Callback for ModifyWords to implement the :T modifier.
1346 * Add the basename of the given word to the buffer. 1340 * Add the basename of the given word to the buffer.
1347 */ 1341 */
1348/*ARGSUSED*/ 1342/*ARGSUSED*/
1349static void 1343static void
1350ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1344ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1351{ 1345{
1352 SepBuf_AddStr(buf, str_basename(word)); 1346 SepBuf_AddStr(buf, str_basename(word));
1353} 1347}
1354 1348
1355/* 1349/*
1356 * Callback for ModifyWords to implement the :E modifier. 1350 * Callback for ModifyWords to implement the :E modifier.
1357 * Add the filename suffix of the given word to the buffer, if it exists. 1351 * Add the filename suffix of the given word to the buffer, if it exists.
1358 */ 1352 */
1359/*ARGSUSED*/ 1353/*ARGSUSED*/
1360static void 1354static void
1361ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1355ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1362{ 1356{
1363 const char *lastDot = strrchr(word, '.'); 1357 const char *lastDot = strrchr(word, '.');
1364 if (lastDot != NULL) 1358 if (lastDot != NULL)
1365 SepBuf_AddStr(buf, lastDot + 1); 1359 SepBuf_AddStr(buf, lastDot + 1);
1366} 1360}
1367 1361
1368/* 1362/*
1369 * Callback for ModifyWords to implement the :R modifier. 1363 * Callback for ModifyWords to implement the :R modifier.
1370 * Add the filename without extension of the given word to the buffer. 1364 * Add the filename without extension of the given word to the buffer.
1371 */ 1365 */
1372/*ARGSUSED*/ 1366/*ARGSUSED*/
1373static void 1367static void
1374ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1368ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1375{ 1369{
1376 const char *lastDot = strrchr(word, '.'); 1370 const char *lastDot = strrchr(word, '.');
1377 size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word); 1371 size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word);
1378 SepBuf_AddBytes(buf, word, len); 1372 SepBuf_AddBytes(buf, word, len);
1379} 1373}
1380 1374
1381/* 1375/*
1382 * Callback for ModifyWords to implement the :M modifier. 1376 * Callback for ModifyWords to implement the :M modifier.
1383 * Place the word in the buffer if it matches the given pattern. 1377 * Place the word in the buffer if it matches the given pattern.
1384 */ 1378 */
1385static void 1379static void
1386ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1380ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1387{ 1381{
1388 const char *pattern = data; 1382 const char *pattern = data;
1389 DEBUG2(VAR, "VarMatch [%s] [%s]\n", word, pattern); 1383 DEBUG2(VAR, "VarMatch [%s] [%s]\n", word, pattern);
1390 if (Str_Match(word, pattern)) 1384 if (Str_Match(word, pattern))
1391 SepBuf_AddStr(buf, word); 1385 SepBuf_AddStr(buf, word);
1392} 1386}
1393 1387
1394/* 1388/*
1395 * Callback for ModifyWords to implement the :N modifier. 1389 * Callback for ModifyWords to implement the :N modifier.
1396 * Place the word in the buffer if it doesn't match the given pattern. 1390 * Place the word in the buffer if it doesn't match the given pattern.
1397 */ 1391 */
1398static void 1392static void
1399ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1393ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1400{ 1394{
1401 const char *pattern = data; 1395 const char *pattern = data;
1402 if (!Str_Match(word, pattern)) 1396 if (!Str_Match(word, pattern))
1403 SepBuf_AddStr(buf, word); 1397 SepBuf_AddStr(buf, word);
1404} 1398}
1405 1399
1406#ifdef SYSVVARSUB 1400#ifdef SYSVVARSUB
1407 1401
1408/* 1402/*
1409 * Check word against pattern for a match (% is a wildcard). 1403 * Check word against pattern for a match (% is a wildcard).
1410 * 1404 *
1411 * Input: 1405 * Input:
1412 * word Word to examine 1406 * word Word to examine
1413 * pattern Pattern to examine against 1407 * pattern Pattern to examine against
1414 * 1408 *
1415 * Results: 1409 * Results:
1416 * Returns the start of the match, or NULL. 1410 * Returns the start of the match, or NULL.
1417 * out_match_len returns the length of the match, if any. 1411 * out_match_len returns the length of the match, if any.
1418 * out_hasPercent returns whether the pattern contains a percent. 1412 * out_hasPercent returns whether the pattern contains a percent.
1419 */ 1413 */
1420static const char * 1414static const char *
1421SysVMatch(const char *word, const char *pattern, 1415SysVMatch(const char *word, const char *pattern,
1422 size_t *out_match_len, Boolean *out_hasPercent) 1416 size_t *out_match_len, Boolean *out_hasPercent)
1423{ 1417{
1424 const char *p = pattern; 1418 const char *p = pattern;
1425 const char *w = word; 1419 const char *w = word;
1426 const char *percent; 1420 const char *percent;
1427 size_t w_len; 1421 size_t w_len;
1428 size_t p_len; 1422 size_t p_len;
1429 const char *w_tail; 1423 const char *w_tail;
1430 1424
1431 *out_hasPercent = FALSE; 1425 *out_hasPercent = FALSE;
1432 percent = strchr(p, '%'); 1426 percent = strchr(p, '%');
1433 if (percent != NULL) { /* ${VAR:...%...=...} */ 1427 if (percent != NULL) { /* ${VAR:...%...=...} */
1434 *out_hasPercent = TRUE; 1428 *out_hasPercent = TRUE;
1435 if (w[0] == '\0') 1429 if (w[0] == '\0')
1436 return NULL; /* empty word does not match pattern */ 1430 return NULL; /* empty word does not match pattern */
1437 1431
1438 /* check that the prefix matches */ 1432 /* check that the prefix matches */
1439 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1433 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1440 continue; 1434 continue;
1441 if (p != percent) 1435 if (p != percent)
1442 return NULL; /* No match */ 1436 return NULL; /* No match */
1443 1437
1444 p++; /* Skip the percent */ 1438 p++; /* Skip the percent */
1445 if (*p == '\0') { 1439 if (*p == '\0') {
1446 /* No more pattern, return the rest of the string */ 1440 /* No more pattern, return the rest of the string */
1447 *out_match_len = strlen(w); 1441 *out_match_len = strlen(w);
1448 return w; 1442 return w;
1449 } 1443 }
1450 } 1444 }
1451 1445
1452 /* Test whether the tail matches */ 1446 /* Test whether the tail matches */
1453 w_len = strlen(w); 1447 w_len = strlen(w);
1454 p_len = strlen(p); 1448 p_len = strlen(p);
1455 if (w_len < p_len) 1449 if (w_len < p_len)
1456 return NULL; 1450 return NULL;
1457 1451
1458 w_tail = w + w_len - p_len; 1452 w_tail = w + w_len - p_len;
1459 if (memcmp(p, w_tail, p_len) != 0) 1453 if (memcmp(p, w_tail, p_len) != 0)
1460 return NULL; 1454 return NULL;
1461 1455
1462 *out_match_len = (size_t)(w_tail - w); 1456 *out_match_len = (size_t)(w_tail - w);
1463 return w; 1457 return w;
1464} 1458}
1465 1459
1466struct ModifyWord_SYSVSubstArgs { 1460struct ModifyWord_SYSVSubstArgs {
1467 GNode *scope; 1461 GNode *scope;
1468 const char *lhs; 1462 const char *lhs;
1469 const char *rhs; 1463 const char *rhs;