Sun Jul 26 19:16:18 2020 UTC ()
make(1): eliminate another local variable in Var_Parse


(rillig)
diff -r1.326 -r1.327 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/07/26 19:13:42 1.326
+++ src/usr.bin/make/var.c 2020/07/26 19:16:17 1.327
@@ -1,1078 +1,1078 @@ @@ -1,1078 +1,1078 @@
1/* $NetBSD: var.c,v 1.326 2020/07/26 19:13:42 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.327 2020/07/26 19:16:17 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.326 2020/07/26 19:13:42 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.327 2020/07/26 19:16:17 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.326 2020/07/26 19:13:42 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.327 2020/07/26 19:16:17 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 value of a variable in a context or 101 * Var_Value Return the value of a variable in a context or
102 * NULL if the variable is undefined. 102 * 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/* 139/*
140 * This lets us tell if we have replaced the original environ 140 * This lets us tell if we have replaced the original environ
141 * (which we cannot free). 141 * (which we cannot free).
142 */ 142 */
143char **savedEnv = NULL; 143char **savedEnv = NULL;
144 144
145/* 145/*
146 * This is a harmless return value for Var_Parse that can be used by Var_Subst 146 * This is a harmless return value for Var_Parse that can be used by Var_Subst
147 * to determine if there was an error in parsing -- easier than returning 147 * to determine if there was an error in parsing -- easier than returning
148 * a flag, as things outside this module don't give a hoot. 148 * a flag, as things outside this module don't give a hoot.
149 */ 149 */
150char var_Error[] = ""; 150char var_Error[] = "";
151 151
152/* 152/*
153 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for 153 * Similar to var_Error, but returned when the 'VARE_UNDEFERR' flag for
154 * Var_Parse is not set. Why not just use a constant? Well, GCC likes 154 * Var_Parse is not set. Why not just use a constant? Well, GCC likes
155 * to condense identical string instances... 155 * to condense identical string instances...
156 */ 156 */
157static char varNoError[] = ""; 157static char varNoError[] = "";
158 158
159/* 159/*
160 * Traditionally we consume $$ during := like any other expansion. 160 * Traditionally we consume $$ during := like any other expansion.
161 * Other make's do not. 161 * Other make's do not.
162 * This knob allows controlling the behavior. 162 * This knob allows controlling the behavior.
163 * FALSE to consume $$ during := assignment. 163 * FALSE to consume $$ during := assignment.
164 * TRUE to preserve $$ during := assignment. 164 * TRUE to preserve $$ during := assignment.
165 */ 165 */
166#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 166#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
167static Boolean save_dollars = TRUE; 167static Boolean save_dollars = TRUE;
168 168
169/* 169/*
170 * Internally, variables are contained in four different contexts. 170 * Internally, variables are contained in four different contexts.
171 * 1) the environment. They cannot be changed. If an environment 171 * 1) the environment. They cannot be changed. If an environment
172 * variable is appended to, the result is placed in the global 172 * variable is appended to, the result is placed in the global
173 * context. 173 * context.
174 * 2) the global context. Variables set in the Makefile are located in 174 * 2) the global context. Variables set in the Makefile are located in
175 * the global context. 175 * the global context.
176 * 3) the command-line context. All variables set on the command line 176 * 3) the command-line context. All variables set on the command line
177 * are placed in this context. They are UNALTERABLE once placed here. 177 * are placed in this context. They are UNALTERABLE once placed here.
178 * 4) the local context. Each target has associated with it a context 178 * 4) the local context. Each target has associated with it a context
179 * list. On this list are located the structures describing such 179 * list. On this list are located the structures describing such
180 * local variables as $(@) and $(*) 180 * local variables as $(@) and $(*)
181 * The four contexts are searched in the reverse order from which they are 181 * The four contexts are searched in the reverse order from which they are
182 * listed (but see checkEnvFirst). 182 * listed (but see checkEnvFirst).
183 */ 183 */
184GNode *VAR_INTERNAL; /* variables from make itself */ 184GNode *VAR_INTERNAL; /* variables from make itself */
185GNode *VAR_GLOBAL; /* variables from the makefile */ 185GNode *VAR_GLOBAL; /* variables from the makefile */
186GNode *VAR_CMD; /* variables defined on the command-line */ 186GNode *VAR_CMD; /* variables defined on the command-line */
187 187
188typedef enum { 188typedef enum {
189 FIND_CMD = 0x01, /* look in VAR_CMD when searching */ 189 FIND_CMD = 0x01, /* look in VAR_CMD when searching */
190 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ 190 FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */
191 FIND_ENV = 0x04 /* look in the environment also */ 191 FIND_ENV = 0x04 /* look in the environment also */
192} VarFindFlags; 192} VarFindFlags;
193 193
194typedef enum { 194typedef enum {
195 VAR_IN_USE = 0x01, /* Variable's value is currently being used 195 VAR_IN_USE = 0x01, /* Variable's value is currently being used
196 * by Var_Parse or Var_Subst. 196 * by Var_Parse or Var_Subst.
197 * Used to avoid endless recursion */ 197 * Used to avoid endless recursion */
198 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */ 198 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */
199 VAR_JUNK = 0x04, /* Variable is a junk variable that 199 VAR_JUNK = 0x04, /* Variable is a junk variable that
200 * should be destroyed when done with 200 * should be destroyed when done with
201 * it. Used by Var_Parse for undefined, 201 * it. Used by Var_Parse for undefined,
202 * modified variables */ 202 * modified variables */
203 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found 203 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found
204 * a use for it in some modifier and 204 * a use for it in some modifier and
205 * the value is therefore valid */ 205 * the value is therefore valid */
206 VAR_EXPORTED = 0x10, /* Variable is exported */ 206 VAR_EXPORTED = 0x10, /* Variable is exported */
207 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export. 207 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export.
208 * This would be true if it contains $'s */ 208 * This would be true if it contains $'s */
209 VAR_FROM_CMD = 0x40 /* Variable came from command line */ 209 VAR_FROM_CMD = 0x40 /* Variable came from command line */
210} Var_Flags; 210} Var_Flags;
211 211
212typedef struct Var { 212typedef struct Var {
213 char *name; /* the variable's name */ 213 char *name; /* the variable's name */
214 Buffer val; /* its value */ 214 Buffer val; /* its value */
215 Var_Flags flags; /* miscellaneous status flags */ 215 Var_Flags flags; /* miscellaneous status flags */
216} Var; 216} Var;
217 217
218/* 218/*
219 * Exporting vars is expensive so skip it if we can 219 * Exporting vars is expensive so skip it if we can
220 */ 220 */
221typedef enum { 221typedef enum {
222 VAR_EXPORTED_NONE, 222 VAR_EXPORTED_NONE,
223 VAR_EXPORTED_YES, 223 VAR_EXPORTED_YES,
224 VAR_EXPORTED_ALL 224 VAR_EXPORTED_ALL
225} VarExportedMode; 225} VarExportedMode;
226static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 226static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
227 227
228typedef enum { 228typedef enum {
229 /* 229 /*
230 * We pass this to Var_Export when doing the initial export 230 * We pass this to Var_Export when doing the initial export
231 * or after updating an exported var. 231 * or after updating an exported var.
232 */ 232 */
233 VAR_EXPORT_PARENT = 0x01, 233 VAR_EXPORT_PARENT = 0x01,
234 /* 234 /*
235 * We pass this to Var_Export1 to tell it to leave the value alone. 235 * We pass this to Var_Export1 to tell it to leave the value alone.
236 */ 236 */
237 VAR_EXPORT_LITERAL = 0x02 237 VAR_EXPORT_LITERAL = 0x02
238} VarExportFlags; 238} VarExportFlags;
239 239
240/* Flags for pattern matching in the :S and :C modifiers */ 240/* Flags for pattern matching in the :S and :C modifiers */
241typedef enum { 241typedef enum {
242 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */ 242 VARP_SUB_GLOBAL = 0x01, /* Apply substitution globally */
243 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */ 243 VARP_SUB_ONE = 0x02, /* Apply substitution to one word */
244 VARP_SUB_MATCHED = 0x04, /* There was a match */ 244 VARP_SUB_MATCHED = 0x04, /* There was a match */
245 VARP_ANCHOR_START = 0x08, /* Match at start of word */ 245 VARP_ANCHOR_START = 0x08, /* Match at start of word */
246 VARP_ANCHOR_END = 0x10 /* Match at end of word */ 246 VARP_ANCHOR_END = 0x10 /* Match at end of word */
247} VarPatternFlags; 247} VarPatternFlags;
248 248
249typedef enum { 249typedef enum {
250 VAR_NO_EXPORT = 0x01 /* do not export */ 250 VAR_NO_EXPORT = 0x01 /* do not export */
251} VarSet_Flags; 251} VarSet_Flags;
252 252
253#define BROPEN '{' 253#define BROPEN '{'
254#define BRCLOSE '}' 254#define BRCLOSE '}'
255#define PROPEN '(' 255#define PROPEN '('
256#define PRCLOSE ')' 256#define PRCLOSE ')'
257 257
258/*- 258/*-
259 *----------------------------------------------------------------------- 259 *-----------------------------------------------------------------------
260 * VarFind -- 260 * VarFind --
261 * Find the given variable in the given context and any other contexts 261 * Find the given variable in the given context and any other contexts
262 * indicated. 262 * indicated.
263 * 263 *
264 * Input: 264 * Input:
265 * name name to find 265 * name name to find
266 * ctxt context in which to find it 266 * ctxt context in which to find it
267 * flags FIND_GLOBAL look in VAR_GLOBAL as well 267 * flags FIND_GLOBAL look in VAR_GLOBAL as well
268 * FIND_CMD look in VAR_CMD as well 268 * FIND_CMD look in VAR_CMD as well
269 * FIND_ENV look in the environment as well 269 * FIND_ENV look in the environment as well
270 * 270 *
271 * Results: 271 * Results:
272 * A pointer to the structure describing the desired variable or 272 * A pointer to the structure describing the desired variable or
273 * NULL if the variable does not exist. 273 * NULL if the variable does not exist.
274 * 274 *
275 * Side Effects: 275 * Side Effects:
276 * None 276 * None
277 *----------------------------------------------------------------------- 277 *-----------------------------------------------------------------------
278 */ 278 */
279static Var * 279static Var *
280VarFind(const char *name, GNode *ctxt, VarFindFlags flags) 280VarFind(const char *name, GNode *ctxt, VarFindFlags flags)
281{ 281{
282 /* 282 /*
283 * If the variable name begins with a '.', it could very well be one of 283 * If the variable name begins with a '.', it could very well be one of
284 * the local ones. We check the name against all the local variables 284 * the local ones. We check the name against all the local variables
285 * and substitute the short version in for 'name' if it matches one of 285 * and substitute the short version in for 'name' if it matches one of
286 * them. 286 * them.
287 */ 287 */
288 if (*name == '.' && isupper((unsigned char) name[1])) { 288 if (*name == '.' && isupper((unsigned char) name[1])) {
289 switch (name[1]) { 289 switch (name[1]) {
290 case 'A': 290 case 'A':
291 if (strcmp(name, ".ALLSRC") == 0) 291 if (strcmp(name, ".ALLSRC") == 0)
292 name = ALLSRC; 292 name = ALLSRC;
293 if (strcmp(name, ".ARCHIVE") == 0) 293 if (strcmp(name, ".ARCHIVE") == 0)
294 name = ARCHIVE; 294 name = ARCHIVE;
295 break; 295 break;
296 case 'I': 296 case 'I':
297 if (strcmp(name, ".IMPSRC") == 0) 297 if (strcmp(name, ".IMPSRC") == 0)
298 name = IMPSRC; 298 name = IMPSRC;
299 break; 299 break;
300 case 'M': 300 case 'M':
301 if (strcmp(name, ".MEMBER") == 0) 301 if (strcmp(name, ".MEMBER") == 0)
302 name = MEMBER; 302 name = MEMBER;
303 break; 303 break;
304 case 'O': 304 case 'O':
305 if (strcmp(name, ".OODATE") == 0) 305 if (strcmp(name, ".OODATE") == 0)
306 name = OODATE; 306 name = OODATE;
307 break; 307 break;
308 case 'P': 308 case 'P':
309 if (strcmp(name, ".PREFIX") == 0) 309 if (strcmp(name, ".PREFIX") == 0)
310 name = PREFIX; 310 name = PREFIX;
311 break; 311 break;
312 case 'T': 312 case 'T':
313 if (strcmp(name, ".TARGET") == 0) 313 if (strcmp(name, ".TARGET") == 0)
314 name = TARGET; 314 name = TARGET;
315 break; 315 break;
316 } 316 }
317 } 317 }
318 318
319#ifdef notyet 319#ifdef notyet
320 /* for compatibility with gmake */ 320 /* for compatibility with gmake */
321 if (name[0] == '^' && name[1] == '\0') 321 if (name[0] == '^' && name[1] == '\0')
322 name = ALLSRC; 322 name = ALLSRC;
323#endif 323#endif
324 324
325 /* 325 /*
326 * First look for the variable in the given context. If it's not there, 326 * First look for the variable in the given context. If it's not there,
327 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 327 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
328 * depending on the FIND_* flags in 'flags' 328 * depending on the FIND_* flags in 'flags'
329 */ 329 */
330 Hash_Entry *var = Hash_FindEntry(&ctxt->context, name); 330 Hash_Entry *var = Hash_FindEntry(&ctxt->context, name);
331 331
332 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) { 332 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
333 var = Hash_FindEntry(&VAR_CMD->context, name); 333 var = Hash_FindEntry(&VAR_CMD->context, name);
334 } 334 }
335 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && 335 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
336 ctxt != VAR_GLOBAL) 336 ctxt != VAR_GLOBAL)
337 { 337 {
338 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 338 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
339 if (var == NULL && ctxt != VAR_INTERNAL) { 339 if (var == NULL && ctxt != VAR_INTERNAL) {
340 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 340 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
341 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 341 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
342 } 342 }
343 } 343 }
344 if (var == NULL && (flags & FIND_ENV)) { 344 if (var == NULL && (flags & FIND_ENV)) {
345 char *env; 345 char *env;
346 346
347 if ((env = getenv(name)) != NULL) { 347 if ((env = getenv(name)) != NULL) {
348 Var *v = bmake_malloc(sizeof(Var)); 348 Var *v = bmake_malloc(sizeof(Var));
349 v->name = bmake_strdup(name); 349 v->name = bmake_strdup(name);
350 350
351 int len = (int)strlen(env); 351 int len = (int)strlen(env);
352 Buf_Init(&v->val, len + 1); 352 Buf_Init(&v->val, len + 1);
353 Buf_AddBytes(&v->val, len, env); 353 Buf_AddBytes(&v->val, len, env);
354 354
355 v->flags = VAR_FROM_ENV; 355 v->flags = VAR_FROM_ENV;
356 return v; 356 return v;
357 } else if (checkEnvFirst && (flags & FIND_GLOBAL) && 357 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
358 ctxt != VAR_GLOBAL) 358 ctxt != VAR_GLOBAL)
359 { 359 {
360 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 360 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
361 if (var == NULL && ctxt != VAR_INTERNAL) { 361 if (var == NULL && ctxt != VAR_INTERNAL) {
362 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 362 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
363 } 363 }
364 if (var == NULL) { 364 if (var == NULL) {
365 return NULL; 365 return NULL;
366 } else { 366 } else {
367 return (Var *)Hash_GetValue(var); 367 return (Var *)Hash_GetValue(var);
368 } 368 }
369 } else { 369 } else {
370 return NULL; 370 return NULL;
371 } 371 }
372 } else if (var == NULL) { 372 } else if (var == NULL) {
373 return NULL; 373 return NULL;
374 } else { 374 } else {
375 return (Var *)Hash_GetValue(var); 375 return (Var *)Hash_GetValue(var);
376 } 376 }
377} 377}
378 378
379/*- 379/*-
380 *----------------------------------------------------------------------- 380 *-----------------------------------------------------------------------
381 * VarFreeEnv -- 381 * VarFreeEnv --
382 * If the variable is an environment variable, free it 382 * If the variable is an environment variable, free it
383 * 383 *
384 * Input: 384 * Input:
385 * v the variable 385 * v the variable
386 * destroy true if the value buffer should be destroyed. 386 * destroy true if the value buffer should be destroyed.
387 * 387 *
388 * Results: 388 * Results:
389 * 1 if it is an environment variable 0 ow. 389 * 1 if it is an environment variable 0 ow.
390 * 390 *
391 * Side Effects: 391 * Side Effects:
392 * The variable is free'ed if it is an environent variable. 392 * The variable is free'ed if it is an environent variable.
393 *----------------------------------------------------------------------- 393 *-----------------------------------------------------------------------
394 */ 394 */
395static Boolean 395static Boolean
396VarFreeEnv(Var *v, Boolean destroy) 396VarFreeEnv(Var *v, Boolean destroy)
397{ 397{
398 if (!(v->flags & VAR_FROM_ENV)) 398 if (!(v->flags & VAR_FROM_ENV))
399 return FALSE; 399 return FALSE;
400 free(v->name); 400 free(v->name);
401 Buf_Destroy(&v->val, destroy); 401 Buf_Destroy(&v->val, destroy);
402 free(v); 402 free(v);
403 return TRUE; 403 return TRUE;
404} 404}
405 405
406/*- 406/*-
407 *----------------------------------------------------------------------- 407 *-----------------------------------------------------------------------
408 * VarAdd -- 408 * VarAdd --
409 * Add a new variable of name name and value val to the given context 409 * Add a new variable of name name and value val to the given context
410 * 410 *
411 * Input: 411 * Input:
412 * name name of variable to add 412 * name name of variable to add
413 * val value to set it to 413 * val value to set it to
414 * ctxt context in which to set it 414 * ctxt context in which to set it
415 * 415 *
416 * Side Effects: 416 * Side Effects:
417 * The new variable is placed at the front of the given context 417 * The new variable is placed at the front of the given context
418 * The name and val arguments are duplicated so they may 418 * The name and val arguments are duplicated so they may
419 * safely be freed. 419 * safely be freed.
420 *----------------------------------------------------------------------- 420 *-----------------------------------------------------------------------
421 */ 421 */
422static void 422static void
423VarAdd(const char *name, const char *val, GNode *ctxt) 423VarAdd(const char *name, const char *val, GNode *ctxt)
424{ 424{
425 Var *v = bmake_malloc(sizeof(Var)); 425 Var *v = bmake_malloc(sizeof(Var));
426 426
427 int len = val != NULL ? (int)strlen(val) : 0; 427 int len = val != NULL ? (int)strlen(val) : 0;
428 Buf_Init(&v->val, len + 1); 428 Buf_Init(&v->val, len + 1);
429 Buf_AddBytes(&v->val, len, val); 429 Buf_AddBytes(&v->val, len, val);
430 430
431 v->flags = 0; 431 v->flags = 0;
432 432
433 Hash_Entry *h = Hash_CreateEntry(&ctxt->context, name, NULL); 433 Hash_Entry *h = Hash_CreateEntry(&ctxt->context, name, NULL);
434 Hash_SetValue(h, v); 434 Hash_SetValue(h, v);
435 v->name = h->name; 435 v->name = h->name;
436 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) { 436 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) {
437 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 437 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
438 } 438 }
439} 439}
440 440
441/*- 441/*-
442 *----------------------------------------------------------------------- 442 *-----------------------------------------------------------------------
443 * Var_Delete -- 443 * Var_Delete --
444 * Remove a variable from a context. 444 * Remove a variable from a context.
445 * 445 *
446 * Side Effects: 446 * Side Effects:
447 * The Var structure is removed and freed. 447 * The Var structure is removed and freed.
448 * 448 *
449 *----------------------------------------------------------------------- 449 *-----------------------------------------------------------------------
450 */ 450 */
451void 451void
452Var_Delete(const char *name, GNode *ctxt) 452Var_Delete(const char *name, GNode *ctxt)
453{ 453{
454 Hash_Entry *ln; 454 Hash_Entry *ln;
455 char *cp; 455 char *cp;
456 456
457 if (strchr(name, '$') != NULL) { 457 if (strchr(name, '$') != NULL) {
458 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES); 458 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES);
459 } else { 459 } else {
460 cp = UNCONST(name); 460 cp = UNCONST(name);
461 } 461 }
462 ln = Hash_FindEntry(&ctxt->context, cp); 462 ln = Hash_FindEntry(&ctxt->context, cp);
463 if (DEBUG(VAR)) { 463 if (DEBUG(VAR)) {
464 fprintf(debug_file, "%s:delete %s%s\n", 464 fprintf(debug_file, "%s:delete %s%s\n",
465 ctxt->name, cp, ln ? "" : " (not found)"); 465 ctxt->name, cp, ln ? "" : " (not found)");
466 } 466 }
467 if (cp != name) 467 if (cp != name)
468 free(cp); 468 free(cp);
469 if (ln != NULL) { 469 if (ln != NULL) {
470 Var *v = (Var *)Hash_GetValue(ln); 470 Var *v = (Var *)Hash_GetValue(ln);
471 if (v->flags & VAR_EXPORTED) 471 if (v->flags & VAR_EXPORTED)
472 unsetenv(v->name); 472 unsetenv(v->name);
473 if (strcmp(MAKE_EXPORTED, v->name) == 0) 473 if (strcmp(MAKE_EXPORTED, v->name) == 0)
474 var_exportedVars = VAR_EXPORTED_NONE; 474 var_exportedVars = VAR_EXPORTED_NONE;
475 if (v->name != ln->name) 475 if (v->name != ln->name)
476 free(v->name); 476 free(v->name);
477 Hash_DeleteEntry(&ctxt->context, ln); 477 Hash_DeleteEntry(&ctxt->context, ln);
478 Buf_Destroy(&v->val, TRUE); 478 Buf_Destroy(&v->val, TRUE);
479 free(v); 479 free(v);
480 } 480 }
481} 481}
482 482
483 483
484/* 484/*
485 * Export a var. 485 * Export a var.
486 * We ignore make internal variables (those which start with '.') 486 * We ignore make internal variables (those which start with '.')
487 * Also we jump through some hoops to avoid calling setenv 487 * Also we jump through some hoops to avoid calling setenv
488 * more than necessary since it can leak. 488 * more than necessary since it can leak.
489 * We only manipulate flags of vars if 'parent' is set. 489 * We only manipulate flags of vars if 'parent' is set.
490 */ 490 */
491static int 491static int
492Var_Export1(const char *name, VarExportFlags flags) 492Var_Export1(const char *name, VarExportFlags flags)
493{ 493{
494 char tmp[BUFSIZ]; 494 char tmp[BUFSIZ];
495 Var *v; 495 Var *v;
496 char *val = NULL; 496 char *val = NULL;
497 int n; 497 int n;
498 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 498 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
499 499
500 if (*name == '.') 500 if (*name == '.')
501 return 0; /* skip internals */ 501 return 0; /* skip internals */
502 if (!name[1]) { 502 if (!name[1]) {
503 /* 503 /*
504 * A single char. 504 * A single char.
505 * If it is one of the vars that should only appear in 505 * If it is one of the vars that should only appear in
506 * local context, skip it, else we can get Var_Subst 506 * local context, skip it, else we can get Var_Subst
507 * into a loop. 507 * into a loop.
508 */ 508 */
509 switch (name[0]) { 509 switch (name[0]) {
510 case '@': 510 case '@':
511 case '%': 511 case '%':
512 case '*': 512 case '*':
513 case '!': 513 case '!':
514 return 0; 514 return 0;
515 } 515 }
516 } 516 }
517 v = VarFind(name, VAR_GLOBAL, 0); 517 v = VarFind(name, VAR_GLOBAL, 0);
518 if (v == NULL) 518 if (v == NULL)
519 return 0; 519 return 0;
520 if (!parent && 520 if (!parent &&
521 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { 521 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) {
522 return 0; /* nothing to do */ 522 return 0; /* nothing to do */
523 } 523 }
524 val = Buf_GetAll(&v->val, NULL); 524 val = Buf_GetAll(&v->val, NULL);
525 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { 525 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
526 if (parent) { 526 if (parent) {
527 /* 527 /*
528 * Flag this as something we need to re-export. 528 * Flag this as something we need to re-export.
529 * No point actually exporting it now though, 529 * No point actually exporting it now though,
530 * the child can do it at the last minute. 530 * the child can do it at the last minute.
531 */ 531 */
532 v->flags |= (VAR_EXPORTED | VAR_REEXPORT); 532 v->flags |= (VAR_EXPORTED | VAR_REEXPORT);
533 return 1; 533 return 1;
534 } 534 }
535 if (v->flags & VAR_IN_USE) { 535 if (v->flags & VAR_IN_USE) {
536 /* 536 /*
537 * We recursed while exporting in a child. 537 * We recursed while exporting in a child.
538 * This isn't going to end well, just skip it. 538 * This isn't going to end well, just skip it.
539 */ 539 */
540 return 0; 540 return 0;
541 } 541 }
542 n = snprintf(tmp, sizeof(tmp), "${%s}", name); 542 n = snprintf(tmp, sizeof(tmp), "${%s}", name);
543 if (n < (int)sizeof(tmp)) { 543 if (n < (int)sizeof(tmp)) {
544 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 544 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
545 setenv(name, val, 1); 545 setenv(name, val, 1);
546 free(val); 546 free(val);
547 } 547 }
548 } else { 548 } else {
549 if (parent) 549 if (parent)
550 v->flags &= ~VAR_REEXPORT; /* once will do */ 550 v->flags &= ~VAR_REEXPORT; /* once will do */
551 if (parent || !(v->flags & VAR_EXPORTED)) 551 if (parent || !(v->flags & VAR_EXPORTED))
552 setenv(name, val, 1); 552 setenv(name, val, 1);
553 } 553 }
554 /* 554 /*
555 * This is so Var_Set knows to call Var_Export again... 555 * This is so Var_Set knows to call Var_Export again...
556 */ 556 */
557 if (parent) { 557 if (parent) {
558 v->flags |= VAR_EXPORTED; 558 v->flags |= VAR_EXPORTED;
559 } 559 }
560 return 1; 560 return 1;
561} 561}
562 562
563static void 563static void
564Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED) 564Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
565{ 565{
566 Var *var = entry; 566 Var *var = entry;
567 Var_Export1(var->name, 0); 567 Var_Export1(var->name, 0);
568} 568}
569 569
570/* 570/*
571 * This gets called from our children. 571 * This gets called from our children.
572 */ 572 */
573void 573void
574Var_ExportVars(void) 574Var_ExportVars(void)
575{ 575{
576 char tmp[BUFSIZ]; 576 char tmp[BUFSIZ];
577 char *val; 577 char *val;
578 int n; 578 int n;
579 579
580 /* 580 /*
581 * Several make's support this sort of mechanism for tracking 581 * Several make's support this sort of mechanism for tracking
582 * recursion - but each uses a different name. 582 * recursion - but each uses a different name.
583 * We allow the makefiles to update MAKELEVEL and ensure 583 * We allow the makefiles to update MAKELEVEL and ensure
584 * children see a correctly incremented value. 584 * children see a correctly incremented value.
585 */ 585 */
586 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 586 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
587 setenv(MAKE_LEVEL_ENV, tmp, 1); 587 setenv(MAKE_LEVEL_ENV, tmp, 1);
588 588
589 if (VAR_EXPORTED_NONE == var_exportedVars) 589 if (VAR_EXPORTED_NONE == var_exportedVars)
590 return; 590 return;
591 591
592 if (VAR_EXPORTED_ALL == var_exportedVars) { 592 if (VAR_EXPORTED_ALL == var_exportedVars) {
593 /* Ouch! This is crazy... */ 593 /* Ouch! This is crazy... */
594 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); 594 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
595 return; 595 return;
596 } 596 }
597 /* 597 /*
598 * We have a number of exported vars, 598 * We have a number of exported vars,
599 */ 599 */
600 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); 600 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
601 if (n < (int)sizeof(tmp)) { 601 if (n < (int)sizeof(tmp)) {
602 char **av; 602 char **av;
603 char *as; 603 char *as;
604 int ac; 604 int ac;
605 int i; 605 int i;
606 606
607 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 607 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
608 if (*val) { 608 if (*val) {
609 av = brk_string(val, &ac, FALSE, &as); 609 av = brk_string(val, &ac, FALSE, &as);
610 for (i = 0; i < ac; i++) 610 for (i = 0; i < ac; i++)
611 Var_Export1(av[i], 0); 611 Var_Export1(av[i], 0);
612 free(as); 612 free(as);
613 free(av); 613 free(av);
614 } 614 }
615 free(val); 615 free(val);
616 } 616 }
617} 617}
618 618
619/* 619/*
620 * This is called when .export is seen or 620 * This is called when .export is seen or
621 * .MAKE.EXPORTED is modified. 621 * .MAKE.EXPORTED is modified.
622 * It is also called when any exported var is modified. 622 * It is also called when any exported var is modified.
623 */ 623 */
624void 624void
625Var_Export(char *str, int isExport) 625Var_Export(char *str, int isExport)
626{ 626{
627 char **av; 627 char **av;
628 char *as; 628 char *as;
629 VarExportFlags flags; 629 VarExportFlags flags;
630 int ac; 630 int ac;
631 int i; 631 int i;
632 632
633 if (isExport && (!str || !str[0])) { 633 if (isExport && (!str || !str[0])) {
634 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 634 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
635 return; 635 return;
636 } 636 }
637 637
638 flags = 0; 638 flags = 0;
639 if (strncmp(str, "-env", 4) == 0) { 639 if (strncmp(str, "-env", 4) == 0) {
640 str += 4; 640 str += 4;
641 } else if (strncmp(str, "-literal", 8) == 0) { 641 } else if (strncmp(str, "-literal", 8) == 0) {
642 str += 8; 642 str += 8;
643 flags |= VAR_EXPORT_LITERAL; 643 flags |= VAR_EXPORT_LITERAL;
644 } else { 644 } else {
645 flags |= VAR_EXPORT_PARENT; 645 flags |= VAR_EXPORT_PARENT;
646 } 646 }
647 647
648 char *val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES); 648 char *val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES);
649 if (*val) { 649 if (*val) {
650 av = brk_string(val, &ac, FALSE, &as); 650 av = brk_string(val, &ac, FALSE, &as);
651 for (i = 0; i < ac; i++) { 651 for (i = 0; i < ac; i++) {
652 const char *name = av[i]; 652 const char *name = av[i];
653 if (!name[1]) { 653 if (!name[1]) {
654 /* 654 /*
655 * A single char. 655 * A single char.
656 * If it is one of the vars that should only appear in 656 * If it is one of the vars that should only appear in
657 * local context, skip it, else we can get Var_Subst 657 * local context, skip it, else we can get Var_Subst
658 * into a loop. 658 * into a loop.
659 */ 659 */
660 switch (name[0]) { 660 switch (name[0]) {
661 case '@': 661 case '@':
662 case '%': 662 case '%':
663 case '*': 663 case '*':
664 case '!': 664 case '!':
665 continue; 665 continue;
666 } 666 }
667 } 667 }
668 if (Var_Export1(name, flags)) { 668 if (Var_Export1(name, flags)) {
669 if (VAR_EXPORTED_ALL != var_exportedVars) 669 if (VAR_EXPORTED_ALL != var_exportedVars)
670 var_exportedVars = VAR_EXPORTED_YES; 670 var_exportedVars = VAR_EXPORTED_YES;
671 if (isExport && (flags & VAR_EXPORT_PARENT)) { 671 if (isExport && (flags & VAR_EXPORT_PARENT)) {
672 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 672 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
673 } 673 }
674 } 674 }
675 } 675 }
676 free(as); 676 free(as);
677 free(av); 677 free(av);
678 } 678 }
679 free(val); 679 free(val);
680} 680}
681 681
682 682
683extern char **environ; 683extern char **environ;
684 684
685/* 685/*
686 * This is called when .unexport[-env] is seen. 686 * This is called when .unexport[-env] is seen.
687 */ 687 */
688void 688void
689Var_UnExport(char *str) 689Var_UnExport(char *str)
690{ 690{
691 char tmp[BUFSIZ]; 691 char tmp[BUFSIZ];
692 char *vlist; 692 char *vlist;
693 char *cp; 693 char *cp;
694 Boolean unexport_env; 694 Boolean unexport_env;
695 int n; 695 int n;
696 696
697 if (str == NULL || str[0] == '\0') 697 if (str == NULL || str[0] == '\0')
698 return; /* assert? */ 698 return; /* assert? */
699 699
700 vlist = NULL; 700 vlist = NULL;
701 701
702 str += 8; 702 str += 8;
703 unexport_env = (strncmp(str, "-env", 4) == 0); 703 unexport_env = (strncmp(str, "-env", 4) == 0);
704 if (unexport_env) { 704 if (unexport_env) {
705 char **newenv; 705 char **newenv;
706 706
707 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 707 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
708 if (environ == savedEnv) { 708 if (environ == savedEnv) {
709 /* we have been here before! */ 709 /* we have been here before! */
710 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 710 newenv = bmake_realloc(environ, 2 * sizeof(char *));
711 } else { 711 } else {
712 if (savedEnv) { 712 if (savedEnv) {
713 free(savedEnv); 713 free(savedEnv);
714 savedEnv = NULL; 714 savedEnv = NULL;
715 } 715 }
716 newenv = bmake_malloc(2 * sizeof(char *)); 716 newenv = bmake_malloc(2 * sizeof(char *));
717 } 717 }
718 if (!newenv) 718 if (!newenv)
719 return; 719 return;
720 /* Note: we cannot safely free() the original environ. */ 720 /* Note: we cannot safely free() the original environ. */
721 environ = savedEnv = newenv; 721 environ = savedEnv = newenv;
722 newenv[0] = NULL; 722 newenv[0] = NULL;
723 newenv[1] = NULL; 723 newenv[1] = NULL;
724 if (cp && *cp) 724 if (cp && *cp)
725 setenv(MAKE_LEVEL_ENV, cp, 1); 725 setenv(MAKE_LEVEL_ENV, cp, 1);
726 } else { 726 } else {
727 for (; *str != '\n' && isspace((unsigned char) *str); str++) 727 for (; *str != '\n' && isspace((unsigned char) *str); str++)
728 continue; 728 continue;
729 if (str[0] && str[0] != '\n') { 729 if (str[0] && str[0] != '\n') {
730 vlist = str; 730 vlist = str;
731 } 731 }
732 } 732 }
733 733
734 if (!vlist) { 734 if (!vlist) {
735 /* Using .MAKE.EXPORTED */ 735 /* Using .MAKE.EXPORTED */
736 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, 736 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
737 VARE_WANTRES); 737 VARE_WANTRES);
738 } 738 }
739 if (vlist) { 739 if (vlist) {
740 Var *v; 740 Var *v;
741 char **av; 741 char **av;
742 char *as; 742 char *as;
743 int ac; 743 int ac;
744 int i; 744 int i;
745 745
746 av = brk_string(vlist, &ac, FALSE, &as); 746 av = brk_string(vlist, &ac, FALSE, &as);
747 for (i = 0; i < ac; i++) { 747 for (i = 0; i < ac; i++) {
748 v = VarFind(av[i], VAR_GLOBAL, 0); 748 v = VarFind(av[i], VAR_GLOBAL, 0);
749 if (!v) 749 if (!v)
750 continue; 750 continue;
751 if (!unexport_env && 751 if (!unexport_env &&
752 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) 752 (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED)
753 unsetenv(v->name); 753 unsetenv(v->name);
754 v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT); 754 v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT);
755 /* 755 /*
756 * If we are unexporting a list, 756 * If we are unexporting a list,
757 * remove each one from .MAKE.EXPORTED. 757 * remove each one from .MAKE.EXPORTED.
758 * If we are removing them all, 758 * If we are removing them all,
759 * just delete .MAKE.EXPORTED below. 759 * just delete .MAKE.EXPORTED below.
760 */ 760 */
761 if (vlist == str) { 761 if (vlist == str) {
762 n = snprintf(tmp, sizeof(tmp), 762 n = snprintf(tmp, sizeof(tmp),
763 "${" MAKE_EXPORTED ":N%s}", v->name); 763 "${" MAKE_EXPORTED ":N%s}", v->name);
764 if (n < (int)sizeof(tmp)) { 764 if (n < (int)sizeof(tmp)) {
765 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 765 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
766 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 766 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
767 free(cp); 767 free(cp);
768 } 768 }
769 } 769 }
770 } 770 }
771 free(as); 771 free(as);
772 free(av); 772 free(av);
773 if (vlist != str) { 773 if (vlist != str) {
774 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 774 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
775 free(vlist); 775 free(vlist);
776 } 776 }
777 } 777 }
778} 778}
779 779
780static void 780static void
781Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 781Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
782 VarSet_Flags flags) 782 VarSet_Flags flags)
783{ 783{
784 Var *v; 784 Var *v;
785 char *expanded_name = NULL; 785 char *expanded_name = NULL;
786 786
787 /* 787 /*
788 * We only look for a variable in the given context since anything set 788 * We only look for a variable in the given context since anything set
789 * here will override anything in a lower context, so there's not much 789 * here will override anything in a lower context, so there's not much
790 * point in searching them all just to save a bit of memory... 790 * point in searching them all just to save a bit of memory...
791 */ 791 */
792 if (strchr(name, '$') != NULL) { 792 if (strchr(name, '$') != NULL) {
793 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 793 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
794 if (expanded_name[0] == '\0') { 794 if (expanded_name[0] == '\0') {
795 if (DEBUG(VAR)) { 795 if (DEBUG(VAR)) {
796 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " 796 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
797 "name expands to empty string - ignored\n", 797 "name expands to empty string - ignored\n",
798 name, val); 798 name, val);
799 } 799 }
800 free(expanded_name); 800 free(expanded_name);
801 return; 801 return;
802 } 802 }
803 name = expanded_name; 803 name = expanded_name;
804 } 804 }
805 if (ctxt == VAR_GLOBAL) { 805 if (ctxt == VAR_GLOBAL) {
806 v = VarFind(name, VAR_CMD, 0); 806 v = VarFind(name, VAR_CMD, 0);
807 if (v != NULL) { 807 if (v != NULL) {
808 if ((v->flags & VAR_FROM_CMD)) { 808 if ((v->flags & VAR_FROM_CMD)) {
809 if (DEBUG(VAR)) { 809 if (DEBUG(VAR)) {
810 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); 810 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
811 } 811 }
812 goto out; 812 goto out;
813 } 813 }
814 VarFreeEnv(v, TRUE); 814 VarFreeEnv(v, TRUE);
815 } 815 }
816 } 816 }
817 v = VarFind(name, ctxt, 0); 817 v = VarFind(name, ctxt, 0);
818 if (v == NULL) { 818 if (v == NULL) {
819 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 819 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
820 /* 820 /*
821 * This var would normally prevent the same name being added 821 * This var would normally prevent the same name being added
822 * to VAR_GLOBAL, so delete it from there if needed. 822 * to VAR_GLOBAL, so delete it from there if needed.
823 * Otherwise -V name may show the wrong value. 823 * Otherwise -V name may show the wrong value.
824 */ 824 */
825 Var_Delete(name, VAR_GLOBAL); 825 Var_Delete(name, VAR_GLOBAL);
826 } 826 }
827 VarAdd(name, val, ctxt); 827 VarAdd(name, val, ctxt);
828 } else { 828 } else {
829 Buf_Empty(&v->val); 829 Buf_Empty(&v->val);
830 if (val) 830 if (val)
831 Buf_AddStr(&v->val, val); 831 Buf_AddStr(&v->val, val);
832 832
833 if (DEBUG(VAR)) { 833 if (DEBUG(VAR)) {
834 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 834 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
835 } 835 }
836 if ((v->flags & VAR_EXPORTED)) { 836 if ((v->flags & VAR_EXPORTED)) {
837 Var_Export1(name, VAR_EXPORT_PARENT); 837 Var_Export1(name, VAR_EXPORT_PARENT);
838 } 838 }
839 } 839 }
840 /* 840 /*
841 * Any variables given on the command line are automatically exported 841 * Any variables given on the command line are automatically exported
842 * to the environment (as per POSIX standard) 842 * to the environment (as per POSIX standard)
843 */ 843 */
844 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 844 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
845 if (v == NULL) { 845 if (v == NULL) {
846 /* we just added it */ 846 /* we just added it */
847 v = VarFind(name, ctxt, 0); 847 v = VarFind(name, ctxt, 0);
848 } 848 }
849 if (v != NULL) 849 if (v != NULL)
850 v->flags |= VAR_FROM_CMD; 850 v->flags |= VAR_FROM_CMD;
851 /* 851 /*
852 * If requested, don't export these in the environment 852 * If requested, don't export these in the environment
853 * individually. We still put them in MAKEOVERRIDES so 853 * individually. We still put them in MAKEOVERRIDES so
854 * that the command-line settings continue to override 854 * that the command-line settings continue to override
855 * Makefile settings. 855 * Makefile settings.
856 */ 856 */
857 if (varNoExportEnv != TRUE) 857 if (varNoExportEnv != TRUE)
858 setenv(name, val ? val : "", 1); 858 setenv(name, val ? val : "", 1);
859 859
860 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 860 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
861 } 861 }
862 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0) 862 if (name[0] == '.' && strcmp(name, SAVE_DOLLARS) == 0)
863 save_dollars = s2Boolean(val, save_dollars); 863 save_dollars = s2Boolean(val, save_dollars);
864 864
865out: 865out:
866 free(expanded_name); 866 free(expanded_name);
867 if (v != NULL) 867 if (v != NULL)
868 VarFreeEnv(v, TRUE); 868 VarFreeEnv(v, TRUE);
869} 869}
870 870
871/*- 871/*-
872 *----------------------------------------------------------------------- 872 *-----------------------------------------------------------------------
873 * Var_Set -- 873 * Var_Set --
874 * Set the variable name to the value val in the given context. 874 * Set the variable name to the value val in the given context.
875 * 875 *
876 * Input: 876 * Input:
877 * name name of variable to set 877 * name name of variable to set
878 * val value to give to the variable 878 * val value to give to the variable
879 * ctxt context in which to set it 879 * ctxt context in which to set it
880 * 880 *
881 * Side Effects: 881 * Side Effects:
882 * If the variable doesn't yet exist, a new record is created for it. 882 * If the variable doesn't yet exist, a new record is created for it.
883 * Else the old value is freed and the new one stuck in its place 883 * Else the old value is freed and the new one stuck in its place
884 * 884 *
885 * Notes: 885 * Notes:
886 * The variable is searched for only in its context before being 886 * The variable is searched for only in its context before being
887 * created in that context. I.e. if the context is VAR_GLOBAL, 887 * created in that context. I.e. if the context is VAR_GLOBAL,
888 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 888 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
889 * VAR_CMD->context is searched. This is done to avoid the literally 889 * VAR_CMD->context is searched. This is done to avoid the literally
890 * thousands of unnecessary strcmp's that used to be done to 890 * thousands of unnecessary strcmp's that used to be done to
891 * set, say, $(@) or $(<). 891 * set, say, $(@) or $(<).
892 * If the context is VAR_GLOBAL though, we check if the variable 892 * If the context is VAR_GLOBAL though, we check if the variable
893 * was set in VAR_CMD from the command line and skip it if so. 893 * was set in VAR_CMD from the command line and skip it if so.
894 *----------------------------------------------------------------------- 894 *-----------------------------------------------------------------------
895 */ 895 */
896void 896void
897Var_Set(const char *name, const char *val, GNode *ctxt) 897Var_Set(const char *name, const char *val, GNode *ctxt)
898{ 898{
899 Var_Set_with_flags(name, val, ctxt, 0); 899 Var_Set_with_flags(name, val, ctxt, 0);
900} 900}
901 901
902/*- 902/*-
903 *----------------------------------------------------------------------- 903 *-----------------------------------------------------------------------
904 * Var_Append -- 904 * Var_Append --
905 * The variable of the given name has the given value appended to it in 905 * The variable of the given name has the given value appended to it in
906 * the given context. 906 * the given context.
907 * 907 *
908 * Input: 908 * Input:
909 * name name of variable to modify 909 * name name of variable to modify
910 * val String to append to it 910 * val String to append to it
911 * ctxt Context in which this should occur 911 * ctxt Context in which this should occur
912 * 912 *
913 * Side Effects: 913 * Side Effects:
914 * If the variable doesn't exist, it is created. Else the strings 914 * If the variable doesn't exist, it is created. Else the strings
915 * are concatenated (with a space in between). 915 * are concatenated (with a space in between).
916 * 916 *
917 * Notes: 917 * Notes:
918 * Only if the variable is being sought in the global context is the 918 * Only if the variable is being sought in the global context is the
919 * environment searched. 919 * environment searched.
920 * XXX: Knows its calling circumstances in that if called with ctxt 920 * XXX: Knows its calling circumstances in that if called with ctxt
921 * an actual target, it will only search that context since only 921 * an actual target, it will only search that context since only
922 * a local variable could be being appended to. This is actually 922 * a local variable could be being appended to. This is actually
923 * a big win and must be tolerated. 923 * a big win and must be tolerated.
924 *----------------------------------------------------------------------- 924 *-----------------------------------------------------------------------
925 */ 925 */
926void 926void
927Var_Append(const char *name, const char *val, GNode *ctxt) 927Var_Append(const char *name, const char *val, GNode *ctxt)
928{ 928{
929 Var *v; 929 Var *v;
930 Hash_Entry *h; 930 Hash_Entry *h;
931 char *expanded_name = NULL; 931 char *expanded_name = NULL;
932 932
933 if (strchr(name, '$') != NULL) { 933 if (strchr(name, '$') != NULL) {
934 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 934 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
935 if (expanded_name[0] == '\0') { 935 if (expanded_name[0] == '\0') {
936 if (DEBUG(VAR)) { 936 if (DEBUG(VAR)) {
937 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " 937 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
938 "name expands to empty string - ignored\n", 938 "name expands to empty string - ignored\n",
939 name, val); 939 name, val);
940 } 940 }
941 free(expanded_name); 941 free(expanded_name);
942 return; 942 return;
943 } 943 }
944 name = expanded_name; 944 name = expanded_name;
945 } 945 }
946 946
947 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); 947 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0);
948 948
949 if (v == NULL) { 949 if (v == NULL) {
950 Var_Set(name, val, ctxt); 950 Var_Set(name, val, ctxt);
951 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { 951 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
952 Buf_AddByte(&v->val, ' '); 952 Buf_AddByte(&v->val, ' ');
953 Buf_AddStr(&v->val, val); 953 Buf_AddStr(&v->val, val);
954 954
955 if (DEBUG(VAR)) { 955 if (DEBUG(VAR)) {
956 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, 956 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
957 Buf_GetAll(&v->val, NULL)); 957 Buf_GetAll(&v->val, NULL));
958 } 958 }
959 959
960 if (v->flags & VAR_FROM_ENV) { 960 if (v->flags & VAR_FROM_ENV) {
961 /* 961 /*
962 * If the original variable came from the environment, we 962 * If the original variable came from the environment, we
963 * have to install it in the global context (we could place 963 * have to install it in the global context (we could place
964 * it in the environment, but then we should provide a way to 964 * it in the environment, but then we should provide a way to
965 * export other variables...) 965 * export other variables...)
966 */ 966 */
967 v->flags &= ~VAR_FROM_ENV; 967 v->flags &= ~VAR_FROM_ENV;
968 h = Hash_CreateEntry(&ctxt->context, name, NULL); 968 h = Hash_CreateEntry(&ctxt->context, name, NULL);
969 Hash_SetValue(h, v); 969 Hash_SetValue(h, v);
970 } 970 }
971 } 971 }
972 free(expanded_name); 972 free(expanded_name);
973} 973}
974 974
975/*- 975/*-
976 *----------------------------------------------------------------------- 976 *-----------------------------------------------------------------------
977 * Var_Exists -- 977 * Var_Exists --
978 * See if the given variable exists. 978 * See if the given variable exists.
979 * 979 *
980 * Input: 980 * Input:
981 * name Variable to find 981 * name Variable to find
982 * ctxt Context in which to start search 982 * ctxt Context in which to start search
983 * 983 *
984 * Results: 984 * Results:
985 * TRUE if it does, FALSE if it doesn't 985 * TRUE if it does, FALSE if it doesn't
986 * 986 *
987 * Side Effects: 987 * Side Effects:
988 * None. 988 * None.
989 * 989 *
990 *----------------------------------------------------------------------- 990 *-----------------------------------------------------------------------
991 */ 991 */
992Boolean 992Boolean
993Var_Exists(const char *name, GNode *ctxt) 993Var_Exists(const char *name, GNode *ctxt)
994{ 994{
995 Var *v; 995 Var *v;
996 char *cp; 996 char *cp;
997 997
998 if ((cp = strchr(name, '$')) != NULL) 998 if ((cp = strchr(name, '$')) != NULL)
999 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 999 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
1000 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); 1000 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV);
1001 free(cp); 1001 free(cp);
1002 if (v == NULL) 1002 if (v == NULL)
1003 return FALSE; 1003 return FALSE;
1004 1004
1005 (void)VarFreeEnv(v, TRUE); 1005 (void)VarFreeEnv(v, TRUE);
1006 return TRUE; 1006 return TRUE;
1007} 1007}
1008 1008
1009/*- 1009/*-
1010 *----------------------------------------------------------------------- 1010 *-----------------------------------------------------------------------
1011 * Var_Value -- 1011 * Var_Value --
1012 * Return the value of the named variable in the given context 1012 * Return the value of the named variable in the given context
1013 * 1013 *
1014 * Input: 1014 * Input:
1015 * name name to find 1015 * name name to find
1016 * ctxt context in which to search for it 1016 * ctxt context in which to search for it
1017 * 1017 *
1018 * Results: 1018 * Results:
1019 * The value if the variable exists, NULL if it doesn't 1019 * The value if the variable exists, NULL if it doesn't
1020 * 1020 *
1021 * Side Effects: 1021 * Side Effects:
1022 * None 1022 * None
1023 *----------------------------------------------------------------------- 1023 *-----------------------------------------------------------------------
1024 */ 1024 */
1025char * 1025char *
1026Var_Value(const char *name, GNode *ctxt, char **frp) 1026Var_Value(const char *name, GNode *ctxt, char **frp)
1027{ 1027{
1028 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1028 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1029 *frp = NULL; 1029 *frp = NULL;
1030 if (v == NULL) 1030 if (v == NULL)
1031 return NULL; 1031 return NULL;
1032 1032
1033 char *p = Buf_GetAll(&v->val, NULL); 1033 char *p = Buf_GetAll(&v->val, NULL);
1034 if (VarFreeEnv(v, FALSE)) 1034 if (VarFreeEnv(v, FALSE))
1035 *frp = p; 1035 *frp = p;
1036 return p; 1036 return p;
1037} 1037}
1038 1038
1039 1039
1040/* SepBuf is a string being built from "words", interleaved with separators. */ 1040/* SepBuf is a string being built from "words", interleaved with separators. */
1041typedef struct { 1041typedef struct {
1042 Buffer buf; 1042 Buffer buf;
1043 Boolean needSep; 1043 Boolean needSep;
1044 char sep; 1044 char sep;
1045} SepBuf; 1045} SepBuf;
1046 1046
1047static void 1047static void
1048SepBuf_Init(SepBuf *buf, char sep) 1048SepBuf_Init(SepBuf *buf, char sep)
1049{ 1049{
1050 Buf_Init(&buf->buf, 32 /* bytes */); 1050 Buf_Init(&buf->buf, 32 /* bytes */);
1051 buf->needSep = FALSE; 1051 buf->needSep = FALSE;
1052 buf->sep = sep; 1052 buf->sep = sep;
1053} 1053}
1054 1054
1055static void 1055static void
1056SepBuf_Sep(SepBuf *buf) 1056SepBuf_Sep(SepBuf *buf)
1057{ 1057{
1058 buf->needSep = TRUE; 1058 buf->needSep = TRUE;
1059} 1059}
1060 1060
1061static void 1061static void
1062SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1062SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1063{ 1063{
1064 if (mem_size == 0) 1064 if (mem_size == 0)
1065 return; 1065 return;
1066 if (buf->needSep && buf->sep != '\0') { 1066 if (buf->needSep && buf->sep != '\0') {
1067 Buf_AddByte(&buf->buf, buf->sep); 1067 Buf_AddByte(&buf->buf, buf->sep);
1068 buf->needSep = FALSE; 1068 buf->needSep = FALSE;
1069 } 1069 }
1070 Buf_AddBytes(&buf->buf, mem_size, mem); 1070 Buf_AddBytes(&buf->buf, mem_size, mem);
1071} 1071}
1072 1072
1073static void 1073static void
1074SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1074SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1075{ 1075{
1076 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1076 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1077} 1077}
1078 1078
@@ -2387,1520 +2387,1518 @@ ApplyModifier_Subst(const char * const m @@ -2387,1520 +2387,1518 @@ ApplyModifier_Subst(const char * const m
2387 ModifyWord_SubstArgs args; 2387 ModifyWord_SubstArgs args;
2388 Boolean oneBigWord = st->oneBigWord; 2388 Boolean oneBigWord = st->oneBigWord;
2389 char delim = mod[1]; 2389 char delim = mod[1];
2390 2390
2391 st->cp = mod + 2; 2391 st->cp = mod + 2;
2392 2392
2393 /* 2393 /*
2394 * If pattern begins with '^', it is anchored to the 2394 * If pattern begins with '^', it is anchored to the
2395 * start of the word -- skip over it and flag pattern. 2395 * start of the word -- skip over it and flag pattern.
2396 */ 2396 */
2397 args.pflags = 0; 2397 args.pflags = 0;
2398 if (*st->cp == '^') { 2398 if (*st->cp == '^') {
2399 args.pflags |= VARP_ANCHOR_START; 2399 args.pflags |= VARP_ANCHOR_START;
2400 st->cp++; 2400 st->cp++;
2401 } 2401 }
2402 2402
2403 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2403 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2404 &args.lhsLen, &args.pflags, NULL); 2404 &args.lhsLen, &args.pflags, NULL);
2405 if (lhs == NULL) { 2405 if (lhs == NULL) {
2406 st->missing_delim = delim; 2406 st->missing_delim = delim;
2407 return FALSE; 2407 return FALSE;
2408 } 2408 }
2409 args.lhs = lhs; 2409 args.lhs = lhs;
2410 2410
2411 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2411 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2412 &args.rhsLen, NULL, &args); 2412 &args.rhsLen, NULL, &args);
2413 if (rhs == NULL) { 2413 if (rhs == NULL) {
2414 st->missing_delim = delim; 2414 st->missing_delim = delim;
2415 return FALSE; 2415 return FALSE;
2416 } 2416 }
2417 args.rhs = rhs; 2417 args.rhs = rhs;
2418 2418
2419 /* 2419 /*
2420 * Check for global substitution. If 'g' after the final 2420 * Check for global substitution. If 'g' after the final
2421 * delimiter, substitution is global and is marked that 2421 * delimiter, substitution is global and is marked that
2422 * way. 2422 * way.
2423 */ 2423 */
2424 for (;; st->cp++) { 2424 for (;; st->cp++) {
2425 switch (*st->cp) { 2425 switch (*st->cp) {
2426 case 'g': 2426 case 'g':
2427 args.pflags |= VARP_SUB_GLOBAL; 2427 args.pflags |= VARP_SUB_GLOBAL;
2428 continue; 2428 continue;
2429 case '1': 2429 case '1':
2430 args.pflags |= VARP_SUB_ONE; 2430 args.pflags |= VARP_SUB_ONE;
2431 continue; 2431 continue;
2432 case 'W': 2432 case 'W':
2433 oneBigWord = TRUE; 2433 oneBigWord = TRUE;
2434 continue; 2434 continue;
2435 } 2435 }
2436 break; 2436 break;
2437 } 2437 }
2438 2438
2439 st->termc = *st->cp; 2439 st->termc = *st->cp;
2440 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2440 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2441 ModifyWord_Subst, &args); 2441 ModifyWord_Subst, &args);
2442 2442
2443 free(lhs); 2443 free(lhs);
2444 free(rhs); 2444 free(rhs);
2445 return TRUE; 2445 return TRUE;
2446} 2446}
2447 2447
2448#ifndef NO_REGEX 2448#ifndef NO_REGEX
2449 2449
2450/* :C,from,to, */ 2450/* :C,from,to, */
2451static Boolean 2451static Boolean
2452ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) 2452ApplyModifier_Regex(const char *mod, ApplyModifiersState *st)
2453{ 2453{
2454 ModifyWord_SubstRegexArgs args; 2454 ModifyWord_SubstRegexArgs args;
2455 2455
2456 args.pflags = 0; 2456 args.pflags = 0;
2457 Boolean oneBigWord = st->oneBigWord; 2457 Boolean oneBigWord = st->oneBigWord;
2458 char delim = mod[1]; 2458 char delim = mod[1];
2459 2459
2460 st->cp = mod + 2; 2460 st->cp = mod + 2;
2461 2461
2462 char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2462 char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2463 NULL, NULL, NULL); 2463 NULL, NULL, NULL);
2464 if (re == NULL) { 2464 if (re == NULL) {
2465 st->missing_delim = delim; 2465 st->missing_delim = delim;
2466 return FALSE; 2466 return FALSE;
2467 } 2467 }
2468 2468
2469 args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2469 args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2470 NULL, NULL, NULL); 2470 NULL, NULL, NULL);
2471 if (args.replace == NULL) { 2471 if (args.replace == NULL) {
2472 free(re); 2472 free(re);
2473 st->missing_delim = delim; 2473 st->missing_delim = delim;
2474 return FALSE; 2474 return FALSE;
2475 } 2475 }
2476 2476
2477 for (;; st->cp++) { 2477 for (;; st->cp++) {
2478 switch (*st->cp) { 2478 switch (*st->cp) {
2479 case 'g': 2479 case 'g':
2480 args.pflags |= VARP_SUB_GLOBAL; 2480 args.pflags |= VARP_SUB_GLOBAL;
2481 continue; 2481 continue;
2482 case '1': 2482 case '1':
2483 args.pflags |= VARP_SUB_ONE; 2483 args.pflags |= VARP_SUB_ONE;
2484 continue; 2484 continue;
2485 case 'W': 2485 case 'W':
2486 oneBigWord = TRUE; 2486 oneBigWord = TRUE;
2487 continue; 2487 continue;
2488 } 2488 }
2489 break; 2489 break;
2490 } 2490 }
2491 2491
2492 st->termc = *st->cp; 2492 st->termc = *st->cp;
2493 2493
2494 int error = regcomp(&args.re, re, REG_EXTENDED); 2494 int error = regcomp(&args.re, re, REG_EXTENDED);
2495 free(re); 2495 free(re);
2496 if (error) { 2496 if (error) {
2497 *st->lengthPtr = st->cp - st->start + 1; 2497 *st->lengthPtr = st->cp - st->start + 1;
2498 VarREError(error, &args.re, "RE substitution error"); 2498 VarREError(error, &args.re, "RE substitution error");
2499 free(args.replace); 2499 free(args.replace);
2500 return FALSE; 2500 return FALSE;
2501 } 2501 }
2502 2502
2503 args.nsub = args.re.re_nsub + 1; 2503 args.nsub = args.re.re_nsub + 1;
2504 if (args.nsub < 1) 2504 if (args.nsub < 1)
2505 args.nsub = 1; 2505 args.nsub = 1;
2506 if (args.nsub > 10) 2506 if (args.nsub > 10)
2507 args.nsub = 10; 2507 args.nsub = 10;
2508 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2508 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2509 ModifyWord_SubstRegex, &args); 2509 ModifyWord_SubstRegex, &args);
2510 regfree(&args.re); 2510 regfree(&args.re);
2511 free(args.replace); 2511 free(args.replace);
2512 return TRUE; 2512 return TRUE;
2513} 2513}
2514#endif 2514#endif
2515 2515
2516static void 2516static void
2517ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2517ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2518{ 2518{
2519 SepBuf_AddStr(buf, word); 2519 SepBuf_AddStr(buf, word);
2520} 2520}
2521 2521
2522/* :ts<separator> */ 2522/* :ts<separator> */
2523static Boolean 2523static Boolean
2524ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) 2524ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st)
2525{ 2525{
2526 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2526 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2527 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ 2527 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */
2528 st->sep = sep[0]; 2528 st->sep = sep[0];
2529 st->cp = sep + 1; 2529 st->cp = sep + 1;
2530 } else if (sep[0] == st->endc || sep[0] == ':') { 2530 } else if (sep[0] == st->endc || sep[0] == ':') {
2531 /* ":ts<endc>" or ":ts:" */ 2531 /* ":ts<endc>" or ":ts:" */
2532 st->sep = '\0'; /* no separator */ 2532 st->sep = '\0'; /* no separator */
2533 st->cp = sep; 2533 st->cp = sep;
2534 } else if (sep[0] == '\\') { 2534 } else if (sep[0] == '\\') {
2535 const char *xp = sep + 1; 2535 const char *xp = sep + 1;
2536 int base = 8; /* assume octal */ 2536 int base = 8; /* assume octal */
2537 2537
2538 switch (sep[1]) { 2538 switch (sep[1]) {
2539 case 'n': 2539 case 'n':
2540 st->sep = '\n'; 2540 st->sep = '\n';
2541 st->cp = sep + 2; 2541 st->cp = sep + 2;
2542 break; 2542 break;
2543 case 't': 2543 case 't':
2544 st->sep = '\t'; 2544 st->sep = '\t';
2545 st->cp = sep + 2; 2545 st->cp = sep + 2;
2546 break; 2546 break;
2547 case 'x': 2547 case 'x':
2548 base = 16; 2548 base = 16;
2549 xp++; 2549 xp++;
2550 goto get_numeric; 2550 goto get_numeric;
2551 case '0': 2551 case '0':
2552 base = 0; 2552 base = 0;
2553 goto get_numeric; 2553 goto get_numeric;
2554 default: 2554 default:
2555 if (!isdigit((unsigned char)sep[1])) 2555 if (!isdigit((unsigned char)sep[1]))
2556 return FALSE; /* ":ts<backslash><unrecognised>". */ 2556 return FALSE; /* ":ts<backslash><unrecognised>". */
2557 2557
2558 char *end; 2558 char *end;
2559 get_numeric: 2559 get_numeric:
2560 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); 2560 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base);
2561 if (*end != ':' && *end != st->endc) 2561 if (*end != ':' && *end != st->endc)
2562 return FALSE; 2562 return FALSE;
2563 st->cp = end; 2563 st->cp = end;
2564 break; 2564 break;
2565 } 2565 }
2566 } else { 2566 } else {
2567 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ 2567 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */
2568 } 2568 }
2569 2569
2570 st->termc = *st->cp; 2570 st->termc = *st->cp;
2571 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2571 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2572 ModifyWord_Copy, NULL); 2572 ModifyWord_Copy, NULL);
2573 return TRUE; 2573 return TRUE;
2574} 2574}
2575 2575
2576/* :tA, :tu, :tl, :ts<separator>, etc. */ 2576/* :tA, :tu, :tl, :ts<separator>, etc. */
2577static Boolean 2577static Boolean
2578ApplyModifier_To(const char *mod, ApplyModifiersState *st) 2578ApplyModifier_To(const char *mod, ApplyModifiersState *st)
2579{ 2579{
2580 st->cp = mod + 1; /* make sure it is set */ 2580 st->cp = mod + 1; /* make sure it is set */
2581 if (mod[1] == st->endc || mod[1] == ':') 2581 if (mod[1] == st->endc || mod[1] == ':')
2582 return FALSE; /* Found ":t<endc>" or ":t:". */ 2582 return FALSE; /* Found ":t<endc>" or ":t:". */
2583 2583
2584 if (mod[1] == 's') 2584 if (mod[1] == 's')
2585 return ApplyModifier_ToSep(mod + 2, st); 2585 return ApplyModifier_ToSep(mod + 2, st);
2586 2586
2587 if (mod[2] != st->endc && mod[2] != ':') 2587 if (mod[2] != st->endc && mod[2] != ':')
2588 return FALSE; /* Found ":t<unrecognised><unrecognised>". */ 2588 return FALSE; /* Found ":t<unrecognised><unrecognised>". */
2589 2589
2590 /* Check for two-character options: ":tu", ":tl" */ 2590 /* Check for two-character options: ":tu", ":tl" */
2591 if (mod[1] == 'A') { /* absolute path */ 2591 if (mod[1] == 'A') { /* absolute path */
2592 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2592 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2593 ModifyWord_Realpath, NULL); 2593 ModifyWord_Realpath, NULL);
2594 st->cp = mod + 2; 2594 st->cp = mod + 2;
2595 st->termc = *st->cp; 2595 st->termc = *st->cp;
2596 } else if (mod[1] == 'u') { 2596 } else if (mod[1] == 'u') {
2597 char *dp = bmake_strdup(st->nstr); 2597 char *dp = bmake_strdup(st->nstr);
2598 for (st->newStr = dp; *dp; dp++) 2598 for (st->newStr = dp; *dp; dp++)
2599 *dp = toupper((unsigned char)*dp); 2599 *dp = toupper((unsigned char)*dp);
2600 st->cp = mod + 2; 2600 st->cp = mod + 2;
2601 st->termc = *st->cp; 2601 st->termc = *st->cp;
2602 } else if (mod[1] == 'l') { 2602 } else if (mod[1] == 'l') {
2603 char *dp = bmake_strdup(st->nstr); 2603 char *dp = bmake_strdup(st->nstr);
2604 for (st->newStr = dp; *dp; dp++) 2604 for (st->newStr = dp; *dp; dp++)
2605 *dp = tolower((unsigned char)*dp); 2605 *dp = tolower((unsigned char)*dp);
2606 st->cp = mod + 2; 2606 st->cp = mod + 2;
2607 st->termc = *st->cp; 2607 st->termc = *st->cp;
2608 } else if (mod[1] == 'W' || mod[1] == 'w') { 2608 } else if (mod[1] == 'W' || mod[1] == 'w') {
2609 st->oneBigWord = mod[1] == 'W'; 2609 st->oneBigWord = mod[1] == 'W';
2610 st->newStr = st->nstr; 2610 st->newStr = st->nstr;
2611 st->cp = mod + 2; 2611 st->cp = mod + 2;
2612 st->termc = *st->cp; 2612 st->termc = *st->cp;
2613 } else { 2613 } else {
2614 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2614 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2615 return FALSE; 2615 return FALSE;
2616 } 2616 }
2617 return TRUE; 2617 return TRUE;
2618} 2618}
2619 2619
2620/* :[#], :[1], etc. */ 2620/* :[#], :[1], etc. */
2621static int 2621static int
2622ApplyModifier_Words(const char *mod, ApplyModifiersState *st) 2622ApplyModifier_Words(const char *mod, ApplyModifiersState *st)
2623{ 2623{
2624 st->cp = mod + 1; /* point to char after '[' */ 2624 st->cp = mod + 1; /* point to char after '[' */
2625 char delim = ']'; /* look for closing ']' */ 2625 char delim = ']'; /* look for closing ']' */
2626 char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2626 char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2627 NULL, NULL, NULL); 2627 NULL, NULL, NULL);
2628 if (estr == NULL) { 2628 if (estr == NULL) {
2629 st->missing_delim = delim; 2629 st->missing_delim = delim;
2630 return 'c'; 2630 return 'c';
2631 } 2631 }
2632 2632
2633 /* now st->cp points just after the closing ']' */ 2633 /* now st->cp points just after the closing ']' */
2634 if (st->cp[0] != ':' && st->cp[0] != st->endc) 2634 if (st->cp[0] != ':' && st->cp[0] != st->endc)
2635 goto bad_modifier; /* Found junk after ']' */ 2635 goto bad_modifier; /* Found junk after ']' */
2636 2636
2637 if (estr[0] == '\0') 2637 if (estr[0] == '\0')
2638 goto bad_modifier; /* empty square brackets in ":[]". */ 2638 goto bad_modifier; /* empty square brackets in ":[]". */
2639 2639
2640 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2640 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2641 if (st->oneBigWord) { 2641 if (st->oneBigWord) {
2642 st->newStr = bmake_strdup("1"); 2642 st->newStr = bmake_strdup("1");
2643 } else { 2643 } else {
2644 /* XXX: brk_string() is a rather expensive 2644 /* XXX: brk_string() is a rather expensive
2645 * way of counting words. */ 2645 * way of counting words. */
2646 char *as; 2646 char *as;
2647 int ac; 2647 int ac;
2648 char **av = brk_string(st->nstr, &ac, FALSE, &as); 2648 char **av = brk_string(st->nstr, &ac, FALSE, &as);
2649 free(as); 2649 free(as);
2650 free(av); 2650 free(av);
2651 2651
2652 Buffer buf; 2652 Buffer buf;
2653 Buf_Init(&buf, 4); /* 3 digits + '\0' */ 2653 Buf_Init(&buf, 4); /* 3 digits + '\0' */
2654 Buf_AddInt(&buf, ac); 2654 Buf_AddInt(&buf, ac);
2655 st->newStr = Buf_Destroy(&buf, FALSE); 2655 st->newStr = Buf_Destroy(&buf, FALSE);
2656 } 2656 }
2657 goto ok; 2657 goto ok;
2658 } 2658 }
2659 2659
2660 if (estr[0] == '*' && estr[1] == '\0') { 2660 if (estr[0] == '*' && estr[1] == '\0') {
2661 /* Found ":[*]" */ 2661 /* Found ":[*]" */
2662 st->oneBigWord = TRUE; 2662 st->oneBigWord = TRUE;
2663 st->newStr = st->nstr; 2663 st->newStr = st->nstr;
2664 goto ok; 2664 goto ok;
2665 } 2665 }
2666 2666
2667 if (estr[0] == '@' && estr[1] == '\0') { 2667 if (estr[0] == '@' && estr[1] == '\0') {
2668 /* Found ":[@]" */ 2668 /* Found ":[@]" */
2669 st->oneBigWord = FALSE; 2669 st->oneBigWord = FALSE;
2670 st->newStr = st->nstr; 2670 st->newStr = st->nstr;
2671 goto ok; 2671 goto ok;
2672 } 2672 }
2673 2673
2674 /* 2674 /*
2675 * We expect estr to contain a single integer for :[N], or two integers 2675 * We expect estr to contain a single integer for :[N], or two integers
2676 * separated by ".." for :[start..end]. 2676 * separated by ".." for :[start..end].
2677 */ 2677 */
2678 char *ep; 2678 char *ep;
2679 int first = strtol(estr, &ep, 0); 2679 int first = strtol(estr, &ep, 0);
2680 int last; 2680 int last;
2681 if (ep == estr) /* Found junk instead of a number */ 2681 if (ep == estr) /* Found junk instead of a number */
2682 goto bad_modifier; 2682 goto bad_modifier;
2683 2683
2684 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2684 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2685 last = first; 2685 last = first;
2686 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2686 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2687 /* Expecting another integer after ".." */ 2687 /* Expecting another integer after ".." */
2688 ep += 2; 2688 ep += 2;
2689 last = strtol(ep, &ep, 0); 2689 last = strtol(ep, &ep, 0);
2690 if (ep[0] != '\0') /* Found junk after ".." */ 2690 if (ep[0] != '\0') /* Found junk after ".." */
2691 goto bad_modifier; 2691 goto bad_modifier;
2692 } else 2692 } else
2693 goto bad_modifier; /* Found junk instead of ".." */ 2693 goto bad_modifier; /* Found junk instead of ".." */
2694 2694
2695 /* 2695 /*
2696 * Now seldata is properly filled in, but we still have to check for 0 as 2696 * Now seldata is properly filled in, but we still have to check for 0 as
2697 * a special case. 2697 * a special case.
2698 */ 2698 */
2699 if (first == 0 && last == 0) { 2699 if (first == 0 && last == 0) {
2700 /* ":[0]" or perhaps ":[0..0]" */ 2700 /* ":[0]" or perhaps ":[0..0]" */
2701 st->oneBigWord = TRUE; 2701 st->oneBigWord = TRUE;
2702 st->newStr = st->nstr; 2702 st->newStr = st->nstr;
2703 goto ok; 2703 goto ok;
2704 } 2704 }
2705 2705
2706 /* ":[0..N]" or ":[N..0]" */ 2706 /* ":[0..N]" or ":[N..0]" */
2707 if (first == 0 || last == 0) 2707 if (first == 0 || last == 0)
2708 goto bad_modifier; 2708 goto bad_modifier;
2709 2709
2710 /* Normal case: select the words described by seldata. */ 2710 /* Normal case: select the words described by seldata. */
2711 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); 2711 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last);
2712 2712
2713ok: 2713ok:
2714 st->termc = *st->cp; 2714 st->termc = *st->cp;
2715 free(estr); 2715 free(estr);
2716 return 0; 2716 return 0;
2717 2717
2718bad_modifier: 2718bad_modifier:
2719 free(estr); 2719 free(estr);
2720 return 'b'; 2720 return 'b';
2721} 2721}
2722 2722
2723/* :O or :Ox */ 2723/* :O or :Ox */
2724static Boolean 2724static Boolean
2725ApplyModifier_Order(const char *mod, ApplyModifiersState *st) 2725ApplyModifier_Order(const char *mod, ApplyModifiersState *st)
2726{ 2726{
2727 char otype; 2727 char otype;
2728 2728
2729 st->cp = mod + 1; /* skip to the rest in any case */ 2729 st->cp = mod + 1; /* skip to the rest in any case */
2730 if (mod[1] == st->endc || mod[1] == ':') { 2730 if (mod[1] == st->endc || mod[1] == ':') {
2731 otype = 's'; 2731 otype = 's';
2732 st->termc = *st->cp; 2732 st->termc = *st->cp;
2733 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2733 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2734 (mod[2] == st->endc || mod[2] == ':')) { 2734 (mod[2] == st->endc || mod[2] == ':')) {
2735 otype = mod[1]; 2735 otype = mod[1];
2736 st->cp = mod + 2; 2736 st->cp = mod + 2;
2737 st->termc = *st->cp; 2737 st->termc = *st->cp;
2738 } else { 2738 } else {
2739 return FALSE; 2739 return FALSE;
2740 } 2740 }
2741 st->newStr = VarOrder(st->nstr, otype); 2741 st->newStr = VarOrder(st->nstr, otype);
2742 return TRUE; 2742 return TRUE;
2743} 2743}
2744 2744
2745/* :? then : else */ 2745/* :? then : else */
2746static Boolean 2746static Boolean
2747ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) 2747ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st)
2748{ 2748{
2749 Boolean value = FALSE; 2749 Boolean value = FALSE;
2750 int cond_rc = 0; 2750 int cond_rc = 0;
2751 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; 2751 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES;
2752 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; 2752 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES;
2753 2753
2754 if (st->eflags & VARE_WANTRES) { 2754 if (st->eflags & VARE_WANTRES) {
2755 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); 2755 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
2756 if (cond_rc != COND_INVALID && value) 2756 if (cond_rc != COND_INVALID && value)
2757 then_eflags |= VARE_WANTRES; 2757 then_eflags |= VARE_WANTRES;
2758 if (cond_rc != COND_INVALID && !value) 2758 if (cond_rc != COND_INVALID && !value)
2759 else_eflags |= VARE_WANTRES; 2759 else_eflags |= VARE_WANTRES;
2760 } 2760 }
2761 2761
2762 st->cp = mod + 1; 2762 st->cp = mod + 1;
2763 char delim = ':'; 2763 char delim = ':';
2764 char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt, 2764 char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt,
2765 NULL, NULL, NULL); 2765 NULL, NULL, NULL);
2766 if (then_expr == NULL) { 2766 if (then_expr == NULL) {
2767 st->missing_delim = delim; 2767 st->missing_delim = delim;
2768 return FALSE; 2768 return FALSE;
2769 } 2769 }
2770 2770
2771 delim = st->endc; /* BRCLOSE or PRCLOSE */ 2771 delim = st->endc; /* BRCLOSE or PRCLOSE */
2772 char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt, 2772 char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt,
2773 NULL, NULL, NULL); 2773 NULL, NULL, NULL);
2774 if (else_expr == NULL) { 2774 if (else_expr == NULL) {
2775 st->missing_delim = delim; 2775 st->missing_delim = delim;
2776 return FALSE; 2776 return FALSE;
2777 } 2777 }
2778 2778
2779 st->termc = *--st->cp; 2779 st->termc = *--st->cp;
2780 if (cond_rc == COND_INVALID) { 2780 if (cond_rc == COND_INVALID) {
2781 Error("Bad conditional expression `%s' in %s?%s:%s", 2781 Error("Bad conditional expression `%s' in %s?%s:%s",
2782 st->v->name, st->v->name, then_expr, else_expr); 2782 st->v->name, st->v->name, then_expr, else_expr);
2783 return FALSE; 2783 return FALSE;
2784 } 2784 }
2785 2785
2786 if (value) { 2786 if (value) {
2787 st->newStr = then_expr; 2787 st->newStr = then_expr;
2788 free(else_expr); 2788 free(else_expr);
2789 } else { 2789 } else {
2790 st->newStr = else_expr; 2790 st->newStr = else_expr;
2791 free(then_expr); 2791 free(then_expr);
2792 } 2792 }
2793 if (st->v->flags & VAR_JUNK) 2793 if (st->v->flags & VAR_JUNK)
2794 st->v->flags |= VAR_KEEP; 2794 st->v->flags |= VAR_KEEP;
2795 return TRUE; 2795 return TRUE;
2796} 2796}
2797 2797
2798/* 2798/*
2799 * The ::= modifiers actually assign a value to the variable. 2799 * The ::= modifiers actually assign a value to the variable.
2800 * Their main purpose is in supporting modifiers of .for loop 2800 * Their main purpose is in supporting modifiers of .for loop
2801 * iterators and other obscure uses. They always expand to 2801 * iterators and other obscure uses. They always expand to
2802 * nothing. In a target rule that would otherwise expand to an 2802 * nothing. In a target rule that would otherwise expand to an
2803 * empty line they can be preceded with @: to keep make happy. 2803 * empty line they can be preceded with @: to keep make happy.
2804 * Eg. 2804 * Eg.
2805 * 2805 *
2806 * foo: .USE 2806 * foo: .USE
2807 * .for i in ${.TARGET} ${.TARGET:R}.gz 2807 * .for i in ${.TARGET} ${.TARGET:R}.gz
2808 * @: ${t::=$i} 2808 * @: ${t::=$i}
2809 * @echo blah ${t:T} 2809 * @echo blah ${t:T}
2810 * .endfor 2810 * .endfor
2811 * 2811 *
2812 * ::=<str> Assigns <str> as the new value of variable. 2812 * ::=<str> Assigns <str> as the new value of variable.
2813 * ::?=<str> Assigns <str> as value of variable if 2813 * ::?=<str> Assigns <str> as value of variable if
2814 * it was not already set. 2814 * it was not already set.
2815 * ::+=<str> Appends <str> to variable. 2815 * ::+=<str> Appends <str> to variable.
2816 * ::!=<cmd> Assigns output of <cmd> as the new value of 2816 * ::!=<cmd> Assigns output of <cmd> as the new value of
2817 * variable. 2817 * variable.
2818 */ 2818 */
2819static int 2819static int
2820ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) 2820ApplyModifier_Assign(const char *mod, ApplyModifiersState *st)
2821{ 2821{
2822 const char *op = mod + 1; 2822 const char *op = mod + 1;
2823 if (!(op[0] == '=' || 2823 if (!(op[0] == '=' ||
2824 (op[1] == '=' && 2824 (op[1] == '=' &&
2825 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2825 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2826 return 'd'; /* "::<unrecognised>" */ 2826 return 'd'; /* "::<unrecognised>" */
2827 2827
2828 GNode *v_ctxt; /* context where v belongs */ 2828 GNode *v_ctxt; /* context where v belongs */
2829 2829
2830 if (st->v->name[0] == 0) 2830 if (st->v->name[0] == 0)
2831 return 'b'; 2831 return 'b';
2832 2832
2833 v_ctxt = st->ctxt; 2833 v_ctxt = st->ctxt;
2834 char *sv_name = NULL; 2834 char *sv_name = NULL;
2835 if (st->v->flags & VAR_JUNK) { 2835 if (st->v->flags & VAR_JUNK) {
2836 /* 2836 /*
2837 * We need to bmake_strdup() it incase ParseModifierPart() recurses. 2837 * We need to bmake_strdup() it incase ParseModifierPart() recurses.
2838 */ 2838 */
2839 sv_name = st->v->name; 2839 sv_name = st->v->name;
2840 st->v->name = bmake_strdup(st->v->name); 2840 st->v->name = bmake_strdup(st->v->name);
2841 } else if (st->ctxt != VAR_GLOBAL) { 2841 } else if (st->ctxt != VAR_GLOBAL) {
2842 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2842 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2843 if (gv == NULL) 2843 if (gv == NULL)
2844 v_ctxt = VAR_GLOBAL; 2844 v_ctxt = VAR_GLOBAL;
2845 else 2845 else
2846 VarFreeEnv(gv, TRUE); 2846 VarFreeEnv(gv, TRUE);
2847 } 2847 }
2848 2848
2849 switch (op[0]) { 2849 switch (op[0]) {
2850 case '+': 2850 case '+':
2851 case '?': 2851 case '?':
2852 case '!': 2852 case '!':
2853 st->cp = mod + 3; 2853 st->cp = mod + 3;
2854 break; 2854 break;
2855 default: 2855 default:
2856 st->cp = mod + 2; 2856 st->cp = mod + 2;
2857 break; 2857 break;
2858 } 2858 }
2859 2859
2860 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; 2860 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
2861 char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2861 char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2862 NULL, NULL, NULL); 2862 NULL, NULL, NULL);
2863 if (st->v->flags & VAR_JUNK) { 2863 if (st->v->flags & VAR_JUNK) {
2864 /* restore original name */ 2864 /* restore original name */
2865 free(st->v->name); 2865 free(st->v->name);
2866 st->v->name = sv_name; 2866 st->v->name = sv_name;
2867 } 2867 }
2868 if (val == NULL) { 2868 if (val == NULL) {
2869 st->missing_delim = delim; 2869 st->missing_delim = delim;
2870 return 'c'; 2870 return 'c';
2871 } 2871 }
2872 2872
2873 st->termc = *--st->cp; 2873 st->termc = *--st->cp;
2874 2874
2875 if (st->eflags & VARE_WANTRES) { 2875 if (st->eflags & VARE_WANTRES) {
2876 switch (op[0]) { 2876 switch (op[0]) {
2877 case '+': 2877 case '+':
2878 Var_Append(st->v->name, val, v_ctxt); 2878 Var_Append(st->v->name, val, v_ctxt);
2879 break; 2879 break;
2880 case '!': { 2880 case '!': {
2881 const char *emsg; 2881 const char *emsg;
2882 st->newStr = Cmd_Exec(val, &emsg); 2882 st->newStr = Cmd_Exec(val, &emsg);
2883 if (emsg) 2883 if (emsg)
2884 Error(emsg, st->nstr); 2884 Error(emsg, st->nstr);
2885 else 2885 else
2886 Var_Set(st->v->name, st->newStr, v_ctxt); 2886 Var_Set(st->v->name, st->newStr, v_ctxt);
2887 free(st->newStr); 2887 free(st->newStr);
2888 break; 2888 break;
2889 } 2889 }
2890 case '?': 2890 case '?':
2891 if ((st->v->flags & VAR_JUNK) == 0) 2891 if ((st->v->flags & VAR_JUNK) == 0)
2892 break; 2892 break;
2893 /* FALLTHROUGH */ 2893 /* FALLTHROUGH */
2894 default: 2894 default:
2895 Var_Set(st->v->name, val, v_ctxt); 2895 Var_Set(st->v->name, val, v_ctxt);
2896 break; 2896 break;
2897 } 2897 }
2898 } 2898 }
2899 free(val); 2899 free(val);
2900 st->newStr = varNoError; 2900 st->newStr = varNoError;
2901 return 0; 2901 return 0;
2902} 2902}
2903 2903
2904/* remember current value */ 2904/* remember current value */
2905static Boolean 2905static Boolean
2906ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) 2906ApplyModifier_Remember(const char *mod, ApplyModifiersState *st)
2907{ 2907{
2908 st->cp = mod + 1; /* make sure it is set */ 2908 st->cp = mod + 1; /* make sure it is set */
2909 if (!STRMOD_MATCHX(mod, "_", 1)) 2909 if (!STRMOD_MATCHX(mod, "_", 1))
2910 return FALSE; 2910 return FALSE;
2911 2911
2912 if (mod[1] == '=') { 2912 if (mod[1] == '=') {
2913 char *np; 2913 char *np;
2914 int n; 2914 int n;
2915 2915
2916 st->cp++; 2916 st->cp++;
2917 n = strcspn(st->cp, ":)}"); 2917 n = strcspn(st->cp, ":)}");
2918 np = bmake_strndup(st->cp, n + 1); 2918 np = bmake_strndup(st->cp, n + 1);
2919 np[n] = '\0'; 2919 np[n] = '\0';
2920 st->cp = mod + 2 + n; 2920 st->cp = mod + 2 + n;
2921 Var_Set(np, st->nstr, st->ctxt); 2921 Var_Set(np, st->nstr, st->ctxt);
2922 free(np); 2922 free(np);
2923 } else { 2923 } else {
2924 Var_Set("_", st->nstr, st->ctxt); 2924 Var_Set("_", st->nstr, st->ctxt);
2925 } 2925 }
2926 st->newStr = st->nstr; 2926 st->newStr = st->nstr;
2927 st->termc = *st->cp; 2927 st->termc = *st->cp;
2928 return TRUE; 2928 return TRUE;
2929} 2929}
2930 2930
2931#ifdef SYSVVARSUB 2931#ifdef SYSVVARSUB
2932/* :from=to */ 2932/* :from=to */
2933static int 2933static int
2934ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) 2934ApplyModifier_SysV(const char *mod, ApplyModifiersState *st)
2935{ 2935{
2936 Boolean eqFound = FALSE; 2936 Boolean eqFound = FALSE;
2937 2937
2938 /* 2938 /*
2939 * First we make a pass through the string trying 2939 * First we make a pass through the string trying
2940 * to verify it is a SYSV-make-style translation: 2940 * to verify it is a SYSV-make-style translation:
2941 * it must be: <string1>=<string2>) 2941 * it must be: <string1>=<string2>)
2942 */ 2942 */
2943 st->cp = mod; 2943 st->cp = mod;
2944 int nest = 1; 2944 int nest = 1;
2945 while (*st->cp != '\0' && nest > 0) { 2945 while (*st->cp != '\0' && nest > 0) {
2946 if (*st->cp == '=') { 2946 if (*st->cp == '=') {
2947 eqFound = TRUE; 2947 eqFound = TRUE;
2948 /* continue looking for st->endc */ 2948 /* continue looking for st->endc */
2949 } else if (*st->cp == st->endc) 2949 } else if (*st->cp == st->endc)
2950 nest--; 2950 nest--;
2951 else if (*st->cp == st->startc) 2951 else if (*st->cp == st->startc)
2952 nest++; 2952 nest++;
2953 if (nest > 0) 2953 if (nest > 0)
2954 st->cp++; 2954 st->cp++;
2955 } 2955 }
2956 if (*st->cp != st->endc || !eqFound) 2956 if (*st->cp != st->endc || !eqFound)
2957 return 0; 2957 return 0;
2958 2958
2959 char delim = '='; 2959 char delim = '=';
2960 st->cp = mod; 2960 st->cp = mod;
2961 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2961 char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2962 NULL, NULL, NULL); 2962 NULL, NULL, NULL);
2963 if (lhs == NULL) { 2963 if (lhs == NULL) {
2964 st->missing_delim = delim; 2964 st->missing_delim = delim;
2965 return 'c'; 2965 return 'c';
2966 } 2966 }
2967 2967
2968 delim = st->endc; 2968 delim = st->endc;
2969 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, 2969 char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt,
2970 NULL, NULL, NULL); 2970 NULL, NULL, NULL);
2971 if (rhs == NULL) { 2971 if (rhs == NULL) {
2972 st->missing_delim = delim; 2972 st->missing_delim = delim;
2973 return 'c'; 2973 return 'c';
2974 } 2974 }
2975 2975
2976 /* 2976 /*
2977 * SYSV modifications happen through the whole 2977 * SYSV modifications happen through the whole
2978 * string. Note the pattern is anchored at the end. 2978 * string. Note the pattern is anchored at the end.
2979 */ 2979 */
2980 st->termc = *--st->cp; 2980 st->termc = *--st->cp;
2981 if (lhs[0] == '\0' && *st->nstr == '\0') { 2981 if (lhs[0] == '\0' && *st->nstr == '\0') {
2982 st->newStr = st->nstr; /* special case */ 2982 st->newStr = st->nstr; /* special case */
2983 } else { 2983 } else {
2984 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; 2984 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
2985 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2985 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2986 ModifyWord_SYSVSubst, &args); 2986 ModifyWord_SYSVSubst, &args);
2987 } 2987 }
2988 free(lhs); 2988 free(lhs);
2989 free(rhs); 2989 free(rhs);
2990 return '='; 2990 return '=';
2991} 2991}
2992#endif 2992#endif
2993 2993
2994/* 2994/*
2995 * Now we need to apply any modifiers the user wants applied. 2995 * Now we need to apply any modifiers the user wants applied.
2996 * These are: 2996 * These are:
2997 * :M<pattern> words which match the given <pattern>. 2997 * :M<pattern> words which match the given <pattern>.
2998 * <pattern> is of the standard file 2998 * <pattern> is of the standard file
2999 * wildcarding form. 2999 * wildcarding form.
3000 * :N<pattern> words which do not match the given <pattern>. 3000 * :N<pattern> words which do not match the given <pattern>.
3001 * :S<d><pat1><d><pat2><d>[1gW] 3001 * :S<d><pat1><d><pat2><d>[1gW]
3002 * Substitute <pat2> for <pat1> in the value 3002 * Substitute <pat2> for <pat1> in the value
3003 * :C<d><pat1><d><pat2><d>[1gW] 3003 * :C<d><pat1><d><pat2><d>[1gW]
3004 * Substitute <pat2> for regex <pat1> in the value 3004 * Substitute <pat2> for regex <pat1> in the value
3005 * :H Substitute the head of each word 3005 * :H Substitute the head of each word
3006 * :T Substitute the tail of each word 3006 * :T Substitute the tail of each word
3007 * :E Substitute the extension (minus '.') of 3007 * :E Substitute the extension (minus '.') of
3008 * each word 3008 * each word
3009 * :R Substitute the root of each word 3009 * :R Substitute the root of each word
3010 * (pathname minus the suffix). 3010 * (pathname minus the suffix).
3011 * :O ("Order") Alphabeticaly sort words in variable. 3011 * :O ("Order") Alphabeticaly sort words in variable.
3012 * :Ox ("intermiX") Randomize words in variable. 3012 * :Ox ("intermiX") Randomize words in variable.
3013 * :u ("uniq") Remove adjacent duplicate words. 3013 * :u ("uniq") Remove adjacent duplicate words.
3014 * :tu Converts the variable contents to uppercase. 3014 * :tu Converts the variable contents to uppercase.
3015 * :tl Converts the variable contents to lowercase. 3015 * :tl Converts the variable contents to lowercase.
3016 * :ts[c] Sets varSpace - the char used to 3016 * :ts[c] Sets varSpace - the char used to
3017 * separate words to 'c'. If 'c' is 3017 * separate words to 'c'. If 'c' is
3018 * omitted then no separation is used. 3018 * omitted then no separation is used.
3019 * :tW Treat the variable contents as a single 3019 * :tW Treat the variable contents as a single
3020 * word, even if it contains spaces. 3020 * word, even if it contains spaces.
3021 * (Mnemonic: one big 'W'ord.) 3021 * (Mnemonic: one big 'W'ord.)
3022 * :tw Treat the variable contents as multiple 3022 * :tw Treat the variable contents as multiple
3023 * space-separated words. 3023 * space-separated words.
3024 * (Mnemonic: many small 'w'ords.) 3024 * (Mnemonic: many small 'w'ords.)
3025 * :[index] Select a single word from the value. 3025 * :[index] Select a single word from the value.
3026 * :[start..end] Select multiple words from the value. 3026 * :[start..end] Select multiple words from the value.
3027 * :[*] or :[0] Select the entire value, as a single 3027 * :[*] or :[0] Select the entire value, as a single
3028 * word. Equivalent to :tW. 3028 * word. Equivalent to :tW.
3029 * :[@] Select the entire value, as multiple 3029 * :[@] Select the entire value, as multiple
3030 * words. Undoes the effect of :[*]. 3030 * words. Undoes the effect of :[*].
3031 * Equivalent to :tw. 3031 * Equivalent to :tw.
3032 * :[#] Returns the number of words in the value. 3032 * :[#] Returns the number of words in the value.
3033 * 3033 *
3034 * :?<true-value>:<false-value> 3034 * :?<true-value>:<false-value>
3035 * If the variable evaluates to true, return 3035 * If the variable evaluates to true, return
3036 * true value, else return the second value. 3036 * true value, else return the second value.
3037 * :lhs=rhs Like :S, but the rhs goes to the end of 3037 * :lhs=rhs Like :S, but the rhs goes to the end of
3038 * the invocation. 3038 * the invocation.
3039 * :sh Treat the current value as a command 3039 * :sh Treat the current value as a command
3040 * to be run, new value is its output. 3040 * to be run, new value is its output.
3041 * The following added so we can handle ODE makefiles. 3041 * The following added so we can handle ODE makefiles.
3042 * :@<tmpvar>@<newval>@ 3042 * :@<tmpvar>@<newval>@
3043 * Assign a temporary local variable <tmpvar> 3043 * Assign a temporary local variable <tmpvar>
3044 * to the current value of each word in turn 3044 * to the current value of each word in turn
3045 * and replace each word with the result of 3045 * and replace each word with the result of
3046 * evaluating <newval> 3046 * evaluating <newval>
3047 * :D<newval> Use <newval> as value if variable defined 3047 * :D<newval> Use <newval> as value if variable defined
3048 * :U<newval> Use <newval> as value if variable undefined 3048 * :U<newval> Use <newval> as value if variable undefined
3049 * :L Use the name of the variable as the value. 3049 * :L Use the name of the variable as the value.
3050 * :P Use the path of the node that has the same 3050 * :P Use the path of the node that has the same
3051 * name as the variable as the value. This 3051 * name as the variable as the value. This
3052 * basically includes an implied :L so that 3052 * basically includes an implied :L so that
3053 * the common method of refering to the path 3053 * the common method of refering to the path
3054 * of your dependent 'x' in a rule is to use 3054 * of your dependent 'x' in a rule is to use
3055 * the form '${x:P}'. 3055 * the form '${x:P}'.
3056 * :!<cmd>! Run cmd much the same as :sh run's the 3056 * :!<cmd>! Run cmd much the same as :sh run's the
3057 * current value of the variable. 3057 * current value of the variable.
3058 * Assignment operators (see ApplyModifier_Assign). 3058 * Assignment operators (see ApplyModifier_Assign).
3059 */ 3059 */
3060static char * 3060static char *
3061ApplyModifiers(char *nstr, const char *tstr, 3061ApplyModifiers(char *nstr, const char *tstr,
3062 int const startc, int const endc, 3062 int const startc, int const endc,
3063 Var * const v, GNode * const ctxt, VarEvalFlags const eflags, 3063 Var * const v, GNode * const ctxt, VarEvalFlags const eflags,
3064 int * const lengthPtr, void ** const freePtr) 3064 int * const lengthPtr, void ** const freePtr)
3065{ 3065{
3066 ApplyModifiersState st = { 3066 ApplyModifiersState st = {
3067 startc, endc, v, ctxt, eflags, lengthPtr, freePtr, 3067 startc, endc, v, ctxt, eflags, lengthPtr, freePtr,
3068 nstr, tstr, tstr, 3068 nstr, tstr, tstr,
3069 '\0', '\0', 0, ' ', FALSE, NULL 3069 '\0', '\0', 0, ' ', FALSE, NULL
3070 }; 3070 };
3071 3071
3072 const char *p = tstr; 3072 const char *p = tstr;
3073 while (*p != '\0' && *p != endc) { 3073 while (*p != '\0' && *p != endc) {
3074 3074
3075 if (*p == '$') { 3075 if (*p == '$') {
3076 /* 3076 /*
3077 * We may have some complex modifiers in a variable. 3077 * We may have some complex modifiers in a variable.
3078 */ 3078 */
3079 void *freeIt; 3079 void *freeIt;
3080 char *rval; 3080 char *rval;
3081 int rlen; 3081 int rlen;
3082 int c; 3082 int c;
3083 3083
3084 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt); 3084 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt);
3085 3085
3086 /* 3086 /*
3087 * If we have not parsed up to st.endc or ':', 3087 * If we have not parsed up to st.endc or ':',
3088 * we are not interested. 3088 * we are not interested.
3089 */ 3089 */
3090 if (rval != NULL && *rval && 3090 if (rval != NULL && *rval &&
3091 (c = p[rlen]) != '\0' && 3091 (c = p[rlen]) != '\0' &&
3092 c != ':' && 3092 c != ':' &&
3093 c != st.endc) { 3093 c != st.endc) {
3094 free(freeIt); 3094 free(freeIt);
3095 goto apply_mods; 3095 goto apply_mods;
3096 } 3096 }
3097 3097
3098 if (DEBUG(VAR)) { 3098 if (DEBUG(VAR)) {
3099 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", 3099 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3100 rval, rlen, p, rlen, p + rlen); 3100 rval, rlen, p, rlen, p + rlen);
3101 } 3101 }
3102 3102
3103 p += rlen; 3103 p += rlen;
3104 3104
3105 if (rval != NULL && *rval) { 3105 if (rval != NULL && *rval) {
3106 int used; 3106 int used;
3107 3107
3108 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v, 3108 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3109 st.ctxt, st.eflags, &used, st.freePtr); 3109 st.ctxt, st.eflags, &used, st.freePtr);
3110 if (st.nstr == var_Error 3110 if (st.nstr == var_Error
3111 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0) 3111 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0)
3112 || strlen(rval) != (size_t) used) { 3112 || strlen(rval) != (size_t) used) {
3113 free(freeIt); 3113 free(freeIt);
3114 goto out; /* error already reported */ 3114 goto out; /* error already reported */
3115 } 3115 }
3116 } 3116 }
3117 free(freeIt); 3117 free(freeIt);
3118 if (*p == ':') 3118 if (*p == ':')
3119 p++; 3119 p++;
3120 else if (*p == '\0' && endc != '\0') { 3120 else if (*p == '\0' && endc != '\0') {
3121 Error("Unclosed variable specification after complex " 3121 Error("Unclosed variable specification after complex "
3122 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3122 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3123 goto out; 3123 goto out;
3124 } 3124 }
3125 continue; 3125 continue;
3126 } 3126 }
3127 apply_mods: 3127 apply_mods:
3128 if (DEBUG(VAR)) { 3128 if (DEBUG(VAR)) {
3129 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, 3129 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3130 *p, st.nstr); 3130 *p, st.nstr);
3131 } 3131 }
3132 st.newStr = var_Error; 3132 st.newStr = var_Error;
3133 switch ((st.modifier = *p)) { 3133 switch ((st.modifier = *p)) {
3134 case ':': 3134 case ':':
3135 { 3135 {
3136 int res = ApplyModifier_Assign(p, &st); 3136 int res = ApplyModifier_Assign(p, &st);
3137 if (res == 'b') 3137 if (res == 'b')
3138 goto bad_modifier; 3138 goto bad_modifier;
3139 if (res == 'c') 3139 if (res == 'c')
3140 goto cleanup; 3140 goto cleanup;
3141 if (res == 'd') 3141 if (res == 'd')
3142 goto default_case; 3142 goto default_case;
3143 break; 3143 break;
3144 } 3144 }
3145 case '@': 3145 case '@':
3146 if (!ApplyModifier_Loop(p, &st)) 3146 if (!ApplyModifier_Loop(p, &st))
3147 goto cleanup; 3147 goto cleanup;
3148 break; 3148 break;
3149 case '_': 3149 case '_':
3150 if (!ApplyModifier_Remember(p, &st)) 3150 if (!ApplyModifier_Remember(p, &st))
3151 goto default_case; 3151 goto default_case;
3152 break; 3152 break;
3153 case 'D': 3153 case 'D':
3154 case 'U': 3154 case 'U':
3155 ApplyModifier_Defined(p, &st); 3155 ApplyModifier_Defined(p, &st);
3156 break; 3156 break;
3157 case 'L': 3157 case 'L':
3158 { 3158 {
3159 if ((st.v->flags & VAR_JUNK) != 0) 3159 if ((st.v->flags & VAR_JUNK) != 0)
3160 st.v->flags |= VAR_KEEP; 3160 st.v->flags |= VAR_KEEP;
3161 st.newStr = bmake_strdup(st.v->name); 3161 st.newStr = bmake_strdup(st.v->name);
3162 st.cp = p + 1; 3162 st.cp = p + 1;
3163 st.termc = *st.cp; 3163 st.termc = *st.cp;
3164 break; 3164 break;
3165 } 3165 }
3166 case 'P': 3166 case 'P':
3167 ApplyModifier_Path(p, &st); 3167 ApplyModifier_Path(p, &st);
3168 break; 3168 break;
3169 case '!': 3169 case '!':
3170 if (!ApplyModifier_Exclam(p, &st)) 3170 if (!ApplyModifier_Exclam(p, &st))
3171 goto cleanup; 3171 goto cleanup;
3172 break; 3172 break;
3173 case '[': 3173 case '[':
3174 { 3174 {
3175 int res = ApplyModifier_Words(p, &st); 3175 int res = ApplyModifier_Words(p, &st);
3176 if (res == 'b') 3176 if (res == 'b')
3177 goto bad_modifier; 3177 goto bad_modifier;
3178 if (res == 'c') 3178 if (res == 'c')
3179 goto cleanup; 3179 goto cleanup;
3180 break; 3180 break;
3181 } 3181 }
3182 case 'g': 3182 case 'g':
3183 if (!ApplyModifier_Gmtime(p, &st)) 3183 if (!ApplyModifier_Gmtime(p, &st))
3184 goto default_case; 3184 goto default_case;
3185 break; 3185 break;
3186 case 'h': 3186 case 'h':
3187 if (!ApplyModifier_Hash(p, &st)) 3187 if (!ApplyModifier_Hash(p, &st))
3188 goto default_case; 3188 goto default_case;
3189 break; 3189 break;
3190 case 'l': 3190 case 'l':
3191 if (!ApplyModifier_Localtime(p, &st)) 3191 if (!ApplyModifier_Localtime(p, &st))
3192 goto default_case; 3192 goto default_case;
3193 break; 3193 break;
3194 case 't': 3194 case 't':
3195 if (!ApplyModifier_To(p, &st)) 3195 if (!ApplyModifier_To(p, &st))
3196 goto bad_modifier; 3196 goto bad_modifier;
3197 break; 3197 break;
3198 case 'N': 3198 case 'N':
3199 case 'M': 3199 case 'M':
3200 ApplyModifier_Match(p, &st); 3200 ApplyModifier_Match(p, &st);
3201 break; 3201 break;
3202 case 'S': 3202 case 'S':
3203 if (!ApplyModifier_Subst(p, &st)) 3203 if (!ApplyModifier_Subst(p, &st))
3204 goto cleanup; 3204 goto cleanup;
3205 break; 3205 break;
3206 case '?': 3206 case '?':
3207 if (!ApplyModifier_IfElse(p, &st)) 3207 if (!ApplyModifier_IfElse(p, &st))
3208 goto cleanup; 3208 goto cleanup;
3209 break; 3209 break;
3210#ifndef NO_REGEX 3210#ifndef NO_REGEX
3211 case 'C': 3211 case 'C':
3212 if (!ApplyModifier_Regex(p, &st)) 3212 if (!ApplyModifier_Regex(p, &st))
3213 goto cleanup; 3213 goto cleanup;
3214 break; 3214 break;
3215#endif 3215#endif
3216 case 'q': 3216 case 'q':
3217 case 'Q': 3217 case 'Q':
3218 if (p[1] == st.endc || p[1] == ':') { 3218 if (p[1] == st.endc || p[1] == ':') {
3219 st.newStr = VarQuote(st.nstr, st.modifier == 'q'); 3219 st.newStr = VarQuote(st.nstr, st.modifier == 'q');
3220 st.cp = p + 1; 3220 st.cp = p + 1;
3221 st.termc = *st.cp; 3221 st.termc = *st.cp;
3222 break; 3222 break;
3223 } 3223 }
3224 goto default_case; 3224 goto default_case;
3225 case 'T': 3225 case 'T':
3226 if (p[1] == st.endc || p[1] == ':') { 3226 if (p[1] == st.endc || p[1] == ':') {
3227 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3227 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3228 st.nstr, ModifyWord_Tail, NULL); 3228 st.nstr, ModifyWord_Tail, NULL);
3229 st.cp = p + 1; 3229 st.cp = p + 1;
3230 st.termc = *st.cp; 3230 st.termc = *st.cp;
3231 break; 3231 break;
3232 } 3232 }
3233 goto default_case; 3233 goto default_case;
3234 case 'H': 3234 case 'H':
3235 if (p[1] == st.endc || p[1] == ':') { 3235 if (p[1] == st.endc || p[1] == ':') {
3236 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3236 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3237 st.nstr, ModifyWord_Head, NULL); 3237 st.nstr, ModifyWord_Head, NULL);
3238 st.cp = p + 1; 3238 st.cp = p + 1;
3239 st.termc = *st.cp; 3239 st.termc = *st.cp;
3240 break; 3240 break;
3241 } 3241 }
3242 goto default_case; 3242 goto default_case;
3243 case 'E': 3243 case 'E':
3244 if (p[1] == st.endc || p[1] == ':') { 3244 if (p[1] == st.endc || p[1] == ':') {
3245 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3245 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3246 st.nstr, ModifyWord_Suffix, NULL); 3246 st.nstr, ModifyWord_Suffix, NULL);
3247 st.cp = p + 1; 3247 st.cp = p + 1;
3248 st.termc = *st.cp; 3248 st.termc = *st.cp;
3249 break; 3249 break;
3250 } 3250 }
3251 goto default_case; 3251 goto default_case;
3252 case 'R': 3252 case 'R':
3253 if (p[1] == st.endc || p[1] == ':') { 3253 if (p[1] == st.endc || p[1] == ':') {
3254 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3254 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3255 st.nstr, ModifyWord_Root, NULL); 3255 st.nstr, ModifyWord_Root, NULL);
3256 st.cp = p + 1; 3256 st.cp = p + 1;
3257 st.termc = *st.cp; 3257 st.termc = *st.cp;
3258 break; 3258 break;
3259 } 3259 }
3260 goto default_case; 3260 goto default_case;
3261 case 'r': 3261 case 'r':
3262 if (!ApplyModifier_Range(p, &st)) 3262 if (!ApplyModifier_Range(p, &st))
3263 goto default_case; 3263 goto default_case;
3264 break; 3264 break;
3265 case 'O': 3265 case 'O':
3266 if (!ApplyModifier_Order(p, &st)) 3266 if (!ApplyModifier_Order(p, &st))
3267 goto bad_modifier; 3267 goto bad_modifier;
3268 break; 3268 break;
3269 case 'u': 3269 case 'u':
3270 if (p[1] == st.endc || p[1] == ':') { 3270 if (p[1] == st.endc || p[1] == ':') {
3271 st.newStr = VarUniq(st.nstr); 3271 st.newStr = VarUniq(st.nstr);
3272 st.cp = p + 1; 3272 st.cp = p + 1;
3273 st.termc = *st.cp; 3273 st.termc = *st.cp;
3274 break; 3274 break;
3275 } 3275 }
3276 goto default_case; 3276 goto default_case;
3277#ifdef SUNSHCMD 3277#ifdef SUNSHCMD
3278 case 's': 3278 case 's':
3279 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { 3279 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) {
3280 const char *emsg; 3280 const char *emsg;
3281 if (st.eflags & VARE_WANTRES) { 3281 if (st.eflags & VARE_WANTRES) {
3282 st.newStr = Cmd_Exec(st.nstr, &emsg); 3282 st.newStr = Cmd_Exec(st.nstr, &emsg);
3283 if (emsg) 3283 if (emsg)
3284 Error(emsg, st.nstr); 3284 Error(emsg, st.nstr);
3285 } else 3285 } else
3286 st.newStr = varNoError; 3286 st.newStr = varNoError;
3287 st.cp = p + 2; 3287 st.cp = p + 2;
3288 st.termc = *st.cp; 3288 st.termc = *st.cp;
3289 break; 3289 break;
3290 } 3290 }
3291 goto default_case; 3291 goto default_case;
3292#endif 3292#endif
3293 default: 3293 default:
3294 default_case: 3294 default_case:
3295 { 3295 {
3296#ifdef SYSVVARSUB 3296#ifdef SYSVVARSUB
3297 int res = ApplyModifier_SysV(p, &st); 3297 int res = ApplyModifier_SysV(p, &st);
3298 if (res == 'c') 3298 if (res == 'c')
3299 goto cleanup; 3299 goto cleanup;
3300 if (res != '=') 3300 if (res != '=')
3301#endif 3301#endif
3302 { 3302 {
3303 Error("Unknown modifier '%c'", *p); 3303 Error("Unknown modifier '%c'", *p);
3304 for (st.cp = p + 1; 3304 for (st.cp = p + 1;
3305 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; 3305 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3306 st.cp++) 3306 st.cp++)
3307 continue; 3307 continue;
3308 st.termc = *st.cp; 3308 st.termc = *st.cp;
3309 st.newStr = var_Error; 3309 st.newStr = var_Error;
3310 } 3310 }
3311 } 3311 }
3312 } 3312 }
3313 if (DEBUG(VAR)) { 3313 if (DEBUG(VAR)) {
3314 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", 3314 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3315 st.v->name, st.modifier, st.newStr); 3315 st.v->name, st.modifier, st.newStr);
3316 } 3316 }
3317 3317
3318 if (st.newStr != st.nstr) { 3318 if (st.newStr != st.nstr) {
3319 if (*st.freePtr) { 3319 if (*st.freePtr) {
3320 free(st.nstr); 3320 free(st.nstr);
3321 *st.freePtr = NULL; 3321 *st.freePtr = NULL;
3322 } 3322 }
3323 st.nstr = st.newStr; 3323 st.nstr = st.newStr;
3324 if (st.nstr != var_Error && st.nstr != varNoError) { 3324 if (st.nstr != var_Error && st.nstr != varNoError) {
3325 *st.freePtr = st.nstr; 3325 *st.freePtr = st.nstr;
3326 } 3326 }
3327 } 3327 }
3328 if (st.termc == '\0' && st.endc != '\0') { 3328 if (st.termc == '\0' && st.endc != '\0') {
3329 Error("Unclosed variable specification (expecting '%c') " 3329 Error("Unclosed variable specification (expecting '%c') "
3330 "for \"%s\" (value \"%s\") modifier %c", 3330 "for \"%s\" (value \"%s\") modifier %c",
3331 st.endc, st.v->name, st.nstr, st.modifier); 3331 st.endc, st.v->name, st.nstr, st.modifier);
3332 } else if (st.termc == ':') { 3332 } else if (st.termc == ':') {
3333 st.cp++; 3333 st.cp++;
3334 } 3334 }
3335 p = st.cp; 3335 p = st.cp;
3336 } 3336 }
3337out: 3337out:
3338 *st.lengthPtr = p - st.start; 3338 *st.lengthPtr = p - st.start;
3339 return st.nstr; 3339 return st.nstr;
3340 3340
3341bad_modifier: 3341bad_modifier:
3342 Error("Bad modifier `:%.*s' for %s", 3342 Error("Bad modifier `:%.*s' for %s",
3343 (int)strcspn(p, ":)}"), p, st.v->name); 3343 (int)strcspn(p, ":)}"), p, st.v->name);
3344 3344
3345cleanup: 3345cleanup:
3346 *st.lengthPtr = st.cp - st.start; 3346 *st.lengthPtr = st.cp - st.start;
3347 if (st.missing_delim != '\0') 3347 if (st.missing_delim != '\0')
3348 Error("Unclosed substitution for %s (%c missing)", 3348 Error("Unclosed substitution for %s (%c missing)",
3349 st.v->name, st.missing_delim); 3349 st.v->name, st.missing_delim);
3350 free(*st.freePtr); 3350 free(*st.freePtr);
3351 *st.freePtr = NULL; 3351 *st.freePtr = NULL;
3352 return var_Error; 3352 return var_Error;
3353} 3353}
3354 3354
3355/*- 3355/*-
3356 *----------------------------------------------------------------------- 3356 *-----------------------------------------------------------------------
3357 * Var_Parse -- 3357 * Var_Parse --
3358 * Given the start of a variable invocation, extract the variable 3358 * Given the start of a variable invocation, extract the variable
3359 * name and find its value, then modify it according to the 3359 * name and find its value, then modify it according to the
3360 * specification. 3360 * specification.
3361 * 3361 *
3362 * Input: 3362 * Input:
3363 * str The string to parse 3363 * str The string to parse
3364 * ctxt The context for the variable 3364 * ctxt The context for the variable
3365 * flags VARE_UNDEFERR if undefineds are an error 3365 * flags VARE_UNDEFERR if undefineds are an error
3366 * VARE_WANTRES if we actually want the result 3366 * VARE_WANTRES if we actually want the result
3367 * VARE_ASSIGN if we are in a := assignment 3367 * VARE_ASSIGN if we are in a := assignment
3368 * lengthPtr OUT: The length of the specification 3368 * lengthPtr OUT: The length of the specification
3369 * freePtr OUT: Non-NULL if caller should free *freePtr 3369 * freePtr OUT: Non-NULL if caller should free *freePtr
3370 * 3370 *
3371 * Results: 3371 * Results:
3372 * The (possibly-modified) value of the variable or var_Error if the 3372 * The (possibly-modified) value of the variable or var_Error if the
3373 * specification is invalid. The length of the specification is 3373 * specification is invalid. The length of the specification is
3374 * placed in *lengthPtr (for invalid specifications, this is just 3374 * placed in *lengthPtr (for invalid specifications, this is just
3375 * 2...?). 3375 * 2...?).
3376 * If *freePtr is non-NULL then it's a pointer that the caller 3376 * If *freePtr is non-NULL then it's a pointer that the caller
3377 * should pass to free() to free memory used by the result. 3377 * should pass to free() to free memory used by the result.
3378 * 3378 *
3379 * Side Effects: 3379 * Side Effects:
3380 * None. 3380 * None.
3381 * 3381 *
3382 *----------------------------------------------------------------------- 3382 *-----------------------------------------------------------------------
3383 */ 3383 */
3384/* coverity[+alloc : arg-*4] */ 3384/* coverity[+alloc : arg-*4] */
3385char * 3385char *
3386Var_Parse(const char *str, GNode *ctxt, VarEvalFlags flags, 3386Var_Parse(const char * const str, GNode *ctxt, VarEvalFlags flags,
3387 int *lengthPtr, void **freePtr) 3387 int *lengthPtr, void **freePtr)
3388{ 3388{
3389 const char *tstr; /* Pointer into str */ 3389 const char *tstr; /* Pointer into str */
3390 Var *v; /* Variable in invocation */ 3390 Var *v; /* Variable in invocation */
3391 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3391 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3392 char endc; /* Ending character when variable in parens 3392 char endc; /* Ending character when variable in parens
3393 * or braces */ 3393 * or braces */
3394 char startc; /* Starting character when variable in parens 3394 char startc; /* Starting character when variable in parens
3395 * or braces */ 3395 * or braces */
3396 int vlen; /* Length of variable name */ 3396 int vlen; /* Length of variable name */
3397 const char *start; /* Points to original start of str */ 
3398 char *nstr; /* New string, used during expansion */ 3397 char *nstr; /* New string, used during expansion */
3399 Boolean dynamic; /* TRUE if the variable is local and we're 3398 Boolean dynamic; /* TRUE if the variable is local and we're
3400 * expanding it in a non-local context. This 3399 * expanding it in a non-local context. This
3401 * is done to support dynamic sources. The 3400 * is done to support dynamic sources. The
3402 * result is just the invocation, unaltered */ 3401 * result is just the invocation, unaltered */
3403 const char *extramodifiers; /* extra modifiers to apply first */ 3402 const char *extramodifiers; /* extra modifiers to apply first */
3404 3403
3405 *freePtr = NULL; 3404 *freePtr = NULL;
3406 extramodifiers = NULL; 3405 extramodifiers = NULL;
3407 dynamic = FALSE; 3406 dynamic = FALSE;
3408 start = str; 
3409 3407
3410 startc = str[1]; 3408 startc = str[1];
3411 if (startc != PROPEN && startc != BROPEN) { 3409 if (startc != PROPEN && startc != BROPEN) {
3412 /* 3410 /*
3413 * If it's not bounded by braces of some sort, life is much simpler. 3411 * If it's not bounded by braces of some sort, life is much simpler.
3414 * We just need to check for the first character and return the 3412 * We just need to check for the first character and return the
3415 * value if it exists. 3413 * value if it exists.
3416 */ 3414 */
3417 3415
3418 /* Error out some really stupid names */ 3416 /* Error out some really stupid names */
3419 if (startc == '\0' || strchr(")}:$", startc)) { 3417 if (startc == '\0' || strchr(")}:$", startc)) {
3420 *lengthPtr = 1; 3418 *lengthPtr = 1;
3421 return var_Error; 3419 return var_Error;
3422 } 3420 }
3423 char name[] = { startc, '\0' }; 3421 char name[] = { startc, '\0' };
3424 3422
3425 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3423 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3426 if (v == NULL) { 3424 if (v == NULL) {
3427 *lengthPtr = 2; 3425 *lengthPtr = 2;
3428 3426
3429 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 3427 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3430 /* 3428 /*
3431 * If substituting a local variable in a non-local context, 3429 * If substituting a local variable in a non-local context,
3432 * assume it's for dynamic source stuff. We have to handle 3430 * assume it's for dynamic source stuff. We have to handle
3433 * this specially and return the longhand for the variable 3431 * this specially and return the longhand for the variable
3434 * with the dollar sign escaped so it makes it back to the 3432 * with the dollar sign escaped so it makes it back to the
3435 * caller. Only four of the local variables are treated 3433 * caller. Only four of the local variables are treated
3436 * specially as they are the only four that will be set 3434 * specially as they are the only four that will be set
3437 * when dynamic sources are expanded. 3435 * when dynamic sources are expanded.
3438 */ 3436 */
3439 switch (str[1]) { 3437 switch (str[1]) {
3440 case '@': 3438 case '@':
3441 return UNCONST("$(.TARGET)"); 3439 return UNCONST("$(.TARGET)");
3442 case '%': 3440 case '%':
3443 return UNCONST("$(.MEMBER)"); 3441 return UNCONST("$(.MEMBER)");
3444 case '*': 3442 case '*':
3445 return UNCONST("$(.PREFIX)"); 3443 return UNCONST("$(.PREFIX)");
3446 case '!': 3444 case '!':
3447 return UNCONST("$(.ARCHIVE)"); 3445 return UNCONST("$(.ARCHIVE)");
3448 } 3446 }
3449 } 3447 }
3450 return (flags & VARE_UNDEFERR) ? var_Error : varNoError; 3448 return (flags & VARE_UNDEFERR) ? var_Error : varNoError;
3451 } else { 3449 } else {
3452 haveModifier = FALSE; 3450 haveModifier = FALSE;
3453 tstr = str + 1; 3451 tstr = str + 1;
3454 endc = str[1]; 3452 endc = str[1];
3455 } 3453 }
3456 } else { 3454 } else {
3457 Buffer buf; /* Holds the variable name */ 3455 Buffer buf; /* Holds the variable name */
3458 int depth = 1; 3456 int depth = 1;
3459 3457
3460 endc = startc == PROPEN ? PRCLOSE : BRCLOSE; 3458 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3461 Buf_Init(&buf, 0); 3459 Buf_Init(&buf, 0);
3462 3460
3463 /* 3461 /*
3464 * Skip to the end character or a colon, whichever comes first. 3462 * Skip to the end character or a colon, whichever comes first.
3465 */ 3463 */
3466 for (tstr = str + 2; *tstr != '\0'; tstr++) { 3464 for (tstr = str + 2; *tstr != '\0'; tstr++) {
3467 /* Track depth so we can spot parse errors. */ 3465 /* Track depth so we can spot parse errors. */
3468 if (*tstr == startc) 3466 if (*tstr == startc)
3469 depth++; 3467 depth++;
3470 if (*tstr == endc) { 3468 if (*tstr == endc) {
3471 if (--depth == 0) 3469 if (--depth == 0)
3472 break; 3470 break;
3473 } 3471 }
3474 if (depth == 1 && *tstr == ':') 3472 if (depth == 1 && *tstr == ':')
3475 break; 3473 break;
3476 /* A variable inside a variable, expand. */ 3474 /* A variable inside a variable, expand. */
3477 if (*tstr == '$') { 3475 if (*tstr == '$') {
3478 int rlen; 3476 int rlen;
3479 void *freeIt; 3477 void *freeIt;
3480 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); 3478 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
3481 if (rval != NULL) 3479 if (rval != NULL)
3482 Buf_AddStr(&buf, rval); 3480 Buf_AddStr(&buf, rval);
3483 free(freeIt); 3481 free(freeIt);
3484 tstr += rlen - 1; 3482 tstr += rlen - 1;
3485 } else 3483 } else
3486 Buf_AddByte(&buf, *tstr); 3484 Buf_AddByte(&buf, *tstr);
3487 } 3485 }
3488 if (*tstr == ':') { 3486 if (*tstr == ':') {
3489 haveModifier = TRUE; 3487 haveModifier = TRUE;
3490 } else if (*tstr == endc) { 3488 } else if (*tstr == endc) {
3491 haveModifier = FALSE; 3489 haveModifier = FALSE;
3492 } else { 3490 } else {
3493 /* 3491 /*
3494 * If we never did find the end character, return NULL 3492 * If we never did find the end character, return NULL
3495 * right now, setting the length to be the distance to 3493 * right now, setting the length to be the distance to
3496 * the end of the string, since that's what make does. 3494 * the end of the string, since that's what make does.
3497 */ 3495 */
3498 *lengthPtr = tstr - str; 3496 *lengthPtr = tstr - str;
3499 Buf_Destroy(&buf, TRUE); 3497 Buf_Destroy(&buf, TRUE);
3500 return var_Error; 3498 return var_Error;
3501 } 3499 }
3502 3500
3503 char *varname = Buf_GetAll(&buf, &vlen); 3501 char *varname = Buf_GetAll(&buf, &vlen);
3504 3502
3505 /* 3503 /*
3506 * At this point, varname points into newly allocated memory from 3504 * At this point, varname points into newly allocated memory from
3507 * buf, containing only the name of the variable. 3505 * buf, containing only the name of the variable.
3508 * 3506 *
3509 * start and tstr point into the const string that was pointed 3507 * start and tstr point into the const string that was pointed
3510 * to by the original value of the str parameter. start points 3508 * to by the original value of the str parameter. start points
3511 * to the '$' at the beginning of the string, while tstr points 3509 * to the '$' at the beginning of the string, while tstr points
3512 * to the char just after the end of the variable name -- this 3510 * to the char just after the end of the variable name -- this
3513 * will be '\0', ':', PRCLOSE, or BRCLOSE. 3511 * will be '\0', ':', PRCLOSE, or BRCLOSE.
3514 */ 3512 */
3515 3513
3516 v = VarFind(varname, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3514 v = VarFind(varname, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3517 /* 3515 /*
3518 * Check also for bogus D and F forms of local variables since we're 3516 * Check also for bogus D and F forms of local variables since we're
3519 * in a local context and the name is the right length. 3517 * in a local context and the name is the right length.
3520 */ 3518 */
3521 if (v == NULL && ctxt != VAR_CMD && ctxt != VAR_GLOBAL && 3519 if (v == NULL && ctxt != VAR_CMD && ctxt != VAR_GLOBAL &&
3522 vlen == 2 && (varname[1] == 'F' || varname[1] == 'D') && 3520 vlen == 2 && (varname[1] == 'F' || varname[1] == 'D') &&
3523 strchr("@%?*!<>", varname[0]) != NULL) { 3521 strchr("@%?*!<>", varname[0]) != NULL) {
3524 /* 3522 /*
3525 * Well, it's local -- go look for it. 3523 * Well, it's local -- go look for it.
3526 */ 3524 */
3527 char name[] = {varname[0], '\0' }; 3525 char name[] = {varname[0], '\0' };
3528 v = VarFind(name, ctxt, 0); 3526 v = VarFind(name, ctxt, 0);
3529 3527
3530 if (v != NULL) { 3528 if (v != NULL) {
3531 if (varname[1] == 'D') { 3529 if (varname[1] == 'D') {
3532 extramodifiers = "H:"; 3530 extramodifiers = "H:";
3533 } else { /* F */ 3531 } else { /* F */
3534 extramodifiers = "T:"; 3532 extramodifiers = "T:";
3535 } 3533 }
3536 } 3534 }
3537 } 3535 }
3538 3536
3539 if (v == NULL) { 3537 if (v == NULL) {
3540 if ((vlen == 1 || 3538 if ((vlen == 1 ||
3541 ((vlen == 2 && (varname[1] == 'F' || varname[1] == 'D')))) && 3539 ((vlen == 2 && (varname[1] == 'F' || varname[1] == 'D')))) &&
3542 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3540 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3543 { 3541 {
3544 /* 3542 /*
3545 * If substituting a local variable in a non-local context, 3543 * If substituting a local variable in a non-local context,
3546 * assume it's for dynamic source stuff. We have to handle 3544 * assume it's for dynamic source stuff. We have to handle
3547 * this specially and return the longhand for the variable 3545 * this specially and return the longhand for the variable
3548 * with the dollar sign escaped so it makes it back to the 3546 * with the dollar sign escaped so it makes it back to the
3549 * caller. Only four of the local variables are treated 3547 * caller. Only four of the local variables are treated
3550 * specially as they are the only four that will be set 3548 * specially as they are the only four that will be set
3551 * when dynamic sources are expanded. 3549 * when dynamic sources are expanded.
3552 */ 3550 */
3553 switch (varname[0]) { 3551 switch (varname[0]) {
3554 case '@': 3552 case '@':
3555 case '%': 3553 case '%':
3556 case '*': 3554 case '*':
3557 case '!': 3555 case '!':
3558 dynamic = TRUE; 3556 dynamic = TRUE;
3559 break; 3557 break;
3560 } 3558 }
3561 } else if (vlen > 2 && varname[0] == '.' && 3559 } else if (vlen > 2 && varname[0] == '.' &&
3562 isupper((unsigned char) varname[1]) && 3560 isupper((unsigned char) varname[1]) &&
3563 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL)) 3561 (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3564 { 3562 {
3565 int len = vlen - 1; 3563 int len = vlen - 1;
3566 if ((strncmp(varname, ".TARGET", len) == 0) || 3564 if ((strncmp(varname, ".TARGET", len) == 0) ||
3567 (strncmp(varname, ".ARCHIVE", len) == 0) || 3565 (strncmp(varname, ".ARCHIVE", len) == 0) ||
3568 (strncmp(varname, ".PREFIX", len) == 0) || 3566 (strncmp(varname, ".PREFIX", len) == 0) ||
3569 (strncmp(varname, ".MEMBER", len) == 0)) 3567 (strncmp(varname, ".MEMBER", len) == 0))
3570 { 3568 {
3571 dynamic = TRUE; 3569 dynamic = TRUE;
3572 } 3570 }
3573 } 3571 }
3574 3572
3575 if (!haveModifier) { 3573 if (!haveModifier) {
3576 /* 3574 /*
3577 * No modifiers -- have specification length so we can return 3575 * No modifiers -- have specification length so we can return
3578 * now. 3576 * now.
3579 */ 3577 */
3580 *lengthPtr = tstr - start + 1; 3578 *lengthPtr = tstr - str + 1;
3581 if (dynamic) { 3579 if (dynamic) {
3582 char *pstr = bmake_strndup(start, *lengthPtr); 3580 char *pstr = bmake_strndup(str, *lengthPtr);
3583 *freePtr = pstr; 3581 *freePtr = pstr;
3584 Buf_Destroy(&buf, TRUE); 3582 Buf_Destroy(&buf, TRUE);
3585 return pstr; 3583 return pstr;
3586 } else { 3584 } else {
3587 Buf_Destroy(&buf, TRUE); 3585 Buf_Destroy(&buf, TRUE);
3588 return (flags & VARE_UNDEFERR) ? var_Error : varNoError; 3586 return (flags & VARE_UNDEFERR) ? var_Error : varNoError;
3589 } 3587 }
3590 } else { 3588 } else {
3591 /* 3589 /*
3592 * Still need to get to the end of the variable specification, 3590 * Still need to get to the end of the variable specification,
3593 * so kludge up a Var structure for the modifications 3591 * so kludge up a Var structure for the modifications
3594 */ 3592 */
3595 v = bmake_malloc(sizeof(Var)); 3593 v = bmake_malloc(sizeof(Var));
3596 v->name = varname; 3594 v->name = varname;
3597 Buf_Init(&v->val, 1); 3595 Buf_Init(&v->val, 1);
3598 v->flags = VAR_JUNK; 3596 v->flags = VAR_JUNK;
3599 Buf_Destroy(&buf, FALSE); 3597 Buf_Destroy(&buf, FALSE);
3600 } 3598 }
3601 } else 3599 } else
3602 Buf_Destroy(&buf, TRUE); 3600 Buf_Destroy(&buf, TRUE);
3603 } 3601 }
3604 3602
3605 if (v->flags & VAR_IN_USE) { 3603 if (v->flags & VAR_IN_USE) {
3606 Fatal("Variable %s is recursive.", v->name); 3604 Fatal("Variable %s is recursive.", v->name);
3607 /*NOTREACHED*/ 3605 /*NOTREACHED*/
3608 } else { 3606 } else {
3609 v->flags |= VAR_IN_USE; 3607 v->flags |= VAR_IN_USE;
3610 } 3608 }
3611 /* 3609 /*
3612 * Before doing any modification, we have to make sure the value 3610 * Before doing any modification, we have to make sure the value
3613 * has been fully expanded. If it looks like recursion might be 3611 * has been fully expanded. If it looks like recursion might be
3614 * necessary (there's a dollar sign somewhere in the variable's value) 3612 * necessary (there's a dollar sign somewhere in the variable's value)
3615 * we just call Var_Subst to do any other substitutions that are 3613 * we just call Var_Subst to do any other substitutions that are
3616 * necessary. Note that the value returned by Var_Subst will have 3614 * necessary. Note that the value returned by Var_Subst will have
3617 * been dynamically-allocated, so it will need freeing when we 3615 * been dynamically-allocated, so it will need freeing when we
3618 * return. 3616 * return.
3619 */ 3617 */
3620 nstr = Buf_GetAll(&v->val, NULL); 3618 nstr = Buf_GetAll(&v->val, NULL);
3621 if (strchr(nstr, '$') != NULL && (flags & VARE_WANTRES) != 0) { 3619 if (strchr(nstr, '$') != NULL && (flags & VARE_WANTRES) != 0) {
3622 nstr = Var_Subst(NULL, nstr, ctxt, flags); 3620 nstr = Var_Subst(NULL, nstr, ctxt, flags);
3623 *freePtr = nstr; 3621 *freePtr = nstr;
3624 } 3622 }
3625 3623
3626 v->flags &= ~VAR_IN_USE; 3624 v->flags &= ~VAR_IN_USE;
3627 3625
3628 if (nstr != NULL && (haveModifier || extramodifiers != NULL)) { 3626 if (nstr != NULL && (haveModifier || extramodifiers != NULL)) {
3629 void *extraFree; 3627 void *extraFree;
3630 int used; 3628 int used;
3631 3629
3632 extraFree = NULL; 3630 extraFree = NULL;
3633 if (extramodifiers != NULL) { 3631 if (extramodifiers != NULL) {
3634 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', 3632 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
3635 v, ctxt, flags, &used, &extraFree); 3633 v, ctxt, flags, &used, &extraFree);
3636 } 3634 }
3637 3635
3638 if (haveModifier) { 3636 if (haveModifier) {
3639 /* Skip initial colon. */ 3637 /* Skip initial colon. */
3640 tstr++; 3638 tstr++;
3641 3639
3642 nstr = ApplyModifiers(nstr, tstr, startc, endc, 3640 nstr = ApplyModifiers(nstr, tstr, startc, endc,
3643 v, ctxt, flags, &used, freePtr); 3641 v, ctxt, flags, &used, freePtr);
3644 tstr += used; 3642 tstr += used;
3645 free(extraFree); 3643 free(extraFree);
3646 } else { 3644 } else {
3647 *freePtr = extraFree; 3645 *freePtr = extraFree;
3648 } 3646 }
3649 } 3647 }
3650 *lengthPtr = tstr - start + (*tstr ? 1 : 0); 3648 *lengthPtr = tstr - str + (*tstr ? 1 : 0);
3651 3649
3652 if (v->flags & VAR_FROM_ENV) { 3650 if (v->flags & VAR_FROM_ENV) {
3653 Boolean destroy = FALSE; 3651 Boolean destroy = FALSE;
3654 3652
3655 if (nstr != Buf_GetAll(&v->val, NULL)) { 3653 if (nstr != Buf_GetAll(&v->val, NULL)) {
3656 destroy = TRUE; 3654 destroy = TRUE;
3657 } else { 3655 } else {
3658 /* 3656 /*
3659 * Returning the value unmodified, so tell the caller to free 3657 * Returning the value unmodified, so tell the caller to free
3660 * the thing. 3658 * the thing.
3661 */ 3659 */
3662 *freePtr = nstr; 3660 *freePtr = nstr;
3663 } 3661 }
3664 VarFreeEnv(v, destroy); 3662 VarFreeEnv(v, destroy);
3665 } else if (v->flags & VAR_JUNK) { 3663 } else if (v->flags & VAR_JUNK) {
3666 /* 3664 /*
3667 * Perform any free'ing needed and set *freePtr to NULL so the caller 3665 * Perform any free'ing needed and set *freePtr to NULL so the caller
3668 * doesn't try to free a static pointer. 3666 * doesn't try to free a static pointer.
3669 * If VAR_KEEP is also set then we want to keep str(?) as is. 3667 * If VAR_KEEP is also set then we want to keep str(?) as is.
3670 */ 3668 */
3671 if (!(v->flags & VAR_KEEP)) { 3669 if (!(v->flags & VAR_KEEP)) {
3672 if (*freePtr) { 3670 if (*freePtr) {
3673 free(nstr); 3671 free(nstr);
3674 *freePtr = NULL; 3672 *freePtr = NULL;
3675 } 3673 }
3676 if (dynamic) { 3674 if (dynamic) {
3677 nstr = bmake_strndup(start, *lengthPtr); 3675 nstr = bmake_strndup(str, *lengthPtr);
3678 *freePtr = nstr; 3676 *freePtr = nstr;
3679 } else { 3677 } else {
3680 nstr = (flags & VARE_UNDEFERR) ? var_Error : varNoError; 3678 nstr = (flags & VARE_UNDEFERR) ? var_Error : varNoError;
3681 } 3679 }
3682 } 3680 }
3683 if (nstr != Buf_GetAll(&v->val, NULL)) 3681 if (nstr != Buf_GetAll(&v->val, NULL))
3684 Buf_Destroy(&v->val, TRUE); 3682 Buf_Destroy(&v->val, TRUE);
3685 free(v->name); 3683 free(v->name);
3686 free(v); 3684 free(v);
3687 } 3685 }
3688 return nstr; 3686 return nstr;
3689} 3687}
3690 3688
3691/*- 3689/*-
3692 *----------------------------------------------------------------------- 3690 *-----------------------------------------------------------------------
3693 * Var_Subst -- 3691 * Var_Subst --
3694 * Substitute for all variables in the given string in the given context. 3692 * Substitute for all variables in the given string in the given context.
3695 * If flags & VARE_UNDEFERR, Parse_Error will be called when an undefined 3693 * If flags & VARE_UNDEFERR, Parse_Error will be called when an undefined
3696 * variable is encountered. 3694 * variable is encountered.
3697 * 3695 *
3698 * Input: 3696 * Input:
3699 * var Named variable || NULL for all 3697 * var Named variable || NULL for all
3700 * str the string which to substitute 3698 * str the string which to substitute
3701 * ctxt the context wherein to find variables 3699 * ctxt the context wherein to find variables
3702 * flags VARE_UNDEFERR if undefineds are an error 3700 * flags VARE_UNDEFERR if undefineds are an error
3703 * VARE_WANTRES if we actually want the result 3701 * VARE_WANTRES if we actually want the result
3704 * VARE_ASSIGN if we are in a := assignment 3702 * VARE_ASSIGN if we are in a := assignment
3705 * 3703 *
3706 * Results: 3704 * Results:
3707 * The resulting string. 3705 * The resulting string.
3708 * 3706 *
3709 * Side Effects: 3707 * Side Effects:
3710 * None. 3708 * None.
3711 *----------------------------------------------------------------------- 3709 *-----------------------------------------------------------------------
3712 */ 3710 */
3713char * 3711char *
3714Var_Subst(const char *var, const char *str, GNode *ctxt, VarEvalFlags flags) 3712Var_Subst(const char *var, const char *str, GNode *ctxt, VarEvalFlags flags)
3715{ 3713{
3716 Buffer buf; /* Buffer for forming things */ 3714 Buffer buf; /* Buffer for forming things */
3717 char *val; /* Value to substitute for a variable */ 3715 char *val; /* Value to substitute for a variable */
3718 int length; /* Length of the variable invocation */ 3716 int length; /* Length of the variable invocation */
3719 Boolean trailingBslash; /* variable ends in \ */ 3717 Boolean trailingBslash; /* variable ends in \ */
3720 void *freeIt = NULL; /* Set if it should be freed */ 3718 void *freeIt = NULL; /* Set if it should be freed */
3721 static Boolean errorReported; /* Set true if an error has already 3719 static Boolean errorReported; /* Set true if an error has already
3722 * been reported to prevent a plethora 3720 * been reported to prevent a plethora
3723 * of messages when recursing */ 3721 * of messages when recursing */
3724 3722
3725 Buf_Init(&buf, 0); 3723 Buf_Init(&buf, 0);
3726 errorReported = FALSE; 3724 errorReported = FALSE;
3727 trailingBslash = FALSE; 3725 trailingBslash = FALSE;
3728 3726
3729 while (*str) { 3727 while (*str) {
3730 if (*str == '\n' && trailingBslash) 3728 if (*str == '\n' && trailingBslash)
3731 Buf_AddByte(&buf, ' '); 3729 Buf_AddByte(&buf, ' ');
3732 if (var == NULL && (*str == '$') && (str[1] == '$')) { 3730 if (var == NULL && (*str == '$') && (str[1] == '$')) {
3733 /* 3731 /*
3734 * A dollar sign may be escaped either with another dollar sign. 3732 * A dollar sign may be escaped either with another dollar sign.
3735 * In such a case, we skip over the escape character and store the 3733 * In such a case, we skip over the escape character and store the
3736 * dollar sign into the buffer directly. 3734 * dollar sign into the buffer directly.
3737 */ 3735 */
3738 if (save_dollars && (flags & VARE_ASSIGN)) 3736 if (save_dollars && (flags & VARE_ASSIGN))
3739 Buf_AddByte(&buf, *str); 3737 Buf_AddByte(&buf, *str);
3740 str++; 3738 str++;
3741 Buf_AddByte(&buf, *str); 3739 Buf_AddByte(&buf, *str);
3742 str++; 3740 str++;
3743 } else if (*str != '$') { 3741 } else if (*str != '$') {
3744 /* 3742 /*
3745 * Skip as many characters as possible -- either to the end of 3743 * Skip as many characters as possible -- either to the end of
3746 * the string or to the next dollar sign (variable invocation). 3744 * the string or to the next dollar sign (variable invocation).
3747 */ 3745 */
3748 const char *cp; 3746 const char *cp;
3749 3747
3750 for (cp = str++; *str != '$' && *str != '\0'; str++) 3748 for (cp = str++; *str != '$' && *str != '\0'; str++)
3751 continue; 3749 continue;
3752 Buf_AddBytesBetween(&buf, cp, str); 3750 Buf_AddBytesBetween(&buf, cp, str);
3753 } else { 3751 } else {
3754 if (var != NULL) { 3752 if (var != NULL) {
3755 int expand; 3753 int expand;
3756 for (;;) { 3754 for (;;) {
3757 if (str[1] == '\0') { 3755 if (str[1] == '\0') {
3758 /* A trailing $ is kind of a special case */ 3756 /* A trailing $ is kind of a special case */
3759 Buf_AddByte(&buf, str[0]); 3757 Buf_AddByte(&buf, str[0]);
3760 str++; 3758 str++;
3761 expand = FALSE; 3759 expand = FALSE;
3762 } else if (str[1] != PROPEN && str[1] != BROPEN) { 3760 } else if (str[1] != PROPEN && str[1] != BROPEN) {
3763 if (str[1] != *var || strlen(var) > 1) { 3761 if (str[1] != *var || strlen(var) > 1) {
3764 Buf_AddBytes(&buf, 2, str); 3762 Buf_AddBytes(&buf, 2, str);
3765 str += 2; 3763 str += 2;
3766 expand = FALSE; 3764 expand = FALSE;
3767 } else 3765 } else
3768 expand = TRUE; 3766 expand = TRUE;
3769 break; 3767 break;
3770 } else { 3768 } else {
3771 const char *p; 3769 const char *p;
3772 3770
3773 /* Scan up to the end of the variable name. */ 3771 /* Scan up to the end of the variable name. */
3774 for (p = &str[2]; *p && 3772 for (p = &str[2]; *p &&
3775 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) 3773 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
3776 if (*p == '$') 3774 if (*p == '$')
3777 break; 3775 break;
3778 /* 3776 /*
3779 * A variable inside the variable. We cannot expand 3777 * A variable inside the variable. We cannot expand
3780 * the external variable yet, so we try again with 3778 * the external variable yet, so we try again with
3781 * the nested one 3779 * the nested one
3782 */ 3780 */
3783 if (*p == '$') { 3781 if (*p == '$') {
3784 Buf_AddBytesBetween(&buf, str, p); 3782 Buf_AddBytesBetween(&buf, str, p);
3785 str = p; 3783 str = p;
3786 continue; 3784 continue;
3787 } 3785 }
3788 3786
3789 if (strncmp(var, str + 2, p - str - 2) != 0 || 3787 if (strncmp(var, str + 2, p - str - 2) != 0 ||
3790 var[p - str - 2] != '\0') { 3788 var[p - str - 2] != '\0') {
3791 /* 3789 /*
3792 * Not the variable we want to expand, scan 3790 * Not the variable we want to expand, scan
3793 * until the next variable 3791 * until the next variable
3794 */ 3792 */
3795 for (; *p != '$' && *p != '\0'; p++) 3793 for (; *p != '$' && *p != '\0'; p++)
3796 continue; 3794 continue;
3797 Buf_AddBytesBetween(&buf, str, p); 3795 Buf_AddBytesBetween(&buf, str, p);
3798 str = p; 3796 str = p;
3799 expand = FALSE; 3797 expand = FALSE;
3800 } else 3798 } else
3801 expand = TRUE; 3799 expand = TRUE;
3802 break; 3800 break;
3803 } 3801 }
3804 } 3802 }
3805 if (!expand) 3803 if (!expand)
3806 continue; 3804 continue;
3807 } 3805 }
3808 3806
3809 val = Var_Parse(str, ctxt, flags, &length, &freeIt); 3807 val = Var_Parse(str, ctxt, flags, &length, &freeIt);
3810 3808
3811 /* 3809 /*
3812 * When we come down here, val should either point to the 3810 * When we come down here, val should either point to the
3813 * value of this variable, suitably modified, or be NULL. 3811 * value of this variable, suitably modified, or be NULL.
3814 * Length should be the total length of the potential 3812 * Length should be the total length of the potential
3815 * variable invocation (from $ to end character...) 3813 * variable invocation (from $ to end character...)
3816 */ 3814 */
3817 if (val == var_Error || val == varNoError) { 3815 if (val == var_Error || val == varNoError) {
3818 /* 3816 /*
3819 * If performing old-time variable substitution, skip over 3817 * If performing old-time variable substitution, skip over
3820 * the variable and continue with the substitution. Otherwise, 3818 * the variable and continue with the substitution. Otherwise,
3821 * store the dollar sign and advance str so we continue with 3819 * store the dollar sign and advance str so we continue with
3822 * the string... 3820 * the string...
3823 */ 3821 */
3824 if (oldVars) { 3822 if (oldVars) {
3825 str += length; 3823 str += length;
3826 } else if ((flags & VARE_UNDEFERR) || val == var_Error) { 3824 } else if ((flags & VARE_UNDEFERR) || val == var_Error) {
3827 /* 3825 /*
3828 * If variable is undefined, complain and skip the 3826 * If variable is undefined, complain and skip the
3829 * variable. The complaint will stop us from doing anything 3827 * variable. The complaint will stop us from doing anything
3830 * when the file is parsed. 3828 * when the file is parsed.
3831 */ 3829 */
3832 if (!errorReported) { 3830 if (!errorReported) {
3833 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", 3831 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
3834 length, str); 3832 length, str);
3835 } 3833 }
3836 str += length; 3834 str += length;
3837 errorReported = TRUE; 3835 errorReported = TRUE;
3838 } else { 3836 } else {
3839 Buf_AddByte(&buf, *str); 3837 Buf_AddByte(&buf, *str);
3840 str += 1; 3838 str += 1;
3841 } 3839 }
3842 } else { 3840 } else {
3843 /* 3841 /*
3844 * We've now got a variable structure to store in. But first, 3842 * We've now got a variable structure to store in. But first,
3845 * advance the string pointer. 3843 * advance the string pointer.
3846 */ 3844 */
3847 str += length; 3845 str += length;
3848 3846
3849 /* 3847 /*
3850 * Copy all the characters from the variable value straight 3848 * Copy all the characters from the variable value straight
3851 * into the new string. 3849 * into the new string.
3852 */ 3850 */
3853 length = strlen(val); 3851 length = strlen(val);
3854 Buf_AddBytes(&buf, length, val); 3852 Buf_AddBytes(&buf, length, val);
3855 trailingBslash = length > 0 && val[length - 1] == '\\'; 3853 trailingBslash = length > 0 && val[length - 1] == '\\';
3856 } 3854 }
3857 free(freeIt); 3855 free(freeIt);
3858 freeIt = NULL; 3856 freeIt = NULL;
3859 } 3857 }
3860 } 3858 }
3861 3859
3862 return Buf_DestroyCompact(&buf); 3860 return Buf_DestroyCompact(&buf);
3863} 3861}
3864 3862
3865/* Initialize the module. */ 3863/* Initialize the module. */
3866void 3864void
3867Var_Init(void) 3865Var_Init(void)
3868{ 3866{
3869 VAR_INTERNAL = Targ_NewGN("Internal"); 3867 VAR_INTERNAL = Targ_NewGN("Internal");
3870 VAR_GLOBAL = Targ_NewGN("Global"); 3868 VAR_GLOBAL = Targ_NewGN("Global");
3871 VAR_CMD = Targ_NewGN("Command"); 3869 VAR_CMD = Targ_NewGN("Command");
3872} 3870}
3873 3871
3874 3872
3875void 3873void
3876Var_End(void) 3874Var_End(void)
3877{ 3875{
3878 Var_Stats(); 3876 Var_Stats();
3879} 3877}
3880 3878
3881void 3879void
3882Var_Stats(void) 3880Var_Stats(void)
3883{ 3881{
3884 Hash_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL"); 3882 Hash_DebugStats(&VAR_GLOBAL->context, "VAR_GLOBAL");
3885} 3883}
3886 3884
3887 3885
3888/****************** PRINT DEBUGGING INFO *****************/ 3886/****************** PRINT DEBUGGING INFO *****************/
3889static void 3887static void
3890VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED) 3888VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED)
3891{ 3889{
3892 Var *v = (Var *)vp; 3890 Var *v = (Var *)vp;
3893 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); 3891 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
3894} 3892}
3895 3893
3896/*- 3894/*-
3897 *----------------------------------------------------------------------- 3895 *-----------------------------------------------------------------------
3898 * Var_Dump -- 3896 * Var_Dump --
3899 * print all variables in a context 3897 * print all variables in a context
3900 *----------------------------------------------------------------------- 3898 *-----------------------------------------------------------------------
3901 */ 3899 */
3902void 3900void
3903Var_Dump(GNode *ctxt) 3901Var_Dump(GNode *ctxt)
3904{ 3902{
3905 Hash_ForEach(&ctxt->context, VarPrintVar, NULL); 3903 Hash_ForEach(&ctxt->context, VarPrintVar, NULL);
3906} 3904}