Mon Jul 27 22:21:29 2020 UTC ()
make(1): remove unnecessary variable assignment

It is not the job of an ApplyModifier function to directly manipulate the
final result of the ApplyModifiers function.  In fact, the resulting
pointer was overwritten unconditionally, in such an obvious way that the
compiler could have detected this.  GCC 5 didn't though, which reduces
the code size a bit.


(rillig)
diff -r1.341 -r1.342 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/07/27 22:02:26 1.341
+++ src/usr.bin/make/var.c 2020/07/27 22:21:29 1.342
@@ -1,1078 +1,1078 @@ @@ -1,1078 +1,1078 @@
1/* $NetBSD: var.c,v 1.341 2020/07/27 22:02:26 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.342 2020/07/27 22:21:29 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71#ifndef MAKE_NATIVE 71#ifndef MAKE_NATIVE
72static char rcsid[] = "$NetBSD: var.c,v 1.341 2020/07/27 22:02:26 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.342 2020/07/27 22:21:29 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.341 2020/07/27 22:02:26 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.342 2020/07/27 22:21:29 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 <ctype.h> 127#include <ctype.h>
128#include <inttypes.h> 128#include <inttypes.h>
129#include <limits.h> 129#include <limits.h>
130#include <stdlib.h> 130#include <stdlib.h>
131#include <time.h> 131#include <time.h>
132 132
133#include "make.h" 133#include "make.h"
134#include "buf.h" 134#include "buf.h"
135#include "dir.h" 135#include "dir.h"
136#include "job.h" 136#include "job.h"
137#include "metachar.h" 137#include "metachar.h"
138 138
139#define VAR_DEBUG(fmt, ...) \ 139#define VAR_DEBUG(fmt, ...) \
140 if (!DEBUG(VAR)) \ 140 if (!DEBUG(VAR)) \
141 (void) 0; \ 141 (void) 0; \
142 else \ 142 else \
143 fprintf(debug_file, fmt, __VA_ARGS__) 143 fprintf(debug_file, fmt, __VA_ARGS__)
144 144
145/* 145/*
146 * This lets us tell if we have replaced the original environ 146 * This lets us tell if we have replaced the original environ
147 * (which we cannot free). 147 * (which we cannot free).
148 */ 148 */
149char **savedEnv = NULL; 149char **savedEnv = NULL;
150 150
151/* 151/*
152 * This is a harmless return value for Var_Parse that can be used by Var_Subst 152 * This is a harmless return value for Var_Parse that can be used by Var_Subst
153 * to determine if there was an error in parsing -- easier than returning 153 * to determine if there was an error in parsing -- easier than returning
154 * a flag, as things outside this module don't give a hoot. 154 * a flag, as things outside this module don't give a hoot.
155 */ 155 */
156char var_Error[] = ""; 156char var_Error[] = "";
157 157
158/* 158/*
159 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for 159 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for
160 * Var_Parse is not set. Why not just use a constant? Well, GCC likes 160 * Var_Parse is not set. Why not just use a constant? Well, GCC likes
161 * to condense identical string instances... 161 * to condense identical string instances...
162 */ 162 */
163static char varNoError[] = ""; 163static char varNoError[] = "";
164 164
165/* 165/*
166 * Traditionally we consume $$ during := like any other expansion. 166 * Traditionally we consume $$ during := like any other expansion.
167 * Other make's do not. 167 * Other make's do not.
168 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
169 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
170 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
171 */ 171 */
172#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
173static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
174 174
175/* 175/*
176 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
177 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
178 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
179 * context. 179 * context.
180 * 2) the global context. Variables set in the Makefile are located in 180 * 2) the global context. Variables set in the Makefile are located in
181 * the global context. 181 * the global context.
182 * 3) the command-line context. All variables set on the command line 182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. They are UNALTERABLE once placed here. 183 * are placed in this context. They are UNALTERABLE once placed here.
184 * 4) the local context. Each target has associated with it a context 184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are 187 * The four contexts are searched in the reverse order from which they are
188 * listed (but see checkEnvFirst). 188 * listed (but see checkEnvFirst).
189 */ 189 */
190GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
191GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
192GNode *VAR_CMD; /* variables defined on the command-line */ 192GNode *VAR_CMD; /* variables defined on the command-line */
193 193
194typedef enum { 194typedef enum {
195 FIND_CMD = 0x01, /* look in VAR_CMD when searching */ 195 FIND_CMD = 0x01, /* look in VAR_CMD when searching */
196 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ 196 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */
197 FIND_ENV = 0x04 /* look in the environment also */ 197 FIND_ENV = 0x04 /* look in the environment also */
198} VarFindFlags; 198} VarFindFlags;
199 199
200typedef enum { 200typedef enum {
201 VAR_IN_USE = 0x01, /* Variable's value is currently being used 201 VAR_IN_USE = 0x01, /* Variable's value is currently being used
202 * by Var_Parse or Var_Subst. 202 * by Var_Parse or Var_Subst.
203 * Used to avoid endless recursion */ 203 * Used to avoid endless recursion */
204 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */ 204 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */
205 VAR_JUNK = 0x04, /* Variable is a junk variable that 205 VAR_JUNK = 0x04, /* Variable is a junk variable that
206 * should be destroyed when done with 206 * should be destroyed when done with
207 * it. Used by Var_Parse for undefined, 207 * it. Used by Var_Parse for undefined,
208 * modified variables */ 208 * modified variables */
209 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found 209 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found
210 * a use for it in some modifier and 210 * a use for it in some modifier and
211 * the value is therefore valid */ 211 * the value is therefore valid */
212 VAR_EXPORTED = 0x10, /* Variable is exported */ 212 VAR_EXPORTED = 0x10, /* Variable is exported */
213 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export. 213 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export.
214 * This would be true if it contains $'s */ 214 * This would be true if it contains $'s */
215 VAR_FROM_CMD = 0x40 /* Variable came from command line */ 215 VAR_FROM_CMD = 0x40 /* Variable came from command line */
216} Var_Flags; 216} Var_Flags;
217 217
218typedef struct Var { 218typedef struct Var {
219 char *name; /* the variable's name */ 219 char *name; /* the variable's name */
220 Buffer val; /* its value */ 220 Buffer val; /* its value */
221 Var_Flags flags; /* miscellaneous status flags */ 221 Var_Flags flags; /* miscellaneous status flags */
222} Var; 222} Var;
223 223
224/* 224/*
225 * Exporting vars is expensive so skip it if we can 225 * Exporting vars is expensive so skip it if we can
226 */ 226 */
227typedef enum { 227typedef enum {
228 VAR_EXPORTED_NONE, 228 VAR_EXPORTED_NONE,
229 VAR_EXPORTED_YES, 229 VAR_EXPORTED_YES,
230 VAR_EXPORTED_ALL 230 VAR_EXPORTED_ALL
231} VarExportedMode; 231} VarExportedMode;
232static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 232static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
233 233
234typedef enum { 234typedef enum {
235 /* 235 /*
236 * We pass this to Var_Export when doing the initial export 236 * We pass this to Var_Export when doing the initial export
237 * or after updating an exported var. 237 * or after updating an exported var.
238 */ 238 */
239 VAR_EXPORT_PARENT = 0x01, 239 VAR_EXPORT_PARENT = 0x01,
240 /* 240 /*
241 * We pass this to Var_Export1 to tell it to leave the value alone. 241 * We pass this to Var_Export1 to tell it to leave the value alone.
242 */ 242 */
243 VAR_EXPORT_LITERAL = 0x02 243 VAR_EXPORT_LITERAL = 0x02
244} VarExportFlags; 244} VarExportFlags;
245 245
246/* Flags for pattern matching in the :S and :C modifiers */ 246/* Flags for pattern matching in the :S and :C modifiers */
247typedef enum { 247typedef enum {
248 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */ 248 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */
249 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */ 249 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */
250 VARP_SUB_MATCHED = 0x04, /* There was a match */ 250 VARP_SUB_MATCHED = 0x04, /* There was a match */
251 VARP_ANCHOR_START = 0x08, /* Match at start of word */ 251 VARP_ANCHOR_START = 0x08, /* Match at start of word */
252 VARP_ANCHOR_END = 0x10 /* Match at end of word */ 252 VARP_ANCHOR_END = 0x10 /* Match at end of word */
253} VarPatternFlags; 253} VarPatternFlags;
254 254
255typedef enum { 255typedef enum {
256 VAR_NO_EXPORT = 0x01 /* do not export */ 256 VAR_NO_EXPORT = 0x01 /* do not export */
257} VarSet_Flags; 257} VarSet_Flags;
258 258
259#define BROPEN '{' 259#define BROPEN '{'
260#define BRCLOSE '}' 260#define BRCLOSE '}'
261#define PROPEN '(' 261#define PROPEN '('
262#define PRCLOSE ')' 262#define PRCLOSE ')'
263 263
264/*- 264/*-
265 *----------------------------------------------------------------------- 265 *-----------------------------------------------------------------------
266 * VarFind -- 266 * VarFind --
267 * Find the given variable in the given context and any other contexts 267 * Find the given variable in the given context and any other contexts
268 * indicated. 268 * indicated.
269 * 269 *
270 * Input: 270 * Input:
271 * name name to find 271 * name name to find
272 * ctxt context in which to find it 272 * ctxt context in which to find it
273 * flags FIND_GLOBAL look in VAR_GLOBAL as well 273 * flags FIND_GLOBAL look in VAR_GLOBAL as well
274 * FIND_CMD look in VAR_CMD as well 274 * FIND_CMD look in VAR_CMD as well
275 * FIND_ENV look in the environment as well 275 * FIND_ENV look in the environment as well
276 * 276 *
277 * Results: 277 * Results:
278 * A pointer to the structure describing the desired variable or 278 * A pointer to the structure describing the desired variable or
279 * NULL if the variable does not exist. 279 * NULL if the variable does not exist.
280 * 280 *
281 * Side Effects: 281 * Side Effects:
282 * None 282 * None
283 *----------------------------------------------------------------------- 283 *-----------------------------------------------------------------------
284 */ 284 */
285static Var * 285static Var *
286VarFind(const char *name, GNode *ctxt, VarFindFlags flags) 286VarFind(const char *name, GNode *ctxt, VarFindFlags flags)
287{ 287{
288 /* 288 /*
289 * If the variable name begins with a '.', it could very well be one of 289 * If the variable name begins with a '.', it could very well be one of
290 * the local ones. We check the name against all the local variables 290 * the local ones. We check the name against all the local variables
291 * and substitute the short version in for 'name' if it matches one of 291 * and substitute the short version in for 'name' if it matches one of
292 * them. 292 * them.
293 */ 293 */
294 if (*name == '.' && isupper((unsigned char) name[1])) { 294 if (*name == '.' && isupper((unsigned char) name[1])) {
295 switch (name[1]) { 295 switch (name[1]) {
296 case 'A': 296 case 'A':
297 if (strcmp(name, ".ALLSRC") == 0) 297 if (strcmp(name, ".ALLSRC") == 0)
298 name = ALLSRC; 298 name = ALLSRC;
299 if (strcmp(name, ".ARCHIVE") == 0) 299 if (strcmp(name, ".ARCHIVE") == 0)
300 name = ARCHIVE; 300 name = ARCHIVE;
301 break; 301 break;
302 case 'I': 302 case 'I':
303 if (strcmp(name, ".IMPSRC") == 0) 303 if (strcmp(name, ".IMPSRC") == 0)
304 name = IMPSRC; 304 name = IMPSRC;
305 break; 305 break;
306 case 'M': 306 case 'M':
307 if (strcmp(name, ".MEMBER") == 0) 307 if (strcmp(name, ".MEMBER") == 0)
308 name = MEMBER; 308 name = MEMBER;
309 break; 309 break;
310 case 'O': 310 case 'O':
311 if (strcmp(name, ".OODATE") == 0) 311 if (strcmp(name, ".OODATE") == 0)
312 name = OODATE; 312 name = OODATE;
313 break; 313 break;
314 case 'P': 314 case 'P':
315 if (strcmp(name, ".PREFIX") == 0) 315 if (strcmp(name, ".PREFIX") == 0)
316 name = PREFIX; 316 name = PREFIX;
317 break; 317 break;
318 case 'T': 318 case 'T':
319 if (strcmp(name, ".TARGET") == 0) 319 if (strcmp(name, ".TARGET") == 0)
320 name = TARGET; 320 name = TARGET;
321 break; 321 break;
322 } 322 }
323 } 323 }
324 324
325#ifdef notyet 325#ifdef notyet
326 /* for compatibility with gmake */ 326 /* for compatibility with gmake */
327 if (name[0] == '^' && name[1] == '\0') 327 if (name[0] == '^' && name[1] == '\0')
328 name = ALLSRC; 328 name = ALLSRC;
329#endif 329#endif
330 330
331 /* 331 /*
332 * First look for the variable in the given context. If it's not there, 332 * First look for the variable in the given context. If it's not there,
333 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 333 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
334 * depending on the FIND_* flags in 'flags' 334 * depending on the FIND_* flags in 'flags'
335 */ 335 */
336 Hash_Entry *var = Hash_FindEntry(&ctxt->context, name); 336 Hash_Entry *var = Hash_FindEntry(&ctxt->context, name);
337 337
338 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) { 338 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
339 var = Hash_FindEntry(&VAR_CMD->context, name); 339 var = Hash_FindEntry(&VAR_CMD->context, name);
340 } 340 }
341 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && 341 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
342 ctxt != VAR_GLOBAL) 342 ctxt != VAR_GLOBAL)
343 { 343 {
344 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 344 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
345 if (var == NULL && ctxt != VAR_INTERNAL) { 345 if (var == NULL && ctxt != VAR_INTERNAL) {
346 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 346 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
347 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 347 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
348 } 348 }
349 } 349 }
350 if (var == NULL && (flags & FIND_ENV)) { 350 if (var == NULL && (flags & FIND_ENV)) {
351 char *env; 351 char *env;
352 352
353 if ((env = getenv(name)) != NULL) { 353 if ((env = getenv(name)) != NULL) {
354 Var *v = bmake_malloc(sizeof(Var)); 354 Var *v = bmake_malloc(sizeof(Var));
355 v->name = bmake_strdup(name); 355 v->name = bmake_strdup(name);
356 356
357 int len = (int)strlen(env); 357 int len = (int)strlen(env);
358 Buf_Init(&v->val, len + 1); 358 Buf_Init(&v->val, len + 1);
359 Buf_AddBytes(&v->val, len, env); 359 Buf_AddBytes(&v->val, len, env);
360 360
361 v->flags = VAR_FROM_ENV; 361 v->flags = VAR_FROM_ENV;
362 return v; 362 return v;
363 } else if (checkEnvFirst && (flags & FIND_GLOBAL) && 363 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
364 ctxt != VAR_GLOBAL) 364 ctxt != VAR_GLOBAL)
365 { 365 {
366 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 366 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
367 if (var == NULL && ctxt != VAR_INTERNAL) { 367 if (var == NULL && ctxt != VAR_INTERNAL) {
368 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 368 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
369 } 369 }
370 if (var == NULL) { 370 if (var == NULL) {
371 return NULL; 371 return NULL;
372 } else { 372 } else {
373 return (Var *)Hash_GetValue(var); 373 return (Var *)Hash_GetValue(var);
374 } 374 }
375 } else { 375 } else {
376 return NULL; 376 return NULL;
377 } 377 }
378 } else if (var == NULL) { 378 } else if (var == NULL) {
379 return NULL; 379 return NULL;
380 } else { 380 } else {
381 return (Var *)Hash_GetValue(var); 381 return (Var *)Hash_GetValue(var);
382 } 382 }
383} 383}
384 384
385/*- 385/*-
386 *----------------------------------------------------------------------- 386 *-----------------------------------------------------------------------
387 * VarFreeEnv -- 387 * VarFreeEnv --
388 * If the variable is an environment variable, free it 388 * If the variable is an environment variable, free it
389 * 389 *
390 * Input: 390 * Input:
391 * v the variable 391 * v the variable
392 * destroy true if the value buffer should be destroyed. 392 * destroy true if the value buffer should be destroyed.
393 * 393 *
394 * Results: 394 * Results:
395 * 1 if it is an environment variable 0 ow. 395 * 1 if it is an environment variable 0 ow.
396 * 396 *
397 * Side Effects: 397 * Side Effects:
398 * The variable is free'ed if it is an environent variable. 398 * The variable is free'ed if it is an environent variable.
399 *----------------------------------------------------------------------- 399 *-----------------------------------------------------------------------
400 */ 400 */
401static Boolean 401static Boolean
402VarFreeEnv(Var *v, Boolean destroy) 402VarFreeEnv(Var *v, Boolean destroy)
403{ 403{
404 if (!(v->flags & VAR_FROM_ENV)) 404 if (!(v->flags & VAR_FROM_ENV))
405 return FALSE; 405 return FALSE;
406 free(v->name); 406 free(v->name);
407 Buf_Destroy(&v->val, destroy); 407 Buf_Destroy(&v->val, destroy);
408 free(v); 408 free(v);
409 return TRUE; 409 return TRUE;
410} 410}
411 411
412/*- 412/*-
413 *----------------------------------------------------------------------- 413 *-----------------------------------------------------------------------
414 * VarAdd -- 414 * VarAdd --
415 * Add a new variable of name name and value val to the given context 415 * Add a new variable of name name and value val to the given context
416 * 416 *
417 * Input: 417 * Input:
418 * name name of variable to add 418 * name name of variable to add
419 * val value to set it to 419 * val value to set it to
420 * ctxt context in which to set it 420 * ctxt context in which to set it
421 * 421 *
422 * Side Effects: 422 * Side Effects:
423 * The new variable is placed at the front of the given context 423 * The new variable is placed at the front of the given context
424 * The name and val arguments are duplicated so they may 424 * The name and val arguments are duplicated so they may
425 * safely be freed. 425 * safely be freed.
426 *----------------------------------------------------------------------- 426 *-----------------------------------------------------------------------
427 */ 427 */
428static void 428static void
429VarAdd(const char *name, const char *val, GNode *ctxt) 429VarAdd(const char *name, const char *val, GNode *ctxt)
430{ 430{
431 Var *v = bmake_malloc(sizeof(Var)); 431 Var *v = bmake_malloc(sizeof(Var));
432 432
433 int len = val != NULL ? (int)strlen(val) : 0; 433 int len = val != NULL ? (int)strlen(val) : 0;
434 Buf_Init(&v->val, len + 1); 434 Buf_Init(&v->val, len + 1);
435 Buf_AddBytes(&v->val, len, val); 435 Buf_AddBytes(&v->val, len, val);
436 436
437 v->flags = 0; 437 v->flags = 0;
438 438
439 Hash_Entry *h = Hash_CreateEntry(&ctxt->context, name, NULL); 439 Hash_Entry *h = Hash_CreateEntry(&ctxt->context, name, NULL);
440 Hash_SetValue(h, v); 440 Hash_SetValue(h, v);
441 v->name = h->name; 441 v->name = h->name;
442 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) { 442 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) {
443 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 443 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
444 } 444 }
445} 445}
446 446
447/*- 447/*-
448 *----------------------------------------------------------------------- 448 *-----------------------------------------------------------------------
449 * Var_Delete -- 449 * Var_Delete --
450 * Remove a variable from a context. 450 * Remove a variable from a context.
451 * 451 *
452 * Side Effects: 452 * Side Effects:
453 * The Var structure is removed and freed. 453 * The Var structure is removed and freed.
454 * 454 *
455 *----------------------------------------------------------------------- 455 *-----------------------------------------------------------------------
456 */ 456 */
457void 457void
458Var_Delete(const char *name, GNode *ctxt) 458Var_Delete(const char *name, GNode *ctxt)
459{ 459{
460 Hash_Entry *ln; 460 Hash_Entry *ln;
461 char *cp; 461 char *cp;
462 462
463 if (strchr(name, '$') != NULL) { 463 if (strchr(name, '$') != NULL) {
464 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES); 464 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES);
465 } else { 465 } else {
466 cp = UNCONST(name); 466 cp = UNCONST(name);
467 } 467 }
468 ln = Hash_FindEntry(&ctxt->context, cp); 468 ln = Hash_FindEntry(&ctxt->context, cp);
469 if (DEBUG(VAR)) { 469 if (DEBUG(VAR)) {
470 fprintf(debug_file, "%s:delete %s%s\n", 470 fprintf(debug_file, "%s:delete %s%s\n",
471 ctxt->name, cp, ln ? "" : " (not found)"); 471 ctxt->name, cp, ln ? "" : " (not found)");
472 } 472 }
473 if (cp != name) 473 if (cp != name)
474 free(cp); 474 free(cp);
475 if (ln != NULL) { 475 if (ln != NULL) {
476 Var *v = (Var *)Hash_GetValue(ln); 476 Var *v = (Var *)Hash_GetValue(ln);
477 if (v->flags & VAR_EXPORTED) 477 if (v->flags & VAR_EXPORTED)
478 unsetenv(v->name); 478 unsetenv(v->name);
479 if (strcmp(MAKE_EXPORTED, v->name) == 0) 479 if (strcmp(MAKE_EXPORTED, v->name) == 0)
480 var_exportedVars = VAR_EXPORTED_NONE; 480 var_exportedVars = VAR_EXPORTED_NONE;
481 if (v->name != ln->name) 481 if (v->name != ln->name)
482 free(v->name); 482 free(v->name);
483 Hash_DeleteEntry(&ctxt->context, ln); 483 Hash_DeleteEntry(&ctxt->context, ln);
484 Buf_Destroy(&v->val, TRUE); 484 Buf_Destroy(&v->val, TRUE);
485 free(v); 485 free(v);
486 } 486 }
487} 487}
488 488
489 489
490/* 490/*
491 * Export a var. 491 * Export a var.
492 * We ignore make internal variables (those which start with '.') 492 * We ignore make internal variables (those which start with '.')
493 * Also we jump through some hoops to avoid calling setenv 493 * Also we jump through some hoops to avoid calling setenv
494 * more than necessary since it can leak. 494 * more than necessary since it can leak.
495 * We only manipulate flags of vars if 'parent' is set. 495 * We only manipulate flags of vars if 'parent' is set.
496 */ 496 */
497static int 497static int
498Var_Export1(const char *name, VarExportFlags flags) 498Var_Export1(const char *name, VarExportFlags flags)
499{ 499{
500 char tmp[BUFSIZ]; 500 char tmp[BUFSIZ];
501 Var *v; 501 Var *v;
502 char *val = NULL; 502 char *val = NULL;
503 int n; 503 int n;
504 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 504 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
505 505
506 if (*name == '.') 506 if (*name == '.')
507 return 0; /* skip internals */ 507 return 0; /* skip internals */
508 if (!name[1]) { 508 if (!name[1]) {
509 /* 509 /*
510 * A single char. 510 * A single char.
511 * If it is one of the vars that should only appear in 511 * If it is one of the vars that should only appear in
512 * local context, skip it, else we can get Var_Subst 512 * local context, skip it, else we can get Var_Subst
513 * into a loop. 513 * into a loop.
514 */ 514 */
515 switch (name[0]) { 515 switch (name[0]) {
516 case '@': 516 case '@':
517 case '%': 517 case '%':
518 case '*': 518 case '*':
519 case '!': 519 case '!':
520 return 0; 520 return 0;
521 } 521 }
522 } 522 }
523 v = VarFind(name, VAR_GLOBAL, 0); 523 v = VarFind(name, VAR_GLOBAL, 0);
524 if (v == NULL) 524 if (v == NULL)
525 return 0; 525 return 0;
526 if (!parent && 526 if (!parent &&
527 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { 527 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) {
528 return 0; /* nothing to do */ 528 return 0; /* nothing to do */
529 } 529 }
530 val = Buf_GetAll(&v->val, NULL); 530 val = Buf_GetAll(&v->val, NULL);
531 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { 531 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
532 if (parent) { 532 if (parent) {
533 /* 533 /*
534 * Flag this as something we need to re-export. 534 * Flag this as something we need to re-export.
535 * No point actually exporting it now though, 535 * No point actually exporting it now though,
536 * the child can do it at the last minute. 536 * the child can do it at the last minute.
537 */ 537 */
538 v->flags |= (VAR_EXPORTED | VAR_REEXPORT); 538 v->flags |= (VAR_EXPORTED | VAR_REEXPORT);
539 return 1; 539 return 1;
540 } 540 }
541 if (v->flags & VAR_IN_USE) { 541 if (v->flags & VAR_IN_USE) {
542 /* 542 /*
543 * We recursed while exporting in a child. 543 * We recursed while exporting in a child.
544 * This isn't going to end well, just skip it. 544 * This isn't going to end well, just skip it.
545 */ 545 */
546 return 0; 546 return 0;
547 } 547 }
548 n = snprintf(tmp, sizeof(tmp), "${%s}", name); 548 n = snprintf(tmp, sizeof(tmp), "${%s}", name);
549 if (n < (int)sizeof(tmp)) { 549 if (n < (int)sizeof(tmp)) {
550 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 550 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
551 setenv(name, val, 1); 551 setenv(name, val, 1);
552 free(val); 552 free(val);
553 } 553 }
554 } else { 554 } else {
555 if (parent) 555 if (parent)
556 v->flags &= ~VAR_REEXPORT; /* once will do */ 556 v->flags &= ~VAR_REEXPORT; /* once will do */
557 if (parent || !(v->flags & VAR_EXPORTED)) 557 if (parent || !(v->flags & VAR_EXPORTED))
558 setenv(name, val, 1); 558 setenv(name, val, 1);
559 } 559 }
560 /* 560 /*
561 * This is so Var_Set knows to call Var_Export again... 561 * This is so Var_Set knows to call Var_Export again...
562 */ 562 */
563 if (parent) { 563 if (parent) {
564 v->flags |= VAR_EXPORTED; 564 v->flags |= VAR_EXPORTED;
565 } 565 }
566 return 1; 566 return 1;
567} 567}
568 568
569static void 569static void
570Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED) 570Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
571{ 571{
572 Var *var = entry; 572 Var *var = entry;
573 Var_Export1(var->name, 0); 573 Var_Export1(var->name, 0);
574} 574}
575 575
576/* 576/*
577 * This gets called from our children. 577 * This gets called from our children.
578 */ 578 */
579void 579void
580Var_ExportVars(void) 580Var_ExportVars(void)
581{ 581{
582 char tmp[BUFSIZ]; 582 char tmp[BUFSIZ];
583 char *val; 583 char *val;
584 int n; 584 int n;
585 585
586 /* 586 /*
587 * Several make's support this sort of mechanism for tracking 587 * Several make's support this sort of mechanism for tracking
588 * recursion - but each uses a different name. 588 * recursion - but each uses a different name.
589 * We allow the makefiles to update MAKELEVEL and ensure 589 * We allow the makefiles to update MAKELEVEL and ensure
590 * children see a correctly incremented value. 590 * children see a correctly incremented value.
591 */ 591 */
592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 592 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
593 setenv(MAKE_LEVEL_ENV, tmp, 1); 593 setenv(MAKE_LEVEL_ENV, tmp, 1);
594 594
595 if (VAR_EXPORTED_NONE == var_exportedVars) 595 if (VAR_EXPORTED_NONE == var_exportedVars)
596 return; 596 return;
597 597
598 if (VAR_EXPORTED_ALL == var_exportedVars) { 598 if (VAR_EXPORTED_ALL == var_exportedVars) {
599 /* Ouch! This is crazy... */ 599 /* Ouch! This is crazy... */
600 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); 600 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
601 return; 601 return;
602 } 602 }
603 /* 603 /*
604 * We have a number of exported vars, 604 * We have a number of exported vars,
605 */ 605 */
606 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); 606 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
607 if (n < (int)sizeof(tmp)) { 607 if (n < (int)sizeof(tmp)) {
608 char **av; 608 char **av;
609 char *as; 609 char *as;
610 int ac; 610 int ac;
611 int i; 611 int i;
612 612
613 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 613 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
614 if (*val) { 614 if (*val) {
615 av = brk_string(val, &ac, FALSE, &as); 615 av = brk_string(val, &ac, FALSE, &as);
616 for (i = 0; i < ac; i++) 616 for (i = 0; i < ac; i++)
617 Var_Export1(av[i], 0); 617 Var_Export1(av[i], 0);
618 free(as); 618 free(as);
619 free(av); 619 free(av);
620 } 620 }
621 free(val); 621 free(val);
622 } 622 }
623} 623}
624 624
625/* 625/*
626 * This is called when .export is seen or 626 * This is called when .export is seen or
627 * .MAKE.EXPORTED is modified. 627 * .MAKE.EXPORTED is modified.
628 * It is also called when any exported var is modified. 628 * It is also called when any exported var is modified.
629 */ 629 */
630void 630void
631Var_Export(char *str, int isExport) 631Var_Export(char *str, int isExport)
632{ 632{
633 char **av; 633 char **av;
634 char *as; 634 char *as;
635 VarExportFlags flags; 635 VarExportFlags flags;
636 int ac; 636 int ac;
637 int i; 637 int i;
638 638
639 if (isExport && (!str || !str[0])) { 639 if (isExport && (!str || !str[0])) {
640 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 640 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
641 return; 641 return;
642 } 642 }
643 643
644 flags = 0; 644 flags = 0;
645 if (strncmp(str, "-env", 4) == 0) { 645 if (strncmp(str, "-env", 4) == 0) {
646 str += 4; 646 str += 4;
647 } else if (strncmp(str, "-literal", 8) == 0) { 647 } else if (strncmp(str, "-literal", 8) == 0) {
648 str += 8; 648 str += 8;
649 flags |= VAR_EXPORT_LITERAL; 649 flags |= VAR_EXPORT_LITERAL;
650 } else { 650 } else {
651 flags |= VAR_EXPORT_PARENT; 651 flags |= VAR_EXPORT_PARENT;
652 } 652 }
653 653
654 char *val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES); 654 char *val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES);
655 if (*val) { 655 if (*val) {
656 av = brk_string(val, &ac, FALSE, &as); 656 av = brk_string(val, &ac, FALSE, &as);
657 for (i = 0; i < ac; i++) { 657 for (i = 0; i < ac; i++) {
658 const char *name = av[i]; 658 const char *name = av[i];
659 if (!name[1]) { 659 if (!name[1]) {
660 /* 660 /*
661 * A single char. 661 * A single char.
662 * If it is one of the vars that should only appear in 662 * If it is one of the vars that should only appear in
663 * local context, skip it, else we can get Var_Subst 663 * local context, skip it, else we can get Var_Subst
664 * into a loop. 664 * into a loop.
665 */ 665 */
666 switch (name[0]) { 666 switch (name[0]) {
667 case '@': 667 case '@':
668 case '%': 668 case '%':
669 case '*': 669 case '*':
670 case '!': 670 case '!':
671 continue; 671 continue;
672 } 672 }
673 } 673 }
674 if (Var_Export1(name, flags)) { 674 if (Var_Export1(name, flags)) {
675 if (VAR_EXPORTED_ALL != var_exportedVars) 675 if (VAR_EXPORTED_ALL != var_exportedVars)
676 var_exportedVars = VAR_EXPORTED_YES; 676 var_exportedVars = VAR_EXPORTED_YES;
677 if (isExport && (flags & VAR_EXPORT_PARENT)) { 677 if (isExport && (flags & VAR_EXPORT_PARENT)) {
678 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 678 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
679 } 679 }
680 } 680 }
681 } 681 }
682 free(as); 682 free(as);
683 free(av); 683 free(av);
684 } 684 }
685 free(val); 685 free(val);
686} 686}
687 687
688 688
689extern char **environ; 689extern char **environ;
690 690
691/* 691/*
692 * This is called when .unexport[-env] is seen. 692 * This is called when .unexport[-env] is seen.
693 * 693 *
694 * str must have the form "unexport[-env] varname...". 694 * str must have the form "unexport[-env] varname...".
695 */ 695 */
696void 696void
697Var_UnExport(char *str) 697Var_UnExport(char *str)
698{ 698{
699 char tmp[BUFSIZ]; 699 char tmp[BUFSIZ];
700 char *vlist; 700 char *vlist;
701 char *cp; 701 char *cp;
702 Boolean unexport_env; 702 Boolean unexport_env;
703 int n; 703 int n;
704 704
705 vlist = NULL; 705 vlist = NULL;
706 706
707 str += strlen("unexport"); 707 str += strlen("unexport");
708 unexport_env = (strncmp(str, "-env", 4) == 0); 708 unexport_env = (strncmp(str, "-env", 4) == 0);
709 if (unexport_env) { 709 if (unexport_env) {
710 char **newenv; 710 char **newenv;
711 711
712 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 712 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
713 if (environ == savedEnv) { 713 if (environ == savedEnv) {
714 /* we have been here before! */ 714 /* we have been here before! */
715 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 715 newenv = bmake_realloc(environ, 2 * sizeof(char *));
716 } else { 716 } else {
717 if (savedEnv) { 717 if (savedEnv) {
718 free(savedEnv); 718 free(savedEnv);
719 savedEnv = NULL; 719 savedEnv = NULL;
720 } 720 }
721 newenv = bmake_malloc(2 * sizeof(char *)); 721 newenv = bmake_malloc(2 * sizeof(char *));
722 } 722 }
723 if (!newenv) 723 if (!newenv)
724 return; 724 return;
725 /* Note: we cannot safely free() the original environ. */ 725 /* Note: we cannot safely free() the original environ. */
726 environ = savedEnv = newenv; 726 environ = savedEnv = newenv;
727 newenv[0] = NULL; 727 newenv[0] = NULL;
728 newenv[1] = NULL; 728 newenv[1] = NULL;
729 if (cp && *cp) 729 if (cp && *cp)
730 setenv(MAKE_LEVEL_ENV, cp, 1); 730 setenv(MAKE_LEVEL_ENV, cp, 1);
731 } else { 731 } else {
732 for (; *str != '\n' && isspace((unsigned char) *str); str++) 732 for (; *str != '\n' && isspace((unsigned char) *str); str++)
733 continue; 733 continue;
734 if (str[0] && str[0] != '\n') { 734 if (str[0] && str[0] != '\n') {
735 vlist = str; 735 vlist = str;
736 } 736 }
737 } 737 }
738 738
739 if (!vlist) { 739 if (!vlist) {
740 /* Using .MAKE.EXPORTED */ 740 /* Using .MAKE.EXPORTED */
741 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, 741 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
742 VARE_WANTRES); 742 VARE_WANTRES);
743 } 743 }
744 if (vlist) { 744 if (vlist) {
745 Var *v; 745 Var *v;
746 char **av; 746 char **av;
747 char *as; 747 char *as;
748 int ac; 748 int ac;
749 int i; 749 int i;
750 750
751 av = brk_string(vlist, &ac, FALSE, &as); 751 av = brk_string(vlist, &ac, FALSE, &as);
752 for (i = 0; i < ac; i++) { 752 for (i = 0; i < ac; i++) {
753 v = VarFind(av[i], VAR_GLOBAL, 0); 753 v = VarFind(av[i], VAR_GLOBAL, 0);
754 if (!v) 754 if (!v)
755 continue; 755 continue;
756 if (!unexport_env && 756 if (!unexport_env &&
757 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) 757 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED)
758 unsetenv(v->name); 758 unsetenv(v->name);
759 v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT); 759 v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT);
760 /* 760 /*
761 * If we are unexporting a list, 761 * If we are unexporting a list,
762 * remove each one from .MAKE.EXPORTED. 762 * remove each one from .MAKE.EXPORTED.
763 * If we are removing them all, 763 * If we are removing them all,
764 * just delete .MAKE.EXPORTED below. 764 * just delete .MAKE.EXPORTED below.
765 */ 765 */
766 if (vlist == str) { 766 if (vlist == str) {
767 n = snprintf(tmp, sizeof(tmp), 767 n = snprintf(tmp, sizeof(tmp),
768 "${" MAKE_EXPORTED ":N%s}", v->name); 768 "${" MAKE_EXPORTED ":N%s}", v->name);
769 if (n < (int)sizeof(tmp)) { 769 if (n < (int)sizeof(tmp)) {
770 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 770 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
771 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 771 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
772 free(cp); 772 free(cp);
773 } 773 }
774 } 774 }
775 } 775 }
776 free(as); 776 free(as);
777 free(av); 777 free(av);
778 if (vlist != str) { 778 if (vlist != str) {
779 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 779 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
780 free(vlist); 780 free(vlist);
781 } 781 }
782 } 782 }
783} 783}
784 784
785static void 785static void
786Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 786Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
787 VarSet_Flags flags) 787 VarSet_Flags flags)
788{ 788{
789 Var *v; 789 Var *v;
790 char *expanded_name = NULL; 790 char *expanded_name = NULL;
791 791
792 /* 792 /*
793 * We only look for a variable in the given context since anything set 793 * We only look for a variable in the given context since anything set
794 * here will override anything in a lower context, so there's not much 794 * here will override anything in a lower context, so there's not much
795 * point in searching them all just to save a bit of memory... 795 * point in searching them all just to save a bit of memory...
796 */ 796 */
797 if (strchr(name, '$') != NULL) { 797 if (strchr(name, '$') != NULL) {
798 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 798 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
799 if (expanded_name[0] == '\0') { 799 if (expanded_name[0] == '\0') {
800 if (DEBUG(VAR)) { 800 if (DEBUG(VAR)) {
801 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " 801 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
802 "name expands to empty string - ignored\n", 802 "name expands to empty string - ignored\n",
803 name, val); 803 name, val);
804 } 804 }
805 free(expanded_name); 805 free(expanded_name);
806 return; 806 return;
807 } 807 }
808 name = expanded_name; 808 name = expanded_name;
809 } 809 }
810 if (ctxt == VAR_GLOBAL) { 810 if (ctxt == VAR_GLOBAL) {
811 v = VarFind(name, VAR_CMD, 0); 811 v = VarFind(name, VAR_CMD, 0);
812 if (v != NULL) { 812 if (v != NULL) {
813 if ((v->flags & VAR_FROM_CMD)) { 813 if ((v->flags & VAR_FROM_CMD)) {
814 if (DEBUG(VAR)) { 814 if (DEBUG(VAR)) {
815 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); 815 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
816 } 816 }
817 goto out; 817 goto out;
818 } 818 }
819 VarFreeEnv(v, TRUE); 819 VarFreeEnv(v, TRUE);
820 } 820 }
821 } 821 }
822 v = VarFind(name, ctxt, 0); 822 v = VarFind(name, ctxt, 0);
823 if (v == NULL) { 823 if (v == NULL) {
824 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 824 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
825 /* 825 /*
826 * This var would normally prevent the same name being added 826 * This var would normally prevent the same name being added
827 * to VAR_GLOBAL, so delete it from there if needed. 827 * to VAR_GLOBAL, so delete it from there if needed.
828 * Otherwise -V name may show the wrong value. 828 * Otherwise -V name may show the wrong value.
829 */ 829 */
830 Var_Delete(name, VAR_GLOBAL); 830 Var_Delete(name, VAR_GLOBAL);
831 } 831 }
832 VarAdd(name, val, ctxt); 832 VarAdd(name, val, ctxt);
833 } else { 833 } else {
834 Buf_Empty(&v->val); 834 Buf_Empty(&v->val);
835 if (val) 835 if (val)
836 Buf_AddStr(&v->val, val); 836 Buf_AddStr(&v->val, val);
837 837
838 if (DEBUG(VAR)) { 838 if (DEBUG(VAR)) {
839 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 839 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
840 } 840 }
841 if ((v->flags & VAR_EXPORTED)) { 841 if ((v->flags & VAR_EXPORTED)) {
842 Var_Export1(name, VAR_EXPORT_PARENT); 842 Var_Export1(name, VAR_EXPORT_PARENT);
843 } 843 }
844 } 844 }
845 /* 845 /*
846 * Any variables given on the command line are automatically exported 846 * Any variables given on the command line are automatically exported
847 * to the environment (as per POSIX standard) 847 * to the environment (as per POSIX standard)
848 */ 848 */
849 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 849 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
850 if (v == NULL) { 850 if (v == NULL) {
851 /* we just added it */ 851 /* we just added it */
852 v = VarFind(name, ctxt, 0); 852 v = VarFind(name, ctxt, 0);
853 } 853 }
854 if (v != NULL) 854 if (v != NULL)
855 v->flags |= VAR_FROM_CMD; 855 v->flags |= VAR_FROM_CMD;
856 /* 856 /*
857 * If requested, don't export these in the environment 857 * If requested, don't export these in the environment
858 * individually. We still put them in MAKEOVERRIDES so 858 * individually. We still put them in MAKEOVERRIDES so
859 * that the command-line settings continue to override 859 * that the command-line settings continue to override
860 * Makefile settings. 860 * Makefile settings.
861 */ 861 */
862 if (varNoExportEnv != TRUE) 862 if (varNoExportEnv != TRUE)
863 setenv(name, val ? val : "", 1); 863 setenv(name, val ? val : "", 1);
864 864
865 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 865 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
866 } 866 }
867 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0) 867 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0)
868 save_dollars = s2Boolean(val, save_dollars); 868 save_dollars = s2Boolean(val, save_dollars);
869 869
870out: 870out:
871 free(expanded_name); 871 free(expanded_name);
872 if (v != NULL) 872 if (v != NULL)
873 VarFreeEnv(v, TRUE); 873 VarFreeEnv(v, TRUE);
874} 874}
875 875
876/*- 876/*-
877 *----------------------------------------------------------------------- 877 *-----------------------------------------------------------------------
878 * Var_Set -- 878 * Var_Set --
879 * Set the variable name to the value val in the given context. 879 * Set the variable name to the value val in the given context.
880 * 880 *
881 * Input: 881 * Input:
882 * name name of variable to set 882 * name name of variable to set
883 * val value to give to the variable 883 * val value to give to the variable
884 * ctxt context in which to set it 884 * ctxt context in which to set it
885 * 885 *
886 * Side Effects: 886 * Side Effects:
887 * If the variable doesn't yet exist, a new record is created for it. 887 * If the variable doesn't yet exist, a new record is created for it.
888 * Else the old value is freed and the new one stuck in its place 888 * Else the old value is freed and the new one stuck in its place
889 * 889 *
890 * Notes: 890 * Notes:
891 * The variable is searched for only in its context before being 891 * The variable is searched for only in its context before being
892 * created in that context. I.e. if the context is VAR_GLOBAL, 892 * created in that context. I.e. if the context is VAR_GLOBAL,
893 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 893 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
894 * VAR_CMD->context is searched. This is done to avoid the literally 894 * VAR_CMD->context is searched. This is done to avoid the literally
895 * thousands of unnecessary strcmp's that used to be done to 895 * thousands of unnecessary strcmp's that used to be done to
896 * set, say, $(@) or $(<). 896 * set, say, $(@) or $(<).
897 * If the context is VAR_GLOBAL though, we check if the variable 897 * If the context is VAR_GLOBAL though, we check if the variable
898 * was set in VAR_CMD from the command line and skip it if so. 898 * was set in VAR_CMD from the command line and skip it if so.
899 *----------------------------------------------------------------------- 899 *-----------------------------------------------------------------------
900 */ 900 */
901void 901void
902Var_Set(const char *name, const char *val, GNode *ctxt) 902Var_Set(const char *name, const char *val, GNode *ctxt)
903{ 903{
904 Var_Set_with_flags(name, val, ctxt, 0); 904 Var_Set_with_flags(name, val, ctxt, 0);
905} 905}
906 906
907/*- 907/*-
908 *----------------------------------------------------------------------- 908 *-----------------------------------------------------------------------
909 * Var_Append -- 909 * Var_Append --
910 * The variable of the given name has the given value appended to it in 910 * The variable of the given name has the given value appended to it in
911 * the given context. 911 * the given context.
912 * 912 *
913 * Input: 913 * Input:
914 * name name of variable to modify 914 * name name of variable to modify
915 * val String to append to it 915 * val String to append to it
916 * ctxt Context in which this should occur 916 * ctxt Context in which this should occur
917 * 917 *
918 * Side Effects: 918 * Side Effects:
919 * If the variable doesn't exist, it is created. Else the strings 919 * If the variable doesn't exist, it is created. Else the strings
920 * are concatenated (with a space in between). 920 * are concatenated (with a space in between).
921 * 921 *
922 * Notes: 922 * Notes:
923 * Only if the variable is being sought in the global context is the 923 * Only if the variable is being sought in the global context is the
924 * environment searched. 924 * environment searched.
925 * XXX: Knows its calling circumstances in that if called with ctxt 925 * XXX: Knows its calling circumstances in that if called with ctxt
926 * an actual target, it will only search that context since only 926 * an actual target, it will only search that context since only
927 * a local variable could be being appended to. This is actually 927 * a local variable could be being appended to. This is actually
928 * a big win and must be tolerated. 928 * a big win and must be tolerated.
929 *----------------------------------------------------------------------- 929 *-----------------------------------------------------------------------
930 */ 930 */
931void 931void
932Var_Append(const char *name, const char *val, GNode *ctxt) 932Var_Append(const char *name, const char *val, GNode *ctxt)
933{ 933{
934 Var *v; 934 Var *v;
935 Hash_Entry *h; 935 Hash_Entry *h;
936 char *expanded_name = NULL; 936 char *expanded_name = NULL;
937 937
938 if (strchr(name, '$') != NULL) { 938 if (strchr(name, '$') != NULL) {
939 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 939 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
940 if (expanded_name[0] == '\0') { 940 if (expanded_name[0] == '\0') {
941 if (DEBUG(VAR)) { 941 if (DEBUG(VAR)) {
942 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " 942 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
943 "name expands to empty string - ignored\n", 943 "name expands to empty string - ignored\n",
944 name, val); 944 name, val);
945 } 945 }
946 free(expanded_name); 946 free(expanded_name);
947 return; 947 return;
948 } 948 }
949 name = expanded_name; 949 name = expanded_name;
950 } 950 }
951 951
952 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); 952 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0);
953 953
954 if (v == NULL) { 954 if (v == NULL) {
955 Var_Set(name, val, ctxt); 955 Var_Set(name, val, ctxt);
956 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { 956 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
957 Buf_AddByte(&v->val, ' '); 957 Buf_AddByte(&v->val, ' ');
958 Buf_AddStr(&v->val, val); 958 Buf_AddStr(&v->val, val);
959 959
960 if (DEBUG(VAR)) { 960 if (DEBUG(VAR)) {
961 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, 961 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
962 Buf_GetAll(&v->val, NULL)); 962 Buf_GetAll(&v->val, NULL));
963 } 963 }
964 964
965 if (v->flags & VAR_FROM_ENV) { 965 if (v->flags & VAR_FROM_ENV) {
966 /* 966 /*
967 * If the original variable came from the environment, we 967 * If the original variable came from the environment, we
968 * have to install it in the global context (we could place 968 * have to install it in the global context (we could place
969 * it in the environment, but then we should provide a way to 969 * it in the environment, but then we should provide a way to
970 * export other variables...) 970 * export other variables...)
971 */ 971 */
972 v->flags &= ~VAR_FROM_ENV; 972 v->flags &= ~VAR_FROM_ENV;
973 h = Hash_CreateEntry(&ctxt->context, name, NULL); 973 h = Hash_CreateEntry(&ctxt->context, name, NULL);
974 Hash_SetValue(h, v); 974 Hash_SetValue(h, v);
975 } 975 }
976 } 976 }
977 free(expanded_name); 977 free(expanded_name);
978} 978}
979 979
980/*- 980/*-
981 *----------------------------------------------------------------------- 981 *-----------------------------------------------------------------------
982 * Var_Exists -- 982 * Var_Exists --
983 * See if the given variable exists. 983 * See if the given variable exists.
984 * 984 *
985 * Input: 985 * Input:
986 * name Variable to find 986 * name Variable to find
987 * ctxt Context in which to start search 987 * ctxt Context in which to start search
988 * 988 *
989 * Results: 989 * Results:
990 * TRUE if it does, FALSE if it doesn't 990 * TRUE if it does, FALSE if it doesn't
991 * 991 *
992 * Side Effects: 992 * Side Effects:
993 * None. 993 * None.
994 * 994 *
995 *----------------------------------------------------------------------- 995 *-----------------------------------------------------------------------
996 */ 996 */
997Boolean 997Boolean
998Var_Exists(const char *name, GNode *ctxt) 998Var_Exists(const char *name, GNode *ctxt)
999{ 999{
1000 Var *v; 1000 Var *v;
1001 char *cp; 1001 char *cp;
1002 1002
1003 if ((cp = strchr(name, '$')) != NULL) 1003 if ((cp = strchr(name, '$')) != NULL)
1004 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 1004 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
1005 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); 1005 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV);
1006 free(cp); 1006 free(cp);
1007 if (v == NULL) 1007 if (v == NULL)
1008 return FALSE; 1008 return FALSE;
1009 1009
1010 (void)VarFreeEnv(v, TRUE); 1010 (void)VarFreeEnv(v, TRUE);
1011 return TRUE; 1011 return TRUE;
1012} 1012}
1013 1013
1014/*- 1014/*-
1015 *----------------------------------------------------------------------- 1015 *-----------------------------------------------------------------------
1016 * Var_Value -- 1016 * Var_Value --
1017 * Return the unexpanded value of the given variable in the given 1017 * Return the unexpanded value of the given variable in the given
1018 * context. 1018 * context.
1019 * 1019 *
1020 * Input: 1020 * Input:
1021 * name name to find 1021 * name name to find
1022 * ctxt context in which to search for it 1022 * ctxt context in which to search for it
1023 * 1023 *
1024 * Results: 1024 * Results:
1025 * The value if the variable exists, NULL if it doesn't. 1025 * The value if the variable exists, NULL if it doesn't.
1026 * If the returned value is not NULL, the caller must free *freeIt 1026 * If the returned value is not NULL, the caller must free *freeIt
1027 * as soon as the returned value is no longer needed. 1027 * as soon as the returned value is no longer needed.
1028 *----------------------------------------------------------------------- 1028 *-----------------------------------------------------------------------
1029 */ 1029 */
1030char * 1030char *
1031Var_Value(const char *name, GNode *ctxt, char **freeIt) 1031Var_Value(const char *name, GNode *ctxt, char **freeIt)
1032{ 1032{
1033 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1033 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1034 *freeIt = NULL; 1034 *freeIt = NULL;
1035 if (v == NULL) 1035 if (v == NULL)
1036 return NULL; 1036 return NULL;
1037 1037
1038 char *p = Buf_GetAll(&v->val, NULL); 1038 char *p = Buf_GetAll(&v->val, NULL);
1039 if (VarFreeEnv(v, FALSE)) 1039 if (VarFreeEnv(v, FALSE))
1040 *freeIt = p; 1040 *freeIt = p;
1041 return p; 1041 return p;
1042} 1042}
1043 1043
1044 1044
1045/* SepBuf is a string being built from "words", interleaved with separators. */ 1045/* SepBuf is a string being built from "words", interleaved with separators. */
1046typedef struct { 1046typedef struct {
1047 Buffer buf; 1047 Buffer buf;
1048 Boolean needSep; 1048 Boolean needSep;
1049 char sep; 1049 char sep;
1050} SepBuf; 1050} SepBuf;
1051 1051
1052static void 1052static void
1053SepBuf_Init(SepBuf *buf, char sep) 1053SepBuf_Init(SepBuf *buf, char sep)
1054{ 1054{
1055 Buf_Init(&buf->buf, 32 /* bytes */); 1055 Buf_Init(&buf->buf, 32 /* bytes */);
1056 buf->needSep = FALSE; 1056 buf->needSep = FALSE;
1057 buf->sep = sep; 1057 buf->sep = sep;
1058} 1058}
1059 1059
1060static void 1060static void
1061SepBuf_Sep(SepBuf *buf) 1061SepBuf_Sep(SepBuf *buf)
1062{ 1062{
1063 buf->needSep = TRUE; 1063 buf->needSep = TRUE;
1064} 1064}
1065 1065
1066static void 1066static void
1067SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1067SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1068{ 1068{
1069 if (mem_size == 0) 1069 if (mem_size == 0)
1070 return; 1070 return;
1071 if (buf->needSep && buf->sep != '\0') { 1071 if (buf->needSep && buf->sep != '\0') {
1072 Buf_AddByte(&buf->buf, buf->sep); 1072 Buf_AddByte(&buf->buf, buf->sep);
1073 buf->needSep = FALSE; 1073 buf->needSep = FALSE;
1074 } 1074 }
1075 Buf_AddBytes(&buf->buf, mem_size, mem); 1075 Buf_AddBytes(&buf->buf, mem_size, mem);
1076} 1076}
1077 1077
1078static void 1078static void
@@ -1514,1999 +1514,1998 @@ VarSelectWords(Byte sep, Boolean oneBigW @@ -1514,1999 +1514,1998 @@ VarSelectWords(Byte sep, Boolean oneBigW
1514 int last) 1514 int last)
1515{ 1515{
1516 SepBuf buf; 1516 SepBuf buf;
1517 char **av; /* word list */ 1517 char **av; /* word list */
1518 char *as; /* word list memory */ 1518 char *as; /* word list memory */
1519 int ac, i; 1519 int ac, i;
1520 int start, end, step; 1520 int start, end, step;
1521 1521
1522 SepBuf_Init(&buf, sep); 1522 SepBuf_Init(&buf, sep);
1523 1523
1524 if (oneBigWord) { 1524 if (oneBigWord) {
1525 /* fake what brk_string() would do if there were only one word */ 1525 /* fake what brk_string() would do if there were only one word */
1526 ac = 1; 1526 ac = 1;
1527 av = bmake_malloc((ac + 1) * sizeof(char *)); 1527 av = bmake_malloc((ac + 1) * sizeof(char *));
1528 as = bmake_strdup(str); 1528 as = bmake_strdup(str);
1529 av[0] = as; 1529 av[0] = as;
1530 av[1] = NULL; 1530 av[1] = NULL;
1531 } else { 1531 } else {
1532 av = brk_string(str, &ac, FALSE, &as); 1532 av = brk_string(str, &ac, FALSE, &as);
1533 } 1533 }
1534 1534
1535 /* 1535 /*
1536 * Now sanitize seldata. 1536 * Now sanitize seldata.
1537 * If seldata->start or seldata->end are negative, convert them to 1537 * If seldata->start or seldata->end are negative, convert them to
1538 * the positive equivalents (-1 gets converted to argc, -2 gets 1538 * the positive equivalents (-1 gets converted to argc, -2 gets
1539 * converted to (argc-1), etc.). 1539 * converted to (argc-1), etc.).
1540 */ 1540 */
1541 if (first < 0) 1541 if (first < 0)
1542 first += ac + 1; 1542 first += ac + 1;
1543 if (last < 0) 1543 if (last < 0)
1544 last += ac + 1; 1544 last += ac + 1;
1545 1545
1546 /* 1546 /*
1547 * We avoid scanning more of the list than we need to. 1547 * We avoid scanning more of the list than we need to.
1548 */ 1548 */
1549 if (first > last) { 1549 if (first > last) {
1550 start = MIN(ac, first) - 1; 1550 start = MIN(ac, first) - 1;
1551 end = MAX(0, last - 1); 1551 end = MAX(0, last - 1);
1552 step = -1; 1552 step = -1;
1553 } else { 1553 } else {
1554 start = MAX(0, first - 1); 1554 start = MAX(0, first - 1);
1555 end = MIN(ac, last); 1555 end = MIN(ac, last);
1556 step = 1; 1556 step = 1;
1557 } 1557 }
1558 1558
1559 for (i = start; (step < 0) == (i >= end); i += step) { 1559 for (i = start; (step < 0) == (i >= end); i += step) {
1560 SepBuf_AddStr(&buf, av[i]); 1560 SepBuf_AddStr(&buf, av[i]);
1561 SepBuf_Sep(&buf); 1561 SepBuf_Sep(&buf);
1562 } 1562 }
1563 1563
1564 free(as); 1564 free(as);
1565 free(av); 1565 free(av);
1566 1566
1567 return SepBuf_Destroy(&buf, FALSE); 1567 return SepBuf_Destroy(&buf, FALSE);
1568} 1568}
1569 1569
1570 1570
1571/* Callback for ModifyWords to implement the :tA modifier. 1571/* Callback for ModifyWords to implement the :tA modifier.
1572 * Replace each word with the result of realpath() if successful. */ 1572 * Replace each word with the result of realpath() if successful. */
1573static void 1573static void
1574ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1574ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1575{ 1575{
1576 struct stat st; 1576 struct stat st;
1577 char rbuf[MAXPATHLEN]; 1577 char rbuf[MAXPATHLEN];
1578 1578
1579 const char *rp = cached_realpath(word, rbuf); 1579 const char *rp = cached_realpath(word, rbuf);
1580 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1580 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1581 word = rp; 1581 word = rp;
1582 1582
1583 SepBuf_AddStr(buf, word); 1583 SepBuf_AddStr(buf, word);
1584} 1584}
1585 1585
1586/*- 1586/*-
1587 *----------------------------------------------------------------------- 1587 *-----------------------------------------------------------------------
1588 * Modify each of the words of the passed string using the given function. 1588 * Modify each of the words of the passed string using the given function.
1589 * 1589 *
1590 * Input: 1590 * Input:
1591 * str String whose words should be modified 1591 * str String whose words should be modified
1592 * modifyWord Function that modifies a single word 1592 * modifyWord Function that modifies a single word
1593 * data Custom data for modifyWord 1593 * data Custom data for modifyWord
1594 * 1594 *
1595 * Results: 1595 * Results:
1596 * A string of all the words modified appropriately. 1596 * A string of all the words modified appropriately.
1597 *----------------------------------------------------------------------- 1597 *-----------------------------------------------------------------------
1598 */ 1598 */
1599static char * 1599static char *
1600ModifyWords(GNode *ctx, Byte sep, Boolean oneBigWord, 1600ModifyWords(GNode *ctx, Byte sep, Boolean oneBigWord,
1601 const char *str, ModifyWordsCallback modifyWord, void *data) 1601 const char *str, ModifyWordsCallback modifyWord, void *data)
1602{ 1602{
1603 if (oneBigWord) { 1603 if (oneBigWord) {
1604 SepBuf result; 1604 SepBuf result;
1605 SepBuf_Init(&result, sep); 1605 SepBuf_Init(&result, sep);
1606 modifyWord(str, &result, data); 1606 modifyWord(str, &result, data);
1607 return SepBuf_Destroy(&result, FALSE); 1607 return SepBuf_Destroy(&result, FALSE);
1608 } 1608 }
1609 1609
1610 SepBuf result; 1610 SepBuf result;
1611 char **av; /* word list */ 1611 char **av; /* word list */
1612 char *as; /* word list memory */ 1612 char *as; /* word list memory */
1613 int ac, i; 1613 int ac, i;
1614 1614
1615 SepBuf_Init(&result, sep); 1615 SepBuf_Init(&result, sep);
1616 1616
1617 av = brk_string(str, &ac, FALSE, &as); 1617 av = brk_string(str, &ac, FALSE, &as);
1618 1618
1619 if (DEBUG(VAR)) { 1619 if (DEBUG(VAR)) {
1620 fprintf(debug_file, "ModifyWords: split \"%s\" into %d words\n", 1620 fprintf(debug_file, "ModifyWords: split \"%s\" into %d words\n",
1621 str, ac); 1621 str, ac);
1622 } 1622 }
1623 1623
1624 for (i = 0; i < ac; i++) { 1624 for (i = 0; i < ac; i++) {
1625 size_t orig_count = result.buf.count; 1625 size_t orig_count = result.buf.count;
1626 modifyWord(av[i], &result, data); 1626 modifyWord(av[i], &result, data);
1627 size_t count = result.buf.count; 1627 size_t count = result.buf.count;
1628 if (count != orig_count) 1628 if (count != orig_count)
1629 SepBuf_Sep(&result); 1629 SepBuf_Sep(&result);
1630 } 1630 }
1631 1631
1632 free(as); 1632 free(as);
1633 free(av); 1633 free(av);
1634 1634
1635 return SepBuf_Destroy(&result, FALSE); 1635 return SepBuf_Destroy(&result, FALSE);
1636} 1636}
1637 1637
1638 1638
1639static int 1639static int
1640VarWordCompare(const void *a, const void *b) 1640VarWordCompare(const void *a, const void *b)
1641{ 1641{
1642 int r = strcmp(*(const char * const *)a, *(const char * const *)b); 1642 int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1643 return r; 1643 return r;
1644} 1644}
1645 1645
1646static int 1646static int
1647VarWordCompareReverse(const void *a, const void *b) 1647VarWordCompareReverse(const void *a, const void *b)
1648{ 1648{
1649 int r = strcmp(*(const char * const *)b, *(const char * const *)a); 1649 int r = strcmp(*(const char * const *)b, *(const char * const *)a);
1650 return r; 1650 return r;
1651} 1651}
1652 1652
1653/*- 1653/*-
1654 *----------------------------------------------------------------------- 1654 *-----------------------------------------------------------------------
1655 * VarOrder -- 1655 * VarOrder --
1656 * Order the words in the string. 1656 * Order the words in the string.
1657 * 1657 *
1658 * Input: 1658 * Input:
1659 * str String whose words should be sorted. 1659 * str String whose words should be sorted.
1660 * otype How to order: s - sort, x - random. 1660 * otype How to order: s - sort, x - random.
1661 * 1661 *
1662 * Results: 1662 * Results:
1663 * A string containing the words ordered. 1663 * A string containing the words ordered.
1664 * 1664 *
1665 * Side Effects: 1665 * Side Effects:
1666 * None. 1666 * None.
1667 * 1667 *
1668 *----------------------------------------------------------------------- 1668 *-----------------------------------------------------------------------
1669 */ 1669 */
1670static char * 1670static char *
1671VarOrder(const char *str, const char otype) 1671VarOrder(const char *str, const char otype)
1672{ 1672{
1673 Buffer buf; /* Buffer for the new string */ 1673 Buffer buf; /* Buffer for the new string */
1674 char **av; /* word list */ 1674 char **av; /* word list */
1675 char *as; /* word list memory */ 1675 char *as; /* word list memory */
1676 int ac, i; 1676 int ac, i;
1677 1677
1678 Buf_Init(&buf, 0); 1678 Buf_Init(&buf, 0);
1679 1679
1680 av = brk_string(str, &ac, FALSE, &as); 1680 av = brk_string(str, &ac, FALSE, &as);
1681 1681
1682 if (ac > 0) { 1682 if (ac > 0) {
1683 switch (otype) { 1683 switch (otype) {
1684 case 'r': /* reverse sort alphabetically */ 1684 case 'r': /* reverse sort alphabetically */
1685 qsort(av, ac, sizeof(char *), VarWordCompareReverse); 1685 qsort(av, ac, sizeof(char *), VarWordCompareReverse);
1686 break; 1686 break;
1687 case 's': /* sort alphabetically */ 1687 case 's': /* sort alphabetically */
1688 qsort(av, ac, sizeof(char *), VarWordCompare); 1688 qsort(av, ac, sizeof(char *), VarWordCompare);
1689 break; 1689 break;
1690 case 'x': /* randomize */ 1690 case 'x': /* randomize */
1691 /* 1691 /*
1692 * We will use [ac..2] range for mod factors. This will produce 1692 * We will use [ac..2] range for mod factors. This will produce
1693 * random numbers in [(ac-1)..0] interval, and minimal 1693 * random numbers in [(ac-1)..0] interval, and minimal
1694 * reasonable value for mod factor is 2 (the mod 1 will produce 1694 * reasonable value for mod factor is 2 (the mod 1 will produce
1695 * 0 with probability 1). 1695 * 0 with probability 1).
1696 */ 1696 */
1697 for (i = ac - 1; i > 0; i--) { 1697 for (i = ac - 1; i > 0; i--) {
1698 int rndidx = random() % (i + 1); 1698 int rndidx = random() % (i + 1);
1699 char *t = av[i]; 1699 char *t = av[i];
1700 av[i] = av[rndidx]; 1700 av[i] = av[rndidx];
1701 av[rndidx] = t; 1701 av[rndidx] = t;
1702 } 1702 }
1703 } 1703 }
1704 } 1704 }
1705 1705
1706 for (i = 0; i < ac; i++) { 1706 for (i = 0; i < ac; i++) {
1707 if (i != 0) 1707 if (i != 0)
1708 Buf_AddByte(&buf, ' '); 1708 Buf_AddByte(&buf, ' ');
1709 Buf_AddStr(&buf, av[i]); 1709 Buf_AddStr(&buf, av[i]);
1710 } 1710 }
1711 1711
1712 free(as); 1712 free(as);
1713 free(av); 1713 free(av);
1714 1714
1715 return Buf_Destroy(&buf, FALSE); 1715 return Buf_Destroy(&buf, FALSE);
1716} 1716}
1717 1717
1718 1718
1719/* Remove adjacent duplicate words. */ 1719/* Remove adjacent duplicate words. */
1720static char * 1720static char *
1721VarUniq(const char *str) 1721VarUniq(const char *str)
1722{ 1722{
1723 Buffer buf; /* Buffer for new string */ 1723 Buffer buf; /* Buffer for new string */
1724 char **av; /* List of words to affect */ 1724 char **av; /* List of words to affect */
1725 char *as; /* Word list memory */ 1725 char *as; /* Word list memory */
1726 int ac, i, j; 1726 int ac, i, j;
1727 1727
1728 Buf_Init(&buf, 0); 1728 Buf_Init(&buf, 0);
1729 av = brk_string(str, &ac, FALSE, &as); 1729 av = brk_string(str, &ac, FALSE, &as);
1730 1730
1731 if (ac > 1) { 1731 if (ac > 1) {
1732 for (j = 0, i = 1; i < ac; i++) 1732 for (j = 0, i = 1; i < ac; i++)
1733 if (strcmp(av[i], av[j]) != 0 && (++j != i)) 1733 if (strcmp(av[i], av[j]) != 0 && (++j != i))
1734 av[j] = av[i]; 1734 av[j] = av[i];
1735 ac = j + 1; 1735 ac = j + 1;
1736 } 1736 }
1737 1737
1738 for (i = 0; i < ac; i++) { 1738 for (i = 0; i < ac; i++) {
1739 if (i != 0) 1739 if (i != 0)
1740 Buf_AddByte(&buf, ' '); 1740 Buf_AddByte(&buf, ' ');
1741 Buf_AddStr(&buf, av[i]); 1741 Buf_AddStr(&buf, av[i]);
1742 } 1742 }
1743 1743
1744 free(as); 1744 free(as);
1745 free(av); 1745 free(av);
1746 1746
1747 return Buf_Destroy(&buf, FALSE); 1747 return Buf_Destroy(&buf, FALSE);
1748} 1748}
1749 1749
1750/*- 1750/*-
1751 *----------------------------------------------------------------------- 1751 *-----------------------------------------------------------------------
1752 * VarRange -- 1752 * VarRange --
1753 * Return an integer sequence 1753 * Return an integer sequence
1754 * 1754 *
1755 * Input: 1755 * Input:
1756 * str String whose words provide default range 1756 * str String whose words provide default range
1757 * ac range length, if 0 use str words 1757 * ac range length, if 0 use str words
1758 * 1758 *
1759 * Side Effects: 1759 * Side Effects:
1760 * None. 1760 * None.
1761 * 1761 *
1762 *----------------------------------------------------------------------- 1762 *-----------------------------------------------------------------------
1763 */ 1763 */
1764static char * 1764static char *
1765VarRange(const char *str, int ac) 1765VarRange(const char *str, int ac)
1766{ 1766{
1767 Buffer buf; /* Buffer for new string */ 1767 Buffer buf; /* Buffer for new string */
1768 char **av; /* List of words to affect */ 1768 char **av; /* List of words to affect */
1769 char *as; /* Word list memory */ 1769 char *as; /* Word list memory */
1770 int i; 1770 int i;
1771 1771
1772 Buf_Init(&buf, 0); 1772 Buf_Init(&buf, 0);
1773 if (ac > 0) { 1773 if (ac > 0) {
1774 as = NULL; 1774 as = NULL;
1775 av = NULL; 1775 av = NULL;
1776 } else { 1776 } else {
1777 av = brk_string(str, &ac, FALSE, &as); 1777 av = brk_string(str, &ac, FALSE, &as);
1778 } 1778 }
1779 for (i = 0; i < ac; i++) { 1779 for (i = 0; i < ac; i++) {
1780 if (i != 0) 1780 if (i != 0)
1781 Buf_AddByte(&buf, ' '); 1781 Buf_AddByte(&buf, ' ');
1782 Buf_AddInt(&buf, 1 + i); 1782 Buf_AddInt(&buf, 1 + i);
1783 } 1783 }
1784 1784
1785 free(as); 1785 free(as);
1786 free(av); 1786 free(av);
1787 1787
1788 return Buf_Destroy(&buf, FALSE); 1788 return Buf_Destroy(&buf, FALSE);
1789} 1789}
1790 1790
1791 1791
1792/*- 1792/*-
1793 * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/ 1793 * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/
1794 * or the :@ modifier, until the next unescaped delimiter. The delimiter, as 1794 * or the :@ modifier, until the next unescaped delimiter. The delimiter, as
1795 * well as the backslash or the dollar, can be escaped with a backslash. 1795 * well as the backslash or the dollar, can be escaped with a backslash.
1796 * 1796 *
1797 * Return the parsed (and possibly expanded) string, or NULL if no delimiter 1797 * Return the parsed (and possibly expanded) string, or NULL if no delimiter
1798 * was found. 1798 * was found.
1799 * 1799 *
1800 * Nested variables in the text are expanded unless VARE_NOSUBST is set. 1800 * Nested variables in the text are expanded unless VARE_NOSUBST is set.
1801 * 1801 *
1802 * If out_length is specified, store the length of the returned string, just 1802 * If out_length is specified, store the length of the returned string, just
1803 * to save another strlen call. 1803 * to save another strlen call.
1804 * 1804 *
1805 * If out_pflags is specified and the last character of the pattern is a $, 1805 * If out_pflags is specified and the last character of the pattern is a $,
1806 * set the VARP_ANCHOR_END bit of mpflags (for the first part of the :S 1806 * set the VARP_ANCHOR_END bit of mpflags (for the first part of the :S
1807 * modifier). 1807 * modifier).
1808 * 1808 *
1809 * If subst is specified, handle escaped ampersands and replace unescaped 1809 * If subst is specified, handle escaped ampersands and replace unescaped
1810 * ampersands with the lhs of the pattern (for the second part of the :S 1810 * ampersands with the lhs of the pattern (for the second part of the :S
1811 * modifier). 1811 * modifier).
1812 */ 1812 */
1813static char * 1813static char *
1814ParseModifierPart(const char **tstr, int delim, VarEvalFlags eflags, 1814ParseModifierPart(const char **tstr, int delim, VarEvalFlags eflags,
1815 GNode *ctxt, size_t *out_length, 1815 GNode *ctxt, size_t *out_length,
1816 VarPatternFlags *out_pflags, ModifyWord_SubstArgs *subst) 1816 VarPatternFlags *out_pflags, ModifyWord_SubstArgs *subst)
1817{ 1817{
1818 const char *cp; 1818 const char *cp;
1819 char *rstr; 1819 char *rstr;
1820 Buffer buf; 1820 Buffer buf;
1821 VarEvalFlags errnum = eflags & VARE_UNDEFERR; 1821 VarEvalFlags errnum = eflags & VARE_UNDEFERR;
1822 1822
1823 Buf_Init(&buf, 0); 1823 Buf_Init(&buf, 0);
1824 1824
1825 /* 1825 /*
1826 * Skim through until the matching delimiter is found; 1826 * Skim through until the matching delimiter is found;
1827 * pick up variable substitutions on the way. Also allow 1827 * pick up variable substitutions on the way. Also allow
1828 * backslashes to quote the delimiter, $, and \, but don't 1828 * backslashes to quote the delimiter, $, and \, but don't
1829 * touch other backslashes. 1829 * touch other backslashes.
1830 */ 1830 */
1831 for (cp = *tstr; *cp != '\0' && *cp != delim; cp++) { 1831 for (cp = *tstr; *cp != '\0' && *cp != delim; cp++) {
1832 Boolean is_escaped = cp[0] == '\\' && ( 1832 Boolean is_escaped = cp[0] == '\\' && (
1833 cp[1] == delim || cp[1] == '\\' || cp[1] == '$' || 1833 cp[1] == delim || cp[1] == '\\' || cp[1] == '$' ||
1834 (cp[1] == '&' && subst != NULL)); 1834 (cp[1] == '&' && subst != NULL));
1835 if (is_escaped) { 1835 if (is_escaped) {
1836 Buf_AddByte(&buf, cp[1]); 1836 Buf_AddByte(&buf, cp[1]);
1837 cp++; 1837 cp++;
1838 } else if (*cp == '$') { 1838 } else if (*cp == '$') {
1839 if (cp[1] == delim) { /* Unescaped $ at end of pattern */ 1839 if (cp[1] == delim) { /* Unescaped $ at end of pattern */
1840 if (out_pflags != NULL) 1840 if (out_pflags != NULL)
1841 *out_pflags |= VARP_ANCHOR_END; 1841 *out_pflags |= VARP_ANCHOR_END;
1842 else 1842 else
1843 Buf_AddByte(&buf, *cp); 1843 Buf_AddByte(&buf, *cp);
1844 } else { 1844 } else {
1845 if (eflags & VARE_WANTRES) { 1845 if (eflags & VARE_WANTRES) {
1846 const char *cp2; 1846 const char *cp2;
1847 int len; 1847 int len;
1848 void *freeIt; 1848 void *freeIt;
1849 1849
1850 /* 1850 /*
1851 * If unescaped dollar sign not before the 1851 * If unescaped dollar sign not before the
1852 * delimiter, assume it's a variable 1852 * delimiter, assume it's a variable
1853 * substitution and recurse. 1853 * substitution and recurse.
1854 */ 1854 */
1855 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES), 1855 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES),
1856 &len, &freeIt); 1856 &len, &freeIt);
1857 Buf_AddStr(&buf, cp2); 1857 Buf_AddStr(&buf, cp2);
1858 free(freeIt); 1858 free(freeIt);
1859 cp += len - 1; 1859 cp += len - 1;
1860 } else { 1860 } else {
1861 const char *cp2 = &cp[1]; 1861 const char *cp2 = &cp[1];
1862 1862
1863 if (*cp2 == PROPEN || *cp2 == BROPEN) { 1863 if (*cp2 == PROPEN || *cp2 == BROPEN) {
1864 /* 1864 /*
1865 * Find the end of this variable reference 1865 * Find the end of this variable reference
1866 * and suck it in without further ado. 1866 * and suck it in without further ado.
1867 * It will be interpreted later. 1867 * It will be interpreted later.
1868 */ 1868 */
1869 int have = *cp2; 1869 int have = *cp2;
1870 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; 1870 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
1871 int depth = 1; 1871 int depth = 1;
1872 1872
1873 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { 1873 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
1874 if (cp2[-1] != '\\') { 1874 if (cp2[-1] != '\\') {
1875 if (*cp2 == have) 1875 if (*cp2 == have)
1876 ++depth; 1876 ++depth;
1877 if (*cp2 == want) 1877 if (*cp2 == want)
1878 --depth; 1878 --depth;
1879 } 1879 }
1880 } 1880 }
1881 Buf_AddBytesBetween(&buf, cp, cp2); 1881 Buf_AddBytesBetween(&buf, cp, cp2);
1882 cp = --cp2; 1882 cp = --cp2;
1883 } else 1883 } else
1884 Buf_AddByte(&buf, *cp); 1884 Buf_AddByte(&buf, *cp);
1885 } 1885 }
1886 } 1886 }
1887 } else if (subst != NULL && *cp == '&') 1887 } else if (subst != NULL && *cp == '&')
1888 Buf_AddBytes(&buf, subst->lhsLen, subst->lhs); 1888 Buf_AddBytes(&buf, subst->lhsLen, subst->lhs);
1889 else 1889 else
1890 Buf_AddByte(&buf, *cp); 1890 Buf_AddByte(&buf, *cp);
1891 } 1891 }
1892 1892
1893 if (*cp != delim) { 1893 if (*cp != delim) {
1894 *tstr = cp; 1894 *tstr = cp;
1895 return NULL; 1895 return NULL;
1896 } 1896 }
1897 1897
1898 *tstr = ++cp; 1898 *tstr = ++cp;
1899 if (out_length != NULL) 1899 if (out_length != NULL)
1900 *out_length = Buf_Size(&buf); 1900 *out_length = Buf_Size(&buf);
1901 rstr = Buf_Destroy(&buf, FALSE); 1901 rstr = Buf_Destroy(&buf, FALSE);
1902 if (DEBUG(VAR)) 1902 if (DEBUG(VAR))
1903 fprintf(debug_file, "Modifier part: \"%s\"\n", rstr); 1903 fprintf(debug_file, "Modifier part: \"%s\"\n", rstr);
1904 return rstr; 1904 return rstr;
1905} 1905}
1906 1906
1907/*- 1907/*-
1908 *----------------------------------------------------------------------- 1908 *-----------------------------------------------------------------------
1909 * VarQuote -- 1909 * VarQuote --
1910 * Quote shell meta-characters and space characters in the string 1910 * Quote shell meta-characters and space characters in the string
1911 * if quoteDollar is set, also quote and double any '$' characters. 1911 * if quoteDollar is set, also quote and double any '$' characters.
1912 * 1912 *
1913 * Results: 1913 * Results:
1914 * The quoted string 1914 * The quoted string
1915 * 1915 *
1916 * Side Effects: 1916 * Side Effects:
1917 * None. 1917 * None.
1918 * 1918 *
1919 *----------------------------------------------------------------------- 1919 *-----------------------------------------------------------------------
1920 */ 1920 */
1921static char * 1921static char *
1922VarQuote(char *str, Boolean quoteDollar) 1922VarQuote(char *str, Boolean quoteDollar)
1923{ 1923{
1924 Buffer buf; 1924 Buffer buf;
1925 Buf_Init(&buf, 0); 1925 Buf_Init(&buf, 0);
1926 1926
1927 for (; *str != '\0'; str++) { 1927 for (; *str != '\0'; str++) {
1928 if (*str == '\n') { 1928 if (*str == '\n') {
1929 const char *newline = Shell_GetNewline(); 1929 const char *newline = Shell_GetNewline();
1930 if (newline == NULL) 1930 if (newline == NULL)
1931 newline = "\\\n"; 1931 newline = "\\\n";
1932 Buf_AddStr(&buf, newline); 1932 Buf_AddStr(&buf, newline);
1933 continue; 1933 continue;
1934 } 1934 }
1935 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) 1935 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
1936 Buf_AddByte(&buf, '\\'); 1936 Buf_AddByte(&buf, '\\');
1937 Buf_AddByte(&buf, *str); 1937 Buf_AddByte(&buf, *str);
1938 if (quoteDollar && *str == '$') 1938 if (quoteDollar && *str == '$')
1939 Buf_AddStr(&buf, "\\$"); 1939 Buf_AddStr(&buf, "\\$");
1940 } 1940 }
1941 1941
1942 str = Buf_Destroy(&buf, FALSE); 1942 str = Buf_Destroy(&buf, FALSE);
1943 if (DEBUG(VAR)) 1943 if (DEBUG(VAR))
1944 fprintf(debug_file, "QuoteMeta: [%s]\n", str); 1944 fprintf(debug_file, "QuoteMeta: [%s]\n", str);
1945 return str; 1945 return str;
1946} 1946}
1947 1947
1948/*- 1948/*-
1949 *----------------------------------------------------------------------- 1949 *-----------------------------------------------------------------------
1950 * VarHash -- 1950 * VarHash --
1951 * Hash the string using the MurmurHash3 algorithm. 1951 * Hash the string using the MurmurHash3 algorithm.
1952 * Output is computed using 32bit Little Endian arithmetic. 1952 * Output is computed using 32bit Little Endian arithmetic.
1953 * 1953 *
1954 * Input: 1954 * Input:
1955 * str String to modify 1955 * str String to modify
1956 * 1956 *
1957 * Results: 1957 * Results:
1958 * Hash value of str, encoded as 8 hex digits. 1958 * Hash value of str, encoded as 8 hex digits.
1959 * 1959 *
1960 * Side Effects: 1960 * Side Effects:
1961 * None. 1961 * None.
1962 * 1962 *
1963 *----------------------------------------------------------------------- 1963 *-----------------------------------------------------------------------
1964 */ 1964 */
1965static char * 1965static char *
1966VarHash(const char *str) 1966VarHash(const char *str)
1967{ 1967{
1968 static const char hexdigits[16] = "0123456789abcdef"; 1968 static const char hexdigits[16] = "0123456789abcdef";
1969 Buffer buf; 1969 Buffer buf;
1970 size_t len, len2; 1970 size_t len, len2;
1971 const unsigned char *ustr = (const unsigned char *)str; 1971 const unsigned char *ustr = (const unsigned char *)str;
1972 uint32_t h, k, c1, c2; 1972 uint32_t h, k, c1, c2;
1973 1973
1974 h = 0x971e137bU; 1974 h = 0x971e137bU;
1975 c1 = 0x95543787U; 1975 c1 = 0x95543787U;
1976 c2 = 0x2ad7eb25U; 1976 c2 = 0x2ad7eb25U;
1977 len2 = strlen(str); 1977 len2 = strlen(str);
1978 1978
1979 for (len = len2; len; ) { 1979 for (len = len2; len; ) {
1980 k = 0; 1980 k = 0;
1981 switch (len) { 1981 switch (len) {
1982 default: 1982 default:
1983 k = ((uint32_t)ustr[3] << 24) | 1983 k = ((uint32_t)ustr[3] << 24) |
1984 ((uint32_t)ustr[2] << 16) | 1984 ((uint32_t)ustr[2] << 16) |
1985 ((uint32_t)ustr[1] << 8) | 1985 ((uint32_t)ustr[1] << 8) |
1986 (uint32_t)ustr[0]; 1986 (uint32_t)ustr[0];
1987 len -= 4; 1987 len -= 4;
1988 ustr += 4; 1988 ustr += 4;
1989 break; 1989 break;
1990 case 3: 1990 case 3:
1991 k |= (uint32_t)ustr[2] << 16; 1991 k |= (uint32_t)ustr[2] << 16;
1992 /* FALLTHROUGH */ 1992 /* FALLTHROUGH */
1993 case 2: 1993 case 2:
1994 k |= (uint32_t)ustr[1] << 8; 1994 k |= (uint32_t)ustr[1] << 8;
1995 /* FALLTHROUGH */ 1995 /* FALLTHROUGH */
1996 case 1: 1996 case 1:
1997 k |= (uint32_t)ustr[0]; 1997 k |= (uint32_t)ustr[0];
1998 len = 0; 1998 len = 0;
1999 } 1999 }
2000 c1 = c1 * 5 + 0x7b7d159cU; 2000 c1 = c1 * 5 + 0x7b7d159cU;
2001 c2 = c2 * 5 + 0x6bce6396U; 2001 c2 = c2 * 5 + 0x6bce6396U;
2002 k *= c1; 2002 k *= c1;
2003 k = (k << 11) ^ (k >> 21); 2003 k = (k << 11) ^ (k >> 21);
2004 k *= c2; 2004 k *= c2;
2005 h = (h << 13) ^ (h >> 19); 2005 h = (h << 13) ^ (h >> 19);
2006 h = h * 5 + 0x52dce729U; 2006 h = h * 5 + 0x52dce729U;
2007 h ^= k; 2007 h ^= k;
2008 } 2008 }
2009 h ^= len2; 2009 h ^= len2;
2010 h *= 0x85ebca6b; 2010 h *= 0x85ebca6b;
2011 h ^= h >> 13; 2011 h ^= h >> 13;
2012 h *= 0xc2b2ae35; 2012 h *= 0xc2b2ae35;
2013 h ^= h >> 16; 2013 h ^= h >> 16;
2014 2014
2015 Buf_Init(&buf, 0); 2015 Buf_Init(&buf, 0);
2016 for (len = 0; len < 8; ++len) { 2016 for (len = 0; len < 8; ++len) {
2017 Buf_AddByte(&buf, hexdigits[h & 15]); 2017 Buf_AddByte(&buf, hexdigits[h & 15]);
2018 h >>= 4; 2018 h >>= 4;
2019 } 2019 }
2020 2020
2021 return Buf_Destroy(&buf, FALSE); 2021 return Buf_Destroy(&buf, FALSE);
2022} 2022}
2023 2023
2024static char * 2024static char *
2025VarStrftime(const char *fmt, int zulu, time_t utc) 2025VarStrftime(const char *fmt, int zulu, time_t utc)
2026{ 2026{
2027 char buf[BUFSIZ]; 2027 char buf[BUFSIZ];
2028 2028
2029 if (!utc) 2029 if (!utc)
2030 time(&utc); 2030 time(&utc);
2031 if (!*fmt) 2031 if (!*fmt)
2032 fmt = "%c"; 2032 fmt = "%c";
2033 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); 2033 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2034 2034
2035 buf[sizeof(buf) - 1] = '\0'; 2035 buf[sizeof(buf) - 1] = '\0';
2036 return bmake_strdup(buf); 2036 return bmake_strdup(buf);
2037} 2037}
2038 2038
2039typedef struct { 2039typedef struct {
2040 /* const parameters */ 2040 /* const parameters */
2041 int startc; /* '\0' or '{' or '(' */ 2041 int startc; /* '\0' or '{' or '(' */
2042 int endc; 2042 int endc;
2043 Var *v; 2043 Var *v;
2044 GNode *ctxt; 2044 GNode *ctxt;
2045 VarEvalFlags eflags; 2045 VarEvalFlags eflags;
2046 int *lengthPtr; 2046 int *lengthPtr;
2047 void **freePtr; 2047 void **freePtr;
2048 2048
2049 /* read-write */ 2049 /* read-write */
2050 char *nstr; 2050 char *nstr;
2051 const char *start; 2051 const char *start;
2052 const char *cp; /* The position where parsing continues 2052 const char *cp; /* The position where parsing continues
2053 * after the current modifier. */ 2053 * after the current modifier. */
2054 char termc; /* Character which terminated scan */ 2054 char termc; /* Character which terminated scan */
2055 char missing_delim; /* For error reporting */ 2055 char missing_delim; /* For error reporting */
2056 2056
2057 Byte sep; /* Word separator in expansions */ 2057 Byte sep; /* Word separator in expansions */
2058 Boolean oneBigWord; /* TRUE if we will treat the variable as a 2058 Boolean oneBigWord; /* TRUE if we will treat the variable as a
2059 * single big word, even if it contains 2059 * single big word, even if it contains
2060 * embedded spaces (as opposed to the 2060 * embedded spaces (as opposed to the
2061 * usual behaviour of treating it as 2061 * usual behaviour of treating it as
2062 * several space-separated words). */ 2062 * several space-separated words). */
2063 2063
2064 /* result */ 2064 /* result */
2065 char *newStr; /* New value to return */ 2065 char *newStr; /* New value to return */
2066} ApplyModifiersState; 2066} ApplyModifiersState;
2067 2067
2068/* we now have some modifiers with long names */ 2068/* we now have some modifiers with long names */
2069static Boolean 2069static Boolean
2070ModMatch(const char *mod, const char *modname, char endc) 2070ModMatch(const char *mod, const char *modname, char endc)
2071{ 2071{
2072 size_t n = strlen(modname); 2072 size_t n = strlen(modname);
2073 return strncmp(mod, modname, n) == 0 && 2073 return strncmp(mod, modname, n) == 0 &&
2074 (mod[n] == endc || mod[n] == ':'); 2074 (mod[n] == endc || mod[n] == ':');
2075} 2075}
2076 2076
2077static inline Boolean 2077static inline Boolean
2078ModMatchEq(const char *mod, const char *modname, char endc) 2078ModMatchEq(const char *mod, const char *modname, char endc)
2079{ 2079{
2080 size_t n = strlen(modname); 2080 size_t n = strlen(modname);
2081 return strncmp(mod, modname, n) == 0 && 2081 return strncmp(mod, modname, n) == 0 &&
2082 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2082 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2083} 2083}
2084 2084
2085/* :@var@...${var}...@ */ 2085/* :@var@...${var}...@ */
2086static Boolean 2086static Boolean
2087ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { 2087ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) {
2088 ModifyWord_LoopArgs args; 2088 ModifyWord_LoopArgs args;
2089 2089
2090 args.ctx = st->ctxt; 2090 args.ctx = st->ctxt;
2091 st->cp = mod + 1; 2091 st->cp = mod + 1;
2092 char delim = '@'; 2092 char delim = '@';
2093 args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, 2093 args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES,
2094 st->ctxt, NULL, NULL, NULL); 2094 st->ctxt, NULL, NULL, NULL);
2095 if (args.tvar == NULL) { 2095 if (args.tvar == NULL) {
2096 st->missing_delim = delim; 2096 st->missing_delim = delim;
2097 return FALSE; 2097 return FALSE;
2098 } 2098 }
2099 2099
2100 args.str = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, 2100 args.str = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES,
2101 st->ctxt, NULL, NULL, NULL); 2101 st->ctxt, NULL, NULL, NULL);
2102 if (args.str == NULL) { 2102 if (args.str == NULL) {
2103 st->missing_delim = delim; 2103 st->missing_delim = delim;
2104 return FALSE; 2104 return FALSE;
2105 } 2105 }
2106 2106
2107 st->termc = *st->cp; 2107 st->termc = *st->cp;
2108 2108
2109 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2109 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2110 int prev_sep = st->sep; 2110 int prev_sep = st->sep;
2111 st->sep = ' '; /* XXX: this is inconsistent */ 2111 st->sep = ' '; /* XXX: this is inconsistent */
2112 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2112 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2113 ModifyWord_Loop, &args); 2113 ModifyWord_Loop, &args);
2114 st->sep = prev_sep; 2114 st->sep = prev_sep;
2115 Var_Delete(args.tvar, st->ctxt); 2115 Var_Delete(args.tvar, st->ctxt);
2116 free(args.tvar); 2116 free(args.tvar);
2117 free(args.str); 2117 free(args.str);
2118 return TRUE; 2118 return TRUE;
2119} 2119}
2120 2120
2121/* :Ddefined or :Uundefined */ 2121/* :Ddefined or :Uundefined */
2122static void 2122static void
2123ApplyModifier_Defined(const char *mod, ApplyModifiersState *st) 2123ApplyModifier_Defined(const char *mod, ApplyModifiersState *st)
2124{ 2124{
2125 Buffer buf; /* Buffer for patterns */ 2125 Buffer buf; /* Buffer for patterns */
2126 VarEvalFlags neflags; 2126 VarEvalFlags neflags;
2127 2127
2128 if (st->eflags & VARE_WANTRES) { 2128 if (st->eflags & VARE_WANTRES) {
2129 Boolean wantres; 2129 Boolean wantres;
2130 if (*mod == 'U') 2130 if (*mod == 'U')
2131 wantres = ((st->v->flags & VAR_JUNK) != 0); 2131 wantres = ((st->v->flags & VAR_JUNK) != 0);
2132 else 2132 else
2133 wantres = ((st->v->flags & VAR_JUNK) == 0); 2133 wantres = ((st->v->flags & VAR_JUNK) == 0);
2134 neflags = st->eflags & ~VARE_WANTRES; 2134 neflags = st->eflags & ~VARE_WANTRES;
2135 if (wantres) 2135 if (wantres)
2136 neflags |= VARE_WANTRES; 2136 neflags |= VARE_WANTRES;
2137 } else 2137 } else
2138 neflags = st->eflags; 2138 neflags = st->eflags;
2139 2139
2140 /* 2140 /*
2141 * Pass through mod looking for 1) escaped delimiters, 2141 * Pass through mod looking for 1) escaped delimiters,
2142 * '$'s and backslashes (place the escaped character in 2142 * '$'s and backslashes (place the escaped character in
2143 * uninterpreted) and 2) unescaped $'s that aren't before 2143 * uninterpreted) and 2) unescaped $'s that aren't before
2144 * the delimiter (expand the variable substitution). 2144 * the delimiter (expand the variable substitution).
2145 * The result is left in the Buffer buf. 2145 * The result is left in the Buffer buf.
2146 */ 2146 */
2147 Buf_Init(&buf, 0); 2147 Buf_Init(&buf, 0);
2148 const char *p = mod + 1; 2148 const char *p = mod + 1;
2149 while (*p != st->endc && *p != ':' && *p != '\0') { 2149 while (*p != st->endc && *p != ':' && *p != '\0') {
2150 if (*p == '\\' && 2150 if (*p == '\\' &&
2151 (p[1] == ':' || p[1] == '$' || p[1] == st->endc || p[1] == '\\')) { 2151 (p[1] == ':' || p[1] == '$' || p[1] == st->endc || p[1] == '\\')) {
2152 Buf_AddByte(&buf, p[1]); 2152 Buf_AddByte(&buf, p[1]);
2153 p += 2; 2153 p += 2;
2154 } else if (*p == '$') { 2154 } else if (*p == '$') {
2155 /* 2155 /*
2156 * If unescaped dollar sign, assume it's a 2156 * If unescaped dollar sign, assume it's a
2157 * variable substitution and recurse. 2157 * variable substitution and recurse.
2158 */ 2158 */
2159 const char *cp2; 2159 const char *cp2;
2160 int len; 2160 int len;
2161 void *freeIt; 2161 void *freeIt;
2162 2162
2163 cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt); 2163 cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt);
2164 Buf_AddStr(&buf, cp2); 2164 Buf_AddStr(&buf, cp2);
2165 free(freeIt); 2165 free(freeIt);
2166 p += len; 2166 p += len;
2167 } else { 2167 } else {
2168 Buf_AddByte(&buf, *p); 2168 Buf_AddByte(&buf, *p);
2169 p++; 2169 p++;
2170 } 2170 }
2171 } 2171 }
2172 2172
2173 st->cp = p; 2173 st->cp = p;
2174 st->termc = *st->cp; 2174 st->termc = *st->cp;
2175 2175
2176 if (st->v->flags & VAR_JUNK) 2176 if (st->v->flags & VAR_JUNK)
2177 st->v->flags |= VAR_KEEP; 2177 st->v->flags |= VAR_KEEP;
2178 if (neflags & VARE_WANTRES) { 2178 if (neflags & VARE_WANTRES) {
2179 st->newStr = Buf_Destroy(&buf, FALSE); 2179 st->newStr = Buf_Destroy(&buf, FALSE);
2180 } else { 2180 } else {
2181 st->newStr = st->nstr; 2181 st->newStr = st->nstr;
2182 Buf_Destroy(&buf, TRUE); 2182 Buf_Destroy(&buf, TRUE);
2183 } 2183 }
2184} 2184}
2185 2185
2186/* :gmtime */ 2186/* :gmtime */
2187static Boolean 2187static Boolean
2188ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) 2188ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st)
2189{ 2189{
2190 if (!ModMatchEq(mod, "gmtime", st->endc)) { 2190 if (!ModMatchEq(mod, "gmtime", st->endc)) {
2191 st->cp = mod + 1; 2191 st->cp = mod + 1;
2192 return FALSE; 2192 return FALSE;
2193 } 2193 }
2194 2194
2195 time_t utc; 2195 time_t utc;
2196 if (mod[6] == '=') { 2196 if (mod[6] == '=') {
2197 char *ep; 2197 char *ep;
2198 utc = strtoul(mod + 7, &ep, 10); 2198 utc = strtoul(mod + 7, &ep, 10);
2199 st->cp = ep; 2199 st->cp = ep;
2200 } else { 2200 } else {
2201 utc = 0; 2201 utc = 0;
2202 st->cp = mod + 6; 2202 st->cp = mod + 6;
2203 } 2203 }
2204 st->newStr = VarStrftime(st->nstr, 1, utc); 2204 st->newStr = VarStrftime(st->nstr, 1, utc);
2205 st->termc = *st->cp; 2205 st->termc = *st->cp;
2206 return TRUE; 2206 return TRUE;
2207} 2207}
2208 2208
2209/* :localtime */ 2209/* :localtime */
2210static Boolean 2210static Boolean
2211ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) 2211ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st)
2212{ 2212{
2213 if (!ModMatchEq(mod, "localtime", st->endc)) { 2213 if (!ModMatchEq(mod, "localtime", st->endc)) {
2214 st->cp = mod + 1; 2214 st->cp = mod + 1;
2215 return FALSE; 2215 return FALSE;
2216 } 2216 }
2217 2217
2218 time_t utc; 2218 time_t utc;
2219 if (mod[9] == '=') { 2219 if (mod[9] == '=') {
2220 char *ep; 2220 char *ep;
2221 utc = strtoul(mod + 10, &ep, 10); 2221 utc = strtoul(mod + 10, &ep, 10);
2222 st->cp = ep; 2222 st->cp = ep;
2223 } else { 2223 } else {
2224 utc = 0; 2224 utc = 0;
2225 st->cp = mod + 9; 2225 st->cp = mod + 9;
2226 } 2226 }
2227 st->newStr = VarStrftime(st->nstr, 0, utc); 2227 st->newStr = VarStrftime(st->nstr, 0, utc);
2228 st->termc = *st->cp; 2228 st->termc = *st->cp;
2229 return TRUE; 2229 return TRUE;
2230} 2230}
2231 2231
2232/* :hash */ 2232/* :hash */
2233static Boolean 2233static Boolean
2234ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) 2234ApplyModifier_Hash(const char *mod, ApplyModifiersState *st)
2235{ 2235{
2236 if (!ModMatch(mod, "hash", st->endc)) { 2236 if (!ModMatch(mod, "hash", st->endc)) {
2237 st->cp = mod + 1; 2237 st->cp = mod + 1;
2238 return FALSE; 2238 return FALSE;
2239 } 2239 }
2240 2240
2241 st->newStr = VarHash(st->nstr); 2241 st->newStr = VarHash(st->nstr);
2242 st->cp = mod + 4; 2242 st->cp = mod + 4;
2243 st->termc = *st->cp; 2243 st->termc = *st->cp;
2244 return TRUE; 2244 return TRUE;
2245} 2245}
2246 2246
2247/* :P */ 2247/* :P */
2248static void 2248static void
2249ApplyModifier_Path(const char *mod, ApplyModifiersState *st) 2249ApplyModifier_Path(const char *mod, ApplyModifiersState *st)
2250{ 2250{
2251 if (st->v->flags & VAR_JUNK) 2251 if (st->v->flags & VAR_JUNK)
2252 st->v->flags |= VAR_KEEP; 2252 st->v->flags |= VAR_KEEP;
2253 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); 2253 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2254 if (gn == NULL || gn->type & OP_NOPATH) { 2254 if (gn == NULL || gn->type & OP_NOPATH) {
2255 st->newStr = NULL; 2255 st->newStr = NULL;
2256 } else if (gn->path) { 2256 } else if (gn->path) {
2257 st->newStr = bmake_strdup(gn->path); 2257 st->newStr = bmake_strdup(gn->path);
2258 } else { 2258 } else {
2259 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); 2259 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2260 } 2260 }
2261 if (!st->newStr) 2261 if (!st->newStr)
2262 st->newStr = bmake_strdup(st->v->name); 2262 st->newStr = bmake_strdup(st->v->name);
2263 st->cp = mod + 1; 2263 st->cp = mod + 1;
2264 st->termc = *st->cp; 2264 st->termc = *st->cp;
2265} 2265}
2266 2266
2267/* :!cmd! */ 2267/* :!cmd! */
2268static Boolean 2268static Boolean
2269ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) 2269ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st)
2270{ 2270{
2271 st->cp = mod + 1; 2271 st->cp = mod + 1;
2272 char delim = '!'; 2272 char delim = '!';
2273 char *cmd = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2273 char *cmd = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2274 NULL, NULL, NULL); 2274 NULL, NULL, NULL);
2275 if (cmd == NULL) { 2275 if (cmd == NULL) {
2276 st->missing_delim = delim; 2276 st->missing_delim = delim;
2277 return FALSE; 2277 return FALSE;
2278 } 2278 }
2279 2279
2280 const char *emsg = NULL; 2280 const char *emsg = NULL;
2281 if (st->eflags & VARE_WANTRES) 2281 if (st->eflags & VARE_WANTRES)
2282 st->newStr = Cmd_Exec(cmd, &emsg); 2282 st->newStr = Cmd_Exec(cmd, &emsg);
2283 else 2283 else
2284 st->newStr = varNoError; 2284 st->newStr = varNoError;
2285 free(cmd); 2285 free(cmd);
2286 2286
2287 if (emsg) 2287 if (emsg)
2288 Error(emsg, st->nstr); 2288 Error(emsg, st->nstr);
2289 2289
2290 st->termc = *st->cp; 2290 st->termc = *st->cp;
2291 if (st->v->flags & VAR_JUNK) 2291 if (st->v->flags & VAR_JUNK)
2292 st->v->flags |= VAR_KEEP; 2292 st->v->flags |= VAR_KEEP;
2293 return TRUE; 2293 return TRUE;
2294} 2294}
2295 2295
2296/* :range */ 2296/* :range */
2297static Boolean 2297static Boolean
2298ApplyModifier_Range(const char *mod, ApplyModifiersState *st) 2298ApplyModifier_Range(const char *mod, ApplyModifiersState *st)
2299{ 2299{
2300 if (!ModMatchEq(mod, "range", st->endc)) { 2300 if (!ModMatchEq(mod, "range", st->endc)) {
2301 st->cp = mod + 1; 2301 st->cp = mod + 1;
2302 return FALSE; 2302 return FALSE;
2303 } 2303 }
2304 2304
2305 int n; 2305 int n;
2306 if (mod[5] == '=') { 2306 if (mod[5] == '=') {
2307 char *ep; 2307 char *ep;
2308 n = strtoul(mod + 6, &ep, 10); 2308 n = strtoul(mod + 6, &ep, 10);
2309 st->cp = ep; 2309 st->cp = ep;
2310 } else { 2310 } else {
2311 n = 0; 2311 n = 0;
2312 st->cp = mod + 5; 2312 st->cp = mod + 5;
2313 } 2313 }
2314 st->newStr = VarRange(st->nstr, n); 2314 st->newStr = VarRange(st->nstr, n);
2315 st->termc = *st->cp; 2315 st->termc = *st->cp;
2316 return TRUE; 2316 return TRUE;
2317} 2317}
2318 2318
2319/* :Mpattern or :Npattern */ 2319/* :Mpattern or :Npattern */
2320static void 2320static void
2321ApplyModifier_Match(const char *mod, ApplyModifiersState *st) 2321ApplyModifier_Match(const char *mod, ApplyModifiersState *st)
2322{ 2322{
2323 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2323 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2324 Boolean needSubst = FALSE; 2324 Boolean needSubst = FALSE;
2325 /* 2325 /*
2326 * In the loop below, ignore ':' unless we are at (or back to) the 2326 * In the loop below, ignore ':' unless we are at (or back to) the
2327 * original brace level. 2327 * original brace level.
2328 * XXX This will likely not work right if $() and ${} are intermixed. 2328 * XXX This will likely not work right if $() and ${} are intermixed.
2329 */ 2329 */
2330 int nest = 1; 2330 int nest = 1;
2331 for (st->cp = mod + 1; 2331 for (st->cp = mod + 1;
2332 *st->cp != '\0' && !(*st->cp == ':' && nest == 1); 2332 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2333 st->cp++) { 2333 st->cp++) {
2334 if (*st->cp == '\\' && 2334 if (*st->cp == '\\' &&
2335 (st->cp[1] == ':' || st->cp[1] == st->endc || 2335 (st->cp[1] == ':' || st->cp[1] == st->endc ||
2336 st->cp[1] == st->startc)) { 2336 st->cp[1] == st->startc)) {
2337 if (!needSubst) 2337 if (!needSubst)
2338 copy = TRUE; 2338 copy = TRUE;
2339 st->cp++; 2339 st->cp++;
2340 continue; 2340 continue;
2341 } 2341 }
2342 if (*st->cp == '$') 2342 if (*st->cp == '$')
2343 needSubst = TRUE; 2343 needSubst = TRUE;
2344 if (*st->cp == '(' || *st->cp == '{') 2344 if (*st->cp == '(' || *st->cp == '{')
2345 ++nest; 2345 ++nest;
2346 if (*st->cp == ')' || *st->cp == '}') { 2346 if (*st->cp == ')' || *st->cp == '}') {
2347 --nest; 2347 --nest;
2348 if (nest == 0) 2348 if (nest == 0)
2349 break; 2349 break;
2350 } 2350 }
2351 } 2351 }
2352 st->termc = *st->cp; 2352 st->termc = *st->cp;
2353 const char *endpat = st->cp; 2353 const char *endpat = st->cp;
2354 2354
2355 char *pattern = NULL; 2355 char *pattern = NULL;
2356 if (copy) { 2356 if (copy) {
2357 /* 2357 /*
2358 * Need to compress the \:'s out of the pattern, so 2358 * Need to compress the \:'s out of the pattern, so
2359 * allocate enough room to hold the uncompressed 2359 * allocate enough room to hold the uncompressed
2360 * pattern (note that st->cp started at mod+1, so 2360 * pattern (note that st->cp started at mod+1, so
2361 * st->cp - mod takes the null byte into account) and 2361 * st->cp - mod takes the null byte into account) and
2362 * compress the pattern into the space. 2362 * compress the pattern into the space.
2363 */ 2363 */
2364 pattern = bmake_malloc(st->cp - mod); 2364 pattern = bmake_malloc(st->cp - mod);
2365 char *cp2; 2365 char *cp2;
2366 for (cp2 = pattern, st->cp = mod + 1; 2366 for (cp2 = pattern, st->cp = mod + 1;
2367 st->cp < endpat; 2367 st->cp < endpat;
2368 st->cp++, cp2++) { 2368 st->cp++, cp2++) {
2369 if ((*st->cp == '\\') && (st->cp+1 < endpat) && 2369 if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2370 (st->cp[1] == ':' || st->cp[1] == st->endc)) 2370 (st->cp[1] == ':' || st->cp[1] == st->endc))
2371 st->cp++; 2371 st->cp++;
2372 *cp2 = *st->cp; 2372 *cp2 = *st->cp;
2373 } 2373 }
2374 *cp2 = '\0'; 2374 *cp2 = '\0';
2375 endpat = cp2; 2375 endpat = cp2;
2376 } else { 2376 } else {
2377 /* 2377 /*
2378 * Either Var_Subst or ModifyWords will need a 2378 * Either Var_Subst or ModifyWords will need a
2379 * nul-terminated string soon, so construct one now. 2379 * nul-terminated string soon, so construct one now.
2380 */ 2380 */
2381 pattern = bmake_strndup(mod + 1, endpat - (mod + 1)); 2381 pattern = bmake_strndup(mod + 1, endpat - (mod + 1));
2382 } 2382 }
2383 if (needSubst) { 2383 if (needSubst) {
2384 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2384 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2385 char *old_pattern = pattern; 2385 char *old_pattern = pattern;
2386 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags); 2386 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags);
2387 free(old_pattern); 2387 free(old_pattern);
2388 } 2388 }
2389 if (DEBUG(VAR)) 2389 if (DEBUG(VAR))
2390 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", 2390 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2391 st->v->name, st->nstr, pattern); 2391 st->v->name, st->nstr, pattern);
2392 ModifyWordsCallback callback = mod[0] == 'M' 2392 ModifyWordsCallback callback = mod[0] == 'M'
2393 ? ModifyWord_Match : ModifyWord_NoMatch; 2393 ? ModifyWord_Match : ModifyWord_NoMatch;
2394 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2394 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2395 callback, pattern); 2395 callback, pattern);
2396 free(pattern); 2396 free(pattern);
2397} 2397}
2398 2398
2399/* :S,from,to, */ 2399/* :S,from,to, */
2400static Boolean 2400static Boolean
2401ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) 2401ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st)
2402{ 2402{
2403 ModifyWord_SubstArgs args; 2403 ModifyWord_SubstArgs args;
2404 Boolean oneBigWord = st->oneBigWord; 2404 Boolean oneBigWord = st->oneBigWord;
2405 char delim = mod[1]; 2405 char delim = mod[1];
2406 2406
2407 st->cp = mod + 2; 2407 st->cp = mod + 2;
2408 2408
2409 /* 2409 /*
2410 * If pattern begins with '^', it is anchored to the 2410 * If pattern begins with '^', it is anchored to the
2411 * start of the word -- skip over it and flag pattern. 2411 * start of the word -- skip over it and flag pattern.
2412 */ 2412 */
2413 args.pflags = 0; 2413 args.pflags = 0;
2414 if (*st->cp == '^') { 2414 if (*st->cp == '^') {
2415 args.pflags |= VARP_ANCHOR_START; 2415 args.pflags |= VARP_ANCHOR_START;
2416 st->cp++; 2416 st->cp++;
2417 } 2417 }
2418 2418
2419 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2419 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2420 &args.lhsLen, &args.pflags, NULL); 2420 &args.lhsLen, &args.pflags, NULL);
2421 if (lhs == NULL) { 2421 if (lhs == NULL) {
2422 st->missing_delim = delim; 2422 st->missing_delim = delim;
2423 return FALSE; 2423 return FALSE;
2424 } 2424 }
2425 args.lhs = lhs; 2425 args.lhs = lhs;
2426 2426
2427 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2427 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2428 &args.rhsLen, NULL, &args); 2428 &args.rhsLen, NULL, &args);
2429 if (rhs == NULL) { 2429 if (rhs == NULL) {
2430 st->missing_delim = delim; 2430 st->missing_delim = delim;
2431 return FALSE; 2431 return FALSE;
2432 } 2432 }
2433 args.rhs = rhs; 2433 args.rhs = rhs;
2434 2434
2435 /* 2435 /*
2436 * Check for global substitution. If 'g' after the final 2436 * Check for global substitution. If 'g' after the final
2437 * delimiter, substitution is global and is marked that 2437 * delimiter, substitution is global and is marked that
2438 * way. 2438 * way.
2439 */ 2439 */
2440 for (;; st->cp++) { 2440 for (;; st->cp++) {
2441 switch (*st->cp) { 2441 switch (*st->cp) {
2442 case 'g': 2442 case 'g':
2443 args.pflags |= VARP_SUB_GLOBAL; 2443 args.pflags |= VARP_SUB_GLOBAL;
2444 continue; 2444 continue;
2445 case '1': 2445 case '1':
2446 args.pflags |= VARP_SUB_ONE; 2446 args.pflags |= VARP_SUB_ONE;
2447 continue; 2447 continue;
2448 case 'W': 2448 case 'W':
2449 oneBigWord = TRUE; 2449 oneBigWord = TRUE;
2450 continue; 2450 continue;
2451 } 2451 }
2452 break; 2452 break;
2453 } 2453 }
2454 2454
2455 st->termc = *st->cp; 2455 st->termc = *st->cp;
2456 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2456 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2457 ModifyWord_Subst, &args); 2457 ModifyWord_Subst, &args);
2458 2458
2459 free(lhs); 2459 free(lhs);
2460 free(rhs); 2460 free(rhs);
2461 return TRUE; 2461 return TRUE;
2462} 2462}
2463 2463
2464#ifndef NO_REGEX 2464#ifndef NO_REGEX
2465 2465
2466/* :C,from,to, */ 2466/* :C,from,to, */
2467static Boolean 2467static Boolean
2468ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) 2468ApplyModifier_Regex(const char *mod, ApplyModifiersState *st)
2469{ 2469{
2470 ModifyWord_SubstRegexArgs args; 2470 ModifyWord_SubstRegexArgs args;
2471 2471
2472 args.pflags = 0; 2472 args.pflags = 0;
2473 Boolean oneBigWord = st->oneBigWord; 2473 Boolean oneBigWord = st->oneBigWord;
2474 char delim = mod[1]; 2474 char delim = mod[1];
2475 2475
2476 st->cp = mod + 2; 2476 st->cp = mod + 2;
2477 2477
2478 char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2478 char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2479 NULL, NULL, NULL); 2479 NULL, NULL, NULL);
2480 if (re == NULL) { 2480 if (re == NULL) {
2481 st->missing_delim = delim; 2481 st->missing_delim = delim;
2482 return FALSE; 2482 return FALSE;
2483 } 2483 }
2484 2484
2485 args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2485 args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2486 NULL, NULL, NULL); 2486 NULL, NULL, NULL);
2487 if (args.replace == NULL) { 2487 if (args.replace == NULL) {
2488 free(re); 2488 free(re);
2489 st->missing_delim = delim; 2489 st->missing_delim = delim;
2490 return FALSE; 2490 return FALSE;
2491 } 2491 }
2492 2492
2493 for (;; st->cp++) { 2493 for (;; st->cp++) {
2494 switch (*st->cp) { 2494 switch (*st->cp) {
2495 case 'g': 2495 case 'g':
2496 args.pflags |= VARP_SUB_GLOBAL; 2496 args.pflags |= VARP_SUB_GLOBAL;
2497 continue; 2497 continue;
2498 case '1': 2498 case '1':
2499 args.pflags |= VARP_SUB_ONE; 2499 args.pflags |= VARP_SUB_ONE;
2500 continue; 2500 continue;
2501 case 'W': 2501 case 'W':
2502 oneBigWord = TRUE; 2502 oneBigWord = TRUE;
2503 continue; 2503 continue;
2504 } 2504 }
2505 break; 2505 break;
2506 } 2506 }
2507 2507
2508 st->termc = *st->cp; 2508 st->termc = *st->cp;
2509 2509
2510 int error = regcomp(&args.re, re, REG_EXTENDED); 2510 int error = regcomp(&args.re, re, REG_EXTENDED);
2511 free(re); 2511 free(re);
2512 if (error) { 2512 if (error) {
2513 *st->lengthPtr = st->cp - st->start + 1; 
2514 VarREError(error, &args.re, "RE substitution error"); 2513 VarREError(error, &args.re, "RE substitution error");
2515 free(args.replace); 2514 free(args.replace);
2516 return FALSE; 2515 return FALSE;
2517 } 2516 }
2518 2517
2519 args.nsub = args.re.re_nsub + 1; 2518 args.nsub = args.re.re_nsub + 1;
2520 if (args.nsub < 1) 2519 if (args.nsub < 1)
2521 args.nsub = 1; 2520 args.nsub = 1;
2522 if (args.nsub > 10) 2521 if (args.nsub > 10)
2523 args.nsub = 10; 2522 args.nsub = 10;
2524 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2523 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2525 ModifyWord_SubstRegex, &args); 2524 ModifyWord_SubstRegex, &args);
2526 regfree(&args.re); 2525 regfree(&args.re);
2527 free(args.replace); 2526 free(args.replace);
2528 return TRUE; 2527 return TRUE;
2529} 2528}
2530#endif 2529#endif
2531 2530
2532static void 2531static void
2533ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2532ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2534{ 2533{
2535 SepBuf_AddStr(buf, word); 2534 SepBuf_AddStr(buf, word);
2536} 2535}
2537 2536
2538/* :ts<separator> */ 2537/* :ts<separator> */
2539static Boolean 2538static Boolean
2540ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) 2539ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st)
2541{ 2540{
2542 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2541 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2543 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ 2542 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */
2544 st->sep = sep[0]; 2543 st->sep = sep[0];
2545 st->cp = sep + 1; 2544 st->cp = sep + 1;
2546 } else if (sep[0] == st->endc || sep[0] == ':') { 2545 } else if (sep[0] == st->endc || sep[0] == ':') {
2547 /* ":ts<endc>" or ":ts:" */ 2546 /* ":ts<endc>" or ":ts:" */
2548 st->sep = '\0'; /* no separator */ 2547 st->sep = '\0'; /* no separator */
2549 st->cp = sep; 2548 st->cp = sep;
2550 } else if (sep[0] == '\\') { 2549 } else if (sep[0] == '\\') {
2551 const char *xp = sep + 1; 2550 const char *xp = sep + 1;
2552 int base = 8; /* assume octal */ 2551 int base = 8; /* assume octal */
2553 2552
2554 switch (sep[1]) { 2553 switch (sep[1]) {
2555 case 'n': 2554 case 'n':
2556 st->sep = '\n'; 2555 st->sep = '\n';
2557 st->cp = sep + 2; 2556 st->cp = sep + 2;
2558 break; 2557 break;
2559 case 't': 2558 case 't':
2560 st->sep = '\t'; 2559 st->sep = '\t';
2561 st->cp = sep + 2; 2560 st->cp = sep + 2;
2562 break; 2561 break;
2563 case 'x': 2562 case 'x':
2564 base = 16; 2563 base = 16;
2565 xp++; 2564 xp++;
2566 goto get_numeric; 2565 goto get_numeric;
2567 case '0': 2566 case '0':
2568 base = 0; 2567 base = 0;
2569 goto get_numeric; 2568 goto get_numeric;
2570 default: 2569 default:
2571 if (!isdigit((unsigned char)sep[1])) 2570 if (!isdigit((unsigned char)sep[1]))
2572 return FALSE; /* ":ts<backslash><unrecognised>". */ 2571 return FALSE; /* ":ts<backslash><unrecognised>". */
2573 2572
2574 char *end; 2573 char *end;
2575 get_numeric: 2574 get_numeric:
2576 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); 2575 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base);
2577 if (*end != ':' && *end != st->endc) 2576 if (*end != ':' && *end != st->endc)
2578 return FALSE; 2577 return FALSE;
2579 st->cp = end; 2578 st->cp = end;
2580 break; 2579 break;
2581 } 2580 }
2582 } else { 2581 } else {
2583 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ 2582 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */
2584 } 2583 }
2585 2584
2586 st->termc = *st->cp; 2585 st->termc = *st->cp;
2587 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2586 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2588 ModifyWord_Copy, NULL); 2587 ModifyWord_Copy, NULL);
2589 return TRUE; 2588 return TRUE;
2590} 2589}
2591 2590
2592/* :tA, :tu, :tl, :ts<separator>, etc. */ 2591/* :tA, :tu, :tl, :ts<separator>, etc. */
2593static Boolean 2592static Boolean
2594ApplyModifier_To(const char *mod, ApplyModifiersState *st) 2593ApplyModifier_To(const char *mod, ApplyModifiersState *st)
2595{ 2594{
2596 st->cp = mod + 1; /* make sure it is set */ 2595 st->cp = mod + 1; /* make sure it is set */
2597 if (mod[1] == st->endc || mod[1] == ':') 2596 if (mod[1] == st->endc || mod[1] == ':')
2598 return FALSE; /* Found ":t<endc>" or ":t:". */ 2597 return FALSE; /* Found ":t<endc>" or ":t:". */
2599 2598
2600 if (mod[1] == 's') 2599 if (mod[1] == 's')
2601 return ApplyModifier_ToSep(mod + 2, st); 2600 return ApplyModifier_ToSep(mod + 2, st);
2602 2601
2603 if (mod[2] != st->endc && mod[2] != ':') 2602 if (mod[2] != st->endc && mod[2] != ':')
2604 return FALSE; /* Found ":t<unrecognised><unrecognised>". */ 2603 return FALSE; /* Found ":t<unrecognised><unrecognised>". */
2605 2604
2606 /* Check for two-character options: ":tu", ":tl" */ 2605 /* Check for two-character options: ":tu", ":tl" */
2607 if (mod[1] == 'A') { /* absolute path */ 2606 if (mod[1] == 'A') { /* absolute path */
2608 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2607 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2609 ModifyWord_Realpath, NULL); 2608 ModifyWord_Realpath, NULL);
2610 st->cp = mod + 2; 2609 st->cp = mod + 2;
2611 st->termc = *st->cp; 2610 st->termc = *st->cp;
2612 } else if (mod[1] == 'u') { 2611 } else if (mod[1] == 'u') {
2613 char *dp = bmake_strdup(st->nstr); 2612 char *dp = bmake_strdup(st->nstr);
2614 for (st->newStr = dp; *dp; dp++) 2613 for (st->newStr = dp; *dp; dp++)
2615 *dp = toupper((unsigned char)*dp); 2614 *dp = toupper((unsigned char)*dp);
2616 st->cp = mod + 2; 2615 st->cp = mod + 2;
2617 st->termc = *st->cp; 2616 st->termc = *st->cp;
2618 } else if (mod[1] == 'l') { 2617 } else if (mod[1] == 'l') {
2619 char *dp = bmake_strdup(st->nstr); 2618 char *dp = bmake_strdup(st->nstr);
2620 for (st->newStr = dp; *dp; dp++) 2619 for (st->newStr = dp; *dp; dp++)
2621 *dp = tolower((unsigned char)*dp); 2620 *dp = tolower((unsigned char)*dp);
2622 st->cp = mod + 2; 2621 st->cp = mod + 2;
2623 st->termc = *st->cp; 2622 st->termc = *st->cp;
2624 } else if (mod[1] == 'W' || mod[1] == 'w') { 2623 } else if (mod[1] == 'W' || mod[1] == 'w') {
2625 st->oneBigWord = mod[1] == 'W'; 2624 st->oneBigWord = mod[1] == 'W';
2626 st->newStr = st->nstr; 2625 st->newStr = st->nstr;
2627 st->cp = mod + 2; 2626 st->cp = mod + 2;
2628 st->termc = *st->cp; 2627 st->termc = *st->cp;
2629 } else { 2628 } else {
2630 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2629 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2631 return FALSE; 2630 return FALSE;
2632 } 2631 }
2633 return TRUE; 2632 return TRUE;
2634} 2633}
2635 2634
2636/* :[#], :[1], etc. */ 2635/* :[#], :[1], etc. */
2637static int 2636static int
2638ApplyModifier_Words(const char *mod, ApplyModifiersState *st) 2637ApplyModifier_Words(const char *mod, ApplyModifiersState *st)
2639{ 2638{
2640 st->cp = mod + 1; /* point to char after '[' */ 2639 st->cp = mod + 1; /* point to char after '[' */
2641 char delim = ']'; /* look for closing ']' */ 2640 char delim = ']'; /* look for closing ']' */
2642 char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2641 char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2643 NULL, NULL, NULL); 2642 NULL, NULL, NULL);
2644 if (estr == NULL) { 2643 if (estr == NULL) {
2645 st->missing_delim = delim; 2644 st->missing_delim = delim;
2646 return 'c'; 2645 return 'c';
2647 } 2646 }
2648 2647
2649 /* now st->cp points just after the closing ']' */ 2648 /* now st->cp points just after the closing ']' */
2650 if (st->cp[0] != ':' && st->cp[0] != st->endc) 2649 if (st->cp[0] != ':' && st->cp[0] != st->endc)
2651 goto bad_modifier; /* Found junk after ']' */ 2650 goto bad_modifier; /* Found junk after ']' */
2652 2651
2653 if (estr[0] == '\0') 2652 if (estr[0] == '\0')
2654 goto bad_modifier; /* empty square brackets in ":[]". */ 2653 goto bad_modifier; /* empty square brackets in ":[]". */
2655 2654
2656 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2655 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2657 if (st->oneBigWord) { 2656 if (st->oneBigWord) {
2658 st->newStr = bmake_strdup("1"); 2657 st->newStr = bmake_strdup("1");
2659 } else { 2658 } else {
2660 /* XXX: brk_string() is a rather expensive 2659 /* XXX: brk_string() is a rather expensive
2661 * way of counting words. */ 2660 * way of counting words. */
2662 char *as; 2661 char *as;
2663 int ac; 2662 int ac;
2664 char **av = brk_string(st->nstr, &ac, FALSE, &as); 2663 char **av = brk_string(st->nstr, &ac, FALSE, &as);
2665 free(as); 2664 free(as);
2666 free(av); 2665 free(av);
2667 2666
2668 Buffer buf; 2667 Buffer buf;
2669 Buf_Init(&buf, 4); /* 3 digits + '\0' */ 2668 Buf_Init(&buf, 4); /* 3 digits + '\0' */
2670 Buf_AddInt(&buf, ac); 2669 Buf_AddInt(&buf, ac);
2671 st->newStr = Buf_Destroy(&buf, FALSE); 2670 st->newStr = Buf_Destroy(&buf, FALSE);
2672 } 2671 }
2673 goto ok; 2672 goto ok;
2674 } 2673 }
2675 2674
2676 if (estr[0] == '*' && estr[1] == '\0') { 2675 if (estr[0] == '*' && estr[1] == '\0') {
2677 /* Found ":[*]" */ 2676 /* Found ":[*]" */
2678 st->oneBigWord = TRUE; 2677 st->oneBigWord = TRUE;
2679 st->newStr = st->nstr; 2678 st->newStr = st->nstr;
2680 goto ok; 2679 goto ok;
2681 } 2680 }
2682 2681
2683 if (estr[0] == '@' && estr[1] == '\0') { 2682 if (estr[0] == '@' && estr[1] == '\0') {
2684 /* Found ":[@]" */ 2683 /* Found ":[@]" */
2685 st->oneBigWord = FALSE; 2684 st->oneBigWord = FALSE;
2686 st->newStr = st->nstr; 2685 st->newStr = st->nstr;
2687 goto ok; 2686 goto ok;
2688 } 2687 }
2689 2688
2690 /* 2689 /*
2691 * We expect estr to contain a single integer for :[N], or two integers 2690 * We expect estr to contain a single integer for :[N], or two integers
2692 * separated by ".." for :[start..end]. 2691 * separated by ".." for :[start..end].
2693 */ 2692 */
2694 char *ep; 2693 char *ep;
2695 int first = strtol(estr, &ep, 0); 2694 int first = strtol(estr, &ep, 0);
2696 int last; 2695 int last;
2697 if (ep == estr) /* Found junk instead of a number */ 2696 if (ep == estr) /* Found junk instead of a number */
2698 goto bad_modifier; 2697 goto bad_modifier;
2699 2698
2700 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2699 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2701 last = first; 2700 last = first;
2702 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2701 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2703 /* Expecting another integer after ".." */ 2702 /* Expecting another integer after ".." */
2704 ep += 2; 2703 ep += 2;
2705 last = strtol(ep, &ep, 0); 2704 last = strtol(ep, &ep, 0);
2706 if (ep[0] != '\0') /* Found junk after ".." */ 2705 if (ep[0] != '\0') /* Found junk after ".." */
2707 goto bad_modifier; 2706 goto bad_modifier;
2708 } else 2707 } else
2709 goto bad_modifier; /* Found junk instead of ".." */ 2708 goto bad_modifier; /* Found junk instead of ".." */
2710 2709
2711 /* 2710 /*
2712 * Now seldata is properly filled in, but we still have to check for 0 as 2711 * Now seldata is properly filled in, but we still have to check for 0 as
2713 * a special case. 2712 * a special case.
2714 */ 2713 */
2715 if (first == 0 && last == 0) { 2714 if (first == 0 && last == 0) {
2716 /* ":[0]" or perhaps ":[0..0]" */ 2715 /* ":[0]" or perhaps ":[0..0]" */
2717 st->oneBigWord = TRUE; 2716 st->oneBigWord = TRUE;
2718 st->newStr = st->nstr; 2717 st->newStr = st->nstr;
2719 goto ok; 2718 goto ok;
2720 } 2719 }
2721 2720
2722 /* ":[0..N]" or ":[N..0]" */ 2721 /* ":[0..N]" or ":[N..0]" */
2723 if (first == 0 || last == 0) 2722 if (first == 0 || last == 0)
2724 goto bad_modifier; 2723 goto bad_modifier;
2725 2724
2726 /* Normal case: select the words described by seldata. */ 2725 /* Normal case: select the words described by seldata. */
2727 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); 2726 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last);
2728 2727
2729ok: 2728ok:
2730 st->termc = *st->cp; 2729 st->termc = *st->cp;
2731 free(estr); 2730 free(estr);
2732 return 0; 2731 return 0;
2733 2732
2734bad_modifier: 2733bad_modifier:
2735 free(estr); 2734 free(estr);
2736 return 'b'; 2735 return 'b';
2737} 2736}
2738 2737
2739/* :O or :Ox */ 2738/* :O or :Ox */
2740static Boolean 2739static Boolean
2741ApplyModifier_Order(const char *mod, ApplyModifiersState *st) 2740ApplyModifier_Order(const char *mod, ApplyModifiersState *st)
2742{ 2741{
2743 char otype; 2742 char otype;
2744 2743
2745 st->cp = mod + 1; /* skip to the rest in any case */ 2744 st->cp = mod + 1; /* skip to the rest in any case */
2746 if (mod[1] == st->endc || mod[1] == ':') { 2745 if (mod[1] == st->endc || mod[1] == ':') {
2747 otype = 's'; 2746 otype = 's';
2748 st->termc = *st->cp; 2747 st->termc = *st->cp;
2749 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2748 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2750 (mod[2] == st->endc || mod[2] == ':')) { 2749 (mod[2] == st->endc || mod[2] == ':')) {
2751 otype = mod[1]; 2750 otype = mod[1];
2752 st->cp = mod + 2; 2751 st->cp = mod + 2;
2753 st->termc = *st->cp; 2752 st->termc = *st->cp;
2754 } else { 2753 } else {
2755 return FALSE; 2754 return FALSE;
2756 } 2755 }
2757 st->newStr = VarOrder(st->nstr, otype); 2756 st->newStr = VarOrder(st->nstr, otype);
2758 return TRUE; 2757 return TRUE;
2759} 2758}
2760 2759
2761/* :? then : else */ 2760/* :? then : else */
2762static Boolean 2761static Boolean
2763ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) 2762ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st)
2764{ 2763{
2765 Boolean value = FALSE; 2764 Boolean value = FALSE;
2766 int cond_rc = 0; 2765 int cond_rc = 0;
2767 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; 2766 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES;
2768 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; 2767 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES;
2769 2768
2770 if (st->eflags & VARE_WANTRES) { 2769 if (st->eflags & VARE_WANTRES) {
2771 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); 2770 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
2772 if (cond_rc != COND_INVALID && value) 2771 if (cond_rc != COND_INVALID && value)
2773 then_eflags |= VARE_WANTRES; 2772 then_eflags |= VARE_WANTRES;
2774 if (cond_rc != COND_INVALID && !value) 2773 if (cond_rc != COND_INVALID && !value)
2775 else_eflags |= VARE_WANTRES; 2774 else_eflags |= VARE_WANTRES;
2776 } 2775 }
2777 2776
2778 st->cp = mod + 1; 2777 st->cp = mod + 1;
2779 char delim = ':'; 2778 char delim = ':';
2780 char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt, 2779 char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt,
2781 NULL, NULL, NULL); 2780 NULL, NULL, NULL);
2782 if (then_expr == NULL) { 2781 if (then_expr == NULL) {
2783 st->missing_delim = delim; 2782 st->missing_delim = delim;
2784 return FALSE; 2783 return FALSE;
2785 } 2784 }
2786 2785
2787 delim = st->endc; /* BRCLOSE or PRCLOSE */ 2786 delim = st->endc; /* BRCLOSE or PRCLOSE */
2788 char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt, 2787 char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt,
2789 NULL, NULL, NULL); 2788 NULL, NULL, NULL);
2790 if (else_expr == NULL) { 2789 if (else_expr == NULL) {
2791 st->missing_delim = delim; 2790 st->missing_delim = delim;
2792 return FALSE; 2791 return FALSE;
2793 } 2792 }
2794 2793
2795 st->termc = *--st->cp; 2794 st->termc = *--st->cp;
2796 if (cond_rc == COND_INVALID) { 2795 if (cond_rc == COND_INVALID) {
2797 Error("Bad conditional expression `%s' in %s?%s:%s", 2796 Error("Bad conditional expression `%s' in %s?%s:%s",
2798 st->v->name, st->v->name, then_expr, else_expr); 2797 st->v->name, st->v->name, then_expr, else_expr);
2799 return FALSE; 2798 return FALSE;
2800 } 2799 }
2801 2800
2802 if (value) { 2801 if (value) {
2803 st->newStr = then_expr; 2802 st->newStr = then_expr;
2804 free(else_expr); 2803 free(else_expr);
2805 } else { 2804 } else {
2806 st->newStr = else_expr; 2805 st->newStr = else_expr;
2807 free(then_expr); 2806 free(then_expr);
2808 } 2807 }
2809 if (st->v->flags & VAR_JUNK) 2808 if (st->v->flags & VAR_JUNK)
2810 st->v->flags |= VAR_KEEP; 2809 st->v->flags |= VAR_KEEP;
2811 return TRUE; 2810 return TRUE;
2812} 2811}
2813 2812
2814/* 2813/*
2815 * The ::= modifiers actually assign a value to the variable. 2814 * The ::= modifiers actually assign a value to the variable.
2816 * Their main purpose is in supporting modifiers of .for loop 2815 * Their main purpose is in supporting modifiers of .for loop
2817 * iterators and other obscure uses. They always expand to 2816 * iterators and other obscure uses. They always expand to
2818 * nothing. In a target rule that would otherwise expand to an 2817 * nothing. In a target rule that would otherwise expand to an
2819 * empty line they can be preceded with @: to keep make happy. 2818 * empty line they can be preceded with @: to keep make happy.
2820 * Eg. 2819 * Eg.
2821 * 2820 *
2822 * foo: .USE 2821 * foo: .USE
2823 * .for i in ${.TARGET} ${.TARGET:R}.gz 2822 * .for i in ${.TARGET} ${.TARGET:R}.gz
2824 * @: ${t::=$i} 2823 * @: ${t::=$i}
2825 * @echo blah ${t:T} 2824 * @echo blah ${t:T}
2826 * .endfor 2825 * .endfor
2827 * 2826 *
2828 * ::=<str> Assigns <str> as the new value of variable. 2827 * ::=<str> Assigns <str> as the new value of variable.
2829 * ::?=<str> Assigns <str> as value of variable if 2828 * ::?=<str> Assigns <str> as value of variable if
2830 * it was not already set. 2829 * it was not already set.
2831 * ::+=<str> Appends <str> to variable. 2830 * ::+=<str> Appends <str> to variable.
2832 * ::!=<cmd> Assigns output of <cmd> as the new value of 2831 * ::!=<cmd> Assigns output of <cmd> as the new value of
2833 * variable. 2832 * variable.
2834 */ 2833 */
2835static int 2834static int
2836ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) 2835ApplyModifier_Assign(const char *mod, ApplyModifiersState *st)
2837{ 2836{
2838 const char *op = mod + 1; 2837 const char *op = mod + 1;
2839 if (!(op[0] == '=' || 2838 if (!(op[0] == '=' ||
2840 (op[1] == '=' && 2839 (op[1] == '=' &&
2841 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2840 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2842 return 'd'; /* "::<unrecognised>" */ 2841 return 'd'; /* "::<unrecognised>" */
2843 2842
2844 GNode *v_ctxt; /* context where v belongs */ 2843 GNode *v_ctxt; /* context where v belongs */
2845 2844
2846 if (st->v->name[0] == 0) 2845 if (st->v->name[0] == 0)
2847 return 'b'; 2846 return 'b';
2848 2847
2849 v_ctxt = st->ctxt; 2848 v_ctxt = st->ctxt;
2850 char *sv_name = NULL; 2849 char *sv_name = NULL;
2851 if (st->v->flags & VAR_JUNK) { 2850 if (st->v->flags & VAR_JUNK) {
2852 /* 2851 /*
2853 * We need to bmake_strdup() it incase ParseModifierPart() recurses. 2852 * We need to bmake_strdup() it incase ParseModifierPart() recurses.
2854 */ 2853 */
2855 sv_name = st->v->name; 2854 sv_name = st->v->name;
2856 st->v->name = bmake_strdup(st->v->name); 2855 st->v->name = bmake_strdup(st->v->name);
2857 } else if (st->ctxt != VAR_GLOBAL) { 2856 } else if (st->ctxt != VAR_GLOBAL) {
2858 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2857 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2859 if (gv == NULL) 2858 if (gv == NULL)
2860 v_ctxt = VAR_GLOBAL; 2859 v_ctxt = VAR_GLOBAL;
2861 else 2860 else
2862 VarFreeEnv(gv, TRUE); 2861 VarFreeEnv(gv, TRUE);
2863 } 2862 }
2864 2863
2865 switch (op[0]) { 2864 switch (op[0]) {
2866 case '+': 2865 case '+':
2867 case '?': 2866 case '?':
2868 case '!': 2867 case '!':
2869 st->cp = mod + 3; 2868 st->cp = mod + 3;
2870 break; 2869 break;
2871 default: 2870 default:
2872 st->cp = mod + 2; 2871 st->cp = mod + 2;
2873 break; 2872 break;
2874 } 2873 }
2875 2874
2876 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; 2875 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
2877 char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2876 char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2878 NULL, NULL, NULL); 2877 NULL, NULL, NULL);
2879 if (st->v->flags & VAR_JUNK) { 2878 if (st->v->flags & VAR_JUNK) {
2880 /* restore original name */ 2879 /* restore original name */
2881 free(st->v->name); 2880 free(st->v->name);
2882 st->v->name = sv_name; 2881 st->v->name = sv_name;
2883 } 2882 }
2884 if (val == NULL) { 2883 if (val == NULL) {
2885 st->missing_delim = delim; 2884 st->missing_delim = delim;
2886 return 'c'; 2885 return 'c';
2887 } 2886 }
2888 2887
2889 st->termc = *--st->cp; 2888 st->termc = *--st->cp;
2890 2889
2891 if (st->eflags & VARE_WANTRES) { 2890 if (st->eflags & VARE_WANTRES) {
2892 switch (op[0]) { 2891 switch (op[0]) {
2893 case '+': 2892 case '+':
2894 Var_Append(st->v->name, val, v_ctxt); 2893 Var_Append(st->v->name, val, v_ctxt);
2895 break; 2894 break;
2896 case '!': { 2895 case '!': {
2897 const char *emsg; 2896 const char *emsg;
2898 st->newStr = Cmd_Exec(val, &emsg); 2897 st->newStr = Cmd_Exec(val, &emsg);
2899 if (emsg) 2898 if (emsg)
2900 Error(emsg, st->nstr); 2899 Error(emsg, st->nstr);
2901 else 2900 else
2902 Var_Set(st->v->name, st->newStr, v_ctxt); 2901 Var_Set(st->v->name, st->newStr, v_ctxt);
2903 free(st->newStr); 2902 free(st->newStr);
2904 break; 2903 break;
2905 } 2904 }
2906 case '?': 2905 case '?':
2907 if (!(st->v->flags & VAR_JUNK)) 2906 if (!(st->v->flags & VAR_JUNK))
2908 break; 2907 break;
2909 /* FALLTHROUGH */ 2908 /* FALLTHROUGH */
2910 default: 2909 default:
2911 Var_Set(st->v->name, val, v_ctxt); 2910 Var_Set(st->v->name, val, v_ctxt);
2912 break; 2911 break;
2913 } 2912 }
2914 } 2913 }
2915 free(val); 2914 free(val);
2916 st->newStr = varNoError; 2915 st->newStr = varNoError;
2917 return 0; 2916 return 0;
2918} 2917}
2919 2918
2920/* remember current value */ 2919/* remember current value */
2921static Boolean 2920static Boolean
2922ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) 2921ApplyModifier_Remember(const char *mod, ApplyModifiersState *st)
2923{ 2922{
2924 if (!ModMatchEq(mod, "_", st->endc)) { 2923 if (!ModMatchEq(mod, "_", st->endc)) {
2925 st->cp = mod + 1; 2924 st->cp = mod + 1;
2926 return FALSE; 2925 return FALSE;
2927 } 2926 }
2928 2927
2929 if (mod[1] == '=') { 2928 if (mod[1] == '=') {
2930 size_t n = strcspn(mod + 2, ":)}"); 2929 size_t n = strcspn(mod + 2, ":)}");
2931 char *name = bmake_strndup(mod + 2, n); 2930 char *name = bmake_strndup(mod + 2, n);
2932 Var_Set(name, st->nstr, st->ctxt); 2931 Var_Set(name, st->nstr, st->ctxt);
2933 free(name); 2932 free(name);
2934 st->cp = mod + 2 + n; 2933 st->cp = mod + 2 + n;
2935 } else { 2934 } else {
2936 Var_Set("_", st->nstr, st->ctxt); 2935 Var_Set("_", st->nstr, st->ctxt);
2937 st->cp = mod + 1; 2936 st->cp = mod + 1;
2938 } 2937 }
2939 st->newStr = st->nstr; 2938 st->newStr = st->nstr;
2940 st->termc = *st->cp; 2939 st->termc = *st->cp;
2941 return TRUE; 2940 return TRUE;
2942} 2941}
2943 2942
2944#ifdef SYSVVARSUB 2943#ifdef SYSVVARSUB
2945/* :from=to */ 2944/* :from=to */
2946static int 2945static int
2947ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) 2946ApplyModifier_SysV(const char *mod, ApplyModifiersState *st)
2948{ 2947{
2949 Boolean eqFound = FALSE; 2948 Boolean eqFound = FALSE;
2950 2949
2951 /* 2950 /*
2952 * First we make a pass through the string trying 2951 * First we make a pass through the string trying
2953 * to verify it is a SYSV-make-style translation: 2952 * to verify it is a SYSV-make-style translation:
2954 * it must be: <string1>=<string2>) 2953 * it must be: <string1>=<string2>)
2955 */ 2954 */
2956 st->cp = mod; 2955 st->cp = mod;
2957 int nest = 1; 2956 int nest = 1;
2958 while (*st->cp != '\0' && nest > 0) { 2957 while (*st->cp != '\0' && nest > 0) {
2959 if (*st->cp == '=') { 2958 if (*st->cp == '=') {
2960 eqFound = TRUE; 2959 eqFound = TRUE;
2961 /* continue looking for st->endc */ 2960 /* continue looking for st->endc */
2962 } else if (*st->cp == st->endc) 2961 } else if (*st->cp == st->endc)
2963 nest--; 2962 nest--;
2964 else if (*st->cp == st->startc) 2963 else if (*st->cp == st->startc)
2965 nest++; 2964 nest++;
2966 if (nest > 0) 2965 if (nest > 0)
2967 st->cp++; 2966 st->cp++;
2968 } 2967 }
2969 if (*st->cp != st->endc || !eqFound) 2968 if (*st->cp != st->endc || !eqFound)
2970 return 0; 2969 return 0;
2971 2970
2972 char delim = '='; 2971 char delim = '=';
2973 st->cp = mod; 2972 st->cp = mod;
2974 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2973 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2975 NULL, NULL, NULL); 2974 NULL, NULL, NULL);
2976 if (lhs == NULL) { 2975 if (lhs == NULL) {
2977 st->missing_delim = delim; 2976 st->missing_delim = delim;
2978 return 'c'; 2977 return 'c';
2979 } 2978 }
2980 2979
2981 delim = st->endc; 2980 delim = st->endc;
2982 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2981 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2983 NULL, NULL, NULL); 2982 NULL, NULL, NULL);
2984 if (rhs == NULL) { 2983 if (rhs == NULL) {
2985 st->missing_delim = delim; 2984 st->missing_delim = delim;
2986 return 'c'; 2985 return 'c';
2987 } 2986 }
2988 2987
2989 /* 2988 /*
2990 * SYSV modifications happen through the whole 2989 * SYSV modifications happen through the whole
2991 * string. Note the pattern is anchored at the end. 2990 * string. Note the pattern is anchored at the end.
2992 */ 2991 */
2993 st->termc = *--st->cp; 2992 st->termc = *--st->cp;
2994 if (lhs[0] == '\0' && *st->nstr == '\0') { 2993 if (lhs[0] == '\0' && *st->nstr == '\0') {
2995 st->newStr = st->nstr; /* special case */ 2994 st->newStr = st->nstr; /* special case */
2996 } else { 2995 } else {
2997 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; 2996 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
2998 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2997 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2999 ModifyWord_SYSVSubst, &args); 2998 ModifyWord_SYSVSubst, &args);
3000 } 2999 }
3001 free(lhs); 3000 free(lhs);
3002 free(rhs); 3001 free(rhs);
3003 return '='; 3002 return '=';
3004} 3003}
3005#endif 3004#endif
3006 3005
3007/* 3006/*
3008 * Now we need to apply any modifiers the user wants applied. 3007 * Now we need to apply any modifiers the user wants applied.
3009 * These are: 3008 * These are:
3010 * :M<pattern> words which match the given <pattern>. 3009 * :M<pattern> words which match the given <pattern>.
3011 * <pattern> is of the standard file 3010 * <pattern> is of the standard file
3012 * wildcarding form. 3011 * wildcarding form.
3013 * :N<pattern> words which do not match the given <pattern>. 3012 * :N<pattern> words which do not match the given <pattern>.
3014 * :S<d><pat1><d><pat2><d>[1gW] 3013 * :S<d><pat1><d><pat2><d>[1gW]
3015 * Substitute <pat2> for <pat1> in the value 3014 * Substitute <pat2> for <pat1> in the value
3016 * :C<d><pat1><d><pat2><d>[1gW] 3015 * :C<d><pat1><d><pat2><d>[1gW]
3017 * Substitute <pat2> for regex <pat1> in the value 3016 * Substitute <pat2> for regex <pat1> in the value
3018 * :H Substitute the head of each word 3017 * :H Substitute the head of each word
3019 * :T Substitute the tail of each word 3018 * :T Substitute the tail of each word
3020 * :E Substitute the extension (minus '.') of 3019 * :E Substitute the extension (minus '.') of
3021 * each word 3020 * each word
3022 * :R Substitute the root of each word 3021 * :R Substitute the root of each word
3023 * (pathname minus the suffix). 3022 * (pathname minus the suffix).
3024 * :O ("Order") Alphabeticaly sort words in variable. 3023 * :O ("Order") Alphabeticaly sort words in variable.
3025 * :Ox ("intermiX") Randomize words in variable. 3024 * :Ox ("intermiX") Randomize words in variable.
3026 * :u ("uniq") Remove adjacent duplicate words. 3025 * :u ("uniq") Remove adjacent duplicate words.
3027 * :tu Converts the variable contents to uppercase. 3026 * :tu Converts the variable contents to uppercase.
3028 * :tl Converts the variable contents to lowercase. 3027 * :tl Converts the variable contents to lowercase.
3029 * :ts[c] Sets varSpace - the char used to 3028 * :ts[c] Sets varSpace - the char used to
3030 * separate words to 'c'. If 'c' is 3029 * separate words to 'c'. If 'c' is
3031 * omitted then no separation is used. 3030 * omitted then no separation is used.
3032 * :tW Treat the variable contents as a single 3031 * :tW Treat the variable contents as a single
3033 * word, even if it contains spaces. 3032 * word, even if it contains spaces.
3034 * (Mnemonic: one big 'W'ord.) 3033 * (Mnemonic: one big 'W'ord.)
3035 * :tw Treat the variable contents as multiple 3034 * :tw Treat the variable contents as multiple
3036 * space-separated words. 3035 * space-separated words.
3037 * (Mnemonic: many small 'w'ords.) 3036 * (Mnemonic: many small 'w'ords.)
3038 * :[index] Select a single word from the value. 3037 * :[index] Select a single word from the value.
3039 * :[start..end] Select multiple words from the value. 3038 * :[start..end] Select multiple words from the value.
3040 * :[*] or :[0] Select the entire value, as a single 3039 * :[*] or :[0] Select the entire value, as a single
3041 * word. Equivalent to :tW. 3040 * word. Equivalent to :tW.
3042 * :[@] Select the entire value, as multiple 3041 * :[@] Select the entire value, as multiple
3043 * words. Undoes the effect of :[*]. 3042 * words. Undoes the effect of :[*].
3044 * Equivalent to :tw. 3043 * Equivalent to :tw.
3045 * :[#] Returns the number of words in the value. 3044 * :[#] Returns the number of words in the value.
3046 * 3045 *
3047 * :?<true-value>:<false-value> 3046 * :?<true-value>:<false-value>
3048 * If the variable evaluates to true, return 3047 * If the variable evaluates to true, return
3049 * true value, else return the second value. 3048 * true value, else return the second value.
3050 * :lhs=rhs Like :S, but the rhs goes to the end of 3049 * :lhs=rhs Like :S, but the rhs goes to the end of
3051 * the invocation. 3050 * the invocation.
3052 * :sh Treat the current value as a command 3051 * :sh Treat the current value as a command
3053 * to be run, new value is its output. 3052 * to be run, new value is its output.
3054 * The following added so we can handle ODE makefiles. 3053 * The following added so we can handle ODE makefiles.
3055 * :@<tmpvar>@<newval>@ 3054 * :@<tmpvar>@<newval>@
3056 * Assign a temporary local variable <tmpvar> 3055 * Assign a temporary local variable <tmpvar>
3057 * to the current value of each word in turn 3056 * to the current value of each word in turn
3058 * and replace each word with the result of 3057 * and replace each word with the result of
3059 * evaluating <newval> 3058 * evaluating <newval>
3060 * :D<newval> Use <newval> as value if variable defined 3059 * :D<newval> Use <newval> as value if variable defined
3061 * :U<newval> Use <newval> as value if variable undefined 3060 * :U<newval> Use <newval> as value if variable undefined
3062 * :L Use the name of the variable as the value. 3061 * :L Use the name of the variable as the value.
3063 * :P Use the path of the node that has the same 3062 * :P Use the path of the node that has the same
3064 * name as the variable as the value. This 3063 * name as the variable as the value. This
3065 * basically includes an implied :L so that 3064 * basically includes an implied :L so that
3066 * the common method of refering to the path 3065 * the common method of refering to the path
3067 * of your dependent 'x' in a rule is to use 3066 * of your dependent 'x' in a rule is to use
3068 * the form '${x:P}'. 3067 * the form '${x:P}'.
3069 * :!<cmd>! Run cmd much the same as :sh run's the 3068 * :!<cmd>! Run cmd much the same as :sh run's the
3070 * current value of the variable. 3069 * current value of the variable.
3071 * Assignment operators (see ApplyModifier_Assign). 3070 * Assignment operators (see ApplyModifier_Assign).
3072 */ 3071 */
3073static char * 3072static char *
3074ApplyModifiers(char *nstr, const char *tstr, 3073ApplyModifiers(char *nstr, const char *tstr,
3075 int const startc, int const endc, 3074 int const startc, int const endc,
3076 Var * const v, GNode * const ctxt, VarEvalFlags const eflags, 3075 Var * const v, GNode * const ctxt, VarEvalFlags const eflags,
3077 int * const lengthPtr, void ** const freePtr) 3076 int * const lengthPtr, void ** const freePtr)
3078{ 3077{
3079 ApplyModifiersState st = { 3078 ApplyModifiersState st = {
3080 startc, endc, v, ctxt, eflags, lengthPtr, freePtr, 3079 startc, endc, v, ctxt, eflags, lengthPtr, freePtr,
3081 nstr, tstr, tstr, 3080 nstr, tstr, tstr,
3082 '\0', '\0', ' ', FALSE, NULL 3081 '\0', '\0', ' ', FALSE, NULL
3083 }; 3082 };
3084 3083
3085 const char *p = tstr; 3084 const char *p = tstr;
3086 while (*p != '\0' && *p != endc) { 3085 while (*p != '\0' && *p != endc) {
3087 3086
3088 if (*p == '$') { 3087 if (*p == '$') {
3089 /* 3088 /*
3090 * We may have some complex modifiers in a variable. 3089 * We may have some complex modifiers in a variable.
3091 */ 3090 */
3092 void *freeIt; 3091 void *freeIt;
3093 const char *rval; 3092 const char *rval;
3094 int rlen; 3093 int rlen;
3095 int c; 3094 int c;
3096 3095
3097 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt); 3096 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt);
3098 3097
3099 /* 3098 /*
3100 * If we have not parsed up to st.endc or ':', 3099 * If we have not parsed up to st.endc or ':',
3101 * we are not interested. 3100 * we are not interested.
3102 */ 3101 */
3103 if (rval != NULL && *rval && 3102 if (rval != NULL && *rval &&
3104 (c = p[rlen]) != '\0' && 3103 (c = p[rlen]) != '\0' &&
3105 c != ':' && 3104 c != ':' &&
3106 c != st.endc) { 3105 c != st.endc) {
3107 free(freeIt); 3106 free(freeIt);
3108 goto apply_mods; 3107 goto apply_mods;
3109 } 3108 }
3110 3109
3111 if (DEBUG(VAR)) { 3110 if (DEBUG(VAR)) {
3112 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", 3111 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3113 rval, rlen, p, rlen, p + rlen); 3112 rval, rlen, p, rlen, p + rlen);
3114 } 3113 }
3115 3114
3116 p += rlen; 3115 p += rlen;
3117 3116
3118 if (rval != NULL && *rval) { 3117 if (rval != NULL && *rval) {
3119 int used; 3118 int used;
3120 3119
3121 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v, 3120 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3122 st.ctxt, st.eflags, &used, st.freePtr); 3121 st.ctxt, st.eflags, &used, st.freePtr);
3123 if (st.nstr == var_Error 3122 if (st.nstr == var_Error
3124 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0) 3123 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0)
3125 || strlen(rval) != (size_t) used) { 3124 || strlen(rval) != (size_t) used) {
3126 free(freeIt); 3125 free(freeIt);
3127 goto out; /* error already reported */ 3126 goto out; /* error already reported */
3128 } 3127 }
3129 } 3128 }
3130 free(freeIt); 3129 free(freeIt);
3131 if (*p == ':') 3130 if (*p == ':')
3132 p++; 3131 p++;
3133 else if (*p == '\0' && endc != '\0') { 3132 else if (*p == '\0' && endc != '\0') {
3134 Error("Unclosed variable specification after complex " 3133 Error("Unclosed variable specification after complex "
3135 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3134 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3136 goto out; 3135 goto out;
3137 } 3136 }
3138 continue; 3137 continue;
3139 } 3138 }
3140 apply_mods: 3139 apply_mods:
3141 if (DEBUG(VAR)) { 3140 if (DEBUG(VAR)) {
3142 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, 3141 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3143 *p, st.nstr); 3142 *p, st.nstr);
3144 } 3143 }
3145 st.newStr = var_Error; 3144 st.newStr = var_Error;
3146 char modifier = *p; 3145 char modifier = *p;
3147 switch (modifier) { 3146 switch (modifier) {
3148 case ':': 3147 case ':':
3149 { 3148 {
3150 int res = ApplyModifier_Assign(p, &st); 3149 int res = ApplyModifier_Assign(p, &st);
3151 if (res == 'b') 3150 if (res == 'b')
3152 goto bad_modifier; 3151 goto bad_modifier;
3153 if (res == 'c') 3152 if (res == 'c')
3154 goto cleanup; 3153 goto cleanup;
3155 if (res == 'd') 3154 if (res == 'd')
3156 goto default_case; 3155 goto default_case;
3157 break; 3156 break;
3158 } 3157 }
3159 case '@': 3158 case '@':
3160 if (!ApplyModifier_Loop(p, &st)) 3159 if (!ApplyModifier_Loop(p, &st))
3161 goto cleanup; 3160 goto cleanup;
3162 break; 3161 break;
3163 case '_': 3162 case '_':
3164 if (!ApplyModifier_Remember(p, &st)) 3163 if (!ApplyModifier_Remember(p, &st))
3165 goto default_case; 3164 goto default_case;
3166 break; 3165 break;
3167 case 'D': 3166 case 'D':
3168 case 'U': 3167 case 'U':
3169 ApplyModifier_Defined(p, &st); 3168 ApplyModifier_Defined(p, &st);
3170 break; 3169 break;
3171 case 'L': 3170 case 'L':
3172 { 3171 {
3173 if (st.v->flags & VAR_JUNK) 3172 if (st.v->flags & VAR_JUNK)
3174 st.v->flags |= VAR_KEEP; 3173 st.v->flags |= VAR_KEEP;
3175 st.newStr = bmake_strdup(st.v->name); 3174 st.newStr = bmake_strdup(st.v->name);
3176 st.cp = p + 1; 3175 st.cp = p + 1;
3177 st.termc = *st.cp; 3176 st.termc = *st.cp;
3178 break; 3177 break;
3179 } 3178 }
3180 case 'P': 3179 case 'P':
3181 ApplyModifier_Path(p, &st); 3180 ApplyModifier_Path(p, &st);
3182 break; 3181 break;
3183 case '!': 3182 case '!':
3184 if (!ApplyModifier_Exclam(p, &st)) 3183 if (!ApplyModifier_Exclam(p, &st))
3185 goto cleanup; 3184 goto cleanup;
3186 break; 3185 break;
3187 case '[': 3186 case '[':
3188 { 3187 {
3189 int res = ApplyModifier_Words(p, &st); 3188 int res = ApplyModifier_Words(p, &st);
3190 if (res == 'b') 3189 if (res == 'b')
3191 goto bad_modifier; 3190 goto bad_modifier;
3192 if (res == 'c') 3191 if (res == 'c')
3193 goto cleanup; 3192 goto cleanup;
3194 break; 3193 break;
3195 } 3194 }
3196 case 'g': 3195 case 'g':
3197 if (!ApplyModifier_Gmtime(p, &st)) 3196 if (!ApplyModifier_Gmtime(p, &st))
3198 goto default_case; 3197 goto default_case;
3199 break; 3198 break;
3200 case 'h': 3199 case 'h':
3201 if (!ApplyModifier_Hash(p, &st)) 3200 if (!ApplyModifier_Hash(p, &st))
3202 goto default_case; 3201 goto default_case;
3203 break; 3202 break;
3204 case 'l': 3203 case 'l':
3205 if (!ApplyModifier_Localtime(p, &st)) 3204 if (!ApplyModifier_Localtime(p, &st))
3206 goto default_case; 3205 goto default_case;
3207 break; 3206 break;
3208 case 't': 3207 case 't':
3209 if (!ApplyModifier_To(p, &st)) 3208 if (!ApplyModifier_To(p, &st))
3210 goto bad_modifier; 3209 goto bad_modifier;
3211 break; 3210 break;
3212 case 'N': 3211 case 'N':
3213 case 'M': 3212 case 'M':
3214 ApplyModifier_Match(p, &st); 3213 ApplyModifier_Match(p, &st);
3215 break; 3214 break;
3216 case 'S': 3215 case 'S':
3217 if (!ApplyModifier_Subst(p, &st)) 3216 if (!ApplyModifier_Subst(p, &st))
3218 goto cleanup; 3217 goto cleanup;
3219 break; 3218 break;
3220 case '?': 3219 case '?':
3221 if (!ApplyModifier_IfElse(p, &st)) 3220 if (!ApplyModifier_IfElse(p, &st))
3222 goto cleanup; 3221 goto cleanup;
3223 break; 3222 break;
3224#ifndef NO_REGEX 3223#ifndef NO_REGEX
3225 case 'C': 3224 case 'C':
3226 if (!ApplyModifier_Regex(p, &st)) 3225 if (!ApplyModifier_Regex(p, &st))
3227 goto cleanup; 3226 goto cleanup;
3228 break; 3227 break;
3229#endif 3228#endif
3230 case 'q': 3229 case 'q':
3231 case 'Q': 3230 case 'Q':
3232 if (p[1] == st.endc || p[1] == ':') { 3231 if (p[1] == st.endc || p[1] == ':') {
3233 st.newStr = VarQuote(st.nstr, modifier == 'q'); 3232 st.newStr = VarQuote(st.nstr, modifier == 'q');
3234 st.cp = p + 1; 3233 st.cp = p + 1;
3235 st.termc = *st.cp; 3234 st.termc = *st.cp;
3236 break; 3235 break;
3237 } 3236 }
3238 goto default_case; 3237 goto default_case;
3239 case 'T': 3238 case 'T':
3240 if (p[1] == st.endc || p[1] == ':') { 3239 if (p[1] == st.endc || p[1] == ':') {
3241 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3240 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3242 st.nstr, ModifyWord_Tail, NULL); 3241 st.nstr, ModifyWord_Tail, NULL);
3243 st.cp = p + 1; 3242 st.cp = p + 1;
3244 st.termc = *st.cp; 3243 st.termc = *st.cp;
3245 break; 3244 break;
3246 } 3245 }
3247 goto default_case; 3246 goto default_case;
3248 case 'H': 3247 case 'H':
3249 if (p[1] == st.endc || p[1] == ':') { 3248 if (p[1] == st.endc || p[1] == ':') {
3250 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3249 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3251 st.nstr, ModifyWord_Head, NULL); 3250 st.nstr, ModifyWord_Head, NULL);
3252 st.cp = p + 1; 3251 st.cp = p + 1;
3253 st.termc = *st.cp; 3252 st.termc = *st.cp;
3254 break; 3253 break;
3255 } 3254 }
3256 goto default_case; 3255 goto default_case;
3257 case 'E': 3256 case 'E':
3258 if (p[1] == st.endc || p[1] == ':') { 3257 if (p[1] == st.endc || p[1] == ':') {
3259 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3258 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3260 st.nstr, ModifyWord_Suffix, NULL); 3259 st.nstr, ModifyWord_Suffix, NULL);
3261 st.cp = p + 1; 3260 st.cp = p + 1;
3262 st.termc = *st.cp; 3261 st.termc = *st.cp;
3263 break; 3262 break;
3264 } 3263 }
3265 goto default_case; 3264 goto default_case;
3266 case 'R': 3265 case 'R':
3267 if (p[1] == st.endc || p[1] == ':') { 3266 if (p[1] == st.endc || p[1] == ':') {
3268 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3267 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3269 st.nstr, ModifyWord_Root, NULL); 3268 st.nstr, ModifyWord_Root, NULL);
3270 st.cp = p + 1; 3269 st.cp = p + 1;
3271 st.termc = *st.cp; 3270 st.termc = *st.cp;
3272 break; 3271 break;
3273 } 3272 }
3274 goto default_case; 3273 goto default_case;
3275 case 'r': 3274 case 'r':
3276 if (!ApplyModifier_Range(p, &st)) 3275 if (!ApplyModifier_Range(p, &st))
3277 goto default_case; 3276 goto default_case;
3278 break; 3277 break;
3279 case 'O': 3278 case 'O':
3280 if (!ApplyModifier_Order(p, &st)) 3279 if (!ApplyModifier_Order(p, &st))
3281 goto bad_modifier; 3280 goto bad_modifier;
3282 break; 3281 break;
3283 case 'u': 3282 case 'u':
3284 if (p[1] == st.endc || p[1] == ':') { 3283 if (p[1] == st.endc || p[1] == ':') {
3285 st.newStr = VarUniq(st.nstr); 3284 st.newStr = VarUniq(st.nstr);
3286 st.cp = p + 1; 3285 st.cp = p + 1;
3287 st.termc = *st.cp; 3286 st.termc = *st.cp;
3288 break; 3287 break;
3289 } 3288 }
3290 goto default_case; 3289 goto default_case;
3291#ifdef SUNSHCMD 3290#ifdef SUNSHCMD
3292 case 's': 3291 case 's':
3293 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { 3292 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) {
3294 const char *emsg; 3293 const char *emsg;
3295 if (st.eflags & VARE_WANTRES) { 3294 if (st.eflags & VARE_WANTRES) {
3296 st.newStr = Cmd_Exec(st.nstr, &emsg); 3295 st.newStr = Cmd_Exec(st.nstr, &emsg);
3297 if (emsg) 3296 if (emsg)
3298 Error(emsg, st.nstr); 3297 Error(emsg, st.nstr);
3299 } else 3298 } else
3300 st.newStr = varNoError; 3299 st.newStr = varNoError;
3301 st.cp = p + 2; 3300 st.cp = p + 2;
3302 st.termc = *st.cp; 3301 st.termc = *st.cp;
3303 break; 3302 break;
3304 } 3303 }
3305 goto default_case; 3304 goto default_case;
3306#endif 3305#endif
3307 default: 3306 default:
3308 default_case: 3307 default_case:
3309 { 3308 {
3310#ifdef SYSVVARSUB 3309#ifdef SYSVVARSUB
3311 int res = ApplyModifier_SysV(p, &st); 3310 int res = ApplyModifier_SysV(p, &st);
3312 if (res == 'c') 3311 if (res == 'c')
3313 goto cleanup; 3312 goto cleanup;
3314 if (res != '=') 3313 if (res != '=')
3315#endif 3314#endif
3316 { 3315 {
3317 Error("Unknown modifier '%c'", *p); 3316 Error("Unknown modifier '%c'", *p);
3318 for (st.cp = p + 1; 3317 for (st.cp = p + 1;
3319 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; 3318 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3320 st.cp++) 3319 st.cp++)
3321 continue; 3320 continue;
3322 st.termc = *st.cp; 3321 st.termc = *st.cp;
3323 st.newStr = var_Error; 3322 st.newStr = var_Error;
3324 } 3323 }
3325 } 3324 }
3326 } 3325 }
3327 if (DEBUG(VAR)) { 3326 if (DEBUG(VAR)) {
3328 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", 3327 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3329 st.v->name, modifier, st.newStr); 3328 st.v->name, modifier, st.newStr);
3330 } 3329 }
3331 3330
3332 if (st.newStr != st.nstr) { 3331 if (st.newStr != st.nstr) {
3333 if (*st.freePtr) { 3332 if (*st.freePtr) {
3334 free(st.nstr); 3333 free(st.nstr);
3335 *st.freePtr = NULL; 3334 *st.freePtr = NULL;
3336 } 3335 }
3337 st.nstr = st.newStr; 3336 st.nstr = st.newStr;
3338 if (st.nstr != var_Error && st.nstr != varNoError) { 3337 if (st.nstr != var_Error && st.nstr != varNoError) {
3339 *st.freePtr = st.nstr; 3338 *st.freePtr = st.nstr;
3340 } 3339 }
3341 } 3340 }
3342 if (st.termc == '\0' && st.endc != '\0') { 3341 if (st.termc == '\0' && st.endc != '\0') {
3343 Error("Unclosed variable specification (expecting '%c') " 3342 Error("Unclosed variable specification (expecting '%c') "
3344 "for \"%s\" (value \"%s\") modifier %c", 3343 "for \"%s\" (value \"%s\") modifier %c",
3345 st.endc, st.v->name, st.nstr, modifier); 3344 st.endc, st.v->name, st.nstr, modifier);
3346 } else if (st.termc == ':') { 3345 } else if (st.termc == ':') {
3347 st.cp++; 3346 st.cp++;
3348 } 3347 }
3349 p = st.cp; 3348 p = st.cp;
3350 } 3349 }
3351out: 3350out:
3352 *st.lengthPtr = p - st.start; 3351 *st.lengthPtr = p - st.start;
3353 return st.nstr; 3352 return st.nstr;
3354 3353
3355bad_modifier: 3354bad_modifier:
3356 Error("Bad modifier `:%.*s' for %s", 3355 Error("Bad modifier `:%.*s' for %s",
3357 (int)strcspn(p, ":)}"), p, st.v->name); 3356 (int)strcspn(p, ":)}"), p, st.v->name);
3358 3357
3359cleanup: 3358cleanup:
3360 *st.lengthPtr = st.cp - st.start; 3359 *st.lengthPtr = st.cp - st.start;
3361 if (st.missing_delim != '\0') 3360 if (st.missing_delim != '\0')
3362 Error("Unclosed substitution for %s (%c missing)", 3361 Error("Unclosed substitution for %s (%c missing)",
3363 st.v->name, st.missing_delim); 3362 st.v->name, st.missing_delim);
3364 free(*st.freePtr); 3363 free(*st.freePtr);
3365 *st.freePtr = NULL; 3364 *st.freePtr = NULL;
3366 return var_Error; 3365 return var_Error;
3367} 3366}
3368 3367
3369static Boolean 3368static Boolean
3370VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) 3369VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen)
3371{ 3370{
3372 if ((namelen == 1 || 3371 if ((namelen == 1 ||
3373 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && 3372 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) &&
3374 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3373 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3375 { 3374 {
3376 /* 3375 /*
3377 * If substituting a local variable in a non-local context, 3376 * If substituting a local variable in a non-local context,
3378 * assume it's for dynamic source stuff. We have to handle 3377 * assume it's for dynamic source stuff. We have to handle
3379 * this specially and return the longhand for the variable 3378 * this specially and return the longhand for the variable
3380 * with the dollar sign escaped so it makes it back to the 3379 * with the dollar sign escaped so it makes it back to the
3381 * caller. Only four of the local variables are treated 3380 * caller. Only four of the local variables are treated
3382 * specially as they are the only four that will be set 3381 * specially as they are the only four that will be set
3383 * when dynamic sources are expanded. 3382 * when dynamic sources are expanded.
3384 */ 3383 */
3385 switch (varname[0]) { 3384 switch (varname[0]) {
3386 case '@': 3385 case '@':
3387 case '%': 3386 case '%':
3388 case '*': 3387 case '*':
3389 case '!': 3388 case '!':
3390 return TRUE; 3389 return TRUE;
3391 } 3390 }
3392 return FALSE; 3391 return FALSE;
3393 } 3392 }
3394 3393
3395 if ((namelen == 7 || namelen == 8) && varname[0] == '.' && 3394 if ((namelen == 7 || namelen == 8) && varname[0] == '.' &&
3396 isupper((unsigned char) varname[1]) && 3395 isupper((unsigned char) varname[1]) &&
3397 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3396 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3398 { 3397 {
3399 return strcmp(varname, ".TARGET") == 0 || 3398 return strcmp(varname, ".TARGET") == 0 ||
3400 strcmp(varname, ".ARCHIVE") == 0 || 3399 strcmp(varname, ".ARCHIVE") == 0 ||
3401 strcmp(varname, ".PREFIX") == 0 || 3400 strcmp(varname, ".PREFIX") == 0 ||
3402 strcmp(varname, ".MEMBER") == 0; 3401 strcmp(varname, ".MEMBER") == 0;
3403 } 3402 }
3404 3403
3405 return FALSE; 3404 return FALSE;
3406} 3405}
3407 3406
3408/*- 3407/*-
3409 *----------------------------------------------------------------------- 3408 *-----------------------------------------------------------------------
3410 * Var_Parse -- 3409 * Var_Parse --
3411 * Given the start of a variable invocation (such as $v, $(VAR), 3410 * Given the start of a variable invocation (such as $v, $(VAR),
3412 * ${VAR:Mpattern}), extract the variable name, possibly some 3411 * ${VAR:Mpattern}), extract the variable name, possibly some
3413 * modifiers and find its value by applying the modifiers to the 3412 * modifiers and find its value by applying the modifiers to the
3414 * original value. 3413 * original value.
3415 * 3414 *
3416 * Input: 3415 * Input:
3417 * str The string to parse 3416 * str The string to parse
3418 * ctxt The context for the variable 3417 * ctxt The context for the variable
3419 * flags VARE_UNDEFERR if undefineds are an error 3418 * flags VARE_UNDEFERR if undefineds are an error
3420 * VARE_WANTRES if we actually want the result 3419 * VARE_WANTRES if we actually want the result
3421 * VARE_ASSIGN if we are in a := assignment 3420 * VARE_ASSIGN if we are in a := assignment
3422 * lengthPtr OUT: The length of the specification 3421 * lengthPtr OUT: The length of the specification
3423 * freePtr OUT: Non-NULL if caller should free *freePtr 3422 * freePtr OUT: Non-NULL if caller should free *freePtr
3424 * 3423 *
3425 * Results: 3424 * Results:
3426 * The (possibly-modified) value of the variable or var_Error if the 3425 * The (possibly-modified) value of the variable or var_Error if the
3427 * specification is invalid. The length of the specification is 3426 * specification is invalid. The length of the specification is
3428 * placed in *lengthPtr (for invalid specifications, this is just 3427 * placed in *lengthPtr (for invalid specifications, this is just
3429 * 2...?). 3428 * 2...?).
3430 * If *freePtr is non-NULL then it's a pointer that the caller 3429 * If *freePtr is non-NULL then it's a pointer that the caller
3431 * should pass to free() to free memory used by the result. 3430 * should pass to free() to free memory used by the result.
3432 * 3431 *
3433 * Side Effects: 3432 * Side Effects:
3434 * None. 3433 * None.
3435 * 3434 *
3436 *----------------------------------------------------------------------- 3435 *-----------------------------------------------------------------------
3437 */ 3436 */
3438/* coverity[+alloc : arg-*4] */ 3437/* coverity[+alloc : arg-*4] */
3439const char * 3438const char *
3440Var_Parse(const char * const str, GNode *ctxt, VarEvalFlags eflags, 3439Var_Parse(const char * const str, GNode *ctxt, VarEvalFlags eflags,
3441 int *lengthPtr, void **freePtr) 3440 int *lengthPtr, void **freePtr)
3442{ 3441{
3443 const char *tstr; /* Pointer into str */ 3442 const char *tstr; /* Pointer into str */
3444 Var *v; /* Variable in invocation */ 3443 Var *v; /* Variable in invocation */
3445 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3444 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3446 char endc; /* Ending character when variable in parens 3445 char endc; /* Ending character when variable in parens
3447 * or braces */ 3446 * or braces */
3448 char startc; /* Starting character when variable in parens 3447 char startc; /* Starting character when variable in parens
3449 * or braces */ 3448 * or braces */
3450 char *nstr; /* New string, used during expansion */ 3449 char *nstr; /* New string, used during expansion */
3451 Boolean dynamic; /* TRUE if the variable is local and we're 3450 Boolean dynamic; /* TRUE if the variable is local and we're
3452 * expanding it in a non-local context. This 3451 * expanding it in a non-local context. This
3453 * is done to support dynamic sources. The 3452 * is done to support dynamic sources. The
3454 * result is just the invocation, unaltered */ 3453 * result is just the invocation, unaltered */
3455 const char *extramodifiers; /* extra modifiers to apply first */ 3454 const char *extramodifiers; /* extra modifiers to apply first */
3456 3455
3457 *freePtr = NULL; 3456 *freePtr = NULL;
3458 extramodifiers = NULL; 3457 extramodifiers = NULL;
3459 dynamic = FALSE; 3458 dynamic = FALSE;
3460 3459
3461 startc = str[1]; 3460 startc = str[1];
3462 if (startc != PROPEN && startc != BROPEN) { 3461 if (startc != PROPEN && startc != BROPEN) {
3463 /* 3462 /*
3464 * If it's not bounded by braces of some sort, life is much simpler. 3463 * If it's not bounded by braces of some sort, life is much simpler.
3465 * We just need to check for the first character and return the 3464 * We just need to check for the first character and return the
3466 * value if it exists. 3465 * value if it exists.
3467 */ 3466 */
3468 3467
3469 /* Error out some really stupid names */ 3468 /* Error out some really stupid names */
3470 if (startc == '\0' || strchr(")}:$", startc)) { 3469 if (startc == '\0' || strchr(")}:$", startc)) {
3471 *lengthPtr = 1; 3470 *lengthPtr = 1;
3472 return var_Error; 3471 return var_Error;
3473 } 3472 }
3474 char name[] = { startc, '\0' }; 3473 char name[] = { startc, '\0' };
3475 3474
3476 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3475 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3477 if (v == NULL) { 3476 if (v == NULL) {
3478 *lengthPtr = 2; 3477 *lengthPtr = 2;
3479 3478
3480 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 3479 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3481 /* 3480 /*
3482 * If substituting a local variable in a non-local context, 3481 * If substituting a local variable in a non-local context,
3483 * assume it's for dynamic source stuff. We have to handle 3482 * assume it's for dynamic source stuff. We have to handle
3484 * this specially and return the longhand for the variable 3483 * this specially and return the longhand for the variable
3485 * with the dollar sign escaped so it makes it back to the 3484 * with the dollar sign escaped so it makes it back to the
3486 * caller. Only four of the local variables are treated 3485 * caller. Only four of the local variables are treated
3487 * specially as they are the only four that will be set 3486 * specially as they are the only four that will be set
3488 * when dynamic sources are expanded. 3487 * when dynamic sources are expanded.
3489 */ 3488 */
3490 switch (str[1]) { 3489 switch (str[1]) {
3491 case '@': 3490 case '@':
3492 return "$(.TARGET)"; 3491 return "$(.TARGET)";
3493 case '%': 3492 case '%':
3494 return "$(.MEMBER)"; 3493 return "$(.MEMBER)";
3495 case '*': 3494 case '*':
3496 return "$(.PREFIX)"; 3495 return "$(.PREFIX)";
3497 case '!': 3496 case '!':
3498 return "$(.ARCHIVE)"; 3497 return "$(.ARCHIVE)";
3499 } 3498 }
3500 } 3499 }
3501 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError; 3500 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError;
3502 } else { 3501 } else {
3503 haveModifier = FALSE; 3502 haveModifier = FALSE;
3504 tstr = str + 1; 3503 tstr = str + 1;
3505 endc = str[1]; 3504 endc = str[1];
3506 } 3505 }
3507 } else { 3506 } else {
3508 Buffer namebuf; /* Holds the variable name */ 3507 Buffer namebuf; /* Holds the variable name */
3509 int depth = 1; 3508 int depth = 1;
3510 3509
3511 endc = startc == PROPEN ? PRCLOSE : BRCLOSE; 3510 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3512 Buf_Init(&namebuf, 0); 3511 Buf_Init(&namebuf, 0);