Sun Jul 26 15:37:44 2020 UTC ()
make(1): help the compiler to find common subexpressions


(rillig)
diff -r1.314 -r1.315 src/usr.bin/make/var.c

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

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