Sun Nov 1 12:34:46 2020 UTC ()
make(1): clean up comments in ApplyModifier_Words


(rillig)
diff -r1.632 -r1.633 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/10/31 23:23:22 1.632
+++ src/usr.bin/make/var.c 2020/11/01 12:34:45 1.633
@@ -1,3736 +1,3737 @@ @@ -1,3736 +1,3737 @@
1/* $NetBSD: var.c,v 1.632 2020/10/31 23:23:22 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.633 2020/11/01 12:34:45 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 <errno.h> 122#include <errno.h>
123#include <inttypes.h> 123#include <inttypes.h>
124#include <limits.h> 124#include <limits.h>
125#include <time.h> 125#include <time.h>
126 126
127#include "make.h" 127#include "make.h"
128#include "dir.h" 128#include "dir.h"
129#include "job.h" 129#include "job.h"
130#include "metachar.h" 130#include "metachar.h"
131 131
132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 132/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
133MAKE_RCSID("$NetBSD: var.c,v 1.632 2020/10/31 23:23:22 rillig Exp $"); 133MAKE_RCSID("$NetBSD: var.c,v 1.633 2020/11/01 12:34:45 rillig Exp $");
134 134
135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 135#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 136#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 137#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 138#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
139 139
140ENUM_FLAGS_RTTI_3(VarEvalFlags, 140ENUM_FLAGS_RTTI_3(VarEvalFlags,
141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 141 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
142 142
143/* 143/*
144 * This lets us tell if we have replaced the original environ 144 * This lets us tell if we have replaced the original environ
145 * (which we cannot free). 145 * (which we cannot free).
146 */ 146 */
147char **savedEnv = NULL; 147char **savedEnv = NULL;
148 148
149/* Special return value for Var_Parse, indicating a parse error. It may be 149/* Special return value for Var_Parse, indicating a parse error. It may be
150 * caused by an undefined variable, a syntax error in a modifier or 150 * caused by an undefined variable, a syntax error in a modifier or
151 * something entirely different. */ 151 * something entirely different. */
152char var_Error[] = ""; 152char var_Error[] = "";
153 153
154/* Special return value for Var_Parse, indicating an undefined variable in 154/* Special return value for Var_Parse, indicating an undefined variable in
155 * a case where VARE_UNDEFERR is not set. This undefined variable is 155 * a case where VARE_UNDEFERR is not set. This undefined variable is
156 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 156 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
157 * be deferred until it is defined in an actual target. */ 157 * be deferred until it is defined in an actual target. */
158static char varUndefined[] = ""; 158static char varUndefined[] = "";
159 159
160/* Special return value for Var_Parse, just to avoid allocating empty strings. 160/* Special return value for Var_Parse, just to avoid allocating empty strings.
161 * In contrast to var_Error and varUndefined, this is not an error marker but 161 * In contrast to var_Error and varUndefined, this is not an error marker but
162 * just an ordinary successful return value. */ 162 * just an ordinary successful return value. */
163static char emptyString[] = ""; 163static char emptyString[] = "";
164 164
165/* 165/*
166 * Traditionally this make consumed $$ during := like any other expansion. 166 * Traditionally this make consumed $$ during := like any other expansion.
167 * Other make's do not, and this make follows straight since 2016-01-09. 167 * Other make's do not, and this make follows straight since 2016-01-09.
168 * 168 *
169 * This knob allows controlling the behavior. 169 * This knob allows controlling the behavior.
170 * FALSE to consume $$ during := assignment. 170 * FALSE to consume $$ during := assignment.
171 * TRUE to preserve $$ during := assignment. 171 * TRUE to preserve $$ during := assignment.
172 */ 172 */
173#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 173#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
174static Boolean save_dollars = TRUE; 174static Boolean save_dollars = TRUE;
175 175
176/* 176/*
177 * Internally, variables are contained in four different contexts. 177 * Internally, variables are contained in four different contexts.
178 * 1) the environment. They cannot be changed. If an environment 178 * 1) the environment. They cannot be changed. If an environment
179 * variable is appended to, the result is placed in the global 179 * variable is appended to, the result is placed in the global
180 * context. 180 * context.
181 * 2) the global context. Variables set in the makefiles are located 181 * 2) the global context. Variables set in the makefiles are located
182 * here. 182 * here.
183 * 3) the command-line context. All variables set on the command line 183 * 3) the command-line context. All variables set on the command line
184 * are placed in this context. 184 * are placed in this context.
185 * 4) the local context. Each target has associated with it a context 185 * 4) the local context. Each target has associated with it a context
186 * list. On this list are located the structures describing such 186 * list. On this list are located the structures describing such
187 * local variables as $(@) and $(*) 187 * local variables as $(@) and $(*)
188 * The four contexts are searched in the reverse order from which they are 188 * The four contexts are searched in the reverse order from which they are
189 * listed (but see opts.checkEnvFirst). 189 * listed (but see opts.checkEnvFirst).
190 */ 190 */
191GNode *VAR_INTERNAL; /* variables from make itself */ 191GNode *VAR_INTERNAL; /* variables from make itself */
192GNode *VAR_GLOBAL; /* variables from the makefile */ 192GNode *VAR_GLOBAL; /* variables from the makefile */
193GNode *VAR_CMDLINE; /* variables defined on the command-line */ 193GNode *VAR_CMDLINE; /* variables defined on the command-line */
194 194
195typedef enum VarFlags { 195typedef enum VarFlags {
196 196
197 /* The variable's value is currently being used by Var_Parse or Var_Subst. 197 /* The variable's value is currently being used by Var_Parse or Var_Subst.
198 * This marker is used to avoid endless recursion. */ 198 * This marker is used to avoid endless recursion. */
199 VAR_IN_USE = 0x01, 199 VAR_IN_USE = 0x01,
200 200
201 /* The variable comes from the environment. 201 /* The variable comes from the environment.
202 * These variables are not registered in any GNode, therefore they must 202 * These variables are not registered in any GNode, therefore they must
203 * be freed as soon as they are not used anymore. */ 203 * be freed as soon as they are not used anymore. */
204 VAR_FROM_ENV = 0x02, 204 VAR_FROM_ENV = 0x02,
205 205
206 /* The variable is exported to the environment, to be used by child 206 /* The variable is exported to the environment, to be used by child
207 * processes. */ 207 * processes. */
208 VAR_EXPORTED = 0x10, 208 VAR_EXPORTED = 0x10,
209 209
210 /* At the point where this variable was exported, it contained an 210 /* At the point where this variable was exported, it contained an
211 * unresolved reference to another variable. Before any child process is 211 * unresolved reference to another variable. Before any child process is
212 * started, it needs to be exported again, in the hope that the referenced 212 * started, it needs to be exported again, in the hope that the referenced
213 * variable can then be resolved. */ 213 * variable can then be resolved. */
214 VAR_REEXPORT = 0x20, 214 VAR_REEXPORT = 0x20,
215 215
216 /* The variable came from the command line. */ 216 /* The variable came from the command line. */
217 VAR_FROM_CMD = 0x40, 217 VAR_FROM_CMD = 0x40,
218 218
219 /* The variable value cannot be changed anymore, and the variable cannot 219 /* The variable value cannot be changed anymore, and the variable cannot
220 * be deleted. Any attempts to do so are ignored. */ 220 * be deleted. Any attempts to do so are ignored. */
221 VAR_READONLY = 0x80 221 VAR_READONLY = 0x80
222} VarFlags; 222} VarFlags;
223 223
224ENUM_FLAGS_RTTI_6(VarFlags, 224ENUM_FLAGS_RTTI_6(VarFlags,
225 VAR_IN_USE, VAR_FROM_ENV, 225 VAR_IN_USE, VAR_FROM_ENV,
226 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 226 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
227 227
228/* Variables are defined using one of the VAR=value assignments. Their 228/* Variables are defined using one of the VAR=value assignments. Their
229 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 229 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
230 * such as ${VAR:S,from,to,g:Q}. 230 * such as ${VAR:S,from,to,g:Q}.
231 * 231 *
232 * There are 3 kinds of variables: context variables, environment variables, 232 * There are 3 kinds of variables: context variables, environment variables,
233 * undefined variables. 233 * undefined variables.
234 * 234 *
235 * Context variables are stored in a GNode.context. The only way to undefine 235 * Context variables are stored in a GNode.context. The only way to undefine
236 * a context variable is using the .undef directive. In particular, it must 236 * a context variable is using the .undef directive. In particular, it must
237 * not be possible to undefine a variable during the evaluation of an 237 * not be possible to undefine a variable during the evaluation of an
238 * expression, or Var.name might point nowhere. 238 * expression, or Var.name might point nowhere.
239 * 239 *
240 * Environment variables are temporary. They are returned by VarFind, and 240 * Environment variables are temporary. They are returned by VarFind, and
241 * after using them, they must be freed using VarFreeEnv. 241 * after using them, they must be freed using VarFreeEnv.
242 * 242 *
243 * Undefined variables occur during evaluation of variable expressions such 243 * Undefined variables occur during evaluation of variable expressions such
244 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 244 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
245 */ 245 */
246typedef struct Var { 246typedef struct Var {
247 /* The name of the variable, once set, doesn't change anymore. 247 /* The name of the variable, once set, doesn't change anymore.
248 * For context variables, it aliases the corresponding HashEntry name. 248 * For context variables, it aliases the corresponding HashEntry name.
249 * For environment and undefined variables, it is allocated. */ 249 * For environment and undefined variables, it is allocated. */
250 const char *name; 250 const char *name;
251 void *name_freeIt; 251 void *name_freeIt;
252 252
253 Buffer val; /* its value */ 253 Buffer val; /* its value */
254 VarFlags flags; /* miscellaneous status flags */ 254 VarFlags flags; /* miscellaneous status flags */
255} Var; 255} Var;
256 256
257/* 257/*
258 * Exporting vars is expensive so skip it if we can 258 * Exporting vars is expensive so skip it if we can
259 */ 259 */
260typedef enum VarExportedMode { 260typedef enum VarExportedMode {
261 VAR_EXPORTED_NONE, 261 VAR_EXPORTED_NONE,
262 VAR_EXPORTED_SOME, 262 VAR_EXPORTED_SOME,
263 VAR_EXPORTED_ALL 263 VAR_EXPORTED_ALL
264} VarExportedMode; 264} VarExportedMode;
265 265
266static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 266static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
267 267
268typedef enum VarExportFlags { 268typedef enum VarExportFlags {
269 /* 269 /*
270 * We pass this to Var_Export when doing the initial export 270 * We pass this to Var_Export when doing the initial export
271 * or after updating an exported var. 271 * or after updating an exported var.
272 */ 272 */
273 VAR_EXPORT_PARENT = 0x01, 273 VAR_EXPORT_PARENT = 0x01,
274 /* 274 /*
275 * We pass this to Var_Export1 to tell it to leave the value alone. 275 * We pass this to Var_Export1 to tell it to leave the value alone.
276 */ 276 */
277 VAR_EXPORT_LITERAL = 0x02 277 VAR_EXPORT_LITERAL = 0x02
278} VarExportFlags; 278} VarExportFlags;
279 279
280/* Flags for pattern matching in the :S and :C modifiers */ 280/* Flags for pattern matching in the :S and :C modifiers */
281typedef enum VarPatternFlags { 281typedef enum VarPatternFlags {
282 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */ 282 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
283 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */ 283 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
284 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */ 284 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
285 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */ 285 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
286} VarPatternFlags; 286} VarPatternFlags;
287 287
288static Var * 288static Var *
289VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 289VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
290{ 290{
291 size_t value_len = strlen(value); 291 size_t value_len = strlen(value);
292 Var *var = bmake_malloc(sizeof *var); 292 Var *var = bmake_malloc(sizeof *var);
293 var->name = name; 293 var->name = name;
294 var->name_freeIt = name_freeIt; 294 var->name_freeIt = name_freeIt;
295 Buf_Init(&var->val, value_len + 1); 295 Buf_Init(&var->val, value_len + 1);
296 Buf_AddBytes(&var->val, value, value_len); 296 Buf_AddBytes(&var->val, value, value_len);
297 var->flags = flags; 297 var->flags = flags;
298 return var; 298 return var;
299} 299}
300 300
301static const char * 301static const char *
302CanonicalVarname(const char *name) 302CanonicalVarname(const char *name)
303{ 303{
304 if (*name == '.' && ch_isupper(name[1])) { 304 if (*name == '.' && ch_isupper(name[1])) {
305 switch (name[1]) { 305 switch (name[1]) {
306 case 'A': 306 case 'A':
307 if (strcmp(name, ".ALLSRC") == 0) 307 if (strcmp(name, ".ALLSRC") == 0)
308 name = ALLSRC; 308 name = ALLSRC;
309 if (strcmp(name, ".ARCHIVE") == 0) 309 if (strcmp(name, ".ARCHIVE") == 0)
310 name = ARCHIVE; 310 name = ARCHIVE;
311 break; 311 break;
312 case 'I': 312 case 'I':
313 if (strcmp(name, ".IMPSRC") == 0) 313 if (strcmp(name, ".IMPSRC") == 0)
314 name = IMPSRC; 314 name = IMPSRC;
315 break; 315 break;
316 case 'M': 316 case 'M':
317 if (strcmp(name, ".MEMBER") == 0) 317 if (strcmp(name, ".MEMBER") == 0)
318 name = MEMBER; 318 name = MEMBER;
319 break; 319 break;
320 case 'O': 320 case 'O':
321 if (strcmp(name, ".OODATE") == 0) 321 if (strcmp(name, ".OODATE") == 0)
322 name = OODATE; 322 name = OODATE;
323 break; 323 break;
324 case 'P': 324 case 'P':
325 if (strcmp(name, ".PREFIX") == 0) 325 if (strcmp(name, ".PREFIX") == 0)
326 name = PREFIX; 326 name = PREFIX;
327 break; 327 break;
328 case 'S': 328 case 'S':
329 if (strcmp(name, ".SHELL") == 0) { 329 if (strcmp(name, ".SHELL") == 0) {
330 if (!shellPath) 330 if (!shellPath)
331 Shell_Init(); 331 Shell_Init();
332 } 332 }
333 break; 333 break;
334 case 'T': 334 case 'T':
335 if (strcmp(name, ".TARGET") == 0) 335 if (strcmp(name, ".TARGET") == 0)
336 name = TARGET; 336 name = TARGET;
337 break; 337 break;
338 } 338 }
339 } 339 }
340 340
341 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 341 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
342 342
343 return name; 343 return name;
344} 344}
345 345
346static Var * 346static Var *
347GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 347GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
348{ 348{
349 return HashTable_FindValueHash(&ctxt->context, varname, hash); 349 return HashTable_FindValueHash(&ctxt->context, varname, hash);
350} 350}
351 351
352/* Find the variable in the context, and maybe in other contexts as well. 352/* Find the variable in the context, and maybe in other contexts as well.
353 * 353 *
354 * Input: 354 * Input:
355 * name name to find, is not expanded any further 355 * name name to find, is not expanded any further
356 * ctxt context in which to look first 356 * ctxt context in which to look first
357 * elsewhere TRUE to look in other contexts as well 357 * elsewhere TRUE to look in other contexts as well
358 * 358 *
359 * Results: 359 * Results:
360 * The found variable, or NULL if the variable does not exist. 360 * The found variable, or NULL if the variable does not exist.
361 * If the variable is an environment variable, it must be freed using 361 * If the variable is an environment variable, it must be freed using
362 * VarFreeEnv after use. 362 * VarFreeEnv after use.
363 */ 363 */
364static Var * 364static Var *
365VarFind(const char *name, GNode *ctxt, Boolean elsewhere) 365VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
366{ 366{
367 Var *var; 367 Var *var;
368 unsigned int nameHash; 368 unsigned int nameHash;
369 369
370 /* 370 /*
371 * If the variable name begins with a '.', it could very well be one of 371 * If the variable name begins with a '.', it could very well be one of
372 * the local ones. We check the name against all the local variables 372 * the local ones. We check the name against all the local variables
373 * and substitute the short version in for 'name' if it matches one of 373 * and substitute the short version in for 'name' if it matches one of
374 * them. 374 * them.
375 */ 375 */
376 name = CanonicalVarname(name); 376 name = CanonicalVarname(name);
377 nameHash = Hash_Hash(name); 377 nameHash = Hash_Hash(name);
378 378
379 /* First look for the variable in the given context. */ 379 /* First look for the variable in the given context. */
380 var = GNode_FindVar(ctxt, name, nameHash); 380 var = GNode_FindVar(ctxt, name, nameHash);
381 if (!elsewhere) 381 if (!elsewhere)
382 return var; 382 return var;
383 383
384 /* The variable was not found in the given context. Now look for it in 384 /* The variable was not found in the given context. Now look for it in
385 * the other contexts as well. */ 385 * the other contexts as well. */
386 if (var == NULL && ctxt != VAR_CMDLINE) 386 if (var == NULL && ctxt != VAR_CMDLINE)
387 var = GNode_FindVar(VAR_CMDLINE, name, nameHash); 387 var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
388 388
389 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { 389 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
390 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 390 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
391 if (var == NULL && ctxt != VAR_INTERNAL) { 391 if (var == NULL && ctxt != VAR_INTERNAL) {
392 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 392 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
393 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 393 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
394 } 394 }
395 } 395 }
396 396
397 if (var == NULL) { 397 if (var == NULL) {
398 char *env; 398 char *env;
399 399
400 if ((env = getenv(name)) != NULL) { 400 if ((env = getenv(name)) != NULL) {
401 char *varname = bmake_strdup(name); 401 char *varname = bmake_strdup(name);
402 return VarNew(varname, varname, env, VAR_FROM_ENV); 402 return VarNew(varname, varname, env, VAR_FROM_ENV);
403 } 403 }
404 404
405 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { 405 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
406 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 406 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
407 if (var == NULL && ctxt != VAR_INTERNAL) 407 if (var == NULL && ctxt != VAR_INTERNAL)
408 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 408 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
409 return var; 409 return var;
410 } 410 }
411 411
412 return NULL; 412 return NULL;
413 } 413 }
414 414
415 return var; 415 return var;
416} 416}
417 417
418/* If the variable is an environment variable, free it. 418/* If the variable is an environment variable, free it.
419 * 419 *
420 * Input: 420 * Input:
421 * v the variable 421 * v the variable
422 * freeValue true if the variable value should be freed as well 422 * freeValue true if the variable value should be freed as well
423 * 423 *
424 * Results: 424 * Results:
425 * TRUE if it is an environment variable, FALSE otherwise. 425 * TRUE if it is an environment variable, FALSE otherwise.
426 */ 426 */
427static Boolean 427static Boolean
428VarFreeEnv(Var *v, Boolean freeValue) 428VarFreeEnv(Var *v, Boolean freeValue)
429{ 429{
430 if (!(v->flags & VAR_FROM_ENV)) 430 if (!(v->flags & VAR_FROM_ENV))
431 return FALSE; 431 return FALSE;
432 432
433 free(v->name_freeIt); 433 free(v->name_freeIt);
434 Buf_Destroy(&v->val, freeValue); 434 Buf_Destroy(&v->val, freeValue);
435 free(v); 435 free(v);
436 return TRUE; 436 return TRUE;
437} 437}
438 438
439/* Add a new variable of the given name and value to the given context. 439/* Add a new variable of the given name and value to the given context.
440 * The name and val arguments are duplicated so they may safely be freed. */ 440 * The name and val arguments are duplicated so they may safely be freed. */
441static void 441static void
442VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 442VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
443{ 443{
444 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 444 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
445 Var *v = VarNew(he->key /* aliased */, NULL, val, 445 Var *v = VarNew(he->key /* aliased */, NULL, val,
446 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 446 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
447 HashEntry_Set(he, v); 447 HashEntry_Set(he, v);
448 if (!(ctxt->flags & INTERNAL)) { 448 if (!(ctxt->flags & INTERNAL)) {
449 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 449 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
450 } 450 }
451} 451}
452 452
453/* Remove a variable from a context, freeing all related memory as well. 453/* Remove a variable from a context, freeing all related memory as well.
454 * The variable name is expanded once. */ 454 * The variable name is expanded once. */
455void 455void
456Var_Delete(const char *name, GNode *ctxt) 456Var_Delete(const char *name, GNode *ctxt)
457{ 457{
458 char *name_freeIt = NULL; 458 char *name_freeIt = NULL;
459 HashEntry *he; 459 HashEntry *he;
460 460
461 if (strchr(name, '$') != NULL) { 461 if (strchr(name, '$') != NULL) {
462 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 462 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
463 /* TODO: handle errors */ 463 /* TODO: handle errors */
464 name = name_freeIt; 464 name = name_freeIt;
465 } 465 }
466 he = HashTable_FindEntry(&ctxt->context, name); 466 he = HashTable_FindEntry(&ctxt->context, name);
467 VAR_DEBUG3("%s:delete %s%s\n", 467 VAR_DEBUG3("%s:delete %s%s\n",
468 ctxt->name, name, he != NULL ? "" : " (not found)"); 468 ctxt->name, name, he != NULL ? "" : " (not found)");
469 free(name_freeIt); 469 free(name_freeIt);
470 470
471 if (he != NULL) { 471 if (he != NULL) {
472 Var *v = HashEntry_Get(he); 472 Var *v = HashEntry_Get(he);
473 if (v->flags & VAR_EXPORTED) 473 if (v->flags & VAR_EXPORTED)
474 unsetenv(v->name); 474 unsetenv(v->name);
475 if (strcmp(v->name, MAKE_EXPORTED) == 0) 475 if (strcmp(v->name, MAKE_EXPORTED) == 0)
476 var_exportedVars = VAR_EXPORTED_NONE; 476 var_exportedVars = VAR_EXPORTED_NONE;
477 assert(v->name_freeIt == NULL); 477 assert(v->name_freeIt == NULL);
478 HashTable_DeleteEntry(&ctxt->context, he); 478 HashTable_DeleteEntry(&ctxt->context, he);
479 Buf_Destroy(&v->val, TRUE); 479 Buf_Destroy(&v->val, TRUE);
480 free(v); 480 free(v);
481 } 481 }
482} 482}
483 483
484static Boolean 484static Boolean
485MayExport(const char *name) 485MayExport(const char *name)
486{ 486{
487 if (name[0] == '.') 487 if (name[0] == '.')
488 return FALSE; /* skip internals */ 488 return FALSE; /* skip internals */
489 if (name[0] == '-') 489 if (name[0] == '-')
490 return FALSE; /* skip misnamed variables */ 490 return FALSE; /* skip misnamed variables */
491 if (name[1] == '\0') { 491 if (name[1] == '\0') {
492 /* 492 /*
493 * A single char. 493 * A single char.
494 * If it is one of the vars that should only appear in 494 * If it is one of the vars that should only appear in
495 * local context, skip it, else we can get Var_Subst 495 * local context, skip it, else we can get Var_Subst
496 * into a loop. 496 * into a loop.
497 */ 497 */
498 switch (name[0]) { 498 switch (name[0]) {
499 case '@': 499 case '@':
500 case '%': 500 case '%':
501 case '*': 501 case '*':
502 case '!': 502 case '!':
503 return FALSE; 503 return FALSE;
504 } 504 }
505 } 505 }
506 return TRUE; 506 return TRUE;
507} 507}
508 508
509/* 509/*
510 * Export a single variable. 510 * Export a single variable.
511 * We ignore make internal variables (those which start with '.'). 511 * We ignore make internal variables (those which start with '.').
512 * Also we jump through some hoops to avoid calling setenv 512 * Also we jump through some hoops to avoid calling setenv
513 * more than necessary since it can leak. 513 * more than necessary since it can leak.
514 * We only manipulate flags of vars if 'parent' is set. 514 * We only manipulate flags of vars if 'parent' is set.
515 */ 515 */
516static Boolean 516static Boolean
517Var_Export1(const char *name, VarExportFlags flags) 517Var_Export1(const char *name, VarExportFlags flags)
518{ 518{
519 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 519 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
520 Var *v; 520 Var *v;
521 char *val; 521 char *val;
522 522
523 if (!MayExport(name)) 523 if (!MayExport(name))
524 return FALSE; 524 return FALSE;
525 525
526 v = VarFind(name, VAR_GLOBAL, 0); 526 v = VarFind(name, VAR_GLOBAL, 0);
527 if (v == NULL) 527 if (v == NULL)
528 return FALSE; 528 return FALSE;
529 529
530 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 530 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
531 return FALSE; /* nothing to do */ 531 return FALSE; /* nothing to do */
532 532
533 val = Buf_GetAll(&v->val, NULL); 533 val = Buf_GetAll(&v->val, NULL);
534 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 534 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
535 char *expr; 535 char *expr;
536 536
537 if (parent) { 537 if (parent) {
538 /* 538 /*
539 * Flag the variable as something we need to re-export. 539 * Flag the variable as something we need to re-export.
540 * No point actually exporting it now though, 540 * No point actually exporting it now though,
541 * the child process can do it at the last minute. 541 * the child process can do it at the last minute.
542 */ 542 */
543 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 543 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
544 return TRUE; 544 return TRUE;
545 } 545 }
546 if (v->flags & VAR_IN_USE) { 546 if (v->flags & VAR_IN_USE) {
547 /* 547 /*
548 * We recursed while exporting in a child. 548 * We recursed while exporting in a child.
549 * This isn't going to end well, just skip it. 549 * This isn't going to end well, just skip it.
550 */ 550 */
551 return FALSE; 551 return FALSE;
552 } 552 }
553 553
554 /* XXX: name is injected without escaping it */ 554 /* XXX: name is injected without escaping it */
555 expr = str_concat3("${", name, "}"); 555 expr = str_concat3("${", name, "}");
556 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 556 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
557 /* TODO: handle errors */ 557 /* TODO: handle errors */
558 setenv(name, val, 1); 558 setenv(name, val, 1);
559 free(val); 559 free(val);
560 free(expr); 560 free(expr);
561 } else { 561 } else {
562 if (parent) 562 if (parent)
563 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 563 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
564 if (parent || !(v->flags & VAR_EXPORTED)) 564 if (parent || !(v->flags & VAR_EXPORTED))
565 setenv(name, val, 1); 565 setenv(name, val, 1);
566 } 566 }
567 567
568 /* 568 /*
569 * This is so Var_Set knows to call Var_Export again... 569 * This is so Var_Set knows to call Var_Export again...
570 */ 570 */
571 if (parent) { 571 if (parent) {
572 v->flags |= VAR_EXPORTED; 572 v->flags |= VAR_EXPORTED;
573 } 573 }
574 return TRUE; 574 return TRUE;
575} 575}
576 576
577/* 577/*
578 * This gets called from our child processes. 578 * This gets called from our child processes.
579 */ 579 */
580void 580void
581Var_ExportVars(void) 581Var_ExportVars(void)
582{ 582{
583 char *val; 583 char *val;
584 584
585 /* 585 /*
586 * Several make's support this sort of mechanism for tracking 586 * Several make's support this sort of mechanism for tracking
587 * recursion - but each uses a different name. 587 * recursion - but each uses a different name.
588 * We allow the makefiles to update MAKELEVEL and ensure 588 * We allow the makefiles to update MAKELEVEL and ensure
589 * children see a correctly incremented value. 589 * children see a correctly incremented value.
590 */ 590 */
591 char tmp[BUFSIZ]; 591 char tmp[BUFSIZ];
592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
593 setenv(MAKE_LEVEL_ENV, tmp, 1); 593 setenv(MAKE_LEVEL_ENV, tmp, 1);
594 594
595 if (var_exportedVars == VAR_EXPORTED_NONE) 595 if (var_exportedVars == VAR_EXPORTED_NONE)
596 return; 596 return;
597 597
598 if (var_exportedVars == VAR_EXPORTED_ALL) { 598 if (var_exportedVars == VAR_EXPORTED_ALL) {
599 HashIter hi; 599 HashIter hi;
600 600
601 /* Ouch! Exporting all variables at once is crazy... */ 601 /* Ouch! Exporting all variables at once is crazy... */
602 HashIter_Init(&hi, &VAR_GLOBAL->context); 602 HashIter_Init(&hi, &VAR_GLOBAL->context);
603 while (HashIter_Next(&hi) != NULL) { 603 while (HashIter_Next(&hi) != NULL) {
604 Var *var = hi.entry->value; 604 Var *var = hi.entry->value;
605 Var_Export1(var->name, 0); 605 Var_Export1(var->name, 0);
606 } 606 }
607 return; 607 return;
608 } 608 }
609 609
610 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 610 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
611 /* TODO: handle errors */ 611 /* TODO: handle errors */
612 if (*val) { 612 if (*val) {
613 Words words = Str_Words(val, FALSE); 613 Words words = Str_Words(val, FALSE);
614 size_t i; 614 size_t i;
615 615
616 for (i = 0; i < words.len; i++) 616 for (i = 0; i < words.len; i++)
617 Var_Export1(words.words[i], 0); 617 Var_Export1(words.words[i], 0);
618 Words_Free(words); 618 Words_Free(words);
619 } 619 }
620 free(val); 620 free(val);
621} 621}
622 622
623/* 623/*
624 * This is called when .export is seen or .MAKE.EXPORTED is modified. 624 * This is called when .export is seen or .MAKE.EXPORTED is modified.
625 * 625 *
626 * It is also called when any exported variable is modified. 626 * It is also called when any exported variable is modified.
627 * XXX: Is it really? 627 * XXX: Is it really?
628 * 628 *
629 * str has the format "[-env|-literal] varname...". 629 * str has the format "[-env|-literal] varname...".
630 */ 630 */
631void 631void
632Var_Export(const char *str, Boolean isExport) 632Var_Export(const char *str, Boolean isExport)
633{ 633{
634 VarExportFlags flags; 634 VarExportFlags flags;
635 char *val; 635 char *val;
636 636
637 if (isExport && str[0] == '\0') { 637 if (isExport && str[0] == '\0') {
638 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 638 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
639 return; 639 return;
640 } 640 }
641 641
642 if (isExport && strncmp(str, "-env", 4) == 0) { 642 if (isExport && strncmp(str, "-env", 4) == 0) {
643 str += 4; 643 str += 4;
644 flags = 0; 644 flags = 0;
645 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 645 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
646 str += 8; 646 str += 8;
647 flags = VAR_EXPORT_LITERAL; 647 flags = VAR_EXPORT_LITERAL;
648 } else { 648 } else {
649 flags = VAR_EXPORT_PARENT; 649 flags = VAR_EXPORT_PARENT;
650 } 650 }
651 651
652 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 652 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
653 /* TODO: handle errors */ 653 /* TODO: handle errors */
654 if (val[0] != '\0') { 654 if (val[0] != '\0') {
655 Words words = Str_Words(val, FALSE); 655 Words words = Str_Words(val, FALSE);
656 656
657 size_t i; 657 size_t i;
658 for (i = 0; i < words.len; i++) { 658 for (i = 0; i < words.len; i++) {
659 const char *name = words.words[i]; 659 const char *name = words.words[i];
660 if (Var_Export1(name, flags)) { 660 if (Var_Export1(name, flags)) {
661 if (var_exportedVars == VAR_EXPORTED_NONE) 661 if (var_exportedVars == VAR_EXPORTED_NONE)
662 var_exportedVars = VAR_EXPORTED_SOME; 662 var_exportedVars = VAR_EXPORTED_SOME;
663 if (isExport && (flags & VAR_EXPORT_PARENT)) { 663 if (isExport && (flags & VAR_EXPORT_PARENT)) {
664 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 664 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
665 } 665 }
666 } 666 }
667 } 667 }
668 Words_Free(words); 668 Words_Free(words);
669 } 669 }
670 free(val); 670 free(val);
671} 671}
672 672
673 673
674extern char **environ; 674extern char **environ;
675 675
676/* 676/*
677 * This is called when .unexport[-env] is seen. 677 * This is called when .unexport[-env] is seen.
678 * 678 *
679 * str must have the form "unexport[-env] varname...". 679 * str must have the form "unexport[-env] varname...".
680 */ 680 */
681void 681void
682Var_UnExport(const char *str) 682Var_UnExport(const char *str)
683{ 683{
684 const char *varnames; 684 const char *varnames;
685 char *varnames_freeIt; 685 char *varnames_freeIt;
686 Boolean unexport_env; 686 Boolean unexport_env;
687 687
688 varnames = NULL; 688 varnames = NULL;
689 varnames_freeIt = NULL; 689 varnames_freeIt = NULL;
690 690
691 str += strlen("unexport"); 691 str += strlen("unexport");
692 unexport_env = strncmp(str, "-env", 4) == 0; 692 unexport_env = strncmp(str, "-env", 4) == 0;
693 if (unexport_env) { 693 if (unexport_env) {
694 const char *cp; 694 const char *cp;
695 char **newenv; 695 char **newenv;
696 696
697 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 697 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
698 if (environ == savedEnv) { 698 if (environ == savedEnv) {
699 /* we have been here before! */ 699 /* we have been here before! */
700 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 700 newenv = bmake_realloc(environ, 2 * sizeof(char *));
701 } else { 701 } else {
702 if (savedEnv) { 702 if (savedEnv) {
703 free(savedEnv); 703 free(savedEnv);
704 savedEnv = NULL; 704 savedEnv = NULL;
705 } 705 }
706 newenv = bmake_malloc(2 * sizeof(char *)); 706 newenv = bmake_malloc(2 * sizeof(char *));
707 } 707 }
708 708
709 /* Note: we cannot safely free() the original environ. */ 709 /* Note: we cannot safely free() the original environ. */
710 environ = savedEnv = newenv; 710 environ = savedEnv = newenv;
711 newenv[0] = NULL; 711 newenv[0] = NULL;
712 newenv[1] = NULL; 712 newenv[1] = NULL;
713 if (cp && *cp) 713 if (cp && *cp)
714 setenv(MAKE_LEVEL_ENV, cp, 1); 714 setenv(MAKE_LEVEL_ENV, cp, 1);
715 } else { 715 } else {
716 cpp_skip_whitespace(&str); 716 cpp_skip_whitespace(&str);
717 if (str[0] != '\0') 717 if (str[0] != '\0')
718 varnames = str; 718 varnames = str;
719 } 719 }
720 720
721 if (varnames == NULL) { 721 if (varnames == NULL) {
722 /* Using .MAKE.EXPORTED */ 722 /* Using .MAKE.EXPORTED */
723 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 723 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
724 &varnames_freeIt); 724 &varnames_freeIt);
725 /* TODO: handle errors */ 725 /* TODO: handle errors */
726 varnames = varnames_freeIt; 726 varnames = varnames_freeIt;
727 } 727 }
728 728
729 { 729 {
730 Var *v; 730 Var *v;
731 size_t i; 731 size_t i;
732 732
733 Words words = Str_Words(varnames, FALSE); 733 Words words = Str_Words(varnames, FALSE);
734 for (i = 0; i < words.len; i++) { 734 for (i = 0; i < words.len; i++) {
735 const char *varname = words.words[i]; 735 const char *varname = words.words[i];
736 v = VarFind(varname, VAR_GLOBAL, 0); 736 v = VarFind(varname, VAR_GLOBAL, 0);
737 if (v == NULL) { 737 if (v == NULL) {
738 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 738 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
739 continue; 739 continue;
740 } 740 }
741 741
742 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 742 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
743 if (!unexport_env && (v->flags & VAR_EXPORTED) && 743 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
744 !(v->flags & VAR_REEXPORT)) 744 !(v->flags & VAR_REEXPORT))
745 unsetenv(v->name); 745 unsetenv(v->name);
746 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 746 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
747 747
748 /* 748 /*
749 * If we are unexporting a list, 749 * If we are unexporting a list,
750 * remove each one from .MAKE.EXPORTED. 750 * remove each one from .MAKE.EXPORTED.
751 * If we are removing them all, 751 * If we are removing them all,
752 * just delete .MAKE.EXPORTED below. 752 * just delete .MAKE.EXPORTED below.
753 */ 753 */
754 if (varnames == str) { 754 if (varnames == str) {
755 /* XXX: v->name is injected without escaping it */ 755 /* XXX: v->name is injected without escaping it */
756 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 756 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
757 char *cp; 757 char *cp;
758 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 758 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
759 /* TODO: handle errors */ 759 /* TODO: handle errors */
760 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 760 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
761 free(cp); 761 free(cp);
762 free(expr); 762 free(expr);
763 } 763 }
764 } 764 }
765 Words_Free(words); 765 Words_Free(words);
766 if (varnames != str) { 766 if (varnames != str) {
767 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 767 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
768 free(varnames_freeIt); 768 free(varnames_freeIt);
769 } 769 }
770 } 770 }
771} 771}
772 772
773/* See Var_Set for documentation. */ 773/* See Var_Set for documentation. */
774void 774void
775Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 775Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
776 VarSet_Flags flags) 776 VarSet_Flags flags)
777{ 777{
778 const char *unexpanded_name = name; 778 const char *unexpanded_name = name;
779 char *name_freeIt = NULL; 779 char *name_freeIt = NULL;
780 Var *v; 780 Var *v;
781 781
782 assert(val != NULL); 782 assert(val != NULL);
783 783
784 if (strchr(name, '$') != NULL) { 784 if (strchr(name, '$') != NULL) {
785 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 785 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
786 /* TODO: handle errors */ 786 /* TODO: handle errors */
787 name = name_freeIt; 787 name = name_freeIt;
788 } 788 }
789 789
790 if (name[0] == '\0') { 790 if (name[0] == '\0') {
791 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 791 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
792 "name expands to empty string - ignored\n", 792 "name expands to empty string - ignored\n",
793 unexpanded_name, val); 793 unexpanded_name, val);
794 free(name_freeIt); 794 free(name_freeIt);
795 return; 795 return;
796 } 796 }
797 797
798 if (ctxt == VAR_GLOBAL) { 798 if (ctxt == VAR_GLOBAL) {
799 v = VarFind(name, VAR_CMDLINE, 0); 799 v = VarFind(name, VAR_CMDLINE, 0);
800 if (v != NULL) { 800 if (v != NULL) {
801 if (v->flags & VAR_FROM_CMD) { 801 if (v->flags & VAR_FROM_CMD) {
802 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 802 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
803 goto out; 803 goto out;
804 } 804 }
805 VarFreeEnv(v, TRUE); 805 VarFreeEnv(v, TRUE);
806 } 806 }
807 } 807 }
808 808
809 /* 809 /*
810 * We only look for a variable in the given context since anything set 810 * We only look for a variable in the given context since anything set
811 * here will override anything in a lower context, so there's not much 811 * here will override anything in a lower context, so there's not much
812 * point in searching them all just to save a bit of memory... 812 * point in searching them all just to save a bit of memory...
813 */ 813 */
814 v = VarFind(name, ctxt, 0); 814 v = VarFind(name, ctxt, 0);
815 if (v == NULL) { 815 if (v == NULL) {
816 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 816 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
817 /* 817 /*
818 * This var would normally prevent the same name being added 818 * This var would normally prevent the same name being added
819 * to VAR_GLOBAL, so delete it from there if needed. 819 * to VAR_GLOBAL, so delete it from there if needed.
820 * Otherwise -V name may show the wrong value. 820 * Otherwise -V name may show the wrong value.
821 */ 821 */
822 /* XXX: name is expanded for the second time */ 822 /* XXX: name is expanded for the second time */
823 Var_Delete(name, VAR_GLOBAL); 823 Var_Delete(name, VAR_GLOBAL);
824 } 824 }
825 VarAdd(name, val, ctxt, flags); 825 VarAdd(name, val, ctxt, flags);
826 } else { 826 } else {
827 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 827 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
828 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 828 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
829 ctxt->name, name, val); 829 ctxt->name, name, val);
830 goto out; 830 goto out;
831 } 831 }
832 Buf_Empty(&v->val); 832 Buf_Empty(&v->val);
833 Buf_AddStr(&v->val, val); 833 Buf_AddStr(&v->val, val);
834 834
835 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 835 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
836 if (v->flags & VAR_EXPORTED) { 836 if (v->flags & VAR_EXPORTED) {
837 Var_Export1(name, VAR_EXPORT_PARENT); 837 Var_Export1(name, VAR_EXPORT_PARENT);
838 } 838 }
839 } 839 }
840 /* 840 /*
841 * Any variables given on the command line are automatically exported 841 * Any variables given on the command line are automatically exported
842 * to the environment (as per POSIX standard) 842 * to the environment (as per POSIX standard)
843 * Other than internals. 843 * Other than internals.
844 */ 844 */
845 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 845 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
846 if (v == NULL) 846 if (v == NULL)
847 v = VarFind(name, ctxt, 0); /* we just added it */ 847 v = VarFind(name, ctxt, 0); /* we just added it */
848 v->flags |= VAR_FROM_CMD; 848 v->flags |= VAR_FROM_CMD;
849 849
850 /* 850 /*
851 * If requested, don't export these in the environment 851 * If requested, don't export these in the environment
852 * individually. We still put them in MAKEOVERRIDES so 852 * individually. We still put them in MAKEOVERRIDES so
853 * that the command-line settings continue to override 853 * that the command-line settings continue to override
854 * Makefile settings. 854 * Makefile settings.
855 */ 855 */
856 if (!opts.varNoExportEnv) 856 if (!opts.varNoExportEnv)
857 setenv(name, val, 1); 857 setenv(name, val, 1);
858 858
859 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 859 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
860 } 860 }
861 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 861 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
862 save_dollars = s2Boolean(val, save_dollars); 862 save_dollars = s2Boolean(val, save_dollars);
863 863
864out: 864out:
865 free(name_freeIt); 865 free(name_freeIt);
866 if (v != NULL) 866 if (v != NULL)
867 VarFreeEnv(v, TRUE); 867 VarFreeEnv(v, TRUE);
868} 868}
869 869
870/*- 870/*-
871 *----------------------------------------------------------------------- 871 *-----------------------------------------------------------------------
872 * Var_Set -- 872 * Var_Set --
873 * Set the variable name to the value val in the given context. 873 * Set the variable name to the value val in the given context.
874 * 874 *
875 * If the variable doesn't yet exist, it is created. 875 * If the variable doesn't yet exist, it is created.
876 * Otherwise the new value overwrites and replaces the old value. 876 * Otherwise the new value overwrites and replaces the old value.
877 * 877 *
878 * Input: 878 * Input:
879 * name name of the variable to set, is expanded once 879 * name name of the variable to set, is expanded once
880 * val value to give to the variable 880 * val value to give to the variable
881 * ctxt context in which to set it 881 * ctxt context in which to set it
882 * 882 *
883 * Notes: 883 * Notes:
884 * The variable is searched for only in its context before being 884 * The variable is searched for only in its context before being
885 * created in that context. I.e. if the context is VAR_GLOBAL, 885 * created in that context. I.e. if the context is VAR_GLOBAL,
886 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 886 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
887 * only VAR_CMDLINE->context is searched. This is done to avoid the 887 * only VAR_CMDLINE->context is searched. This is done to avoid the
888 * literally thousands of unnecessary strcmp's that used to be done to 888 * literally thousands of unnecessary strcmp's that used to be done to
889 * set, say, $(@) or $(<). 889 * set, say, $(@) or $(<).
890 * If the context is VAR_GLOBAL though, we check if the variable 890 * If the context is VAR_GLOBAL though, we check if the variable
891 * was set in VAR_CMDLINE from the command line and skip it if so. 891 * was set in VAR_CMDLINE from the command line and skip it if so.
892 *----------------------------------------------------------------------- 892 *-----------------------------------------------------------------------
893 */ 893 */
894void 894void
895Var_Set(const char *name, const char *val, GNode *ctxt) 895Var_Set(const char *name, const char *val, GNode *ctxt)
896{ 896{
897 Var_Set_with_flags(name, val, ctxt, 0); 897 Var_Set_with_flags(name, val, ctxt, 0);
898} 898}
899 899
900/*- 900/*-
901 *----------------------------------------------------------------------- 901 *-----------------------------------------------------------------------
902 * Var_Append -- 902 * Var_Append --
903 * The variable of the given name has the given value appended to it in 903 * The variable of the given name has the given value appended to it in
904 * the given context. 904 * the given context.
905 * 905 *
906 * If the variable doesn't exist, it is created. Otherwise the strings 906 * If the variable doesn't exist, it is created. Otherwise the strings
907 * are concatenated, with a space in between. 907 * are concatenated, with a space in between.
908 * 908 *
909 * Input: 909 * Input:
910 * name name of the variable to modify, is expanded once 910 * name name of the variable to modify, is expanded once
911 * val string to append to it 911 * val string to append to it
912 * ctxt context in which this should occur 912 * ctxt context in which this should occur
913 * 913 *
914 * Notes: 914 * Notes:
915 * Only if the variable is being sought in the global context is the 915 * Only if the variable is being sought in the global context is the
916 * environment searched. 916 * environment searched.
917 * XXX: Knows its calling circumstances in that if called with ctxt 917 * XXX: Knows its calling circumstances in that if called with ctxt
918 * an actual target, it will only search that context since only 918 * an actual target, it will only search that context since only
919 * a local variable could be being appended to. This is actually 919 * a local variable could be being appended to. This is actually
920 * a big win and must be tolerated. 920 * a big win and must be tolerated.
921 *----------------------------------------------------------------------- 921 *-----------------------------------------------------------------------
922 */ 922 */
923void 923void
924Var_Append(const char *name, const char *val, GNode *ctxt) 924Var_Append(const char *name, const char *val, GNode *ctxt)
925{ 925{
926 char *name_freeIt = NULL; 926 char *name_freeIt = NULL;
927 Var *v; 927 Var *v;
928 928
929 assert(val != NULL); 929 assert(val != NULL);
930 930
931 if (strchr(name, '$') != NULL) { 931 if (strchr(name, '$') != NULL) {
932 const char *unexpanded_name = name; 932 const char *unexpanded_name = name;
933 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 933 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
934 /* TODO: handle errors */ 934 /* TODO: handle errors */
935 name = name_freeIt; 935 name = name_freeIt;
936 if (name[0] == '\0') { 936 if (name[0] == '\0') {
937 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 937 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
938 "name expands to empty string - ignored\n", 938 "name expands to empty string - ignored\n",
939 unexpanded_name, val); 939 unexpanded_name, val);
940 free(name_freeIt); 940 free(name_freeIt);
941 return; 941 return;
942 } 942 }
943 } 943 }
944 944
945 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 945 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
946 946
947 if (v == NULL) { 947 if (v == NULL) {
948 /* XXX: name is expanded for the second time */ 948 /* XXX: name is expanded for the second time */
949 Var_Set(name, val, ctxt); 949 Var_Set(name, val, ctxt);
950 } else if (v->flags & VAR_READONLY) { 950 } else if (v->flags & VAR_READONLY) {
951 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 951 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
952 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 952 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
953 Buf_AddByte(&v->val, ' '); 953 Buf_AddByte(&v->val, ' ');
954 Buf_AddStr(&v->val, val); 954 Buf_AddStr(&v->val, val);
955 955
956 VAR_DEBUG3("%s:%s = %s\n", 956 VAR_DEBUG3("%s:%s = %s\n",
957 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 957 ctxt->name, name, Buf_GetAll(&v->val, NULL));
958 958
959 if (v->flags & VAR_FROM_ENV) { 959 if (v->flags & VAR_FROM_ENV) {
960 HashEntry *h; 960 HashEntry *h;
961 961
962 /* 962 /*
963 * If the original variable came from the environment, we 963 * If the original variable came from the environment, we
964 * have to install it in the global context (we could place 964 * have to install it in the global context (we could place
965 * it in the environment, but then we should provide a way to 965 * it in the environment, but then we should provide a way to
966 * export other variables...) 966 * export other variables...)
967 */ 967 */
968 v->flags &= ~(unsigned)VAR_FROM_ENV; 968 v->flags &= ~(unsigned)VAR_FROM_ENV;
969 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 969 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
970 HashEntry_Set(h, v); 970 HashEntry_Set(h, v);
971 } 971 }
972 } 972 }
973 free(name_freeIt); 973 free(name_freeIt);
974} 974}
975 975
976/* See if the given variable exists, in the given context or in other 976/* See if the given variable exists, in the given context or in other
977 * fallback contexts. 977 * fallback contexts.
978 * 978 *
979 * Input: 979 * Input:
980 * name Variable to find, is expanded once 980 * name Variable to find, is expanded once
981 * ctxt Context in which to start search 981 * ctxt Context in which to start search
982 */ 982 */
983Boolean 983Boolean
984Var_Exists(const char *name, GNode *ctxt) 984Var_Exists(const char *name, GNode *ctxt)
985{ 985{
986 char *name_freeIt = NULL; 986 char *name_freeIt = NULL;
987 Var *v; 987 Var *v;
988 988
989 if (strchr(name, '$') != NULL) { 989 if (strchr(name, '$') != NULL) {
990 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 990 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
991 /* TODO: handle errors */ 991 /* TODO: handle errors */
992 name = name_freeIt; 992 name = name_freeIt;
993 } 993 }
994 994
995 v = VarFind(name, ctxt, TRUE); 995 v = VarFind(name, ctxt, TRUE);
996 free(name_freeIt); 996 free(name_freeIt);
997 if (v == NULL) 997 if (v == NULL)
998 return FALSE; 998 return FALSE;
999 999
1000 (void)VarFreeEnv(v, TRUE); 1000 (void)VarFreeEnv(v, TRUE);
1001 return TRUE; 1001 return TRUE;
1002} 1002}
1003 1003
1004/*- 1004/*-
1005 *----------------------------------------------------------------------- 1005 *-----------------------------------------------------------------------
1006 * Var_Value -- 1006 * Var_Value --
1007 * Return the unexpanded value of the given variable in the given 1007 * Return the unexpanded value of the given variable in the given
1008 * context, or the usual contexts. 1008 * context, or the usual contexts.
1009 * 1009 *
1010 * Input: 1010 * Input:
1011 * name name to find, is not expanded any further 1011 * name name to find, is not expanded any further
1012 * ctxt context in which to search for it 1012 * ctxt context in which to search for it
1013 * 1013 *
1014 * Results: 1014 * Results:
1015 * The value if the variable exists, NULL if it doesn't. 1015 * The value if the variable exists, NULL if it doesn't.
1016 * If the returned value is not NULL, the caller must free 1016 * If the returned value is not NULL, the caller must free
1017 * out_freeIt when the returned value is no longer needed. 1017 * out_freeIt when the returned value is no longer needed.
1018 *----------------------------------------------------------------------- 1018 *-----------------------------------------------------------------------
1019 */ 1019 */
1020const char * 1020const char *
1021Var_Value(const char *name, GNode *ctxt, void **out_freeIt) 1021Var_Value(const char *name, GNode *ctxt, void **out_freeIt)
1022{ 1022{
1023 Var *v = VarFind(name, ctxt, TRUE); 1023 Var *v = VarFind(name, ctxt, TRUE);
1024 char *value; 1024 char *value;
1025 1025
1026 *out_freeIt = NULL; 1026 *out_freeIt = NULL;
1027 if (v == NULL) 1027 if (v == NULL)
1028 return NULL; 1028 return NULL;
1029 1029
1030 value = Buf_GetAll(&v->val, NULL); 1030 value = Buf_GetAll(&v->val, NULL);
1031 if (VarFreeEnv(v, FALSE)) 1031 if (VarFreeEnv(v, FALSE))
1032 *out_freeIt = value; 1032 *out_freeIt = value;
1033 return value; 1033 return value;
1034} 1034}
1035 1035
1036/* Return the unexpanded variable value from this node, without trying to look 1036/* Return the unexpanded variable value from this node, without trying to look
1037 * up the variable in any other context. */ 1037 * up the variable in any other context. */
1038const char * 1038const char *
1039Var_ValueDirect(const char *name, GNode *ctxt) 1039Var_ValueDirect(const char *name, GNode *ctxt)
1040{ 1040{
1041 Var *v = VarFind(name, ctxt, FALSE); 1041 Var *v = VarFind(name, ctxt, FALSE);
1042 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL; 1042 return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
1043} 1043}
1044 1044
1045 1045
1046/* SepBuf is a string being built from words, interleaved with separators. */ 1046/* SepBuf is a string being built from words, interleaved with separators. */
1047typedef struct SepBuf { 1047typedef struct SepBuf {
1048 Buffer buf; 1048 Buffer buf;
1049 Boolean needSep; 1049 Boolean needSep;
1050 char sep; /* usually ' ', but see the :ts modifier */ 1050 char sep; /* usually ' ', but see the :ts modifier */
1051} SepBuf; 1051} SepBuf;
1052 1052
1053static void 1053static void
1054SepBuf_Init(SepBuf *buf, char sep) 1054SepBuf_Init(SepBuf *buf, char sep)
1055{ 1055{
1056 Buf_Init(&buf->buf, 32 /* bytes */); 1056 Buf_Init(&buf->buf, 32 /* bytes */);
1057 buf->needSep = FALSE; 1057 buf->needSep = FALSE;
1058 buf->sep = sep; 1058 buf->sep = sep;
1059} 1059}
1060 1060
1061static void 1061static void
1062SepBuf_Sep(SepBuf *buf) 1062SepBuf_Sep(SepBuf *buf)
1063{ 1063{
1064 buf->needSep = TRUE; 1064 buf->needSep = TRUE;
1065} 1065}
1066 1066
1067static void 1067static void
1068SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1068SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1069{ 1069{
1070 if (mem_size == 0) 1070 if (mem_size == 0)
1071 return; 1071 return;
1072 if (buf->needSep && buf->sep != '\0') { 1072 if (buf->needSep && buf->sep != '\0') {
1073 Buf_AddByte(&buf->buf, buf->sep); 1073 Buf_AddByte(&buf->buf, buf->sep);
1074 buf->needSep = FALSE; 1074 buf->needSep = FALSE;
1075 } 1075 }
1076 Buf_AddBytes(&buf->buf, mem, mem_size); 1076 Buf_AddBytes(&buf->buf, mem, mem_size);
1077} 1077}
1078 1078
1079static void 1079static void
1080SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1080SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1081{ 1081{
1082 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1082 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1083} 1083}
1084 1084
1085static void 1085static void
1086SepBuf_AddStr(SepBuf *buf, const char *str) 1086SepBuf_AddStr(SepBuf *buf, const char *str)
1087{ 1087{
1088 SepBuf_AddBytes(buf, str, strlen(str)); 1088 SepBuf_AddBytes(buf, str, strlen(str));
1089} 1089}
1090 1090
1091static char * 1091static char *
1092SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1092SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1093{ 1093{
1094 return Buf_Destroy(&buf->buf, free_buf); 1094 return Buf_Destroy(&buf->buf, free_buf);
1095} 1095}
1096 1096
1097 1097
1098/* This callback for ModifyWords gets a single word from a variable expression 1098/* This callback for ModifyWords gets a single word from a variable expression
1099 * and typically adds a modification of this word to the buffer. It may also 1099 * and typically adds a modification of this word to the buffer. It may also
1100 * do nothing or add several words. 1100 * do nothing or add several words.
1101 * 1101 *
1102 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for 1102 * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1103 * each word of "a b c". */ 1103 * each word of "a b c". */
1104typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1104typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1105 1105
1106 1106
1107/* Callback for ModifyWords to implement the :H modifier. 1107/* Callback for ModifyWords to implement the :H modifier.
1108 * Add the dirname of the given word to the buffer. */ 1108 * Add the dirname of the given word to the buffer. */
1109static void 1109static void
1110ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1110ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1111{ 1111{
1112 const char *slash = strrchr(word, '/'); 1112 const char *slash = strrchr(word, '/');
1113 if (slash != NULL) 1113 if (slash != NULL)
1114 SepBuf_AddBytesBetween(buf, word, slash); 1114 SepBuf_AddBytesBetween(buf, word, slash);
1115 else 1115 else
1116 SepBuf_AddStr(buf, "."); 1116 SepBuf_AddStr(buf, ".");
1117} 1117}
1118 1118
1119/* Callback for ModifyWords to implement the :T modifier. 1119/* Callback for ModifyWords to implement the :T modifier.
1120 * Add the basename of the given word to the buffer. */ 1120 * Add the basename of the given word to the buffer. */
1121static void 1121static void
1122ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1122ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1123{ 1123{
1124 const char *slash = strrchr(word, '/'); 1124 const char *slash = strrchr(word, '/');
1125 const char *base = slash != NULL ? slash + 1 : word; 1125 const char *base = slash != NULL ? slash + 1 : word;
1126 SepBuf_AddStr(buf, base); 1126 SepBuf_AddStr(buf, base);
1127} 1127}
1128 1128
1129/* Callback for ModifyWords to implement the :E modifier. 1129/* Callback for ModifyWords to implement the :E modifier.
1130 * Add the filename suffix of the given word to the buffer, if it exists. */ 1130 * Add the filename suffix of the given word to the buffer, if it exists. */
1131static void 1131static void
1132ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1132ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1133{ 1133{
1134 const char *dot = strrchr(word, '.'); 1134 const char *dot = strrchr(word, '.');
1135 if (dot != NULL) 1135 if (dot != NULL)
1136 SepBuf_AddStr(buf, dot + 1); 1136 SepBuf_AddStr(buf, dot + 1);
1137} 1137}
1138 1138
1139/* Callback for ModifyWords to implement the :R modifier. 1139/* Callback for ModifyWords to implement the :R modifier.
1140 * Add the basename of the given word to the buffer. */ 1140 * Add the basename of the given word to the buffer. */
1141static void 1141static void
1142ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1142ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1143{ 1143{
1144 const char *dot = strrchr(word, '.'); 1144 const char *dot = strrchr(word, '.');
1145 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1145 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1146 SepBuf_AddBytes(buf, word, len); 1146 SepBuf_AddBytes(buf, word, len);
1147} 1147}
1148 1148
1149/* Callback for ModifyWords to implement the :M modifier. 1149/* Callback for ModifyWords to implement the :M modifier.
1150 * Place the word in the buffer if it matches the given pattern. */ 1150 * Place the word in the buffer if it matches the given pattern. */
1151static void 1151static void
1152ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1152ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1153{ 1153{
1154 const char *pattern = data; 1154 const char *pattern = data;
1155 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1155 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1156 if (Str_Match(word, pattern)) 1156 if (Str_Match(word, pattern))
1157 SepBuf_AddStr(buf, word); 1157 SepBuf_AddStr(buf, word);
1158} 1158}
1159 1159
1160/* Callback for ModifyWords to implement the :N modifier. 1160/* Callback for ModifyWords to implement the :N modifier.
1161 * Place the word in the buffer if it doesn't match the given pattern. */ 1161 * Place the word in the buffer if it doesn't match the given pattern. */
1162static void 1162static void
1163ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1163ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1164{ 1164{
1165 const char *pattern = data; 1165 const char *pattern = data;
1166 if (!Str_Match(word, pattern)) 1166 if (!Str_Match(word, pattern))
1167 SepBuf_AddStr(buf, word); 1167 SepBuf_AddStr(buf, word);
1168} 1168}
1169 1169
1170#ifdef SYSVVARSUB 1170#ifdef SYSVVARSUB
1171/* Check word against pattern for a match (% is a wildcard). 1171/* Check word against pattern for a match (% is a wildcard).
1172 * 1172 *
1173 * Input: 1173 * Input:
1174 * word Word to examine 1174 * word Word to examine
1175 * pattern Pattern to examine against 1175 * pattern Pattern to examine against
1176 * 1176 *
1177 * Results: 1177 * Results:
1178 * Returns the start of the match, or NULL. 1178 * Returns the start of the match, or NULL.
1179 * out_match_len returns the length of the match, if any. 1179 * out_match_len returns the length of the match, if any.
1180 * out_hasPercent returns whether the pattern contains a percent. 1180 * out_hasPercent returns whether the pattern contains a percent.
1181 */ 1181 */
1182static const char * 1182static const char *
1183SysVMatch(const char *word, const char *pattern, 1183SysVMatch(const char *word, const char *pattern,
1184 size_t *out_match_len, Boolean *out_hasPercent) 1184 size_t *out_match_len, Boolean *out_hasPercent)
1185{ 1185{
1186 const char *p = pattern; 1186 const char *p = pattern;
1187 const char *w = word; 1187 const char *w = word;
1188 const char *percent; 1188 const char *percent;
1189 size_t w_len; 1189 size_t w_len;
1190 size_t p_len; 1190 size_t p_len;
1191 const char *w_tail; 1191 const char *w_tail;
1192 1192
1193 *out_hasPercent = FALSE; 1193 *out_hasPercent = FALSE;
1194 percent = strchr(p, '%'); 1194 percent = strchr(p, '%');
1195 if (percent != NULL) { /* ${VAR:...%...=...} */ 1195 if (percent != NULL) { /* ${VAR:...%...=...} */
1196 *out_hasPercent = TRUE; 1196 *out_hasPercent = TRUE;
1197 if (*w == '\0') 1197 if (*w == '\0')
1198 return NULL; /* empty word does not match pattern */ 1198 return NULL; /* empty word does not match pattern */
1199 1199
1200 /* check that the prefix matches */ 1200 /* check that the prefix matches */
1201 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1201 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1202 continue; 1202 continue;
1203 if (p != percent) 1203 if (p != percent)
1204 return NULL; /* No match */ 1204 return NULL; /* No match */
1205 1205
1206 p++; /* Skip the percent */ 1206 p++; /* Skip the percent */
1207 if (*p == '\0') { 1207 if (*p == '\0') {
1208 /* No more pattern, return the rest of the string */ 1208 /* No more pattern, return the rest of the string */
1209 *out_match_len = strlen(w); 1209 *out_match_len = strlen(w);
1210 return w; 1210 return w;
1211 } 1211 }
1212 } 1212 }
1213 1213
1214 /* Test whether the tail matches */ 1214 /* Test whether the tail matches */
1215 w_len = strlen(w); 1215 w_len = strlen(w);
1216 p_len = strlen(p); 1216 p_len = strlen(p);
1217 if (w_len < p_len) 1217 if (w_len < p_len)
1218 return NULL; 1218 return NULL;
1219 1219
1220 w_tail = w + w_len - p_len; 1220 w_tail = w + w_len - p_len;
1221 if (memcmp(p, w_tail, p_len) != 0) 1221 if (memcmp(p, w_tail, p_len) != 0)
1222 return NULL; 1222 return NULL;
1223 1223
1224 *out_match_len = (size_t)(w_tail - w); 1224 *out_match_len = (size_t)(w_tail - w);
1225 return w; 1225 return w;
1226} 1226}
1227 1227
1228struct ModifyWord_SYSVSubstArgs { 1228struct ModifyWord_SYSVSubstArgs {
1229 GNode *ctx; 1229 GNode *ctx;
1230 const char *lhs; 1230 const char *lhs;
1231 const char *rhs; 1231 const char *rhs;
1232}; 1232};
1233 1233
1234/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1234/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1235static void 1235static void
1236ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1236ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1237{ 1237{
1238 const struct ModifyWord_SYSVSubstArgs *args = data; 1238 const struct ModifyWord_SYSVSubstArgs *args = data;
1239 char *rhs_expanded; 1239 char *rhs_expanded;
1240 const char *rhs; 1240 const char *rhs;
1241 const char *percent; 1241 const char *percent;
1242 1242
1243 size_t match_len; 1243 size_t match_len;
1244 Boolean lhsPercent; 1244 Boolean lhsPercent;
1245 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent); 1245 const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
1246 if (match == NULL) { 1246 if (match == NULL) {
1247 SepBuf_AddStr(buf, word); 1247 SepBuf_AddStr(buf, word);
1248 return; 1248 return;
1249 } 1249 }
1250 1250
1251 /* Append rhs to the buffer, substituting the first '%' with the 1251 /* Append rhs to the buffer, substituting the first '%' with the
1252 * match, but only if the lhs had a '%' as well. */ 1252 * match, but only if the lhs had a '%' as well. */
1253 1253
1254 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1254 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1255 /* TODO: handle errors */ 1255 /* TODO: handle errors */
1256 1256
1257 rhs = rhs_expanded; 1257 rhs = rhs_expanded;
1258 percent = strchr(rhs, '%'); 1258 percent = strchr(rhs, '%');
1259 1259
1260 if (percent != NULL && lhsPercent) { 1260 if (percent != NULL && lhsPercent) {
1261 /* Copy the prefix of the replacement pattern */ 1261 /* Copy the prefix of the replacement pattern */
1262 SepBuf_AddBytesBetween(buf, rhs, percent); 1262 SepBuf_AddBytesBetween(buf, rhs, percent);
1263 rhs = percent + 1; 1263 rhs = percent + 1;
1264 } 1264 }
1265 if (percent != NULL || !lhsPercent) 1265 if (percent != NULL || !lhsPercent)
1266 SepBuf_AddBytes(buf, match, match_len); 1266 SepBuf_AddBytes(buf, match, match_len);
1267 1267
1268 /* Append the suffix of the replacement pattern */ 1268 /* Append the suffix of the replacement pattern */
1269 SepBuf_AddStr(buf, rhs); 1269 SepBuf_AddStr(buf, rhs);
1270 1270
1271 free(rhs_expanded); 1271 free(rhs_expanded);
1272} 1272}
1273#endif 1273#endif
1274 1274
1275 1275
1276struct ModifyWord_SubstArgs { 1276struct ModifyWord_SubstArgs {
1277 const char *lhs; 1277 const char *lhs;
1278 size_t lhsLen; 1278 size_t lhsLen;
1279 const char *rhs; 1279 const char *rhs;
1280 size_t rhsLen; 1280 size_t rhsLen;
1281 VarPatternFlags pflags; 1281 VarPatternFlags pflags;
1282 Boolean matched; 1282 Boolean matched;
1283}; 1283};
1284 1284
1285/* Callback for ModifyWords to implement the :S,from,to, modifier. 1285/* Callback for ModifyWords to implement the :S,from,to, modifier.
1286 * Perform a string substitution on the given word. */ 1286 * Perform a string substitution on the given word. */
1287static void 1287static void
1288ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1288ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1289{ 1289{
1290 size_t wordLen = strlen(word); 1290 size_t wordLen = strlen(word);
1291 struct ModifyWord_SubstArgs *args = data; 1291 struct ModifyWord_SubstArgs *args = data;
1292 const char *match; 1292 const char *match;
1293 1293
1294 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1294 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1295 goto nosub; 1295 goto nosub;
1296 1296
1297 if (args->pflags & VARP_ANCHOR_START) { 1297 if (args->pflags & VARP_ANCHOR_START) {
1298 if (wordLen < args->lhsLen || 1298 if (wordLen < args->lhsLen ||
1299 memcmp(word, args->lhs, args->lhsLen) != 0) 1299 memcmp(word, args->lhs, args->lhsLen) != 0)
1300 goto nosub; 1300 goto nosub;
1301 1301
1302 if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen) 1302 if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
1303 goto nosub; 1303 goto nosub;
1304 1304
1305 /* :S,^prefix,replacement, or :S,^whole$,replacement, */ 1305 /* :S,^prefix,replacement, or :S,^whole$,replacement, */
1306 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1306 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1307 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1307 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1308 args->matched = TRUE; 1308 args->matched = TRUE;
1309 return; 1309 return;
1310 } 1310 }
1311 1311
1312 if (args->pflags & VARP_ANCHOR_END) { 1312 if (args->pflags & VARP_ANCHOR_END) {
1313 const char *start; 1313 const char *start;
1314 1314
1315 if (wordLen < args->lhsLen) 1315 if (wordLen < args->lhsLen)
1316 goto nosub; 1316 goto nosub;
1317 1317
1318 start = word + (wordLen - args->lhsLen); 1318 start = word + (wordLen - args->lhsLen);
1319 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1319 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1320 goto nosub; 1320 goto nosub;
1321 1321
1322 /* :S,suffix$,replacement, */ 1322 /* :S,suffix$,replacement, */
1323 SepBuf_AddBytesBetween(buf, word, start); 1323 SepBuf_AddBytesBetween(buf, word, start);
1324 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1324 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1325 args->matched = TRUE; 1325 args->matched = TRUE;
1326 return; 1326 return;
1327 } 1327 }
1328 1328
1329 if (args->lhs[0] == '\0') 1329 if (args->lhs[0] == '\0')
1330 goto nosub; 1330 goto nosub;
1331 1331
1332 /* unanchored case, may match more than once */ 1332 /* unanchored case, may match more than once */
1333 while ((match = strstr(word, args->lhs)) != NULL) { 1333 while ((match = strstr(word, args->lhs)) != NULL) {
1334 SepBuf_AddBytesBetween(buf, word, match); 1334 SepBuf_AddBytesBetween(buf, word, match);
1335 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1335 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1336 args->matched = TRUE; 1336 args->matched = TRUE;
1337 wordLen -= (size_t)(match - word) + args->lhsLen; 1337 wordLen -= (size_t)(match - word) + args->lhsLen;
1338 word += (size_t)(match - word) + args->lhsLen; 1338 word += (size_t)(match - word) + args->lhsLen;
1339 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1339 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1340 break; 1340 break;
1341 } 1341 }
1342nosub: 1342nosub:
1343 SepBuf_AddBytes(buf, word, wordLen); 1343 SepBuf_AddBytes(buf, word, wordLen);
1344} 1344}
1345 1345
1346#ifndef NO_REGEX 1346#ifndef NO_REGEX
1347/* Print the error caused by a regcomp or regexec call. */ 1347/* Print the error caused by a regcomp or regexec call. */
1348static void 1348static void
1349VarREError(int reerr, regex_t *pat, const char *str) 1349VarREError(int reerr, regex_t *pat, const char *str)
1350{ 1350{
1351 size_t errlen = regerror(reerr, pat, 0, 0); 1351 size_t errlen = regerror(reerr, pat, 0, 0);
1352 char *errbuf = bmake_malloc(errlen); 1352 char *errbuf = bmake_malloc(errlen);
1353 regerror(reerr, pat, errbuf, errlen); 1353 regerror(reerr, pat, errbuf, errlen);
1354 Error("%s: %s", str, errbuf); 1354 Error("%s: %s", str, errbuf);
1355 free(errbuf); 1355 free(errbuf);
1356} 1356}
1357 1357
1358struct ModifyWord_SubstRegexArgs { 1358struct ModifyWord_SubstRegexArgs {
1359 regex_t re; 1359 regex_t re;
1360 size_t nsub; 1360 size_t nsub;
1361 char *replace; 1361 char *replace;
1362 VarPatternFlags pflags; 1362 VarPatternFlags pflags;
1363 Boolean matched; 1363 Boolean matched;
1364}; 1364};
1365 1365
1366/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1366/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1367 * Perform a regex substitution on the given word. */ 1367 * Perform a regex substitution on the given word. */
1368static void 1368static void
1369ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1369ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1370{ 1370{
1371 struct ModifyWord_SubstRegexArgs *args = data; 1371 struct ModifyWord_SubstRegexArgs *args = data;
1372 int xrv; 1372 int xrv;
1373 const char *wp = word; 1373 const char *wp = word;
1374 char *rp; 1374 char *rp;
1375 int flags = 0; 1375 int flags = 0;
1376 regmatch_t m[10]; 1376 regmatch_t m[10];
1377 1377
1378 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1378 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1379 goto nosub; 1379 goto nosub;
1380 1380
1381tryagain: 1381tryagain:
1382 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1382 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1383 1383
1384 switch (xrv) { 1384 switch (xrv) {
1385 case 0: 1385 case 0:
1386 args->matched = TRUE; 1386 args->matched = TRUE;
1387 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1387 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1388 1388
1389 for (rp = args->replace; *rp; rp++) { 1389 for (rp = args->replace; *rp; rp++) {
1390 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1390 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1391 SepBuf_AddBytes(buf, rp + 1, 1); 1391 SepBuf_AddBytes(buf, rp + 1, 1);
1392 rp++; 1392 rp++;
1393 continue; 1393 continue;
1394 } 1394 }
1395 1395
1396 if (*rp == '&') { 1396 if (*rp == '&') {
1397 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1397 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1398 continue; 1398 continue;
1399 } 1399 }
1400 1400
1401 if (*rp != '\\' || !ch_isdigit(rp[1])) { 1401 if (*rp != '\\' || !ch_isdigit(rp[1])) {
1402 SepBuf_AddBytes(buf, rp, 1); 1402 SepBuf_AddBytes(buf, rp, 1);
1403 continue; 1403 continue;
1404 } 1404 }
1405 1405
1406 { /* \0 to \9 backreference */ 1406 { /* \0 to \9 backreference */
1407 size_t n = (size_t)(rp[1] - '0'); 1407 size_t n = (size_t)(rp[1] - '0');
1408 rp++; 1408 rp++;
1409 1409
1410 if (n >= args->nsub) { 1410 if (n >= args->nsub) {
1411 Error("No subexpression \\%zu", n); 1411 Error("No subexpression \\%zu", n);
1412 } else if (m[n].rm_so == -1) { 1412 } else if (m[n].rm_so == -1) {
1413 Error("No match for subexpression \\%zu", n); 1413 Error("No match for subexpression \\%zu", n);
1414 } else { 1414 } else {
1415 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1415 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1416 wp + m[n].rm_eo); 1416 wp + m[n].rm_eo);
1417 } 1417 }
1418 } 1418 }
1419 } 1419 }
1420 1420
1421 wp += m[0].rm_eo; 1421 wp += m[0].rm_eo;
1422 if (args->pflags & VARP_SUB_GLOBAL) { 1422 if (args->pflags & VARP_SUB_GLOBAL) {
1423 flags |= REG_NOTBOL; 1423 flags |= REG_NOTBOL;
1424 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1424 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1425 SepBuf_AddBytes(buf, wp, 1); 1425 SepBuf_AddBytes(buf, wp, 1);
1426 wp++; 1426 wp++;
1427 } 1427 }
1428 if (*wp) 1428 if (*wp)
1429 goto tryagain; 1429 goto tryagain;
1430 } 1430 }
1431 if (*wp) { 1431 if (*wp) {
1432 SepBuf_AddStr(buf, wp); 1432 SepBuf_AddStr(buf, wp);
1433 } 1433 }
1434 break; 1434 break;
1435 default: 1435 default:
1436 VarREError(xrv, &args->re, "Unexpected regex error"); 1436 VarREError(xrv, &args->re, "Unexpected regex error");
1437 /* FALLTHROUGH */ 1437 /* FALLTHROUGH */
1438 case REG_NOMATCH: 1438 case REG_NOMATCH:
1439 nosub: 1439 nosub:
1440 SepBuf_AddStr(buf, wp); 1440 SepBuf_AddStr(buf, wp);
1441 break; 1441 break;
1442 } 1442 }
1443} 1443}
1444#endif 1444#endif
1445 1445
1446 1446
1447struct ModifyWord_LoopArgs { 1447struct ModifyWord_LoopArgs {
1448 GNode *ctx; 1448 GNode *ctx;
1449 char *tvar; /* name of temporary variable */ 1449 char *tvar; /* name of temporary variable */
1450 char *str; /* string to expand */ 1450 char *str; /* string to expand */
1451 VarEvalFlags eflags; 1451 VarEvalFlags eflags;
1452}; 1452};
1453 1453
1454/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1454/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1455static void 1455static void
1456ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1456ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1457{ 1457{
1458 const struct ModifyWord_LoopArgs *args; 1458 const struct ModifyWord_LoopArgs *args;
1459 char *s; 1459 char *s;
1460 1460
1461 if (word[0] == '\0') 1461 if (word[0] == '\0')
1462 return; 1462 return;
1463 1463
1464 args = data; 1464 args = data;
1465 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1465 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1466 (void)Var_Subst(args->str, args->ctx, args->eflags, &s); 1466 (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1467 /* TODO: handle errors */ 1467 /* TODO: handle errors */
1468 1468
1469 VAR_DEBUG4("ModifyWord_Loop: " 1469 VAR_DEBUG4("ModifyWord_Loop: "
1470 "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n", 1470 "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
1471 word, args->tvar, args->str, s); 1471 word, args->tvar, args->str, s);
1472 1472
1473 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n')) 1473 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1474 buf->needSep = FALSE; 1474 buf->needSep = FALSE;
1475 SepBuf_AddStr(buf, s); 1475 SepBuf_AddStr(buf, s);
1476 free(s); 1476 free(s);
1477} 1477}
1478 1478
1479 1479
1480/* The :[first..last] modifier selects words from the expression. 1480/* The :[first..last] modifier selects words from the expression.
1481 * It can also reverse the words. */ 1481 * It can also reverse the words. */
1482static char * 1482static char *
1483VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1483VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1484 int last) 1484 int last)
1485{ 1485{
1486 Words words; 1486 Words words;
1487 int len, start, end, step; 1487 int len, start, end, step;
1488 int i; 1488 int i;
1489 1489
1490 SepBuf buf; 1490 SepBuf buf;
1491 SepBuf_Init(&buf, sep); 1491 SepBuf_Init(&buf, sep);
1492 1492
1493 if (oneBigWord) { 1493 if (oneBigWord) {
1494 /* fake what Str_Words() would do if there were only one word */ 1494 /* fake what Str_Words() would do if there were only one word */
1495 words.len = 1; 1495 words.len = 1;
1496 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1496 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1497 words.freeIt = bmake_strdup(str); 1497 words.freeIt = bmake_strdup(str);
1498 words.words[0] = words.freeIt; 1498 words.words[0] = words.freeIt;
1499 words.words[1] = NULL; 1499 words.words[1] = NULL;
1500 } else { 1500 } else {
1501 words = Str_Words(str, FALSE); 1501 words = Str_Words(str, FALSE);
1502 } 1502 }
1503 1503
1504 /* 1504 /*
1505 * Now sanitize the given range. 1505 * Now sanitize the given range.
1506 * If first or last are negative, convert them to the positive equivalents 1506 * If first or last are negative, convert them to the positive equivalents
1507 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1507 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1508 */ 1508 */
1509 len = (int)words.len; 1509 len = (int)words.len;
1510 if (first < 0) 1510 if (first < 0)
1511 first += len + 1; 1511 first += len + 1;
1512 if (last < 0) 1512 if (last < 0)
1513 last += len + 1; 1513 last += len + 1;
1514 1514
1515 /* 1515 /*
1516 * We avoid scanning more of the list than we need to. 1516 * We avoid scanning more of the list than we need to.
1517 */ 1517 */
1518 if (first > last) { 1518 if (first > last) {
1519 start = (first > len ? len : first) - 1; 1519 start = (first > len ? len : first) - 1;
1520 end = last < 1 ? 0 : last - 1; 1520 end = last < 1 ? 0 : last - 1;
1521 step = -1; 1521 step = -1;
1522 } else { 1522 } else {
1523 start = first < 1 ? 0 : first - 1; 1523 start = first < 1 ? 0 : first - 1;
1524 end = last > len ? len : last; 1524 end = last > len ? len : last;
1525 step = 1; 1525 step = 1;
1526 } 1526 }
1527 1527
1528 for (i = start; (step < 0) == (i >= end); i += step) { 1528 for (i = start; (step < 0) == (i >= end); i += step) {
1529 SepBuf_AddStr(&buf, words.words[i]); 1529 SepBuf_AddStr(&buf, words.words[i]);
1530 SepBuf_Sep(&buf); 1530 SepBuf_Sep(&buf);
1531 } 1531 }
1532 1532
1533 Words_Free(words); 1533 Words_Free(words);
1534 1534
1535 return SepBuf_Destroy(&buf, FALSE); 1535 return SepBuf_Destroy(&buf, FALSE);
1536} 1536}
1537 1537
1538 1538
1539/* Callback for ModifyWords to implement the :tA modifier. 1539/* Callback for ModifyWords to implement the :tA modifier.
1540 * Replace each word with the result of realpath() if successful. */ 1540 * Replace each word with the result of realpath() if successful. */
1541static void 1541static void
1542ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1542ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1543{ 1543{
1544 struct stat st; 1544 struct stat st;
1545 char rbuf[MAXPATHLEN]; 1545 char rbuf[MAXPATHLEN];
1546 1546
1547 const char *rp = cached_realpath(word, rbuf); 1547 const char *rp = cached_realpath(word, rbuf);
1548 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1548 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1549 word = rp; 1549 word = rp;
1550 1550
1551 SepBuf_AddStr(buf, word); 1551 SepBuf_AddStr(buf, word);
1552} 1552}
1553 1553
1554/* Modify each of the words of the passed string using the given function. 1554/* Modify each of the words of the passed string using the given function.
1555 * 1555 *
1556 * Input: 1556 * Input:
1557 * str String whose words should be modified 1557 * str String whose words should be modified
1558 * modifyWord Function that modifies a single word 1558 * modifyWord Function that modifies a single word
1559 * modifyWord_args Custom arguments for modifyWord 1559 * modifyWord_args Custom arguments for modifyWord
1560 * 1560 *
1561 * Results: 1561 * Results:
1562 * A string of all the words modified appropriately. 1562 * A string of all the words modified appropriately.
1563 *----------------------------------------------------------------------- 1563 *-----------------------------------------------------------------------
1564 */ 1564 */
1565static char * 1565static char *
1566ModifyWords(const char *str, 1566ModifyWords(const char *str,
1567 ModifyWordsCallback modifyWord, void *modifyWord_args, 1567 ModifyWordsCallback modifyWord, void *modifyWord_args,
1568 Boolean oneBigWord, char sep) 1568 Boolean oneBigWord, char sep)
1569{ 1569{
1570 SepBuf result; 1570 SepBuf result;
1571 Words words; 1571 Words words;
1572 size_t i; 1572 size_t i;
1573 1573
1574 if (oneBigWord) { 1574 if (oneBigWord) {
1575 SepBuf_Init(&result, sep); 1575 SepBuf_Init(&result, sep);
1576 modifyWord(str, &result, modifyWord_args); 1576 modifyWord(str, &result, modifyWord_args);
1577 return SepBuf_Destroy(&result, FALSE); 1577 return SepBuf_Destroy(&result, FALSE);
1578 } 1578 }
1579 1579
1580 SepBuf_Init(&result, sep); 1580 SepBuf_Init(&result, sep);
1581 1581
1582 words = Str_Words(str, FALSE); 1582 words = Str_Words(str, FALSE);
1583 1583
1584 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1584 VAR_DEBUG2("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1585 1585
1586 for (i = 0; i < words.len; i++) { 1586 for (i = 0; i < words.len; i++) {
1587 modifyWord(words.words[i], &result, modifyWord_args); 1587 modifyWord(words.words[i], &result, modifyWord_args);
1588 if (Buf_Len(&result.buf) > 0) 1588 if (Buf_Len(&result.buf) > 0)
1589 SepBuf_Sep(&result); 1589 SepBuf_Sep(&result);
1590 } 1590 }
1591 1591
1592 Words_Free(words); 1592 Words_Free(words);
1593 1593
1594 return SepBuf_Destroy(&result, FALSE); 1594 return SepBuf_Destroy(&result, FALSE);
1595} 1595}
1596 1596
1597 1597
1598static char * 1598static char *
1599Words_JoinFree(Words words) 1599Words_JoinFree(Words words)
1600{ 1600{
1601 Buffer buf; 1601 Buffer buf;
1602 size_t i; 1602 size_t i;
1603 1603
1604 Buf_Init(&buf, 0); 1604 Buf_Init(&buf, 0);
1605 1605
1606 for (i = 0; i < words.len; i++) { 1606 for (i = 0; i < words.len; i++) {
1607 if (i != 0) 1607 if (i != 0)
1608 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1608 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1609 Buf_AddStr(&buf, words.words[i]); 1609 Buf_AddStr(&buf, words.words[i]);
1610 } 1610 }
1611 1611
1612 Words_Free(words); 1612 Words_Free(words);
1613 1613
1614 return Buf_Destroy(&buf, FALSE); 1614 return Buf_Destroy(&buf, FALSE);
1615} 1615}
1616 1616
1617/* Remove adjacent duplicate words. */ 1617/* Remove adjacent duplicate words. */
1618static char * 1618static char *
1619VarUniq(const char *str) 1619VarUniq(const char *str)
1620{ 1620{
1621 Words words = Str_Words(str, FALSE); 1621 Words words = Str_Words(str, FALSE);
1622 1622
1623 if (words.len > 1) { 1623 if (words.len > 1) {
1624 size_t i, j; 1624 size_t i, j;
1625 for (j = 0, i = 1; i < words.len; i++) 1625 for (j = 0, i = 1; i < words.len; i++)
1626 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i)) 1626 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1627 words.words[j] = words.words[i]; 1627 words.words[j] = words.words[i];
1628 words.len = j + 1; 1628 words.len = j + 1;
1629 } 1629 }
1630 1630
1631 return Words_JoinFree(words); 1631 return Words_JoinFree(words);
1632} 1632}
1633 1633
1634 1634
1635/* Quote shell meta-characters and space characters in the string. 1635/* Quote shell meta-characters and space characters in the string.
1636 * If quoteDollar is set, also quote and double any '$' characters. */ 1636 * If quoteDollar is set, also quote and double any '$' characters. */
1637static char * 1637static char *
1638VarQuote(const char *str, Boolean quoteDollar) 1638VarQuote(const char *str, Boolean quoteDollar)
1639{ 1639{
1640 Buffer buf; 1640 Buffer buf;
1641 Buf_Init(&buf, 0); 1641 Buf_Init(&buf, 0);
1642 1642
1643 for (; *str != '\0'; str++) { 1643 for (; *str != '\0'; str++) {
1644 if (*str == '\n') { 1644 if (*str == '\n') {
1645 const char *newline = Shell_GetNewline(); 1645 const char *newline = Shell_GetNewline();
1646 if (newline == NULL) 1646 if (newline == NULL)
1647 newline = "\\\n"; 1647 newline = "\\\n";
1648 Buf_AddStr(&buf, newline); 1648 Buf_AddStr(&buf, newline);
1649 continue; 1649 continue;
1650 } 1650 }
1651 if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str)) 1651 if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str))
1652 Buf_AddByte(&buf, '\\'); 1652 Buf_AddByte(&buf, '\\');
1653 Buf_AddByte(&buf, *str); 1653 Buf_AddByte(&buf, *str);
1654 if (quoteDollar && *str == '$') 1654 if (quoteDollar && *str == '$')
1655 Buf_AddStr(&buf, "\\$"); 1655 Buf_AddStr(&buf, "\\$");
1656 } 1656 }
1657 1657
1658 return Buf_Destroy(&buf, FALSE); 1658 return Buf_Destroy(&buf, FALSE);
1659} 1659}
1660 1660
1661/* Compute the 32-bit hash of the given string, using the MurmurHash3 1661/* Compute the 32-bit hash of the given string, using the MurmurHash3
1662 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1662 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1663static char * 1663static char *
1664VarHash(const char *str) 1664VarHash(const char *str)
1665{ 1665{
1666 static const char hexdigits[16] = "0123456789abcdef"; 1666 static const char hexdigits[16] = "0123456789abcdef";
1667 const unsigned char *ustr = (const unsigned char *)str; 1667 const unsigned char *ustr = (const unsigned char *)str;
1668 1668
1669 uint32_t h = 0x971e137bU; 1669 uint32_t h = 0x971e137bU;
1670 uint32_t c1 = 0x95543787U; 1670 uint32_t c1 = 0x95543787U;
1671 uint32_t c2 = 0x2ad7eb25U; 1671 uint32_t c2 = 0x2ad7eb25U;
1672 size_t len2 = strlen(str); 1672 size_t len2 = strlen(str);
1673 1673
1674 char *buf; 1674 char *buf;
1675 size_t i; 1675 size_t i;
1676 1676
1677 size_t len; 1677 size_t len;
1678 for (len = len2; len; ) { 1678 for (len = len2; len; ) {
1679 uint32_t k = 0; 1679 uint32_t k = 0;
1680 switch (len) { 1680 switch (len) {
1681 default: 1681 default:
1682 k = ((uint32_t)ustr[3] << 24) | 1682 k = ((uint32_t)ustr[3] << 24) |
1683 ((uint32_t)ustr[2] << 16) | 1683 ((uint32_t)ustr[2] << 16) |
1684 ((uint32_t)ustr[1] << 8) | 1684 ((uint32_t)ustr[1] << 8) |
1685 (uint32_t)ustr[0]; 1685 (uint32_t)ustr[0];
1686 len -= 4; 1686 len -= 4;
1687 ustr += 4; 1687 ustr += 4;
1688 break; 1688 break;
1689 case 3: 1689 case 3:
1690 k |= (uint32_t)ustr[2] << 16; 1690 k |= (uint32_t)ustr[2] << 16;
1691 /* FALLTHROUGH */ 1691 /* FALLTHROUGH */
1692 case 2: 1692 case 2:
1693 k |= (uint32_t)ustr[1] << 8; 1693 k |= (uint32_t)ustr[1] << 8;
1694 /* FALLTHROUGH */ 1694 /* FALLTHROUGH */
1695 case 1: 1695 case 1:
1696 k |= (uint32_t)ustr[0]; 1696 k |= (uint32_t)ustr[0];
1697 len = 0; 1697 len = 0;
1698 } 1698 }
1699 c1 = c1 * 5 + 0x7b7d159cU; 1699 c1 = c1 * 5 + 0x7b7d159cU;
1700 c2 = c2 * 5 + 0x6bce6396U; 1700 c2 = c2 * 5 + 0x6bce6396U;
1701 k *= c1; 1701 k *= c1;
1702 k = (k << 11) ^ (k >> 21); 1702 k = (k << 11) ^ (k >> 21);
1703 k *= c2; 1703 k *= c2;
1704 h = (h << 13) ^ (h >> 19); 1704 h = (h << 13) ^ (h >> 19);
1705 h = h * 5 + 0x52dce729U; 1705 h = h * 5 + 0x52dce729U;
1706 h ^= k; 1706 h ^= k;
1707 } 1707 }
1708 h ^= (uint32_t)len2; 1708 h ^= (uint32_t)len2;
1709 h *= 0x85ebca6b; 1709 h *= 0x85ebca6b;
1710 h ^= h >> 13; 1710 h ^= h >> 13;
1711 h *= 0xc2b2ae35; 1711 h *= 0xc2b2ae35;
1712 h ^= h >> 16; 1712 h ^= h >> 16;
1713 1713
1714 buf = bmake_malloc(9); 1714 buf = bmake_malloc(9);
1715 for (i = 0; i < 8; i++) { 1715 for (i = 0; i < 8; i++) {
1716 buf[i] = hexdigits[h & 0x0f]; 1716 buf[i] = hexdigits[h & 0x0f];
1717 h >>= 4; 1717 h >>= 4;
1718 } 1718 }
1719 buf[8] = '\0'; 1719 buf[8] = '\0';
1720 return buf; 1720 return buf;
1721} 1721}
1722 1722
1723static char * 1723static char *
1724VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1724VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1725{ 1725{
1726 char buf[BUFSIZ]; 1726 char buf[BUFSIZ];
1727 1727
1728 if (!tim) 1728 if (!tim)
1729 time(&tim); 1729 time(&tim);
1730 if (!*fmt) 1730 if (!*fmt)
1731 fmt = "%c"; 1731 fmt = "%c";
1732 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1732 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1733 1733
1734 buf[sizeof(buf) - 1] = '\0'; 1734 buf[sizeof(buf) - 1] = '\0';
1735 return bmake_strdup(buf); 1735 return bmake_strdup(buf);
1736} 1736}
1737 1737
1738/* The ApplyModifier functions all work in the same way. They get the 1738/* The ApplyModifier functions all work in the same way. They get the
1739 * current parsing position (pp) and parse the modifier from there. The 1739 * current parsing position (pp) and parse the modifier from there. The
1740 * modifier typically lasts until the next ':', or a closing '}' or ')' 1740 * modifier typically lasts until the next ':', or a closing '}' or ')'
1741 * (taken from st->endc), or the end of the string (parse error). 1741 * (taken from st->endc), or the end of the string (parse error).
1742 * 1742 *
1743 * The high-level behavior of these functions is: 1743 * The high-level behavior of these functions is:
1744 * 1744 *
1745 * 1. parse the modifier 1745 * 1. parse the modifier
1746 * 2. evaluate the modifier 1746 * 2. evaluate the modifier
1747 * 3. housekeeping 1747 * 3. housekeeping
1748 * 1748 *
1749 * Parsing the modifier 1749 * Parsing the modifier
1750 * 1750 *
1751 * If parsing succeeds, the parsing position *pp is updated to point to the 1751 * If parsing succeeds, the parsing position *pp is updated to point to the
1752 * first character following the modifier, which typically is either ':' or 1752 * first character following the modifier, which typically is either ':' or
1753 * st->endc. 1753 * st->endc.
1754 * 1754 *
1755 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1755 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1756 * modifiers), return AMR_CLEANUP. 1756 * modifiers), return AMR_CLEANUP.
1757 * 1757 *
1758 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1758 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1759 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1759 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1760 * done as long as there have been no side effects from evaluating nested 1760 * done as long as there have been no side effects from evaluating nested
1761 * variables, to avoid evaluating them more than once. In this case, the 1761 * variables, to avoid evaluating them more than once. In this case, the
1762 * parsing position must not be updated. (XXX: Why not? The original parsing 1762 * parsing position must not be updated. (XXX: Why not? The original parsing
1763 * position is well-known in ApplyModifiers.) 1763 * position is well-known in ApplyModifiers.)
1764 * 1764 *
1765 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1765 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1766 * as a fallback, either issue an error message using Error or Parse_Error 1766 * as a fallback, either issue an error message using Error or Parse_Error
1767 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1767 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1768 * message. Both of these return values will stop processing the variable 1768 * message. Both of these return values will stop processing the variable
1769 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1769 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1770 * continues nevertheless after skipping a few bytes, which essentially is 1770 * continues nevertheless after skipping a few bytes, which essentially is
1771 * undefined behavior. Not in the sense of C, but still it's impossible to 1771 * undefined behavior. Not in the sense of C, but still it's impossible to
1772 * predict what happens in the parser.) 1772 * predict what happens in the parser.)
1773 * 1773 *
1774 * Evaluating the modifier 1774 * Evaluating the modifier
1775 * 1775 *
1776 * After parsing, the modifier is evaluated. The side effects from evaluating 1776 * After parsing, the modifier is evaluated. The side effects from evaluating
1777 * nested variable expressions in the modifier text often already happen 1777 * nested variable expressions in the modifier text often already happen
1778 * during parsing though. 1778 * during parsing though.
1779 * 1779 *
1780 * Evaluating the modifier usually takes the current value of the variable 1780 * Evaluating the modifier usually takes the current value of the variable
1781 * expression from st->val, or the variable name from st->v->name and stores 1781 * expression from st->val, or the variable name from st->v->name and stores
1782 * the result in st->newVal. 1782 * the result in st->newVal.
1783 * 1783 *
1784 * If evaluating fails (as of 2020-08-23), an error message is printed using 1784 * If evaluating fails (as of 2020-08-23), an error message is printed using
1785 * Error. This function has no side-effects, it really just prints the error 1785 * Error. This function has no side-effects, it really just prints the error
1786 * message. Processing the expression continues as if everything were ok. 1786 * message. Processing the expression continues as if everything were ok.
1787 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1787 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1788 * Var_Parse, ApplyModifiers and ModifyWords. 1788 * Var_Parse, ApplyModifiers and ModifyWords.
1789 * 1789 *
1790 * Housekeeping 1790 * Housekeeping
1791 * 1791 *
1792 * Some modifiers such as :D and :U turn undefined expressions into defined 1792 * Some modifiers such as :D and :U turn undefined expressions into defined
1793 * expressions (see VEF_UNDEF, VEF_DEF). 1793 * expressions (see VEF_UNDEF, VEF_DEF).
1794 * 1794 *
1795 * Some modifiers need to free some memory. 1795 * Some modifiers need to free some memory.
1796 */ 1796 */
1797 1797
1798typedef enum VarExprFlags { 1798typedef enum VarExprFlags {
1799 /* The variable expression is based on an undefined variable. */ 1799 /* The variable expression is based on an undefined variable. */
1800 VEF_UNDEF = 0x01, 1800 VEF_UNDEF = 0x01,
1801 /* The variable expression started as an undefined expression, but one 1801 /* The variable expression started as an undefined expression, but one
1802 * of the modifiers (such as :D or :U) has turned the expression from 1802 * of the modifiers (such as :D or :U) has turned the expression from
1803 * undefined to defined. */ 1803 * undefined to defined. */
1804 VEF_DEF = 0x02 1804 VEF_DEF = 0x02
1805} VarExprFlags; 1805} VarExprFlags;
1806 1806
1807ENUM_FLAGS_RTTI_2(VarExprFlags, 1807ENUM_FLAGS_RTTI_2(VarExprFlags,
1808 VEF_UNDEF, VEF_DEF); 1808 VEF_UNDEF, VEF_DEF);
1809 1809
1810 1810
1811typedef struct ApplyModifiersState { 1811typedef struct ApplyModifiersState {
1812 const char startc; /* '\0' or '{' or '(' */ 1812 const char startc; /* '\0' or '{' or '(' */
1813 const char endc; /* '\0' or '}' or ')' */ 1813 const char endc; /* '\0' or '}' or ')' */
1814 Var * const v; 1814 Var * const v;
1815 GNode * const ctxt; 1815 GNode * const ctxt;
1816 const VarEvalFlags eflags; 1816 const VarEvalFlags eflags;
1817 1817
1818 char *val; /* The old value of the expression, 1818 char *val; /* The old value of the expression,
1819 * before applying the modifier, never NULL */ 1819 * before applying the modifier, never NULL */
1820 char *newVal; /* The new value of the expression, 1820 char *newVal; /* The new value of the expression,
1821 * after applying the modifier, never NULL */ 1821 * after applying the modifier, never NULL */
1822 char sep; /* Word separator in expansions 1822 char sep; /* Word separator in expansions
1823 * (see the :ts modifier) */ 1823 * (see the :ts modifier) */
1824 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1824 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1825 * the variable value into words, like :S and 1825 * the variable value into words, like :S and
1826 * :C, treat the variable value as a single big 1826 * :C, treat the variable value as a single big
1827 * word, possibly containing spaces. */ 1827 * word, possibly containing spaces. */
1828 VarExprFlags exprFlags; 1828 VarExprFlags exprFlags;
1829} ApplyModifiersState; 1829} ApplyModifiersState;
1830 1830
1831static void 1831static void
1832ApplyModifiersState_Define(ApplyModifiersState *st) 1832ApplyModifiersState_Define(ApplyModifiersState *st)
1833{ 1833{
1834 if (st->exprFlags & VEF_UNDEF) 1834 if (st->exprFlags & VEF_UNDEF)
1835 st->exprFlags |= VEF_DEF; 1835 st->exprFlags |= VEF_DEF;
1836} 1836}
1837 1837
1838typedef enum ApplyModifierResult { 1838typedef enum ApplyModifierResult {
1839 AMR_OK, /* Continue parsing */ 1839 AMR_OK, /* Continue parsing */
1840 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1840 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1841 AMR_BAD, /* Error out with "Bad modifier" message */ 1841 AMR_BAD, /* Error out with "Bad modifier" message */
1842 AMR_CLEANUP /* Error out without error message */ 1842 AMR_CLEANUP /* Error out without error message */
1843} ApplyModifierResult; 1843} ApplyModifierResult;
1844 1844
1845/* Allow backslashes to escape the delimiter, $, and \, but don't touch other 1845/* Allow backslashes to escape the delimiter, $, and \, but don't touch other
1846 * backslashes. */ 1846 * backslashes. */
1847static Boolean 1847static Boolean
1848IsEscapedModifierPart(const char *p, char delim, 1848IsEscapedModifierPart(const char *p, char delim,
1849 struct ModifyWord_SubstArgs *subst) 1849 struct ModifyWord_SubstArgs *subst)
1850{ 1850{
1851 if (p[0] != '\\') 1851 if (p[0] != '\\')
1852 return FALSE; 1852 return FALSE;
1853 if (p[1] == delim || p[1] == '\\' || p[1] == '$') 1853 if (p[1] == delim || p[1] == '\\' || p[1] == '$')
1854 return TRUE; 1854 return TRUE;
1855 return p[1] == '&' && subst != NULL; 1855 return p[1] == '&' && subst != NULL;
1856} 1856}
1857 1857
1858/* 1858/*
1859 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or 1859 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
1860 * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and 1860 * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
1861 * including the next unescaped delimiter. The delimiter, as well as the 1861 * including the next unescaped delimiter. The delimiter, as well as the
1862 * backslash or the dollar, can be escaped with a backslash. 1862 * backslash or the dollar, can be escaped with a backslash.
1863 * 1863 *
1864 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1864 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1865 * was found. On successful return, the parsing position pp points right 1865 * was found. On successful return, the parsing position pp points right
1866 * after the delimiter. The delimiter is not included in the returned 1866 * after the delimiter. The delimiter is not included in the returned
1867 * value though. 1867 * value though.
1868 */ 1868 */
1869static VarParseResult 1869static VarParseResult
1870ParseModifierPart( 1870ParseModifierPart(
1871 const char **pp, /* The parsing position, updated upon return */ 1871 const char **pp, /* The parsing position, updated upon return */
1872 char delim, /* Parsing stops at this delimiter */ 1872 char delim, /* Parsing stops at this delimiter */
1873 VarEvalFlags eflags, /* Flags for evaluating nested variables; 1873 VarEvalFlags eflags, /* Flags for evaluating nested variables;
1874 * if VARE_WANTRES is not set, the text is 1874 * if VARE_WANTRES is not set, the text is
1875 * only parsed */ 1875 * only parsed */
1876 ApplyModifiersState *st, 1876 ApplyModifiersState *st,
1877 char **out_part, 1877 char **out_part,
1878 size_t *out_length, /* Optionally stores the length of the returned 1878 size_t *out_length, /* Optionally stores the length of the returned
1879 * string, just to save another strlen call. */ 1879 * string, just to save another strlen call. */
1880 VarPatternFlags *out_pflags,/* For the first part of the :S modifier, 1880 VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
1881 * sets the VARP_ANCHOR_END flag if the last 1881 * sets the VARP_ANCHOR_END flag if the last
1882 * character of the pattern is a $. */ 1882 * character of the pattern is a $. */
1883 struct ModifyWord_SubstArgs *subst 1883 struct ModifyWord_SubstArgs *subst
1884 /* For the second part of the :S modifier, 1884 /* For the second part of the :S modifier,
1885 * allow ampersands to be escaped and replace 1885 * allow ampersands to be escaped and replace
1886 * unescaped ampersands with subst->lhs. */ 1886 * unescaped ampersands with subst->lhs. */
1887) { 1887) {
1888 Buffer buf; 1888 Buffer buf;
1889 const char *p; 1889 const char *p;
1890 1890
1891 Buf_Init(&buf, 0); 1891 Buf_Init(&buf, 0);
1892 1892
1893 /* 1893 /*
1894 * Skim through until the matching delimiter is found; pick up variable 1894 * Skim through until the matching delimiter is found; pick up variable
1895 * expressions on the way. 1895 * expressions on the way.
1896 */ 1896 */
1897 p = *pp; 1897 p = *pp;
1898 while (*p != '\0' && *p != delim) { 1898 while (*p != '\0' && *p != delim) {
1899 const char *varstart; 1899 const char *varstart;
1900 1900
1901 if (IsEscapedModifierPart(p, delim, subst)) { 1901 if (IsEscapedModifierPart(p, delim, subst)) {
1902 Buf_AddByte(&buf, p[1]); 1902 Buf_AddByte(&buf, p[1]);
1903 p += 2; 1903 p += 2;
1904 continue; 1904 continue;
1905 } 1905 }
1906 1906
1907 if (*p != '$') { /* Unescaped, simple text */ 1907 if (*p != '$') { /* Unescaped, simple text */
1908 if (subst != NULL && *p == '&') 1908 if (subst != NULL && *p == '&')
1909 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen); 1909 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
1910 else 1910 else
1911 Buf_AddByte(&buf, *p); 1911 Buf_AddByte(&buf, *p);
1912 p++; 1912 p++;
1913 continue; 1913 continue;
1914 } 1914 }
1915 1915
1916 if (p[1] == delim) { /* Unescaped $ at end of pattern */ 1916 if (p[1] == delim) { /* Unescaped $ at end of pattern */
1917 if (out_pflags != NULL) 1917 if (out_pflags != NULL)
1918 *out_pflags |= VARP_ANCHOR_END; 1918 *out_pflags |= VARP_ANCHOR_END;
1919 else 1919 else
1920 Buf_AddByte(&buf, *p); 1920 Buf_AddByte(&buf, *p);
1921 p++; 1921 p++;
1922 continue; 1922 continue;
1923 } 1923 }
1924 1924
1925 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */ 1925 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
1926 const char *nested_p = p; 1926 const char *nested_p = p;
1927 const char *nested_val; 1927 const char *nested_val;
1928 void *nested_val_freeIt; 1928 void *nested_val_freeIt;
1929 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN; 1929 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
1930 1930
1931 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags, 1931 (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
1932 &nested_val, &nested_val_freeIt); 1932 &nested_val, &nested_val_freeIt);
1933 /* TODO: handle errors */ 1933 /* TODO: handle errors */
1934 Buf_AddStr(&buf, nested_val); 1934 Buf_AddStr(&buf, nested_val);
1935 free(nested_val_freeIt); 1935 free(nested_val_freeIt);
1936 p += nested_p - p; 1936 p += nested_p - p;
1937 continue; 1937 continue;
1938 } 1938 }
1939 1939
1940 /* XXX: This whole block is very similar to Var_Parse without 1940 /* XXX: This whole block is very similar to Var_Parse without
1941 * VARE_WANTRES. There may be subtle edge cases though that are 1941 * VARE_WANTRES. There may be subtle edge cases though that are
1942 * not yet covered in the unit tests and that are parsed differently, 1942 * not yet covered in the unit tests and that are parsed differently,
1943 * depending on whether they are evaluated or not. 1943 * depending on whether they are evaluated or not.
1944 * 1944 *
1945 * This subtle difference is not documented in the manual page, 1945 * This subtle difference is not documented in the manual page,
1946 * neither is the difference between parsing :D and :M documented. 1946 * neither is the difference between parsing :D and :M documented.
1947 * No code should ever depend on these details, but who knows. */ 1947 * No code should ever depend on these details, but who knows. */
1948 1948
1949 varstart = p; /* Nested variable, only parsed */ 1949 varstart = p; /* Nested variable, only parsed */
1950 if (p[1] == '(' || p[1] == '{') { 1950 if (p[1] == '(' || p[1] == '{') {
1951 /* 1951 /*
1952 * Find the end of this variable reference 1952 * Find the end of this variable reference
1953 * and suck it in without further ado. 1953 * and suck it in without further ado.
1954 * It will be interpreted later. 1954 * It will be interpreted later.
1955 */ 1955 */
1956 char startc = p[1]; 1956 char startc = p[1];
1957 int endc = startc == '(' ? ')' : '}'; 1957 int endc = startc == '(' ? ')' : '}';
1958 int depth = 1; 1958 int depth = 1;
1959 1959
1960 for (p += 2; *p != '\0' && depth > 0; p++) { 1960 for (p += 2; *p != '\0' && depth > 0; p++) {
1961 if (p[-1] != '\\') { 1961 if (p[-1] != '\\') {
1962 if (*p == startc) 1962 if (*p == startc)
1963 depth++; 1963 depth++;
1964 if (*p == endc) 1964 if (*p == endc)
1965 depth--; 1965 depth--;
1966 } 1966 }
1967 } 1967 }
1968 Buf_AddBytesBetween(&buf, varstart, p); 1968 Buf_AddBytesBetween(&buf, varstart, p);
1969 } else { 1969 } else {
1970 Buf_AddByte(&buf, *varstart); 1970 Buf_AddByte(&buf, *varstart);
1971 p++; 1971 p++;
1972 } 1972 }
1973 } 1973 }
1974 1974
1975 if (*p != delim) { 1975 if (*p != delim) {
1976 *pp = p; 1976 *pp = p;
1977 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim); 1977 Error("Unfinished modifier for %s ('%c' missing)", st->v->name, delim);
1978 *out_part = NULL; 1978 *out_part = NULL;
1979 return VPR_PARSE_MSG; 1979 return VPR_PARSE_MSG;
1980 } 1980 }
1981 1981
1982 *pp = ++p; 1982 *pp = ++p;
1983 if (out_length != NULL) 1983 if (out_length != NULL)
1984 *out_length = Buf_Len(&buf); 1984 *out_length = Buf_Len(&buf);
1985 1985
1986 *out_part = Buf_Destroy(&buf, FALSE); 1986 *out_part = Buf_Destroy(&buf, FALSE);
1987 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part); 1987 VAR_DEBUG1("Modifier part: \"%s\"\n", *out_part);
1988 return VPR_OK; 1988 return VPR_OK;
1989} 1989}
1990 1990
1991/* Test whether mod starts with modname, followed by a delimiter. */ 1991/* Test whether mod starts with modname, followed by a delimiter. */
1992static Boolean 1992static Boolean
1993ModMatch(const char *mod, const char *modname, char endc) 1993ModMatch(const char *mod, const char *modname, char endc)
1994{ 1994{
1995 size_t n = strlen(modname); 1995 size_t n = strlen(modname);
1996 return strncmp(mod, modname, n) == 0 && 1996 return strncmp(mod, modname, n) == 0 &&
1997 (mod[n] == endc || mod[n] == ':'); 1997 (mod[n] == endc || mod[n] == ':');
1998} 1998}
1999 1999
2000/* Test whether mod starts with modname, followed by a delimiter or '='. */ 2000/* Test whether mod starts with modname, followed by a delimiter or '='. */
2001static inline Boolean 2001static inline Boolean
2002ModMatchEq(const char *mod, const char *modname, char endc) 2002ModMatchEq(const char *mod, const char *modname, char endc)
2003{ 2003{
2004 size_t n = strlen(modname); 2004 size_t n = strlen(modname);
2005 return strncmp(mod, modname, n) == 0 && 2005 return strncmp(mod, modname, n) == 0 &&
2006 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2006 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2007} 2007}
2008 2008
2009/* :@var@...${var}...@ */ 2009/* :@var@...${var}...@ */
2010static ApplyModifierResult 2010static ApplyModifierResult
2011ApplyModifier_Loop(const char **pp, ApplyModifiersState *st) 2011ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
2012{ 2012{
2013 struct ModifyWord_LoopArgs args; 2013 struct ModifyWord_LoopArgs args;
2014 char prev_sep; 2014 char prev_sep;
2015 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2015 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2016 VarParseResult res; 2016 VarParseResult res;
2017 2017
2018 args.ctx = st->ctxt; 2018 args.ctx = st->ctxt;
2019 2019
2020 (*pp)++; /* Skip the first '@' */ 2020 (*pp)++; /* Skip the first '@' */
2021 res = ParseModifierPart(pp, '@', eflags, st, 2021 res = ParseModifierPart(pp, '@', eflags, st,
2022 &args.tvar, NULL, NULL, NULL); 2022 &args.tvar, NULL, NULL, NULL);
2023 if (res != VPR_OK) 2023 if (res != VPR_OK)
2024 return AMR_CLEANUP; 2024 return AMR_CLEANUP;
2025 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) { 2025 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) {
2026 Parse_Error(PARSE_FATAL, 2026 Parse_Error(PARSE_FATAL,
2027 "In the :@ modifier of \"%s\", the variable name \"%s\" " 2027 "In the :@ modifier of \"%s\", the variable name \"%s\" "
2028 "must not contain a dollar.", 2028 "must not contain a dollar.",
2029 st->v->name, args.tvar); 2029 st->v->name, args.tvar);
2030 return AMR_CLEANUP; 2030 return AMR_CLEANUP;
2031 } 2031 }
2032 2032
2033 res = ParseModifierPart(pp, '@', eflags, st, 2033 res = ParseModifierPart(pp, '@', eflags, st,
2034 &args.str, NULL, NULL, NULL); 2034 &args.str, NULL, NULL, NULL);
2035 if (res != VPR_OK) 2035 if (res != VPR_OK)
2036 return AMR_CLEANUP; 2036 return AMR_CLEANUP;
2037 2037
2038 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2038 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2039 prev_sep = st->sep; 2039 prev_sep = st->sep;
2040 st->sep = ' '; /* XXX: should be st->sep for consistency */ 2040 st->sep = ' '; /* XXX: should be st->sep for consistency */
2041 st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args, 2041 st->newVal = ModifyWords(st->val, ModifyWord_Loop, &args,
2042 st->oneBigWord, st->sep); 2042 st->oneBigWord, st->sep);
2043 st->sep = prev_sep; 2043 st->sep = prev_sep;
2044 Var_Delete(args.tvar, st->ctxt); 2044 Var_Delete(args.tvar, st->ctxt);
2045 free(args.tvar); 2045 free(args.tvar);
2046 free(args.str); 2046 free(args.str);
2047 return AMR_OK; 2047 return AMR_OK;
2048} 2048}
2049 2049
2050/* :Ddefined or :Uundefined */ 2050/* :Ddefined or :Uundefined */
2051static ApplyModifierResult 2051static ApplyModifierResult
2052ApplyModifier_Defined(const char **pp, ApplyModifiersState *st) 2052ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
2053{ 2053{
2054 Buffer buf; 2054 Buffer buf;
2055 const char *p; 2055 const char *p;
2056 2056
2057 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2057 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2058 if (st->eflags & VARE_WANTRES) { 2058 if (st->eflags & VARE_WANTRES) {
2059 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF)) 2059 if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
2060 eflags |= VARE_WANTRES; 2060 eflags |= VARE_WANTRES;
2061 } 2061 }
2062 2062
2063 Buf_Init(&buf, 0); 2063 Buf_Init(&buf, 0);
2064 p = *pp + 1; 2064 p = *pp + 1;
2065 while (*p != st->endc && *p != ':' && *p != '\0') { 2065 while (*p != st->endc && *p != ':' && *p != '\0') {
2066 2066
2067 /* Escaped delimiter or other special character */ 2067 /* Escaped delimiter or other special character */
2068 if (*p == '\\') { 2068 if (*p == '\\') {
2069 char c = p[1]; 2069 char c = p[1];
2070 if (c == st->endc || c == ':' || c == '$' || c == '\\') { 2070 if (c == st->endc || c == ':' || c == '$' || c == '\\') {
2071 Buf_AddByte(&buf, c); 2071 Buf_AddByte(&buf, c);
2072 p += 2; 2072 p += 2;
2073 continue; 2073 continue;
2074 } 2074 }
2075 } 2075 }
2076 2076
2077 /* Nested variable expression */ 2077 /* Nested variable expression */
2078 if (*p == '$') { 2078 if (*p == '$') {
2079 const char *nested_val; 2079 const char *nested_val;
2080 void *nested_val_freeIt; 2080 void *nested_val_freeIt;
2081 2081
2082 (void)Var_Parse(&p, st->ctxt, eflags, 2082 (void)Var_Parse(&p, st->ctxt, eflags,
2083 &nested_val, &nested_val_freeIt); 2083 &nested_val, &nested_val_freeIt);
2084 /* TODO: handle errors */ 2084 /* TODO: handle errors */
2085 Buf_AddStr(&buf, nested_val); 2085 Buf_AddStr(&buf, nested_val);
2086 free(nested_val_freeIt); 2086 free(nested_val_freeIt);
2087 continue; 2087 continue;
2088 } 2088 }
2089 2089
2090 /* Ordinary text */ 2090 /* Ordinary text */
2091 Buf_AddByte(&buf, *p); 2091 Buf_AddByte(&buf, *p);
2092 p++; 2092 p++;
2093 } 2093 }
2094 *pp = p; 2094 *pp = p;
2095 2095
2096 ApplyModifiersState_Define(st); 2096 ApplyModifiersState_Define(st);
2097 2097
2098 if (eflags & VARE_WANTRES) { 2098 if (eflags & VARE_WANTRES) {
2099 st->newVal = Buf_Destroy(&buf, FALSE); 2099 st->newVal = Buf_Destroy(&buf, FALSE);
2100 } else { 2100 } else {
2101 st->newVal = st->val; 2101 st->newVal = st->val;
2102 Buf_Destroy(&buf, TRUE); 2102 Buf_Destroy(&buf, TRUE);
2103 } 2103 }
2104 return AMR_OK; 2104 return AMR_OK;
2105} 2105}
2106 2106
2107/* :L */ 2107/* :L */
2108static ApplyModifierResult 2108static ApplyModifierResult
2109ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) 2109ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2110{ 2110{
2111 ApplyModifiersState_Define(st); 2111 ApplyModifiersState_Define(st);
2112 st->newVal = bmake_strdup(st->v->name); 2112 st->newVal = bmake_strdup(st->v->name);
2113 (*pp)++; 2113 (*pp)++;
2114 return AMR_OK; 2114 return AMR_OK;
2115} 2115}
2116 2116
2117static Boolean TryParseTime(const char **pp, time_t *out_time) 2117static Boolean
 2118TryParseTime(const char **pp, time_t *out_time)
2118{ 2119{
2119 char *end; 2120 char *end;
2120 unsigned long n; 2121 unsigned long n;
2121 2122
2122 if (!ch_isdigit(**pp)) 2123 if (!ch_isdigit(**pp))
2123 return FALSE; 2124 return FALSE;
2124 2125
2125 errno = 0; 2126 errno = 0;
2126 n = strtoul(*pp, &end, 10); 2127 n = strtoul(*pp, &end, 10);
2127 if (n == ULONG_MAX && errno == ERANGE) 2128 if (n == ULONG_MAX && errno == ERANGE)
2128 return FALSE; 2129 return FALSE;
2129 2130
2130 *pp = end; 2131 *pp = end;
2131 *out_time = (time_t)n; /* ignore possible truncation for now */ 2132 *out_time = (time_t)n; /* ignore possible truncation for now */
2132 return TRUE; 2133 return TRUE;
2133} 2134}
2134 2135
2135/* :gmtime */ 2136/* :gmtime */
2136static ApplyModifierResult 2137static ApplyModifierResult
2137ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st) 2138ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
2138{ 2139{
2139 time_t utc; 2140 time_t utc;
2140 2141
2141 const char *mod = *pp; 2142 const char *mod = *pp;
2142 if (!ModMatchEq(mod, "gmtime", st->endc)) 2143 if (!ModMatchEq(mod, "gmtime", st->endc))
2143 return AMR_UNKNOWN; 2144 return AMR_UNKNOWN;
2144 2145
2145 if (mod[6] == '=') { 2146 if (mod[6] == '=') {
2146 const char *arg = mod + 7; 2147 const char *arg = mod + 7;
2147 if (!TryParseTime(&arg, &utc)) { 2148 if (!TryParseTime(&arg, &utc)) {
2148 Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 7); 2149 Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 7);
2149 return AMR_CLEANUP; 2150 return AMR_CLEANUP;
2150 } 2151 }
2151 *pp = arg; 2152 *pp = arg;
2152 } else { 2153 } else {
2153 utc = 0; 2154 utc = 0;
2154 *pp = mod + 6; 2155 *pp = mod + 6;
2155 } 2156 }
2156 st->newVal = VarStrftime(st->val, TRUE, utc); 2157 st->newVal = VarStrftime(st->val, TRUE, utc);
2157 return AMR_OK; 2158 return AMR_OK;
2158} 2159}
2159 2160
2160/* :localtime */ 2161/* :localtime */
2161static ApplyModifierResult 2162static ApplyModifierResult
2162ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) 2163ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
2163{ 2164{
2164 time_t utc; 2165 time_t utc;
2165 2166
2166 const char *mod = *pp; 2167 const char *mod = *pp;
2167 if (!ModMatchEq(mod, "localtime", st->endc)) 2168 if (!ModMatchEq(mod, "localtime", st->endc))
2168 return AMR_UNKNOWN; 2169 return AMR_UNKNOWN;
2169 2170
2170 if (mod[9] == '=') { 2171 if (mod[9] == '=') {
2171 const char *arg = mod + 10; 2172 const char *arg = mod + 10;
2172 if (!TryParseTime(&arg, &utc)) { 2173 if (!TryParseTime(&arg, &utc)) {
2173 Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 10); 2174 Parse_Error(PARSE_FATAL, "Invalid time value: %s\n", mod + 10);
2174 return AMR_CLEANUP; 2175 return AMR_CLEANUP;
2175 } 2176 }
2176 *pp = arg; 2177 *pp = arg;
2177 } else { 2178 } else {
2178 utc = 0; 2179 utc = 0;
2179 *pp = mod + 9; 2180 *pp = mod + 9;
2180 } 2181 }
2181 st->newVal = VarStrftime(st->val, FALSE, utc); 2182 st->newVal = VarStrftime(st->val, FALSE, utc);
2182 return AMR_OK; 2183 return AMR_OK;
2183} 2184}
2184 2185
2185/* :hash */ 2186/* :hash */
2186static ApplyModifierResult 2187static ApplyModifierResult
2187ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) 2188ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
2188{ 2189{
2189 if (!ModMatch(*pp, "hash", st->endc)) 2190 if (!ModMatch(*pp, "hash", st->endc))
2190 return AMR_UNKNOWN; 2191 return AMR_UNKNOWN;
2191 2192
2192 st->newVal = VarHash(st->val); 2193 st->newVal = VarHash(st->val);
2193 *pp += 4; 2194 *pp += 4;
2194 return AMR_OK; 2195 return AMR_OK;
2195} 2196}
2196 2197
2197/* :P */ 2198/* :P */
2198static ApplyModifierResult 2199static ApplyModifierResult
2199ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2200ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2200{ 2201{
2201 GNode *gn; 2202 GNode *gn;
2202 char *path; 2203 char *path;
2203 2204
2204 ApplyModifiersState_Define(st); 2205 ApplyModifiersState_Define(st);
2205 2206
2206 gn = Targ_FindNode(st->v->name); 2207 gn = Targ_FindNode(st->v->name);
2207 if (gn == NULL || gn->type & OP_NOPATH) { 2208 if (gn == NULL || gn->type & OP_NOPATH) {
2208 path = NULL; 2209 path = NULL;
2209 } else if (gn->path != NULL) { 2210 } else if (gn->path != NULL) {
2210 path = bmake_strdup(gn->path); 2211 path = bmake_strdup(gn->path);
2211 } else { 2212 } else {
2212 SearchPath *searchPath = Suff_FindPath(gn); 2213 SearchPath *searchPath = Suff_FindPath(gn);
2213 path = Dir_FindFile(st->v->name, searchPath); 2214 path = Dir_FindFile(st->v->name, searchPath);
2214 } 2215 }
2215 if (path == NULL) 2216 if (path == NULL)
2216 path = bmake_strdup(st->v->name); 2217 path = bmake_strdup(st->v->name);
2217 st->newVal = path; 2218 st->newVal = path;
2218 2219
2219 (*pp)++; 2220 (*pp)++;
2220 return AMR_OK; 2221 return AMR_OK;
2221} 2222}
2222 2223
2223/* :!cmd! */ 2224/* :!cmd! */
2224static ApplyModifierResult 2225static ApplyModifierResult
2225ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) 2226ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2226{ 2227{
2227 char *cmd; 2228 char *cmd;
2228 const char *errfmt; 2229 const char *errfmt;
2229 VarParseResult res; 2230 VarParseResult res;
2230 2231
2231 (*pp)++; 2232 (*pp)++;
2232 res = ParseModifierPart(pp, '!', st->eflags, st, 2233 res = ParseModifierPart(pp, '!', st->eflags, st,
2233 &cmd, NULL, NULL, NULL); 2234 &cmd, NULL, NULL, NULL);
2234 if (res != VPR_OK) 2235 if (res != VPR_OK)
2235 return AMR_CLEANUP; 2236 return AMR_CLEANUP;
2236 2237
2237 errfmt = NULL; 2238 errfmt = NULL;
2238 if (st->eflags & VARE_WANTRES) 2239 if (st->eflags & VARE_WANTRES)
2239 st->newVal = Cmd_Exec(cmd, &errfmt); 2240 st->newVal = Cmd_Exec(cmd, &errfmt);
2240 else 2241 else
2241 st->newVal = emptyString; 2242 st->newVal = emptyString;
2242 free(cmd); 2243 free(cmd);
2243 2244
2244 if (errfmt != NULL) 2245 if (errfmt != NULL)
2245 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2246 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2246 2247
2247 ApplyModifiersState_Define(st); 2248 ApplyModifiersState_Define(st);
2248 return AMR_OK; 2249 return AMR_OK;
2249} 2250}
2250 2251
2251/* The :range modifier generates an integer sequence as long as the words. 2252/* The :range modifier generates an integer sequence as long as the words.
2252 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2253 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2253static ApplyModifierResult 2254static ApplyModifierResult
2254ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2255ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2255{ 2256{
2256 size_t n; 2257 size_t n;
2257 Buffer buf; 2258 Buffer buf;
2258 size_t i; 2259 size_t i;
2259 2260
2260 const char *mod = *pp; 2261 const char *mod = *pp;
2261 if (!ModMatchEq(mod, "range", st->endc)) 2262 if (!ModMatchEq(mod, "range", st->endc))
2262 return AMR_UNKNOWN; 2263 return AMR_UNKNOWN;
2263 2264
2264 if (mod[5] == '=') { 2265 if (mod[5] == '=') {
2265 char *ep; 2266 char *ep;
2266 n = (size_t)strtoul(mod + 6, &ep, 10); 2267 n = (size_t)strtoul(mod + 6, &ep, 10);
2267 *pp = ep; 2268 *pp = ep;
2268 } else { 2269 } else {
2269 n = 0; 2270 n = 0;
2270 *pp = mod + 5; 2271 *pp = mod + 5;
2271 } 2272 }
2272 2273
2273 if (n == 0) { 2274 if (n == 0) {
2274 Words words = Str_Words(st->val, FALSE); 2275 Words words = Str_Words(st->val, FALSE);
2275 n = words.len; 2276 n = words.len;
2276 Words_Free(words); 2277 Words_Free(words);
2277 } 2278 }
2278 2279
2279 Buf_Init(&buf, 0); 2280 Buf_Init(&buf, 0);
2280 2281
2281 for (i = 0; i < n; i++) { 2282 for (i = 0; i < n; i++) {
2282 if (i != 0) 2283 if (i != 0)
2283 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2284 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2284 Buf_AddInt(&buf, 1 + (int)i); 2285 Buf_AddInt(&buf, 1 + (int)i);
2285 } 2286 }
2286 2287
2287 st->newVal = Buf_Destroy(&buf, FALSE); 2288 st->newVal = Buf_Destroy(&buf, FALSE);
2288 return AMR_OK; 2289 return AMR_OK;
2289} 2290}
2290 2291
2291/* :Mpattern or :Npattern */ 2292/* :Mpattern or :Npattern */
2292static ApplyModifierResult 2293static ApplyModifierResult
2293ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2294ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2294{ 2295{
2295 const char *mod = *pp; 2296 const char *mod = *pp;
2296 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2297 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2297 Boolean needSubst = FALSE; 2298 Boolean needSubst = FALSE;
2298 const char *endpat; 2299 const char *endpat;
2299 char *pattern; 2300 char *pattern;
2300 ModifyWordsCallback callback; 2301 ModifyWordsCallback callback;
2301 2302
2302 /* 2303 /*
2303 * In the loop below, ignore ':' unless we are at (or back to) the 2304 * In the loop below, ignore ':' unless we are at (or back to) the
2304 * original brace level. 2305 * original brace level.
2305 * XXX This will likely not work right if $() and ${} are intermixed. 2306 * XXX This will likely not work right if $() and ${} are intermixed.
2306 */ 2307 */
2307 int nest = 0; 2308 int nest = 0;
2308 const char *p; 2309 const char *p;
2309 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2310 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2310 if (*p == '\\' && 2311 if (*p == '\\' &&
2311 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2312 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2312 if (!needSubst) 2313 if (!needSubst)
2313 copy = TRUE; 2314 copy = TRUE;
2314 p++; 2315 p++;
2315 continue; 2316 continue;
2316 } 2317 }
2317 if (*p == '$') 2318 if (*p == '$')
2318 needSubst = TRUE; 2319 needSubst = TRUE;
2319 if (*p == '(' || *p == '{') 2320 if (*p == '(' || *p == '{')
2320 nest++; 2321 nest++;
2321 if (*p == ')' || *p == '}') { 2322 if (*p == ')' || *p == '}') {
2322 nest--; 2323 nest--;
2323 if (nest < 0) 2324 if (nest < 0)
2324 break; 2325 break;
2325 } 2326 }
2326 } 2327 }
2327 *pp = p; 2328 *pp = p;
2328 endpat = p; 2329 endpat = p;
2329 2330
2330 if (copy) { 2331 if (copy) {
2331 char *dst; 2332 char *dst;
2332 const char *src; 2333 const char *src;
2333 2334
2334 /* Compress the \:'s out of the pattern. */ 2335 /* Compress the \:'s out of the pattern. */
2335 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2336 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2336 dst = pattern; 2337 dst = pattern;
2337 src = mod + 1; 2338 src = mod + 1;
2338 for (; src < endpat; src++, dst++) { 2339 for (; src < endpat; src++, dst++) {
2339 if (src[0] == '\\' && src + 1 < endpat && 2340 if (src[0] == '\\' && src + 1 < endpat &&
2340 /* XXX: st->startc is missing here; see above */ 2341 /* XXX: st->startc is missing here; see above */
2341 (src[1] == ':' || src[1] == st->endc)) 2342 (src[1] == ':' || src[1] == st->endc))
2342 src++; 2343 src++;
2343 *dst = *src; 2344 *dst = *src;
2344 } 2345 }
2345 *dst = '\0'; 2346 *dst = '\0';
2346 endpat = dst; 2347 endpat = dst;
2347 } else { 2348 } else {
2348 pattern = bmake_strsedup(mod + 1, endpat); 2349 pattern = bmake_strsedup(mod + 1, endpat);
2349 } 2350 }
2350 2351
2351 if (needSubst) { 2352 if (needSubst) {
2352 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2353 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2353 char *old_pattern = pattern; 2354 char *old_pattern = pattern;
2354 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern); 2355 (void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2355 /* TODO: handle errors */ 2356 /* TODO: handle errors */
2356 free(old_pattern); 2357 free(old_pattern);
2357 } 2358 }
2358 2359
2359 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2360 VAR_DEBUG3("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2360 2361
2361 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2362 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2362 st->newVal = ModifyWords(st->val, callback, pattern, 2363 st->newVal = ModifyWords(st->val, callback, pattern,
2363 st->oneBigWord, st->sep); 2364 st->oneBigWord, st->sep);
2364 free(pattern); 2365 free(pattern);
2365 return AMR_OK; 2366 return AMR_OK;
2366} 2367}
2367 2368
2368/* :S,from,to, */ 2369/* :S,from,to, */
2369static ApplyModifierResult 2370static ApplyModifierResult
2370ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2371ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2371{ 2372{
2372 struct ModifyWord_SubstArgs args; 2373 struct ModifyWord_SubstArgs args;
2373 char *lhs, *rhs; 2374 char *lhs, *rhs;
2374 Boolean oneBigWord; 2375 Boolean oneBigWord;
2375 VarParseResult res; 2376 VarParseResult res;
2376 2377
2377 char delim = (*pp)[1]; 2378 char delim = (*pp)[1];
2378 if (delim == '\0') { 2379 if (delim == '\0') {
2379 Error("Missing delimiter for :S modifier"); 2380 Error("Missing delimiter for :S modifier");
2380 (*pp)++; 2381 (*pp)++;
2381 return AMR_CLEANUP; 2382 return AMR_CLEANUP;
2382 } 2383 }
2383 2384
2384 *pp += 2; 2385 *pp += 2;
2385 2386
2386 args.pflags = 0; 2387 args.pflags = 0;
2387 args.matched = FALSE; 2388 args.matched = FALSE;
2388 2389
2389 /* 2390 /*
2390 * If pattern begins with '^', it is anchored to the 2391 * If pattern begins with '^', it is anchored to the
2391 * start of the word -- skip over it and flag pattern. 2392 * start of the word -- skip over it and flag pattern.
2392 */ 2393 */
2393 if (**pp == '^') { 2394 if (**pp == '^') {
2394 args.pflags |= VARP_ANCHOR_START; 2395 args.pflags |= VARP_ANCHOR_START;
2395 (*pp)++; 2396 (*pp)++;
2396 } 2397 }
2397 2398
2398 res = ParseModifierPart(pp, delim, st->eflags, st, 2399 res = ParseModifierPart(pp, delim, st->eflags, st,
2399 &lhs, &args.lhsLen, &args.pflags, NULL); 2400 &lhs, &args.lhsLen, &args.pflags, NULL);
2400 if (res != VPR_OK) 2401 if (res != VPR_OK)
2401 return AMR_CLEANUP; 2402 return AMR_CLEANUP;
2402 args.lhs = lhs; 2403 args.lhs = lhs;
2403 2404
2404 res = ParseModifierPart(pp, delim, st->eflags, st, 2405 res = ParseModifierPart(pp, delim, st->eflags, st,
2405 &rhs, &args.rhsLen, NULL, &args); 2406 &rhs, &args.rhsLen, NULL, &args);
2406 if (res != VPR_OK) 2407 if (res != VPR_OK)
2407 return AMR_CLEANUP; 2408 return AMR_CLEANUP;
2408 args.rhs = rhs; 2409 args.rhs = rhs;
2409 2410
2410 oneBigWord = st->oneBigWord; 2411 oneBigWord = st->oneBigWord;
2411 for (;; (*pp)++) { 2412 for (;; (*pp)++) {
2412 switch (**pp) { 2413 switch (**pp) {
2413 case 'g': 2414 case 'g':
2414 args.pflags |= VARP_SUB_GLOBAL; 2415 args.pflags |= VARP_SUB_GLOBAL;
2415 continue; 2416 continue;
2416 case '1': 2417 case '1':
2417 args.pflags |= VARP_SUB_ONE; 2418 args.pflags |= VARP_SUB_ONE;
2418 continue; 2419 continue;
2419 case 'W': 2420 case 'W':
2420 oneBigWord = TRUE; 2421 oneBigWord = TRUE;
2421 continue; 2422 continue;
2422 } 2423 }
2423 break; 2424 break;
2424 } 2425 }
2425 2426
2426 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args, 2427 st->newVal = ModifyWords(st->val, ModifyWord_Subst, &args,
2427 oneBigWord, st->sep); 2428 oneBigWord, st->sep);
2428 2429
2429 free(lhs); 2430 free(lhs);
2430 free(rhs); 2431 free(rhs);
2431 return AMR_OK; 2432 return AMR_OK;
2432} 2433}
2433 2434
2434#ifndef NO_REGEX 2435#ifndef NO_REGEX
2435 2436
2436/* :C,from,to, */ 2437/* :C,from,to, */
2437static ApplyModifierResult 2438static ApplyModifierResult
2438ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2439ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2439{ 2440{
2440 char *re; 2441 char *re;
2441 struct ModifyWord_SubstRegexArgs args; 2442 struct ModifyWord_SubstRegexArgs args;
2442 Boolean oneBigWord; 2443 Boolean oneBigWord;
2443 int error; 2444 int error;
2444 VarParseResult res; 2445 VarParseResult res;
2445 2446
2446 char delim = (*pp)[1]; 2447 char delim = (*pp)[1];
2447 if (delim == '\0') { 2448 if (delim == '\0') {
2448 Error("Missing delimiter for :C modifier"); 2449 Error("Missing delimiter for :C modifier");
2449 (*pp)++; 2450 (*pp)++;
2450 return AMR_CLEANUP; 2451 return AMR_CLEANUP;
2451 } 2452 }
2452 2453
2453 *pp += 2; 2454 *pp += 2;
2454 2455
2455 res = ParseModifierPart(pp, delim, st->eflags, st, 2456 res = ParseModifierPart(pp, delim, st->eflags, st,
2456 &re, NULL, NULL, NULL); 2457 &re, NULL, NULL, NULL);
2457 if (res != VPR_OK) 2458 if (res != VPR_OK)
2458 return AMR_CLEANUP; 2459 return AMR_CLEANUP;
2459 2460
2460 res = ParseModifierPart(pp, delim, st->eflags, st, 2461 res = ParseModifierPart(pp, delim, st->eflags, st,
2461 &args.replace, NULL, NULL, NULL); 2462 &args.replace, NULL, NULL, NULL);
2462 if (args.replace == NULL) { 2463 if (args.replace == NULL) {
2463 free(re); 2464 free(re);
2464 return AMR_CLEANUP; 2465 return AMR_CLEANUP;
2465 } 2466 }
2466 2467
2467 args.pflags = 0; 2468 args.pflags = 0;
2468 args.matched = FALSE; 2469 args.matched = FALSE;
2469 oneBigWord = st->oneBigWord; 2470 oneBigWord = st->oneBigWord;
2470 for (;; (*pp)++) { 2471 for (;; (*pp)++) {
2471 switch (**pp) { 2472 switch (**pp) {
2472 case 'g': 2473 case 'g':
2473 args.pflags |= VARP_SUB_GLOBAL; 2474 args.pflags |= VARP_SUB_GLOBAL;
2474 continue; 2475 continue;
2475 case '1': 2476 case '1':
2476 args.pflags |= VARP_SUB_ONE; 2477 args.pflags |= VARP_SUB_ONE;
2477 continue; 2478 continue;
2478 case 'W': 2479 case 'W':
2479 oneBigWord = TRUE; 2480 oneBigWord = TRUE;
2480 continue; 2481 continue;
2481 } 2482 }
2482 break; 2483 break;
2483 } 2484 }
2484 2485
2485 error = regcomp(&args.re, re, REG_EXTENDED); 2486 error = regcomp(&args.re, re, REG_EXTENDED);
2486 free(re); 2487 free(re);
2487 if (error) { 2488 if (error) {
2488 VarREError(error, &args.re, "Regex compilation error"); 2489 VarREError(error, &args.re, "Regex compilation error");
2489 free(args.replace); 2490 free(args.replace);
2490 return AMR_CLEANUP; 2491 return AMR_CLEANUP;
2491 } 2492 }
2492 2493
2493 args.nsub = args.re.re_nsub + 1; 2494 args.nsub = args.re.re_nsub + 1;
2494 if (args.nsub > 10) 2495 if (args.nsub > 10)
2495 args.nsub = 10; 2496 args.nsub = 10;
2496 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args, 2497 st->newVal = ModifyWords(st->val, ModifyWord_SubstRegex, &args,
2497 oneBigWord, st->sep); 2498 oneBigWord, st->sep);
2498 regfree(&args.re); 2499 regfree(&args.re);
2499 free(args.replace); 2500 free(args.replace);
2500 return AMR_OK; 2501 return AMR_OK;
2501} 2502}
2502#endif 2503#endif
2503 2504
2504/* :Q, :q */ 2505/* :Q, :q */
2505static ApplyModifierResult 2506static ApplyModifierResult
2506ApplyModifier_Quote(const char **pp, ApplyModifiersState *st) 2507ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
2507{ 2508{
2508 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2509 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2509 st->newVal = VarQuote(st->val, **pp == 'q'); 2510 st->newVal = VarQuote(st->val, **pp == 'q');
2510 (*pp)++; 2511 (*pp)++;
2511 return AMR_OK; 2512 return AMR_OK;
2512 } else 2513 } else
2513 return AMR_UNKNOWN; 2514 return AMR_UNKNOWN;
2514} 2515}
2515 2516
2516static void 2517static void
2517ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2518ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2518{ 2519{
2519 SepBuf_AddStr(buf, word); 2520 SepBuf_AddStr(buf, word);
2520} 2521}
2521 2522
2522/* :ts<separator> */ 2523/* :ts<separator> */
2523static ApplyModifierResult 2524static ApplyModifierResult
2524ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2525ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2525{ 2526{
2526 const char *sep = *pp + 2; 2527 const char *sep = *pp + 2;
2527 2528
2528 /* ":ts<any><endc>" or ":ts<any>:" */ 2529 /* ":ts<any><endc>" or ":ts<any>:" */
2529 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2530 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2530 st->sep = sep[0]; 2531 st->sep = sep[0];
2531 *pp = sep + 1; 2532 *pp = sep + 1;
2532 goto ok; 2533 goto ok;
2533 } 2534 }
2534 2535
2535 /* ":ts<endc>" or ":ts:" */ 2536 /* ":ts<endc>" or ":ts:" */
2536 if (sep[0] == st->endc || sep[0] == ':') { 2537 if (sep[0] == st->endc || sep[0] == ':') {
2537 st->sep = '\0'; /* no separator */ 2538 st->sep = '\0'; /* no separator */
2538 *pp = sep; 2539 *pp = sep;
2539 goto ok; 2540 goto ok;
2540 } 2541 }
2541 2542
2542 /* ":ts<unrecognised><unrecognised>". */ 2543 /* ":ts<unrecognised><unrecognised>". */
2543 if (sep[0] != '\\') { 2544 if (sep[0] != '\\') {
2544 (*pp)++; /* just for backwards compatibility */ 2545 (*pp)++; /* just for backwards compatibility */
2545 return AMR_BAD; 2546 return AMR_BAD;
2546 } 2547 }
2547 2548
2548 /* ":ts\n" */ 2549 /* ":ts\n" */
2549 if (sep[1] == 'n') { 2550 if (sep[1] == 'n') {
2550 st->sep = '\n'; 2551 st->sep = '\n';
2551 *pp = sep + 2; 2552 *pp = sep + 2;
2552 goto ok; 2553 goto ok;
2553 } 2554 }
2554 2555
2555 /* ":ts\t" */ 2556 /* ":ts\t" */
2556 if (sep[1] == 't') { 2557 if (sep[1] == 't') {
2557 st->sep = '\t'; 2558 st->sep = '\t';
2558 *pp = sep + 2; 2559 *pp = sep + 2;
2559 goto ok; 2560 goto ok;
2560 } 2561 }
2561 2562
2562 /* ":ts\x40" or ":ts\100" */ 2563 /* ":ts\x40" or ":ts\100" */
2563 { 2564 {
2564 const char *numStart = sep + 1; 2565 const char *numStart = sep + 1;
2565 int base = 8; /* assume octal */ 2566 int base = 8; /* assume octal */
2566 char *end; 2567 char *end;
2567 2568
2568 if (sep[1] == 'x') { 2569 if (sep[1] == 'x') {
2569 base = 16; 2570 base = 16;
2570 numStart++; 2571 numStart++;
2571 } else if (!ch_isdigit(sep[1])) { 2572 } else if (!ch_isdigit(sep[1])) {
2572 (*pp)++; /* just for backwards compatibility */ 2573 (*pp)++; /* just for backwards compatibility */
2573 return AMR_BAD; /* ":ts<backslash><unrecognised>". */ 2574 return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2574 } 2575 }
2575 2576
2576 st->sep = (char)strtoul(numStart, &end, base); 2577 st->sep = (char)strtoul(numStart, &end, base);
2577 if (*end != ':' && *end != st->endc) { 2578 if (*end != ':' && *end != st->endc) {
2578 (*pp)++; /* just for backwards compatibility */ 2579 (*pp)++; /* just for backwards compatibility */
2579 return AMR_BAD; 2580 return AMR_BAD;
2580 } 2581 }
2581 *pp = end; 2582 *pp = end;
2582 } 2583 }
2583 2584
2584ok: 2585ok:
2585 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL, 2586 st->newVal = ModifyWords(st->val, ModifyWord_Copy, NULL,
2586 st->oneBigWord, st->sep); 2587 st->oneBigWord, st->sep);
2587 return AMR_OK; 2588 return AMR_OK;
2588} 2589}
2589 2590
2590/* :tA, :tu, :tl, :ts<separator>, etc. */ 2591/* :tA, :tu, :tl, :ts<separator>, etc. */
2591static ApplyModifierResult 2592static ApplyModifierResult
2592ApplyModifier_To(const char **pp, ApplyModifiersState *st) 2593ApplyModifier_To(const char **pp, ApplyModifiersState *st)
2593{ 2594{
2594 const char *mod = *pp; 2595 const char *mod = *pp;
2595 assert(mod[0] == 't'); 2596 assert(mod[0] == 't');
2596 2597
2597 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { 2598 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2598 *pp = mod + 1; 2599 *pp = mod + 1;
2599 return AMR_BAD; /* Found ":t<endc>" or ":t:". */ 2600 return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2600 } 2601 }
2601 2602
2602 if (mod[1] == 's') 2603 if (mod[1] == 's')
2603 return ApplyModifier_ToSep(pp, st); 2604 return ApplyModifier_ToSep(pp, st);
2604 2605
2605 if (mod[2] != st->endc && mod[2] != ':') { 2606 if (mod[2] != st->endc && mod[2] != ':') {
2606 *pp = mod + 1; 2607 *pp = mod + 1;
2607 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ 2608 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2608 } 2609 }
2609 2610
2610 /* Check for two-character options: ":tu", ":tl" */ 2611 /* Check for two-character options: ":tu", ":tl" */
2611 if (mod[1] == 'A') { /* absolute path */ 2612 if (mod[1] == 'A') { /* absolute path */
2612 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL, 2613 st->newVal = ModifyWords(st->val, ModifyWord_Realpath, NULL,
2613 st->oneBigWord, st->sep); 2614 st->oneBigWord, st->sep);
2614 *pp = mod + 2; 2615 *pp = mod + 2;
2615 return AMR_OK; 2616 return AMR_OK;
2616 } 2617 }
2617 2618
2618 if (mod[1] == 'u') { /* :tu */ 2619 if (mod[1] == 'u') { /* :tu */
2619 size_t i; 2620 size_t i;
2620 size_t len = strlen(st->val); 2621 size_t len = strlen(st->val);
2621 st->newVal = bmake_malloc(len + 1); 2622 st->newVal = bmake_malloc(len + 1);
2622 for (i = 0; i < len + 1; i++) 2623 for (i = 0; i < len + 1; i++)
2623 st->newVal[i] = ch_toupper(st->val[i]); 2624 st->newVal[i] = ch_toupper(st->val[i]);
2624 *pp = mod + 2; 2625 *pp = mod + 2;
2625 return AMR_OK; 2626 return AMR_OK;
2626 } 2627 }
2627 2628
2628 if (mod[1] == 'l') { /* :tl */ 2629 if (mod[1] == 'l') { /* :tl */
2629 size_t i; 2630 size_t i;
2630 size_t len = strlen(st->val); 2631 size_t len = strlen(st->val);
2631 st->newVal = bmake_malloc(len + 1); 2632 st->newVal = bmake_malloc(len + 1);
2632 for (i = 0; i < len + 1; i++) 2633 for (i = 0; i < len + 1; i++)
2633 st->newVal[i] = ch_tolower(st->val[i]); 2634 st->newVal[i] = ch_tolower(st->val[i]);
2634 *pp = mod + 2; 2635 *pp = mod + 2;
2635 return AMR_OK; 2636 return AMR_OK;
2636 } 2637 }
2637 2638
2638 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ 2639 if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2639 st->oneBigWord = mod[1] == 'W'; 2640 st->oneBigWord = mod[1] == 'W';
2640 st->newVal = st->val; 2641 st->newVal = st->val;
2641 *pp = mod + 2; 2642 *pp = mod + 2;
2642 return AMR_OK; 2643 return AMR_OK;
2643 } 2644 }
2644 2645
2645 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2646 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2646 *pp = mod + 1; 2647 *pp = mod + 1;
2647 return AMR_BAD; 2648 return AMR_BAD;
2648} 2649}
2649 2650
2650/* :[#], :[1], etc. */ 2651/* :[#], :[1], etc. */
2651static ApplyModifierResult 2652static ApplyModifierResult
2652ApplyModifier_Words(const char **pp, ApplyModifiersState *st) 2653ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
2653{ 2654{
2654 char *estr; 2655 char *estr;
2655 char *ep; 2656 char *ep;
2656 int first, last; 2657 int first, last;
2657 VarParseResult res; 2658 VarParseResult res;
2658 2659
2659 (*pp)++; /* skip the '[' */ 2660 (*pp)++; /* skip the '[' */
2660 res = ParseModifierPart(pp, ']', st->eflags, st, 2661 res = ParseModifierPart(pp, ']', st->eflags, st,
2661 &estr, NULL, NULL, NULL); 2662 &estr, NULL, NULL, NULL);
2662 if (res != VPR_OK) 2663 if (res != VPR_OK)
2663 return AMR_CLEANUP; 2664 return AMR_CLEANUP;
2664 2665
2665 /* now *pp points just after the closing ']' */ 2666 /* now *pp points just after the closing ']' */
2666 if (**pp != ':' && **pp != st->endc) 2667 if (**pp != ':' && **pp != st->endc)
2667 goto bad_modifier; /* Found junk after ']' */ 2668 goto bad_modifier; /* Found junk after ']' */
2668 2669
2669 if (estr[0] == '\0') 2670 if (estr[0] == '\0')
2670 goto bad_modifier; /* empty square brackets in ":[]". */ 2671 goto bad_modifier; /* empty square brackets in ":[]". */
2671 2672
2672 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2673 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2673 if (st->oneBigWord) { 2674 if (st->oneBigWord) {
2674 st->newVal = bmake_strdup("1"); 2675 st->newVal = bmake_strdup("1");
2675 } else { 2676 } else {
2676 Buffer buf; 2677 Buffer buf;
2677 2678
2678 Words words = Str_Words(st->val, FALSE); 2679 Words words = Str_Words(st->val, FALSE);
2679 size_t ac = words.len; 2680 size_t ac = words.len;
2680 Words_Free(words); 2681 Words_Free(words);
2681 2682
2682 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */ 2683 Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */
2683 Buf_AddInt(&buf, (int)ac); 2684 Buf_AddInt(&buf, (int)ac);
2684 st->newVal = Buf_Destroy(&buf, FALSE); 2685 st->newVal = Buf_Destroy(&buf, FALSE);
2685 } 2686 }
2686 goto ok; 2687 goto ok;
2687 } 2688 }
2688 2689
2689 if (estr[0] == '*' && estr[1] == '\0') { 2690 if (estr[0] == '*' && estr[1] == '\0') {
2690 /* Found ":[*]" */ 2691 /* Found ":[*]" */
2691 st->oneBigWord = TRUE; 2692 st->oneBigWord = TRUE;
2692 st->newVal = st->val; 2693 st->newVal = st->val;
2693 goto ok; 2694 goto ok;
2694 } 2695 }
2695 2696
2696 if (estr[0] == '@' && estr[1] == '\0') { 2697 if (estr[0] == '@' && estr[1] == '\0') {
2697 /* Found ":[@]" */ 2698 /* Found ":[@]" */
2698 st->oneBigWord = FALSE; 2699 st->oneBigWord = FALSE;
2699 st->newVal = st->val; 2700 st->newVal = st->val;
2700 goto ok; 2701 goto ok;
2701 } 2702 }
2702 2703
2703 /* 2704 /*
2704 * We expect estr to contain a single integer for :[N], or two integers 2705 * We expect estr to contain a single integer for :[N], or two integers
2705 * separated by ".." for :[start..end]. 2706 * separated by ".." for :[start..end].
2706 */ 2707 */
2707 first = (int)strtol(estr, &ep, 0); 2708 first = (int)strtol(estr, &ep, 0);
2708 if (ep == estr) /* Found junk instead of a number */ 2709 if (ep == estr) /* Found junk instead of a number */
2709 goto bad_modifier; 2710 goto bad_modifier;
2710 2711
2711 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2712 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2712 last = first; 2713 last = first;
2713 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2714 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2714 /* Expecting another integer after ".." */ 2715 /* Expecting another integer after ".." */
2715 ep += 2; 2716 ep += 2;
2716 last = (int)strtol(ep, &ep, 0); 2717 last = (int)strtol(ep, &ep, 0);
2717 if (ep[0] != '\0') /* Found junk after ".." */ 2718 if (ep[0] != '\0') /* Found junk after ".." */
2718 goto bad_modifier; 2719 goto bad_modifier;
2719 } else 2720 } else
2720 goto bad_modifier; /* Found junk instead of ".." */ 2721 goto bad_modifier; /* Found junk instead of ".." */
2721 2722
2722 /* 2723 /*
2723 * Now seldata is properly filled in, but we still have to check for 0 as 2724 * Now first and last are properly filled in, but we still have to check
2724 * a special case. 2725 * for 0 as a special case.
2725 */ 2726 */
2726 if (first == 0 && last == 0) { 2727 if (first == 0 && last == 0) {
2727 /* ":[0]" or perhaps ":[0..0]" */ 2728 /* ":[0]" or perhaps ":[0..0]" */
2728 st->oneBigWord = TRUE; 2729 st->oneBigWord = TRUE;
2729 st->newVal = st->val; 2730 st->newVal = st->val;
2730 goto ok; 2731 goto ok;
2731 } 2732 }
2732 2733
2733 /* ":[0..N]" or ":[N..0]" */ 2734 /* ":[0..N]" or ":[N..0]" */
2734 if (first == 0 || last == 0) 2735 if (first == 0 || last == 0)
2735 goto bad_modifier; 2736 goto bad_modifier;
2736 2737
2737 /* Normal case: select the words described by seldata. */ 2738 /* Normal case: select the words described by first and last. */
2738 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last); 2739 st->newVal = VarSelectWords(st->sep, st->oneBigWord, st->val, first, last);
2739 2740
2740ok: 2741ok:
2741 free(estr); 2742 free(estr);
2742 return AMR_OK; 2743 return AMR_OK;
2743 2744
2744bad_modifier: 2745bad_modifier:
2745 free(estr); 2746 free(estr);
2746 return AMR_BAD; 2747 return AMR_BAD;
2747} 2748}
2748 2749
2749static int 2750static int
2750str_cmp_asc(const void *a, const void *b) 2751str_cmp_asc(const void *a, const void *b)
2751{ 2752{
2752 return strcmp(*(const char * const *)a, *(const char * const *)b); 2753 return strcmp(*(const char * const *)a, *(const char * const *)b);
2753} 2754}
2754 2755
2755static int 2756static int
2756str_cmp_desc(const void *a, const void *b) 2757str_cmp_desc(const void *a, const void *b)
2757{ 2758{
2758 return strcmp(*(const char * const *)b, *(const char * const *)a); 2759 return strcmp(*(const char * const *)b, *(const char * const *)a);
2759} 2760}
2760 2761
2761/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ 2762/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
2762static ApplyModifierResult 2763static ApplyModifierResult
2763ApplyModifier_Order(const char **pp, ApplyModifiersState *st) 2764ApplyModifier_Order(const char **pp, ApplyModifiersState *st)
2764{ 2765{
2765 const char *mod = (*pp)++; /* skip past the 'O' in any case */ 2766 const char *mod = (*pp)++; /* skip past the 'O' in any case */
2766 2767
2767 Words words = Str_Words(st->val, FALSE); 2768 Words words = Str_Words(st->val, FALSE);
2768 2769
2769 if (mod[1] == st->endc || mod[1] == ':') { 2770 if (mod[1] == st->endc || mod[1] == ':') {
2770 /* :O sorts ascending */ 2771 /* :O sorts ascending */
2771 qsort(words.words, words.len, sizeof(char *), str_cmp_asc); 2772 qsort(words.words, words.len, sizeof(char *), str_cmp_asc);
2772 2773
2773 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2774 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2774 (mod[2] == st->endc || mod[2] == ':')) { 2775 (mod[2] == st->endc || mod[2] == ':')) {
2775 (*pp)++; 2776 (*pp)++;
2776 2777
2777 if (mod[1] == 'r') { 2778 if (mod[1] == 'r') {
2778 /* :Or sorts descending */ 2779 /* :Or sorts descending */
2779 qsort(words.words, words.len, sizeof(char *), str_cmp_desc); 2780 qsort(words.words, words.len, sizeof(char *), str_cmp_desc);
2780 2781
2781 } else { 2782 } else {
2782 /* :Ox shuffles 2783 /* :Ox shuffles
2783 * 2784 *
2784 * We will use [ac..2] range for mod factors. This will produce 2785 * We will use [ac..2] range for mod factors. This will produce
2785 * random numbers in [(ac-1)..0] interval, and minimal 2786 * random numbers in [(ac-1)..0] interval, and minimal
2786 * reasonable value for mod factor is 2 (the mod 1 will produce 2787 * reasonable value for mod factor is 2 (the mod 1 will produce
2787 * 0 with probability 1). 2788 * 0 with probability 1).
2788 */ 2789 */
2789 size_t i; 2790 size_t i;
2790 for (i = words.len - 1; i > 0; i--) { 2791 for (i = words.len - 1; i > 0; i--) {
2791 size_t rndidx = (size_t)random() % (i + 1); 2792 size_t rndidx = (size_t)random() % (i + 1);
2792 char *t = words.words[i]; 2793 char *t = words.words[i];
2793 words.words[i] = words.words[rndidx]; 2794 words.words[i] = words.words[rndidx];
2794 words.words[rndidx] = t; 2795 words.words[rndidx] = t;
2795 } 2796 }
2796 } 2797 }
2797 } else { 2798 } else {
2798 Words_Free(words); 2799 Words_Free(words);
2799 return AMR_BAD; 2800 return AMR_BAD;
2800 } 2801 }
2801 2802
2802 st->newVal = Words_JoinFree(words); 2803 st->newVal = Words_JoinFree(words);
2803 return AMR_OK; 2804 return AMR_OK;
2804} 2805}
2805 2806
2806/* :? then : else */ 2807/* :? then : else */
2807static ApplyModifierResult 2808static ApplyModifierResult
2808ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) 2809ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
2809{ 2810{
2810 char *then_expr, *else_expr; 2811 char *then_expr, *else_expr;
2811 VarParseResult res; 2812 VarParseResult res;
2812 2813
2813 Boolean value = FALSE; 2814 Boolean value = FALSE;
2814 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2815 VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2815 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2816 VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2816 2817
2817 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */ 2818 int cond_rc = COND_PARSE; /* anything other than COND_INVALID */
2818 if (st->eflags & VARE_WANTRES) { 2819 if (st->eflags & VARE_WANTRES) {
2819 cond_rc = Cond_EvalCondition(st->v->name, &value); 2820 cond_rc = Cond_EvalCondition(st->v->name, &value);
2820 if (cond_rc != COND_INVALID && value) 2821 if (cond_rc != COND_INVALID && value)
2821 then_eflags |= VARE_WANTRES; 2822 then_eflags |= VARE_WANTRES;
2822 if (cond_rc != COND_INVALID && !value) 2823 if (cond_rc != COND_INVALID && !value)
2823 else_eflags |= VARE_WANTRES; 2824 else_eflags |= VARE_WANTRES;
2824 } 2825 }
2825 2826
2826 (*pp)++; /* skip past the '?' */ 2827 (*pp)++; /* skip past the '?' */
2827 res = ParseModifierPart(pp, ':', then_eflags, st, 2828 res = ParseModifierPart(pp, ':', then_eflags, st,
2828 &then_expr, NULL, NULL, NULL); 2829 &then_expr, NULL, NULL, NULL);
2829 if (res != VPR_OK) 2830 if (res != VPR_OK)
2830 return AMR_CLEANUP; 2831 return AMR_CLEANUP;
2831 2832
2832 res = ParseModifierPart(pp, st->endc, else_eflags, st, 2833 res = ParseModifierPart(pp, st->endc, else_eflags, st,
2833 &else_expr, NULL, NULL, NULL); 2834 &else_expr, NULL, NULL, NULL);
2834 if (res != VPR_OK) 2835 if (res != VPR_OK)
2835 return AMR_CLEANUP; 2836 return AMR_CLEANUP;
2836 2837
2837 (*pp)--; 2838 (*pp)--;
2838 if (cond_rc == COND_INVALID) { 2839 if (cond_rc == COND_INVALID) {
2839 Error("Bad conditional expression `%s' in %s?%s:%s", 2840 Error("Bad conditional expression `%s' in %s?%s:%s",
2840 st->v->name, st->v->name, then_expr, else_expr); 2841 st->v->name, st->v->name, then_expr, else_expr);
2841 return AMR_CLEANUP; 2842 return AMR_CLEANUP;
2842 } 2843 }
2843 2844
2844 if (value) { 2845 if (value) {
2845 st->newVal = then_expr; 2846 st->newVal = then_expr;
2846 free(else_expr); 2847 free(else_expr);
2847 } else { 2848 } else {
2848 st->newVal = else_expr; 2849 st->newVal = else_expr;
2849 free(then_expr); 2850 free(then_expr);
2850 } 2851 }
2851 ApplyModifiersState_Define(st); 2852 ApplyModifiersState_Define(st);
2852 return AMR_OK; 2853 return AMR_OK;
2853} 2854}
2854 2855
2855/* 2856/*
2856 * The ::= modifiers actually assign a value to the variable. 2857 * The ::= modifiers actually assign a value to the variable.
2857 * Their main purpose is in supporting modifiers of .for loop 2858 * Their main purpose is in supporting modifiers of .for loop
2858 * iterators and other obscure uses. They always expand to 2859 * iterators and other obscure uses. They always expand to
2859 * nothing. In a target rule that would otherwise expand to an 2860 * nothing. In a target rule that would otherwise expand to an
2860 * empty line they can be preceded with @: to keep make happy. 2861 * empty line they can be preceded with @: to keep make happy.
2861 * Eg. 2862 * Eg.
2862 * 2863 *
2863 * foo: .USE 2864 * foo: .USE
2864 * .for i in ${.TARGET} ${.TARGET:R}.gz 2865 * .for i in ${.TARGET} ${.TARGET:R}.gz
2865 * @: ${t::=$i} 2866 * @: ${t::=$i}
2866 * @echo blah ${t:T} 2867 * @echo blah ${t:T}
2867 * .endfor 2868 * .endfor
2868 * 2869 *
2869 * ::=<str> Assigns <str> as the new value of variable. 2870 * ::=<str> Assigns <str> as the new value of variable.
2870 * ::?=<str> Assigns <str> as value of variable if 2871 * ::?=<str> Assigns <str> as value of variable if
2871 * it was not already set. 2872 * it was not already set.
2872 * ::+=<str> Appends <str> to variable. 2873 * ::+=<str> Appends <str> to variable.
2873 * ::!=<cmd> Assigns output of <cmd> as the new value of 2874 * ::!=<cmd> Assigns output of <cmd> as the new value of
2874 * variable. 2875 * variable.
2875 */ 2876 */
2876static ApplyModifierResult 2877static ApplyModifierResult
2877ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) 2878ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
2878{ 2879{
2879 GNode *v_ctxt; 2880 GNode *v_ctxt;
2880 char delim; 2881 char delim;
2881 char *val; 2882 char *val;
2882 VarParseResult res; 2883 VarParseResult res;
2883 2884
2884 const char *mod = *pp; 2885 const char *mod = *pp;
2885 const char *op = mod + 1; 2886 const char *op = mod + 1;
2886 if (!(op[0] == '=' || 2887 if (!(op[0] == '=' ||
2887 (op[1] == '=' && 2888 (op[1] == '=' &&
2888 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2889 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2889 return AMR_UNKNOWN; /* "::<unrecognised>" */ 2890 return AMR_UNKNOWN; /* "::<unrecognised>" */
2890 2891
2891 2892
2892 if (st->v->name[0] == '\0') { 2893 if (st->v->name[0] == '\0') {
2893 *pp = mod + 1; 2894 *pp = mod + 1;
2894 return AMR_BAD; 2895 return AMR_BAD;
2895 } 2896 }
2896 2897
2897 v_ctxt = st->ctxt; /* context where v belongs */ 2898 v_ctxt = st->ctxt; /* context where v belongs */
2898 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) { 2899 if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
2899 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2900 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2900 if (gv == NULL) 2901 if (gv == NULL)
2901 v_ctxt = VAR_GLOBAL; 2902 v_ctxt = VAR_GLOBAL;
2902 else 2903 else
2903 VarFreeEnv(gv, TRUE); 2904 VarFreeEnv(gv, TRUE);
2904 } 2905 }
2905 2906
2906 switch (op[0]) { 2907 switch (op[0]) {
2907 case '+': 2908 case '+':
2908 case '?': 2909 case '?':
2909 case '!': 2910 case '!':
2910 *pp = mod + 3; 2911 *pp = mod + 3;
2911 break; 2912 break;
2912 default: 2913 default:
2913 *pp = mod + 2; 2914 *pp = mod + 2;
2914 break; 2915 break;
2915 } 2916 }
2916 2917
2917 delim = st->startc == '(' ? ')' : '}'; 2918 delim = st->startc == '(' ? ')' : '}';
2918 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL); 2919 res = ParseModifierPart(pp, delim, st->eflags, st, &val, NULL, NULL, NULL);
2919 if (res != VPR_OK) 2920 if (res != VPR_OK)
2920 return AMR_CLEANUP; 2921 return AMR_CLEANUP;
2921 2922
2922 (*pp)--; 2923 (*pp)--;
2923 2924
2924 if (st->eflags & VARE_WANTRES) { 2925 if (st->eflags & VARE_WANTRES) {
2925 switch (op[0]) { 2926 switch (op[0]) {
2926 case '+': 2927 case '+':
2927 Var_Append(st->v->name, val, v_ctxt); 2928 Var_Append(st->v->name, val, v_ctxt);
2928 break; 2929 break;
2929 case '!': { 2930 case '!': {
2930 const char *errfmt; 2931 const char *errfmt;
2931 char *cmd_output = Cmd_Exec(val, &errfmt); 2932 char *cmd_output = Cmd_Exec(val, &errfmt);
2932 if (errfmt) 2933 if (errfmt)
2933 Error(errfmt, val); 2934 Error(errfmt, val);
2934 else 2935 else
2935 Var_Set(st->v->name, cmd_output, v_ctxt); 2936 Var_Set(st->v->name, cmd_output, v_ctxt);
2936 free(cmd_output); 2937 free(cmd_output);
2937 break; 2938 break;
2938 } 2939 }
2939 case '?': 2940 case '?':
2940 if (!(st->exprFlags & VEF_UNDEF)) 2941 if (!(st->exprFlags & VEF_UNDEF))
2941 break; 2942 break;
2942 /* FALLTHROUGH */ 2943 /* FALLTHROUGH */
2943 default: 2944 default:
2944 Var_Set(st->v->name, val, v_ctxt); 2945 Var_Set(st->v->name, val, v_ctxt);
2945 break; 2946 break;
2946 } 2947 }
2947 } 2948 }
2948 free(val); 2949 free(val);
2949 st->newVal = emptyString; 2950 st->newVal = emptyString;
2950 return AMR_OK; 2951 return AMR_OK;
2951} 2952}
2952 2953
2953/* remember current value */ 2954/* remember current value */
2954static ApplyModifierResult 2955static ApplyModifierResult
2955ApplyModifier_Remember(const char **pp, ApplyModifiersState *st) 2956ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
2956{ 2957{
2957 const char *mod = *pp; 2958 const char *mod = *pp;
2958 if (!ModMatchEq(mod, "_", st->endc)) 2959 if (!ModMatchEq(mod, "_", st->endc))
2959 return AMR_UNKNOWN; 2960 return AMR_UNKNOWN;
2960 2961
2961 if (mod[1] == '=') { 2962 if (mod[1] == '=') {
2962 size_t n = strcspn(mod + 2, ":)}"); 2963 size_t n = strcspn(mod + 2, ":)}");
2963 char *name = bmake_strldup(mod + 2, n); 2964 char *name = bmake_strldup(mod + 2, n);
2964 Var_Set(name, st->val, st->ctxt); 2965 Var_Set(name, st->val, st->ctxt);
2965 free(name); 2966 free(name);
2966 *pp = mod + 2 + n; 2967 *pp = mod + 2 + n;
2967 } else { 2968 } else {
2968 Var_Set("_", st->val, st->ctxt); 2969 Var_Set("_", st->val, st->ctxt);
2969 *pp = mod + 1; 2970 *pp = mod + 1;
2970 } 2971 }
2971 st->newVal = st->val; 2972 st->newVal = st->val;
2972 return AMR_OK; 2973 return AMR_OK;
2973} 2974}
2974 2975
2975/* Apply the given function to each word of the variable value. */ 2976/* Apply the given function to each word of the variable value. */
2976static ApplyModifierResult 2977static ApplyModifierResult
2977ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, 2978ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
2978 ModifyWordsCallback modifyWord) 2979 ModifyWordsCallback modifyWord)
2979{ 2980{
2980 char delim = (*pp)[1]; 2981 char delim = (*pp)[1];
2981 if (delim != st->endc && delim != ':') 2982 if (delim != st->endc && delim != ':')
2982 return AMR_UNKNOWN; 2983 return AMR_UNKNOWN;
2983 2984
2984 st->newVal = ModifyWords(st->val, modifyWord, NULL, 2985 st->newVal = ModifyWords(st->val, modifyWord, NULL,
2985 st->oneBigWord, st->sep); 2986 st->oneBigWord, st->sep);
2986 (*pp)++; 2987 (*pp)++;
2987 return AMR_OK; 2988 return AMR_OK;
2988} 2989}
2989 2990
2990static ApplyModifierResult 2991static ApplyModifierResult
2991ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) 2992ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
2992{ 2993{
2993 if ((*pp)[1] == st->endc || (*pp)[1] == ':') { 2994 if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2994 st->newVal = VarUniq(st->val); 2995 st->newVal = VarUniq(st->val);
2995 (*pp)++; 2996 (*pp)++;
2996 return AMR_OK; 2997 return AMR_OK;
2997 } else 2998 } else
2998 return AMR_UNKNOWN; 2999 return AMR_UNKNOWN;
2999} 3000}
3000 3001
3001#ifdef SYSVVARSUB 3002#ifdef SYSVVARSUB
3002/* :from=to */ 3003/* :from=to */
3003static ApplyModifierResult 3004static ApplyModifierResult
3004ApplyModifier_SysV(const char **pp, ApplyModifiersState *st) 3005ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
3005{ 3006{
3006 char *lhs, *rhs; 3007 char *lhs, *rhs;
3007 VarParseResult res; 3008 VarParseResult res;
3008 3009
3009 const char *mod = *pp; 3010 const char *mod = *pp;
3010 Boolean eqFound = FALSE; 3011 Boolean eqFound = FALSE;
3011 3012
3012 /* 3013 /*
3013 * First we make a pass through the string trying 3014 * First we make a pass through the string trying
3014 * to verify it is a SYSV-make-style translation: 3015 * to verify it is a SYSV-make-style translation:
3015 * it must be: <string1>=<string2>) 3016 * it must be: <string1>=<string2>)
3016 */ 3017 */
3017 int nest = 1; 3018 int nest = 1;
3018 const char *next = mod; 3019 const char *next = mod;
3019 while (*next != '\0' && nest > 0) { 3020 while (*next != '\0' && nest > 0) {
3020 if (*next == '=') { 3021 if (*next == '=') {
3021 eqFound = TRUE; 3022 eqFound = TRUE;
3022 /* continue looking for st->endc */ 3023 /* continue looking for st->endc */
3023 } else if (*next == st->endc) 3024 } else if (*next == st->endc)
3024 nest--; 3025 nest--;
3025 else if (*next == st->startc) 3026 else if (*next == st->startc)
3026 nest++; 3027 nest++;
3027 if (nest > 0) 3028 if (nest > 0)
3028 next++; 3029 next++;
3029 } 3030 }
3030 if (*next != st->endc || !eqFound) 3031 if (*next != st->endc || !eqFound)
3031 return AMR_UNKNOWN; 3032 return AMR_UNKNOWN;
3032 3033
3033 *pp = mod; 3034 *pp = mod;
3034 res = ParseModifierPart(pp, '=', st->eflags, st, 3035 res = ParseModifierPart(pp, '=', st->eflags, st,
3035 &lhs, NULL, NULL, NULL); 3036 &lhs, NULL, NULL, NULL);
3036 if (res != VPR_OK) 3037 if (res != VPR_OK)
3037 return AMR_CLEANUP; 3038 return AMR_CLEANUP;
3038 3039
3039 res = ParseModifierPart(pp, st->endc, st->eflags, st, 3040 res = ParseModifierPart(pp, st->endc, st->eflags, st,
3040 &rhs, NULL, NULL, NULL); 3041 &rhs, NULL, NULL, NULL);
3041 if (res != VPR_OK) 3042 if (res != VPR_OK)
3042 return AMR_CLEANUP; 3043 return AMR_CLEANUP;
3043 3044
3044 /* 3045 /*
3045 * SYSV modifications happen through the whole 3046 * SYSV modifications happen through the whole
3046 * string. Note the pattern is anchored at the end. 3047 * string. Note the pattern is anchored at the end.
3047 */ 3048 */
3048 (*pp)--; 3049 (*pp)--;
3049 if (lhs[0] == '\0' && st->val[0] == '\0') { 3050 if (lhs[0] == '\0' && st->val[0] == '\0') {
3050 st->newVal = st->val; /* special case */ 3051 st->newVal = st->val; /* special case */
3051 } else { 3052 } else {
3052 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs}; 3053 struct ModifyWord_SYSVSubstArgs args = {st->ctxt, lhs, rhs};
3053 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args, 3054 st->newVal = ModifyWords(st->val, ModifyWord_SYSVSubst, &args,
3054 st->oneBigWord, st->sep); 3055 st->oneBigWord, st->sep);
3055 } 3056 }
3056 free(lhs); 3057 free(lhs);
3057 free(rhs); 3058 free(rhs);
3058 return AMR_OK; 3059 return AMR_OK;
3059} 3060}
3060#endif 3061#endif
3061 3062
3062#ifdef SUNSHCMD 3063#ifdef SUNSHCMD
3063/* :sh */ 3064/* :sh */
3064static ApplyModifierResult 3065static ApplyModifierResult
3065ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) 3066ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
3066{ 3067{
3067 const char *p = *pp; 3068 const char *p = *pp;
3068 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) { 3069 if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3069 if (st->eflags & VARE_WANTRES) { 3070 if (st->eflags & VARE_WANTRES) {
3070 const char *errfmt; 3071 const char *errfmt;
3071 st->newVal = Cmd_Exec(st->val, &errfmt); 3072 st->newVal = Cmd_Exec(st->val, &errfmt);
3072 if (errfmt) 3073 if (errfmt)
3073 Error(errfmt, st->val); 3074 Error(errfmt, st->val);
3074 } else 3075 } else
3075 st->newVal = emptyString; 3076 st->newVal = emptyString;
3076 *pp = p + 2; 3077 *pp = p + 2;
3077 return AMR_OK; 3078 return AMR_OK;
3078 } else 3079 } else
3079 return AMR_UNKNOWN; 3080 return AMR_UNKNOWN;
3080} 3081}
3081#endif 3082#endif
3082 3083
3083static void 3084static void
3084LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc) 3085LogBeforeApply(const ApplyModifiersState *st, const char *mod, const char endc)
3085{ 3086{
3086 char eflags_str[VarEvalFlags_ToStringSize]; 3087 char eflags_str[VarEvalFlags_ToStringSize];
3087 char vflags_str[VarFlags_ToStringSize]; 3088 char vflags_str[VarFlags_ToStringSize];
3088 char exprflags_str[VarExprFlags_ToStringSize]; 3089 char exprflags_str[VarExprFlags_ToStringSize];
3089 Boolean is_single_char = mod[0] != '\0' && 3090 Boolean is_single_char = mod[0] != '\0' &&
3090 (mod[1] == endc || mod[1] == ':'); 3091 (mod[1] == endc || mod[1] == ':');
3091 3092
3092 /* At this point, only the first character of the modifier can 3093 /* At this point, only the first character of the modifier can
3093 * be used since the end of the modifier is not yet known. */ 3094 * be used since the end of the modifier is not yet known. */
3094 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n", 3095 debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
3095 st->v->name, mod[0], is_single_char ? "" : "...", st->val, 3096 st->v->name, mod[0], is_single_char ? "" : "...", st->val,
3096 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3097 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3097 st->eflags, VarEvalFlags_ToStringSpecs), 3098 st->eflags, VarEvalFlags_ToStringSpecs),
3098 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3099 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3099 st->v->flags, VarFlags_ToStringSpecs), 3100 st->v->flags, VarFlags_ToStringSpecs),
3100 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3101 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3101 st->exprFlags, 3102 st->exprFlags,
3102 VarExprFlags_ToStringSpecs)); 3103 VarExprFlags_ToStringSpecs));
3103} 3104}
3104 3105
3105static void 3106static void
3106LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod) 3107LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3107{ 3108{
3108 char eflags_str[VarEvalFlags_ToStringSize]; 3109 char eflags_str[VarEvalFlags_ToStringSize];
3109 char vflags_str[VarFlags_ToStringSize]; 3110 char vflags_str[VarFlags_ToStringSize];
3110 char exprflags_str[VarExprFlags_ToStringSize]; 3111 char exprflags_str[VarExprFlags_ToStringSize];
3111 const char *quot = st->newVal == var_Error ? "" : "\""; 3112 const char *quot = st->newVal == var_Error ? "" : "\"";
3112 const char *newVal = st->newVal == var_Error ? "error" : st->newVal; 3113 const char *newVal = st->newVal == var_Error ? "error" : st->newVal;
3113 3114
3114 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n", 3115 debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
3115 st->v->name, (int)(p - mod), mod, quot, newVal, quot, 3116 st->v->name, (int)(p - mod), mod, quot, newVal, quot,
3116 Enum_FlagsToString(eflags_str, sizeof eflags_str, 3117 Enum_FlagsToString(eflags_str, sizeof eflags_str,
3117 st->eflags, VarEvalFlags_ToStringSpecs), 3118 st->eflags, VarEvalFlags_ToStringSpecs),
3118 Enum_FlagsToString(vflags_str, sizeof vflags_str, 3119 Enum_FlagsToString(vflags_str, sizeof vflags_str,
3119 st->v->flags, VarFlags_ToStringSpecs), 3120 st->v->flags, VarFlags_ToStringSpecs),
3120 Enum_FlagsToString(exprflags_str, sizeof exprflags_str, 3121 Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3121 st->exprFlags, 3122 st->exprFlags,
3122 VarExprFlags_ToStringSpecs)); 3123 VarExprFlags_ToStringSpecs));
3123} 3124}
3124 3125
3125static ApplyModifierResult 3126static ApplyModifierResult
3126ApplyModifier(const char **pp, ApplyModifiersState *st) 3127ApplyModifier(const char **pp, ApplyModifiersState *st)
3127{ 3128{
3128 switch (**pp) { 3129 switch (**pp) {
3129 case ':': 3130 case ':':
3130 return ApplyModifier_Assign(pp, st); 3131 return ApplyModifier_Assign(pp, st);
3131 case '@': 3132 case '@':
3132 return ApplyModifier_Loop(pp, st); 3133 return ApplyModifier_Loop(pp, st);
3133 case '_': 3134 case '_':
3134 return ApplyModifier_Remember(pp, st); 3135 return ApplyModifier_Remember(pp, st);
3135 case 'D': 3136 case 'D':
3136 case 'U': 3137 case 'U':
3137 return ApplyModifier_Defined(pp, st); 3138 return ApplyModifier_Defined(pp, st);
3138 case 'L': 3139 case 'L':
3139 return ApplyModifier_Literal(pp, st); 3140 return ApplyModifier_Literal(pp, st);
3140 case 'P': 3141 case 'P':
3141 return ApplyModifier_Path(pp, st); 3142 return ApplyModifier_Path(pp, st);
3142 case '!': 3143 case '!':
3143 return ApplyModifier_ShellCommand(pp, st); 3144 return ApplyModifier_ShellCommand(pp, st);
3144 case '[': 3145 case '[':
3145 return ApplyModifier_Words(pp, st); 3146 return ApplyModifier_Words(pp, st);
3146 case 'g': 3147 case 'g':
3147 return ApplyModifier_Gmtime(pp, st); 3148 return ApplyModifier_Gmtime(pp, st);
3148 case 'h': 3149 case 'h':
3149 return ApplyModifier_Hash(pp, st); 3150 return ApplyModifier_Hash(pp, st);
3150 case 'l': 3151 case 'l':
3151 return ApplyModifier_Localtime(pp, st); 3152 return ApplyModifier_Localtime(pp, st);
3152 case 't': 3153 case 't':
3153 return ApplyModifier_To(pp, st); 3154 return ApplyModifier_To(pp, st);
3154 case 'N': 3155 case 'N':
3155 case 'M': 3156 case 'M':
3156 return ApplyModifier_Match(pp, st); 3157 return ApplyModifier_Match(pp, st);
3157 case 'S': 3158 case 'S':
3158 return ApplyModifier_Subst(pp, st); 3159 return ApplyModifier_Subst(pp, st);
3159 case '?': 3160 case '?':
3160 return ApplyModifier_IfElse(pp, st); 3161 return ApplyModifier_IfElse(pp, st);
3161#ifndef NO_REGEX 3162#ifndef NO_REGEX
3162 case 'C': 3163 case 'C':
3163 return ApplyModifier_Regex(pp, st); 3164 return ApplyModifier_Regex(pp, st);
3164#endif 3165#endif
3165 case 'q': 3166 case 'q':
3166 case 'Q': 3167 case 'Q':
3167 return ApplyModifier_Quote(pp, st); 3168 return ApplyModifier_Quote(pp, st);
3168 case 'T': 3169 case 'T':
3169 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail); 3170 return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
3170 case 'H': 3171 case 'H':
3171 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head); 3172 return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
3172 case 'E': 3173 case 'E':
3173 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix); 3174 return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
3174 case 'R': 3175 case 'R':
3175 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root); 3176 return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
3176 case 'r': 3177 case 'r':
3177 return ApplyModifier_Range(pp, st); 3178 return ApplyModifier_Range(pp, st);
3178 case 'O': 3179 case 'O':
3179 return ApplyModifier_Order(pp, st); 3180 return ApplyModifier_Order(pp, st);
3180 case 'u': 3181 case 'u':
3181 return ApplyModifier_Unique(pp, st); 3182 return ApplyModifier_Unique(pp, st);
3182#ifdef SUNSHCMD 3183#ifdef SUNSHCMD
3183 case 's': 3184 case 's':
3184 return ApplyModifier_SunShell(pp, st); 3185 return ApplyModifier_SunShell(pp, st);
3185#endif 3186#endif
3186 default: 3187 default:
3187 return AMR_UNKNOWN; 3188 return AMR_UNKNOWN;
3188 } 3189 }
3189} 3190}
3190 3191
3191/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ 3192/* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3192static char * 3193static char *
3193ApplyModifiers( 3194ApplyModifiers(
3194 const char **pp, /* the parsing position, updated upon return */ 3195 const char **pp, /* the parsing position, updated upon return */
3195 char *val, /* the current value of the variable */ 3196 char *val, /* the current value of the variable */
3196 char const startc, /* '(' or '{', or '\0' for indirect modifiers */ 3197 char const startc, /* '(' or '{', or '\0' for indirect modifiers */
3197 char const endc, /* ')' or '}', or '\0' for indirect modifiers */ 3198 char const endc, /* ')' or '}', or '\0' for indirect modifiers */
3198 Var * const v, 3199 Var * const v,
3199 VarExprFlags *exprFlags, 3200 VarExprFlags *exprFlags,
3200 GNode * const ctxt, /* for looking up and modifying variables */ 3201 GNode * const ctxt, /* for looking up and modifying variables */
3201 VarEvalFlags const eflags, 3202 VarEvalFlags const eflags,
3202 void ** const freePtr /* free this after using the return value */ 3203 void ** const freePtr /* free this after using the return value */
3203) { 3204) {
3204 ApplyModifiersState st = { 3205 ApplyModifiersState st = {
3205 startc, endc, v, ctxt, eflags, val, 3206 startc, endc, v, ctxt, eflags, val,
3206 var_Error, /* .newVal */ 3207 var_Error, /* .newVal */
3207 ' ', /* .sep */ 3208 ' ', /* .sep */
3208 FALSE, /* .oneBigWord */ 3209 FALSE, /* .oneBigWord */
3209 *exprFlags /* .exprFlags */ 3210 *exprFlags /* .exprFlags */
3210 }; 3211 };
3211 const char *p; 3212 const char *p;
3212 const char *mod; 3213 const char *mod;
3213 ApplyModifierResult res; 3214 ApplyModifierResult res;
3214 3215
3215 assert(startc == '(' || startc == '{' || startc == '\0'); 3216 assert(startc == '(' || startc == '{' || startc == '\0');
3216 assert(endc == ')' || endc == '}' || endc == '\0'); 3217 assert(endc == ')' || endc == '}' || endc == '\0');
3217 assert(val != NULL); 3218 assert(val != NULL);
3218 3219
3219 p = *pp; 3220 p = *pp;
3220 while (*p != '\0' && *p != endc) { 3221 while (*p != '\0' && *p != endc) {
3221 3222
3222 if (*p == '$') { 3223 if (*p == '$') {
3223 /* 3224 /*
3224 * We may have some complex modifiers in a variable. 3225 * We may have some complex modifiers in a variable.
3225 */ 3226 */
3226 const char *nested_p = p; 3227 const char *nested_p = p;
3227 void *freeIt; 3228 void *freeIt;
3228 const char *rval; 3229 const char *rval;
3229 char c; 3230 char c;
3230 3231
3231 (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt); 3232 (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt);
3232 /* TODO: handle errors */ 3233 /* TODO: handle errors */
3233 3234
3234 /* 3235 /*
3235 * If we have not parsed up to st.endc or ':', we are not 3236 * If we have not parsed up to st.endc or ':', we are not
3236 * interested. This means the expression ${VAR:${M_1}${M_2}} 3237 * interested. This means the expression ${VAR:${M_1}${M_2}}
3237 * is not accepted, but ${VAR:${M_1}:${M_2}} is. 3238 * is not accepted, but ${VAR:${M_1}:${M_2}} is.
3238 */ 3239 */
3239 if (rval[0] != '\0' && 3240 if (rval[0] != '\0' &&
3240 (c = *nested_p) != '\0' && c != ':' && c != st.endc) { 3241 (c = *nested_p) != '\0' && c != ':' && c != st.endc) {
3241 if (DEBUG(LINT)) 3242 if (DEBUG(LINT))
3242 Parse_Error(PARSE_FATAL, 3243 Parse_Error(PARSE_FATAL,
3243 "Missing delimiter ':' after indirect modifier \"%.*s\"", 3244 "Missing delimiter ':' after indirect modifier \"%.*s\"",
3244 (int)(nested_p - p), p); 3245 (int)(nested_p - p), p);
3245 3246
3246 free(freeIt); 3247 free(freeIt);
3247 /* XXX: apply_mods doesn't sound like "not interested". */ 3248 /* XXX: apply_mods doesn't sound like "not interested". */
3248 /* XXX: Why is the indirect modifier parsed again by 3249 /* XXX: Why is the indirect modifier parsed again by
3249 * apply_mods? If any, p should be advanced to nested_p. */ 3250 * apply_mods? If any, p should be advanced to nested_p. */
3250 goto apply_mods; 3251 goto apply_mods;
3251 } 3252 }
3252 3253
3253 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", 3254 VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n",
3254 rval, (int)(size_t)(nested_p - p), p); 3255 rval, (int)(size_t)(nested_p - p), p);
3255 3256
3256 p = nested_p; 3257 p = nested_p;
3257 3258
3258 if (rval[0] != '\0') { 3259 if (rval[0] != '\0') {
3259 const char *rval_pp = rval; 3260 const char *rval_pp = rval;
3260 st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v, 3261 st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v,
3261 &st.exprFlags, ctxt, eflags, freePtr); 3262 &st.exprFlags, ctxt, eflags, freePtr);
3262 if (st.val == var_Error 3263 if (st.val == var_Error
3263 || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR)) 3264 || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR))
3264 || *rval_pp != '\0') { 3265 || *rval_pp != '\0') {
3265 free(freeIt); 3266 free(freeIt);
3266 goto out; /* error already reported */ 3267 goto out; /* error already reported */
3267 } 3268 }
3268 } 3269 }
3269 free(freeIt); 3270 free(freeIt);
3270 3271
3271 if (*p == ':') 3272 if (*p == ':')
3272 p++; 3273 p++;
3273 else if (*p == '\0' && endc != '\0') { 3274 else if (*p == '\0' && endc != '\0') {
3274 Error("Unclosed variable specification after complex " 3275 Error("Unclosed variable specification after complex "
3275 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3276 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3276 goto out; 3277 goto out;
3277 } 3278 }
3278 continue; 3279 continue;
3279 } 3280 }
3280 apply_mods: 3281 apply_mods:
3281 st.newVal = var_Error; /* default value, in case of errors */ 3282 st.newVal = var_Error; /* default value, in case of errors */
3282 mod = p; 3283 mod = p;
3283 3284
3284 if (DEBUG(VAR)) 3285 if (DEBUG(VAR))
3285 LogBeforeApply(&st, mod, endc); 3286 LogBeforeApply(&st, mod, endc);
3286 3287
3287 res = ApplyModifier(&p, &st); 3288 res = ApplyModifier(&p, &st);
3288 3289
3289#ifdef SYSVVARSUB 3290#ifdef SYSVVARSUB
3290 if (res == AMR_UNKNOWN) { 3291 if (res == AMR_UNKNOWN) {
3291 assert(p == mod); 3292 assert(p == mod);
3292 res = ApplyModifier_SysV(&p, &st); 3293 res = ApplyModifier_SysV(&p, &st);
3293 } 3294 }
3294#endif 3295#endif
3295 3296
3296 if (res == AMR_UNKNOWN) { 3297 if (res == AMR_UNKNOWN) {
3297 Error("Unknown modifier '%c'", *mod); 3298 Error("Unknown modifier '%c'", *mod);
3298 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++) 3299 for (p++; *p != ':' && *p != st.endc && *p != '\0'; p++)
3299 continue; 3300 continue;
3300 st.newVal = var_Error; 3301 st.newVal = var_Error;
3301 } 3302 }
3302 if (res == AMR_CLEANUP) 3303 if (res == AMR_CLEANUP)
3303 goto cleanup; 3304 goto cleanup;
3304 if (res == AMR_BAD) 3305 if (res == AMR_BAD)
3305 goto bad_modifier; 3306 goto bad_modifier;
3306 3307
3307 if (DEBUG(VAR)) 3308 if (DEBUG(VAR))
3308 LogAfterApply(&st, p, mod); 3309 LogAfterApply(&st, p, mod);
3309 3310
3310 if (st.newVal != st.val) { 3311 if (st.newVal != st.val) {
3311 if (*freePtr) { 3312 if (*freePtr) {
3312 free(st.val); 3313 free(st.val);
3313 *freePtr = NULL; 3314 *freePtr = NULL;
3314 } 3315 }
3315 st.val = st.newVal; 3316 st.val = st.newVal;
3316 if (st.val != var_Error && st.val != varUndefined && 3317 if (st.val != var_Error && st.val != varUndefined &&
3317 st.val != emptyString) { 3318 st.val != emptyString) {
3318 *freePtr = st.val; 3319 *freePtr = st.val;
3319 } 3320 }
3320 } 3321 }
3321 if (*p == '\0' && st.endc != '\0') { 3322 if (*p == '\0' && st.endc != '\0') {
3322 Error("Unclosed variable specification (expecting '%c') " 3323 Error("Unclosed variable specification (expecting '%c') "
3323 "for \"%s\" (value \"%s\") modifier %c", 3324 "for \"%s\" (value \"%s\") modifier %c",
3324 st.endc, st.v->name, st.val, *mod); 3325 st.endc, st.v->name, st.val, *mod);
3325 } else if (*p == ':') { 3326 } else if (*p == ':') {
3326 p++; 3327 p++;
3327 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) { 3328 } else if (DEBUG(LINT) && *p != '\0' && *p != endc) {
3328 Parse_Error(PARSE_FATAL, 3329 Parse_Error(PARSE_FATAL,
3329 "Missing delimiter ':' after modifier \"%.*s\"", 3330 "Missing delimiter ':' after modifier \"%.*s\"",
3330 (int)(p - mod), mod); 3331 (int)(p - mod), mod);
3331 } 3332 }
3332 } 3333 }
3333out: 3334out:
3334 *pp = p; 3335 *pp = p;
3335 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */ 3336 assert(st.val != NULL); /* Use var_Error or varUndefined instead. */
3336 *exprFlags = st.exprFlags; 3337 *exprFlags = st.exprFlags;
3337 return st.val; 3338 return st.val;
3338 3339
3339bad_modifier: 3340bad_modifier:
3340 Error("Bad modifier `:%.*s' for %s", 3341 Error("Bad modifier `:%.*s' for %s",
3341 (int)strcspn(mod, ":)}"), mod, st.v->name); 3342 (int)strcspn(mod, ":)}"), mod, st.v->name);
3342 3343
3343cleanup: 3344cleanup:
3344 *pp = p; 3345 *pp = p;
3345 free(*freePtr); 3346 free(*freePtr);
3346 *freePtr = NULL; 3347 *freePtr = NULL;
3347 *exprFlags = st.exprFlags; 3348 *exprFlags = st.exprFlags;
3348 return var_Error; 3349 return var_Error;
3349} 3350}
3350 3351
3351/* Only four of the local variables are treated specially as they are the 3352/* Only four of the local variables are treated specially as they are the
3352 * only four that will be set when dynamic sources are expanded. */ 3353 * only four that will be set when dynamic sources are expanded. */
3353static Boolean 3354static Boolean
3354VarnameIsDynamic(const char *name, size_t len) 3355VarnameIsDynamic(const char *name, size_t len)
3355{ 3356{
3356 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) { 3357 if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3357 switch (name[0]) { 3358 switch (name[0]) {
3358 case '@': 3359 case '@':
3359 case '%': 3360 case '%':
3360 case '*': 3361 case '*':
3361 case '!': 3362 case '!':
3362 return TRUE; 3363 return TRUE;
3363 } 3364 }
3364 return FALSE; 3365 return FALSE;
3365 } 3366 }
3366 3367
3367 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) { 3368 if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3368 return strcmp(name, ".TARGET") == 0 || 3369 return strcmp(name, ".TARGET") == 0 ||
3369 strcmp(name, ".ARCHIVE") == 0 || 3370 strcmp(name, ".ARCHIVE") == 0 ||
3370 strcmp(name, ".PREFIX") == 0 || 3371 strcmp(name, ".PREFIX") == 0 ||
3371 strcmp(name, ".MEMBER") == 0; 3372 strcmp(name, ".MEMBER") == 0;
3372 } 3373 }
3373 3374
3374 return FALSE; 3375 return FALSE;
3375} 3376}
3376 3377
3377static const char * 3378static const char *
3378UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags) 3379UndefinedShortVarValue(char varname, const GNode *ctxt, VarEvalFlags eflags)
3379{ 3380{
3380 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) { 3381 if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3381 /* 3382 /*
3382 * If substituting a local variable in a non-local context, 3383 * If substituting a local variable in a non-local context,
3383 * assume it's for dynamic source stuff. We have to handle 3384 * assume it's for dynamic source stuff. We have to handle
3384 * this specially and return the longhand for the variable 3385 * this specially and return the longhand for the variable
3385 * with the dollar sign escaped so it makes it back to the 3386 * with the dollar sign escaped so it makes it back to the
3386 * caller. Only four of the local variables are treated 3387 * caller. Only four of the local variables are treated
3387 * specially as they are the only four that will be set 3388 * specially as they are the only four that will be set
3388 * when dynamic sources are expanded. 3389 * when dynamic sources are expanded.
3389 */ 3390 */
3390 switch (varname) { 3391 switch (varname) {
3391 case '@': 3392 case '@':
3392 return "$(.TARGET)"; 3393 return "$(.TARGET)";
3393 case '%': 3394 case '%':
3394 return "$(.MEMBER)"; 3395 return "$(.MEMBER)";
3395 case '*': 3396 case '*':
3396 return "$(.PREFIX)"; 3397 return "$(.PREFIX)";
3397 case '!': 3398 case '!':
3398 return "$(.ARCHIVE)"; 3399 return "$(.ARCHIVE)";
3399 } 3400 }
3400 } 3401 }
3401 return eflags & VARE_UNDEFERR ? var_Error : varUndefined; 3402 return eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3402} 3403}
3403 3404
3404/* Parse a variable name, until the end character or a colon, whichever 3405/* Parse a variable name, until the end character or a colon, whichever
3405 * comes first. */ 3406 * comes first. */
3406static char * 3407static char *
3407ParseVarname(const char **pp, char startc, char endc, 3408ParseVarname(const char **pp, char startc, char endc,
3408 GNode *ctxt, VarEvalFlags eflags, 3409 GNode *ctxt, VarEvalFlags eflags,
3409 size_t *out_varname_len) 3410 size_t *out_varname_len)
3410{ 3411{
3411 Buffer buf; 3412 Buffer buf;
3412 const char *p = *pp; 3413 const char *p = *pp;
3413 int depth = 1; 3414 int depth = 1;
3414 3415
3415 Buf_Init(&buf, 0); 3416 Buf_Init(&buf, 0);
3416 3417
3417 while (*p != '\0') { 3418 while (*p != '\0') {
3418 /* Track depth so we can spot parse errors. */ 3419 /* Track depth so we can spot parse errors. */
3419 if (*p == startc) 3420 if (*p == startc)
3420 depth++; 3421 depth++;
3421 if (*p == endc) { 3422 if (*p == endc) {
3422 if (--depth == 0) 3423 if (--depth == 0)
3423 break; 3424 break;
3424 } 3425 }
3425 if (*p == ':' && depth == 1) 3426 if (*p == ':' && depth == 1)
3426 break; 3427 break;
3427 3428
3428 /* A variable inside a variable, expand. */ 3429 /* A variable inside a variable, expand. */
3429 if (*p == '$') { 3430 if (*p == '$') {
3430 void *freeIt; 3431 void *freeIt;
3431 const char *rval; 3432 const char *rval;
3432 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt); 3433 (void)Var_Parse(&p, ctxt, eflags, &rval, &freeIt);
3433 /* TODO: handle errors */ 3434 /* TODO: handle errors */
3434 Buf_AddStr(&buf, rval); 3435 Buf_AddStr(&buf, rval);
3435 free(freeIt); 3436 free(freeIt);
3436 } else { 3437 } else {
3437 Buf_AddByte(&buf, *p); 3438 Buf_AddByte(&buf, *p);
3438 p++; 3439 p++;
3439 } 3440 }
3440 } 3441 }
3441 *pp = p; 3442 *pp = p;
3442 *out_varname_len = Buf_Len(&buf); 3443 *out_varname_len = Buf_Len(&buf);
3443 return Buf_Destroy(&buf, FALSE); 3444 return Buf_Destroy(&buf, FALSE);
3444} 3445}
3445 3446
3446static Boolean 3447static Boolean
3447ValidShortVarname(char varname, const char *start) 3448ValidShortVarname(char varname, const char *start)
3448{ 3449{
3449 switch (varname) { 3450 switch (varname) {
3450 case '\0': 3451 case '\0':
3451 case ')': 3452 case ')':
3452 case '}': 3453 case '}':
3453 case ':': 3454 case ':':
3454 case '$': 3455 case '$':
3455 break; /* and continue below */ 3456 break; /* and continue below */
3456 default: 3457 default:
3457 return TRUE; 3458 return TRUE;
3458 } 3459 }
3459 3460
3460 if (!DEBUG(LINT)) 3461 if (!DEBUG(LINT))
3461 return FALSE; 3462 return FALSE;
3462 3463
3463 if (varname == '$') 3464 if (varname == '$')
3464 Parse_Error(PARSE_FATAL, 3465 Parse_Error(PARSE_FATAL,
3465 "To escape a dollar, use \\$, not $$, at \"%s\"", start); 3466 "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3466 else if (varname == '\0') 3467 else if (varname == '\0')
3467 Parse_Error(PARSE_FATAL, "Dollar followed by nothing"); 3468 Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3468 else 3469 else
3469 Parse_Error(PARSE_FATAL, 3470 Parse_Error(PARSE_FATAL,
3470 "Invalid variable name '%c', at \"%s\"", varname, start); 3471 "Invalid variable name '%c', at \"%s\"", varname, start);
3471 3472
3472 return FALSE; 3473 return FALSE;
3473} 3474}
3474 3475
3475/* Parse a single-character variable name such as $V or $@. 3476/* Parse a single-character variable name such as $V or $@.
3476 * Return whether to continue parsing. */ 3477 * Return whether to continue parsing. */
3477static Boolean 3478static Boolean
3478ParseVarnameShort( 3479ParseVarnameShort(
3479 char startc, 3480 char startc,
3480 const char **pp, 3481 const char **pp,
3481 GNode *ctxt, 3482 GNode *ctxt,
3482 VarEvalFlags eflags, 3483 VarEvalFlags eflags,
3483 VarParseResult *out_FALSE_res, 3484 VarParseResult *out_FALSE_res,
3484 const char **out_FALSE_val, 3485 const char **out_FALSE_val,
3485 Var **out_TRUE_var 3486 Var **out_TRUE_var
3486) { 3487) {
3487 char name[2]; 3488 char name[2];
3488 Var *v; 3489 Var *v;
3489 3490
3490 /* 3491 /*
3491 * If it's not bounded by braces of some sort, life is much simpler. 3492 * If it's not bounded by braces of some sort, life is much simpler.
3492 * We just need to check for the first character and return the 3493 * We just need to check for the first character and return the
3493 * value if it exists. 3494 * value if it exists.
3494 */ 3495 */
3495 3496
3496 if (!ValidShortVarname(startc, *pp)) { 3497 if (!ValidShortVarname(startc, *pp)) {
3497 (*pp)++; 3498 (*pp)++;
3498 *out_FALSE_val = var_Error; 3499 *out_FALSE_val = var_Error;
3499 *out_FALSE_res = VPR_PARSE_MSG; 3500 *out_FALSE_res = VPR_PARSE_MSG;
3500 return FALSE; 3501 return FALSE;
3501 } 3502 }
3502 3503
3503 name[0] = startc; 3504 name[0] = startc;
3504 name[1] = '\0'; 3505 name[1] = '\0';
3505 v = VarFind(name, ctxt, TRUE); 3506 v = VarFind(name, ctxt, TRUE);
3506 if (v == NULL) { 3507 if (v == NULL) {
3507 *pp += 2; 3508 *pp += 2;
3508 3509
3509 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags); 3510 *out_FALSE_val = UndefinedShortVarValue(startc, ctxt, eflags);
3510 if (DEBUG(LINT) && *out_FALSE_val == var_Error) { 3511 if (DEBUG(LINT) && *out_FALSE_val == var_Error) {
3511 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); 3512 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name);
3512 *out_FALSE_res = VPR_UNDEF_MSG; 3513 *out_FALSE_res = VPR_UNDEF_MSG;
3513 return FALSE; 3514 return FALSE;
3514 } 3515 }
3515 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; 3516 *out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK;
3516 return FALSE; 3517 return FALSE;
3517 } 3518 }
3518 3519
3519 *out_TRUE_var = v; 3520 *out_TRUE_var = v;
3520 return TRUE; 3521 return TRUE;
3521} 3522}
3522 3523
3523/* Parse a long variable name enclosed in braces or parentheses such as $(VAR) 3524/* Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3524 * or ${VAR}, up to the closing brace or parenthesis, or in the case of 3525 * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3525 * ${VAR:Modifiers}, up to the ':' that starts the modifiers. 3526 * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3526 * Return whether to continue parsing. */ 3527 * Return whether to continue parsing. */
3527static Boolean 3528static Boolean
3528ParseVarnameLong( 3529ParseVarnameLong(
3529 const char **pp, 3530 const char **pp,
3530 char startc, 3531 char startc,
3531 GNode *ctxt, 3532 GNode *ctxt,
3532 VarEvalFlags eflags, 3533 VarEvalFlags eflags,
3533 3534
3534 VarParseResult *out_FALSE_res, 3535 VarParseResult *out_FALSE_res,
3535 const char **out_FALSE_val, 3536 const char **out_FALSE_val,
3536 void **out_FALSE_freePtr, 3537 void **out_FALSE_freePtr,
3537 3538
3538 char *out_TRUE_endc, 3539 char *out_TRUE_endc,
3539 const char **out_TRUE_p, 3540 const char **out_TRUE_p,
3540 Var **out_TRUE_v, 3541 Var **out_TRUE_v,
3541 Boolean *out_TRUE_haveModifier, 3542 Boolean *out_TRUE_haveModifier,
3542 const char **out_TRUE_extraModifiers, 3543 const char **out_TRUE_extraModifiers,
3543 Boolean *out_TRUE_dynamic, 3544 Boolean *out_TRUE_dynamic,
3544 VarExprFlags *out_TRUE_exprFlags 3545 VarExprFlags *out_TRUE_exprFlags
3545) { 3546) {
3546 size_t namelen; 3547 size_t namelen;
3547 char *varname; 3548 char *varname;
3548 Var *v; 3549 Var *v;
3549 Boolean haveModifier; 3550 Boolean haveModifier;
3550 Boolean dynamic = FALSE; 3551 Boolean dynamic = FALSE;
3551 3552
3552 const char *const start = *pp; 3553 const char *const start = *pp;
3553 char endc = startc == '(' ? ')' : '}'; 3554 char endc = startc == '(' ? ')' : '}';
3554 3555
3555 const char *p = start + 2; 3556 const char *p = start + 2;
3556 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen); 3557 varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
3557 3558
3558 if (*p == ':') { 3559 if (*p == ':') {
3559 haveModifier = TRUE; 3560 haveModifier = TRUE;
3560 } else if (*p == endc) { 3561 } else if (*p == endc) {
3561 haveModifier = FALSE; 3562 haveModifier = FALSE;
3562 } else { 3563 } else {
3563 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); 3564 Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
3564 *pp = p; 3565 *pp = p;
3565 free(varname); 3566 free(varname);
3566 *out_FALSE_val = var_Error; 3567 *out_FALSE_val = var_Error;
3567 *out_FALSE_res = VPR_PARSE_MSG; 3568 *out_FALSE_res = VPR_PARSE_MSG;
3568 return FALSE; 3569 return FALSE;
3569 } 3570 }
3570 3571
3571 v = VarFind(varname, ctxt, TRUE); 3572 v = VarFind(varname, ctxt, TRUE);
3572 3573
3573 /* At this point, p points just after the variable name, 3574 /* At this point, p points just after the variable name,
3574 * either at ':' or at endc. */ 3575 * either at ':' or at endc. */
3575 3576
3576 /* 3577 /*
3577 * Check also for bogus D and F forms of local variables since we're 3578 * Check also for bogus D and F forms of local variables since we're
3578 * in a local context and the name is the right length. 3579 * in a local context and the name is the right length.
3579 */ 3580 */
3580 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && 3581 if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL &&
3581 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3582 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3582 strchr("@%?*!<>", varname[0]) != NULL) 3583 strchr("@%?*!<>", varname[0]) != NULL)
3583 { 3584 {
3584 /* 3585 /*
3585 * Well, it's local -- go look for it. 3586 * Well, it's local -- go look for it.
3586 */ 3587 */
3587 char name[] = { varname[0], '\0' }; 3588 char name[] = { varname[0], '\0' };
3588 v = VarFind(name, ctxt, 0); 3589 v = VarFind(name, ctxt, 0);
3589 3590
3590 if (v != NULL) { 3591 if (v != NULL) {
3591 if (varname[1] == 'D') { 3592 if (varname[1] == 'D') {
3592 *out_TRUE_extraModifiers = "H:"; 3593 *out_TRUE_extraModifiers = "H:";
3593 } else { /* F */ 3594 } else { /* F */
3594 *out_TRUE_extraModifiers = "T:"; 3595 *out_TRUE_extraModifiers = "T:";
3595 } 3596 }
3596 } 3597 }
3597 } 3598 }
3598 3599
3599 if (v == NULL) { 3600 if (v == NULL) {
3600 /* Defer expansion of dynamic variables if they appear in non-local 3601 /* Defer expansion of dynamic variables if they appear in non-local
3601 * context since they are not defined there. */ 3602 * context since they are not defined there. */
3602 dynamic = VarnameIsDynamic(varname, namelen) && 3603 dynamic = VarnameIsDynamic(varname, namelen) &&
3603 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL); 3604 (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
3604 3605
3605 if (!haveModifier) { 3606 if (!haveModifier) {
3606 p++; /* skip endc */ 3607 p++; /* skip endc */
3607 *pp = p; 3608 *pp = p;
3608 if (dynamic) { 3609 if (dynamic) {
3609 char *pstr = bmake_strsedup(start, p); 3610 char *pstr = bmake_strsedup(start, p);
3610 free(varname); 3611 free(varname);
3611 *out_FALSE_res = VPR_OK; 3612 *out_FALSE_res = VPR_OK;
3612 *out_FALSE_freePtr = pstr; 3613 *out_FALSE_freePtr = pstr;
3613 *out_FALSE_val = pstr; 3614 *out_FALSE_val = pstr;
3614 return FALSE; 3615 return FALSE;
3615 } 3616 }
3616 3617
3617 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) && 3618 if ((eflags & VARE_UNDEFERR) && (eflags & VARE_WANTRES) &&
3618 DEBUG(LINT)) 3619 DEBUG(LINT))
3619 { 3620 {
3620 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", 3621 Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined",
3621 varname); 3622 varname);
3622 free(varname); 3623 free(varname);
3623 *out_FALSE_res = VPR_UNDEF_MSG; 3624 *out_FALSE_res = VPR_UNDEF_MSG;
3624 *out_FALSE_val = var_Error; 3625 *out_FALSE_val = var_Error;
3625 return FALSE; 3626 return FALSE;
3626 } 3627 }
3627 3628
3628 if (eflags & VARE_UNDEFERR) { 3629 if (eflags & VARE_UNDEFERR) {
3629 free(varname); 3630 free(varname);
3630 *out_FALSE_res = VPR_UNDEF_SILENT; 3631 *out_FALSE_res = VPR_UNDEF_SILENT;
3631 *out_FALSE_val = var_Error; 3632 *out_FALSE_val = var_Error;
3632 return FALSE; 3633 return FALSE;
3633 } 3634 }
3634 3635
3635 free(varname); 3636 free(varname);
3636 *out_FALSE_res = VPR_OK; 3637 *out_FALSE_res = VPR_OK;
3637 *out_FALSE_val = varUndefined; 3638 *out_FALSE_val = varUndefined;
3638 return FALSE; 3639 return FALSE;
3639 } 3640 }
3640 3641
3641 /* The variable expression is based on an undefined variable. 3642 /* The variable expression is based on an undefined variable.
3642 * Nevertheless it needs a Var, for modifiers that access the 3643 * Nevertheless it needs a Var, for modifiers that access the
3643 * variable name, such as :L or :?. 3644 * variable name, such as :L or :?.
3644 * 3645 *
3645 * Most modifiers leave this expression in the "undefined" state 3646 * Most modifiers leave this expression in the "undefined" state
3646 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this 3647 * (VEF_UNDEF), only a few modifiers like :D, :U, :L, :P turn this
3647 * undefined expression into a defined expression (VEF_DEF). 3648 * undefined expression into a defined expression (VEF_DEF).
3648 * 3649 *
3649 * At the end, after applying all modifiers, if the expression 3650 * At the end, after applying all modifiers, if the expression
3650 * is still undefined, Var_Parse will return an empty string 3651 * is still undefined, Var_Parse will return an empty string
3651 * instead of the actually computed value. */ 3652 * instead of the actually computed value. */
3652 v = VarNew(varname, varname, "", 0); 3653 v = VarNew(varname, varname, "", 0);
3653 *out_TRUE_exprFlags = VEF_UNDEF; 3654 *out_TRUE_exprFlags = VEF_UNDEF;
3654 } else 3655 } else
3655 free(varname); 3656 free(varname);
3656 3657
3657 *out_TRUE_endc = endc; 3658 *out_TRUE_endc = endc;
3658 *out_TRUE_p = p; 3659 *out_TRUE_p = p;
3659 *out_TRUE_v = v; 3660 *out_TRUE_v = v;
3660 *out_TRUE_haveModifier = haveModifier; 3661 *out_TRUE_haveModifier = haveModifier;
3661 *out_TRUE_dynamic = dynamic; 3662 *out_TRUE_dynamic = dynamic;
3662 return TRUE; 3663 return TRUE;
3663} 3664}
3664 3665
3665/*- 3666/*-
3666 *----------------------------------------------------------------------- 3667 *-----------------------------------------------------------------------
3667 * Var_Parse -- 3668 * Var_Parse --
3668 * Given the start of a variable expression (such as $v, $(VAR), 3669 * Given the start of a variable expression (such as $v, $(VAR),
3669 * ${VAR:Mpattern}), extract the variable name, possibly some 3670 * ${VAR:Mpattern}), extract the variable name, possibly some
3670 * modifiers and find its value by applying the modifiers to the 3671 * modifiers and find its value by applying the modifiers to the
3671 * original value. 3672 * original value.
3672 * 3673 *
3673 * When parsing a condition in ParseEmptyArg, pp may also point to 3674 * When parsing a condition in ParseEmptyArg, pp may also point to
3674 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically 3675 * the "y" of "empty(VARNAME:Modifiers)", which is syntactically
3675 * identical. 3676 * identical.
3676 * 3677 *
3677 * Input: 3678 * Input:
3678 * str The string to parse 3679 * str The string to parse
3679 * ctxt The context for the variable 3680 * ctxt The context for the variable
3680 * flags Select the exact details of parsing 3681 * flags Select the exact details of parsing
3681 * out_val_freeIt Must be freed by the caller after using out_val 3682 * out_val_freeIt Must be freed by the caller after using out_val
3682 * 3683 *
3683 * Results: 3684 * Results:
3684 * Returns the value of the variable expression, never NULL. 3685 * Returns the value of the variable expression, never NULL.
3685 * Returns var_Error if there was a parse error and VARE_UNDEFERR was 3686 * Returns var_Error if there was a parse error and VARE_UNDEFERR was
3686 * set. 3687 * set.
3687 * Returns varUndefined if there was an undefined variable and 3688 * Returns varUndefined if there was an undefined variable and
3688 * VARE_UNDEFERR was not set. 3689 * VARE_UNDEFERR was not set.
3689 * 3690 *
3690 * Parsing should continue at *pp. 3691 * Parsing should continue at *pp.
3691 * TODO: Document the value of *pp on parse errors. It might be advanced 3692 * TODO: Document the value of *pp on parse errors. It might be advanced
3692 * by 0, or +1, or the index of the parse error, or the guessed end of the 3693 * by 0, or +1, or the index of the parse error, or the guessed end of the
3693 * variable expression. 3694 * variable expression.
3694 * 3695 *
3695 * If var_Error is returned, a diagnostic may or may not have been 3696 * If var_Error is returned, a diagnostic may or may not have been
3696 * printed. XXX: This is inconsistent. 3697 * printed. XXX: This is inconsistent.
3697 * 3698 *
3698 * If varUndefined is returned, a diagnostic may or may not have been 3699 * If varUndefined is returned, a diagnostic may or may not have been
3699 * printed. XXX: This is inconsistent. 3700 * printed. XXX: This is inconsistent.
3700 * 3701 *
3701 * After using the returned value, *out_val_freeIt must be freed, 3702 * After using the returned value, *out_val_freeIt must be freed,
3702 * preferably using bmake_free since it is NULL in most cases. 3703 * preferably using bmake_free since it is NULL in most cases.
3703 * 3704 *
3704 * Side Effects: 3705 * Side Effects:
3705 * Any effects from the modifiers, such as :!cmd! or ::=value. 3706 * Any effects from the modifiers, such as :!cmd! or ::=value.
3706 *----------------------------------------------------------------------- 3707 *-----------------------------------------------------------------------
3707 */ 3708 */
3708/* coverity[+alloc : arg-*4] */ 3709/* coverity[+alloc : arg-*4] */
3709VarParseResult 3710VarParseResult
3710Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, 3711Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags,
3711 const char **out_val, void **out_val_freeIt) 3712 const char **out_val, void **out_val_freeIt)
3712{ 3713{
3713 const char *const start = *pp; 3714 const char *const start = *pp;
3714 const char *p; 3715 const char *p;
3715 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3716 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3716 char startc; /* Starting character if variable in parens 3717 char startc; /* Starting character if variable in parens
3717 * or braces */ 3718 * or braces */
3718 char endc; /* Ending character if variable in parens 3719 char endc; /* Ending character if variable in parens
3719 * or braces */ 3720 * or braces */
3720 Boolean dynamic; /* TRUE if the variable is local and we're 3721 Boolean dynamic; /* TRUE if the variable is local and we're
3721 * expanding it in a non-local context. This 3722 * expanding it in a non-local context. This
3722 * is done to support dynamic sources. The 3723 * is done to support dynamic sources. The
3723 * result is just the expression, unaltered */ 3724 * result is just the expression, unaltered */
3724 const char *extramodifiers; 3725 const char *extramodifiers;
3725 Var *v; 3726 Var *v;
3726 char *nstr; 3727 char *nstr;
3727 char eflags_str[VarEvalFlags_ToStringSize]; 3728 char eflags_str[VarEvalFlags_ToStringSize];
3728 VarExprFlags exprFlags = 0; 3729 VarExprFlags exprFlags = 0;
3729 3730
3730 VAR_DEBUG2("Var_Parse: %s with %s\n", start, 3731 VAR_DEBUG2("Var_Parse: %s with %s\n", start,
3731 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags, 3732 Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
3732 VarEvalFlags_ToStringSpecs)); 3733 VarEvalFlags_ToStringSpecs));
3733 3734
3734 *out_val_freeIt = NULL; 3735 *out_val_freeIt = NULL;
3735 extramodifiers = NULL; /* extra modifiers to apply first */ 3736 extramodifiers = NULL; /* extra modifiers to apply first */
3736 dynamic = FALSE; 3737 dynamic = FALSE;