Sun Jul 26 22:43:17 2020 UTC ()
make(1): extract code for dynamic variable names out of Var_Parse


(rillig)
diff -r1.334 -r1.335 src/usr.bin/make/var.c

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

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