Mon Aug 31 19:09:19 2020 UTC ()
make(1): inline a local variable in VarUniq

Just to eliminate any remote possibility of aliasing and thereby
forgetting to update all involved variables.


(rillig)
diff -r1.481 -r1.482 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/08/31 19:05:53 1.481
+++ src/usr.bin/make/var.c 2020/08/31 19:09:19 1.482
@@ -1,2617 +1,2616 @@ @@ -1,2617 +1,2616 @@
1/* $NetBSD: var.c,v 1.481 2020/08/31 19:05:53 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.482 2020/08/31 19:09:19 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#ifndef MAKE_NATIVE 71#ifndef MAKE_NATIVE
72static char rcsid[] = "$NetBSD: var.c,v 1.481 2020/08/31 19:05:53 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.482 2020/08/31 19:09:19 rillig Exp $";
73#else 73#else
74#include <sys/cdefs.h> 74#include <sys/cdefs.h>
75#ifndef lint 75#ifndef lint
76#if 0 76#if 0
77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; 77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
78#else 78#else
79__RCSID("$NetBSD: var.c,v 1.481 2020/08/31 19:05:53 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.482 2020/08/31 19:09:19 rillig Exp $");
80#endif 80#endif
81#endif /* not lint */ 81#endif /* not lint */
82#endif 82#endif
83 83
84/*- 84/*-
85 * var.c -- 85 * var.c --
86 * Variable-handling functions 86 * Variable-handling functions
87 * 87 *
88 * Interface: 88 * Interface:
89 * Var_Set Set the value of a variable in the given 89 * Var_Set Set the value of a variable in the given
90 * context. The variable is created if it doesn't 90 * context. The variable is created if it doesn't
91 * yet exist. 91 * yet exist.
92 * 92 *
93 * Var_Append Append more characters to an existing variable 93 * Var_Append Append more characters to an existing variable
94 * in the given context. The variable needn't 94 * in the given context. The variable needn't
95 * exist already -- it will be created if it doesn't. 95 * exist already -- it will be created if it doesn't.
96 * A space is placed between the old value and the 96 * A space is placed between the old value and the
97 * new one. 97 * new one.
98 * 98 *
99 * Var_Exists See if a variable exists. 99 * Var_Exists See if a variable exists.
100 * 100 *
101 * Var_Value Return the unexpanded value of a variable in a 101 * Var_Value Return the unexpanded value of a variable in a
102 * context or NULL if the variable is undefined. 102 * context or NULL if the variable is undefined.
103 * 103 *
104 * Var_Subst Substitute either a single variable or all 104 * Var_Subst Substitute either a single variable or all
105 * variables in a string, using the given context. 105 * variables in a string, using the given context.
106 * 106 *
107 * Var_Parse Parse a variable expansion from a string and 107 * Var_Parse Parse a variable expansion from a string and
108 * return the result and the number of characters 108 * return the result and the number of characters
109 * consumed. 109 * consumed.
110 * 110 *
111 * Var_Delete Delete a variable in a context. 111 * Var_Delete Delete a variable in a context.
112 * 112 *
113 * Var_Init Initialize this module. 113 * Var_Init Initialize this module.
114 * 114 *
115 * Debugging: 115 * Debugging:
116 * Var_Dump Print out all variables defined in the given 116 * Var_Dump Print out all variables defined in the given
117 * context. 117 * context.
118 * 118 *
119 * XXX: There's a lot of duplication in these functions. 119 * XXX: There's a lot of duplication in these functions.
120 */ 120 */
121 121
122#include <sys/stat.h> 122#include <sys/stat.h>
123#ifndef NO_REGEX 123#ifndef NO_REGEX
124#include <sys/types.h> 124#include <sys/types.h>
125#include <regex.h> 125#include <regex.h>
126#endif 126#endif
127#include <inttypes.h> 127#include <inttypes.h>
128#include <limits.h> 128#include <limits.h>
129#include <time.h> 129#include <time.h>
130 130
131#include "make.h" 131#include "make.h"
132#include "enum.h" 132#include "enum.h"
133#include "dir.h" 133#include "dir.h"
134#include "job.h" 134#include "job.h"
135#include "metachar.h" 135#include "metachar.h"
136 136
137#define VAR_DEBUG_IF(cond, fmt, ...) \ 137#define VAR_DEBUG_IF(cond, fmt, ...) \
138 if (!(DEBUG(VAR) && (cond))) \ 138 if (!(DEBUG(VAR) && (cond))) \
139 (void) 0; \ 139 (void) 0; \
140 else \ 140 else \
141 fprintf(debug_file, fmt, __VA_ARGS__) 141 fprintf(debug_file, fmt, __VA_ARGS__)
142 142
143#define VAR_DEBUG(fmt, ...) VAR_DEBUG_IF(TRUE, fmt, __VA_ARGS__) 143#define VAR_DEBUG(fmt, ...) VAR_DEBUG_IF(TRUE, fmt, __VA_ARGS__)
144 144
145ENUM_FLAGS_RTTI_3(VarEvalFlags, 145ENUM_FLAGS_RTTI_3(VarEvalFlags,
146 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 146 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
147 147
148/* 148/*
149 * This lets us tell if we have replaced the original environ 149 * This lets us tell if we have replaced the original environ
150 * (which we cannot free). 150 * (which we cannot free).
151 */ 151 */
152char **savedEnv = NULL; 152char **savedEnv = NULL;
153 153
154/* 154/*
155 * This is a harmless return value for Var_Parse that can be used by Var_Subst 155 * This is a harmless return value for Var_Parse that can be used by Var_Subst
156 * to determine if there was an error in parsing -- easier than returning 156 * to determine if there was an error in parsing -- easier than returning
157 * a flag, as things outside this module don't give a hoot. 157 * a flag, as things outside this module don't give a hoot.
158 */ 158 */
159char var_Error[] = ""; 159char var_Error[] = "";
160 160
161/* 161/*
162 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for 162 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for
163 * Var_Parse is not set. 163 * Var_Parse is not set.
164 * 164 *
165 * Why not just use a constant? Well, GCC likes to condense identical string 165 * Why not just use a constant? Well, GCC likes to condense identical string
166 * instances... 166 * instances...
167 */ 167 */
168static char varNoError[] = ""; 168static char varNoError[] = "";
169 169
170/* 170/*
171 * Traditionally we consume $$ during := like any other expansion. 171 * Traditionally we consume $$ during := like any other expansion.
172 * Other make's do not. 172 * Other make's do not.
173 * This knob allows controlling the behavior. 173 * This knob allows controlling the behavior.
174 * FALSE to consume $$ during := assignment. 174 * FALSE to consume $$ during := assignment.
175 * TRUE to preserve $$ during := assignment. 175 * TRUE to preserve $$ during := assignment.
176 */ 176 */
177#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 177#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
178static Boolean save_dollars = TRUE; 178static Boolean save_dollars = TRUE;
179 179
180/* 180/*
181 * Internally, variables are contained in four different contexts. 181 * Internally, variables are contained in four different contexts.
182 * 1) the environment. They cannot be changed. If an environment 182 * 1) the environment. They cannot be changed. If an environment
183 * variable is appended to, the result is placed in the global 183 * variable is appended to, the result is placed in the global
184 * context. 184 * context.
185 * 2) the global context. Variables set in the Makefile are located in 185 * 2) the global context. Variables set in the Makefile are located in
186 * the global context. 186 * the global context.
187 * 3) the command-line context. All variables set on the command line 187 * 3) the command-line context. All variables set on the command line
188 * are placed in this context. They are UNALTERABLE once placed here. 188 * are placed in this context. They are UNALTERABLE once placed here.
189 * 4) the local context. Each target has associated with it a context 189 * 4) the local context. Each target has associated with it a context
190 * list. On this list are located the structures describing such 190 * list. On this list are located the structures describing such
191 * local variables as $(@) and $(*) 191 * local variables as $(@) and $(*)
192 * The four contexts are searched in the reverse order from which they are 192 * The four contexts are searched in the reverse order from which they are
193 * listed (but see checkEnvFirst). 193 * listed (but see checkEnvFirst).
194 */ 194 */
195GNode *VAR_INTERNAL; /* variables from make itself */ 195GNode *VAR_INTERNAL; /* variables from make itself */
196GNode *VAR_GLOBAL; /* variables from the makefile */ 196GNode *VAR_GLOBAL; /* variables from the makefile */
197GNode *VAR_CMD; /* variables defined on the command-line */ 197GNode *VAR_CMD; /* variables defined on the command-line */
198 198
199typedef enum { 199typedef enum {
200 FIND_CMD = 0x01, /* look in VAR_CMD when searching */ 200 FIND_CMD = 0x01, /* look in VAR_CMD when searching */
201 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ 201 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */
202 FIND_ENV = 0x04 /* look in the environment also */ 202 FIND_ENV = 0x04 /* look in the environment also */
203} VarFindFlags; 203} VarFindFlags;
204 204
205typedef enum { 205typedef enum {
206 /* The variable's value is currently being used by Var_Parse or Var_Subst. 206 /* The variable's value is currently being used by Var_Parse or Var_Subst.
207 * This marker is used to avoid endless recursion. */ 207 * This marker is used to avoid endless recursion. */
208 VAR_IN_USE = 0x01, 208 VAR_IN_USE = 0x01,
209 /* The variable comes from the environment. 209 /* The variable comes from the environment.
210 * These variables are not registered in any GNode, therefore they must 210 * These variables are not registered in any GNode, therefore they must
211 * be freed as soon as they are not used anymore. */ 211 * be freed as soon as they are not used anymore. */
212 VAR_FROM_ENV = 0x02, 212 VAR_FROM_ENV = 0x02,
213 /* The variable is a junk variable that should be destroyed when done with 213 /* The variable is a junk variable that should be destroyed when done with
214 * it. Used by Var_Parse for undefined, modified variables. */ 214 * it. Used by Var_Parse for undefined, modified variables. */
215 VAR_JUNK = 0x04, 215 VAR_JUNK = 0x04,
216 /* Variable is VAR_JUNK, but we found a use for it in some modifier and 216 /* Variable is VAR_JUNK, but we found a use for it in some modifier and
217 * the value is therefore valid. */ 217 * the value is therefore valid. */
218 VAR_KEEP = 0x08, 218 VAR_KEEP = 0x08,
219 /* The variable is exported to the environment, to be used by child 219 /* The variable is exported to the environment, to be used by child
220 * processes. */ 220 * processes. */
221 VAR_EXPORTED = 0x10, 221 VAR_EXPORTED = 0x10,
222 /* At the point where this variable was exported, it contained an 222 /* At the point where this variable was exported, it contained an
223 * unresolved reference to another variable. Before any child process is 223 * unresolved reference to another variable. Before any child process is
224 * started, it needs to be exported again, in the hope that the referenced 224 * started, it needs to be exported again, in the hope that the referenced
225 * variable can then be resolved. */ 225 * variable can then be resolved. */
226 VAR_REEXPORT = 0x20, 226 VAR_REEXPORT = 0x20,
227 /* The variable came from command line. */ 227 /* The variable came from command line. */
228 VAR_FROM_CMD = 0x40, 228 VAR_FROM_CMD = 0x40,
229 VAR_READONLY = 0x80 229 VAR_READONLY = 0x80
230} VarFlags; 230} VarFlags;
231 231
232ENUM_FLAGS_RTTI_8(VarFlags, 232ENUM_FLAGS_RTTI_8(VarFlags,
233 VAR_IN_USE, VAR_FROM_ENV, VAR_JUNK, VAR_KEEP, 233 VAR_IN_USE, VAR_FROM_ENV, VAR_JUNK, VAR_KEEP,
234 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 234 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
235 235
236typedef struct Var { 236typedef struct Var {
237 char *name; /* the variable's name; it is allocated for 237 char *name; /* the variable's name; it is allocated for
238 * environment variables and aliased to the 238 * environment variables and aliased to the
239 * Hash_Entry name for all other variables, 239 * Hash_Entry name for all other variables,
240 * and thus must not be modified */ 240 * and thus must not be modified */
241 Buffer val; /* its value */ 241 Buffer val; /* its value */
242 VarFlags flags; /* miscellaneous status flags */ 242 VarFlags flags; /* miscellaneous status flags */
243} Var; 243} Var;
244 244
245/* 245/*
246 * Exporting vars is expensive so skip it if we can 246 * Exporting vars is expensive so skip it if we can
247 */ 247 */
248typedef enum { 248typedef enum {
249 VAR_EXPORTED_NONE, 249 VAR_EXPORTED_NONE,
250 VAR_EXPORTED_YES, 250 VAR_EXPORTED_YES,
251 VAR_EXPORTED_ALL 251 VAR_EXPORTED_ALL
252} VarExportedMode; 252} VarExportedMode;
253 253
254static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 254static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
255 255
256typedef enum { 256typedef enum {
257 /* 257 /*
258 * We pass this to Var_Export when doing the initial export 258 * We pass this to Var_Export when doing the initial export
259 * or after updating an exported var. 259 * or after updating an exported var.
260 */ 260 */
261 VAR_EXPORT_PARENT = 0x01, 261 VAR_EXPORT_PARENT = 0x01,
262 /* 262 /*
263 * We pass this to Var_Export1 to tell it to leave the value alone. 263 * We pass this to Var_Export1 to tell it to leave the value alone.
264 */ 264 */
265 VAR_EXPORT_LITERAL = 0x02 265 VAR_EXPORT_LITERAL = 0x02
266} VarExportFlags; 266} VarExportFlags;
267 267
268/* Flags for pattern matching in the :S and :C modifiers */ 268/* Flags for pattern matching in the :S and :C modifiers */
269typedef enum { 269typedef enum {
270 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */ 270 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */
271 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */ 271 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */
272 VARP_ANCHOR_START = 0x04, /* Match at start of word */ 272 VARP_ANCHOR_START = 0x04, /* Match at start of word */
273 VARP_ANCHOR_END = 0x08 /* Match at end of word */ 273 VARP_ANCHOR_END = 0x08 /* Match at end of word */
274} VarPatternFlags; 274} VarPatternFlags;
275 275
276#define BROPEN '{' 276#define BROPEN '{'
277#define BRCLOSE '}' 277#define BRCLOSE '}'
278#define PROPEN '(' 278#define PROPEN '('
279#define PRCLOSE ')' 279#define PRCLOSE ')'
280 280
281/*- 281/*-
282 *----------------------------------------------------------------------- 282 *-----------------------------------------------------------------------
283 * VarFind -- 283 * VarFind --
284 * Find the given variable in the given context and any other contexts 284 * Find the given variable in the given context and any other contexts
285 * indicated. 285 * indicated.
286 * 286 *
287 * Input: 287 * Input:
288 * name name to find 288 * name name to find
289 * ctxt context in which to find it 289 * ctxt context in which to find it
290 * flags FIND_GLOBAL look in VAR_GLOBAL as well 290 * flags FIND_GLOBAL look in VAR_GLOBAL as well
291 * FIND_CMD look in VAR_CMD as well 291 * FIND_CMD look in VAR_CMD as well
292 * FIND_ENV look in the environment as well 292 * FIND_ENV look in the environment as well
293 * 293 *
294 * Results: 294 * Results:
295 * A pointer to the structure describing the desired variable or 295 * A pointer to the structure describing the desired variable or
296 * NULL if the variable does not exist. 296 * NULL if the variable does not exist.
297 * 297 *
298 * Side Effects: 298 * Side Effects:
299 * None 299 * None
300 *----------------------------------------------------------------------- 300 *-----------------------------------------------------------------------
301 */ 301 */
302static Var * 302static Var *
303VarFind(const char *name, GNode *ctxt, VarFindFlags flags) 303VarFind(const char *name, GNode *ctxt, VarFindFlags flags)
304{ 304{
305 Hash_Entry *var; 305 Hash_Entry *var;
306 306
307 /* 307 /*
308 * If the variable name begins with a '.', it could very well be one of 308 * If the variable name begins with a '.', it could very well be one of
309 * the local ones. We check the name against all the local variables 309 * the local ones. We check the name against all the local variables
310 * and substitute the short version in for 'name' if it matches one of 310 * and substitute the short version in for 'name' if it matches one of
311 * them. 311 * them.
312 */ 312 */
313 if (*name == '.' && isupper((unsigned char)name[1])) { 313 if (*name == '.' && isupper((unsigned char)name[1])) {
314 switch (name[1]) { 314 switch (name[1]) {
315 case 'A': 315 case 'A':
316 if (strcmp(name, ".ALLSRC") == 0) 316 if (strcmp(name, ".ALLSRC") == 0)
317 name = ALLSRC; 317 name = ALLSRC;
318 if (strcmp(name, ".ARCHIVE") == 0) 318 if (strcmp(name, ".ARCHIVE") == 0)
319 name = ARCHIVE; 319 name = ARCHIVE;
320 break; 320 break;
321 case 'I': 321 case 'I':
322 if (strcmp(name, ".IMPSRC") == 0) 322 if (strcmp(name, ".IMPSRC") == 0)
323 name = IMPSRC; 323 name = IMPSRC;
324 break; 324 break;
325 case 'M': 325 case 'M':
326 if (strcmp(name, ".MEMBER") == 0) 326 if (strcmp(name, ".MEMBER") == 0)
327 name = MEMBER; 327 name = MEMBER;
328 break; 328 break;
329 case 'O': 329 case 'O':
330 if (strcmp(name, ".OODATE") == 0) 330 if (strcmp(name, ".OODATE") == 0)
331 name = OODATE; 331 name = OODATE;
332 break; 332 break;
333 case 'P': 333 case 'P':
334 if (strcmp(name, ".PREFIX") == 0) 334 if (strcmp(name, ".PREFIX") == 0)
335 name = PREFIX; 335 name = PREFIX;
336 break; 336 break;
337 case 'S': 337 case 'S':
338 if (strcmp(name, ".SHELL") == 0 ) { 338 if (strcmp(name, ".SHELL") == 0 ) {
339 if (!shellPath) 339 if (!shellPath)
340 Shell_Init(); 340 Shell_Init();
341 } 341 }
342 break; 342 break;
343 case 'T': 343 case 'T':
344 if (strcmp(name, ".TARGET") == 0) 344 if (strcmp(name, ".TARGET") == 0)
345 name = TARGET; 345 name = TARGET;
346 break; 346 break;
347 } 347 }
348 } 348 }
349 349
350#ifdef notyet 350#ifdef notyet
351 /* for compatibility with gmake */ 351 /* for compatibility with gmake */
352 if (name[0] == '^' && name[1] == '\0') 352 if (name[0] == '^' && name[1] == '\0')
353 name = ALLSRC; 353 name = ALLSRC;
354#endif 354#endif
355 355
356 /* 356 /*
357 * First look for the variable in the given context. If it's not there, 357 * First look for the variable in the given context. If it's not there,
358 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 358 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
359 * depending on the FIND_* flags in 'flags' 359 * depending on the FIND_* flags in 'flags'
360 */ 360 */
361 var = Hash_FindEntry(&ctxt->context, name); 361 var = Hash_FindEntry(&ctxt->context, name);
362 362
363 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) 363 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD)
364 var = Hash_FindEntry(&VAR_CMD->context, name); 364 var = Hash_FindEntry(&VAR_CMD->context, name);
365 365
366 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && 366 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
367 ctxt != VAR_GLOBAL) 367 ctxt != VAR_GLOBAL)
368 { 368 {
369 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 369 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
370 if (var == NULL && ctxt != VAR_INTERNAL) { 370 if (var == NULL && ctxt != VAR_INTERNAL) {
371 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 371 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
372 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 372 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
373 } 373 }
374 } 374 }
375 375
376 if (var == NULL && (flags & FIND_ENV)) { 376 if (var == NULL && (flags & FIND_ENV)) {
377 char *env; 377 char *env;
378 378
379 if ((env = getenv(name)) != NULL) { 379 if ((env = getenv(name)) != NULL) {
380 Var *v = bmake_malloc(sizeof(Var)); 380 Var *v = bmake_malloc(sizeof(Var));
381 size_t len; 381 size_t len;
382 v->name = bmake_strdup(name); 382 v->name = bmake_strdup(name);
383 383
384 len = strlen(env); 384 len = strlen(env);
385 Buf_Init(&v->val, len + 1); 385 Buf_Init(&v->val, len + 1);
386 Buf_AddBytes(&v->val, env, len); 386 Buf_AddBytes(&v->val, env, len);
387 387
388 v->flags = VAR_FROM_ENV; 388 v->flags = VAR_FROM_ENV;
389 return v; 389 return v;
390 } 390 }
391 391
392 if (checkEnvFirst && (flags & FIND_GLOBAL) && ctxt != VAR_GLOBAL) { 392 if (checkEnvFirst && (flags & FIND_GLOBAL) && ctxt != VAR_GLOBAL) {
393 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 393 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
394 if (var == NULL && ctxt != VAR_INTERNAL) 394 if (var == NULL && ctxt != VAR_INTERNAL)
395 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 395 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
396 if (var == NULL) 396 if (var == NULL)
397 return NULL; 397 return NULL;
398 else 398 else
399 return (Var *)Hash_GetValue(var); 399 return (Var *)Hash_GetValue(var);
400 } 400 }
401 401
402 return NULL; 402 return NULL;
403 } 403 }
404 404
405 if (var == NULL) 405 if (var == NULL)
406 return NULL; 406 return NULL;
407 else 407 else
408 return (Var *)Hash_GetValue(var); 408 return (Var *)Hash_GetValue(var);
409} 409}
410 410
411/*- 411/*-
412 *----------------------------------------------------------------------- 412 *-----------------------------------------------------------------------
413 * VarFreeEnv -- 413 * VarFreeEnv --
414 * If the variable is an environment variable, free it 414 * If the variable is an environment variable, free it
415 * 415 *
416 * Input: 416 * Input:
417 * v the variable 417 * v the variable
418 * destroy true if the value buffer should be destroyed. 418 * destroy true if the value buffer should be destroyed.
419 * 419 *
420 * Results: 420 * Results:
421 * TRUE if it is an environment variable, FALSE otherwise. 421 * TRUE if it is an environment variable, FALSE otherwise.
422 *----------------------------------------------------------------------- 422 *-----------------------------------------------------------------------
423 */ 423 */
424static Boolean 424static Boolean
425VarFreeEnv(Var *v, Boolean destroy) 425VarFreeEnv(Var *v, Boolean destroy)
426{ 426{
427 if (!(v->flags & VAR_FROM_ENV)) 427 if (!(v->flags & VAR_FROM_ENV))
428 return FALSE; 428 return FALSE;
429 free(v->name); 429 free(v->name);
430 Buf_Destroy(&v->val, destroy); 430 Buf_Destroy(&v->val, destroy);
431 free(v); 431 free(v);
432 return TRUE; 432 return TRUE;
433} 433}
434 434
435/* Add a new variable of the given name and value to the given context. 435/* Add a new variable of the given name and value to the given context.
436 * The name and val arguments are duplicated so they may safely be freed. */ 436 * The name and val arguments are duplicated so they may safely be freed. */
437static void 437static void
438VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 438VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
439{ 439{
440 Var *v = bmake_malloc(sizeof(Var)); 440 Var *v = bmake_malloc(sizeof(Var));
441 size_t len = strlen(val); 441 size_t len = strlen(val);
442 Hash_Entry *he; 442 Hash_Entry *he;
443 443
444 Buf_Init(&v->val, len + 1); 444 Buf_Init(&v->val, len + 1);
445 Buf_AddBytes(&v->val, val, len); 445 Buf_AddBytes(&v->val, val, len);
446 446
447 v->flags = 0; 447 v->flags = 0;
448 if (flags & VAR_SET_READONLY) 448 if (flags & VAR_SET_READONLY)
449 v->flags |= VAR_READONLY; 449 v->flags |= VAR_READONLY;
450 450
451 he = Hash_CreateEntry(&ctxt->context, name, NULL); 451 he = Hash_CreateEntry(&ctxt->context, name, NULL);
452 Hash_SetValue(he, v); 452 Hash_SetValue(he, v);
453 v->name = he->name; 453 v->name = he->name;
454 VAR_DEBUG_IF(!(ctxt->flags & INTERNAL), 454 VAR_DEBUG_IF(!(ctxt->flags & INTERNAL),
455 "%s:%s = %s\n", ctxt->name, name, val); 455 "%s:%s = %s\n", ctxt->name, name, val);
456} 456}
457 457
458/* Remove a variable from a context, freeing the Var structure as well. */ 458/* Remove a variable from a context, freeing the Var structure as well. */
459void 459void
460Var_Delete(const char *name, GNode *ctxt) 460Var_Delete(const char *name, GNode *ctxt)
461{ 461{
462 char *name_freeIt = NULL; 462 char *name_freeIt = NULL;
463 Hash_Entry *he; 463 Hash_Entry *he;
464 464
465 if (strchr(name, '$') != NULL) 465 if (strchr(name, '$') != NULL)
466 name = name_freeIt = Var_Subst(name, VAR_GLOBAL, VARE_WANTRES); 466 name = name_freeIt = Var_Subst(name, VAR_GLOBAL, VARE_WANTRES);
467 he = Hash_FindEntry(&ctxt->context, name); 467 he = Hash_FindEntry(&ctxt->context, name);
468 VAR_DEBUG("%s:delete %s%s\n", 468 VAR_DEBUG("%s:delete %s%s\n",
469 ctxt->name, name, he != NULL ? "" : " (not found)"); 469 ctxt->name, name, he != NULL ? "" : " (not found)");
470 free(name_freeIt); 470 free(name_freeIt);
471 471
472 if (he != NULL) { 472 if (he != NULL) {
473 Var *v = (Var *)Hash_GetValue(he); 473 Var *v = (Var *)Hash_GetValue(he);
474 if (v->flags & VAR_EXPORTED) 474 if (v->flags & VAR_EXPORTED)
475 unsetenv(v->name); 475 unsetenv(v->name);
476 if (strcmp(v->name, MAKE_EXPORTED) == 0) 476 if (strcmp(v->name, MAKE_EXPORTED) == 0)
477 var_exportedVars = VAR_EXPORTED_NONE; 477 var_exportedVars = VAR_EXPORTED_NONE;
478 if (v->name != he->name) 478 if (v->name != he->name)
479 free(v->name); 479 free(v->name);
480 Hash_DeleteEntry(&ctxt->context, he); 480 Hash_DeleteEntry(&ctxt->context, he);
481 Buf_Destroy(&v->val, TRUE); 481 Buf_Destroy(&v->val, TRUE);
482 free(v); 482 free(v);
483 } 483 }
484} 484}
485 485
486 486
487/* 487/*
488 * Export a single variable. 488 * Export a single variable.
489 * We ignore make internal variables (those which start with '.'). 489 * We ignore make internal variables (those which start with '.').
490 * Also we jump through some hoops to avoid calling setenv 490 * Also we jump through some hoops to avoid calling setenv
491 * more than necessary since it can leak. 491 * more than necessary since it can leak.
492 * We only manipulate flags of vars if 'parent' is set. 492 * We only manipulate flags of vars if 'parent' is set.
493 */ 493 */
494static Boolean 494static Boolean
495Var_Export1(const char *name, VarExportFlags flags) 495Var_Export1(const char *name, VarExportFlags flags)
496{ 496{
497 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 497 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
498 Var *v; 498 Var *v;
499 char *val; 499 char *val;
500 500
501 if (name[0] == '.') 501 if (name[0] == '.')
502 return FALSE; /* skip internals */ 502 return FALSE; /* skip internals */
503 if (name[1] == '\0') { 503 if (name[1] == '\0') {
504 /* 504 /*
505 * A single char. 505 * A single char.
506 * If it is one of the vars that should only appear in 506 * If it is one of the vars that should only appear in
507 * local context, skip it, else we can get Var_Subst 507 * local context, skip it, else we can get Var_Subst
508 * into a loop. 508 * into a loop.
509 */ 509 */
510 switch (name[0]) { 510 switch (name[0]) {
511 case '@': 511 case '@':
512 case '%': 512 case '%':
513 case '*': 513 case '*':
514 case '!': 514 case '!':
515 return FALSE; 515 return FALSE;
516 } 516 }
517 } 517 }
518 518
519 v = VarFind(name, VAR_GLOBAL, 0); 519 v = VarFind(name, VAR_GLOBAL, 0);
520 if (v == NULL) 520 if (v == NULL)
521 return FALSE; 521 return FALSE;
522 522
523 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 523 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
524 return FALSE; /* nothing to do */ 524 return FALSE; /* nothing to do */
525 525
526 val = Buf_GetAll(&v->val, NULL); 526 val = Buf_GetAll(&v->val, NULL);
527 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 527 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
528 char *expr; 528 char *expr;
529 529
530 if (parent) { 530 if (parent) {
531 /* 531 /*
532 * Flag this as something we need to re-export. 532 * Flag this as something we need to re-export.
533 * No point actually exporting it now though, 533 * No point actually exporting it now though,
534 * the child can do it at the last minute. 534 * the child can do it at the last minute.
535 */ 535 */
536 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 536 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
537 return TRUE; 537 return TRUE;
538 } 538 }
539 if (v->flags & VAR_IN_USE) { 539 if (v->flags & VAR_IN_USE) {
540 /* 540 /*
541 * We recursed while exporting in a child. 541 * We recursed while exporting in a child.
542 * This isn't going to end well, just skip it. 542 * This isn't going to end well, just skip it.
543 */ 543 */
544 return FALSE; 544 return FALSE;
545 } 545 }
546 546
547 expr = str_concat3("${", name, "}"); 547 expr = str_concat3("${", name, "}");
548 val = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); 548 val = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES);
549 setenv(name, val, 1); 549 setenv(name, val, 1);
550 free(val); 550 free(val);
551 free(expr); 551 free(expr);
552 } else { 552 } else {
553 if (parent) 553 if (parent)
554 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 554 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
555 if (parent || !(v->flags & VAR_EXPORTED)) 555 if (parent || !(v->flags & VAR_EXPORTED))
556 setenv(name, val, 1); 556 setenv(name, val, 1);
557 } 557 }
558 /* 558 /*
559 * This is so Var_Set knows to call Var_Export again... 559 * This is so Var_Set knows to call Var_Export again...
560 */ 560 */
561 if (parent) { 561 if (parent) {
562 v->flags |= VAR_EXPORTED; 562 v->flags |= VAR_EXPORTED;
563 } 563 }
564 return TRUE; 564 return TRUE;
565} 565}
566 566
567static void 567static void
568Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED) 568Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
569{ 569{
570 Var *var = entry; 570 Var *var = entry;
571 Var_Export1(var->name, 0); 571 Var_Export1(var->name, 0);
572} 572}
573 573
574/* 574/*
575 * This gets called from our children. 575 * This gets called from our children.
576 */ 576 */
577void 577void
578Var_ExportVars(void) 578Var_ExportVars(void)
579{ 579{
580 char *val; 580 char *val;
581 581
582 /* 582 /*
583 * Several make's support this sort of mechanism for tracking 583 * Several make's support this sort of mechanism for tracking
584 * recursion - but each uses a different name. 584 * recursion - but each uses a different name.
585 * We allow the makefiles to update MAKELEVEL and ensure 585 * We allow the makefiles to update MAKELEVEL and ensure
586 * children see a correctly incremented value. 586 * children see a correctly incremented value.
587 */ 587 */
588 char tmp[BUFSIZ]; 588 char tmp[BUFSIZ];
589 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 589 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
590 setenv(MAKE_LEVEL_ENV, tmp, 1); 590 setenv(MAKE_LEVEL_ENV, tmp, 1);
591 591
592 if (var_exportedVars == VAR_EXPORTED_NONE) 592 if (var_exportedVars == VAR_EXPORTED_NONE)
593 return; 593 return;
594 594
595 if (var_exportedVars == VAR_EXPORTED_ALL) { 595 if (var_exportedVars == VAR_EXPORTED_ALL) {
596 /* Ouch! This is crazy... */ 596 /* Ouch! This is crazy... */
597 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); 597 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
598 return; 598 return;
599 } 599 }
600 600
601 val = Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES); 601 val = Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES);
602 if (*val) { 602 if (*val) {
603 Words words = Str_Words(val, FALSE); 603 Words words = Str_Words(val, FALSE);
604 size_t i; 604 size_t i;
605 605
606 for (i = 0; i < words.len; i++) 606 for (i = 0; i < words.len; i++)
607 Var_Export1(words.words[i], 0); 607 Var_Export1(words.words[i], 0);
608 Words_Free(words); 608 Words_Free(words);
609 } 609 }
610 free(val); 610 free(val);
611} 611}
612 612
613/* 613/*
614 * This is called when .export is seen or .MAKE.EXPORTED is modified. 614 * This is called when .export is seen or .MAKE.EXPORTED is modified.
615 * 615 *
616 * It is also called when any exported variable is modified. 616 * It is also called when any exported variable is modified.
617 * XXX: Is it really? 617 * XXX: Is it really?
618 * 618 *
619 * str has the format "[-env|-literal] varname...". 619 * str has the format "[-env|-literal] varname...".
620 */ 620 */
621void 621void
622Var_Export(const char *str, Boolean isExport) 622Var_Export(const char *str, Boolean isExport)
623{ 623{
624 VarExportFlags flags; 624 VarExportFlags flags;
625 char *val; 625 char *val;
626 626
627 if (isExport && str[0] == '\0') { 627 if (isExport && str[0] == '\0') {
628 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 628 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
629 return; 629 return;
630 } 630 }
631 631
632 flags = 0; 632 flags = 0;
633 if (strncmp(str, "-env", 4) == 0) { 633 if (strncmp(str, "-env", 4) == 0) {
634 str += 4; 634 str += 4;
635 } else if (strncmp(str, "-literal", 8) == 0) { 635 } else if (strncmp(str, "-literal", 8) == 0) {
636 str += 8; 636 str += 8;
637 flags |= VAR_EXPORT_LITERAL; 637 flags |= VAR_EXPORT_LITERAL;
638 } else { 638 } else {
639 flags |= VAR_EXPORT_PARENT; 639 flags |= VAR_EXPORT_PARENT;
640 } 640 }
641 641
642 val = Var_Subst(str, VAR_GLOBAL, VARE_WANTRES); 642 val = Var_Subst(str, VAR_GLOBAL, VARE_WANTRES);
643 if (val[0] != '\0') { 643 if (val[0] != '\0') {
644 Words words = Str_Words(val, FALSE); 644 Words words = Str_Words(val, FALSE);
645 645
646 size_t i; 646 size_t i;
647 for (i = 0; i < words.len; i++) { 647 for (i = 0; i < words.len; i++) {
648 const char *name = words.words[i]; 648 const char *name = words.words[i];
649 if (Var_Export1(name, flags)) { 649 if (Var_Export1(name, flags)) {
650 if (var_exportedVars != VAR_EXPORTED_ALL) 650 if (var_exportedVars != VAR_EXPORTED_ALL)
651 var_exportedVars = VAR_EXPORTED_YES; 651 var_exportedVars = VAR_EXPORTED_YES;
652 if (isExport && (flags & VAR_EXPORT_PARENT)) { 652 if (isExport && (flags & VAR_EXPORT_PARENT)) {
653 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 653 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
654 } 654 }
655 } 655 }
656 } 656 }
657 Words_Free(words); 657 Words_Free(words);
658 } 658 }
659 free(val); 659 free(val);
660} 660}
661 661
662 662
663extern char **environ; 663extern char **environ;
664 664
665/* 665/*
666 * This is called when .unexport[-env] is seen. 666 * This is called when .unexport[-env] is seen.
667 * 667 *
668 * str must have the form "unexport[-env] varname...". 668 * str must have the form "unexport[-env] varname...".
669 */ 669 */
670void 670void
671Var_UnExport(const char *str) 671Var_UnExport(const char *str)
672{ 672{
673 const char *varnames; 673 const char *varnames;
674 char *varnames_freeIt; 674 char *varnames_freeIt;
675 Boolean unexport_env; 675 Boolean unexport_env;
676 676
677 varnames = NULL; 677 varnames = NULL;
678 varnames_freeIt = NULL; 678 varnames_freeIt = NULL;
679 679
680 str += strlen("unexport"); 680 str += strlen("unexport");
681 unexport_env = strncmp(str, "-env", 4) == 0; 681 unexport_env = strncmp(str, "-env", 4) == 0;
682 if (unexport_env) { 682 if (unexport_env) {
683 const char *cp; 683 const char *cp;
684 char **newenv; 684 char **newenv;
685 685
686 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 686 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
687 if (environ == savedEnv) { 687 if (environ == savedEnv) {
688 /* we have been here before! */ 688 /* we have been here before! */
689 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 689 newenv = bmake_realloc(environ, 2 * sizeof(char *));
690 } else { 690 } else {
691 if (savedEnv) { 691 if (savedEnv) {
692 free(savedEnv); 692 free(savedEnv);
693 savedEnv = NULL; 693 savedEnv = NULL;
694 } 694 }
695 newenv = bmake_malloc(2 * sizeof(char *)); 695 newenv = bmake_malloc(2 * sizeof(char *));
696 } 696 }
697 697
698 /* Note: we cannot safely free() the original environ. */ 698 /* Note: we cannot safely free() the original environ. */
699 environ = savedEnv = newenv; 699 environ = savedEnv = newenv;
700 newenv[0] = NULL; 700 newenv[0] = NULL;
701 newenv[1] = NULL; 701 newenv[1] = NULL;
702 if (cp && *cp) 702 if (cp && *cp)
703 setenv(MAKE_LEVEL_ENV, cp, 1); 703 setenv(MAKE_LEVEL_ENV, cp, 1);
704 } else { 704 } else {
705 for (; isspace((unsigned char)*str); str++) 705 for (; isspace((unsigned char)*str); str++)
706 continue; 706 continue;
707 if (str[0] != '\0') 707 if (str[0] != '\0')
708 varnames = str; 708 varnames = str;
709 } 709 }
710 710
711 if (varnames == NULL) { 711 if (varnames == NULL) {
712 /* Using .MAKE.EXPORTED */ 712 /* Using .MAKE.EXPORTED */
713 varnames = varnames_freeIt = Var_Subst("${" MAKE_EXPORTED ":O:u}", 713 varnames = varnames_freeIt = Var_Subst("${" MAKE_EXPORTED ":O:u}",
714 VAR_GLOBAL, VARE_WANTRES); 714 VAR_GLOBAL, VARE_WANTRES);
715 } 715 }
716 716
717 { 717 {
718 Var *v; 718 Var *v;
719 size_t i; 719 size_t i;
720 720
721 Words words = Str_Words(varnames, FALSE); 721 Words words = Str_Words(varnames, FALSE);
722 for (i = 0; i < words.len; i++) { 722 for (i = 0; i < words.len; i++) {
723 const char *varname = words.words[i]; 723 const char *varname = words.words[i];
724 v = VarFind(varname, VAR_GLOBAL, 0); 724 v = VarFind(varname, VAR_GLOBAL, 0);
725 if (v == NULL) { 725 if (v == NULL) {
726 VAR_DEBUG("Not unexporting \"%s\" (not found)\n", varname); 726 VAR_DEBUG("Not unexporting \"%s\" (not found)\n", varname);
727 continue; 727 continue;
728 } 728 }
729 729
730 VAR_DEBUG("Unexporting \"%s\"\n", varname); 730 VAR_DEBUG("Unexporting \"%s\"\n", varname);
731 if (!unexport_env && (v->flags & VAR_EXPORTED) && 731 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
732 !(v->flags & VAR_REEXPORT)) 732 !(v->flags & VAR_REEXPORT))
733 unsetenv(v->name); 733 unsetenv(v->name);
734 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 734 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
735 735
736 /* 736 /*
737 * If we are unexporting a list, 737 * If we are unexporting a list,
738 * remove each one from .MAKE.EXPORTED. 738 * remove each one from .MAKE.EXPORTED.
739 * If we are removing them all, 739 * If we are removing them all,
740 * just delete .MAKE.EXPORTED below. 740 * just delete .MAKE.EXPORTED below.
741 */ 741 */
742 if (varnames == str) { 742 if (varnames == str) {
743 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 743 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
744 char *cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); 744 char *cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES);
745 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 745 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
746 free(cp); 746 free(cp);
747 free(expr); 747 free(expr);
748 } 748 }
749 } 749 }
750 Words_Free(words); 750 Words_Free(words);
751 if (varnames != str) { 751 if (varnames != str) {
752 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 752 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
753 free(varnames_freeIt); 753 free(varnames_freeIt);
754 } 754 }
755 } 755 }
756} 756}
757 757
758/* See Var_Set for documentation. */ 758/* See Var_Set for documentation. */
759void 759void
760Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 760Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
761 VarSet_Flags flags) 761 VarSet_Flags flags)
762{ 762{
763 const char *unexpanded_name = name; 763 const char *unexpanded_name = name;
764 char *name_freeIt = NULL; 764 char *name_freeIt = NULL;
765 Var *v; 765 Var *v;
766 766
767 assert(val != NULL); 767 assert(val != NULL);
768 768
769 /* 769 /*
770 * We only look for a variable in the given context since anything set 770 * We only look for a variable in the given context since anything set
771 * here will override anything in a lower context, so there's not much 771 * here will override anything in a lower context, so there's not much
772 * point in searching them all just to save a bit of memory... 772 * point in searching them all just to save a bit of memory...
773 */ 773 */
774 if (strchr(name, '$') != NULL) 774 if (strchr(name, '$') != NULL)
775 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES); 775 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES);
776 776
777 if (name[0] == '\0') { 777 if (name[0] == '\0') {
778 VAR_DEBUG("Var_Set(\"%s\", \"%s\", ...) " 778 VAR_DEBUG("Var_Set(\"%s\", \"%s\", ...) "
779 "name expands to empty string - ignored\n", 779 "name expands to empty string - ignored\n",
780 unexpanded_name, val); 780 unexpanded_name, val);
781 free(name_freeIt); 781 free(name_freeIt);
782 return; 782 return;
783 } 783 }
784 784
785 if (ctxt == VAR_GLOBAL) { 785 if (ctxt == VAR_GLOBAL) {
786 v = VarFind(name, VAR_CMD, 0); 786 v = VarFind(name, VAR_CMD, 0);
787 if (v != NULL) { 787 if (v != NULL) {
788 if (v->flags & VAR_FROM_CMD) { 788 if (v->flags & VAR_FROM_CMD) {
789 VAR_DEBUG("%s:%s = %s ignored!\n", ctxt->name, name, val); 789 VAR_DEBUG("%s:%s = %s ignored!\n", ctxt->name, name, val);
790 goto out; 790 goto out;
791 } 791 }
792 VarFreeEnv(v, TRUE); 792 VarFreeEnv(v, TRUE);
793 } 793 }
794 } 794 }
795 795
796 v = VarFind(name, ctxt, 0); 796 v = VarFind(name, ctxt, 0);
797 if (v == NULL) { 797 if (v == NULL) {
798 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT)) { 798 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT)) {
799 /* 799 /*
800 * This var would normally prevent the same name being added 800 * This var would normally prevent the same name being added
801 * to VAR_GLOBAL, so delete it from there if needed. 801 * to VAR_GLOBAL, so delete it from there if needed.
802 * Otherwise -V name may show the wrong value. 802 * Otherwise -V name may show the wrong value.
803 */ 803 */
804 Var_Delete(name, VAR_GLOBAL); 804 Var_Delete(name, VAR_GLOBAL);
805 } 805 }
806 VarAdd(name, val, ctxt, flags); 806 VarAdd(name, val, ctxt, flags);
807 } else { 807 } else {
808 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 808 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
809 VAR_DEBUG("%s:%s = %s ignored (read-only)\n", 809 VAR_DEBUG("%s:%s = %s ignored (read-only)\n",
810 ctxt->name, name, val); 810 ctxt->name, name, val);
811 goto out; 811 goto out;
812 }  812 }
813 Buf_Empty(&v->val); 813 Buf_Empty(&v->val);
814 if (val) 814 if (val)
815 Buf_AddStr(&v->val, val); 815 Buf_AddStr(&v->val, val);
816 816
817 VAR_DEBUG("%s:%s = %s\n", ctxt->name, name, val); 817 VAR_DEBUG("%s:%s = %s\n", ctxt->name, name, val);
818 if (v->flags & VAR_EXPORTED) { 818 if (v->flags & VAR_EXPORTED) {
819 Var_Export1(name, VAR_EXPORT_PARENT); 819 Var_Export1(name, VAR_EXPORT_PARENT);
820 } 820 }
821 } 821 }
822 /* 822 /*
823 * Any variables given on the command line are automatically exported 823 * Any variables given on the command line are automatically exported
824 * to the environment (as per POSIX standard) 824 * to the environment (as per POSIX standard)
825 * Other than internals. 825 * Other than internals.
826 */ 826 */
827 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 827 if (ctxt == VAR_CMD && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
828 if (v == NULL) { 828 if (v == NULL) {
829 /* we just added it */ 829 /* we just added it */
830 v = VarFind(name, ctxt, 0); 830 v = VarFind(name, ctxt, 0);
831 } 831 }
832 if (v != NULL) 832 if (v != NULL)
833 v->flags |= VAR_FROM_CMD; 833 v->flags |= VAR_FROM_CMD;
834 /* 834 /*
835 * If requested, don't export these in the environment 835 * If requested, don't export these in the environment
836 * individually. We still put them in MAKEOVERRIDES so 836 * individually. We still put them in MAKEOVERRIDES so
837 * that the command-line settings continue to override 837 * that the command-line settings continue to override
838 * Makefile settings. 838 * Makefile settings.
839 */ 839 */
840 if (!varNoExportEnv) 840 if (!varNoExportEnv)
841 setenv(name, val ? val : "", 1); 841 setenv(name, val ? val : "", 1);
842 842
843 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 843 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
844 } 844 }
845 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0) 845 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0)
846 save_dollars = s2Boolean(val, save_dollars); 846 save_dollars = s2Boolean(val, save_dollars);
847 847
848out: 848out:
849 free(name_freeIt); 849 free(name_freeIt);
850 if (v != NULL) 850 if (v != NULL)
851 VarFreeEnv(v, TRUE); 851 VarFreeEnv(v, TRUE);
852} 852}
853 853
854/*- 854/*-
855 *----------------------------------------------------------------------- 855 *-----------------------------------------------------------------------
856 * Var_Set -- 856 * Var_Set --
857 * Set the variable name to the value val in the given context. 857 * Set the variable name to the value val in the given context.
858 * 858 *
859 * Input: 859 * Input:
860 * name name of variable to set 860 * name name of variable to set
861 * val value to give to the variable 861 * val value to give to the variable
862 * ctxt context in which to set it 862 * ctxt context in which to set it
863 * 863 *
864 * Side Effects: 864 * Side Effects:
865 * If the variable doesn't yet exist, it is created. 865 * If the variable doesn't yet exist, it is created.
866 * Otherwise the new value overwrites and replaces the old value. 866 * Otherwise the new value overwrites and replaces the old value.
867 * 867 *
868 * Notes: 868 * Notes:
869 * The variable is searched for only in its context before being 869 * The variable is searched for only in its context before being
870 * created in that context. I.e. if the context is VAR_GLOBAL, 870 * created in that context. I.e. if the context is VAR_GLOBAL,
871 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 871 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
872 * VAR_CMD->context is searched. This is done to avoid the literally 872 * VAR_CMD->context is searched. This is done to avoid the literally
873 * thousands of unnecessary strcmp's that used to be done to 873 * thousands of unnecessary strcmp's that used to be done to
874 * set, say, $(@) or $(<). 874 * set, say, $(@) or $(<).
875 * If the context is VAR_GLOBAL though, we check if the variable 875 * If the context is VAR_GLOBAL though, we check if the variable
876 * was set in VAR_CMD from the command line and skip it if so. 876 * was set in VAR_CMD from the command line and skip it if so.
877 *----------------------------------------------------------------------- 877 *-----------------------------------------------------------------------
878 */ 878 */
879void 879void
880Var_Set(const char *name, const char *val, GNode *ctxt) 880Var_Set(const char *name, const char *val, GNode *ctxt)
881{ 881{
882 Var_Set_with_flags(name, val, ctxt, 0); 882 Var_Set_with_flags(name, val, ctxt, 0);
883} 883}
884 884
885/*- 885/*-
886 *----------------------------------------------------------------------- 886 *-----------------------------------------------------------------------
887 * Var_Append -- 887 * Var_Append --
888 * The variable of the given name has the given value appended to it in 888 * The variable of the given name has the given value appended to it in
889 * the given context. 889 * the given context.
890 * 890 *
891 * Input: 891 * Input:
892 * name name of variable to modify 892 * name name of variable to modify
893 * val string to append to it 893 * val string to append to it
894 * ctxt context in which this should occur 894 * ctxt context in which this should occur
895 * 895 *
896 * Side Effects: 896 * Side Effects:
897 * If the variable doesn't exist, it is created. Otherwise the strings 897 * If the variable doesn't exist, it is created. Otherwise the strings
898 * are concatenated, with a space in between. 898 * are concatenated, with a space in between.
899 * 899 *
900 * Notes: 900 * Notes:
901 * Only if the variable is being sought in the global context is the 901 * Only if the variable is being sought in the global context is the
902 * environment searched. 902 * environment searched.
903 * XXX: Knows its calling circumstances in that if called with ctxt 903 * XXX: Knows its calling circumstances in that if called with ctxt
904 * an actual target, it will only search that context since only 904 * an actual target, it will only search that context since only
905 * a local variable could be being appended to. This is actually 905 * a local variable could be being appended to. This is actually
906 * a big win and must be tolerated. 906 * a big win and must be tolerated.
907 *----------------------------------------------------------------------- 907 *-----------------------------------------------------------------------
908 */ 908 */
909void 909void
910Var_Append(const char *name, const char *val, GNode *ctxt) 910Var_Append(const char *name, const char *val, GNode *ctxt)
911{ 911{
912 char *name_freeIt = NULL; 912 char *name_freeIt = NULL;
913 Var *v; 913 Var *v;
914 914
915 assert(val != NULL); 915 assert(val != NULL);
916 916
917 if (strchr(name, '$') != NULL) { 917 if (strchr(name, '$') != NULL) {
918 const char *unexpanded_name = name; 918 const char *unexpanded_name = name;
919 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES); 919 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES);
920 if (name[0] == '\0') { 920 if (name[0] == '\0') {
921 VAR_DEBUG("Var_Append(\"%s\", \"%s\", ...) " 921 VAR_DEBUG("Var_Append(\"%s\", \"%s\", ...) "
922 "name expands to empty string - ignored\n", 922 "name expands to empty string - ignored\n",
923 unexpanded_name, val); 923 unexpanded_name, val);
924 free(name_freeIt); 924 free(name_freeIt);
925 return; 925 return;
926 } 926 }
927 } 927 }
928 928
929 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); 929 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0);
930 930
931 if (v == NULL) { 931 if (v == NULL) {
932 Var_Set(name, val, ctxt); 932 Var_Set(name, val, ctxt);
933 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { 933 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
934 Buf_AddByte(&v->val, ' '); 934 Buf_AddByte(&v->val, ' ');
935 Buf_AddStr(&v->val, val); 935 Buf_AddStr(&v->val, val);
936 936
937 VAR_DEBUG("%s:%s = %s\n", ctxt->name, name, 937 VAR_DEBUG("%s:%s = %s\n", ctxt->name, name,
938 Buf_GetAll(&v->val, NULL)); 938 Buf_GetAll(&v->val, NULL));
939 939
940 if (v->flags & VAR_FROM_ENV) { 940 if (v->flags & VAR_FROM_ENV) {
941 Hash_Entry *h; 941 Hash_Entry *h;
942 942
943 /* 943 /*
944 * If the original variable came from the environment, we 944 * If the original variable came from the environment, we
945 * have to install it in the global context (we could place 945 * have to install it in the global context (we could place
946 * it in the environment, but then we should provide a way to 946 * it in the environment, but then we should provide a way to
947 * export other variables...) 947 * export other variables...)
948 */ 948 */
949 v->flags &= ~(unsigned)VAR_FROM_ENV; 949 v->flags &= ~(unsigned)VAR_FROM_ENV;
950 h = Hash_CreateEntry(&ctxt->context, name, NULL); 950 h = Hash_CreateEntry(&ctxt->context, name, NULL);
951 Hash_SetValue(h, v); 951 Hash_SetValue(h, v);
952 } 952 }
953 } 953 }
954 free(name_freeIt); 954 free(name_freeIt);
955} 955}
956 956
957/*- 957/*-
958 *----------------------------------------------------------------------- 958 *-----------------------------------------------------------------------
959 * Var_Exists -- 959 * Var_Exists --
960 * See if the given variable exists. 960 * See if the given variable exists.
961 * 961 *
962 * Input: 962 * Input:
963 * name Variable to find 963 * name Variable to find
964 * ctxt Context in which to start search 964 * ctxt Context in which to start search
965 * 965 *
966 * Results: 966 * Results:
967 * TRUE if it does, FALSE if it doesn't 967 * TRUE if it does, FALSE if it doesn't
968 * 968 *
969 * Side Effects: 969 * Side Effects:
970 * None. 970 * None.
971 * 971 *
972 *----------------------------------------------------------------------- 972 *-----------------------------------------------------------------------
973 */ 973 */
974Boolean 974Boolean
975Var_Exists(const char *name, GNode *ctxt) 975Var_Exists(const char *name, GNode *ctxt)
976{ 976{
977 char *name_freeIt = NULL; 977 char *name_freeIt = NULL;
978 Var *v; 978 Var *v;
979 979
980 if (strchr(name, '$') != NULL) 980 if (strchr(name, '$') != NULL)
981 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES); 981 name = name_freeIt = Var_Subst(name, ctxt, VARE_WANTRES);
982 982
983 v = VarFind(name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); 983 v = VarFind(name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV);
984 free(name_freeIt); 984 free(name_freeIt);
985 if (v == NULL) 985 if (v == NULL)
986 return FALSE; 986 return FALSE;
987 987
988 (void)VarFreeEnv(v, TRUE); 988 (void)VarFreeEnv(v, TRUE);
989 return TRUE; 989 return TRUE;
990} 990}
991 991
992/*- 992/*-
993 *----------------------------------------------------------------------- 993 *-----------------------------------------------------------------------
994 * Var_Value -- 994 * Var_Value --
995 * Return the unexpanded value of the given variable in the given 995 * Return the unexpanded value of the given variable in the given
996 * context, or the usual contexts. 996 * context, or the usual contexts.
997 * 997 *
998 * Input: 998 * Input:
999 * name name to find 999 * name name to find
1000 * ctxt context in which to search for it 1000 * ctxt context in which to search for it
1001 * 1001 *
1002 * Results: 1002 * Results:
1003 * The value if the variable exists, NULL if it doesn't. 1003 * The value if the variable exists, NULL if it doesn't.
1004 * If the returned value is not NULL, the caller must free *freeIt 1004 * If the returned value is not NULL, the caller must free *freeIt
1005 * as soon as the returned value is no longer needed. 1005 * as soon as the returned value is no longer needed.
1006 *----------------------------------------------------------------------- 1006 *-----------------------------------------------------------------------
1007 */ 1007 */
1008const char * 1008const char *
1009Var_Value(const char *name, GNode *ctxt, char **freeIt) 1009Var_Value(const char *name, GNode *ctxt, char **freeIt)
1010{ 1010{
1011 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1011 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1012 char *p; 1012 char *p;
1013 1013
1014 *freeIt = NULL; 1014 *freeIt = NULL;
1015 if (v == NULL) 1015 if (v == NULL)
1016 return NULL; 1016 return NULL;
1017 1017
1018 p = Buf_GetAll(&v->val, NULL); 1018 p = Buf_GetAll(&v->val, NULL);
1019 if (VarFreeEnv(v, FALSE)) 1019 if (VarFreeEnv(v, FALSE))
1020 *freeIt = p; 1020 *freeIt = p;
1021 return p; 1021 return p;
1022} 1022}
1023 1023
1024 1024
1025/* SepBuf is a string being built from "words", interleaved with separators. */ 1025/* SepBuf is a string being built from "words", interleaved with separators. */
1026typedef struct { 1026typedef struct {
1027 Buffer buf; 1027 Buffer buf;
1028 Boolean needSep; 1028 Boolean needSep;
1029 char sep; /* usually ' ', but see the :ts modifier */ 1029 char sep; /* usually ' ', but see the :ts modifier */
1030} SepBuf; 1030} SepBuf;
1031 1031
1032static void 1032static void
1033SepBuf_Init(SepBuf *buf, char sep) 1033SepBuf_Init(SepBuf *buf, char sep)
1034{ 1034{
1035 Buf_Init(&buf->buf, 32 /* bytes */); 1035 Buf_Init(&buf->buf, 32 /* bytes */);
1036 buf->needSep = FALSE; 1036 buf->needSep = FALSE;
1037 buf->sep = sep; 1037 buf->sep = sep;
1038} 1038}
1039 1039
1040static void 1040static void
1041SepBuf_Sep(SepBuf *buf) 1041SepBuf_Sep(SepBuf *buf)
1042{ 1042{
1043 buf->needSep = TRUE; 1043 buf->needSep = TRUE;
1044} 1044}
1045 1045
1046static void 1046static void
1047SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1047SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1048{ 1048{
1049 if (mem_size == 0) 1049 if (mem_size == 0)
1050 return; 1050 return;
1051 if (buf->needSep && buf->sep != '\0') { 1051 if (buf->needSep && buf->sep != '\0') {
1052 Buf_AddByte(&buf->buf, buf->sep); 1052 Buf_AddByte(&buf->buf, buf->sep);
1053 buf->needSep = FALSE; 1053 buf->needSep = FALSE;
1054 } 1054 }
1055 Buf_AddBytes(&buf->buf, mem, mem_size); 1055 Buf_AddBytes(&buf->buf, mem, mem_size);
1056} 1056}
1057 1057
1058static void 1058static void
1059SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1059SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1060{ 1060{
1061 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1061 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1062} 1062}
1063 1063
1064static void 1064static void
1065SepBuf_AddStr(SepBuf *buf, const char *str) 1065SepBuf_AddStr(SepBuf *buf, const char *str)
1066{ 1066{
1067 SepBuf_AddBytes(buf, str, strlen(str)); 1067 SepBuf_AddBytes(buf, str, strlen(str));
1068} 1068}
1069 1069
1070static char * 1070static char *
1071SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1071SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1072{ 1072{
1073 return Buf_Destroy(&buf->buf, free_buf); 1073 return Buf_Destroy(&buf->buf, free_buf);
1074} 1074}
1075 1075
1076 1076
1077/* This callback for ModifyWords gets a single word from an expression and 1077/* This callback for ModifyWords gets a single word from an expression and
1078 * typically adds a modification of this word to the buffer. It may also do 1078 * typically adds a modification of this word to the buffer. It may also do
1079 * nothing or add several words. */ 1079 * nothing or add several words. */
1080typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1080typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1081 1081
1082 1082
1083/* Callback for ModifyWords to implement the :H modifier. 1083/* Callback for ModifyWords to implement the :H modifier.
1084 * Add the dirname of the given word to the buffer. */ 1084 * Add the dirname of the given word to the buffer. */
1085static void 1085static void
1086ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1086ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1087{ 1087{
1088 const char *slash = strrchr(word, '/'); 1088 const char *slash = strrchr(word, '/');
1089 if (slash != NULL) 1089 if (slash != NULL)
1090 SepBuf_AddBytesBetween(buf, word, slash); 1090 SepBuf_AddBytesBetween(buf, word, slash);
1091 else 1091 else
1092 SepBuf_AddStr(buf, "."); 1092 SepBuf_AddStr(buf, ".");
1093} 1093}
1094 1094
1095/* Callback for ModifyWords to implement the :T modifier. 1095/* Callback for ModifyWords to implement the :T modifier.
1096 * Add the basename of the given word to the buffer. */ 1096 * Add the basename of the given word to the buffer. */
1097static void 1097static void
1098ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1098ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1099{ 1099{
1100 const char *slash = strrchr(word, '/'); 1100 const char *slash = strrchr(word, '/');
1101 const char *base = slash != NULL ? slash + 1 : word; 1101 const char *base = slash != NULL ? slash + 1 : word;
1102 SepBuf_AddStr(buf, base); 1102 SepBuf_AddStr(buf, base);
1103} 1103}
1104 1104
1105/* Callback for ModifyWords to implement the :E modifier. 1105/* Callback for ModifyWords to implement the :E modifier.
1106 * Add the filename suffix of the given word to the buffer, if it exists. */ 1106 * Add the filename suffix of the given word to the buffer, if it exists. */
1107static void 1107static void
1108ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1108ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1109{ 1109{
1110 const char *dot = strrchr(word, '.'); 1110 const char *dot = strrchr(word, '.');
1111 if (dot != NULL) 1111 if (dot != NULL)
1112 SepBuf_AddStr(buf, dot + 1); 1112 SepBuf_AddStr(buf, dot + 1);
1113} 1113}
1114 1114
1115/* Callback for ModifyWords to implement the :R modifier. 1115/* Callback for ModifyWords to implement the :R modifier.
1116 * Add the basename of the given word to the buffer. */ 1116 * Add the basename of the given word to the buffer. */
1117static void 1117static void
1118ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1118ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1119{ 1119{
1120 const char *dot = strrchr(word, '.'); 1120 const char *dot = strrchr(word, '.');
1121 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1121 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1122 SepBuf_AddBytes(buf, word, len); 1122 SepBuf_AddBytes(buf, word, len);
1123} 1123}
1124 1124
1125/* Callback for ModifyWords to implement the :M modifier. 1125/* Callback for ModifyWords to implement the :M modifier.
1126 * Place the word in the buffer if it matches the given pattern. */ 1126 * Place the word in the buffer if it matches the given pattern. */
1127static void 1127static void
1128ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1128ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1129{ 1129{
1130 const char *pattern = data; 1130 const char *pattern = data;
1131 VAR_DEBUG("VarMatch [%s] [%s]\n", word, pattern); 1131 VAR_DEBUG("VarMatch [%s] [%s]\n", word, pattern);
1132 if (Str_Match(word, pattern)) 1132 if (Str_Match(word, pattern))
1133 SepBuf_AddStr(buf, word); 1133 SepBuf_AddStr(buf, word);
1134} 1134}
1135 1135
1136/* Callback for ModifyWords to implement the :N modifier. 1136/* Callback for ModifyWords to implement the :N modifier.
1137 * Place the word in the buffer if it doesn't match the given pattern. */ 1137 * Place the word in the buffer if it doesn't match the given pattern. */
1138static void 1138static void
1139ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1139ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1140{ 1140{
1141 const char *pattern = data; 1141 const char *pattern = data;
1142 if (!Str_Match(word, pattern)) 1142 if (!Str_Match(word, pattern))
1143 SepBuf_AddStr(buf, word); 1143 SepBuf_AddStr(buf, word);
1144} 1144}
1145 1145
1146#ifdef SYSVVARSUB 1146#ifdef SYSVVARSUB
1147/*- 1147/*-
1148 *----------------------------------------------------------------------- 1148 *-----------------------------------------------------------------------
1149 * Str_SYSVMatch -- 1149 * Str_SYSVMatch --
1150 * Check word against pattern for a match (% is wild), 1150 * Check word against pattern for a match (% is wild),
1151 * 1151 *
1152 * Input: 1152 * Input:
1153 * word Word to examine 1153 * word Word to examine
1154 * pattern Pattern to examine against 1154 * pattern Pattern to examine against
1155 * 1155 *
1156 * Results: 1156 * Results:
1157 * Returns the start of the match, or NULL. 1157 * Returns the start of the match, or NULL.
1158 * *match_len returns the length of the match, if any. 1158 * *match_len returns the length of the match, if any.
1159 * *hasPercent returns whether the pattern contains a percent. 1159 * *hasPercent returns whether the pattern contains a percent.
1160 *----------------------------------------------------------------------- 1160 *-----------------------------------------------------------------------
1161 */ 1161 */
1162static const char * 1162static const char *
1163Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len, 1163Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len,
1164 Boolean *hasPercent) 1164 Boolean *hasPercent)
1165{ 1165{
1166 const char *p = pattern; 1166 const char *p = pattern;
1167 const char *w = word; 1167 const char *w = word;
1168 const char *percent; 1168 const char *percent;
1169 size_t w_len; 1169 size_t w_len;
1170 size_t p_len; 1170 size_t p_len;
1171 const char *w_tail; 1171 const char *w_tail;
1172 1172
1173 *hasPercent = FALSE; 1173 *hasPercent = FALSE;
1174 if (*p == '\0') { /* ${VAR:=suffix} */ 1174 if (*p == '\0') { /* ${VAR:=suffix} */
1175 *match_len = strlen(w); /* Null pattern is the whole string */ 1175 *match_len = strlen(w); /* Null pattern is the whole string */
1176 return w; 1176 return w;
1177 } 1177 }
1178 1178
1179 percent = strchr(p, '%'); 1179 percent = strchr(p, '%');
1180 if (percent != NULL) { /* ${VAR:...%...=...} */ 1180 if (percent != NULL) { /* ${VAR:...%...=...} */
1181 *hasPercent = TRUE; 1181 *hasPercent = TRUE;
1182 if (*w == '\0') 1182 if (*w == '\0')
1183 return NULL; /* empty word does not match pattern */ 1183 return NULL; /* empty word does not match pattern */
1184 1184
1185 /* check that the prefix matches */ 1185 /* check that the prefix matches */
1186 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1186 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1187 continue; 1187 continue;
1188 if (p != percent) 1188 if (p != percent)
1189 return NULL; /* No match */ 1189 return NULL; /* No match */
1190 1190
1191 p++; /* Skip the percent */ 1191 p++; /* Skip the percent */
1192 if (*p == '\0') { 1192 if (*p == '\0') {
1193 /* No more pattern, return the rest of the string */ 1193 /* No more pattern, return the rest of the string */
1194 *match_len = strlen(w); 1194 *match_len = strlen(w);
1195 return w; 1195 return w;
1196 } 1196 }
1197 } 1197 }
1198 1198
1199 /* Test whether the tail matches */ 1199 /* Test whether the tail matches */
1200 w_len = strlen(w); 1200 w_len = strlen(w);
1201 p_len = strlen(p); 1201 p_len = strlen(p);
1202 if (w_len < p_len) 1202 if (w_len < p_len)
1203 return NULL; 1203 return NULL;
1204 1204
1205 w_tail = w + w_len - p_len; 1205 w_tail = w + w_len - p_len;
1206 if (memcmp(p, w_tail, p_len) != 0) 1206 if (memcmp(p, w_tail, p_len) != 0)
1207 return NULL; 1207 return NULL;
1208 1208
1209 *match_len = (size_t)(w_tail - w); 1209 *match_len = (size_t)(w_tail - w);
1210 return w; 1210 return w;
1211} 1211}
1212 1212
1213typedef struct { 1213typedef struct {
1214 GNode *ctx; 1214 GNode *ctx;
1215 const char *lhs; 1215 const char *lhs;
1216 const char *rhs; 1216 const char *rhs;
1217} ModifyWord_SYSVSubstArgs; 1217} ModifyWord_SYSVSubstArgs;
1218 1218
1219/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1219/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1220static void 1220static void
1221ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1221ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1222{ 1222{
1223 const ModifyWord_SYSVSubstArgs *args = data; 1223 const ModifyWord_SYSVSubstArgs *args = data;
1224 char *rhs_expanded; 1224 char *rhs_expanded;
1225 const char *rhs; 1225 const char *rhs;
1226 const char *percent; 1226 const char *percent;
1227 1227
1228 size_t match_len; 1228 size_t match_len;
1229 Boolean lhsPercent; 1229 Boolean lhsPercent;
1230 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent); 1230 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent);
1231 if (match == NULL) { 1231 if (match == NULL) {
1232 SepBuf_AddStr(buf, word); 1232 SepBuf_AddStr(buf, word);
1233 return; 1233 return;
1234 } 1234 }
1235 1235
1236 /* Append rhs to the buffer, substituting the first '%' with the 1236 /* Append rhs to the buffer, substituting the first '%' with the
1237 * match, but only if the lhs had a '%' as well. */ 1237 * match, but only if the lhs had a '%' as well. */
1238 1238
1239 rhs_expanded = Var_Subst(args->rhs, args->ctx, VARE_WANTRES); 1239 rhs_expanded = Var_Subst(args->rhs, args->ctx, VARE_WANTRES);
1240 1240
1241 rhs = rhs_expanded; 1241 rhs = rhs_expanded;
1242 percent = strchr(rhs, '%'); 1242 percent = strchr(rhs, '%');
1243 1243
1244 if (percent != NULL && lhsPercent) { 1244 if (percent != NULL && lhsPercent) {
1245 /* Copy the prefix of the replacement pattern */ 1245 /* Copy the prefix of the replacement pattern */
1246 SepBuf_AddBytesBetween(buf, rhs, percent); 1246 SepBuf_AddBytesBetween(buf, rhs, percent);
1247 rhs = percent + 1; 1247 rhs = percent + 1;
1248 } 1248 }
1249 if (percent != NULL || !lhsPercent) 1249 if (percent != NULL || !lhsPercent)
1250 SepBuf_AddBytes(buf, match, match_len); 1250 SepBuf_AddBytes(buf, match, match_len);
1251 1251
1252 /* Append the suffix of the replacement pattern */ 1252 /* Append the suffix of the replacement pattern */
1253 SepBuf_AddStr(buf, rhs); 1253 SepBuf_AddStr(buf, rhs);
1254 1254
1255 free(rhs_expanded); 1255 free(rhs_expanded);
1256} 1256}
1257#endif 1257#endif
1258 1258
1259 1259
1260typedef struct { 1260typedef struct {
1261 const char *lhs; 1261 const char *lhs;
1262 size_t lhsLen; 1262 size_t lhsLen;
1263 const char *rhs; 1263 const char *rhs;
1264 size_t rhsLen; 1264 size_t rhsLen;
1265 VarPatternFlags pflags; 1265 VarPatternFlags pflags;
1266 Boolean matched; 1266 Boolean matched;
1267} ModifyWord_SubstArgs; 1267} ModifyWord_SubstArgs;
1268 1268
1269/* Callback for ModifyWords to implement the :S,from,to, modifier. 1269/* Callback for ModifyWords to implement the :S,from,to, modifier.
1270 * Perform a string substitution on the given word. */ 1270 * Perform a string substitution on the given word. */
1271static void 1271static void
1272ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1272ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1273{ 1273{
1274 size_t wordLen = strlen(word); 1274 size_t wordLen = strlen(word);
1275 ModifyWord_SubstArgs *args = data; 1275 ModifyWord_SubstArgs *args = data;
1276 const char *match; 1276 const char *match;
1277 1277
1278 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1278 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1279 goto nosub; 1279 goto nosub;
1280 1280
1281 if (args->pflags & VARP_ANCHOR_START) { 1281 if (args->pflags & VARP_ANCHOR_START) {
1282 if (wordLen < args->lhsLen || 1282 if (wordLen < args->lhsLen ||
1283 memcmp(word, args->lhs, args->lhsLen) != 0) 1283 memcmp(word, args->lhs, args->lhsLen) != 0)
1284 goto nosub; 1284 goto nosub;
1285 1285
1286 if (args->pflags & VARP_ANCHOR_END) { 1286 if (args->pflags & VARP_ANCHOR_END) {
1287 if (wordLen != args->lhsLen) 1287 if (wordLen != args->lhsLen)
1288 goto nosub; 1288 goto nosub;
1289 1289
1290 /* :S,^whole$,replacement, */ 1290 /* :S,^whole$,replacement, */
1291 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1291 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1292 args->matched = TRUE; 1292 args->matched = TRUE;
1293 } else { 1293 } else {
1294 /* :S,^prefix,replacement, */ 1294 /* :S,^prefix,replacement, */
1295 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1295 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1296 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1296 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1297 args->matched = TRUE; 1297 args->matched = TRUE;
1298 } 1298 }
1299 return; 1299 return;
1300 } 1300 }
1301 1301
1302 if (args->pflags & VARP_ANCHOR_END) { 1302 if (args->pflags & VARP_ANCHOR_END) {
1303 const char *start; 1303 const char *start;
1304 1304
1305 if (wordLen < args->lhsLen) 1305 if (wordLen < args->lhsLen)
1306 goto nosub; 1306 goto nosub;
1307 1307
1308 start = word + (wordLen - args->lhsLen); 1308 start = word + (wordLen - args->lhsLen);
1309 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1309 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1310 goto nosub; 1310 goto nosub;
1311 1311
1312 /* :S,suffix$,replacement, */ 1312 /* :S,suffix$,replacement, */
1313 SepBuf_AddBytesBetween(buf, word, start); 1313 SepBuf_AddBytesBetween(buf, word, start);
1314 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1314 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1315 args->matched = TRUE; 1315 args->matched = TRUE;
1316 return; 1316 return;
1317 } 1317 }
1318 1318
1319 /* unanchored case, may match more than once */ 1319 /* unanchored case, may match more than once */
1320 while ((match = Str_FindSubstring(word, args->lhs)) != NULL) { 1320 while ((match = Str_FindSubstring(word, args->lhs)) != NULL) {
1321 SepBuf_AddBytesBetween(buf, word, match); 1321 SepBuf_AddBytesBetween(buf, word, match);
1322 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1322 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1323 args->matched = TRUE; 1323 args->matched = TRUE;
1324 wordLen -= (size_t)(match - word) + args->lhsLen; 1324 wordLen -= (size_t)(match - word) + args->lhsLen;
1325 word += (size_t)(match - word) + args->lhsLen; 1325 word += (size_t)(match - word) + args->lhsLen;
1326 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1326 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1327 break; 1327 break;
1328 } 1328 }
1329nosub: 1329nosub:
1330 SepBuf_AddBytes(buf, word, wordLen); 1330 SepBuf_AddBytes(buf, word, wordLen);
1331} 1331}
1332 1332
1333#ifndef NO_REGEX 1333#ifndef NO_REGEX
1334/* Print the error caused by a regcomp or regexec call. */ 1334/* Print the error caused by a regcomp or regexec call. */
1335static void 1335static void
1336VarREError(int reerr, regex_t *pat, const char *str) 1336VarREError(int reerr, regex_t *pat, const char *str)
1337{ 1337{
1338 size_t errlen = regerror(reerr, pat, 0, 0); 1338 size_t errlen = regerror(reerr, pat, 0, 0);
1339 char *errbuf = bmake_malloc(errlen); 1339 char *errbuf = bmake_malloc(errlen);
1340 regerror(reerr, pat, errbuf, errlen); 1340 regerror(reerr, pat, errbuf, errlen);
1341 Error("%s: %s", str, errbuf); 1341 Error("%s: %s", str, errbuf);
1342 free(errbuf); 1342 free(errbuf);
1343} 1343}
1344 1344
1345typedef struct { 1345typedef struct {
1346 regex_t re; 1346 regex_t re;
1347 size_t nsub; 1347 size_t nsub;
1348 char *replace; 1348 char *replace;
1349 VarPatternFlags pflags; 1349 VarPatternFlags pflags;
1350 Boolean matched; 1350 Boolean matched;
1351} ModifyWord_SubstRegexArgs; 1351} ModifyWord_SubstRegexArgs;
1352 1352
1353/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1353/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1354 * Perform a regex substitution on the given word. */ 1354 * Perform a regex substitution on the given word. */
1355static void 1355static void
1356ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1356ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1357{ 1357{
1358 ModifyWord_SubstRegexArgs *args = data; 1358 ModifyWord_SubstRegexArgs *args = data;
1359 int xrv; 1359 int xrv;
1360 const char *wp = word; 1360 const char *wp = word;
1361 char *rp; 1361 char *rp;
1362 int flags = 0; 1362 int flags = 0;
1363 regmatch_t m[10]; 1363 regmatch_t m[10];
1364 1364
1365 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1365 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1366 goto nosub; 1366 goto nosub;
1367 1367
1368tryagain: 1368tryagain:
1369 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1369 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1370 1370
1371 switch (xrv) { 1371 switch (xrv) {
1372 case 0: 1372 case 0:
1373 args->matched = TRUE; 1373 args->matched = TRUE;
1374 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1374 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1375 1375
1376 for (rp = args->replace; *rp; rp++) { 1376 for (rp = args->replace; *rp; rp++) {
1377 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1377 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1378 SepBuf_AddBytes(buf, rp + 1, 1); 1378 SepBuf_AddBytes(buf, rp + 1, 1);
1379 rp++; 1379 rp++;
1380 continue; 1380 continue;
1381 } 1381 }
1382 1382
1383 if (*rp == '&') { 1383 if (*rp == '&') {
1384 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1384 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1385 continue; 1385 continue;
1386 } 1386 }
1387 1387
1388 if (*rp != '\\' || !isdigit((unsigned char)rp[1])) { 1388 if (*rp != '\\' || !isdigit((unsigned char)rp[1])) {
1389 SepBuf_AddBytes(buf, rp, 1); 1389 SepBuf_AddBytes(buf, rp, 1);
1390 continue; 1390 continue;
1391 } 1391 }
1392 1392
1393 { /* \0 to \9 backreference */ 1393 { /* \0 to \9 backreference */
1394 size_t n = (size_t)(rp[1] - '0'); 1394 size_t n = (size_t)(rp[1] - '0');
1395 rp++; 1395 rp++;
1396 1396
1397 if (n >= args->nsub) { 1397 if (n >= args->nsub) {
1398 Error("No subexpression \\%zu", n); 1398 Error("No subexpression \\%zu", n);
1399 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1399 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1400 Error("No match for subexpression \\%zu", n); 1400 Error("No match for subexpression \\%zu", n);
1401 } else { 1401 } else {
1402 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1402 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1403 wp + m[n].rm_eo); 1403 wp + m[n].rm_eo);
1404 } 1404 }
1405 } 1405 }
1406 } 1406 }
1407 1407
1408 wp += m[0].rm_eo; 1408 wp += m[0].rm_eo;
1409 if (args->pflags & VARP_SUB_GLOBAL) { 1409 if (args->pflags & VARP_SUB_GLOBAL) {
1410 flags |= REG_NOTBOL; 1410 flags |= REG_NOTBOL;
1411 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1411 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1412 SepBuf_AddBytes(buf, wp, 1); 1412 SepBuf_AddBytes(buf, wp, 1);
1413 wp++; 1413 wp++;
1414 } 1414 }
1415 if (*wp) 1415 if (*wp)
1416 goto tryagain; 1416 goto tryagain;
1417 } 1417 }
1418 if (*wp) { 1418 if (*wp) {
1419 SepBuf_AddStr(buf, wp); 1419 SepBuf_AddStr(buf, wp);
1420 } 1420 }
1421 break; 1421 break;
1422 default: 1422 default:
1423 VarREError(xrv, &args->re, "Unexpected regex error"); 1423 VarREError(xrv, &args->re, "Unexpected regex error");
1424 /* fall through */ 1424 /* fall through */
1425 case REG_NOMATCH: 1425 case REG_NOMATCH:
1426 nosub: 1426 nosub:
1427 SepBuf_AddStr(buf, wp); 1427 SepBuf_AddStr(buf, wp);
1428 break; 1428 break;
1429 } 1429 }
1430} 1430}
1431#endif 1431#endif
1432 1432
1433 1433
1434typedef struct { 1434typedef struct {
1435 GNode *ctx; 1435 GNode *ctx;
1436 char *tvar; /* name of temporary variable */ 1436 char *tvar; /* name of temporary variable */
1437 char *str; /* string to expand */ 1437 char *str; /* string to expand */
1438 VarEvalFlags eflags; 1438 VarEvalFlags eflags;
1439} ModifyWord_LoopArgs; 1439} ModifyWord_LoopArgs;
1440 1440
1441/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1441/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1442static void 1442static void
1443ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1443ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1444{ 1444{
1445 const ModifyWord_LoopArgs *args; 1445 const ModifyWord_LoopArgs *args;
1446 char *s; 1446 char *s;
1447 1447
1448 if (word[0] == '\0') 1448 if (word[0] == '\0')
1449 return; 1449 return;
1450 1450
1451 args = data; 1451 args = data;
1452 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1452 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1453 s = Var_Subst(args->str, args->ctx, args->eflags); 1453 s = Var_Subst(args->str, args->ctx, args->eflags);
1454 1454
1455 VAR_DEBUG("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1455 VAR_DEBUG("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1456 "to \"%s\"\n", 1456 "to \"%s\"\n",
1457 word, args->tvar, args->str, s); 1457 word, args->tvar, args->str, s);
1458 1458
1459 if (s[0] == '\n' || (buf->buf.count > 0 && 1459 if (s[0] == '\n' || (buf->buf.count > 0 &&
1460 buf->buf.buffer[buf->buf.count - 1] == '\n')) 1460 buf->buf.buffer[buf->buf.count - 1] == '\n'))
1461 buf->needSep = FALSE; 1461 buf->needSep = FALSE;
1462 SepBuf_AddStr(buf, s); 1462 SepBuf_AddStr(buf, s);
1463 free(s); 1463 free(s);
1464} 1464}
1465 1465
1466 1466
1467/*- 1467/*-
1468 * Implements the :[first..last] modifier. 1468 * Implements the :[first..last] modifier.
1469 * This is a special case of ModifyWords since we want to be able 1469 * This is a special case of ModifyWords since we want to be able
1470 * to scan the list backwards if first > last. 1470 * to scan the list backwards if first > last.
1471 */ 1471 */
1472static char * 1472static char *
1473VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1473VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1474 int last) 1474 int last)
1475{ 1475{
1476 Words words; 1476 Words words;
1477 int start, end, step; 1477 int start, end, step;
1478 int i; 1478 int i;
1479 1479
1480 SepBuf buf; 1480 SepBuf buf;
1481 SepBuf_Init(&buf, sep); 1481 SepBuf_Init(&buf, sep);
1482 1482
1483 if (oneBigWord) { 1483 if (oneBigWord) {
1484 /* fake what Str_Words() would do if there were only one word */ 1484 /* fake what Str_Words() would do if there were only one word */
1485 words.len = 1; 1485 words.len = 1;
1486 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1486 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1487 words.freeIt = bmake_strdup(str); 1487 words.freeIt = bmake_strdup(str);
1488 words.words[0] = words.freeIt; 1488 words.words[0] = words.freeIt;
1489 words.words[1] = NULL; 1489 words.words[1] = NULL;
1490 } else { 1490 } else {
1491 words = Str_Words(str, FALSE); 1491 words = Str_Words(str, FALSE);
1492 } 1492 }
1493 1493
1494 /* 1494 /*
1495 * Now sanitize the given range. 1495 * Now sanitize the given range.
1496 * If first or last are negative, convert them to the positive equivalents 1496 * If first or last are negative, convert them to the positive equivalents
1497 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1497 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1498 */ 1498 */
1499 if (first < 0) 1499 if (first < 0)
1500 first += (int)words.len + 1; 1500 first += (int)words.len + 1;
1501 if (last < 0) 1501 if (last < 0)
1502 last += (int)words.len + 1; 1502 last += (int)words.len + 1;
1503 1503
1504 /* 1504 /*
1505 * We avoid scanning more of the list than we need to. 1505 * We avoid scanning more of the list than we need to.
1506 */ 1506 */
1507 if (first > last) { 1507 if (first > last) {
1508 start = MIN((int)words.len, first) - 1; 1508 start = MIN((int)words.len, first) - 1;
1509 end = MAX(0, last - 1); 1509 end = MAX(0, last - 1);
1510 step = -1; 1510 step = -1;
1511 } else { 1511 } else {
1512 start = MAX(0, first - 1); 1512 start = MAX(0, first - 1);
1513 end = MIN((int)words.len, last); 1513 end = MIN((int)words.len, last);
1514 step = 1; 1514 step = 1;
1515 } 1515 }
1516 1516
1517 for (i = start; (step < 0) == (i >= end); i += step) { 1517 for (i = start; (step < 0) == (i >= end); i += step) {
1518 SepBuf_AddStr(&buf, words.words[i]); 1518 SepBuf_AddStr(&buf, words.words[i]);
1519 SepBuf_Sep(&buf); 1519 SepBuf_Sep(&buf);
1520 } 1520 }
1521 1521
1522 Words_Free(words); 1522 Words_Free(words);
1523 1523
1524 return SepBuf_Destroy(&buf, FALSE); 1524 return SepBuf_Destroy(&buf, FALSE);
1525} 1525}
1526 1526
1527 1527
1528/* Callback for ModifyWords to implement the :tA modifier. 1528/* Callback for ModifyWords to implement the :tA modifier.
1529 * Replace each word with the result of realpath() if successful. */ 1529 * Replace each word with the result of realpath() if successful. */
1530static void 1530static void
1531ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1531ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1532{ 1532{
1533 struct stat st; 1533 struct stat st;
1534 char rbuf[MAXPATHLEN]; 1534 char rbuf[MAXPATHLEN];
1535 1535
1536 const char *rp = cached_realpath(word, rbuf); 1536 const char *rp = cached_realpath(word, rbuf);
1537 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1537 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1538 word = rp; 1538 word = rp;
1539 1539
1540 SepBuf_AddStr(buf, word); 1540 SepBuf_AddStr(buf, word);
1541} 1541}
1542 1542
1543/*- 1543/*-
1544 *----------------------------------------------------------------------- 1544 *-----------------------------------------------------------------------
1545 * Modify each of the words of the passed string using the given function. 1545 * Modify each of the words of the passed string using the given function.
1546 * 1546 *
1547 * Input: 1547 * Input:
1548 * str String whose words should be modified 1548 * str String whose words should be modified
1549 * modifyWord Function that modifies a single word 1549 * modifyWord Function that modifies a single word
1550 * modifyWord_args Custom arguments for modifyWord 1550 * modifyWord_args Custom arguments for modifyWord
1551 * 1551 *
1552 * Results: 1552 * Results:
1553 * A string of all the words modified appropriately. 1553 * A string of all the words modified appropriately.
1554 *----------------------------------------------------------------------- 1554 *-----------------------------------------------------------------------
1555 */ 1555 */
1556static char * 1556static char *
1557ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1557ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str,
1558 ModifyWordsCallback modifyWord, void *modifyWord_args) 1558 ModifyWordsCallback modifyWord, void *modifyWord_args)
1559{ 1559{
1560 SepBuf result; 1560 SepBuf result;
1561 Words words; 1561 Words words;
1562 size_t i; 1562 size_t i;
1563 1563
1564 if (oneBigWord) { 1564 if (oneBigWord) {
1565 SepBuf_Init(&result, sep); 1565 SepBuf_Init(&result, sep);
1566 modifyWord(str, &result, modifyWord_args); 1566 modifyWord(str, &result, modifyWord_args);
1567 return SepBuf_Destroy(&result, FALSE); 1567 return SepBuf_Destroy(&result, FALSE);
1568 } 1568 }
1569 1569
1570 SepBuf_Init(&result, sep); 1570 SepBuf_Init(&result, sep);
1571 1571
1572 words = Str_Words(str, FALSE); 1572 words = Str_Words(str, FALSE);
1573 1573
1574 VAR_DEBUG("ModifyWords: split \"%s\" into %zu words\n", str, words.len); 1574 VAR_DEBUG("ModifyWords: split \"%s\" into %zu words\n", str, words.len);
1575 1575
1576 for (i = 0; i < words.len; i++) { 1576 for (i = 0; i < words.len; i++) {
1577 modifyWord(words.words[i], &result, modifyWord_args); 1577 modifyWord(words.words[i], &result, modifyWord_args);
1578 if (result.buf.count > 0) 1578 if (result.buf.count > 0)
1579 SepBuf_Sep(&result); 1579 SepBuf_Sep(&result);
1580 } 1580 }
1581 1581
1582 Words_Free(words); 1582 Words_Free(words);
1583 1583
1584 return SepBuf_Destroy(&result, FALSE); 1584 return SepBuf_Destroy(&result, FALSE);
1585} 1585}
1586 1586
1587 1587
1588static char * 1588static char *
1589Words_JoinFree(Words words) 1589Words_JoinFree(Words words)
1590{ 1590{
1591 Buffer buf; 1591 Buffer buf;
1592 size_t i; 1592 size_t i;
1593 1593
1594 Buf_Init(&buf, 0); 1594 Buf_Init(&buf, 0);
1595 1595
1596 for (i = 0; i < words.len; i++) { 1596 for (i = 0; i < words.len; i++) {
1597 if (i != 0) 1597 if (i != 0)
1598 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 1598 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
1599 Buf_AddStr(&buf, words.words[i]); 1599 Buf_AddStr(&buf, words.words[i]);
1600 } 1600 }
1601 1601
1602 Words_Free(words); 1602 Words_Free(words);
1603 1603
1604 return Buf_Destroy(&buf, FALSE); 1604 return Buf_Destroy(&buf, FALSE);
1605} 1605}
1606 1606
1607/* Remove adjacent duplicate words. */ 1607/* Remove adjacent duplicate words. */
1608static char * 1608static char *
1609VarUniq(const char *str) 1609VarUniq(const char *str)
1610{ 1610{
1611 Words words = Str_Words(str, FALSE); 1611 Words words = Str_Words(str, FALSE);
1612 char **av = words.words; 
1613 1612
1614 if (words.len > 1) { 1613 if (words.len > 1) {
1615 size_t i, j; 1614 size_t i, j;
1616 for (j = 0, i = 1; i < words.len; i++) 1615 for (j = 0, i = 1; i < words.len; i++)
1617 if (strcmp(av[i], av[j]) != 0 && (++j != i)) 1616 if (strcmp(words.words[i], words.words[j]) != 0 && (++j != i))
1618 av[j] = av[i]; 1617 words.words[j] = words.words[i];
1619 words.len = j + 1; 1618 words.len = j + 1;
1620 } 1619 }
1621 1620
1622 return Words_JoinFree(words); 1621 return Words_JoinFree(words);
1623} 1622}
1624 1623
1625 1624
1626/*- 1625/*-
1627 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ 1626 * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
1628 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and 1627 * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
1629 * including the next unescaped delimiter. The delimiter, as well as the 1628 * including the next unescaped delimiter. The delimiter, as well as the
1630 * backslash or the dollar, can be escaped with a backslash. 1629 * backslash or the dollar, can be escaped with a backslash.
1631 * 1630 *
1632 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1631 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1633 * was found. On successful return, the parsing position pp points right 1632 * was found. On successful return, the parsing position pp points right
1634 * after the delimiter. The delimiter is not included in the returned 1633 * after the delimiter. The delimiter is not included in the returned
1635 * value though. 1634 * value though.
1636 */ 1635 */
1637static char * 1636static char *
1638ParseModifierPart( 1637ParseModifierPart(
1639 const char **pp, /* The parsing position, updated upon return */ 1638 const char **pp, /* The parsing position, updated upon return */
1640 int delim, /* Parsing stops at this delimiter */ 1639 int delim, /* Parsing stops at this delimiter */
1641 VarEvalFlags eflags, /* Flags for evaluating nested variables; 1640 VarEvalFlags eflags, /* Flags for evaluating nested variables;
1642 * if VARE_WANTRES is not set, the text is 1641 * if VARE_WANTRES is not set, the text is
1643 * only parsed */ 1642 * only parsed */
1644 GNode *ctxt, /* For looking up nested variables */ 1643 GNode *ctxt, /* For looking up nested variables */
1645 size_t *out_length, /* Optionally stores the length of the returned 1644 size_t *out_length, /* Optionally stores the length of the returned
1646 * string, just to save another strlen call. */ 1645 * string, just to save another strlen call. */
1647 VarPatternFlags *out_pflags,/* For the first part of the :S modifier, 1646 VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
1648 * sets the VARP_ANCHOR_END flag if the last 1647 * sets the VARP_ANCHOR_END flag if the last
1649 * character of the pattern is a $. */ 1648 * character of the pattern is a $. */
1650 ModifyWord_SubstArgs *subst /* For the second part of the :S modifier, 1649 ModifyWord_SubstArgs *subst /* For the second part of the :S modifier,
1651 * allow ampersands to be escaped and replace 1650 * allow ampersands to be escaped and replace
1652 * unescaped ampersands with subst->lhs. */ 1651 * unescaped ampersands with subst->lhs. */
1653) { 1652) {
1654 Buffer buf; 1653 Buffer buf;
1655 const char *p; 1654 const char *p;
1656 char *rstr; 1655 char *rstr;
1657 1656
1658 Buf_Init(&buf, 0); 1657 Buf_Init(&buf, 0);
1659 1658
1660 /* 1659 /*
1661 * Skim through until the matching delimiter is found; 1660 * Skim through until the matching delimiter is found;
1662 * pick up variable substitutions on the way. Also allow 1661 * pick up variable substitutions on the way. Also allow
1663 * backslashes to quote the delimiter, $, and \, but don't 1662 * backslashes to quote the delimiter, $, and \, but don't
1664 * touch other backslashes. 1663 * touch other backslashes.
1665 */ 1664 */
1666 p = *pp; 1665 p = *pp;
1667 while (*p != '\0' && *p != delim) { 1666 while (*p != '\0' && *p != delim) {
1668 const char *varstart; 1667 const char *varstart;
1669 1668
1670 Boolean is_escaped = p[0] == '\\' && ( 1669 Boolean is_escaped = p[0] == '\\' && (
1671 p[1] == delim || p[1] == '\\' || p[1] == '$' || 1670 p[1] == delim || p[1] == '\\' || p[1] == '$' ||
1672 (p[1] == '&' && subst != NULL)); 1671 (p[1] == '&' && subst != NULL));
1673 if (is_escaped) { 1672 if (is_escaped) {
1674 Buf_AddByte(&buf, p[1]); 1673 Buf_AddByte(&buf, p[1]);
1675 p += 2; 1674 p += 2;
1676 continue; 1675 continue;
1677 } 1676 }
1678 1677
1679 if (*p != '$') { /* Unescaped, simple text */ 1678 if (*p != '$') { /* Unescaped, simple text */
1680 if (subst != NULL && *p == '&') 1679 if (subst != NULL && *p == '&')
1681 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen); 1680 Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
1682 else 1681 else
1683 Buf_AddByte(&buf, *p); 1682 Buf_AddByte(&buf, *p);
1684 p++; 1683 p++;
1685 continue; 1684 continue;
1686 } 1685 }
1687 1686
1688 if (p[1] == delim) { /* Unescaped $ at end of pattern */ 1687 if (p[1] == delim) { /* Unescaped $ at end of pattern */
1689 if (out_pflags != NULL) 1688 if (out_pflags != NULL)
1690 *out_pflags |= VARP_ANCHOR_END; 1689 *out_pflags |= VARP_ANCHOR_END;
1691 else 1690 else
1692 Buf_AddByte(&buf, *p); 1691 Buf_AddByte(&buf, *p);
1693 p++; 1692 p++;
1694 continue; 1693 continue;
1695 } 1694 }
1696 1695
1697 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */ 1696 if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
1698 const char *cp2; 1697 const char *cp2;
1699 int len; 1698 int len;
1700 void *freeIt; 1699 void *freeIt;
1701 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN; 1700 VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
1702 1701
1703 cp2 = Var_Parse(p, ctxt, nested_eflags, &len, &freeIt); 1702 cp2 = Var_Parse(p, ctxt, nested_eflags, &len, &freeIt);
1704 Buf_AddStr(&buf, cp2); 1703 Buf_AddStr(&buf, cp2);
1705 free(freeIt); 1704 free(freeIt);
1706 p += len; 1705 p += len;
1707 continue; 1706 continue;
1708 } 1707 }
1709 1708
1710 /* XXX: This whole block is very similar to Var_Parse without 1709 /* XXX: This whole block is very similar to Var_Parse without
1711 * VARE_WANTRES. There may be subtle edge cases though that are 1710 * VARE_WANTRES. There may be subtle edge cases though that are
1712 * not yet covered in the unit tests and that are parsed differently, 1711 * not yet covered in the unit tests and that are parsed differently,
1713 * depending on whether they are evaluated or not. 1712 * depending on whether they are evaluated or not.
1714 * 1713 *
1715 * This subtle difference is not documented in the manual page, 1714 * This subtle difference is not documented in the manual page,
1716 * neither is the difference between parsing :D and :M documented. 1715 * neither is the difference between parsing :D and :M documented.
1717 * No code should ever depend on these details, but who knows. */ 1716 * No code should ever depend on these details, but who knows. */
1718 1717
1719 varstart = p; /* Nested variable, only parsed */ 1718 varstart = p; /* Nested variable, only parsed */
1720 if (p[1] == PROPEN || p[1] == BROPEN) { 1719 if (p[1] == PROPEN || p[1] == BROPEN) {
1721 /* 1720 /*
1722 * Find the end of this variable reference 1721 * Find the end of this variable reference
1723 * and suck it in without further ado. 1722 * and suck it in without further ado.
1724 * It will be interpreted later. 1723 * It will be interpreted later.
1725 */ 1724 */
1726 int have = p[1]; 1725 int have = p[1];
1727 int want = have == PROPEN ? PRCLOSE : BRCLOSE; 1726 int want = have == PROPEN ? PRCLOSE : BRCLOSE;
1728 int depth = 1; 1727 int depth = 1;
1729 1728
1730 for (p += 2; *p != '\0' && depth > 0; p++) { 1729 for (p += 2; *p != '\0' && depth > 0; p++) {
1731 if (p[-1] != '\\') { 1730 if (p[-1] != '\\') {
1732 if (*p == have) 1731 if (*p == have)
1733 depth++; 1732 depth++;
1734 if (*p == want) 1733 if (*p == want)
1735 depth--; 1734 depth--;
1736 } 1735 }
1737 } 1736 }
1738 Buf_AddBytesBetween(&buf, varstart, p); 1737 Buf_AddBytesBetween(&buf, varstart, p);
1739 } else { 1738 } else {
1740 Buf_AddByte(&buf, *varstart); 1739 Buf_AddByte(&buf, *varstart);
1741 p++; 1740 p++;
1742 } 1741 }
1743 } 1742 }
1744 1743
1745 if (*p != delim) { 1744 if (*p != delim) {
1746 *pp = p; 1745 *pp = p;
1747 return NULL; 1746 return NULL;
1748 } 1747 }
1749 1748
1750 *pp = ++p; 1749 *pp = ++p;
1751 if (out_length != NULL) 1750 if (out_length != NULL)
1752 *out_length = Buf_Size(&buf); 1751 *out_length = Buf_Size(&buf);
1753 1752
1754 rstr = Buf_Destroy(&buf, FALSE); 1753 rstr = Buf_Destroy(&buf, FALSE);
1755 VAR_DEBUG("Modifier part: \"%s\"\n", rstr); 1754 VAR_DEBUG("Modifier part: \"%s\"\n", rstr);
1756 return rstr; 1755 return rstr;
1757} 1756}
1758 1757
1759/*- 1758/*-
1760 *----------------------------------------------------------------------- 1759 *-----------------------------------------------------------------------
1761 * VarQuote -- 1760 * VarQuote --
1762 * Quote shell meta-characters and space characters in the string 1761 * Quote shell meta-characters and space characters in the string
1763 * if quoteDollar is set, also quote and double any '$' characters. 1762 * if quoteDollar is set, also quote and double any '$' characters.
1764 * 1763 *
1765 * Results: 1764 * Results:
1766 * The quoted string 1765 * The quoted string
1767 * 1766 *
1768 * Side Effects: 1767 * Side Effects:
1769 * None. 1768 * None.
1770 * 1769 *
1771 *----------------------------------------------------------------------- 1770 *-----------------------------------------------------------------------
1772 */ 1771 */
1773static char * 1772static char *
1774VarQuote(char *str, Boolean quoteDollar) 1773VarQuote(char *str, Boolean quoteDollar)
1775{ 1774{
1776 Buffer buf; 1775 Buffer buf;
1777 Buf_Init(&buf, 0); 1776 Buf_Init(&buf, 0);
1778 1777
1779 for (; *str != '\0'; str++) { 1778 for (; *str != '\0'; str++) {
1780 if (*str == '\n') { 1779 if (*str == '\n') {
1781 const char *newline = Shell_GetNewline(); 1780 const char *newline = Shell_GetNewline();
1782 if (newline == NULL) 1781 if (newline == NULL)
1783 newline = "\\\n"; 1782 newline = "\\\n";
1784 Buf_AddStr(&buf, newline); 1783 Buf_AddStr(&buf, newline);
1785 continue; 1784 continue;
1786 } 1785 }
1787 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) 1786 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
1788 Buf_AddByte(&buf, '\\'); 1787 Buf_AddByte(&buf, '\\');
1789 Buf_AddByte(&buf, *str); 1788 Buf_AddByte(&buf, *str);
1790 if (quoteDollar && *str == '$') 1789 if (quoteDollar && *str == '$')
1791 Buf_AddStr(&buf, "\\$"); 1790 Buf_AddStr(&buf, "\\$");
1792 } 1791 }
1793 1792
1794 str = Buf_Destroy(&buf, FALSE); 1793 str = Buf_Destroy(&buf, FALSE);
1795 VAR_DEBUG("QuoteMeta: [%s]\n", str); 1794 VAR_DEBUG("QuoteMeta: [%s]\n", str);
1796 return str; 1795 return str;
1797} 1796}
1798 1797
1799/* Compute the 32-bit hash of the given string, using the MurmurHash3 1798/* Compute the 32-bit hash of the given string, using the MurmurHash3
1800 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */ 1799 * algorithm. Output is encoded as 8 hex digits, in Little Endian order. */
1801static char * 1800static char *
1802VarHash(const char *str) 1801VarHash(const char *str)
1803{ 1802{
1804 static const char hexdigits[16] = "0123456789abcdef"; 1803 static const char hexdigits[16] = "0123456789abcdef";
1805 const unsigned char *ustr = (const unsigned char *)str; 1804 const unsigned char *ustr = (const unsigned char *)str;
1806 1805
1807 uint32_t h = 0x971e137bU; 1806 uint32_t h = 0x971e137bU;
1808 uint32_t c1 = 0x95543787U; 1807 uint32_t c1 = 0x95543787U;
1809 uint32_t c2 = 0x2ad7eb25U; 1808 uint32_t c2 = 0x2ad7eb25U;
1810 size_t len2 = strlen(str); 1809 size_t len2 = strlen(str);
1811 1810
1812 char *buf; 1811 char *buf;
1813 size_t i; 1812 size_t i;
1814 1813
1815 size_t len; 1814 size_t len;
1816 for (len = len2; len; ) { 1815 for (len = len2; len; ) {
1817 uint32_t k = 0; 1816 uint32_t k = 0;
1818 switch (len) { 1817 switch (len) {
1819 default: 1818 default:
1820 k = ((uint32_t)ustr[3] << 24) | 1819 k = ((uint32_t)ustr[3] << 24) |
1821 ((uint32_t)ustr[2] << 16) | 1820 ((uint32_t)ustr[2] << 16) |
1822 ((uint32_t)ustr[1] << 8) | 1821 ((uint32_t)ustr[1] << 8) |
1823 (uint32_t)ustr[0]; 1822 (uint32_t)ustr[0];
1824 len -= 4; 1823 len -= 4;
1825 ustr += 4; 1824 ustr += 4;
1826 break; 1825 break;
1827 case 3: 1826 case 3:
1828 k |= (uint32_t)ustr[2] << 16; 1827 k |= (uint32_t)ustr[2] << 16;
1829 /* FALLTHROUGH */ 1828 /* FALLTHROUGH */
1830 case 2: 1829 case 2:
1831 k |= (uint32_t)ustr[1] << 8; 1830 k |= (uint32_t)ustr[1] << 8;
1832 /* FALLTHROUGH */ 1831 /* FALLTHROUGH */
1833 case 1: 1832 case 1:
1834 k |= (uint32_t)ustr[0]; 1833 k |= (uint32_t)ustr[0];
1835 len = 0; 1834 len = 0;
1836 } 1835 }
1837 c1 = c1 * 5 + 0x7b7d159cU; 1836 c1 = c1 * 5 + 0x7b7d159cU;
1838 c2 = c2 * 5 + 0x6bce6396U; 1837 c2 = c2 * 5 + 0x6bce6396U;
1839 k *= c1; 1838 k *= c1;
1840 k = (k << 11) ^ (k >> 21); 1839 k = (k << 11) ^ (k >> 21);
1841 k *= c2; 1840 k *= c2;
1842 h = (h << 13) ^ (h >> 19); 1841 h = (h << 13) ^ (h >> 19);
1843 h = h * 5 + 0x52dce729U; 1842 h = h * 5 + 0x52dce729U;
1844 h ^= k; 1843 h ^= k;
1845 } 1844 }
1846 h ^= (uint32_t)len2; 1845 h ^= (uint32_t)len2;
1847 h *= 0x85ebca6b; 1846 h *= 0x85ebca6b;
1848 h ^= h >> 13; 1847 h ^= h >> 13;
1849 h *= 0xc2b2ae35; 1848 h *= 0xc2b2ae35;
1850 h ^= h >> 16; 1849 h ^= h >> 16;
1851 1850
1852 buf = bmake_malloc(9); 1851 buf = bmake_malloc(9);
1853 for (i = 0; i < 8; i++) { 1852 for (i = 0; i < 8; i++) {
1854 buf[i] = hexdigits[h & 0x0f]; 1853 buf[i] = hexdigits[h & 0x0f];
1855 h >>= 4; 1854 h >>= 4;
1856 } 1855 }
1857 buf[8] = '\0'; 1856 buf[8] = '\0';
1858 return buf; 1857 return buf;
1859} 1858}
1860 1859
1861static char * 1860static char *
1862VarStrftime(const char *fmt, Boolean zulu, time_t tim) 1861VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1863{ 1862{
1864 char buf[BUFSIZ]; 1863 char buf[BUFSIZ];
1865 1864
1866 if (!tim) 1865 if (!tim)
1867 time(&tim); 1866 time(&tim);
1868 if (!*fmt) 1867 if (!*fmt)
1869 fmt = "%c"; 1868 fmt = "%c";
1870 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim)); 1869 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&tim) : localtime(&tim));
1871 1870
1872 buf[sizeof(buf) - 1] = '\0'; 1871 buf[sizeof(buf) - 1] = '\0';
1873 return bmake_strdup(buf); 1872 return bmake_strdup(buf);
1874} 1873}
1875 1874
1876/* The ApplyModifier functions all work in the same way. They get the 1875/* The ApplyModifier functions all work in the same way. They get the
1877 * current parsing position (pp) and parse the modifier from there. The 1876 * current parsing position (pp) and parse the modifier from there. The
1878 * modifier typically lasts until the next ':', or a closing '}' or ')' 1877 * modifier typically lasts until the next ':', or a closing '}' or ')'
1879 * (taken from st->endc), or the end of the string (parse error). 1878 * (taken from st->endc), or the end of the string (parse error).
1880 * 1879 *
1881 * The high-level behavior of these functions is: 1880 * The high-level behavior of these functions is:
1882 * 1881 *
1883 * 1. parse the modifier 1882 * 1. parse the modifier
1884 * 2. evaluate the modifier 1883 * 2. evaluate the modifier
1885 * 3. housekeeping 1884 * 3. housekeeping
1886 * 1885 *
1887 * Parsing the modifier 1886 * Parsing the modifier
1888 * 1887 *
1889 * If parsing succeeds, the parsing position *pp is updated to point to the 1888 * If parsing succeeds, the parsing position *pp is updated to point to the
1890 * first character following the modifier, which typically is either ':' or 1889 * first character following the modifier, which typically is either ':' or
1891 * st->endc. 1890 * st->endc.
1892 * 1891 *
1893 * If parsing fails because of a missing delimiter (as in the :S, :C or :@ 1892 * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1894 * modifiers), set st->missing_delim and return AMR_CLEANUP. 1893 * modifiers), set st->missing_delim and return AMR_CLEANUP.
1895 * 1894 *
1896 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to 1895 * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1897 * try the SysV modifier ${VAR:from=to} as fallback. This should only be 1896 * try the SysV modifier ${VAR:from=to} as fallback. This should only be
1898 * done as long as there have been no side effects from evaluating nested 1897 * done as long as there have been no side effects from evaluating nested
1899 * variables, to avoid evaluating them more than once. In this case, the 1898 * variables, to avoid evaluating them more than once. In this case, the
1900 * parsing position must not be updated. (XXX: Why not? The original parsing 1899 * parsing position must not be updated. (XXX: Why not? The original parsing
1901 * position is well-known in ApplyModifiers.) 1900 * position is well-known in ApplyModifiers.)
1902 * 1901 *
1903 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used 1902 * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1904 * as a fallback, either issue an error message using Error or Parse_Error 1903 * as a fallback, either issue an error message using Error or Parse_Error
1905 * and then return AMR_CLEANUP, or return AMR_BAD for the default error 1904 * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1906 * message. Both of these return values will stop processing the variable 1905 * message. Both of these return values will stop processing the variable
1907 * expression. (XXX: As of 2020-08-23, evaluation of the whole string 1906 * expression. (XXX: As of 2020-08-23, evaluation of the whole string
1908 * continues nevertheless after skipping a few bytes, which essentially is 1907 * continues nevertheless after skipping a few bytes, which essentially is
1909 * undefined behavior. Not in the sense of C, but still it's impossible to 1908 * undefined behavior. Not in the sense of C, but still it's impossible to
1910 * predict what happens in the parser.) 1909 * predict what happens in the parser.)
1911 * 1910 *
1912 * Evaluating the modifier 1911 * Evaluating the modifier
1913 * 1912 *
1914 * After parsing, the modifier is evaluated. The side effects from evaluating 1913 * After parsing, the modifier is evaluated. The side effects from evaluating
1915 * nested variable expressions in the modifier text often already happen 1914 * nested variable expressions in the modifier text often already happen
1916 * during parsing though. 1915 * during parsing though.
1917 * 1916 *
1918 * Evaluating the modifier usually takes the current value of the variable 1917 * Evaluating the modifier usually takes the current value of the variable
1919 * expression from st->val, or the variable name from st->v->name and stores 1918 * expression from st->val, or the variable name from st->v->name and stores
1920 * the result in st->newVal. 1919 * the result in st->newVal.
1921 * 1920 *
1922 * If evaluating fails (as of 2020-08-23), an error message is printed using 1921 * If evaluating fails (as of 2020-08-23), an error message is printed using
1923 * Error. This function has no side-effects, it really just prints the error 1922 * Error. This function has no side-effects, it really just prints the error
1924 * message. Processing the expression continues as if everything were ok. 1923 * message. Processing the expression continues as if everything were ok.
1925 * XXX: This should be fixed by adding proper error handling to Var_Subst, 1924 * XXX: This should be fixed by adding proper error handling to Var_Subst,
1926 * Var_Parse, ApplyModifiers and ModifyWords. 1925 * Var_Parse, ApplyModifiers and ModifyWords.
1927 * 1926 *
1928 * Housekeeping 1927 * Housekeeping
1929 * 1928 *
1930 * Some modifiers such as :D and :U turn undefined variables into useful 1929 * Some modifiers such as :D and :U turn undefined variables into useful
1931 * variables (VAR_JUNK, VAR_KEEP). 1930 * variables (VAR_JUNK, VAR_KEEP).
1932 * 1931 *
1933 * Some modifiers need to free some memory. 1932 * Some modifiers need to free some memory.
1934 */ 1933 */
1935 1934
1936typedef struct { 1935typedef struct {
1937 const char startc; /* '\0' or '{' or '(' */ 1936 const char startc; /* '\0' or '{' or '(' */
1938 const char endc; /* '\0' or '}' or ')' */ 1937 const char endc; /* '\0' or '}' or ')' */
1939 Var * const v; 1938 Var * const v;
1940 GNode * const ctxt; 1939 GNode * const ctxt;
1941 const VarEvalFlags eflags; 1940 const VarEvalFlags eflags;
1942 1941
1943 char *val; /* The old value of the expression, 1942 char *val; /* The old value of the expression,
1944 * before applying the modifier, never NULL */ 1943 * before applying the modifier, never NULL */
1945 char *newVal; /* The new value of the expression, 1944 char *newVal; /* The new value of the expression,
1946 * after applying the modifier, never NULL */ 1945 * after applying the modifier, never NULL */
1947 char missing_delim; /* For error reporting */ 1946 char missing_delim; /* For error reporting */
1948 1947
1949 char sep; /* Word separator in expansions 1948 char sep; /* Word separator in expansions
1950 * (see the :ts modifier) */ 1949 * (see the :ts modifier) */
1951 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split 1950 Boolean oneBigWord; /* TRUE if some modifiers that otherwise split
1952 * the variable value into words, like :S and 1951 * the variable value into words, like :S and
1953 * :C, treat the variable value as a single big 1952 * :C, treat the variable value as a single big
1954 * word, possibly containing spaces. */ 1953 * word, possibly containing spaces. */
1955} ApplyModifiersState; 1954} ApplyModifiersState;
1956 1955
1957typedef enum { 1956typedef enum {
1958 AMR_OK, /* Continue parsing */ 1957 AMR_OK, /* Continue parsing */
1959 AMR_UNKNOWN, /* Not a match, try other modifiers as well */ 1958 AMR_UNKNOWN, /* Not a match, try other modifiers as well */
1960 AMR_BAD, /* Error out with "Bad modifier" message */ 1959 AMR_BAD, /* Error out with "Bad modifier" message */
1961 AMR_CLEANUP /* Error out, with "Unfinished modifier" 1960 AMR_CLEANUP /* Error out, with "Unfinished modifier"
1962 * if st->missing_delim is set. */ 1961 * if st->missing_delim is set. */
1963} ApplyModifierResult; 1962} ApplyModifierResult;
1964 1963
1965/* Test whether mod starts with modname, followed by a delimiter. */ 1964/* Test whether mod starts with modname, followed by a delimiter. */
1966static Boolean 1965static Boolean
1967ModMatch(const char *mod, const char *modname, char endc) 1966ModMatch(const char *mod, const char *modname, char endc)
1968{ 1967{
1969 size_t n = strlen(modname); 1968 size_t n = strlen(modname);
1970 return strncmp(mod, modname, n) == 0 && 1969 return strncmp(mod, modname, n) == 0 &&
1971 (mod[n] == endc || mod[n] == ':'); 1970 (mod[n] == endc || mod[n] == ':');
1972} 1971}
1973 1972
1974/* Test whether mod starts with modname, followed by a delimiter or '='. */ 1973/* Test whether mod starts with modname, followed by a delimiter or '='. */
1975static inline Boolean 1974static inline Boolean
1976ModMatchEq(const char *mod, const char *modname, char endc) 1975ModMatchEq(const char *mod, const char *modname, char endc)
1977{ 1976{
1978 size_t n = strlen(modname); 1977 size_t n = strlen(modname);
1979 return strncmp(mod, modname, n) == 0 && 1978 return strncmp(mod, modname, n) == 0 &&
1980 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 1979 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
1981} 1980}
1982 1981
1983/* :@var@...${var}...@ */ 1982/* :@var@...${var}...@ */
1984static ApplyModifierResult 1983static ApplyModifierResult
1985ApplyModifier_Loop(const char **pp, ApplyModifiersState *st) 1984ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
1986{ 1985{
1987 ModifyWord_LoopArgs args; 1986 ModifyWord_LoopArgs args;
1988 char delim; 1987 char delim;
1989 char prev_sep; 1988 char prev_sep;
1990 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 1989 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
1991 1990
1992 args.ctx = st->ctxt; 1991 args.ctx = st->ctxt;
1993 1992
1994 (*pp)++; /* Skip the first '@' */ 1993 (*pp)++; /* Skip the first '@' */
1995 delim = '@'; 1994 delim = '@';
1996 args.tvar = ParseModifierPart(pp, delim, eflags, 1995 args.tvar = ParseModifierPart(pp, delim, eflags,
1997 st->ctxt, NULL, NULL, NULL); 1996 st->ctxt, NULL, NULL, NULL);
1998 if (args.tvar == NULL) { 1997 if (args.tvar == NULL) {
1999 st->missing_delim = delim; 1998 st->missing_delim = delim;
2000 return AMR_CLEANUP; 1999 return AMR_CLEANUP;
2001 } 2000 }
2002 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) { 2001 if (DEBUG(LINT) && strchr(args.tvar, '$') != NULL) {
2003 Parse_Error(PARSE_FATAL, 2002 Parse_Error(PARSE_FATAL,
2004 "In the :@ modifier of \"%s\", the variable name \"%s\" " 2003 "In the :@ modifier of \"%s\", the variable name \"%s\" "
2005 "must not contain a dollar.", 2004 "must not contain a dollar.",
2006 st->v->name, args.tvar); 2005 st->v->name, args.tvar);
2007 return AMR_CLEANUP; 2006 return AMR_CLEANUP;
2008 } 2007 }
2009 2008
2010 args.str = ParseModifierPart(pp, delim, eflags, 2009 args.str = ParseModifierPart(pp, delim, eflags,
2011 st->ctxt, NULL, NULL, NULL); 2010 st->ctxt, NULL, NULL, NULL);
2012 if (args.str == NULL) { 2011 if (args.str == NULL) {
2013 st->missing_delim = delim; 2012 st->missing_delim = delim;
2014 return AMR_CLEANUP; 2013 return AMR_CLEANUP;
2015 } 2014 }
2016 2015
2017 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2016 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2018 prev_sep = st->sep; 2017 prev_sep = st->sep;
2019 st->sep = ' '; /* XXX: should be st->sep for consistency */ 2018 st->sep = ' '; /* XXX: should be st->sep for consistency */
2020 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2019 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2021 ModifyWord_Loop, &args); 2020 ModifyWord_Loop, &args);
2022 st->sep = prev_sep; 2021 st->sep = prev_sep;
2023 Var_Delete(args.tvar, st->ctxt); 2022 Var_Delete(args.tvar, st->ctxt);
2024 free(args.tvar); 2023 free(args.tvar);
2025 free(args.str); 2024 free(args.str);
2026 return AMR_OK; 2025 return AMR_OK;
2027} 2026}
2028 2027
2029/* :Ddefined or :Uundefined */ 2028/* :Ddefined or :Uundefined */
2030static ApplyModifierResult 2029static ApplyModifierResult
2031ApplyModifier_Defined(const char **pp, ApplyModifiersState *st) 2030ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
2032{ 2031{
2033 Buffer buf; 2032 Buffer buf;
2034 const char *p; 2033 const char *p;
2035 2034
2036 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES; 2035 VarEvalFlags eflags = st->eflags & ~(unsigned)VARE_WANTRES;
2037 if (st->eflags & VARE_WANTRES) { 2036 if (st->eflags & VARE_WANTRES) {
2038 if ((**pp == 'D') == !(st->v->flags & VAR_JUNK)) 2037 if ((**pp == 'D') == !(st->v->flags & VAR_JUNK))
2039 eflags |= VARE_WANTRES; 2038 eflags |= VARE_WANTRES;
2040 } 2039 }
2041 2040
2042 Buf_Init(&buf, 0); 2041 Buf_Init(&buf, 0);
2043 p = *pp + 1; 2042 p = *pp + 1;
2044 while (*p != st->endc && *p != ':' && *p != '\0') { 2043 while (*p != st->endc && *p != ':' && *p != '\0') {
2045 2044
2046 /* Escaped delimiter or other special character */ 2045 /* Escaped delimiter or other special character */
2047 if (*p == '\\') { 2046 if (*p == '\\') {
2048 char c = p[1]; 2047 char c = p[1];
2049 if (c == st->endc || c == ':' || c == '$' || c == '\\') { 2048 if (c == st->endc || c == ':' || c == '$' || c == '\\') {
2050 Buf_AddByte(&buf, c); 2049 Buf_AddByte(&buf, c);
2051 p += 2; 2050 p += 2;
2052 continue; 2051 continue;
2053 } 2052 }
2054 } 2053 }
2055 2054
2056 /* Nested variable expression */ 2055 /* Nested variable expression */
2057 if (*p == '$') { 2056 if (*p == '$') {
2058 const char *cp2; 2057 const char *cp2;
2059 int len; 2058 int len;
2060 void *freeIt; 2059 void *freeIt;
2061 2060
2062 cp2 = Var_Parse(p, st->ctxt, eflags, &len, &freeIt); 2061 cp2 = Var_Parse(p, st->ctxt, eflags, &len, &freeIt);
2063 Buf_AddStr(&buf, cp2); 2062 Buf_AddStr(&buf, cp2);
2064 free(freeIt); 2063 free(freeIt);
2065 p += len; 2064 p += len;
2066 continue; 2065 continue;
2067 } 2066 }
2068 2067
2069 /* Ordinary text */ 2068 /* Ordinary text */
2070 Buf_AddByte(&buf, *p); 2069 Buf_AddByte(&buf, *p);
2071 p++; 2070 p++;
2072 } 2071 }
2073 *pp = p; 2072 *pp = p;
2074 2073
2075 if (st->v->flags & VAR_JUNK) 2074 if (st->v->flags & VAR_JUNK)
2076 st->v->flags |= VAR_KEEP; 2075 st->v->flags |= VAR_KEEP;
2077 if (eflags & VARE_WANTRES) { 2076 if (eflags & VARE_WANTRES) {
2078 st->newVal = Buf_Destroy(&buf, FALSE); 2077 st->newVal = Buf_Destroy(&buf, FALSE);
2079 } else { 2078 } else {
2080 st->newVal = st->val; 2079 st->newVal = st->val;
2081 Buf_Destroy(&buf, TRUE); 2080 Buf_Destroy(&buf, TRUE);
2082 } 2081 }
2083 return AMR_OK; 2082 return AMR_OK;
2084} 2083}
2085 2084
2086/* :gmtime */ 2085/* :gmtime */
2087static ApplyModifierResult 2086static ApplyModifierResult
2088ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st) 2087ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
2089{ 2088{
2090 time_t utc; 2089 time_t utc;
2091 2090
2092 const char *mod = *pp; 2091 const char *mod = *pp;
2093 if (!ModMatchEq(mod, "gmtime", st->endc)) 2092 if (!ModMatchEq(mod, "gmtime", st->endc))
2094 return AMR_UNKNOWN; 2093 return AMR_UNKNOWN;
2095 2094
2096 if (mod[6] == '=') { 2095 if (mod[6] == '=') {
2097 char *ep; 2096 char *ep;
2098 utc = (time_t)strtoul(mod + 7, &ep, 10); 2097 utc = (time_t)strtoul(mod + 7, &ep, 10);
2099 *pp = ep; 2098 *pp = ep;
2100 } else { 2099 } else {
2101 utc = 0; 2100 utc = 0;
2102 *pp = mod + 6; 2101 *pp = mod + 6;
2103 } 2102 }
2104 st->newVal = VarStrftime(st->val, TRUE, utc); 2103 st->newVal = VarStrftime(st->val, TRUE, utc);
2105 return AMR_OK; 2104 return AMR_OK;
2106} 2105}
2107 2106
2108/* :localtime */ 2107/* :localtime */
2109static Boolean 2108static Boolean
2110ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) 2109ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
2111{ 2110{
2112 time_t utc; 2111 time_t utc;
2113 2112
2114 const char *mod = *pp; 2113 const char *mod = *pp;
2115 if (!ModMatchEq(mod, "localtime", st->endc)) 2114 if (!ModMatchEq(mod, "localtime", st->endc))
2116 return AMR_UNKNOWN; 2115 return AMR_UNKNOWN;
2117 2116
2118 if (mod[9] == '=') { 2117 if (mod[9] == '=') {
2119 char *ep; 2118 char *ep;
2120 utc = (time_t)strtoul(mod + 10, &ep, 10); 2119 utc = (time_t)strtoul(mod + 10, &ep, 10);
2121 *pp = ep; 2120 *pp = ep;
2122 } else { 2121 } else {
2123 utc = 0; 2122 utc = 0;
2124 *pp = mod + 9; 2123 *pp = mod + 9;
2125 } 2124 }
2126 st->newVal = VarStrftime(st->val, FALSE, utc); 2125 st->newVal = VarStrftime(st->val, FALSE, utc);
2127 return AMR_OK; 2126 return AMR_OK;
2128} 2127}
2129 2128
2130/* :hash */ 2129/* :hash */
2131static ApplyModifierResult 2130static ApplyModifierResult
2132ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) 2131ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
2133{ 2132{
2134 if (!ModMatch(*pp, "hash", st->endc)) 2133 if (!ModMatch(*pp, "hash", st->endc))
2135 return AMR_UNKNOWN; 2134 return AMR_UNKNOWN;
2136 2135
2137 st->newVal = VarHash(st->val); 2136 st->newVal = VarHash(st->val);
2138 *pp += 4; 2137 *pp += 4;
2139 return AMR_OK; 2138 return AMR_OK;
2140} 2139}
2141 2140
2142/* :P */ 2141/* :P */
2143static ApplyModifierResult 2142static ApplyModifierResult
2144ApplyModifier_Path(const char **pp, ApplyModifiersState *st) 2143ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2145{ 2144{
2146 GNode *gn; 2145 GNode *gn;
2147 char *path; 2146 char *path;
2148 2147
2149 if (st->v->flags & VAR_JUNK) 2148 if (st->v->flags & VAR_JUNK)
2150 st->v->flags |= VAR_KEEP; 2149 st->v->flags |= VAR_KEEP;
2151 2150
2152 gn = Targ_FindNode(st->v->name, TARG_NOCREATE); 2151 gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2153 if (gn == NULL || gn->type & OP_NOPATH) { 2152 if (gn == NULL || gn->type & OP_NOPATH) {
2154 path = NULL; 2153 path = NULL;
2155 } else if (gn->path) { 2154 } else if (gn->path) {
2156 path = bmake_strdup(gn->path); 2155 path = bmake_strdup(gn->path);
2157 } else { 2156 } else {
2158 Lst searchPath = Suff_FindPath(gn); 2157 Lst searchPath = Suff_FindPath(gn);
2159 path = Dir_FindFile(st->v->name, searchPath); 2158 path = Dir_FindFile(st->v->name, searchPath);
2160 } 2159 }
2161 if (path == NULL) 2160 if (path == NULL)
2162 path = bmake_strdup(st->v->name); 2161 path = bmake_strdup(st->v->name);
2163 st->newVal = path; 2162 st->newVal = path;
2164 2163
2165 (*pp)++; 2164 (*pp)++;
2166 return AMR_OK; 2165 return AMR_OK;
2167} 2166}
2168 2167
2169/* :!cmd! */ 2168/* :!cmd! */
2170static ApplyModifierResult 2169static ApplyModifierResult
2171ApplyModifier_Exclam(const char **pp, ApplyModifiersState *st) 2170ApplyModifier_Exclam(const char **pp, ApplyModifiersState *st)
2172{ 2171{
2173 char delim; 2172 char delim;
2174 char *cmd; 2173 char *cmd;
2175 const char *errfmt; 2174 const char *errfmt;
2176 2175
2177 (*pp)++; 2176 (*pp)++;
2178 delim = '!'; 2177 delim = '!';
2179 cmd = ParseModifierPart(pp, delim, st->eflags, st->ctxt, 2178 cmd = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
2180 NULL, NULL, NULL); 2179 NULL, NULL, NULL);
2181 if (cmd == NULL) { 2180 if (cmd == NULL) {
2182 st->missing_delim = delim; 2181 st->missing_delim = delim;
2183 return AMR_CLEANUP; 2182 return AMR_CLEANUP;
2184 } 2183 }
2185 2184
2186 errfmt = NULL; 2185 errfmt = NULL;
2187 if (st->eflags & VARE_WANTRES) 2186 if (st->eflags & VARE_WANTRES)
2188 st->newVal = Cmd_Exec(cmd, &errfmt); 2187 st->newVal = Cmd_Exec(cmd, &errfmt);
2189 else 2188 else
2190 st->newVal = varNoError; 2189 st->newVal = varNoError;
2191 free(cmd); 2190 free(cmd);
2192 2191
2193 if (errfmt != NULL) 2192 if (errfmt != NULL)
2194 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */ 2193 Error(errfmt, st->val); /* XXX: why still return AMR_OK? */
2195 2194
2196 if (st->v->flags & VAR_JUNK) 2195 if (st->v->flags & VAR_JUNK)
2197 st->v->flags |= VAR_KEEP; 2196 st->v->flags |= VAR_KEEP;
2198 return AMR_OK; 2197 return AMR_OK;
2199} 2198}
2200 2199
2201/* The :range modifier generates an integer sequence as long as the words. 2200/* The :range modifier generates an integer sequence as long as the words.
2202 * The :range=7 modifier generates an integer sequence from 1 to 7. */ 2201 * The :range=7 modifier generates an integer sequence from 1 to 7. */
2203static ApplyModifierResult 2202static ApplyModifierResult
2204ApplyModifier_Range(const char **pp, ApplyModifiersState *st) 2203ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
2205{ 2204{
2206 size_t n; 2205 size_t n;
2207 Buffer buf; 2206 Buffer buf;
2208 size_t i; 2207 size_t i;
2209 2208
2210 const char *mod = *pp; 2209 const char *mod = *pp;
2211 if (!ModMatchEq(mod, "range", st->endc)) 2210 if (!ModMatchEq(mod, "range", st->endc))
2212 return AMR_UNKNOWN; 2211 return AMR_UNKNOWN;
2213 2212
2214 if (mod[5] == '=') { 2213 if (mod[5] == '=') {
2215 char *ep; 2214 char *ep;
2216 n = (size_t)strtoul(mod + 6, &ep, 10); 2215 n = (size_t)strtoul(mod + 6, &ep, 10);
2217 *pp = ep; 2216 *pp = ep;
2218 } else { 2217 } else {
2219 n = 0; 2218 n = 0;
2220 *pp = mod + 5; 2219 *pp = mod + 5;
2221 } 2220 }
2222 2221
2223 if (n == 0) { 2222 if (n == 0) {
2224 Words words = Str_Words(st->val, FALSE); 2223 Words words = Str_Words(st->val, FALSE);
2225 n = words.len; 2224 n = words.len;
2226 Words_Free(words); 2225 Words_Free(words);
2227 } 2226 }
2228 2227
2229 Buf_Init(&buf, 0); 2228 Buf_Init(&buf, 0);
2230 2229
2231 for (i = 0; i < n; i++) { 2230 for (i = 0; i < n; i++) {
2232 if (i != 0) 2231 if (i != 0)
2233 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ 2232 Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */
2234 Buf_AddInt(&buf, 1 + (int)i); 2233 Buf_AddInt(&buf, 1 + (int)i);
2235 } 2234 }
2236 2235
2237 st->newVal = Buf_Destroy(&buf, FALSE); 2236 st->newVal = Buf_Destroy(&buf, FALSE);
2238 return AMR_OK; 2237 return AMR_OK;
2239} 2238}
2240 2239
2241/* :Mpattern or :Npattern */ 2240/* :Mpattern or :Npattern */
2242static ApplyModifierResult 2241static ApplyModifierResult
2243ApplyModifier_Match(const char **pp, ApplyModifiersState *st) 2242ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
2244{ 2243{
2245 const char *mod = *pp; 2244 const char *mod = *pp;
2246 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2245 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2247 Boolean needSubst = FALSE; 2246 Boolean needSubst = FALSE;
2248 const char *endpat; 2247 const char *endpat;
2249 char *pattern; 2248 char *pattern;
2250 ModifyWordsCallback callback; 2249 ModifyWordsCallback callback;
2251 2250
2252 /* 2251 /*
2253 * In the loop below, ignore ':' unless we are at (or back to) the 2252 * In the loop below, ignore ':' unless we are at (or back to) the
2254 * original brace level. 2253 * original brace level.
2255 * XXX This will likely not work right if $() and ${} are intermixed. 2254 * XXX This will likely not work right if $() and ${} are intermixed.
2256 */ 2255 */
2257 int nest = 0; 2256 int nest = 0;
2258 const char *p; 2257 const char *p;
2259 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) { 2258 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2260 if (*p == '\\' && 2259 if (*p == '\\' &&
2261 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2260 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2262 if (!needSubst) 2261 if (!needSubst)
2263 copy = TRUE; 2262 copy = TRUE;
2264 p++; 2263 p++;
2265 continue; 2264 continue;
2266 } 2265 }
2267 if (*p == '$') 2266 if (*p == '$')
2268 needSubst = TRUE; 2267 needSubst = TRUE;
2269 if (*p == '(' || *p == '{') 2268 if (*p == '(' || *p == '{')
2270 nest++; 2269 nest++;
2271 if (*p == ')' || *p == '}') { 2270 if (*p == ')' || *p == '}') {
2272 nest--; 2271 nest--;
2273 if (nest < 0) 2272 if (nest < 0)
2274 break; 2273 break;
2275 } 2274 }
2276 } 2275 }
2277 *pp = p; 2276 *pp = p;
2278 endpat = p; 2277 endpat = p;
2279 2278
2280 if (copy) { 2279 if (copy) {
2281 char *dst; 2280 char *dst;
2282 const char *src; 2281 const char *src;
2283 2282
2284 /* Compress the \:'s out of the pattern. */ 2283 /* Compress the \:'s out of the pattern. */
2285 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1); 2284 pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2286 dst = pattern; 2285 dst = pattern;
2287 src = mod + 1; 2286 src = mod + 1;
2288 for (; src < endpat; src++, dst++) { 2287 for (; src < endpat; src++, dst++) {
2289 if (src[0] == '\\' && src + 1 < endpat && 2288 if (src[0] == '\\' && src + 1 < endpat &&
2290 /* XXX: st->startc is missing here; see above */ 2289 /* XXX: st->startc is missing here; see above */
2291 (src[1] == ':' || src[1] == st->endc)) 2290 (src[1] == ':' || src[1] == st->endc))
2292 src++; 2291 src++;
2293 *dst = *src; 2292 *dst = *src;
2294 } 2293 }
2295 *dst = '\0'; 2294 *dst = '\0';
2296 endpat = dst; 2295 endpat = dst;
2297 } else { 2296 } else {
2298 pattern = bmake_strsedup(mod + 1, endpat); 2297 pattern = bmake_strsedup(mod + 1, endpat);
2299 } 2298 }
2300 2299
2301 if (needSubst) { 2300 if (needSubst) {
2302 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2301 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2303 char *old_pattern = pattern; 2302 char *old_pattern = pattern;
2304 pattern = Var_Subst(pattern, st->ctxt, st->eflags); 2303 pattern = Var_Subst(pattern, st->ctxt, st->eflags);
2305 free(old_pattern); 2304 free(old_pattern);
2306 } 2305 }
2307 2306
2308 VAR_DEBUG("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern); 2307 VAR_DEBUG("Pattern[%s] for [%s] is [%s]\n", st->v->name, st->val, pattern);
2309 2308
2310 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch; 2309 callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2311 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2310 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2312 callback, pattern); 2311 callback, pattern);
2313 free(pattern); 2312 free(pattern);
2314 return AMR_OK; 2313 return AMR_OK;
2315} 2314}
2316 2315
2317/* :S,from,to, */ 2316/* :S,from,to, */
2318static ApplyModifierResult 2317static ApplyModifierResult
2319ApplyModifier_Subst(const char **pp, ApplyModifiersState *st) 2318ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
2320{ 2319{
2321 ModifyWord_SubstArgs args; 2320 ModifyWord_SubstArgs args;
2322 char *lhs, *rhs; 2321 char *lhs, *rhs;
2323 Boolean oneBigWord; 2322 Boolean oneBigWord;
2324 2323
2325 char delim = (*pp)[1]; 2324 char delim = (*pp)[1];
2326 if (delim == '\0') { 2325 if (delim == '\0') {
2327 Error("Missing delimiter for :S modifier"); 2326 Error("Missing delimiter for :S modifier");
2328 (*pp)++; 2327 (*pp)++;
2329 return AMR_CLEANUP; 2328 return AMR_CLEANUP;
2330 } 2329 }
2331 2330
2332 *pp += 2; 2331 *pp += 2;
2333 2332
2334 args.pflags = 0; 2333 args.pflags = 0;
2335 args.matched = FALSE; 2334 args.matched = FALSE;
2336 2335
2337 /* 2336 /*
2338 * If pattern begins with '^', it is anchored to the 2337 * If pattern begins with '^', it is anchored to the
2339 * start of the word -- skip over it and flag pattern. 2338 * start of the word -- skip over it and flag pattern.
2340 */ 2339 */
2341 if (**pp == '^') { 2340 if (**pp == '^') {
2342 args.pflags |= VARP_ANCHOR_START; 2341 args.pflags |= VARP_ANCHOR_START;
2343 (*pp)++; 2342 (*pp)++;
2344 } 2343 }
2345 2344
2346 lhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt, 2345 lhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
2347 &args.lhsLen, &args.pflags, NULL); 2346 &args.lhsLen, &args.pflags, NULL);
2348 if (lhs == NULL) { 2347 if (lhs == NULL) {
2349 st->missing_delim = delim; 2348 st->missing_delim = delim;
2350 return AMR_CLEANUP; 2349 return AMR_CLEANUP;
2351 } 2350 }
2352 args.lhs = lhs; 2351 args.lhs = lhs;
2353 2352
2354 rhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt, 2353 rhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
2355 &args.rhsLen, NULL, &args); 2354 &args.rhsLen, NULL, &args);
2356 if (rhs == NULL) { 2355 if (rhs == NULL) {
2357 st->missing_delim = delim; 2356 st->missing_delim = delim;
2358 return AMR_CLEANUP; 2357 return AMR_CLEANUP;
2359 } 2358 }
2360 args.rhs = rhs; 2359 args.rhs = rhs;
2361 2360
2362 oneBigWord = st->oneBigWord; 2361 oneBigWord = st->oneBigWord;
2363 for (;; (*pp)++) { 2362 for (;; (*pp)++) {
2364 switch (**pp) { 2363 switch (**pp) {
2365 case 'g': 2364 case 'g':
2366 args.pflags |= VARP_SUB_GLOBAL; 2365 args.pflags |= VARP_SUB_GLOBAL;
2367 continue; 2366 continue;
2368 case '1': 2367 case '1':
2369 args.pflags |= VARP_SUB_ONE; 2368 args.pflags |= VARP_SUB_ONE;
2370 continue; 2369 continue;
2371 case 'W': 2370 case 'W':
2372 oneBigWord = TRUE; 2371 oneBigWord = TRUE;
2373 continue; 2372 continue;
2374 } 2373 }
2375 break; 2374 break;
2376 } 2375 }
2377 2376
2378 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val, 2377 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val,
2379 ModifyWord_Subst, &args); 2378 ModifyWord_Subst, &args);
2380 2379
2381 free(lhs); 2380 free(lhs);
2382 free(rhs); 2381 free(rhs);
2383 return AMR_OK; 2382 return AMR_OK;
2384} 2383}
2385 2384
2386#ifndef NO_REGEX 2385#ifndef NO_REGEX
2387 2386
2388/* :C,from,to, */ 2387/* :C,from,to, */
2389static ApplyModifierResult 2388static ApplyModifierResult
2390ApplyModifier_Regex(const char **pp, ApplyModifiersState *st) 2389ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
2391{ 2390{
2392 char *re; 2391 char *re;
2393 ModifyWord_SubstRegexArgs args; 2392 ModifyWord_SubstRegexArgs args;
2394 Boolean oneBigWord; 2393 Boolean oneBigWord;
2395 int error; 2394 int error;
2396 2395
2397 char delim = (*pp)[1]; 2396 char delim = (*pp)[1];
2398 if (delim == '\0') { 2397 if (delim == '\0') {
2399 Error("Missing delimiter for :C modifier"); 2398 Error("Missing delimiter for :C modifier");
2400 (*pp)++; 2399 (*pp)++;
2401 return AMR_CLEANUP; 2400 return AMR_CLEANUP;
2402 } 2401 }
2403 2402
2404 *pp += 2; 2403 *pp += 2;
2405 2404
2406 re = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL); 2405 re = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL);
2407 if (re == NULL) { 2406 if (re == NULL) {
2408 st->missing_delim = delim; 2407 st->missing_delim = delim;
2409 return AMR_CLEANUP; 2408 return AMR_CLEANUP;
2410 } 2409 }
2411 2410
2412 args.replace = ParseModifierPart(pp, delim, st->eflags, st->ctxt, 2411 args.replace = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
2413 NULL, NULL, NULL); 2412 NULL, NULL, NULL);
2414 if (args.replace == NULL) { 2413 if (args.replace == NULL) {
2415 free(re); 2414 free(re);
2416 st->missing_delim = delim; 2415 st->missing_delim = delim;
2417 return AMR_CLEANUP; 2416 return AMR_CLEANUP;
2418 } 2417 }
2419 2418
2420 args.pflags = 0; 2419 args.pflags = 0;
2421 args.matched = FALSE; 2420 args.matched = FALSE;
2422 oneBigWord = st->oneBigWord; 2421 oneBigWord = st->oneBigWord;
2423 for (;; (*pp)++) { 2422 for (;; (*pp)++) {
2424 switch (**pp) { 2423 switch (**pp) {
2425 case 'g': 2424 case 'g':
2426 args.pflags |= VARP_SUB_GLOBAL; 2425 args.pflags |= VARP_SUB_GLOBAL;
2427 continue; 2426 continue;
2428 case '1': 2427 case '1':
2429 args.pflags |= VARP_SUB_ONE; 2428 args.pflags |= VARP_SUB_ONE;
2430 continue; 2429 continue;
2431 case 'W': 2430 case 'W':
2432 oneBigWord = TRUE; 2431 oneBigWord = TRUE;
2433 continue; 2432 continue;
2434 } 2433 }
2435 break; 2434 break;
2436 } 2435 }
2437 2436
2438 error = regcomp(&args.re, re, REG_EXTENDED); 2437 error = regcomp(&args.re, re, REG_EXTENDED);
2439 free(re); 2438 free(re);
2440 if (error) { 2439 if (error) {
2441 VarREError(error, &args.re, "Regex compilation error"); 2440 VarREError(error, &args.re, "Regex compilation error");
2442 free(args.replace); 2441 free(args.replace);
2443 return AMR_CLEANUP; 2442 return AMR_CLEANUP;
2444 } 2443 }
2445 2444
2446 args.nsub = args.re.re_nsub + 1; 2445 args.nsub = args.re.re_nsub + 1;
2447 if (args.nsub > 10) 2446 if (args.nsub > 10)
2448 args.nsub = 10; 2447 args.nsub = 10;
2449 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val, 2448 st->newVal = ModifyWords(st->ctxt, st->sep, oneBigWord, st->val,
2450 ModifyWord_SubstRegex, &args); 2449 ModifyWord_SubstRegex, &args);
2451 regfree(&args.re); 2450 regfree(&args.re);
2452 free(args.replace); 2451 free(args.replace);
2453 return AMR_OK; 2452 return AMR_OK;
2454} 2453}
2455#endif 2454#endif
2456 2455
2457static void 2456static void
2458ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2457ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2459{ 2458{
2460 SepBuf_AddStr(buf, word); 2459 SepBuf_AddStr(buf, word);
2461} 2460}
2462 2461
2463/* :ts<separator> */ 2462/* :ts<separator> */
2464static ApplyModifierResult 2463static ApplyModifierResult
2465ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) 2464ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
2466{ 2465{
2467 /* XXX: pp points to the 's', for historic reasons only. 2466 /* XXX: pp points to the 's', for historic reasons only.
2468 * Changing this will influence the error messages. */ 2467 * Changing this will influence the error messages. */
2469 const char *sep = *pp + 1; 2468 const char *sep = *pp + 1;
2470 2469
2471 /* ":ts<any><endc>" or ":ts<any>:" */ 2470 /* ":ts<any><endc>" or ":ts<any>:" */
2472 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2471 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2473 st->sep = sep[0]; 2472 st->sep = sep[0];
2474 *pp = sep + 1; 2473 *pp = sep + 1;
2475 goto ok; 2474 goto ok;
2476 } 2475 }
2477 2476
2478 /* ":ts<endc>" or ":ts:" */ 2477 /* ":ts<endc>" or ":ts:" */
2479 if (sep[0] == st->endc || sep[0] == ':') { 2478 if (sep[0] == st->endc || sep[0] == ':') {
2480 st->sep = '\0'; /* no separator */ 2479 st->sep = '\0'; /* no separator */
2481 *pp = sep; 2480 *pp = sep;
2482 goto ok; 2481 goto ok;
2483 } 2482 }
2484 2483
2485 /* ":ts<unrecognised><unrecognised>". */ 2484 /* ":ts<unrecognised><unrecognised>". */
2486 if (sep[0] != '\\') 2485 if (sep[0] != '\\')
2487 return AMR_BAD; 2486 return AMR_BAD;
2488 2487
2489 /* ":ts\n" */ 2488 /* ":ts\n" */
2490 if (sep[1] == 'n') { 2489 if (sep[1] == 'n') {
2491 st->sep = '\n'; 2490 st->sep = '\n';
2492 *pp = sep + 2; 2491 *pp = sep + 2;
2493 goto ok; 2492 goto ok;
2494 } 2493 }
2495 2494
2496 /* ":ts\t" */ 2495 /* ":ts\t" */
2497 if (sep[1] == 't') { 2496 if (sep[1] == 't') {
2498 st->sep = '\t'; 2497 st->sep = '\t';
2499 *pp = sep + 2; 2498 *pp = sep + 2;
2500 goto ok; 2499 goto ok;
2501 } 2500 }
2502 2501
2503 /* ":ts\x40" or ":ts\100" */ 2502 /* ":ts\x40" or ":ts\100" */
2504 { 2503 {
2505 const char *numStart = sep + 1; 2504 const char *numStart = sep + 1;
2506 int base = 8; /* assume octal */ 2505 int base = 8; /* assume octal */
2507 char *end; 2506 char *end;
2508 2507
2509 if (sep[1] == 'x') { 2508 if (sep[1] == 'x') {
2510 base = 16; 2509 base = 16;
2511 numStart++; 2510 numStart++;
2512 } else if (!isdigit((unsigned char)sep[1])) 2511 } else if (!isdigit((unsigned char)sep[1]))
2513 return AMR_BAD; /* ":ts<backslash><unrecognised>". */ 2512 return AMR_BAD; /* ":ts<backslash><unrecognised>". */
2514 2513
2515 st->sep = (char)strtoul(numStart, &end, base); 2514 st->sep = (char)strtoul(numStart, &end, base);
2516 if (*end != ':' && *end != st->endc) 2515 if (*end != ':' && *end != st->endc)
2517 return AMR_BAD; 2516 return AMR_BAD;
2518 *pp = end; 2517 *pp = end;
2519 } 2518 }
2520 2519
2521ok: 2520ok:
2522 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2521 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2523 ModifyWord_Copy, NULL); 2522 ModifyWord_Copy, NULL);
2524 return AMR_OK; 2523 return AMR_OK;
2525} 2524}
2526 2525
2527/* :tA, :tu, :tl, :ts<separator>, etc. */ 2526/* :tA, :tu, :tl, :ts<separator>, etc. */
2528static ApplyModifierResult 2527static ApplyModifierResult
2529ApplyModifier_To(const char **pp, ApplyModifiersState *st) 2528ApplyModifier_To(const char **pp, ApplyModifiersState *st)
2530{ 2529{
2531 const char *mod = *pp; 2530 const char *mod = *pp;
2532 assert(mod[0] == 't'); 2531 assert(mod[0] == 't');
2533 2532
2534 *pp = mod + 1; /* make sure it is set */ 2533 *pp = mod + 1; /* make sure it is set */
2535 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') 2534 if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0')
2536 return AMR_BAD; /* Found ":t<endc>" or ":t:". */ 2535 return AMR_BAD; /* Found ":t<endc>" or ":t:". */
2537 2536
2538 if (mod[1] == 's') 2537 if (mod[1] == 's')
2539 return ApplyModifier_ToSep(pp, st); 2538 return ApplyModifier_ToSep(pp, st);
2540 2539
2541 if (mod[2] != st->endc && mod[2] != ':') 2540 if (mod[2] != st->endc && mod[2] != ':')
2542 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ 2541 return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */
2543 2542
2544 /* Check for two-character options: ":tu", ":tl" */ 2543 /* Check for two-character options: ":tu", ":tl" */
2545 if (mod[1] == 'A') { /* absolute path */ 2544 if (mod[1] == 'A') { /* absolute path */
2546 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, 2545 st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val,
2547 ModifyWord_Realpath, NULL); 2546 ModifyWord_Realpath, NULL);
2548 *pp = mod + 2; 2547 *pp = mod + 2;
2549 return AMR_OK; 2548 return AMR_OK;
2550 } 2549 }
2551 2550
2552 if (mod[1] == 'u') { 2551 if (mod[1] == 'u') {
2553 size_t i; 2552 size_t i;
2554 size_t len = strlen(st->val); 2553 size_t len = strlen(st->val);
2555 st->newVal = bmake_malloc(len + 1); 2554 st->newVal = bmake_malloc(len + 1);
2556 for (i = 0; i < len + 1; i++) 2555 for (i = 0; i < len + 1; i++)
2557 st->newVal[i] = (char)toupper((unsigned char)st->val[i]); 2556 st->newVal[i] = (char)toupper((unsigned char)st->val[i]);
2558 *pp = mod + 2; 2557 *pp = mod + 2;
2559 return AMR_OK; 2558 return AMR_OK;
2560 } 2559 }
2561 2560
2562 if (mod[1] == 'l') { 2561 if (mod[1] == 'l') {
2563 size_t i; 2562 size_t i;
2564 size_t len = strlen(st->val); 2563 size_t len = strlen(st->val);
2565 st->newVal = bmake_malloc(len + 1); 2564 st->newVal = bmake_malloc(len + 1);
2566 for (i = 0; i < len + 1; i++) 2565 for (i = 0; i < len + 1; i++)
2567 st->newVal[i] = (char)tolower((unsigned char)st->val[i]); 2566 st->newVal[i] = (char)tolower((unsigned char)st->val[i]);
2568 *pp = mod + 2; 2567 *pp = mod + 2;
2569 return AMR_OK; 2568 return AMR_OK;
2570 } 2569 }
2571 2570
2572 if (mod[1] == 'W' || mod[1] == 'w') { 2571 if (mod[1] == 'W' || mod[1] == 'w') {
2573 st->oneBigWord = mod[1] == 'W'; 2572 st->oneBigWord = mod[1] == 'W';
2574 st->newVal = st->val; 2573 st->newVal = st->val;
2575 *pp = mod + 2; 2574 *pp = mod + 2;
2576 return AMR_OK; 2575 return AMR_OK;
2577 } 2576 }
2578 2577
2579 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2578 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2580 return AMR_BAD; 2579 return AMR_BAD;
2581} 2580}
2582 2581
2583/* :[#], :[1], etc. */ 2582/* :[#], :[1], etc. */
2584static ApplyModifierResult 2583static ApplyModifierResult
2585ApplyModifier_Words(const char **pp, ApplyModifiersState *st) 2584ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
2586{ 2585{
2587 char delim; 2586 char delim;
2588 char *estr; 2587 char *estr;
2589 char *ep; 2588 char *ep;
2590 int first, last; 2589 int first, last;
2591 2590
2592 (*pp)++; /* skip the '[' */ 2591 (*pp)++; /* skip the '[' */
2593 delim = ']'; /* look for closing ']' */ 2592 delim = ']'; /* look for closing ']' */
2594 estr = ParseModifierPart(pp, delim, st->eflags, st->ctxt, 2593 estr = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
2595 NULL, NULL, NULL); 2594 NULL, NULL, NULL);
2596 if (estr == NULL) { 2595 if (estr == NULL) {
2597 st->missing_delim = delim; 2596 st->missing_delim = delim;
2598 return AMR_CLEANUP; 2597 return AMR_CLEANUP;
2599 } 2598 }
2600 2599
2601 /* now *pp points just after the closing ']' */ 2600 /* now *pp points just after the closing ']' */
2602 if (**pp != ':' && **pp != st->endc) 2601 if (**pp != ':' && **pp != st->endc)
2603 goto bad_modifier; /* Found junk after ']' */ 2602 goto bad_modifier; /* Found junk after ']' */
2604 2603
2605 if (estr[0] == '\0') 2604 if (estr[0] == '\0')
2606 goto bad_modifier; /* empty square brackets in ":[]". */ 2605 goto bad_modifier; /* empty square brackets in ":[]". */
2607 2606
2608 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2607 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2609 if (st->oneBigWord) { 2608 if (st->oneBigWord) {
2610 st->newVal = bmake_strdup("1"); 2609 st->newVal = bmake_strdup("1");
2611 } else { 2610 } else {
2612 Buffer buf; 2611 Buffer buf;
2613 2612
2614 Words words = Str_Words(st->val, FALSE); 2613 Words words = Str_Words(st->val, FALSE);
2615 size_t ac = words.len; 2614 size_t ac = words.len;
2616 Words_Free(words); 2615 Words_Free(words);
2617  2616