Mon Jul 27 23:24:55 2020 UTC ()
make(1): rename ApplyModifiersState.cp to next

The name "next" is more descriptive than a mere "cp".  It's easy to look
up the type of the variable, but not so easy to guess the purpose of the
variable, therefore the new name concentrates on the purpose.


(rillig)
diff -r1.347 -r1.348 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/07/27 23:04:18 1.347
+++ src/usr.bin/make/var.c 2020/07/27 23:24:55 1.348
@@ -1,3916 +1,3917 @@ @@ -1,3916 +1,3917 @@
1/* $NetBSD: var.c,v 1.347 2020/07/27 23:04:18 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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.347 2020/07/27 23:04:18 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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.347 2020/07/27 23:04:18 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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
1079SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1079SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1080{ 1080{
1081 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1081 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1082} 1082}
1083 1083
1084static void 1084static void
1085SepBuf_AddStr(SepBuf *buf, const char *str) 1085SepBuf_AddStr(SepBuf *buf, const char *str)
1086{ 1086{
1087 SepBuf_AddBytes(buf, str, strlen(str)); 1087 SepBuf_AddBytes(buf, str, strlen(str));
1088} 1088}
1089 1089
1090static char * 1090static char *
1091SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1091SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1092{ 1092{
1093 return Buf_Destroy(&buf->buf, free_buf); 1093 return Buf_Destroy(&buf->buf, free_buf);
1094} 1094}
1095 1095
1096 1096
1097/* This callback for ModifyWords gets a single word from an expression and 1097/* This callback for ModifyWords gets a single word from an expression and
1098 * typically adds a modification of this word to the buffer. It may also do 1098 * typically adds a modification of this word to the buffer. It may also do
1099 * nothing or add several words. */ 1099 * nothing or add several words. */
1100typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1100typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1101 1101
1102 1102
1103/* Callback for ModifyWords to implement the :H modifier. 1103/* Callback for ModifyWords to implement the :H modifier.
1104 * Add the dirname of the given word to the buffer. */ 1104 * Add the dirname of the given word to the buffer. */
1105static void 1105static void
1106ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1106ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1107{ 1107{
1108 const char *slash = strrchr(word, '/'); 1108 const char *slash = strrchr(word, '/');
1109 if (slash != NULL) 1109 if (slash != NULL)
1110 SepBuf_AddBytesBetween(buf, word, slash); 1110 SepBuf_AddBytesBetween(buf, word, slash);
1111 else 1111 else
1112 SepBuf_AddStr(buf, "."); 1112 SepBuf_AddStr(buf, ".");
1113} 1113}
1114 1114
1115/* Callback for ModifyWords to implement the :T modifier. 1115/* Callback for ModifyWords to implement the :T modifier.
1116 * Add the basename of the given word to the buffer. */ 1116 * Add the basename of the given word to the buffer. */
1117static void 1117static void
1118ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1118ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1119{ 1119{
1120 const char *slash = strrchr(word, '/'); 1120 const char *slash = strrchr(word, '/');
1121 const char *base = slash != NULL ? slash + 1 : word; 1121 const char *base = slash != NULL ? slash + 1 : word;
1122 SepBuf_AddStr(buf, base); 1122 SepBuf_AddStr(buf, base);
1123} 1123}
1124 1124
1125/* Callback for ModifyWords to implement the :E modifier. 1125/* Callback for ModifyWords to implement the :E modifier.
1126 * Add the filename suffix of the given word to the buffer, if it exists. */ 1126 * Add the filename suffix of the given word to the buffer, if it exists. */
1127static void 1127static void
1128ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1128ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1129{ 1129{
1130 const char *dot = strrchr(word, '.'); 1130 const char *dot = strrchr(word, '.');
1131 if (dot != NULL) 1131 if (dot != NULL)
1132 SepBuf_AddStr(buf, dot + 1); 1132 SepBuf_AddStr(buf, dot + 1);
1133} 1133}
1134 1134
1135/* Callback for ModifyWords to implement the :R modifier. 1135/* Callback for ModifyWords to implement the :R modifier.
1136 * Add the basename of the given word to the buffer. */ 1136 * Add the basename of the given word to the buffer. */
1137static void 1137static void
1138ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1138ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1139{ 1139{
1140 const char *dot = strrchr(word, '.'); 1140 const char *dot = strrchr(word, '.');
1141 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1141 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1142 SepBuf_AddBytes(buf, word, len); 1142 SepBuf_AddBytes(buf, word, len);
1143} 1143}
1144 1144
1145/* Callback for ModifyWords to implement the :M modifier. 1145/* Callback for ModifyWords to implement the :M modifier.
1146 * Place the word in the buffer if it matches the given pattern. */ 1146 * Place the word in the buffer if it matches the given pattern. */
1147static void 1147static void
1148ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1148ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1149{ 1149{
1150 const char *pattern = data; 1150 const char *pattern = data;
1151 if (DEBUG(VAR)) 1151 if (DEBUG(VAR))
1152 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern); 1152 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
1153 if (Str_Match(word, pattern)) 1153 if (Str_Match(word, pattern))
1154 SepBuf_AddStr(buf, word); 1154 SepBuf_AddStr(buf, word);
1155} 1155}
1156 1156
1157/* Callback for ModifyWords to implement the :N modifier. 1157/* Callback for ModifyWords to implement the :N modifier.
1158 * Place the word in the buffer if it doesn't match the given pattern. */ 1158 * Place the word in the buffer if it doesn't match the given pattern. */
1159static void 1159static void
1160ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1160ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1161{ 1161{
1162 const char *pattern = data; 1162 const char *pattern = data;
1163 if (!Str_Match(word, pattern)) 1163 if (!Str_Match(word, pattern))
1164 SepBuf_AddStr(buf, word); 1164 SepBuf_AddStr(buf, word);
1165} 1165}
1166 1166
1167#ifdef SYSVVARSUB 1167#ifdef SYSVVARSUB
1168/*- 1168/*-
1169 *----------------------------------------------------------------------- 1169 *-----------------------------------------------------------------------
1170 * Str_SYSVMatch -- 1170 * Str_SYSVMatch --
1171 * Check word against pattern for a match (% is wild), 1171 * Check word against pattern for a match (% is wild),
1172 * 1172 *
1173 * Input: 1173 * Input:
1174 * word Word to examine 1174 * word Word to examine
1175 * pattern Pattern to examine against 1175 * pattern Pattern to examine against
1176 * len Number of characters to substitute 1176 * len Number of characters to substitute
1177 * 1177 *
1178 * Results: 1178 * Results:
1179 * Returns the beginning position of a match or null. The number 1179 * Returns the beginning position of a match or null. The number
1180 * of characters matched is returned in len. 1180 * of characters matched is returned in len.
1181 *----------------------------------------------------------------------- 1181 *-----------------------------------------------------------------------
1182 */ 1182 */
1183static const char * 1183static const char *
1184Str_SYSVMatch(const char *word, const char *pattern, size_t *len, 1184Str_SYSVMatch(const char *word, const char *pattern, size_t *len,
1185 Boolean *hasPercent) 1185 Boolean *hasPercent)
1186{ 1186{
1187 const char *p = pattern; 1187 const char *p = pattern;
1188 const char *w = word; 1188 const char *w = word;
1189 const char *m; 1189 const char *m;
1190 1190
1191 *hasPercent = FALSE; 1191 *hasPercent = FALSE;
1192 if (*p == '\0') { 1192 if (*p == '\0') {
1193 /* Null pattern is the whole string */ 1193 /* Null pattern is the whole string */
1194 *len = strlen(w); 1194 *len = strlen(w);
1195 return w; 1195 return w;
1196 } 1196 }
1197 1197
1198 if ((m = strchr(p, '%')) != NULL) { 1198 if ((m = strchr(p, '%')) != NULL) {
1199 *hasPercent = TRUE; 1199 *hasPercent = TRUE;
1200 if (*w == '\0') { 1200 if (*w == '\0') {
1201 /* empty word does not match pattern */ 1201 /* empty word does not match pattern */
1202 return NULL; 1202 return NULL;
1203 } 1203 }
1204 /* check that the prefix matches */ 1204 /* check that the prefix matches */
1205 for (; p != m && *w && *w == *p; w++, p++) 1205 for (; p != m && *w && *w == *p; w++, p++)
1206 continue; 1206 continue;
1207 1207
1208 if (p != m) 1208 if (p != m)
1209 return NULL; /* No match */ 1209 return NULL; /* No match */
1210 1210
1211 if (*++p == '\0') { 1211 if (*++p == '\0') {
1212 /* No more pattern, return the rest of the string */ 1212 /* No more pattern, return the rest of the string */
1213 *len = strlen(w); 1213 *len = strlen(w);
1214 return w; 1214 return w;
1215 } 1215 }
1216 } 1216 }
1217 1217
1218 m = w; 1218 m = w;
1219 1219
1220 /* Find a matching tail */ 1220 /* Find a matching tail */
1221 do { 1221 do {
1222 if (strcmp(p, w) == 0) { 1222 if (strcmp(p, w) == 0) {
1223 *len = w - m; 1223 *len = w - m;
1224 return m; 1224 return m;
1225 } 1225 }
1226 } while (*w++ != '\0'); 1226 } while (*w++ != '\0');
1227 1227
1228 return NULL; 1228 return NULL;
1229} 1229}
1230 1230
1231 1231
1232/*- 1232/*-
1233 *----------------------------------------------------------------------- 1233 *-----------------------------------------------------------------------
1234 * Str_SYSVSubst -- 1234 * Str_SYSVSubst --
1235 * Substitute '%' on the pattern with len characters from src. 1235 * Substitute '%' on the pattern with len characters from src.
1236 * If the pattern does not contain a '%' prepend len characters 1236 * If the pattern does not contain a '%' prepend len characters
1237 * from src. 1237 * from src.
1238 * 1238 *
1239 * Side Effects: 1239 * Side Effects:
1240 * Places result on buf 1240 * Places result on buf
1241 *----------------------------------------------------------------------- 1241 *-----------------------------------------------------------------------
1242 */ 1242 */
1243static void 1243static void
1244Str_SYSVSubst(SepBuf *buf, const char *pat, const char *src, size_t len, 1244Str_SYSVSubst(SepBuf *buf, const char *pat, const char *src, size_t len,
1245 Boolean lhsHasPercent) 1245 Boolean lhsHasPercent)
1246{ 1246{
1247 const char *m; 1247 const char *m;
1248 1248
1249 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) { 1249 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) {
1250 /* Copy the prefix */ 1250 /* Copy the prefix */
1251 SepBuf_AddBytesBetween(buf, pat, m); 1251 SepBuf_AddBytesBetween(buf, pat, m);
1252 /* skip the % */ 1252 /* skip the % */
1253 pat = m + 1; 1253 pat = m + 1;
1254 } 1254 }
1255 if (m != NULL || !lhsHasPercent) { 1255 if (m != NULL || !lhsHasPercent) {
1256 /* Copy the pattern */ 1256 /* Copy the pattern */
1257 SepBuf_AddBytes(buf, src, len); 1257 SepBuf_AddBytes(buf, src, len);
1258 } 1258 }
1259 1259
1260 /* append the rest */ 1260 /* append the rest */
1261 SepBuf_AddStr(buf, pat); 1261 SepBuf_AddStr(buf, pat);
1262} 1262}
1263 1263
1264 1264
1265typedef struct { 1265typedef struct {
1266 GNode *ctx; 1266 GNode *ctx;
1267 const char *lhs; 1267 const char *lhs;
1268 const char *rhs; 1268 const char *rhs;
1269} ModifyWord_SYSVSubstArgs; 1269} ModifyWord_SYSVSubstArgs;
1270 1270
1271/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1271/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1272static void 1272static void
1273ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1273ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1274{ 1274{
1275 const ModifyWord_SYSVSubstArgs *args = data; 1275 const ModifyWord_SYSVSubstArgs *args = data;
1276 1276
1277 size_t len; 1277 size_t len;
1278 Boolean hasPercent; 1278 Boolean hasPercent;
1279 const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent); 1279 const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent);
1280 if (ptr != NULL) { 1280 if (ptr != NULL) {
1281 char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES); 1281 char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES);
1282 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent); 1282 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1283 free(varexp); 1283 free(varexp);
1284 } else { 1284 } else {
1285 SepBuf_AddStr(buf, word); 1285 SepBuf_AddStr(buf, word);
1286 } 1286 }
1287} 1287}
1288#endif 1288#endif
1289 1289
1290 1290
1291typedef struct { 1291typedef struct {
1292 const char *lhs; 1292 const char *lhs;
1293 size_t lhsLen; 1293 size_t lhsLen;
1294 const char *rhs; 1294 const char *rhs;
1295 size_t rhsLen; 1295 size_t rhsLen;
1296 VarPatternFlags pflags; 1296 VarPatternFlags pflags;
1297} ModifyWord_SubstArgs; 1297} ModifyWord_SubstArgs;
1298 1298
1299/* Callback for ModifyWords to implement the :S,from,to, modifier. 1299/* Callback for ModifyWords to implement the :S,from,to, modifier.
1300 * Perform a string substitution on the given word. */ 1300 * Perform a string substitution on the given word. */
1301static void 1301static void
1302ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1302ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1303{ 1303{
1304 size_t wordLen = strlen(word); 1304 size_t wordLen = strlen(word);
1305 ModifyWord_SubstArgs *args = data; 1305 ModifyWord_SubstArgs *args = data;
1306 const VarPatternFlags pflags = args->pflags; 1306 const VarPatternFlags pflags = args->pflags;
1307 1307
1308 if ((pflags & VARP_SUB_ONE) && (pflags & VARP_SUB_MATCHED)) 1308 if ((pflags & VARP_SUB_ONE) && (pflags & VARP_SUB_MATCHED))
1309 goto nosub; 1309 goto nosub;
1310 1310
1311 if (args->pflags & VARP_ANCHOR_START) { 1311 if (args->pflags & VARP_ANCHOR_START) {
1312 if (wordLen < args->lhsLen || 1312 if (wordLen < args->lhsLen ||
1313 memcmp(word, args->lhs, args->lhsLen) != 0) 1313 memcmp(word, args->lhs, args->lhsLen) != 0)
1314 goto nosub; 1314 goto nosub;
1315 1315
1316 if (args->pflags & VARP_ANCHOR_END) { 1316 if (args->pflags & VARP_ANCHOR_END) {
1317 if (wordLen != args->lhsLen) 1317 if (wordLen != args->lhsLen)
1318 goto nosub; 1318 goto nosub;
1319 1319
1320 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1320 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1321 args->pflags |= VARP_SUB_MATCHED; 1321 args->pflags |= VARP_SUB_MATCHED;
1322 } else { 1322 } else {
1323 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1323 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1324 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1324 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1325 args->pflags |= VARP_SUB_MATCHED; 1325 args->pflags |= VARP_SUB_MATCHED;
1326 } 1326 }
1327 return; 1327 return;
1328 } 1328 }
1329 1329
1330 if (args->pflags & VARP_ANCHOR_END) { 1330 if (args->pflags & VARP_ANCHOR_END) {
1331 if (wordLen < args->lhsLen) 1331 if (wordLen < args->lhsLen)
1332 goto nosub; 1332 goto nosub;
1333 1333
1334 const char *start = word + (wordLen - args->lhsLen); 1334 const char *start = word + (wordLen - args->lhsLen);
1335 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1335 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1336 goto nosub; 1336 goto nosub;
1337 1337
1338 SepBuf_AddBytesBetween(buf, word, start); 1338 SepBuf_AddBytesBetween(buf, word, start);
1339 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1339 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1340 args->pflags |= VARP_SUB_MATCHED; 1340 args->pflags |= VARP_SUB_MATCHED;
1341 return; 1341 return;
1342 } 1342 }
1343 1343
1344 /* unanchored */ 1344 /* unanchored */
1345 const char *match; 1345 const char *match;
1346 while ((match = Str_FindSubstring(word, args->lhs)) != NULL) { 1346 while ((match = Str_FindSubstring(word, args->lhs)) != NULL) {
1347 SepBuf_AddBytesBetween(buf, word, match); 1347 SepBuf_AddBytesBetween(buf, word, match);
1348 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1348 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1349 args->pflags |= VARP_SUB_MATCHED; 1349 args->pflags |= VARP_SUB_MATCHED;
1350 wordLen -= (match - word) + args->lhsLen; 1350 wordLen -= (match - word) + args->lhsLen;
1351 word += (match - word) + args->lhsLen; 1351 word += (match - word) + args->lhsLen;
1352 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1352 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1353 break; 1353 break;
1354 } 1354 }
1355nosub: 1355nosub:
1356 SepBuf_AddBytes(buf, word, wordLen); 1356 SepBuf_AddBytes(buf, word, wordLen);
1357} 1357}
1358 1358
1359#ifndef NO_REGEX 1359#ifndef NO_REGEX
1360/*- 1360/*-
1361 *----------------------------------------------------------------------- 1361 *-----------------------------------------------------------------------
1362 * VarREError -- 1362 * VarREError --
1363 * Print the error caused by a regcomp or regexec call. 1363 * Print the error caused by a regcomp or regexec call.
1364 * 1364 *
1365 * Side Effects: 1365 * Side Effects:
1366 * An error gets printed. 1366 * An error gets printed.
1367 * 1367 *
1368 *----------------------------------------------------------------------- 1368 *-----------------------------------------------------------------------
1369 */ 1369 */
1370static void 1370static void
1371VarREError(int reerr, regex_t *pat, const char *str) 1371VarREError(int reerr, regex_t *pat, const char *str)
1372{ 1372{
1373 char *errbuf; 1373 char *errbuf;
1374 int errlen; 1374 int errlen;
1375 1375
1376 errlen = regerror(reerr, pat, 0, 0); 1376 errlen = regerror(reerr, pat, 0, 0);
1377 errbuf = bmake_malloc(errlen); 1377 errbuf = bmake_malloc(errlen);
1378 regerror(reerr, pat, errbuf, errlen); 1378 regerror(reerr, pat, errbuf, errlen);
1379 Error("%s: %s", str, errbuf); 1379 Error("%s: %s", str, errbuf);
1380 free(errbuf); 1380 free(errbuf);
1381} 1381}
1382 1382
1383typedef struct { 1383typedef struct {
1384 regex_t re; 1384 regex_t re;
1385 int nsub; 1385 int nsub;
1386 char *replace; 1386 char *replace;
1387 VarPatternFlags pflags; 1387 VarPatternFlags pflags;
1388} ModifyWord_SubstRegexArgs; 1388} ModifyWord_SubstRegexArgs;
1389 1389
1390/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1390/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1391 * Perform a regex substitution on the given word. */ 1391 * Perform a regex substitution on the given word. */
1392static void 1392static void
1393ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1393ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1394{ 1394{
1395 ModifyWord_SubstRegexArgs *args = data; 1395 ModifyWord_SubstRegexArgs *args = data;
1396 int xrv; 1396 int xrv;
1397 const char *wp = word; 1397 const char *wp = word;
1398 char *rp; 1398 char *rp;
1399 int flags = 0; 1399 int flags = 0;
1400 regmatch_t m[10]; 1400 regmatch_t m[10];
1401 1401
1402 if ((args->pflags & VARP_SUB_ONE) && (args->pflags & VARP_SUB_MATCHED)) 1402 if ((args->pflags & VARP_SUB_ONE) && (args->pflags & VARP_SUB_MATCHED))
1403 goto nosub; 1403 goto nosub;
1404 1404
1405tryagain: 1405tryagain:
1406 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1406 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1407 1407
1408 switch (xrv) { 1408 switch (xrv) {
1409 case 0: 1409 case 0:
1410 args->pflags |= VARP_SUB_MATCHED; 1410 args->pflags |= VARP_SUB_MATCHED;
1411 SepBuf_AddBytes(buf, wp, m[0].rm_so); 1411 SepBuf_AddBytes(buf, wp, m[0].rm_so);
1412 1412
1413 for (rp = args->replace; *rp; rp++) { 1413 for (rp = args->replace; *rp; rp++) {
1414 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1414 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1415 SepBuf_AddBytes(buf, rp + 1, 1); 1415 SepBuf_AddBytes(buf, rp + 1, 1);
1416 rp++; 1416 rp++;
1417 } else if (*rp == '&' || 1417 } else if (*rp == '&' ||
1418 (*rp == '\\' && isdigit((unsigned char)rp[1]))) { 1418 (*rp == '\\' && isdigit((unsigned char)rp[1]))) {
1419 int n; 1419 int n;
1420 char errstr[3]; 1420 char errstr[3];
1421 1421
1422 if (*rp == '&') { 1422 if (*rp == '&') {
1423 n = 0; 1423 n = 0;
1424 errstr[0] = '&'; 1424 errstr[0] = '&';
1425 errstr[1] = '\0'; 1425 errstr[1] = '\0';
1426 } else { 1426 } else {
1427 n = rp[1] - '0'; 1427 n = rp[1] - '0';
1428 errstr[0] = '\\'; 1428 errstr[0] = '\\';
1429 errstr[1] = rp[1]; 1429 errstr[1] = rp[1];
1430 errstr[2] = '\0'; 1430 errstr[2] = '\0';
1431 rp++; 1431 rp++;
1432 } 1432 }
1433 1433
1434 if (n >= args->nsub) { 1434 if (n >= args->nsub) {
1435 Error("No subexpression %s", errstr); 1435 Error("No subexpression %s", errstr);
1436 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1436 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1437 Error("No match for subexpression %s", errstr); 1437 Error("No match for subexpression %s", errstr);
1438 } else { 1438 } else {
1439 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1439 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1440 wp + m[n].rm_eo); 1440 wp + m[n].rm_eo);
1441 } 1441 }
1442 1442
1443 } else { 1443 } else {
1444 SepBuf_AddBytes(buf, rp, 1); 1444 SepBuf_AddBytes(buf, rp, 1);
1445 } 1445 }
1446 } 1446 }
1447 wp += m[0].rm_eo; 1447 wp += m[0].rm_eo;
1448 if (args->pflags & VARP_SUB_GLOBAL) { 1448 if (args->pflags & VARP_SUB_GLOBAL) {
1449 flags |= REG_NOTBOL; 1449 flags |= REG_NOTBOL;
1450 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1450 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1451 SepBuf_AddBytes(buf, wp, 1); 1451 SepBuf_AddBytes(buf, wp, 1);
1452 wp++; 1452 wp++;
1453 } 1453 }
1454 if (*wp) 1454 if (*wp)
1455 goto tryagain; 1455 goto tryagain;
1456 } 1456 }
1457 if (*wp) { 1457 if (*wp) {
1458 SepBuf_AddStr(buf, wp); 1458 SepBuf_AddStr(buf, wp);
1459 } 1459 }
1460 break; 1460 break;
1461 default: 1461 default:
1462 VarREError(xrv, &args->re, "Unexpected regex error"); 1462 VarREError(xrv, &args->re, "Unexpected regex error");
1463 /* fall through */ 1463 /* fall through */
1464 case REG_NOMATCH: 1464 case REG_NOMATCH:
1465 nosub: 1465 nosub:
1466 SepBuf_AddStr(buf, wp); 1466 SepBuf_AddStr(buf, wp);
1467 break; 1467 break;
1468 } 1468 }
1469} 1469}
1470#endif 1470#endif
1471 1471
1472 1472
1473typedef struct { 1473typedef struct {
1474 GNode *ctx; 1474 GNode *ctx;
1475 char *tvar; /* name of temporary variable */ 1475 char *tvar; /* name of temporary variable */
1476 char *str; /* string to expand */ 1476 char *str; /* string to expand */
1477 VarEvalFlags eflags; 1477 VarEvalFlags eflags;
1478} ModifyWord_LoopArgs; 1478} ModifyWord_LoopArgs;
1479 1479
1480/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1480/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1481static void 1481static void
1482ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1482ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1483{ 1483{
1484 if (word[0] == '\0') 1484 if (word[0] == '\0')
1485 return; 1485 return;
1486 1486
1487 const ModifyWord_LoopArgs *args = data; 1487 const ModifyWord_LoopArgs *args = data;
1488 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1488 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1489 char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags); 1489 char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags);
1490 if (DEBUG(VAR)) { 1490 if (DEBUG(VAR)) {
1491 fprintf(debug_file, 1491 fprintf(debug_file,
1492 "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1492 "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1493 "to \"%s\"\n", 1493 "to \"%s\"\n",
1494 word, args->tvar, args->str, s ? s : "(null)"); 1494 word, args->tvar, args->str, s ? s : "(null)");
1495 } 1495 }
1496 1496
1497 if (s != NULL && s[0] != '\0') { 1497 if (s != NULL && s[0] != '\0') {
1498 if (s[0] == '\n' || (buf->buf.count > 0 && 1498 if (s[0] == '\n' || (buf->buf.count > 0 &&
1499 buf->buf.buffer[buf->buf.count - 1] == '\n')) 1499 buf->buf.buffer[buf->buf.count - 1] == '\n'))
1500 buf->needSep = FALSE; 1500 buf->needSep = FALSE;
1501 SepBuf_AddStr(buf, s); 1501 SepBuf_AddStr(buf, s);
1502 } 1502 }
1503 free(s); 1503 free(s);
1504} 1504}
1505 1505
1506 1506
1507/*- 1507/*-
1508 * Implements the :[first..last] modifier. 1508 * Implements the :[first..last] modifier.
1509 * This is a special case of ModifyWords since we want to be able 1509 * This is a special case of ModifyWords since we want to be able
1510 * to scan the list backwards if first > last. 1510 * to scan the list backwards if first > last.
1511 */ 1511 */
1512static char * 1512static char *
1513VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first, 1513VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first,
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 2046
2047 /* read-write */ 2047 /* read-write */
2048 char *nstr; 2048 char *nstr;
2049 const char *cp; /* The position where parsing continues 2049 const char *next; /* The position where parsing continues
2050 * after the current modifier. */ 2050 * after the current modifier. */
2051 char termc; /* Character which terminated scan */ 2051 char termc; /* Character which terminated scan */
2052 char missing_delim; /* For error reporting */ 2052 char missing_delim; /* For error reporting */
2053 2053
2054 Byte sep; /* Word separator in expansions */ 2054 Byte sep; /* Word separator in expansions */
2055 Boolean oneBigWord; /* TRUE if we will treat the variable as a 2055 Boolean oneBigWord; /* TRUE if we will treat the variable as a
2056 * single big word, even if it contains 2056 * single big word, even if it contains
2057 * embedded spaces (as opposed to the 2057 * embedded spaces (as opposed to the
2058 * usual behaviour of treating it as 2058 * usual behaviour of treating it as
2059 * several space-separated words). */ 2059 * several space-separated words). */
2060 2060
2061 /* result */ 2061 /* result */
2062 char *newStr; /* New value to return */ 2062 char *newStr; /* New value to return */
2063} ApplyModifiersState; 2063} ApplyModifiersState;
2064 2064
2065/* we now have some modifiers with long names */ 2065/* we now have some modifiers with long names */
2066static Boolean 2066static Boolean
2067ModMatch(const char *mod, const char *modname, char endc) 2067ModMatch(const char *mod, const char *modname, char endc)
2068{ 2068{
2069 size_t n = strlen(modname); 2069 size_t n = strlen(modname);
2070 return strncmp(mod, modname, n) == 0 && 2070 return strncmp(mod, modname, n) == 0 &&
2071 (mod[n] == endc || mod[n] == ':'); 2071 (mod[n] == endc || mod[n] == ':');
2072} 2072}
2073 2073
2074static inline Boolean 2074static inline Boolean
2075ModMatchEq(const char *mod, const char *modname, char endc) 2075ModMatchEq(const char *mod, const char *modname, char endc)
2076{ 2076{
2077 size_t n = strlen(modname); 2077 size_t n = strlen(modname);
2078 return strncmp(mod, modname, n) == 0 && 2078 return strncmp(mod, modname, n) == 0 &&
2079 (mod[n] == endc || mod[n] == ':' || mod[n] == '='); 2079 (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2080} 2080}
2081 2081
2082/* :@var@...${var}...@ */ 2082/* :@var@...${var}...@ */
2083static Boolean 2083static Boolean
2084ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { 2084ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) {
2085 ModifyWord_LoopArgs args; 2085 ModifyWord_LoopArgs args;
2086 2086
2087 args.ctx = st->ctxt; 2087 args.ctx = st->ctxt;
2088 st->cp = mod + 1; 2088 st->next = mod + 1;
2089 char delim = '@'; 2089 char delim = '@';
2090 args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, 2090 args.tvar = ParseModifierPart(&st->next, delim, st->eflags & ~VARE_WANTRES,
2091 st->ctxt, NULL, NULL, NULL); 2091 st->ctxt, NULL, NULL, NULL);
2092 if (args.tvar == NULL) { 2092 if (args.tvar == NULL) {
2093 st->missing_delim = delim; 2093 st->missing_delim = delim;
2094 return FALSE; 2094 return FALSE;
2095 } 2095 }
2096 2096
2097 args.str = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, 2097 args.str = ParseModifierPart(&st->next, delim, st->eflags & ~VARE_WANTRES,
2098 st->ctxt, NULL, NULL, NULL); 2098 st->ctxt, NULL, NULL, NULL);
2099 if (args.str == NULL) { 2099 if (args.str == NULL) {
2100 st->missing_delim = delim; 2100 st->missing_delim = delim;
2101 return FALSE; 2101 return FALSE;
2102 } 2102 }
2103 2103
2104 st->termc = *st->cp; 2104 st->termc = *st->next;
2105 2105
2106 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2106 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2107 int prev_sep = st->sep; 2107 int prev_sep = st->sep;
2108 st->sep = ' '; /* XXX: this is inconsistent */ 2108 st->sep = ' '; /* XXX: this is inconsistent */
2109 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2109 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2110 ModifyWord_Loop, &args); 2110 ModifyWord_Loop, &args);
2111 st->sep = prev_sep; 2111 st->sep = prev_sep;
2112 Var_Delete(args.tvar, st->ctxt); 2112 Var_Delete(args.tvar, st->ctxt);
2113 free(args.tvar); 2113 free(args.tvar);
2114 free(args.str); 2114 free(args.str);
2115 return TRUE; 2115 return TRUE;
2116} 2116}
2117 2117
2118/* :Ddefined or :Uundefined */ 2118/* :Ddefined or :Uundefined */
2119static void 2119static void
2120ApplyModifier_Defined(const char *mod, ApplyModifiersState *st) 2120ApplyModifier_Defined(const char *mod, ApplyModifiersState *st)
2121{ 2121{
2122 Buffer buf; /* Buffer for patterns */ 2122 Buffer buf; /* Buffer for patterns */
2123 VarEvalFlags neflags; 2123 VarEvalFlags neflags;
2124 2124
2125 if (st->eflags & VARE_WANTRES) { 2125 if (st->eflags & VARE_WANTRES) {
2126 Boolean wantres; 2126 Boolean wantres;
2127 if (*mod == 'U') 2127 if (*mod == 'U')
2128 wantres = ((st->v->flags & VAR_JUNK) != 0); 2128 wantres = ((st->v->flags & VAR_JUNK) != 0);
2129 else 2129 else
2130 wantres = ((st->v->flags & VAR_JUNK) == 0); 2130 wantres = ((st->v->flags & VAR_JUNK) == 0);
2131 neflags = st->eflags & ~VARE_WANTRES; 2131 neflags = st->eflags & ~VARE_WANTRES;
2132 if (wantres) 2132 if (wantres)
2133 neflags |= VARE_WANTRES; 2133 neflags |= VARE_WANTRES;
2134 } else 2134 } else
2135 neflags = st->eflags; 2135 neflags = st->eflags;
2136 2136
2137 /* 2137 /*
2138 * Pass through mod looking for 1) escaped delimiters, 2138 * Pass through mod looking for 1) escaped delimiters,
2139 * '$'s and backslashes (place the escaped character in 2139 * '$'s and backslashes (place the escaped character in
2140 * uninterpreted) and 2) unescaped $'s that aren't before 2140 * uninterpreted) and 2) unescaped $'s that aren't before
2141 * the delimiter (expand the variable substitution). 2141 * the delimiter (expand the variable substitution).
2142 * The result is left in the Buffer buf. 2142 * The result is left in the Buffer buf.
2143 */ 2143 */
2144 Buf_Init(&buf, 0); 2144 Buf_Init(&buf, 0);
2145 const char *p = mod + 1; 2145 const char *p = mod + 1;
2146 while (*p != st->endc && *p != ':' && *p != '\0') { 2146 while (*p != st->endc && *p != ':' && *p != '\0') {
2147 if (*p == '\\' && 2147 if (*p == '\\' &&
2148 (p[1] == ':' || p[1] == '$' || p[1] == st->endc || p[1] == '\\')) { 2148 (p[1] == ':' || p[1] == '$' || p[1] == st->endc || p[1] == '\\')) {
2149 Buf_AddByte(&buf, p[1]); 2149 Buf_AddByte(&buf, p[1]);
2150 p += 2; 2150 p += 2;
2151 } else if (*p == '$') { 2151 } else if (*p == '$') {
2152 /* 2152 /*
2153 * If unescaped dollar sign, assume it's a 2153 * If unescaped dollar sign, assume it's a
2154 * variable substitution and recurse. 2154 * variable substitution and recurse.
2155 */ 2155 */
2156 const char *cp2; 2156 const char *cp2;
2157 int len; 2157 int len;
2158 void *freeIt; 2158 void *freeIt;
2159 2159
2160 cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt); 2160 cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt);
2161 Buf_AddStr(&buf, cp2); 2161 Buf_AddStr(&buf, cp2);
2162 free(freeIt); 2162 free(freeIt);
2163 p += len; 2163 p += len;
2164 } else { 2164 } else {
2165 Buf_AddByte(&buf, *p); 2165 Buf_AddByte(&buf, *p);
2166 p++; 2166 p++;
2167 } 2167 }
2168 } 2168 }
2169 2169
2170 st->cp = p; 2170 st->next = p;
2171 st->termc = *st->cp; 2171 st->termc = *st->next;
2172 2172
2173 if (st->v->flags & VAR_JUNK) 2173 if (st->v->flags & VAR_JUNK)
2174 st->v->flags |= VAR_KEEP; 2174 st->v->flags |= VAR_KEEP;
2175 if (neflags & VARE_WANTRES) { 2175 if (neflags & VARE_WANTRES) {
2176 st->newStr = Buf_Destroy(&buf, FALSE); 2176 st->newStr = Buf_Destroy(&buf, FALSE);
2177 } else { 2177 } else {
2178 st->newStr = st->nstr; 2178 st->newStr = st->nstr;
2179 Buf_Destroy(&buf, TRUE); 2179 Buf_Destroy(&buf, TRUE);
2180 } 2180 }
2181} 2181}
2182 2182
2183/* :gmtime */ 2183/* :gmtime */
2184static Boolean 2184static Boolean
2185ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) 2185ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st)
2186{ 2186{
2187 if (!ModMatchEq(mod, "gmtime", st->endc)) { 2187 if (!ModMatchEq(mod, "gmtime", st->endc)) {
2188 st->cp = mod + 1; 2188 st->next = mod + 1;
2189 return FALSE; 2189 return FALSE;
2190 } 2190 }
2191 2191
2192 time_t utc; 2192 time_t utc;
2193 if (mod[6] == '=') { 2193 if (mod[6] == '=') {
2194 char *ep; 2194 char *ep;
2195 utc = strtoul(mod + 7, &ep, 10); 2195 utc = strtoul(mod + 7, &ep, 10);
2196 st->cp = ep; 2196 st->next = ep;
2197 } else { 2197 } else {
2198 utc = 0; 2198 utc = 0;
2199 st->cp = mod + 6; 2199 st->next = mod + 6;
2200 } 2200 }
2201 st->newStr = VarStrftime(st->nstr, 1, utc); 2201 st->newStr = VarStrftime(st->nstr, 1, utc);
2202 st->termc = *st->cp; 2202 st->termc = *st->next;
2203 return TRUE; 2203 return TRUE;
2204} 2204}
2205 2205
2206/* :localtime */ 2206/* :localtime */
2207static Boolean 2207static Boolean
2208ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) 2208ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st)
2209{ 2209{
2210 if (!ModMatchEq(mod, "localtime", st->endc)) { 2210 if (!ModMatchEq(mod, "localtime", st->endc)) {
2211 st->cp = mod + 1; 2211 st->next = mod + 1;
2212 return FALSE; 2212 return FALSE;
2213 } 2213 }
2214 2214
2215 time_t utc; 2215 time_t utc;
2216 if (mod[9] == '=') { 2216 if (mod[9] == '=') {
2217 char *ep; 2217 char *ep;
2218 utc = strtoul(mod + 10, &ep, 10); 2218 utc = strtoul(mod + 10, &ep, 10);
2219 st->cp = ep; 2219 st->next = ep;
2220 } else { 2220 } else {
2221 utc = 0; 2221 utc = 0;
2222 st->cp = mod + 9; 2222 st->next = mod + 9;
2223 } 2223 }
2224 st->newStr = VarStrftime(st->nstr, 0, utc); 2224 st->newStr = VarStrftime(st->nstr, 0, utc);
2225 st->termc = *st->cp; 2225 st->termc = *st->next;
2226 return TRUE; 2226 return TRUE;
2227} 2227}
2228 2228
2229/* :hash */ 2229/* :hash */
2230static Boolean 2230static Boolean
2231ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) 2231ApplyModifier_Hash(const char *mod, ApplyModifiersState *st)
2232{ 2232{
2233 if (!ModMatch(mod, "hash", st->endc)) { 2233 if (!ModMatch(mod, "hash", st->endc)) {
2234 st->cp = mod + 1; 2234 st->next = mod + 1;
2235 return FALSE; 2235 return FALSE;
2236 } 2236 }
2237 2237
2238 st->newStr = VarHash(st->nstr); 2238 st->newStr = VarHash(st->nstr);
2239 st->cp = mod + 4; 2239 st->next = mod + 4;
2240 st->termc = *st->cp; 2240 st->termc = *st->next;
2241 return TRUE; 2241 return TRUE;
2242} 2242}
2243 2243
2244/* :P */ 2244/* :P */
2245static void 2245static void
2246ApplyModifier_Path(const char *mod, ApplyModifiersState *st) 2246ApplyModifier_Path(const char *mod, ApplyModifiersState *st)
2247{ 2247{
2248 if (st->v->flags & VAR_JUNK) 2248 if (st->v->flags & VAR_JUNK)
2249 st->v->flags |= VAR_KEEP; 2249 st->v->flags |= VAR_KEEP;
2250 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); 2250 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2251 if (gn == NULL || gn->type & OP_NOPATH) { 2251 if (gn == NULL || gn->type & OP_NOPATH) {
2252 st->newStr = NULL; 2252 st->newStr = NULL;
2253 } else if (gn->path) { 2253 } else if (gn->path) {
2254 st->newStr = bmake_strdup(gn->path); 2254 st->newStr = bmake_strdup(gn->path);
2255 } else { 2255 } else {
2256 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); 2256 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2257 } 2257 }
2258 if (!st->newStr) 2258 if (!st->newStr)
2259 st->newStr = bmake_strdup(st->v->name); 2259 st->newStr = bmake_strdup(st->v->name);
2260 st->cp = mod + 1; 2260 st->next = mod + 1;
2261 st->termc = *st->cp; 2261 st->termc = *st->next;
2262} 2262}
2263 2263
2264/* :!cmd! */ 2264/* :!cmd! */
2265static Boolean 2265static Boolean
2266ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) 2266ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st)
2267{ 2267{
2268 st->cp = mod + 1; 2268 st->next = mod + 1;
2269 char delim = '!'; 2269 char delim = '!';
2270 char *cmd = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2270 char *cmd = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2271 NULL, NULL, NULL); 2271 NULL, NULL, NULL);
2272 if (cmd == NULL) { 2272 if (cmd == NULL) {
2273 st->missing_delim = delim; 2273 st->missing_delim = delim;
2274 return FALSE; 2274 return FALSE;
2275 } 2275 }
2276 2276
2277 const char *emsg = NULL; 2277 const char *emsg = NULL;
2278 if (st->eflags & VARE_WANTRES) 2278 if (st->eflags & VARE_WANTRES)
2279 st->newStr = Cmd_Exec(cmd, &emsg); 2279 st->newStr = Cmd_Exec(cmd, &emsg);
2280 else 2280 else
2281 st->newStr = varNoError; 2281 st->newStr = varNoError;
2282 free(cmd); 2282 free(cmd);
2283 2283
2284 if (emsg) 2284 if (emsg)
2285 Error(emsg, st->nstr); 2285 Error(emsg, st->nstr);
2286 2286
2287 st->termc = *st->cp; 2287 st->termc = *st->next;
2288 if (st->v->flags & VAR_JUNK) 2288 if (st->v->flags & VAR_JUNK)
2289 st->v->flags |= VAR_KEEP; 2289 st->v->flags |= VAR_KEEP;
2290 return TRUE; 2290 return TRUE;
2291} 2291}
2292 2292
2293/* :range */ 2293/* :range */
2294static Boolean 2294static Boolean
2295ApplyModifier_Range(const char *mod, ApplyModifiersState *st) 2295ApplyModifier_Range(const char *mod, ApplyModifiersState *st)
2296{ 2296{
2297 if (!ModMatchEq(mod, "range", st->endc)) { 2297 if (!ModMatchEq(mod, "range", st->endc)) {
2298 st->cp = mod + 1; 2298 st->next = mod + 1;
2299 return FALSE; 2299 return FALSE;
2300 } 2300 }
2301 2301
2302 int n; 2302 int n;
2303 if (mod[5] == '=') { 2303 if (mod[5] == '=') {
2304 char *ep; 2304 char *ep;
2305 n = strtoul(mod + 6, &ep, 10); 2305 n = strtoul(mod + 6, &ep, 10);
2306 st->cp = ep; 2306 st->next = ep;
2307 } else { 2307 } else {
2308 n = 0; 2308 n = 0;
2309 st->cp = mod + 5; 2309 st->next = mod + 5;
2310 } 2310 }
2311 st->newStr = VarRange(st->nstr, n); 2311 st->newStr = VarRange(st->nstr, n);
2312 st->termc = *st->cp; 2312 st->termc = *st->next;
2313 return TRUE; 2313 return TRUE;
2314} 2314}
2315 2315
2316/* :Mpattern or :Npattern */ 2316/* :Mpattern or :Npattern */
2317static void 2317static void
2318ApplyModifier_Match(const char *mod, ApplyModifiersState *st) 2318ApplyModifier_Match(const char *mod, ApplyModifiersState *st)
2319{ 2319{
2320 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2320 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2321 Boolean needSubst = FALSE; 2321 Boolean needSubst = FALSE;
2322 /* 2322 /*
2323 * In the loop below, ignore ':' unless we are at (or back to) the 2323 * In the loop below, ignore ':' unless we are at (or back to) the
2324 * original brace level. 2324 * original brace level.
2325 * XXX This will likely not work right if $() and ${} are intermixed. 2325 * XXX This will likely not work right if $() and ${} are intermixed.
2326 */ 2326 */
2327 int nest = 1; 2327 int nest = 1;
2328 const char *p; 2328 const char *p;
2329 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 1); p++) { 2329 for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 1); p++) {
2330 if (*p == '\\' && 2330 if (*p == '\\' &&
2331 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) { 2331 (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2332 if (!needSubst) 2332 if (!needSubst)
2333 copy = TRUE; 2333 copy = TRUE;
2334 p++; 2334 p++;
2335 continue; 2335 continue;
2336 } 2336 }
2337 if (*p == '$') 2337 if (*p == '$')
2338 needSubst = TRUE; 2338 needSubst = TRUE;
2339 if (*p == '(' || *p == '{') 2339 if (*p == '(' || *p == '{')
2340 ++nest; 2340 ++nest;
2341 if (*p == ')' || *p == '}') { 2341 if (*p == ')' || *p == '}') {
2342 --nest; 2342 --nest;
2343 if (nest == 0) 2343 if (nest == 0)
2344 break; 2344 break;
2345 } 2345 }
2346 } 2346 }
2347 st->cp = p; 2347 st->next = p;
2348 st->termc = *st->cp; 2348 st->termc = *st->next;
2349 const char *endpat = st->cp; 2349 const char *endpat = st->next;
2350 2350
2351 char *pattern; 2351 char *pattern;
2352 if (copy) { 2352 if (copy) {
2353 /* Compress the \:'s out of the pattern. */ 2353 /* Compress the \:'s out of the pattern. */
2354 pattern = bmake_malloc(endpat - (mod + 1) + 1); 2354 pattern = bmake_malloc(endpat - (mod + 1) + 1);
2355 char *dst = pattern; 2355 char *dst = pattern;
2356 const char *src = mod + 1; 2356 const char *src = mod + 1;
2357 for (; src < endpat; src++, dst++) { 2357 for (; src < endpat; src++, dst++) {
2358 if (src[0] == '\\' && src + 1 < endpat && 2358 if (src[0] == '\\' && src + 1 < endpat &&
2359 /* XXX: st->startc is missing here; see above */ 2359 /* XXX: st->startc is missing here; see above */
2360 (src[1] == ':' || src[1] == st->endc)) 2360 (src[1] == ':' || src[1] == st->endc))
2361 src++; 2361 src++;
2362 *dst = *src; 2362 *dst = *src;
2363 } 2363 }
2364 *dst = '\0'; 2364 *dst = '\0';
2365 endpat = dst; 2365 endpat = dst;
2366 } else { 2366 } else {
2367 /* 2367 /*
2368 * Either Var_Subst or ModifyWords will need a 2368 * Either Var_Subst or ModifyWords will need a
2369 * nul-terminated string soon, so construct one now. 2369 * nul-terminated string soon, so construct one now.
2370 */ 2370 */
2371 pattern = bmake_strndup(mod + 1, endpat - (mod + 1)); 2371 pattern = bmake_strndup(mod + 1, endpat - (mod + 1));
2372 } 2372 }
2373 2373
2374 if (needSubst) { 2374 if (needSubst) {
2375 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2375 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2376 char *old_pattern = pattern; 2376 char *old_pattern = pattern;
2377 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags); 2377 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags);
2378 free(old_pattern); 2378 free(old_pattern);
2379 } 2379 }
2380 2380
2381 if (DEBUG(VAR)) 2381 if (DEBUG(VAR))
2382 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", 2382 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2383 st->v->name, st->nstr, pattern); 2383 st->v->name, st->nstr, pattern);
2384 2384
2385 ModifyWordsCallback callback = mod[0] == 'M' 2385 ModifyWordsCallback callback = mod[0] == 'M'
2386 ? ModifyWord_Match : ModifyWord_NoMatch; 2386 ? ModifyWord_Match : ModifyWord_NoMatch;
2387 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2387 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2388 callback, pattern); 2388 callback, pattern);
2389 free(pattern); 2389 free(pattern);
2390} 2390}
2391 2391
2392/* :S,from,to, */ 2392/* :S,from,to, */
2393static Boolean 2393static Boolean
2394ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) 2394ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st)
2395{ 2395{
2396 ModifyWord_SubstArgs args; 2396 ModifyWord_SubstArgs args;
2397 Boolean oneBigWord = st->oneBigWord; 2397 Boolean oneBigWord = st->oneBigWord;
2398 char delim = mod[1]; 2398 char delim = mod[1];
2399 2399
2400 st->cp = mod + 2; 2400 st->next = mod + 2;
2401 2401
2402 /* 2402 /*
2403 * If pattern begins with '^', it is anchored to the 2403 * If pattern begins with '^', it is anchored to the
2404 * start of the word -- skip over it and flag pattern. 2404 * start of the word -- skip over it and flag pattern.
2405 */ 2405 */
2406 args.pflags = 0; 2406 args.pflags = 0;
2407 if (*st->cp == '^') { 2407 if (*st->next == '^') {
2408 args.pflags |= VARP_ANCHOR_START; 2408 args.pflags |= VARP_ANCHOR_START;
2409 st->cp++; 2409 st->next++;
2410 } 2410 }
2411 2411
2412 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2412 char *lhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2413 &args.lhsLen, &args.pflags, NULL); 2413 &args.lhsLen, &args.pflags, NULL);
2414 if (lhs == NULL) { 2414 if (lhs == NULL) {
2415 st->missing_delim = delim; 2415 st->missing_delim = delim;
2416 return FALSE; 2416 return FALSE;
2417 } 2417 }
2418 args.lhs = lhs; 2418 args.lhs = lhs;
2419 2419
2420 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2420 char *rhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2421 &args.rhsLen, NULL, &args); 2421 &args.rhsLen, NULL, &args);
2422 if (rhs == NULL) { 2422 if (rhs == NULL) {
2423 st->missing_delim = delim; 2423 st->missing_delim = delim;
2424 return FALSE; 2424 return FALSE;
2425 } 2425 }
2426 args.rhs = rhs; 2426 args.rhs = rhs;
2427 2427
2428 /* 2428 /*
2429 * Check for global substitution. If 'g' after the final 2429 * Check for global substitution. If 'g' after the final
2430 * delimiter, substitution is global and is marked that 2430 * delimiter, substitution is global and is marked that
2431 * way. 2431 * way.
2432 */ 2432 */
2433 for (;; st->cp++) { 2433 for (;; st->next++) {
2434 switch (*st->cp) { 2434 switch (*st->next) {
2435 case 'g': 2435 case 'g':
2436 args.pflags |= VARP_SUB_GLOBAL; 2436 args.pflags |= VARP_SUB_GLOBAL;
2437 continue; 2437 continue;
2438 case '1': 2438 case '1':
2439 args.pflags |= VARP_SUB_ONE; 2439 args.pflags |= VARP_SUB_ONE;
2440 continue; 2440 continue;
2441 case 'W': 2441 case 'W':
2442 oneBigWord = TRUE; 2442 oneBigWord = TRUE;
2443 continue; 2443 continue;
2444 } 2444 }
2445 break; 2445 break;
2446 } 2446 }
2447 2447
2448 st->termc = *st->cp; 2448 st->termc = *st->next;
2449 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2449 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2450 ModifyWord_Subst, &args); 2450 ModifyWord_Subst, &args);
2451 2451
2452 free(lhs); 2452 free(lhs);
2453 free(rhs); 2453 free(rhs);
2454 return TRUE; 2454 return TRUE;
2455} 2455}
2456 2456
2457#ifndef NO_REGEX 2457#ifndef NO_REGEX
2458 2458
2459/* :C,from,to, */ 2459/* :C,from,to, */
2460static Boolean 2460static Boolean
2461ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) 2461ApplyModifier_Regex(const char *mod, ApplyModifiersState *st)
2462{ 2462{
2463 ModifyWord_SubstRegexArgs args; 2463 ModifyWord_SubstRegexArgs args;
2464 2464
2465 args.pflags = 0; 2465 args.pflags = 0;
2466 Boolean oneBigWord = st->oneBigWord; 2466 Boolean oneBigWord = st->oneBigWord;
2467 char delim = mod[1]; 2467 char delim = mod[1];
2468 2468
2469 st->cp = mod + 2; 2469 st->next = mod + 2;
2470 2470
2471 char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2471 char *re = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2472 NULL, NULL, NULL); 2472 NULL, NULL, NULL);
2473 if (re == NULL) { 2473 if (re == NULL) {
2474 st->missing_delim = delim; 2474 st->missing_delim = delim;
2475 return FALSE; 2475 return FALSE;
2476 } 2476 }
2477 2477
2478 args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2478 args.replace = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2479 NULL, NULL, NULL); 2479 NULL, NULL, NULL);
2480 if (args.replace == NULL) { 2480 if (args.replace == NULL) {
2481 free(re); 2481 free(re);
2482 st->missing_delim = delim; 2482 st->missing_delim = delim;
2483 return FALSE; 2483 return FALSE;
2484 } 2484 }
2485 2485
2486 for (;; st->cp++) { 2486 for (;; st->next++) {
2487 switch (*st->cp) { 2487 switch (*st->next) {
2488 case 'g': 2488 case 'g':
2489 args.pflags |= VARP_SUB_GLOBAL; 2489 args.pflags |= VARP_SUB_GLOBAL;
2490 continue; 2490 continue;
2491 case '1': 2491 case '1':
2492 args.pflags |= VARP_SUB_ONE; 2492 args.pflags |= VARP_SUB_ONE;
2493 continue; 2493 continue;
2494 case 'W': 2494 case 'W':
2495 oneBigWord = TRUE; 2495 oneBigWord = TRUE;
2496 continue; 2496 continue;
2497 } 2497 }
2498 break; 2498 break;
2499 } 2499 }
2500 2500
2501 st->termc = *st->cp; 2501 st->termc = *st->next;
2502 2502
2503 int error = regcomp(&args.re, re, REG_EXTENDED); 2503 int error = regcomp(&args.re, re, REG_EXTENDED);
2504 free(re); 2504 free(re);
2505 if (error) { 2505 if (error) {
2506 VarREError(error, &args.re, "RE substitution error"); 2506 VarREError(error, &args.re, "RE substitution error");
2507 free(args.replace); 2507 free(args.replace);
2508 return FALSE; 2508 return FALSE;
2509 } 2509 }
2510 2510
2511 args.nsub = args.re.re_nsub + 1; 2511 args.nsub = args.re.re_nsub + 1;
2512 if (args.nsub < 1) 2512 if (args.nsub < 1)
2513 args.nsub = 1; 2513 args.nsub = 1;
2514 if (args.nsub > 10) 2514 if (args.nsub > 10)
2515 args.nsub = 10; 2515 args.nsub = 10;
2516 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2516 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2517 ModifyWord_SubstRegex, &args); 2517 ModifyWord_SubstRegex, &args);
2518 regfree(&args.re); 2518 regfree(&args.re);
2519 free(args.replace); 2519 free(args.replace);
2520 return TRUE; 2520 return TRUE;
2521} 2521}
2522#endif 2522#endif
2523 2523
2524static void 2524static void
2525ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2525ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2526{ 2526{
2527 SepBuf_AddStr(buf, word); 2527 SepBuf_AddStr(buf, word);
2528} 2528}
2529 2529
2530/* :ts<separator> */ 2530/* :ts<separator> */
2531static Boolean 2531static Boolean
2532ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) 2532ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st)
2533{ 2533{
2534 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2534 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2535 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ 2535 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */
2536 st->sep = sep[0]; 2536 st->sep = sep[0];
2537 st->cp = sep + 1; 2537 st->next = sep + 1;
2538 } else if (sep[0] == st->endc || sep[0] == ':') { 2538 } else if (sep[0] == st->endc || sep[0] == ':') {
2539 /* ":ts<endc>" or ":ts:" */ 2539 /* ":ts<endc>" or ":ts:" */
2540 st->sep = '\0'; /* no separator */ 2540 st->sep = '\0'; /* no separator */
2541 st->cp = sep; 2541 st->next = sep;
2542 } else if (sep[0] == '\\') { 2542 } else if (sep[0] == '\\') {
2543 const char *xp = sep + 1; 2543 const char *xp = sep + 1;
2544 int base = 8; /* assume octal */ 2544 int base = 8; /* assume octal */
2545 2545
2546 switch (sep[1]) { 2546 switch (sep[1]) {
2547 case 'n': 2547 case 'n':
2548 st->sep = '\n'; 2548 st->sep = '\n';
2549 st->cp = sep + 2; 2549 st->next = sep + 2;
2550 break; 2550 break;
2551 case 't': 2551 case 't':
2552 st->sep = '\t'; 2552 st->sep = '\t';
2553 st->cp = sep + 2; 2553 st->next = sep + 2;
2554 break; 2554 break;
2555 case 'x': 2555 case 'x':
2556 base = 16; 2556 base = 16;
2557 xp++; 2557 xp++;
2558 goto get_numeric; 2558 goto get_numeric;
2559 case '0': 2559 case '0':
2560 base = 0; 2560 base = 0;
2561 goto get_numeric; 2561 goto get_numeric;
2562 default: 2562 default:
2563 if (!isdigit((unsigned char)sep[1])) 2563 if (!isdigit((unsigned char)sep[1]))
2564 return FALSE; /* ":ts<backslash><unrecognised>". */ 2564 return FALSE; /* ":ts<backslash><unrecognised>". */
2565 2565
2566 char *end; 2566 char *end;
2567 get_numeric: 2567 get_numeric:
2568 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); 2568 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base);
2569 if (*end != ':' && *end != st->endc) 2569 if (*end != ':' && *end != st->endc)
2570 return FALSE; 2570 return FALSE;
2571 st->cp = end; 2571 st->next = end;
2572 break; 2572 break;
2573 } 2573 }
2574 } else { 2574 } else {
2575 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ 2575 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */
2576 } 2576 }
2577 2577
2578 st->termc = *st->cp; 2578 st->termc = *st->next;
2579 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2579 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2580 ModifyWord_Copy, NULL); 2580 ModifyWord_Copy, NULL);
2581 return TRUE; 2581 return TRUE;
2582} 2582}
2583 2583
2584/* :tA, :tu, :tl, :ts<separator>, etc. */ 2584/* :tA, :tu, :tl, :ts<separator>, etc. */
2585static Boolean 2585static Boolean
2586ApplyModifier_To(const char *mod, ApplyModifiersState *st) 2586ApplyModifier_To(const char *mod, ApplyModifiersState *st)
2587{ 2587{
2588 st->cp = mod + 1; /* make sure it is set */ 2588 st->next = mod + 1; /* make sure it is set */
2589 if (mod[1] == st->endc || mod[1] == ':') 2589 if (mod[1] == st->endc || mod[1] == ':')
2590 return FALSE; /* Found ":t<endc>" or ":t:". */ 2590 return FALSE; /* Found ":t<endc>" or ":t:". */
2591 2591
2592 if (mod[1] == 's') 2592 if (mod[1] == 's')
2593 return ApplyModifier_ToSep(mod + 2, st); 2593 return ApplyModifier_ToSep(mod + 2, st);
2594 2594
2595 if (mod[2] != st->endc && mod[2] != ':') 2595 if (mod[2] != st->endc && mod[2] != ':')
2596 return FALSE; /* Found ":t<unrecognised><unrecognised>". */ 2596 return FALSE; /* Found ":t<unrecognised><unrecognised>". */
2597 2597
2598 /* Check for two-character options: ":tu", ":tl" */ 2598 /* Check for two-character options: ":tu", ":tl" */
2599 if (mod[1] == 'A') { /* absolute path */ 2599 if (mod[1] == 'A') { /* absolute path */
2600 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2600 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2601 ModifyWord_Realpath, NULL); 2601 ModifyWord_Realpath, NULL);
2602 st->cp = mod + 2; 2602 st->next = mod + 2;
2603 st->termc = *st->cp; 2603 st->termc = *st->next;
2604 } else if (mod[1] == 'u') { 2604 } else if (mod[1] == 'u') {
2605 char *dp = bmake_strdup(st->nstr); 2605 char *dp = bmake_strdup(st->nstr);
2606 for (st->newStr = dp; *dp; dp++) 2606 for (st->newStr = dp; *dp; dp++)
2607 *dp = toupper((unsigned char)*dp); 2607 *dp = toupper((unsigned char)*dp);
2608 st->cp = mod + 2; 2608 st->next = mod + 2;
2609 st->termc = *st->cp; 2609 st->termc = *st->next;
2610 } else if (mod[1] == 'l') { 2610 } else if (mod[1] == 'l') {
2611 char *dp = bmake_strdup(st->nstr); 2611 char *dp = bmake_strdup(st->nstr);
2612 for (st->newStr = dp; *dp; dp++) 2612 for (st->newStr = dp; *dp; dp++)
2613 *dp = tolower((unsigned char)*dp); 2613 *dp = tolower((unsigned char)*dp);
2614 st->cp = mod + 2; 2614 st->next = mod + 2;
2615 st->termc = *st->cp; 2615 st->termc = *st->next;
2616 } else if (mod[1] == 'W' || mod[1] == 'w') { 2616 } else if (mod[1] == 'W' || mod[1] == 'w') {
2617 st->oneBigWord = mod[1] == 'W'; 2617 st->oneBigWord = mod[1] == 'W';
2618 st->newStr = st->nstr; 2618 st->newStr = st->nstr;
2619 st->cp = mod + 2; 2619 st->next = mod + 2;
2620 st->termc = *st->cp; 2620 st->termc = *st->next;
2621 } else { 2621 } else {
2622 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2622 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2623 return FALSE; 2623 return FALSE;
2624 } 2624 }
2625 return TRUE; 2625 return TRUE;
2626} 2626}
2627 2627
2628/* :[#], :[1], etc. */ 2628/* :[#], :[1], etc. */
2629static int 2629static int
2630ApplyModifier_Words(const char *mod, ApplyModifiersState *st) 2630ApplyModifier_Words(const char *mod, ApplyModifiersState *st)
2631{ 2631{
2632 st->cp = mod + 1; /* point to char after '[' */ 2632 st->next = mod + 1; /* point to char after '[' */
2633 char delim = ']'; /* look for closing ']' */ 2633 char delim = ']'; /* look for closing ']' */
2634 char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2634 char *estr = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2635 NULL, NULL, NULL); 2635 NULL, NULL, NULL);
2636 if (estr == NULL) { 2636 if (estr == NULL) {
2637 st->missing_delim = delim; 2637 st->missing_delim = delim;
2638 return 'c'; 2638 return 'c';
2639 } 2639 }
2640 2640
2641 /* now st->cp points just after the closing ']' */ 2641 /* now st->next points just after the closing ']' */
2642 if (st->cp[0] != ':' && st->cp[0] != st->endc) 2642 if (st->next[0] != ':' && st->next[0] != st->endc)
2643 goto bad_modifier; /* Found junk after ']' */ 2643 goto bad_modifier; /* Found junk after ']' */
2644 2644
2645 if (estr[0] == '\0') 2645 if (estr[0] == '\0')
2646 goto bad_modifier; /* empty square brackets in ":[]". */ 2646 goto bad_modifier; /* empty square brackets in ":[]". */
2647 2647
2648 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2648 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2649 if (st->oneBigWord) { 2649 if (st->oneBigWord) {
2650 st->newStr = bmake_strdup("1"); 2650 st->newStr = bmake_strdup("1");
2651 } else { 2651 } else {
2652 /* XXX: brk_string() is a rather expensive 2652 /* XXX: brk_string() is a rather expensive
2653 * way of counting words. */ 2653 * way of counting words. */
2654 char *as; 2654 char *as;
2655 int ac; 2655 int ac;
2656 char **av = brk_string(st->nstr, &ac, FALSE, &as); 2656 char **av = brk_string(st->nstr, &ac, FALSE, &as);
2657 free(as); 2657 free(as);
2658 free(av); 2658 free(av);
2659 2659
2660 Buffer buf; 2660 Buffer buf;
2661 Buf_Init(&buf, 4); /* 3 digits + '\0' */ 2661 Buf_Init(&buf, 4); /* 3 digits + '\0' */
2662 Buf_AddInt(&buf, ac); 2662 Buf_AddInt(&buf, ac);
2663 st->newStr = Buf_Destroy(&buf, FALSE); 2663 st->newStr = Buf_Destroy(&buf, FALSE);
2664 } 2664 }
2665 goto ok; 2665 goto ok;
2666 } 2666 }
2667 2667
2668 if (estr[0] == '*' && estr[1] == '\0') { 2668 if (estr[0] == '*' && estr[1] == '\0') {
2669 /* Found ":[*]" */ 2669 /* Found ":[*]" */
2670 st->oneBigWord = TRUE; 2670 st->oneBigWord = TRUE;
2671 st->newStr = st->nstr; 2671 st->newStr = st->nstr;
2672 goto ok; 2672 goto ok;
2673 } 2673 }
2674 2674
2675 if (estr[0] == '@' && estr[1] == '\0') { 2675 if (estr[0] == '@' && estr[1] == '\0') {
2676 /* Found ":[@]" */ 2676 /* Found ":[@]" */
2677 st->oneBigWord = FALSE; 2677 st->oneBigWord = FALSE;
2678 st->newStr = st->nstr; 2678 st->newStr = st->nstr;
2679 goto ok; 2679 goto ok;
2680 } 2680 }
2681 2681
2682 /* 2682 /*
2683 * We expect estr to contain a single integer for :[N], or two integers 2683 * We expect estr to contain a single integer for :[N], or two integers
2684 * separated by ".." for :[start..end]. 2684 * separated by ".." for :[start..end].
2685 */ 2685 */
2686 char *ep; 2686 char *ep;
2687 int first = strtol(estr, &ep, 0); 2687 int first = strtol(estr, &ep, 0);
2688 int last; 2688 int last;
2689 if (ep == estr) /* Found junk instead of a number */ 2689 if (ep == estr) /* Found junk instead of a number */
2690 goto bad_modifier; 2690 goto bad_modifier;
2691 2691
2692 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2692 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2693 last = first; 2693 last = first;
2694 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2694 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2695 /* Expecting another integer after ".." */ 2695 /* Expecting another integer after ".." */
2696 ep += 2; 2696 ep += 2;
2697 last = strtol(ep, &ep, 0); 2697 last = strtol(ep, &ep, 0);
2698 if (ep[0] != '\0') /* Found junk after ".." */ 2698 if (ep[0] != '\0') /* Found junk after ".." */
2699 goto bad_modifier; 2699 goto bad_modifier;
2700 } else 2700 } else
2701 goto bad_modifier; /* Found junk instead of ".." */ 2701 goto bad_modifier; /* Found junk instead of ".." */
2702 2702
2703 /* 2703 /*
2704 * Now seldata is properly filled in, but we still have to check for 0 as 2704 * Now seldata is properly filled in, but we still have to check for 0 as
2705 * a special case. 2705 * a special case.
2706 */ 2706 */
2707 if (first == 0 && last == 0) { 2707 if (first == 0 && last == 0) {
2708 /* ":[0]" or perhaps ":[0..0]" */ 2708 /* ":[0]" or perhaps ":[0..0]" */
2709 st->oneBigWord = TRUE; 2709 st->oneBigWord = TRUE;
2710 st->newStr = st->nstr; 2710 st->newStr = st->nstr;
2711 goto ok; 2711 goto ok;
2712 } 2712 }
2713 2713
2714 /* ":[0..N]" or ":[N..0]" */ 2714 /* ":[0..N]" or ":[N..0]" */
2715 if (first == 0 || last == 0) 2715 if (first == 0 || last == 0)
2716 goto bad_modifier; 2716 goto bad_modifier;
2717 2717
2718 /* Normal case: select the words described by seldata. */ 2718 /* Normal case: select the words described by seldata. */
2719 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); 2719 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last);
2720 2720
2721ok: 2721ok:
2722 st->termc = *st->cp; 2722 st->termc = *st->next;
2723 free(estr); 2723 free(estr);
2724 return 0; 2724 return 0;
2725 2725
2726bad_modifier: 2726bad_modifier:
2727 free(estr); 2727 free(estr);
2728 return 'b'; 2728 return 'b';
2729} 2729}
2730 2730
2731/* :O or :Ox */ 2731/* :O or :Ox */
2732static Boolean 2732static Boolean
2733ApplyModifier_Order(const char *mod, ApplyModifiersState *st) 2733ApplyModifier_Order(const char *mod, ApplyModifiersState *st)
2734{ 2734{
2735 char otype; 2735 char otype;
2736 2736
2737 st->cp = mod + 1; /* skip to the rest in any case */ 2737 st->next = mod + 1; /* skip to the rest in any case */
2738 if (mod[1] == st->endc || mod[1] == ':') { 2738 if (mod[1] == st->endc || mod[1] == ':') {
2739 otype = 's'; 2739 otype = 's';
2740 st->termc = *st->cp; 2740 st->termc = *st->next;
2741 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2741 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2742 (mod[2] == st->endc || mod[2] == ':')) { 2742 (mod[2] == st->endc || mod[2] == ':')) {
2743 otype = mod[1]; 2743 otype = mod[1];
2744 st->cp = mod + 2; 2744 st->next = mod + 2;
2745 st->termc = *st->cp; 2745 st->termc = *st->next;
2746 } else { 2746 } else {
2747 return FALSE; 2747 return FALSE;
2748 } 2748 }
2749 st->newStr = VarOrder(st->nstr, otype); 2749 st->newStr = VarOrder(st->nstr, otype);
2750 return TRUE; 2750 return TRUE;
2751} 2751}
2752 2752
2753/* :? then : else */ 2753/* :? then : else */
2754static Boolean 2754static Boolean
2755ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) 2755ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st)
2756{ 2756{
2757 Boolean value = FALSE; 2757 Boolean value = FALSE;
2758 int cond_rc = 0; 2758 int cond_rc = 0;
2759 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; 2759 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES;
2760 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; 2760 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES;
2761 2761
2762 if (st->eflags & VARE_WANTRES) { 2762 if (st->eflags & VARE_WANTRES) {
2763 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); 2763 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
2764 if (cond_rc != COND_INVALID && value) 2764 if (cond_rc != COND_INVALID && value)
2765 then_eflags |= VARE_WANTRES; 2765 then_eflags |= VARE_WANTRES;
2766 if (cond_rc != COND_INVALID && !value) 2766 if (cond_rc != COND_INVALID && !value)
2767 else_eflags |= VARE_WANTRES; 2767 else_eflags |= VARE_WANTRES;
2768 } 2768 }
2769 2769
2770 st->cp = mod + 1; 2770 st->next = mod + 1;
2771 char delim = ':'; 2771 char delim = ':';
2772 char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt, 2772 char *then_expr = ParseModifierPart(&st->next, delim, then_eflags, st->ctxt,
2773 NULL, NULL, NULL); 2773 NULL, NULL, NULL);
2774 if (then_expr == NULL) { 2774 if (then_expr == NULL) {
2775 st->missing_delim = delim; 2775 st->missing_delim = delim;
2776 return FALSE; 2776 return FALSE;
2777 } 2777 }
2778 2778
2779 delim = st->endc; /* BRCLOSE or PRCLOSE */ 2779 delim = st->endc; /* BRCLOSE or PRCLOSE */
2780 char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt, 2780 char *else_expr = ParseModifierPart(&st->next, delim, else_eflags, st->ctxt,
2781 NULL, NULL, NULL); 2781 NULL, NULL, NULL);
2782 if (else_expr == NULL) { 2782 if (else_expr == NULL) {
2783 st->missing_delim = delim; 2783 st->missing_delim = delim;
2784 return FALSE; 2784 return FALSE;
2785 } 2785 }
2786 2786
2787 st->termc = *--st->cp; 2787 st->termc = *--st->next;
2788 if (cond_rc == COND_INVALID) { 2788 if (cond_rc == COND_INVALID) {
2789 Error("Bad conditional expression `%s' in %s?%s:%s", 2789 Error("Bad conditional expression `%s' in %s?%s:%s",
2790 st->v->name, st->v->name, then_expr, else_expr); 2790 st->v->name, st->v->name, then_expr, else_expr);
2791 return FALSE; 2791 return FALSE;
2792 } 2792 }
2793 2793
2794 if (value) { 2794 if (value) {
2795 st->newStr = then_expr; 2795 st->newStr = then_expr;
2796 free(else_expr); 2796 free(else_expr);
2797 } else { 2797 } else {
2798 st->newStr = else_expr; 2798 st->newStr = else_expr;
2799 free(then_expr); 2799 free(then_expr);
2800 } 2800 }
2801 if (st->v->flags & VAR_JUNK) 2801 if (st->v->flags & VAR_JUNK)
2802 st->v->flags |= VAR_KEEP; 2802 st->v->flags |= VAR_KEEP;
2803 return TRUE; 2803 return TRUE;
2804} 2804}
2805 2805
2806/* 2806/*
2807 * The ::= modifiers actually assign a value to the variable. 2807 * The ::= modifiers actually assign a value to the variable.
2808 * Their main purpose is in supporting modifiers of .for loop 2808 * Their main purpose is in supporting modifiers of .for loop
2809 * iterators and other obscure uses. They always expand to 2809 * iterators and other obscure uses. They always expand to
2810 * nothing. In a target rule that would otherwise expand to an 2810 * nothing. In a target rule that would otherwise expand to an
2811 * empty line they can be preceded with @: to keep make happy. 2811 * empty line they can be preceded with @: to keep make happy.
2812 * Eg. 2812 * Eg.
2813 * 2813 *
2814 * foo: .USE 2814 * foo: .USE
2815 * .for i in ${.TARGET} ${.TARGET:R}.gz 2815 * .for i in ${.TARGET} ${.TARGET:R}.gz
2816 * @: ${t::=$i} 2816 * @: ${t::=$i}
2817 * @echo blah ${t:T} 2817 * @echo blah ${t:T}
2818 * .endfor 2818 * .endfor
2819 * 2819 *
2820 * ::=<str> Assigns <str> as the new value of variable. 2820 * ::=<str> Assigns <str> as the new value of variable.
2821 * ::?=<str> Assigns <str> as value of variable if 2821 * ::?=<str> Assigns <str> as value of variable if
2822 * it was not already set. 2822 * it was not already set.
2823 * ::+=<str> Appends <str> to variable. 2823 * ::+=<str> Appends <str> to variable.
2824 * ::!=<cmd> Assigns output of <cmd> as the new value of 2824 * ::!=<cmd> Assigns output of <cmd> as the new value of
2825 * variable. 2825 * variable.
2826 */ 2826 */
2827static int 2827static int
2828ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) 2828ApplyModifier_Assign(const char *mod, ApplyModifiersState *st)
2829{ 2829{
2830 const char *op = mod + 1; 2830 const char *op = mod + 1;
2831 if (!(op[0] == '=' || 2831 if (!(op[0] == '=' ||
2832 (op[1] == '=' && 2832 (op[1] == '=' &&
2833 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2833 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2834 return 'd'; /* "::<unrecognised>" */ 2834 return 'd'; /* "::<unrecognised>" */
2835 2835
2836 GNode *v_ctxt; /* context where v belongs */ 2836 GNode *v_ctxt; /* context where v belongs */
2837 2837
2838 if (st->v->name[0] == 0) 2838 if (st->v->name[0] == 0)
2839 return 'b'; 2839 return 'b';
2840 2840
2841 v_ctxt = st->ctxt; 2841 v_ctxt = st->ctxt;
2842 char *sv_name = NULL; 2842 char *sv_name = NULL;
2843 if (st->v->flags & VAR_JUNK) { 2843 if (st->v->flags & VAR_JUNK) {
2844 /* 2844 /*
2845 * We need to bmake_strdup() it incase ParseModifierPart() recurses. 2845 * We need to bmake_strdup() it incase ParseModifierPart() recurses.
2846 */ 2846 */
2847 sv_name = st->v->name; 2847 sv_name = st->v->name;
2848 st->v->name = bmake_strdup(st->v->name); 2848 st->v->name = bmake_strdup(st->v->name);
2849 } else if (st->ctxt != VAR_GLOBAL) { 2849 } else if (st->ctxt != VAR_GLOBAL) {
2850 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2850 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2851 if (gv == NULL) 2851 if (gv == NULL)
2852 v_ctxt = VAR_GLOBAL; 2852 v_ctxt = VAR_GLOBAL;
2853 else 2853 else
2854 VarFreeEnv(gv, TRUE); 2854 VarFreeEnv(gv, TRUE);
2855 } 2855 }
2856 2856
2857 switch (op[0]) { 2857 switch (op[0]) {
2858 case '+': 2858 case '+':
2859 case '?': 2859 case '?':
2860 case '!': 2860 case '!':
2861 st->cp = mod + 3; 2861 st->next = mod + 3;
2862 break; 2862 break;
2863 default: 2863 default:
2864 st->cp = mod + 2; 2864 st->next = mod + 2;
2865 break; 2865 break;
2866 } 2866 }
2867 2867
2868 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; 2868 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
2869 char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2869 char *val = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2870 NULL, NULL, NULL); 2870 NULL, NULL, NULL);
2871 if (st->v->flags & VAR_JUNK) { 2871 if (st->v->flags & VAR_JUNK) {
2872 /* restore original name */ 2872 /* restore original name */
2873 free(st->v->name); 2873 free(st->v->name);
2874 st->v->name = sv_name; 2874 st->v->name = sv_name;
2875 } 2875 }
2876 if (val == NULL) { 2876 if (val == NULL) {
2877 st->missing_delim = delim; 2877 st->missing_delim = delim;
2878 return 'c'; 2878 return 'c';
2879 } 2879 }
2880 2880
2881 st->termc = *--st->cp; 2881 st->termc = *--st->next;
2882 2882
2883 if (st->eflags & VARE_WANTRES) { 2883 if (st->eflags & VARE_WANTRES) {
2884 switch (op[0]) { 2884 switch (op[0]) {
2885 case '+': 2885 case '+':
2886 Var_Append(st->v->name, val, v_ctxt); 2886 Var_Append(st->v->name, val, v_ctxt);
2887 break; 2887 break;
2888 case '!': { 2888 case '!': {
2889 const char *emsg; 2889 const char *emsg;
2890 st->newStr = Cmd_Exec(val, &emsg); 2890 st->newStr = Cmd_Exec(val, &emsg);
2891 if (emsg) 2891 if (emsg)
2892 Error(emsg, st->nstr); 2892 Error(emsg, st->nstr);
2893 else 2893 else
2894 Var_Set(st->v->name, st->newStr, v_ctxt); 2894 Var_Set(st->v->name, st->newStr, v_ctxt);
2895 free(st->newStr); 2895 free(st->newStr);
2896 break; 2896 break;
2897 } 2897 }
2898 case '?': 2898 case '?':
2899 if (!(st->v->flags & VAR_JUNK)) 2899 if (!(st->v->flags & VAR_JUNK))
2900 break; 2900 break;
2901 /* FALLTHROUGH */ 2901 /* FALLTHROUGH */
2902 default: 2902 default:
2903 Var_Set(st->v->name, val, v_ctxt); 2903 Var_Set(st->v->name, val, v_ctxt);
2904 break; 2904 break;
2905 } 2905 }
2906 } 2906 }
2907 free(val); 2907 free(val);
2908 st->newStr = varNoError; 2908 st->newStr = varNoError;
2909 return 0; 2909 return 0;
2910} 2910}
2911 2911
2912/* remember current value */ 2912/* remember current value */
2913static Boolean 2913static Boolean
2914ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) 2914ApplyModifier_Remember(const char *mod, ApplyModifiersState *st)
2915{ 2915{
2916 if (!ModMatchEq(mod, "_", st->endc)) { 2916 if (!ModMatchEq(mod, "_", st->endc)) {
2917 st->cp = mod + 1; 2917 st->next = mod + 1;
2918 return FALSE; 2918 return FALSE;
2919 } 2919 }
2920 2920
2921 if (mod[1] == '=') { 2921 if (mod[1] == '=') {
2922 size_t n = strcspn(mod + 2, ":)}"); 2922 size_t n = strcspn(mod + 2, ":)}");
2923 char *name = bmake_strndup(mod + 2, n); 2923 char *name = bmake_strndup(mod + 2, n);
2924 Var_Set(name, st->nstr, st->ctxt); 2924 Var_Set(name, st->nstr, st->ctxt);
2925 free(name); 2925 free(name);
2926 st->cp = mod + 2 + n; 2926 st->next = mod + 2 + n;
2927 } else { 2927 } else {
2928 Var_Set("_", st->nstr, st->ctxt); 2928 Var_Set("_", st->nstr, st->ctxt);
2929 st->cp = mod + 1; 2929 st->next = mod + 1;
2930 } 2930 }
2931 st->newStr = st->nstr; 2931 st->newStr = st->nstr;
2932 st->termc = *st->cp; 2932 st->termc = *st->next;
2933 return TRUE; 2933 return TRUE;
2934} 2934}
2935 2935
2936#ifdef SYSVVARSUB 2936#ifdef SYSVVARSUB
2937/* :from=to */ 2937/* :from=to */
2938static int 2938static int
2939ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) 2939ApplyModifier_SysV(const char *mod, ApplyModifiersState *st)
2940{ 2940{
2941 Boolean eqFound = FALSE; 2941 Boolean eqFound = FALSE;
2942 2942
2943 /* 2943 /*
2944 * First we make a pass through the string trying 2944 * First we make a pass through the string trying
2945 * to verify it is a SYSV-make-style translation: 2945 * to verify it is a SYSV-make-style translation:
2946 * it must be: <string1>=<string2>) 2946 * it must be: <string1>=<string2>)
2947 */ 2947 */
2948 st->cp = mod; 2948 st->next = mod;
2949 int nest = 1; 2949 int nest = 1;
2950 while (*st->cp != '\0' && nest > 0) { 2950 while (*st->next != '\0' && nest > 0) {
2951 if (*st->cp == '=') { 2951 if (*st->next == '=') {
2952 eqFound = TRUE; 2952 eqFound = TRUE;
2953 /* continue looking for st->endc */ 2953 /* continue looking for st->endc */
2954 } else if (*st->cp == st->endc) 2954 } else if (*st->next == st->endc)
2955 nest--; 2955 nest--;
2956 else if (*st->cp == st->startc) 2956 else if (*st->next == st->startc)
2957 nest++; 2957 nest++;
2958 if (nest > 0) 2958 if (nest > 0)
2959 st->cp++; 2959 st->next++;
2960 } 2960 }
2961 if (*st->cp != st->endc || !eqFound) 2961 if (*st->next != st->endc || !eqFound)
2962 return 0; 2962 return 0;
2963 2963
2964 char delim = '='; 2964 char delim = '=';
2965 st->cp = mod; 2965 st->next = mod;
2966 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2966 char *lhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2967 NULL, NULL, NULL); 2967 NULL, NULL, NULL);
2968 if (lhs == NULL) { 2968 if (lhs == NULL) {
2969 st->missing_delim = delim; 2969 st->missing_delim = delim;
2970 return 'c'; 2970 return 'c';
2971 } 2971 }
2972 2972
2973 delim = st->endc; 2973 delim = st->endc;
2974 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2974 char *rhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt,
2975 NULL, NULL, NULL); 2975 NULL, NULL, NULL);
2976 if (rhs == NULL) { 2976 if (rhs == NULL) {
2977 st->missing_delim = delim; 2977 st->missing_delim = delim;
2978 return 'c'; 2978 return 'c';
2979 } 2979 }
2980 2980
2981 /* 2981 /*
2982 * SYSV modifications happen through the whole 2982 * SYSV modifications happen through the whole
2983 * string. Note the pattern is anchored at the end. 2983 * string. Note the pattern is anchored at the end.
2984 */ 2984 */
2985 st->termc = *--st->cp; 2985 st->termc = *--st->next;
2986 if (lhs[0] == '\0' && *st->nstr == '\0') { 2986 if (lhs[0] == '\0' && *st->nstr == '\0') {
2987 st->newStr = st->nstr; /* special case */ 2987 st->newStr = st->nstr; /* special case */
2988 } else { 2988 } else {
2989 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; 2989 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
2990 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2990 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2991 ModifyWord_SYSVSubst, &args); 2991 ModifyWord_SYSVSubst, &args);
2992 } 2992 }
2993 free(lhs); 2993 free(lhs);
2994 free(rhs); 2994 free(rhs);
2995 return '='; 2995 return '=';
2996} 2996}
2997#endif 2997#endif
2998 2998
2999/* 2999/*
3000 * Now we need to apply any modifiers the user wants applied. 3000 * Now we need to apply any modifiers the user wants applied.
3001 * These are: 3001 * These are:
3002 * :M<pattern> words which match the given <pattern>. 3002 * :M<pattern> words which match the given <pattern>.
3003 * <pattern> is of the standard file 3003 * <pattern> is of the standard file
3004 * wildcarding form. 3004 * wildcarding form.
3005 * :N<pattern> words which do not match the given <pattern>. 3005 * :N<pattern> words which do not match the given <pattern>.
3006 * :S<d><pat1><d><pat2><d>[1gW] 3006 * :S<d><pat1><d><pat2><d>[1gW]
3007 * Substitute <pat2> for <pat1> in the value 3007 * Substitute <pat2> for <pat1> in the value
3008 * :C<d><pat1><d><pat2><d>[1gW] 3008 * :C<d><pat1><d><pat2><d>[1gW]
3009 * Substitute <pat2> for regex <pat1> in the value 3009 * Substitute <pat2> for regex <pat1> in the value
3010 * :H Substitute the head of each word 3010 * :H Substitute the head of each word
3011 * :T Substitute the tail of each word 3011 * :T Substitute the tail of each word
3012 * :E Substitute the extension (minus '.') of 3012 * :E Substitute the extension (minus '.') of
3013 * each word 3013 * each word
3014 * :R Substitute the root of each word 3014 * :R Substitute the root of each word
3015 * (pathname minus the suffix). 3015 * (pathname minus the suffix).
3016 * :O ("Order") Alphabeticaly sort words in variable. 3016 * :O ("Order") Alphabeticaly sort words in variable.
3017 * :Ox ("intermiX") Randomize words in variable. 3017 * :Ox ("intermiX") Randomize words in variable.
3018 * :u ("uniq") Remove adjacent duplicate words. 3018 * :u ("uniq") Remove adjacent duplicate words.
3019 * :tu Converts the variable contents to uppercase. 3019 * :tu Converts the variable contents to uppercase.
3020 * :tl Converts the variable contents to lowercase. 3020 * :tl Converts the variable contents to lowercase.
3021 * :ts[c] Sets varSpace - the char used to 3021 * :ts[c] Sets varSpace - the char used to
3022 * separate words to 'c'. If 'c' is 3022 * separate words to 'c'. If 'c' is
3023 * omitted then no separation is used. 3023 * omitted then no separation is used.
3024 * :tW Treat the variable contents as a single 3024 * :tW Treat the variable contents as a single
3025 * word, even if it contains spaces. 3025 * word, even if it contains spaces.
3026 * (Mnemonic: one big 'W'ord.) 3026 * (Mnemonic: one big 'W'ord.)
3027 * :tw Treat the variable contents as multiple 3027 * :tw Treat the variable contents as multiple
3028 * space-separated words. 3028 * space-separated words.
3029 * (Mnemonic: many small 'w'ords.) 3029 * (Mnemonic: many small 'w'ords.)
3030 * :[index] Select a single word from the value. 3030 * :[index] Select a single word from the value.
3031 * :[start..end] Select multiple words from the value. 3031 * :[start..end] Select multiple words from the value.
3032 * :[*] or :[0] Select the entire value, as a single 3032 * :[*] or :[0] Select the entire value, as a single
3033 * word. Equivalent to :tW. 3033 * word. Equivalent to :tW.
3034 * :[@] Select the entire value, as multiple 3034 * :[@] Select the entire value, as multiple
3035 * words. Undoes the effect of :[*]. 3035 * words. Undoes the effect of :[*].
3036 * Equivalent to :tw. 3036 * Equivalent to :tw.
3037 * :[#] Returns the number of words in the value. 3037 * :[#] Returns the number of words in the value.
3038 * 3038 *
3039 * :?<true-value>:<false-value> 3039 * :?<true-value>:<false-value>
3040 * If the variable evaluates to true, return 3040 * If the variable evaluates to true, return
3041 * true value, else return the second value. 3041 * true value, else return the second value.
3042 * :lhs=rhs Like :S, but the rhs goes to the end of 3042 * :lhs=rhs Like :S, but the rhs goes to the end of
3043 * the invocation. 3043 * the invocation.
3044 * :sh Treat the current value as a command 3044 * :sh Treat the current value as a command
3045 * to be run, new value is its output. 3045 * to be run, new value is its output.
3046 * The following added so we can handle ODE makefiles. 3046 * The following added so we can handle ODE makefiles.
3047 * :@<tmpvar>@<newval>@ 3047 * :@<tmpvar>@<newval>@
3048 * Assign a temporary local variable <tmpvar> 3048 * Assign a temporary local variable <tmpvar>
3049 * to the current value of each word in turn 3049 * to the current value of each word in turn
3050 * and replace each word with the result of 3050 * and replace each word with the result of
3051 * evaluating <newval> 3051 * evaluating <newval>
3052 * :D<newval> Use <newval> as value if variable defined 3052 * :D<newval> Use <newval> as value if variable defined
3053 * :U<newval> Use <newval> as value if variable undefined 3053 * :U<newval> Use <newval> as value if variable undefined
3054 * :L Use the name of the variable as the value. 3054 * :L Use the name of the variable as the value.
3055 * :P Use the path of the node that has the same 3055 * :P Use the path of the node that has the same
3056 * name as the variable as the value. This 3056 * name as the variable as the value. This
3057 * basically includes an implied :L so that 3057 * basically includes an implied :L so that
3058 * the common method of refering to the path 3058 * the common method of refering to the path
3059 * of your dependent 'x' in a rule is to use 3059 * of your dependent 'x' in a rule is to use
3060 * the form '${x:P}'. 3060 * the form '${x:P}'.
3061 * :!<cmd>! Run cmd much the same as :sh run's the 3061 * :!<cmd>! Run cmd much the same as :sh run's the
3062 * current value of the variable. 3062 * current value of the variable.
3063 * Assignment operators (see ApplyModifier_Assign). 3063 * Assignment operators (see ApplyModifier_Assign).
3064 */ 3064 */
3065static char * 3065static char *
3066ApplyModifiers(char *nstr, const char * const tstr, 3066ApplyModifiers(char *nstr, const char * const tstr,
3067 int const startc, int const endc, 3067 int const startc, int const endc,
3068 Var * const v, GNode * const ctxt, VarEvalFlags const eflags, 3068 Var * const v, GNode * const ctxt, VarEvalFlags const eflags,
3069 int * const lengthPtr, void ** const freePtr) 3069 int * const lengthPtr, void ** const freePtr)
3070{ 3070{
3071 ApplyModifiersState st = { 3071 ApplyModifiersState st = {
3072 startc, endc, v, ctxt, eflags, 3072 startc, endc, v, ctxt, eflags,
3073 nstr, tstr, '\0', '\0', ' ', FALSE, NULL 3073 nstr, tstr, '\0', '\0', ' ', FALSE, NULL
3074 }; 3074 };
3075 3075
3076 const char *p = tstr; 3076 const char *p = tstr;
3077 while (*p != '\0' && *p != endc) { 3077 while (*p != '\0' && *p != endc) {
3078 3078
3079 if (*p == '$') { 3079 if (*p == '$') {
3080 /* 3080 /*
3081 * We may have some complex modifiers in a variable. 3081 * We may have some complex modifiers in a variable.
3082 */ 3082 */
3083 void *freeIt; 3083 void *freeIt;
3084 const char *rval; 3084 const char *rval;
3085 int rlen; 3085 int rlen;
3086 int c; 3086 int c;
3087 3087
3088 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt); 3088 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt);
3089 3089
3090 /* 3090 /*
3091 * If we have not parsed up to st.endc or ':', 3091 * If we have not parsed up to st.endc or ':',
3092 * we are not interested. 3092 * we are not interested.
3093 */ 3093 */
3094 if (rval != NULL && *rval && 3094 if (rval != NULL && *rval &&
3095 (c = p[rlen]) != '\0' && 3095 (c = p[rlen]) != '\0' &&
3096 c != ':' && 3096 c != ':' &&
3097 c != st.endc) { 3097 c != st.endc) {
3098 free(freeIt); 3098 free(freeIt);
3099 goto apply_mods; 3099 goto apply_mods;
3100 } 3100 }
3101 3101
3102 if (DEBUG(VAR)) { 3102 if (DEBUG(VAR)) {
3103 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", 3103 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3104 rval, rlen, p, rlen, p + rlen); 3104 rval, rlen, p, rlen, p + rlen);
3105 } 3105 }
3106 3106
3107 p += rlen; 3107 p += rlen;
3108 3108
3109 if (rval != NULL && *rval) { 3109 if (rval != NULL && *rval) {
3110 int used; 3110 int used;
3111 3111
3112 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v, 3112 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3113 st.ctxt, st.eflags, &used, freePtr); 3113 st.ctxt, st.eflags, &used, freePtr);
3114 if (st.nstr == var_Error 3114 if (st.nstr == var_Error
3115 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0) 3115 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0)
3116 || strlen(rval) != (size_t) used) { 3116 || strlen(rval) != (size_t) used) {
3117 free(freeIt); 3117 free(freeIt);
3118 goto out; /* error already reported */ 3118 goto out; /* error already reported */
3119 } 3119 }
3120 } 3120 }
3121 free(freeIt); 3121 free(freeIt);
3122 if (*p == ':') 3122 if (*p == ':')
3123 p++; 3123 p++;
3124 else if (*p == '\0' && endc != '\0') { 3124 else if (*p == '\0' && endc != '\0') {
3125 Error("Unclosed variable specification after complex " 3125 Error("Unclosed variable specification after complex "
3126 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3126 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3127 goto out; 3127 goto out;
3128 } 3128 }
3129 continue; 3129 continue;
3130 } 3130 }
3131 apply_mods: 3131 apply_mods:
3132 if (DEBUG(VAR)) { 3132 if (DEBUG(VAR)) {
3133 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, 3133 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3134 *p, st.nstr); 3134 *p, st.nstr);
3135 } 3135 }
3136 st.newStr = var_Error; 3136 st.newStr = var_Error;
3137 char modifier = *p; 3137 char modifier = *p;
3138 switch (modifier) { 3138 switch (modifier) {
3139 case ':': 3139 case ':':
3140 { 3140 {
3141 int res = ApplyModifier_Assign(p, &st); 3141 int res = ApplyModifier_Assign(p, &st);
3142 if (res == 'b') 3142 if (res == 'b')
3143 goto bad_modifier; 3143 goto bad_modifier;
3144 if (res == 'c') 3144 if (res == 'c')
3145 goto cleanup; 3145 goto cleanup;
3146 if (res == 'd') 3146 if (res == 'd')
3147 goto default_case; 3147 goto default_case;
3148 break; 3148 break;
3149 } 3149 }
3150 case '@': 3150 case '@':
3151 if (!ApplyModifier_Loop(p, &st)) 3151 if (!ApplyModifier_Loop(p, &st))
3152 goto cleanup; 3152 goto cleanup;
3153 break; 3153 break;
3154 case '_': 3154 case '_':
3155 if (!ApplyModifier_Remember(p, &st)) 3155 if (!ApplyModifier_Remember(p, &st))
3156 goto default_case; 3156 goto default_case;
3157 break; 3157 break;
3158 case 'D': 3158 case 'D':
3159 case 'U': 3159 case 'U':
3160 ApplyModifier_Defined(p, &st); 3160 ApplyModifier_Defined(p, &st);
3161 break; 3161 break;
3162 case 'L': 3162 case 'L':
3163 { 3163 {
3164 if (st.v->flags & VAR_JUNK) 3164 if (st.v->flags & VAR_JUNK)
3165 st.v->flags |= VAR_KEEP; 3165 st.v->flags |= VAR_KEEP;
3166 st.newStr = bmake_strdup(st.v->name); 3166 st.newStr = bmake_strdup(st.v->name);
3167 st.cp = p + 1; 3167 st.next = p + 1;
3168 st.termc = *st.cp; 3168 st.termc = *st.next;
3169 break; 3169 break;
3170 } 3170 }
3171 case 'P': 3171 case 'P':
3172 ApplyModifier_Path(p, &st); 3172 ApplyModifier_Path(p, &st);
3173 break; 3173 break;
3174 case '!': 3174 case '!':
3175 if (!ApplyModifier_Exclam(p, &st)) 3175 if (!ApplyModifier_Exclam(p, &st))
3176 goto cleanup; 3176 goto cleanup;
3177 break; 3177 break;
3178 case '[': 3178 case '[':
3179 { 3179 {
3180 int res = ApplyModifier_Words(p, &st); 3180 int res = ApplyModifier_Words(p, &st);
3181 if (res == 'b') 3181 if (res == 'b')
3182 goto bad_modifier; 3182 goto bad_modifier;
3183 if (res == 'c') 3183 if (res == 'c')
3184 goto cleanup; 3184 goto cleanup;
3185 break; 3185 break;
3186 } 3186 }
3187 case 'g': 3187 case 'g':
3188 if (!ApplyModifier_Gmtime(p, &st)) 3188 if (!ApplyModifier_Gmtime(p, &st))
3189 goto default_case; 3189 goto default_case;
3190 break; 3190 break;
3191 case 'h': 3191 case 'h':
3192 if (!ApplyModifier_Hash(p, &st)) 3192 if (!ApplyModifier_Hash(p, &st))
3193 goto default_case; 3193 goto default_case;
3194 break; 3194 break;
3195 case 'l': 3195 case 'l':
3196 if (!ApplyModifier_Localtime(p, &st)) 3196 if (!ApplyModifier_Localtime(p, &st))
3197 goto default_case; 3197 goto default_case;
3198 break; 3198 break;
3199 case 't': 3199 case 't':
3200 if (!ApplyModifier_To(p, &st)) 3200 if (!ApplyModifier_To(p, &st))
3201 goto bad_modifier; 3201 goto bad_modifier;
3202 break; 3202 break;
3203 case 'N': 3203 case 'N':
3204 case 'M': 3204 case 'M':
3205 ApplyModifier_Match(p, &st); 3205 ApplyModifier_Match(p, &st);
3206 break; 3206 break;
3207 case 'S': 3207 case 'S':
3208 if (!ApplyModifier_Subst(p, &st)) 3208 if (!ApplyModifier_Subst(p, &st))
3209 goto cleanup; 3209 goto cleanup;
3210 break; 3210 break;
3211 case '?': 3211 case '?':
3212 if (!ApplyModifier_IfElse(p, &st)) 3212 if (!ApplyModifier_IfElse(p, &st))
3213 goto cleanup; 3213 goto cleanup;
3214 break; 3214 break;
3215#ifndef NO_REGEX 3215#ifndef NO_REGEX
3216 case 'C': 3216 case 'C':
3217 if (!ApplyModifier_Regex(p, &st)) 3217 if (!ApplyModifier_Regex(p, &st))
3218 goto cleanup; 3218 goto cleanup;
3219 break; 3219 break;
3220#endif 3220#endif
3221 case 'q': 3221 case 'q':
3222 case 'Q': 3222 case 'Q':
3223 if (p[1] == st.endc || p[1] == ':') { 3223 if (p[1] == st.endc || p[1] == ':') {
3224 st.newStr = VarQuote(st.nstr, modifier == 'q'); 3224 st.newStr = VarQuote(st.nstr, modifier == 'q');
3225 st.cp = p + 1; 3225 st.next = p + 1;
3226 st.termc = *st.cp; 3226 st.termc = *st.next;
3227 break; 3227 break;
3228 } 3228 }
3229 goto default_case; 3229 goto default_case;
3230 case 'T': 3230 case 'T':
3231 if (p[1] == st.endc || p[1] == ':') { 3231 if (p[1] == st.endc || p[1] == ':') {
3232 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3232 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3233 st.nstr, ModifyWord_Tail, NULL); 3233 st.nstr, ModifyWord_Tail, NULL);
3234 st.cp = p + 1; 3234 st.next = p + 1;
3235 st.termc = *st.cp; 3235 st.termc = *st.next;
3236 break; 3236 break;
3237 } 3237 }
3238 goto default_case; 3238 goto default_case;
3239 case 'H': 3239 case 'H':
3240 if (p[1] == st.endc || p[1] == ':') { 3240 if (p[1] == st.endc || p[1] == ':') {
3241 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3241 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3242 st.nstr, ModifyWord_Head, NULL); 3242 st.nstr, ModifyWord_Head, NULL);
3243 st.cp = p + 1; 3243 st.next = p + 1;
3244 st.termc = *st.cp; 3244 st.termc = *st.next;
3245 break; 3245 break;
3246 } 3246 }
3247 goto default_case; 3247 goto default_case;
3248 case 'E': 3248 case 'E':
3249 if (p[1] == st.endc || p[1] == ':') { 3249 if (p[1] == st.endc || p[1] == ':') {
3250 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3250 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3251 st.nstr, ModifyWord_Suffix, NULL); 3251 st.nstr, ModifyWord_Suffix, NULL);
3252 st.cp = p + 1; 3252 st.next = p + 1;
3253 st.termc = *st.cp; 3253 st.termc = *st.next;
3254 break; 3254 break;
3255 } 3255 }
3256 goto default_case; 3256 goto default_case;
3257 case 'R': 3257 case 'R':
3258 if (p[1] == st.endc || p[1] == ':') { 3258 if (p[1] == st.endc || p[1] == ':') {
3259 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3259 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3260 st.nstr, ModifyWord_Root, NULL); 3260 st.nstr, ModifyWord_Root, NULL);
3261 st.cp = p + 1; 3261 st.next = p + 1;
3262 st.termc = *st.cp; 3262 st.termc = *st.next;
3263 break; 3263 break;
3264 } 3264 }
3265 goto default_case; 3265 goto default_case;
3266 case 'r': 3266 case 'r':
3267 if (!ApplyModifier_Range(p, &st)) 3267 if (!ApplyModifier_Range(p, &st))
3268 goto default_case; 3268 goto default_case;
3269 break; 3269 break;
3270 case 'O': 3270 case 'O':
3271 if (!ApplyModifier_Order(p, &st)) 3271 if (!ApplyModifier_Order(p, &st))
3272 goto bad_modifier; 3272 goto bad_modifier;
3273 break; 3273 break;
3274 case 'u': 3274 case 'u':
3275 if (p[1] == st.endc || p[1] == ':') { 3275 if (p[1] == st.endc || p[1] == ':') {
3276 st.newStr = VarUniq(st.nstr); 3276 st.newStr = VarUniq(st.nstr);
3277 st.cp = p + 1; 3277 st.next = p + 1;
3278 st.termc = *st.cp; 3278 st.termc = *st.next;
3279 break; 3279 break;
3280 } 3280 }
3281 goto default_case; 3281 goto default_case;
3282#ifdef SUNSHCMD 3282#ifdef SUNSHCMD
3283 case 's': 3283 case 's':
3284 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { 3284 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) {
3285 const char *emsg; 3285 const char *emsg;
3286 if (st.eflags & VARE_WANTRES) { 3286 if (st.eflags & VARE_WANTRES) {
3287 st.newStr = Cmd_Exec(st.nstr, &emsg); 3287 st.newStr = Cmd_Exec(st.nstr, &emsg);
3288 if (emsg) 3288 if (emsg)
3289 Error(emsg, st.nstr); 3289 Error(emsg, st.nstr);
3290 } else 3290 } else
3291 st.newStr = varNoError; 3291 st.newStr = varNoError;
3292 st.cp = p + 2; 3292 st.next = p + 2;
3293 st.termc = *st.cp; 3293 st.termc = *st.next;
3294 break; 3294 break;
3295 } 3295 }
3296 goto default_case; 3296 goto default_case;
3297#endif 3297#endif
3298 default: 3298 default:
3299 default_case: 3299 default_case:
3300 { 3300 {
3301#ifdef SYSVVARSUB 3301#ifdef SYSVVARSUB
3302 int res = ApplyModifier_SysV(p, &st); 3302 int res = ApplyModifier_SysV(p, &st);
3303 if (res == 'c') 3303 if (res == 'c')
3304 goto cleanup; 3304 goto cleanup;
3305 if (res != '=') 3305 if (res != '=')
3306#endif 3306#endif
3307 { 3307 {
3308 Error("Unknown modifier '%c'", *p); 3308 Error("Unknown modifier '%c'", *p);
3309 for (st.cp = p + 1; 3309 for (st.next = p + 1;
3310 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; 3310 *st.next != ':' && *st.next != st.endc &&
3311 st.cp++) 3311 *st.next != '\0';
 3312 st.next++)
3312 continue; 3313 continue;
3313 st.termc = *st.cp; 3314 st.termc = *st.next;
3314 st.newStr = var_Error; 3315 st.newStr = var_Error;
3315 } 3316 }
3316 } 3317 }
3317 } 3318 }
3318 if (DEBUG(VAR)) { 3319 if (DEBUG(VAR)) {
3319 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", 3320 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3320 st.v->name, modifier, st.newStr); 3321 st.v->name, modifier, st.newStr);
3321 } 3322 }
3322 3323
3323 if (st.newStr != st.nstr) { 3324 if (st.newStr != st.nstr) {
3324 if (*freePtr) { 3325 if (*freePtr) {
3325 free(st.nstr); 3326 free(st.nstr);
3326 *freePtr = NULL; 3327 *freePtr = NULL;
3327 } 3328 }
3328 st.nstr = st.newStr; 3329 st.nstr = st.newStr;
3329 if (st.nstr != var_Error && st.nstr != varNoError) { 3330 if (st.nstr != var_Error && st.nstr != varNoError) {
3330 *freePtr = st.nstr; 3331 *freePtr = st.nstr;
3331 } 3332 }
3332 } 3333 }
3333 if (st.termc == '\0' && st.endc != '\0') { 3334 if (st.termc == '\0' && st.endc != '\0') {
3334 Error("Unclosed variable specification (expecting '%c') " 3335 Error("Unclosed variable specification (expecting '%c') "
3335 "for \"%s\" (value \"%s\") modifier %c", 3336 "for \"%s\" (value \"%s\") modifier %c",
3336 st.endc, st.v->name, st.nstr, modifier); 3337 st.endc, st.v->name, st.nstr, modifier);
3337 } else if (st.termc == ':') { 3338 } else if (st.termc == ':') {
3338 st.cp++; 3339 st.next++;
3339 } 3340 }
3340 p = st.cp; 3341 p = st.next;
3341 } 3342 }
3342out: 3343out:
3343 *lengthPtr = p - tstr; 3344 *lengthPtr = p - tstr;
3344 return st.nstr; 3345 return st.nstr;
3345 3346
3346bad_modifier: 3347bad_modifier:
3347 Error("Bad modifier `:%.*s' for %s", 3348 Error("Bad modifier `:%.*s' for %s",
3348 (int)strcspn(p, ":)}"), p, st.v->name); 3349 (int)strcspn(p, ":)}"), p, st.v->name);
3349 3350
3350cleanup: 3351cleanup:
3351 *lengthPtr = st.cp - tstr; 3352 *lengthPtr = st.next - tstr;
3352 if (st.missing_delim != '\0') 3353 if (st.missing_delim != '\0')
3353 Error("Unclosed substitution for %s (%c missing)", 3354 Error("Unclosed substitution for %s (%c missing)",
3354 st.v->name, st.missing_delim); 3355 st.v->name, st.missing_delim);
3355 free(*freePtr); 3356 free(*freePtr);
3356 *freePtr = NULL; 3357 *freePtr = NULL;
3357 return var_Error; 3358 return var_Error;
3358} 3359}
3359 3360
3360static Boolean 3361static Boolean
3361VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) 3362VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen)
3362{ 3363{
3363 if ((namelen == 1 || 3364 if ((namelen == 1 ||
3364 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && 3365 (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) &&
3365 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3366 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3366 { 3367 {
3367 /* 3368 /*
3368 * If substituting a local variable in a non-local context, 3369 * If substituting a local variable in a non-local context,
3369 * assume it's for dynamic source stuff. We have to handle 3370 * assume it's for dynamic source stuff. We have to handle
3370 * this specially and return the longhand for the variable 3371 * this specially and return the longhand for the variable
3371 * with the dollar sign escaped so it makes it back to the 3372 * with the dollar sign escaped so it makes it back to the
3372 * caller. Only four of the local variables are treated 3373 * caller. Only four of the local variables are treated
3373 * specially as they are the only four that will be set 3374 * specially as they are the only four that will be set
3374 * when dynamic sources are expanded. 3375 * when dynamic sources are expanded.
3375 */ 3376 */
3376 switch (varname[0]) { 3377 switch (varname[0]) {
3377 case '@': 3378 case '@':
3378 case '%': 3379 case '%':
3379 case '*': 3380 case '*':
3380 case '!': 3381 case '!':
3381 return TRUE; 3382 return TRUE;
3382 } 3383 }
3383 return FALSE; 3384 return FALSE;
3384 } 3385 }
3385 3386
3386 if ((namelen == 7 || namelen == 8) && varname[0] == '.' && 3387 if ((namelen == 7 || namelen == 8) && varname[0] == '.' &&
3387 isupper((unsigned char) varname[1]) && 3388 isupper((unsigned char) varname[1]) &&
3388 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3389 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3389 { 3390 {
3390 return strcmp(varname, ".TARGET") == 0 || 3391 return strcmp(varname, ".TARGET") == 0 ||
3391 strcmp(varname, ".ARCHIVE") == 0 || 3392 strcmp(varname, ".ARCHIVE") == 0 ||
3392 strcmp(varname, ".PREFIX") == 0 || 3393 strcmp(varname, ".PREFIX") == 0 ||
3393 strcmp(varname, ".MEMBER") == 0; 3394 strcmp(varname, ".MEMBER") == 0;
3394 } 3395 }
3395 3396
3396 return FALSE; 3397 return FALSE;
3397} 3398}
3398 3399
3399/*- 3400/*-
3400 *----------------------------------------------------------------------- 3401 *-----------------------------------------------------------------------
3401 * Var_Parse -- 3402 * Var_Parse --
3402 * Given the start of a variable invocation (such as $v, $(VAR), 3403 * Given the start of a variable invocation (such as $v, $(VAR),
3403 * ${VAR:Mpattern}), extract the variable name, possibly some 3404 * ${VAR:Mpattern}), extract the variable name, possibly some
3404 * modifiers and find its value by applying the modifiers to the 3405 * modifiers and find its value by applying the modifiers to the
3405 * original value. 3406 * original value.
3406 * 3407 *
3407 * Input: 3408 * Input:
3408 * str The string to parse 3409 * str The string to parse
3409 * ctxt The context for the variable 3410 * ctxt The context for the variable
3410 * flags VARE_UNDEFERR if undefineds are an error 3411 * flags VARE_UNDEFERR if undefineds are an error
3411 * VARE_WANTRES if we actually want the result 3412 * VARE_WANTRES if we actually want the result
3412 * VARE_ASSIGN if we are in a := assignment 3413 * VARE_ASSIGN if we are in a := assignment
3413 * lengthPtr OUT: The length of the specification 3414 * lengthPtr OUT: The length of the specification
3414 * freePtr OUT: Non-NULL if caller should free *freePtr 3415 * freePtr OUT: Non-NULL if caller should free *freePtr
3415 * 3416 *
3416 * Results: 3417 * Results:
3417 * The (possibly-modified) value of the variable or var_Error if the 3418 * The (possibly-modified) value of the variable or var_Error if the
3418 * specification is invalid. The length of the specification is 3419 * specification is invalid. The length of the specification is
3419 * placed in *lengthPtr (for invalid specifications, this is just 3420 * placed in *lengthPtr (for invalid specifications, this is just
3420 * 2...?). 3421 * 2...?).
3421 * If *freePtr is non-NULL then it's a pointer that the caller 3422 * If *freePtr is non-NULL then it's a pointer that the caller
3422 * should pass to free() to free memory used by the result. 3423 * should pass to free() to free memory used by the result.
3423 * 3424 *
3424 * Side Effects: 3425 * Side Effects:
3425 * None. 3426 * None.
3426 * 3427 *
3427 *----------------------------------------------------------------------- 3428 *-----------------------------------------------------------------------
3428 */ 3429 */
3429/* coverity[+alloc : arg-*4] */ 3430/* coverity[+alloc : arg-*4] */
3430const char * 3431const char *
3431Var_Parse(const char * const str, GNode *ctxt, VarEvalFlags eflags, 3432Var_Parse(const char * const str, GNode *ctxt, VarEvalFlags eflags,
3432 int *lengthPtr, void **freePtr) 3433 int *lengthPtr, void **freePtr)
3433{ 3434{
3434 const char *tstr; /* Pointer into str */ 3435 const char *tstr; /* Pointer into str */
3435 Var *v; /* Variable in invocation */ 3436 Var *v; /* Variable in invocation */
3436 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3437 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3437 char endc; /* Ending character when variable in parens 3438 char endc; /* Ending character when variable in parens
3438 * or braces */ 3439 * or braces */
3439 char startc; /* Starting character when variable in parens 3440 char startc; /* Starting character when variable in parens
3440 * or braces */ 3441 * or braces */
3441 char *nstr; /* New string, used during expansion */ 3442 char *nstr; /* New string, used during expansion */
3442 Boolean dynamic; /* TRUE if the variable is local and we're 3443 Boolean dynamic; /* TRUE if the variable is local and we're
3443 * expanding it in a non-local context. This 3444 * expanding it in a non-local context. This
3444 * is done to support dynamic sources. The 3445 * is done to support dynamic sources. The
3445 * result is just the invocation, unaltered */ 3446 * result is just the invocation, unaltered */
3446 const char *extramodifiers; /* extra modifiers to apply first */ 3447 const char *extramodifiers; /* extra modifiers to apply first */
3447 3448
3448 *freePtr = NULL; 3449 *freePtr = NULL;
3449 extramodifiers = NULL; 3450 extramodifiers = NULL;
3450 dynamic = FALSE; 3451 dynamic = FALSE;
3451 3452
3452 startc = str[1]; 3453 startc = str[1];
3453 if (startc != PROPEN && startc != BROPEN) { 3454 if (startc != PROPEN && startc != BROPEN) {
3454 /* 3455 /*
3455 * If it's not bounded by braces of some sort, life is much simpler. 3456 * If it's not bounded by braces of some sort, life is much simpler.
3456 * We just need to check for the first character and return the 3457 * We just need to check for the first character and return the
3457 * value if it exists. 3458 * value if it exists.
3458 */ 3459 */
3459 3460
3460 /* Error out some really stupid names */ 3461 /* Error out some really stupid names */
3461 if (startc == '\0' || strchr(")}:$", startc)) { 3462 if (startc == '\0' || strchr(")}:$", startc)) {
3462 *lengthPtr = 1; 3463 *lengthPtr = 1;
3463 return var_Error; 3464 return var_Error;
3464 } 3465 }
3465 char name[] = { startc, '\0' }; 3466 char name[] = { startc, '\0' };
3466 3467
3467 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3468 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3468 if (v == NULL) { 3469 if (v == NULL) {
3469 *lengthPtr = 2; 3470 *lengthPtr = 2;
3470 3471
3471 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 3472 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3472 /* 3473 /*
3473 * If substituting a local variable in a non-local context, 3474 * If substituting a local variable in a non-local context,
3474 * assume it's for dynamic source stuff. We have to handle 3475 * assume it's for dynamic source stuff. We have to handle
3475 * this specially and return the longhand for the variable 3476 * this specially and return the longhand for the variable
3476 * with the dollar sign escaped so it makes it back to the 3477 * with the dollar sign escaped so it makes it back to the
3477 * caller. Only four of the local variables are treated 3478 * caller. Only four of the local variables are treated
3478 * specially as they are the only four that will be set 3479 * specially as they are the only four that will be set
3479 * when dynamic sources are expanded. 3480 * when dynamic sources are expanded.
3480 */ 3481 */
3481 switch (str[1]) { 3482 switch (str[1]) {
3482 case '@': 3483 case '@':
3483 return "$(.TARGET)"; 3484 return "$(.TARGET)";
3484 case '%': 3485 case '%':
3485 return "$(.MEMBER)"; 3486 return "$(.MEMBER)";
3486 case '*': 3487 case '*':
3487 return "$(.PREFIX)"; 3488 return "$(.PREFIX)";
3488 case '!': 3489 case '!':
3489 return "$(.ARCHIVE)"; 3490 return "$(.ARCHIVE)";
3490 } 3491 }
3491 } 3492 }
3492 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError; 3493 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError;
3493 } else { 3494 } else {
3494 haveModifier = FALSE; 3495 haveModifier = FALSE;
3495 tstr = str + 1; 3496 tstr = str + 1;
3496 endc = str[1]; 3497 endc = str[1];
3497 } 3498 }
3498 } else { 3499 } else {
3499 Buffer namebuf; /* Holds the variable name */ 3500 Buffer namebuf; /* Holds the variable name */
3500 int depth = 1; 3501 int depth = 1;
3501 3502
3502 endc = startc == PROPEN ? PRCLOSE : BRCLOSE; 3503 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3503 Buf_Init(&namebuf, 0); 3504 Buf_Init(&namebuf, 0);
3504 3505
3505 /* 3506 /*
3506 * Skip to the end character or a colon, whichever comes first. 3507 * Skip to the end character or a colon, whichever comes first.
3507 */ 3508 */
3508 for (tstr = str + 2; *tstr != '\0'; tstr++) { 3509 for (tstr = str + 2; *tstr != '\0'; tstr++) {
3509 /* Track depth so we can spot parse errors. */ 3510 /* Track depth so we can spot parse errors. */
3510 if (*tstr == startc) 3511 if (*tstr == startc)
3511 depth++; 3512 depth++;
3512 if (*tstr == endc) { 3513 if (*tstr == endc) {
3513 if (--depth == 0) 3514 if (--depth == 0)
3514 break; 3515 break;
3515 } 3516 }
3516 if (depth == 1 && *tstr == ':') 3517 if (depth == 1 && *tstr == ':')
3517 break; 3518 break;
3518 /* A variable inside a variable, expand. */ 3519 /* A variable inside a variable, expand. */
3519 if (*tstr == '$') { 3520 if (*tstr == '$') {
3520 int rlen; 3521 int rlen;
3521 void *freeIt; 3522 void *freeIt;
3522 const char *rval = Var_Parse(tstr, ctxt, eflags, &rlen, &freeIt); 3523 const char *rval = Var_Parse(tstr, ctxt, eflags, &rlen, &freeIt);
3523 if (rval != NULL) 3524 if (rval != NULL)
3524 Buf_AddStr(&namebuf, rval); 3525 Buf_AddStr(&namebuf, rval);
3525 free(freeIt); 3526 free(freeIt);
3526 tstr += rlen - 1; 3527 tstr += rlen - 1;
3527 } else 3528 } else
3528 Buf_AddByte(&namebuf, *tstr); 3529 Buf_AddByte(&namebuf, *tstr);
3529 } 3530 }
3530 if (*tstr == ':') { 3531 if (*tstr == ':') {
3531 haveModifier = TRUE; 3532 haveModifier = TRUE;
3532 } else if (*tstr == endc) { 3533 } else if (*tstr == endc) {
3533 haveModifier = FALSE; 3534 haveModifier = FALSE;
3534 } else { 3535 } else {
3535 /* 3536 /*
3536 * If we never did find the end character, return NULL 3537 * If we never did find the end character, return NULL
3537 * right now, setting the length to be the distance to 3538 * right now, setting the length to be the distance to
3538 * the end of the string, since that's what make does. 3539 * the end of the string, since that's what make does.
3539 */ 3540 */
3540 *lengthPtr = tstr - str; 3541 *lengthPtr = tstr - str;
3541 Buf_Destroy(&namebuf, TRUE); 3542 Buf_Destroy(&namebuf, TRUE);
3542 return var_Error; 3543 return var_Error;
3543 } 3544 }
3544 3545
3545 int namelen; 3546 int namelen;
3546 char *varname = Buf_GetAll(&namebuf, &namelen); 3547 char *varname = Buf_GetAll(&namebuf, &namelen);
3547 3548
3548 /* 3549 /*
3549 * At this point, varname points into newly allocated memory from 3550 * At this point, varname points into newly allocated memory from
3550 * namebuf, containing only the name of the variable. 3551 * namebuf, containing only the name of the variable.
3551 * 3552 *
3552 * start and tstr point into the const string that was pointed 3553 * start and tstr point into the const string that was pointed
3553 * to by the original value of the str parameter. start points 3554 * to by the original value of the str parameter. start points
3554 * to the '$' at the beginning of the string, while tstr points 3555 * to the '$' at the beginning of the string, while tstr points
3555 * to the char just after the end of the variable name -- this 3556 * to the char just after the end of the variable name -- this
3556 * will be '\0', ':', PRCLOSE, or BRCLOSE. 3557 * will be '\0', ':', PRCLOSE, or BRCLOSE.
3557 */ 3558 */
3558 3559
3559 v = VarFind(varname, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3560 v = VarFind(varname, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3560 /* 3561 /*
3561 * Check also for bogus D and F forms of local variables since we're 3562 * Check also for bogus D and F forms of local variables since we're
3562 * in a local context and the name is the right length. 3563 * in a local context and the name is the right length.
3563 */ 3564 */
3564 if (v == NULL && ctxt != VAR_CMD && ctxt != VAR_GLOBAL && 3565 if (v == NULL && ctxt != VAR_CMD && ctxt != VAR_GLOBAL &&
3565 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3566 namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3566 strchr("@%?*!<>", varname[0]) != NULL) { 3567 strchr("@%?*!<>", varname[0]) != NULL) {
3567 /* 3568 /*
3568 * Well, it's local -- go look for it. 3569 * Well, it's local -- go look for it.
3569 */ 3570 */
3570 char name[] = {varname[0], '\0' }; 3571 char name[] = {varname[0], '\0' };
3571 v = VarFind(name, ctxt, 0); 3572 v = VarFind(name, ctxt, 0);
3572 3573
3573 if (v != NULL) { 3574 if (v != NULL) {
3574 if (varname[1] == 'D') { 3575 if (varname[1] == 'D') {
3575 extramodifiers = "H:"; 3576 extramodifiers = "H:";
3576 } else { /* F */ 3577 } else { /* F */
3577 extramodifiers = "T:"; 3578 extramodifiers = "T:";
3578 } 3579 }
3579 } 3580 }
3580 } 3581 }
3581 3582
3582 if (v == NULL) { 3583 if (v == NULL) {
3583 dynamic = VarIsDynamic(ctxt, varname, namelen); 3584 dynamic = VarIsDynamic(ctxt, varname, namelen);
3584 3585
3585 if (!haveModifier) { 3586 if (!haveModifier) {
3586 /* 3587 /*
3587 * No modifiers -- have specification length so we can return 3588 * No modifiers -- have specification length so we can return
3588 * now. 3589 * now.
3589 */ 3590 */
3590 *lengthPtr = tstr - str + 1; 3591 *lengthPtr = tstr - str + 1;
3591 if (dynamic) { 3592 if (dynamic) {
3592 char *pstr = bmake_strndup(str, *lengthPtr); 3593 char *pstr = bmake_strndup(str, *lengthPtr);
3593 *freePtr = pstr; 3594 *freePtr = pstr;
3594 Buf_Destroy(&namebuf, TRUE); 3595 Buf_Destroy(&namebuf, TRUE);
3595 return pstr; 3596 return pstr;
3596 } else { 3597 } else {
3597 Buf_Destroy(&namebuf, TRUE); 3598 Buf_Destroy(&namebuf, TRUE);
3598 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError; 3599 return (eflags & VARE_UNDEFERR) ? var_Error : varNoError;
3599 } 3600 }
3600 } else { 3601 } else {
3601 /* 3602 /*
3602 * Still need to get to the end of the variable specification, 3603 * Still need to get to the end of the variable specification,
3603 * so kludge up a Var structure for the modifications 3604 * so kludge up a Var structure for the modifications
3604 */ 3605 */
3605 v = bmake_malloc(sizeof(Var)); 3606 v = bmake_malloc(sizeof(Var));
3606 v->name = varname; 3607 v->name = varname;
3607 Buf_Init(&v->val, 1); 3608 Buf_Init(&v->val, 1);
3608 v->flags = VAR_JUNK; 3609 v->flags = VAR_JUNK;
3609 Buf_Destroy(&namebuf, FALSE); 3610 Buf_Destroy(&namebuf, FALSE);
3610 } 3611 }
3611 } else 3612 } else
3612 Buf_Destroy(&namebuf, TRUE); 3613 Buf_Destroy(&namebuf, TRUE);
3613 } 3614 }
3614 3615
3615 if (v->flags & VAR_IN_USE) { 3616 if (v->flags & VAR_IN_USE) {
3616 Fatal("Variable %s is recursive.", v->name); 3617 Fatal("Variable %s is recursive.", v->name);
3617 /*NOTREACHED*/ 3618 /*NOTREACHED*/
3618 } else { 3619 } else {
3619 v->flags |= VAR_IN_USE; 3620 v->flags |= VAR_IN_USE;
3620 } 3621 }
3621 /* 3622 /*
3622 * Before doing any modification, we have to make sure the value 3623 * Before doing any modification, we have to make sure the value
3623 * has been fully expanded. If it looks like recursion might be 3624 * has been fully expanded. If it looks like recursion might be
3624 * necessary (there's a dollar sign somewhere in the variable's value) 3625 * necessary (there's a dollar sign somewhere in the variable's value)
3625 * we just call Var_Subst to do any other substitutions that are 3626 * we just call Var_Subst to do any other substitutions that are
3626 * necessary. Note that the value returned by Var_Subst will have 3627 * necessary. Note that the value returned by Var_Subst will have
3627 * been dynamically-allocated, so it will need freeing when we 3628 * been dynamically-allocated, so it will need freeing when we
3628 * return. 3629 * return.
3629 */ 3630 */
3630 nstr = Buf_GetAll(&v->val, NULL); 3631 nstr = Buf_GetAll(&v->val, NULL);
3631 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES) != 0) { 3632 if (strchr(nstr, '$') != NULL && (eflags & VARE_WANTRES) != 0) {
3632 nstr = Var_Subst(NULL, nstr, ctxt, eflags); 3633 nstr = Var_Subst(NULL, nstr, ctxt, eflags);
3633 *freePtr = nstr; 3634 *freePtr = nstr;
3634 } 3635 }
3635 3636
3636 v->flags &= ~VAR_IN_USE; 3637 v->flags &= ~VAR_IN_USE;
3637 3638
3638 if (nstr != NULL && (haveModifier || extramodifiers != NULL)) { 3639 if (nstr != NULL && (haveModifier || extramodifiers != NULL)) {
3639 void *extraFree; 3640 void *extraFree;
3640 int used; 3641 int used;
3641 3642
3642 extraFree = NULL; 3643 extraFree = NULL;
3643 if (extramodifiers != NULL) { 3644 if (extramodifiers != NULL) {
3644 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', 3645 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
3645 v, ctxt, eflags, &used, &extraFree); 3646 v, ctxt, eflags, &used, &extraFree);
3646 } 3647 }
3647 3648
3648 if (haveModifier) { 3649 if (haveModifier) {
3649 /* Skip initial colon. */ 3650 /* Skip initial colon. */
3650 tstr++; 3651 tstr++;
3651 3652
3652 nstr = ApplyModifiers(nstr, tstr, startc, endc, 3653 nstr = ApplyModifiers(nstr, tstr, startc, endc,
3653 v, ctxt, eflags, &used, freePtr); 3654 v, ctxt, eflags, &used, freePtr);
3654 tstr += used; 3655 tstr += used;
3655 free(extraFree); 3656 free(extraFree);
3656 } else { 3657 } else {
3657 *freePtr = extraFree; 3658 *freePtr = extraFree;
3658 } 3659 }
3659 } 3660 }
3660 *lengthPtr = tstr - str + (*tstr ? 1 : 0); 3661 *lengthPtr = tstr - str + (*tstr ? 1 : 0);
3661 3662
3662 if (v->flags & VAR_FROM_ENV) { 3663 if (v->flags & VAR_FROM_ENV) {
3663 Boolean destroy = FALSE; 3664 Boolean destroy = FALSE;
3664 3665
3665 if (nstr != Buf_GetAll(&v->val, NULL)) { 3666 if (nstr != Buf_GetAll(&v->val, NULL)) {
3666 destroy = TRUE; 3667 destroy = TRUE;
3667 } else { 3668 } else {
3668 /* 3669 /*
3669 * Returning the value unmodified, so tell the caller to free 3670 * Returning the value unmodified, so tell the caller to free
3670 * the thing. 3671 * the thing.
3671 */ 3672 */
3672 *freePtr = nstr; 3673 *freePtr = nstr;
3673 } 3674 }
3674 VarFreeEnv(v, destroy); 3675 VarFreeEnv(v, destroy);
3675 } else if (v->flags & VAR_JUNK) { 3676 } else if (v->flags & VAR_JUNK) {
3676 /* 3677 /*
3677 * Perform any free'ing needed and set *freePtr to NULL so the caller 3678 * Perform any free'ing needed and set *freePtr to NULL so the caller
3678 * doesn't try to free a static pointer. 3679 * doesn't try to free a static pointer.
3679 * If VAR_KEEP is also set then we want to keep str(?) as is. 3680 * If VAR_KEEP is also set then we want to keep str(?) as is.
3680 */ 3681 */
3681 if (!(v->flags & VAR_KEEP)) { 3682 if (!(v->flags & VAR_KEEP)) {
3682 if (*freePtr) { 3683 if (*freePtr) {
3683 free(nstr); 3684 free(nstr);
3684 *freePtr = NULL; 3685 *freePtr = NULL;
3685 } 3686 }
3686 if (dynamic) { 3687 if (dynamic) {
3687 nstr = bmake_strndup(str, *lengthPtr); 3688 nstr = bmake_strndup(str, *lengthPtr);
3688 *freePtr = nstr; 3689 *freePtr = nstr;
3689 } else { 3690 } else {
3690 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varNoError; 3691 nstr = (eflags & VARE_UNDEFERR) ? var_Error : varNoError;
3691 } 3692 }
3692 } 3693 }
3693 if (nstr != Buf_GetAll(&v->val, NULL)) 3694 if (nstr != Buf_GetAll(&v->val, NULL))
3694 Buf_Destroy(&v->val, TRUE); 3695 Buf_Destroy(&v->val, TRUE);
3695 free(v->name); 3696 free(v->name);
3696 free(v); 3697 free(v);
3697 } 3698 }
3698 return nstr; 3699 return nstr;
3699} 3700}
3700 3701
3701/*- 3702/*-
3702 *----------------------------------------------------------------------- 3703 *-----------------------------------------------------------------------
3703 * Var_Subst -- 3704 * Var_Subst --
3704 * Substitute for all variables in the given string in the given context. 3705 * Substitute for all variables in the given string in the given context.
3705 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3706 * If eflags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3706 * variable is encountered. 3707 * variable is encountered.
3707 * 3708 *
3708 * Input: 3709 * Input:
3709 * var Named variable || NULL for all 3710 * var Named variable || NULL for all
3710 * str the string which to substitute 3711 * str the string which to substitute
3711 * ctxt the context wherein to find variables 3712 * ctxt the context wherein to find variables
3712 * eflags VARE_UNDEFERR if undefineds are an error 3713 * eflags VARE_UNDEFERR if undefineds are an error
3713 * VARE_WANTRES if we actually want the result 3714 * VARE_WANTRES if we actually want the result
3714 * VARE_ASSIGN if we are in a := assignment 3715 * VARE_ASSIGN if we are in a := assignment
3715 * 3716 *
3716 * Results: 3717 * Results:
3717 * The resulting string. 3718 * The resulting string.
3718 * 3719 *
3719 * Side Effects: 3720 * Side Effects:
3720 * None. 3721 * None.
3721 *----------------------------------------------------------------------- 3722 *-----------------------------------------------------------------------
3722 */ 3723 */
3723char * 3724char *
3724Var_Subst(const char *var, const char *str, GNode *ctxt, VarEvalFlags eflags) 3725Var_Subst(const char *var, const char *str, GNode *ctxt, VarEvalFlags eflags)
3725{ 3726{
3726 Buffer buf; /* Buffer for forming things */ 3727 Buffer buf; /* Buffer for forming things */
3727 const char *val; /* Value to substitute for a variable */ 3728 const char *val; /* Value to substitute for a variable */
3728 int length; /* Length of the variable invocation */ 3729 int length; /* Length of the variable invocation */
3729 Boolean trailingBslash; /* variable ends in \ */ 3730 Boolean trailingBslash; /* variable ends in \ */
3730 void *freeIt = NULL; /* Set if it should be freed */ 3731 void *freeIt = NULL; /* Set if it should be freed */
3731 static Boolean errorReported; /* Set true if an error has already 3732 static Boolean errorReported; /* Set true if an error has already
3732 * been reported to prevent a plethora 3733 * been reported to prevent a plethora
3733 * of messages when recursing */ 3734 * of messages when recursing */
3734 3735
3735 Buf_Init(&buf, 0); 3736 Buf_Init(&buf, 0);
3736 errorReported = FALSE; 3737 errorReported = FALSE;
3737 trailingBslash = FALSE; 3738 trailingBslash = FALSE;
3738 3739
3739 while (*str) { 3740 while (*str) {
3740 if (*str == '\n' && trailingBslash) 3741 if (*str == '\n' && trailingBslash)
3741 Buf_AddByte(&buf, ' '); 3742 Buf_AddByte(&buf, ' ');
3742 if (var == NULL && (*str == '$') && (str[1] == '$')) { 3743 if (var == NULL && (*str == '$') && (str[1] == '$')) {
3743 /* 3744 /*
3744 * A dollar sign may be escaped either with another dollar sign. 3745 * A dollar sign may be escaped either with another dollar sign.
3745 * In such a case, we skip over the escape character and store the 3746 * In such a case, we skip over the escape character and store the
3746 * dollar sign into the buffer directly. 3747 * dollar sign into the buffer directly.
3747 */ 3748 */
3748 if (save_dollars && (eflags & VARE_ASSIGN)) 3749 if (save_dollars && (eflags & VARE_ASSIGN))
3749 Buf_AddByte(&buf, *str); 3750 Buf_AddByte(&buf, *str);
3750 str++; 3751 str++;
3751 Buf_AddByte(&buf, *str); 3752 Buf_AddByte(&buf, *str);
3752 str++; 3753 str++;
3753 } else if (*str != '$') { 3754 } else if (*str != '$') {
3754 /* 3755 /*
3755 * Skip as many characters as possible -- either to the end of 3756 * Skip as many characters as possible -- either to the end of
3756 * the string or to the next dollar sign (variable invocation). 3757 * the string or to the next dollar sign (variable invocation).
3757 */ 3758 */
3758 const char *cp; 3759 const char *cp;
3759 3760
3760 for (cp = str++; *str != '$' && *str != '\0'; str++) 3761 for (cp = str++; *str != '$' && *str != '\0'; str++)
3761 continue; 3762 continue;
3762 Buf_AddBytesBetween(&buf, cp, str); 3763 Buf_AddBytesBetween(&buf, cp, str);
3763 } else { 3764 } else {
3764 if (var != NULL) { 3765 if (var != NULL) {
3765 int expand; 3766 int expand;
3766 for (;;) { 3767 for (;;) {
3767 if (str[1] == '\0') { 3768 if (str[1] == '\0') {
3768 /* A trailing $ is kind of a special case */ 3769 /* A trailing $ is kind of a special case */
3769 Buf_AddByte(&buf, str[0]); 3770 Buf_AddByte(&buf, str[0]);
3770 str++; 3771 str++;
3771 expand = FALSE; 3772 expand = FALSE;
3772 } else if (str[1] != PROPEN && str[1] != BROPEN) { 3773 } else if (str[1] != PROPEN && str[1] != BROPEN) {
3773 if (str[1] != *var || strlen(var) > 1) { 3774 if (str[1] != *var || strlen(var) > 1) {
3774 Buf_AddBytes(&buf, 2, str); 3775 Buf_AddBytes(&buf, 2, str);
3775 str += 2; 3776 str += 2;
3776 expand = FALSE; 3777 expand = FALSE;
3777 } else 3778 } else
3778 expand = TRUE; 3779 expand = TRUE;
3779 break; 3780 break;
3780 } else { 3781 } else {
3781 const char *p; 3782 const char *p;
3782 3783
3783 /* Scan up to the end of the variable name. */ 3784 /* Scan up to the end of the variable name. */
3784 for (p = &str[2]; *p && 3785 for (p = &str[2]; *p &&
3785 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) 3786 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
3786 if (*p == '$') 3787 if (*p == '$')
3787 break; 3788 break;
3788 /* 3789 /*
3789 * A variable inside the variable. We cannot expand 3790 * A variable inside the variable. We cannot expand
3790 * the external variable yet, so we try again with 3791 * the external variable yet, so we try again with
3791 * the nested one 3792 * the nested one
3792 */ 3793 */
3793 if (*p == '$') { 3794 if (*p == '$') {
3794 Buf_AddBytesBetween(&buf, str, p); 3795 Buf_AddBytesBetween(&buf, str, p);
3795 str = p; 3796 str = p;
3796 continue; 3797 continue;
3797 } 3798 }
3798 3799
3799 if (strncmp(var, str + 2, p - str - 2) != 0 || 3800 if (strncmp(var, str + 2, p - str - 2) != 0 ||
3800 var[p - str - 2] != '\0') { 3801 var[p - str - 2] != '\0') {
3801 /* 3802 /*
3802 * Not the variable we want to expand, scan 3803 * Not the variable we want to expand, scan
3803 * until the next variable 3804 * until the next variable
3804 */ 3805 */
3805 for (; *p != '$' && *p != '\0'; p++) 3806 for (; *p != '$' && *p != '\0'; p++)
3806 continue; 3807 continue;
3807 Buf_AddBytesBetween(&buf, str, p); 3808 Buf_AddBytesBetween(&buf, str, p);
3808 str = p; 3809 str = p;
3809 expand = FALSE; 3810 expand = FALSE;
3810 } else 3811 } else
3811 expand = TRUE; 3812 expand = TRUE;
3812 break; 3813 break;
3813 } 3814 }
3814 } 3815 }
3815 if (!expand) 3816 if (!expand)
3816 continue; 3817 continue;
3817 } 3818 }
3818 3819
3819 val = Var_Parse(str, ctxt, eflags, &length, &freeIt); 3820 val = Var_Parse(str, ctxt, eflags, &length, &freeIt);
3820 3821
3821 /* 3822 /*
3822 * When we come down here, val should either point to the 3823 * When we come down here, val should either point to the
3823 * value of this variable, suitably modified, or be NULL. 3824 * value of this variable, suitably modified, or be NULL.
3824 * Length should be the total length of the potential 3825 * Length should be the total length of the potential
3825 * variable invocation (from $ to end character...) 3826 * variable invocation (from $ to end character...)
3826 */ 3827 */
3827 if (val == var_Error || val == varNoError) { 3828 if (val == var_Error || val == varNoError) {
3828 /* 3829 /*
3829 * If performing old-time variable substitution, skip over 3830 * If performing old-time variable substitution, skip over
3830 * the variable and continue with the substitution. Otherwise, 3831 * the variable and continue with the substitution. Otherwise,
3831 * store the dollar sign and advance str so we continue with 3832 * store the dollar sign and advance str so we continue with
3832 * the string... 3833 * the string...
3833 */ 3834 */
3834 if (oldVars) { 3835 if (oldVars) {
3835 str += length; 3836 str += length;
3836 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) { 3837 } else if ((eflags & VARE_UNDEFERR) || val == var_Error) {
3837 /* 3838 /*
3838 * If variable is undefined, complain and skip the 3839 * If variable is undefined, complain and skip the
3839 * variable. The complaint will stop us from doing anything 3840 * variable. The complaint will stop us from doing anything
3840 * when the file is parsed. 3841 * when the file is parsed.
3841 */ 3842 */
3842 if (!errorReported) { 3843 if (!errorReported) {
3843 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 3844 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
3844 length, str); 3845 length, str);
3845 } 3846 }
3846 str += length; 3847 str += length;
3847 errorReported = TRUE; 3848 errorReported = TRUE;
3848 } else { 3849 } else {
3849 Buf_AddByte(&buf, *str); 3850 Buf_AddByte(&buf, *str);
3850 str += 1; 3851 str += 1;
3851 } 3852 }
3852 } else { 3853 } else {
3853 /* 3854 /*
3854 * We've now got a variable structure to store in. But first, 3855 * We've now got a variable structure to store in. But first,
3855 * advance the string pointer. 3856 * advance the string pointer.
3856 */ 3857 */
3857 str += length; 3858 str += length;
3858 3859
3859 /* 3860 /*
3860 * Copy all the characters from the variable value straight 3861 * Copy all the characters from the variable value straight
3861 * into the new string. 3862 * into the new string.
3862 */ 3863 */
3863 length = strlen(val); 3864 length = strlen(val);
3864 Buf_AddBytes(&buf, length, val); 3865 Buf_AddBytes(&buf, length, val);
3865 trailingBslash = length > 0 && val[length - 1] == '\\'; 3866 trailingBslash = length > 0 && val[length - 1] == '\\';
3866 } 3867 }
3867 free(freeIt); 3868 free(freeIt);
3868 freeIt = NULL; 3869 freeIt = NULL;
3869 } 3870 }
3870 } 3871 }
3871 3872
3872 return Buf_DestroyCompact(&buf); 3873 return Buf_DestroyCompact(&buf);
3873} 3874}
3874 3875
3875/* Initialize the module. */ 3876/* Initialize the module. */
3876void 3877void
3877Var_Init(void) 3878Var_Init(void)
3878{ 3879{
3879 VAR_INTERNAL = Targ_NewGN("Internal"); 3880 VAR_INTERNAL = Targ_NewGN("Internal");
3880 VAR_GLOBAL = Targ_NewGN("Global"); 3881 VAR_GLOBAL = Targ_NewGN("Global");
3881 VAR_CMD = Targ_NewGN("Command"); 3882 VAR_CMD = Targ_NewGN("Command");
3882} 3883}
3883 3884
3884 3885
3885void 3886void
3886Var_End(void) 3887Var_End(void)
3887{ 3888{
3888 Var_Stats(); 3889 Var_Stats();
3889} 3890}
3890 3891
3891void 3892void
3892Var_Stats(void) 3893Var_Stats(void)
3893{ 3894{
3894 Hash_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 3895 Hash_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
3895} 3896}
3896 3897
3897 3898
3898/****************** PRINT DEBUGGING INFO *****************/ 3899/****************** PRINT DEBUGGING INFO *****************/
3899static void 3900static void
3900VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED) 3901VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED)
3901{ 3902{
3902 Var *v = (Var *)vp; 3903 Var *v = (Var *)vp;
3903 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); 3904 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
3904} 3905}
3905 3906
3906/*- 3907/*-
3907 *----------------------------------------------------------------------- 3908 *-----------------------------------------------------------------------
3908 * Var_Dump -- 3909 * Var_Dump --
3909 * print all variables in a context 3910 * print all variables in a context
3910 *----------------------------------------------------------------------- 3911 *-----------------------------------------------------------------------
3911 */ 3912 */
3912void 3913void
3913Var_Dump(GNode *ctxt) 3914Var_Dump(GNode *ctxt)
3914{ 3915{
3915 Hash_ForEach(&ctxt->context, VarPrintVar, NULL); 3916 Hash_ForEach(&ctxt->context, VarPrintVar, NULL);
3916} 3917}