Sun Jul 26 15:26:27 2020 UTC ()
make(1): add convenience functions for adding to a SepBuf


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

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

--- src/usr.bin/make/var.c 2020/07/26 15:09:10 1.313
+++ src/usr.bin/make/var.c 2020/07/26 15:26:27 1.314
@@ -1,3523 +1,3535 @@ @@ -1,3523 +1,3535 @@
1/* $NetBSD: var.c,v 1.313 2020/07/26 15:09:10 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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.313 2020/07/26 15:09:10 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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.313 2020/07/26 15:09:10 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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 void *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
 1074SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
 1075{
 1076 SepBuf_AddBytes(buf, start, (size_t)(end - start));
 1077}
 1078
 1079static void
 1080SepBuf_AddStr(SepBuf *buf, const char *str)
 1081{
 1082 SepBuf_AddBytes(buf, str, strlen(str));
 1083}
 1084
1073static char * 1085static char *
1074SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1086SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1075{ 1087{
1076 return Buf_Destroy(&buf->buf, free_buf); 1088 return Buf_Destroy(&buf->buf, free_buf);
1077} 1089}
1078 1090
1079 1091
1080/* 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
1081 * 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
1082 * nothing or add several words. */ 1094 * nothing or add several words. */
1083typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1095typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1084 1096
1085 1097
1086/* Callback for ModifyWords to implement the :H modifier. 1098/* Callback for ModifyWords to implement the :H modifier.
1087 * Add the dirname of the given word to the buffer. */ 1099 * Add the dirname of the given word to the buffer. */
1088static void 1100static void
1089ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1101ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1090{ 1102{
1091 const char *slash = strrchr(word, '/'); 1103 const char *slash = strrchr(word, '/');
1092 if (slash != NULL) 1104 if (slash != NULL)
1093 SepBuf_AddBytes(buf, word, slash - word); 1105 SepBuf_AddBytesBetween(buf, word, slash);
1094 else 1106 else
1095 SepBuf_AddBytes(buf, ".", 1); 1107 SepBuf_AddStr(buf, ".");
1096} 1108}
1097 1109
1098/* Callback for ModifyWords to implement the :T modifier. 1110/* Callback for ModifyWords to implement the :T modifier.
1099 * Add the basename of the given word to the buffer. */ 1111 * Add the basename of the given word to the buffer. */
1100static void 1112static void
1101ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1113ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1102{ 1114{
1103 const char *slash = strrchr(word, '/'); 1115 const char *slash = strrchr(word, '/');
1104 const char *base = slash != NULL ? slash + 1 : word; 1116 const char *base = slash != NULL ? slash + 1 : word;
1105 SepBuf_AddBytes(buf, base, strlen(base)); 1117 SepBuf_AddStr(buf, base);
1106} 1118}
1107 1119
1108/* Callback for ModifyWords to implement the :E modifier. 1120/* Callback for ModifyWords to implement the :E modifier.
1109 * 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. */
1110static void 1122static void
1111ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1123ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1112{ 1124{
1113 const char *dot = strrchr(word, '.'); 1125 const char *dot = strrchr(word, '.');
1114 if (dot != NULL) 1126 if (dot != NULL)
1115 SepBuf_AddBytes(buf, dot + 1, strlen(dot + 1)); 1127 SepBuf_AddStr(buf, dot + 1);
1116} 1128}
1117 1129
1118/* Callback for ModifyWords to implement the :R modifier. 1130/* Callback for ModifyWords to implement the :R modifier.
1119 * Add the basename of the given word to the buffer. */ 1131 * Add the basename of the given word to the buffer. */
1120static void 1132static void
1121ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1133ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1122{ 1134{
1123 char *dot = strrchr(word, '.'); 1135 const char *dot = strrchr(word, '.');
1124 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1136 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1125 SepBuf_AddBytes(buf, word, len); 1137 SepBuf_AddBytes(buf, word, len);
1126} 1138}
1127 1139
1128/* Callback for ModifyWords to implement the :M modifier. 1140/* Callback for ModifyWords to implement the :M modifier.
1129 * 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. */
1130static void 1142static void
1131ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1143ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1132{ 1144{
1133 const char *pattern = data; 1145 const char *pattern = data;
1134 if (DEBUG(VAR)) 1146 if (DEBUG(VAR))
1135 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern); 1147 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
1136 if (Str_Match(word, pattern)) 1148 if (Str_Match(word, pattern))
1137 SepBuf_AddBytes(buf, word, strlen(word)); 1149 SepBuf_AddStr(buf, word);
1138} 1150}
1139 1151
1140/* Callback for ModifyWords to implement the :N modifier. 1152/* Callback for ModifyWords to implement the :N modifier.
1141 * 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. */
1142static void 1154static void
1143ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1155ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1144{ 1156{
1145 const char *pattern = data; 1157 const char *pattern = data;
1146 if (!Str_Match(word, pattern)) 1158 if (!Str_Match(word, pattern))
1147 SepBuf_AddBytes(buf, word, strlen(word)); 1159 SepBuf_AddStr(buf, word);
1148} 1160}
1149 1161
1150#ifdef SYSVVARSUB 1162#ifdef SYSVVARSUB
1151/*- 1163/*-
1152 *----------------------------------------------------------------------- 1164 *-----------------------------------------------------------------------
1153 * Str_SYSVMatch -- 1165 * Str_SYSVMatch --
1154 * Check word against pattern for a match (% is wild), 1166 * Check word against pattern for a match (% is wild),
1155 * 1167 *
1156 * Input: 1168 * Input:
1157 * word Word to examine 1169 * word Word to examine
1158 * pattern Pattern to examine against 1170 * pattern Pattern to examine against
1159 * len Number of characters to substitute 1171 * len Number of characters to substitute
1160 * 1172 *
1161 * Results: 1173 * Results:
1162 * Returns the beginning position of a match or null. The number 1174 * Returns the beginning position of a match or null. The number
1163 * of characters matched is returned in len. 1175 * of characters matched is returned in len.
1164 *----------------------------------------------------------------------- 1176 *-----------------------------------------------------------------------
1165 */ 1177 */
1166static const char * 1178static const char *
1167Str_SYSVMatch(const char *word, const char *pattern, size_t *len, 1179Str_SYSVMatch(const char *word, const char *pattern, size_t *len,
1168 Boolean *hasPercent) 1180 Boolean *hasPercent)
1169{ 1181{
1170 const char *p = pattern; 1182 const char *p = pattern;
1171 const char *w = word; 1183 const char *w = word;
1172 const char *m; 1184 const char *m;
1173 1185
1174 *hasPercent = FALSE; 1186 *hasPercent = FALSE;
1175 if (*p == '\0') { 1187 if (*p == '\0') {
1176 /* Null pattern is the whole string */ 1188 /* Null pattern is the whole string */
1177 *len = strlen(w); 1189 *len = strlen(w);
1178 return w; 1190 return w;
1179 } 1191 }
1180 1192
1181 if ((m = strchr(p, '%')) != NULL) { 1193 if ((m = strchr(p, '%')) != NULL) {
1182 *hasPercent = TRUE; 1194 *hasPercent = TRUE;
1183 if (*w == '\0') { 1195 if (*w == '\0') {
1184 /* empty word does not match pattern */ 1196 /* empty word does not match pattern */
1185 return NULL; 1197 return NULL;
1186 } 1198 }
1187 /* check that the prefix matches */ 1199 /* check that the prefix matches */
1188 for (; p != m && *w && *w == *p; w++, p++) 1200 for (; p != m && *w && *w == *p; w++, p++)
1189 continue; 1201 continue;
1190 1202
1191 if (p != m) 1203 if (p != m)
1192 return NULL; /* No match */ 1204 return NULL; /* No match */
1193 1205
1194 if (*++p == '\0') { 1206 if (*++p == '\0') {
1195 /* No more pattern, return the rest of the string */ 1207 /* No more pattern, return the rest of the string */
1196 *len = strlen(w); 1208 *len = strlen(w);
1197 return w; 1209 return w;
1198 } 1210 }
1199 } 1211 }
1200 1212
1201 m = w; 1213 m = w;
1202 1214
1203 /* Find a matching tail */ 1215 /* Find a matching tail */
1204 do { 1216 do {
1205 if (strcmp(p, w) == 0) { 1217 if (strcmp(p, w) == 0) {
1206 *len = w - m; 1218 *len = w - m;
1207 return m; 1219 return m;
1208 } 1220 }
1209 } while (*w++ != '\0'); 1221 } while (*w++ != '\0');
1210 1222
1211 return NULL; 1223 return NULL;
1212} 1224}
1213 1225
1214 1226
1215/*- 1227/*-
1216 *----------------------------------------------------------------------- 1228 *-----------------------------------------------------------------------
1217 * Str_SYSVSubst -- 1229 * Str_SYSVSubst --
1218 * Substitute '%' on the pattern with len characters from src. 1230 * Substitute '%' on the pattern with len characters from src.
1219 * If the pattern does not contain a '%' prepend len characters 1231 * If the pattern does not contain a '%' prepend len characters
1220 * from src. 1232 * from src.
1221 * 1233 *
1222 * Side Effects: 1234 * Side Effects:
1223 * Places result on buf 1235 * Places result on buf
1224 *----------------------------------------------------------------------- 1236 *-----------------------------------------------------------------------
1225 */ 1237 */
1226static void 1238static void
1227Str_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,
1228 Boolean lhsHasPercent) 1240 Boolean lhsHasPercent)
1229{ 1241{
1230 const char *m; 1242 const char *m;
1231 1243
1232 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) { 1244 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) {
1233 /* Copy the prefix */ 1245 /* Copy the prefix */
1234 SepBuf_AddBytes(buf, pat, m - pat); 1246 SepBuf_AddBytesBetween(buf, pat, m);
1235 /* skip the % */ 1247 /* skip the % */
1236 pat = m + 1; 1248 pat = m + 1;
1237 } 1249 }
1238 if (m != NULL || !lhsHasPercent) { 1250 if (m != NULL || !lhsHasPercent) {
1239 /* Copy the pattern */ 1251 /* Copy the pattern */
1240 SepBuf_AddBytes(buf, src, len); 1252 SepBuf_AddBytes(buf, src, len);
1241 } 1253 }
1242 1254
1243 /* append the rest */ 1255 /* append the rest */
1244 SepBuf_AddBytes(buf, pat, strlen(pat)); 1256 SepBuf_AddStr(buf, pat);
1245} 1257}
1246 1258
1247 1259
1248typedef struct { 1260typedef struct {
1249 GNode *ctx; 1261 GNode *ctx;
1250 const char *lhs; 1262 const char *lhs;
1251 const char *rhs; 1263 const char *rhs;
1252} ModifyWord_SYSVSubstArgs; 1264} ModifyWord_SYSVSubstArgs;
1253 1265
1254/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1266/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1255static void 1267static void
1256ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1268ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1257{ 1269{
1258 const ModifyWord_SYSVSubstArgs *args = data; 1270 const ModifyWord_SYSVSubstArgs *args = data;
1259 1271
1260 size_t len; 1272 size_t len;
1261 Boolean hasPercent; 1273 Boolean hasPercent;
1262 const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent); 1274 const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent);
1263 if (ptr != NULL) { 1275 if (ptr != NULL) {
1264 char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES); 1276 char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES);
1265 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent); 1277 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1266 free(varexp); 1278 free(varexp);
1267 } else { 1279 } else {
1268 SepBuf_AddBytes(buf, word, strlen(word)); 1280 SepBuf_AddStr(buf, word);
1269 } 1281 }
1270} 1282}
1271#endif 1283#endif
1272 1284
1273 1285
1274typedef struct { 1286typedef struct {
1275 const char *lhs; 1287 const char *lhs;
1276 size_t lhsLen; 1288 size_t lhsLen;
1277 const char *rhs; 1289 const char *rhs;
1278 size_t rhsLen; 1290 size_t rhsLen;
1279 VarPatternFlags pflags; 1291 VarPatternFlags pflags;
1280} ModifyWord_SubstArgs; 1292} ModifyWord_SubstArgs;
1281 1293
1282/* Callback for ModifyWords to implement the :S,from,to, modifier. 1294/* Callback for ModifyWords to implement the :S,from,to, modifier.
1283 * Perform a string substitution on the given word. */ 1295 * Perform a string substitution on the given word. */
1284static void 1296static void
1285ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1297ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1286{ 1298{
1287 size_t wordLen = strlen(word); 1299 size_t wordLen = strlen(word);
1288 ModifyWord_SubstArgs *args = data; 1300 ModifyWord_SubstArgs *args = data;
1289 const VarPatternFlags pflags = args->pflags; 1301 const VarPatternFlags pflags = args->pflags;
1290 1302
1291 if ((pflags & VARP_SUB_ONE) && (pflags & VARP_SUB_MATCHED)) 1303 if ((pflags & VARP_SUB_ONE) && (pflags & VARP_SUB_MATCHED))
1292 goto nosub; 1304 goto nosub;
1293 1305
1294 if (args->pflags & VARP_ANCHOR_START) { 1306 if (args->pflags & VARP_ANCHOR_START) {
1295 if (wordLen < args->lhsLen || 1307 if (wordLen < args->lhsLen ||
1296 memcmp(word, args->lhs, args->lhsLen) != 0) 1308 memcmp(word, args->lhs, args->lhsLen) != 0)
1297 goto nosub; 1309 goto nosub;
1298 1310
1299 if (args->pflags & VARP_ANCHOR_END) { 1311 if (args->pflags & VARP_ANCHOR_END) {
1300 if (wordLen != args->lhsLen) 1312 if (wordLen != args->lhsLen)
1301 goto nosub; 1313 goto nosub;
1302 1314
1303 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1315 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1304 args->pflags |= VARP_SUB_MATCHED; 1316 args->pflags |= VARP_SUB_MATCHED;
1305 } else { 1317 } else {
1306 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1318 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1307 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1319 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1308 args->pflags |= VARP_SUB_MATCHED; 1320 args->pflags |= VARP_SUB_MATCHED;
1309 } 1321 }
1310 return; 1322 return;
1311 } 1323 }
1312 1324
1313 if (args->pflags & VARP_ANCHOR_END) { 1325 if (args->pflags & VARP_ANCHOR_END) {
1314 if (wordLen < args->lhsLen) 1326 if (wordLen < args->lhsLen)
1315 goto nosub; 1327 goto nosub;
1316 const char *start = word + (wordLen - args->lhsLen); 1328 const char *start = word + (wordLen - args->lhsLen);
1317 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1329 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1318 goto nosub; 1330 goto nosub;
1319 1331
1320 SepBuf_AddBytes(buf, word, start - word); 1332 SepBuf_AddBytesBetween(buf, word, start);
1321 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1333 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1322 args->pflags |= VARP_SUB_MATCHED; 1334 args->pflags |= VARP_SUB_MATCHED;
1323 return; 1335 return;
1324 } 1336 }
1325 1337
1326 /* unanchored */ 1338 /* unanchored */
1327 const char *cp; 1339 const char *cp;
1328 while ((cp = Str_FindSubstring(word, args->lhs)) != NULL) { 1340 while ((cp = Str_FindSubstring(word, args->lhs)) != NULL) {
1329 SepBuf_AddBytes(buf, word, cp - word); 1341 SepBuf_AddBytesBetween(buf, word, cp);
1330 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1342 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1331 args->pflags |= VARP_SUB_MATCHED; 1343 args->pflags |= VARP_SUB_MATCHED;
1332 wordLen -= (cp - word) + args->lhsLen; 1344 wordLen -= (cp - word) + args->lhsLen;
1333 word = cp + args->lhsLen; 1345 word = cp + args->lhsLen;
1334 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1346 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1335 break; 1347 break;
1336 } 1348 }
1337nosub: 1349nosub:
1338 SepBuf_AddBytes(buf, word, wordLen); 1350 SepBuf_AddBytes(buf, word, wordLen);
1339} 1351}
1340 1352
1341#ifndef NO_REGEX 1353#ifndef NO_REGEX
1342/*- 1354/*-
1343 *----------------------------------------------------------------------- 1355 *-----------------------------------------------------------------------
1344 * VarREError -- 1356 * VarREError --
1345 * Print the error caused by a regcomp or regexec call. 1357 * Print the error caused by a regcomp or regexec call.
1346 * 1358 *
1347 * Side Effects: 1359 * Side Effects:
1348 * An error gets printed. 1360 * An error gets printed.
1349 * 1361 *
1350 *----------------------------------------------------------------------- 1362 *-----------------------------------------------------------------------
1351 */ 1363 */
1352static void 1364static void
1353VarREError(int reerr, regex_t *pat, const char *str) 1365VarREError(int reerr, regex_t *pat, const char *str)
1354{ 1366{
1355 char *errbuf; 1367 char *errbuf;
1356 int errlen; 1368 int errlen;
1357 1369
1358 errlen = regerror(reerr, pat, 0, 0); 1370 errlen = regerror(reerr, pat, 0, 0);
1359 errbuf = bmake_malloc(errlen); 1371 errbuf = bmake_malloc(errlen);
1360 regerror(reerr, pat, errbuf, errlen); 1372 regerror(reerr, pat, errbuf, errlen);
1361 Error("%s: %s", str, errbuf); 1373 Error("%s: %s", str, errbuf);
1362 free(errbuf); 1374 free(errbuf);
1363} 1375}
1364 1376
1365typedef struct { 1377typedef struct {
1366 regex_t re; 1378 regex_t re;
1367 int nsub; 1379 int nsub;
1368 char *replace; 1380 char *replace;
1369 VarPatternFlags pflags; 1381 VarPatternFlags pflags;
1370} ModifyWord_SubstRegexArgs; 1382} ModifyWord_SubstRegexArgs;
1371 1383
1372/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1384/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1373 * Perform a regex substitution on the given word. */ 1385 * Perform a regex substitution on the given word. */
1374static void 1386static void
1375ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1387ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1376{ 1388{
1377 ModifyWord_SubstRegexArgs *args = data; 1389 ModifyWord_SubstRegexArgs *args = data;
1378 int xrv; 1390 int xrv;
1379 const char *wp = word; 1391 const char *wp = word;
1380 char *rp; 1392 char *rp;
1381 int flags = 0; 1393 int flags = 0;
1382 regmatch_t m[10]; 1394 regmatch_t m[10];
1383 1395
1384 if ((args->pflags & VARP_SUB_ONE) && (args->pflags & VARP_SUB_MATCHED)) 1396 if ((args->pflags & VARP_SUB_ONE) && (args->pflags & VARP_SUB_MATCHED))
1385 goto nosub; 1397 goto nosub;
1386 1398
1387tryagain: 1399tryagain:
1388 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1400 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1389 1401
1390 switch (xrv) { 1402 switch (xrv) {
1391 case 0: 1403 case 0:
1392 args->pflags |= VARP_SUB_MATCHED; 1404 args->pflags |= VARP_SUB_MATCHED;
1393 SepBuf_AddBytes(buf, wp, m[0].rm_so); 1405 SepBuf_AddBytes(buf, wp, m[0].rm_so);
1394 1406
1395 for (rp = args->replace; *rp; rp++) { 1407 for (rp = args->replace; *rp; rp++) {
1396 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1408 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1397 SepBuf_AddBytes(buf, rp + 1, 1); 1409 SepBuf_AddBytes(buf, rp + 1, 1);
1398 rp++; 1410 rp++;
1399 } else if (*rp == '&' || 1411 } else if (*rp == '&' ||
1400 (*rp == '\\' && isdigit((unsigned char)rp[1]))) { 1412 (*rp == '\\' && isdigit((unsigned char)rp[1]))) {
1401 int n; 1413 int n;
1402 char errstr[3]; 1414 char errstr[3];
1403 1415
1404 if (*rp == '&') { 1416 if (*rp == '&') {
1405 n = 0; 1417 n = 0;
1406 errstr[0] = '&'; 1418 errstr[0] = '&';
1407 errstr[1] = '\0'; 1419 errstr[1] = '\0';
1408 } else { 1420 } else {
1409 n = rp[1] - '0'; 1421 n = rp[1] - '0';
1410 errstr[0] = '\\'; 1422 errstr[0] = '\\';
1411 errstr[1] = rp[1]; 1423 errstr[1] = rp[1];
1412 errstr[2] = '\0'; 1424 errstr[2] = '\0';
1413 rp++; 1425 rp++;
1414 } 1426 }
1415 1427
1416 if (n >= args->nsub) { 1428 if (n >= args->nsub) {
1417 Error("No subexpression %s", errstr); 1429 Error("No subexpression %s", errstr);
1418 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1430 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1419 Error("No match for subexpression %s", errstr); 1431 Error("No match for subexpression %s", errstr);
1420 } else { 1432 } else {
1421 SepBuf_AddBytes(buf, wp + m[n].rm_so, 1433 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1422 m[n].rm_eo - m[n].rm_so); 1434 wp + m[n].rm_eo);
1423 } 1435 }
1424 1436
1425 } else { 1437 } else {
1426 SepBuf_AddBytes(buf, rp, 1); 1438 SepBuf_AddBytes(buf, rp, 1);
1427 } 1439 }
1428 } 1440 }
1429 wp += m[0].rm_eo; 1441 wp += m[0].rm_eo;
1430 if (args->pflags & VARP_SUB_GLOBAL) { 1442 if (args->pflags & VARP_SUB_GLOBAL) {
1431 flags |= REG_NOTBOL; 1443 flags |= REG_NOTBOL;
1432 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1444 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1433 SepBuf_AddBytes(buf, wp, 1); 1445 SepBuf_AddBytes(buf, wp, 1);
1434 wp++; 1446 wp++;
1435 } 1447 }
1436 if (*wp) 1448 if (*wp)
1437 goto tryagain; 1449 goto tryagain;
1438 } 1450 }
1439 if (*wp) { 1451 if (*wp) {
1440 SepBuf_AddBytes(buf, wp, strlen(wp)); 1452 SepBuf_AddStr(buf, wp);
1441 } 1453 }
1442 break; 1454 break;
1443 default: 1455 default:
1444 VarREError(xrv, &args->re, "Unexpected regex error"); 1456 VarREError(xrv, &args->re, "Unexpected regex error");
1445 /* fall through */ 1457 /* fall through */
1446 case REG_NOMATCH: 1458 case REG_NOMATCH:
1447 nosub: 1459 nosub:
1448 SepBuf_AddBytes(buf, wp, strlen(wp)); 1460 SepBuf_AddStr(buf, wp);
1449 break; 1461 break;
1450 } 1462 }
1451} 1463}
1452#endif 1464#endif
1453 1465
1454 1466
1455typedef struct { 1467typedef struct {
1456 GNode *ctx; 1468 GNode *ctx;
1457 char *tvar; /* name of temporary variable */ 1469 char *tvar; /* name of temporary variable */
1458 char *str; /* string to expand */ 1470 char *str; /* string to expand */
1459 VarEvalFlags eflags; 1471 VarEvalFlags eflags;
1460} ModifyWord_LoopArgs; 1472} ModifyWord_LoopArgs;
1461 1473
1462/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1474/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1463static void 1475static void
1464ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1476ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1465{ 1477{
1466 if (word[0] == '\0') 1478 if (word[0] == '\0')
1467 return; 1479 return;
1468 1480
1469 const ModifyWord_LoopArgs *args = data; 1481 const ModifyWord_LoopArgs *args = data;
1470 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1482 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1471 char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags); 1483 char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags);
1472 if (DEBUG(VAR)) { 1484 if (DEBUG(VAR)) {
1473 fprintf(debug_file, 1485 fprintf(debug_file,
1474 "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1486 "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1475 "to \"%s\"\n", 1487 "to \"%s\"\n",
1476 word, args->tvar, args->str, s ? s : "(null)"); 1488 word, args->tvar, args->str, s ? s : "(null)");
1477 } 1489 }
1478 1490
1479 if (s != NULL && s[0] != '\0') { 1491 if (s != NULL && s[0] != '\0') {
1480 if (s[0] == '\n' || (buf->buf.count > 0 && 1492 if (s[0] == '\n' || (buf->buf.count > 0 &&
1481 buf->buf.buffer[buf->buf.count - 1] == '\n')) 1493 buf->buf.buffer[buf->buf.count - 1] == '\n'))
1482 buf->needSep = FALSE; 1494 buf->needSep = FALSE;
1483 SepBuf_AddBytes(buf, s, strlen(s)); 1495 SepBuf_AddStr(buf, s);
1484 } 1496 }
1485 free(s); 1497 free(s);
1486} 1498}
1487 1499
1488 1500
1489/*- 1501/*-
1490 * Implements the :[first..last] modifier. 1502 * Implements the :[first..last] modifier.
1491 * This is a special case of ModifyWords since we want to be able 1503 * This is a special case of ModifyWords since we want to be able
1492 * to scan the list backwards if first > last. 1504 * to scan the list backwards if first > last.
1493 */ 1505 */
1494static char * 1506static char *
1495VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first, 1507VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first,
1496 int last) 1508 int last)
1497{ 1509{
1498 SepBuf buf; 1510 SepBuf buf;
1499 char **av; /* word list */ 1511 char **av; /* word list */
1500 char *as; /* word list memory */ 1512 char *as; /* word list memory */
1501 int ac, i; 1513 int ac, i;
1502 int start, end, step; 1514 int start, end, step;
1503 1515
1504 SepBuf_Init(&buf, sep); 1516 SepBuf_Init(&buf, sep);
1505 1517
1506 if (oneBigWord) { 1518 if (oneBigWord) {
1507 /* fake what brk_string() would do if there were only one word */ 1519 /* fake what brk_string() would do if there were only one word */
1508 ac = 1; 1520 ac = 1;
1509 av = bmake_malloc((ac + 1) * sizeof(char *)); 1521 av = bmake_malloc((ac + 1) * sizeof(char *));
1510 as = bmake_strdup(str); 1522 as = bmake_strdup(str);
1511 av[0] = as; 1523 av[0] = as;
1512 av[1] = NULL; 1524 av[1] = NULL;
1513 } else { 1525 } else {
1514 av = brk_string(str, &ac, FALSE, &as); 1526 av = brk_string(str, &ac, FALSE, &as);
1515 } 1527 }
1516 1528
1517 /* 1529 /*
1518 * Now sanitize seldata. 1530 * Now sanitize seldata.
1519 * If seldata->start or seldata->end are negative, convert them to 1531 * If seldata->start or seldata->end are negative, convert them to
1520 * the positive equivalents (-1 gets converted to argc, -2 gets 1532 * the positive equivalents (-1 gets converted to argc, -2 gets
1521 * converted to (argc-1), etc.). 1533 * converted to (argc-1), etc.).
1522 */ 1534 */
1523 if (first < 0) 1535 if (first < 0)
1524 first += ac + 1; 1536 first += ac + 1;
1525 if (last < 0) 1537 if (last < 0)
1526 last += ac + 1; 1538 last += ac + 1;
1527 1539
1528 /* 1540 /*
1529 * We avoid scanning more of the list than we need to. 1541 * We avoid scanning more of the list than we need to.
1530 */ 1542 */
1531 if (first > last) { 1543 if (first > last) {
1532 start = MIN(ac, first) - 1; 1544 start = MIN(ac, first) - 1;
1533 end = MAX(0, last - 1); 1545 end = MAX(0, last - 1);
1534 step = -1; 1546 step = -1;
1535 } else { 1547 } else {
1536 start = MAX(0, first - 1); 1548 start = MAX(0, first - 1);
1537 end = MIN(ac, last); 1549 end = MIN(ac, last);
1538 step = 1; 1550 step = 1;
1539 } 1551 }
1540 1552
1541 for (i = start; (step < 0) == (i >= end); i += step) { 1553 for (i = start; (step < 0) == (i >= end); i += step) {
1542 SepBuf_AddBytes(&buf, av[i], strlen(av[i])); 1554 SepBuf_AddStr(&buf, av[i]);
1543 SepBuf_Sep(&buf); 1555 SepBuf_Sep(&buf);
1544 } 1556 }
1545 1557
1546 free(as); 1558 free(as);
1547 free(av); 1559 free(av);
1548 1560
1549 return SepBuf_Destroy(&buf, FALSE); 1561 return SepBuf_Destroy(&buf, FALSE);
1550} 1562}
1551 1563
1552 1564
1553/* Callback for ModifyWords to implement the :tA modifier. 1565/* Callback for ModifyWords to implement the :tA modifier.
1554 * Replace each word with the result of realpath() if successful. */ 1566 * Replace each word with the result of realpath() if successful. */
1555static void 1567static void
1556ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1568ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1557{ 1569{
1558 struct stat st; 1570 struct stat st;
1559 char rbuf[MAXPATHLEN]; 1571 char rbuf[MAXPATHLEN];
1560 1572
1561 char *rp = cached_realpath(word, rbuf); 1573 const char *rp = cached_realpath(word, rbuf);
1562 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1574 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1563 word = rp; 1575 word = rp;
1564 1576
1565 SepBuf_AddBytes(buf, word, strlen(word)); 1577 SepBuf_AddStr(buf, word);
1566} 1578}
1567 1579
1568/*- 1580/*-
1569 *----------------------------------------------------------------------- 1581 *-----------------------------------------------------------------------
1570 * Modify each of the words of the passed string using the given function. 1582 * Modify each of the words of the passed string using the given function.
1571 * 1583 *
1572 * Input: 1584 * Input:
1573 * str String whose words should be modified 1585 * str String whose words should be modified
1574 * modifyWord Function that modifies a single word 1586 * modifyWord Function that modifies a single word
1575 * data Custom data for modifyWord 1587 * data Custom data for modifyWord
1576 * 1588 *
1577 * Results: 1589 * Results:
1578 * A string of all the words modified appropriately. 1590 * A string of all the words modified appropriately.
1579 *----------------------------------------------------------------------- 1591 *-----------------------------------------------------------------------
1580 */ 1592 */
1581static char * 1593static char *
1582ModifyWords(GNode *ctx, Byte sep, Boolean oneBigWord, 1594ModifyWords(GNode *ctx, Byte sep, Boolean oneBigWord,
1583 const char *str, ModifyWordsCallback modifyWord, void *data) 1595 const char *str, ModifyWordsCallback modifyWord, void *data)
1584{ 1596{
1585 SepBuf result; 1597 SepBuf result;
1586 char **av; /* word list */ 1598 char **av; /* word list */
1587 char *as; /* word list memory */ 1599 char *as; /* word list memory */
1588 int ac, i; 1600 int ac, i;
1589 1601
1590 SepBuf_Init(&result, sep); 1602 SepBuf_Init(&result, sep);
1591 1603
1592 if (oneBigWord) { 1604 if (oneBigWord) {
1593 /* fake what brk_string() would do if there were only one word */ 1605 /* fake what brk_string() would do if there were only one word */
1594 ac = 1; 1606 ac = 1;
1595 av = bmake_malloc((ac + 1) * sizeof(char *)); 1607 av = bmake_malloc((ac + 1) * sizeof(char *));
1596 as = bmake_strdup(str); 1608 as = bmake_strdup(str);
1597 av[0] = as; 1609 av[0] = as;
1598 av[1] = NULL; 1610 av[1] = NULL;
1599 } else { 1611 } else {
1600 av = brk_string(str, &ac, FALSE, &as); 1612 av = brk_string(str, &ac, FALSE, &as);
1601 } 1613 }
1602 1614
1603 if (DEBUG(VAR)) { 1615 if (DEBUG(VAR)) {
1604 fprintf(debug_file, "ModifyWords: split \"%s\" into %d words\n", 1616 fprintf(debug_file, "ModifyWords: split \"%s\" into %d words\n",
1605 str, ac); 1617 str, ac);
1606 } 1618 }
1607 1619
1608 for (i = 0; i < ac; i++) { 1620 for (i = 0; i < ac; i++) {
1609 size_t orig_count = result.buf.count; 1621 size_t orig_count = result.buf.count;
1610 modifyWord(av[i], &result, data); 1622 modifyWord(av[i], &result, data);
1611 size_t count = result.buf.count; 1623 size_t count = result.buf.count;
1612 if (count != orig_count) 1624 if (count != orig_count)
1613 SepBuf_Sep(&result); 1625 SepBuf_Sep(&result);
1614 } 1626 }
1615 1627
1616 free(as); 1628 free(as);
1617 free(av); 1629 free(av);
1618 1630
1619 return SepBuf_Destroy(&result, FALSE); 1631 return SepBuf_Destroy(&result, FALSE);
1620} 1632}
1621 1633
1622 1634
1623static int 1635static int
1624VarWordCompare(const void *a, const void *b) 1636VarWordCompare(const void *a, const void *b)
1625{ 1637{
1626 int r = strcmp(*(const char * const *)a, *(const char * const *)b); 1638 int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1627 return r; 1639 return r;
1628} 1640}
1629 1641
1630static int 1642static int
1631VarWordCompareReverse(const void *a, const void *b) 1643VarWordCompareReverse(const void *a, const void *b)
1632{ 1644{
1633 int r = strcmp(*(const char * const *)b, *(const char * const *)a); 1645 int r = strcmp(*(const char * const *)b, *(const char * const *)a);
1634 return r; 1646 return r;
1635} 1647}
1636 1648
1637/*- 1649/*-
1638 *----------------------------------------------------------------------- 1650 *-----------------------------------------------------------------------
1639 * VarOrder -- 1651 * VarOrder --
1640 * Order the words in the string. 1652 * Order the words in the string.
1641 * 1653 *
1642 * Input: 1654 * Input:
1643 * str String whose words should be sorted. 1655 * str String whose words should be sorted.
1644 * otype How to order: s - sort, x - random. 1656 * otype How to order: s - sort, x - random.
1645 * 1657 *
1646 * Results: 1658 * Results:
1647 * A string containing the words ordered. 1659 * A string containing the words ordered.
1648 * 1660 *
1649 * Side Effects: 1661 * Side Effects:
1650 * None. 1662 * None.
1651 * 1663 *
1652 *----------------------------------------------------------------------- 1664 *-----------------------------------------------------------------------
1653 */ 1665 */
1654static char * 1666static char *
1655VarOrder(const char *str, const char otype) 1667VarOrder(const char *str, const char otype)
1656{ 1668{
1657 Buffer buf; /* Buffer for the new string */ 1669 Buffer buf; /* Buffer for the new string */
1658 char **av; /* word list [first word does not count] */ 1670 char **av; /* word list [first word does not count] */
1659 char *as; /* word list memory */ 1671 char *as; /* word list memory */
1660 int ac, i; 1672 int ac, i;
1661 1673
1662 Buf_Init(&buf, 0); 1674 Buf_Init(&buf, 0);
1663 1675
1664 av = brk_string(str, &ac, FALSE, &as); 1676 av = brk_string(str, &ac, FALSE, &as);
1665 1677
1666 if (ac > 0) { 1678 if (ac > 0) {
1667 switch (otype) { 1679 switch (otype) {
1668 case 'r': /* reverse sort alphabetically */ 1680 case 'r': /* reverse sort alphabetically */
1669 qsort(av, ac, sizeof(char *), VarWordCompareReverse); 1681 qsort(av, ac, sizeof(char *), VarWordCompareReverse);
1670 break; 1682 break;
1671 case 's': /* sort alphabetically */ 1683 case 's': /* sort alphabetically */
1672 qsort(av, ac, sizeof(char *), VarWordCompare); 1684 qsort(av, ac, sizeof(char *), VarWordCompare);
1673 break; 1685 break;
1674 case 'x': /* randomize */ 1686 case 'x': /* randomize */
1675 { 1687 {
1676 /* 1688 /*
1677 * We will use [ac..2] range for mod factors. This will produce 1689 * We will use [ac..2] range for mod factors. This will produce
1678 * random numbers in [(ac-1)..0] interval, and minimal 1690 * random numbers in [(ac-1)..0] interval, and minimal
1679 * reasonable value for mod factor is 2 (the mod 1 will produce 1691 * reasonable value for mod factor is 2 (the mod 1 will produce
1680 * 0 with probability 1). 1692 * 0 with probability 1).
1681 */ 1693 */
1682 for (i = ac - 1; i > 0; i--) { 1694 for (i = ac - 1; i > 0; i--) {
1683 int rndidx = random() % (i + 1); 1695 int rndidx = random() % (i + 1);
1684 char *t = av[i]; 1696 char *t = av[i];
1685 av[i] = av[rndidx]; 1697 av[i] = av[rndidx];
1686 av[rndidx] = t; 1698 av[rndidx] = t;
1687 } 1699 }
1688 } 1700 }
1689 } 1701 }
1690 } 1702 }
1691 1703
1692 for (i = 0; i < ac; i++) { 1704 for (i = 0; i < ac; i++) {
1693 Buf_AddStr(&buf, av[i]); 1705 Buf_AddStr(&buf, av[i]);
1694 if (i != ac - 1) 1706 if (i != ac - 1)
1695 Buf_AddByte(&buf, ' '); 1707 Buf_AddByte(&buf, ' ');
1696 } 1708 }
1697 1709
1698 free(as); 1710 free(as);
1699 free(av); 1711 free(av);
1700 1712
1701 return Buf_Destroy(&buf, FALSE); 1713 return Buf_Destroy(&buf, FALSE);
1702} 1714}
1703 1715
1704 1716
1705/*- 1717/*-
1706 *----------------------------------------------------------------------- 1718 *-----------------------------------------------------------------------
1707 * VarUniq -- 1719 * VarUniq --
1708 * Remove adjacent duplicate words. 1720 * Remove adjacent duplicate words.
1709 * 1721 *
1710 * Input: 1722 * Input:
1711 * str String whose words should be sorted 1723 * str String whose words should be sorted
1712 * 1724 *
1713 * Results: 1725 * Results:
1714 * A string containing the resulting words. 1726 * A string containing the resulting words.
1715 * 1727 *
1716 * Side Effects: 1728 * Side Effects:
1717 * None. 1729 * None.
1718 * 1730 *
1719 *----------------------------------------------------------------------- 1731 *-----------------------------------------------------------------------
1720 */ 1732 */
1721static char * 1733static char *
1722VarUniq(const char *str) 1734VarUniq(const char *str)
1723{ 1735{
1724 Buffer buf; /* Buffer for new string */ 1736 Buffer buf; /* Buffer for new string */
1725 char **av; /* List of words to affect */ 1737 char **av; /* List of words to affect */
1726 char *as; /* Word list memory */ 1738 char *as; /* Word list memory */
1727 int ac, i, j; 1739 int ac, i, j;
1728 1740
1729 Buf_Init(&buf, 0); 1741 Buf_Init(&buf, 0);
1730 av = brk_string(str, &ac, FALSE, &as); 1742 av = brk_string(str, &ac, FALSE, &as);
1731 1743
1732 if (ac > 1) { 1744 if (ac > 1) {
1733 for (j = 0, i = 1; i < ac; i++) 1745 for (j = 0, i = 1; i < ac; i++)
1734 if (strcmp(av[i], av[j]) != 0 && (++j != i)) 1746 if (strcmp(av[i], av[j]) != 0 && (++j != i))
1735 av[j] = av[i]; 1747 av[j] = av[i];
1736 ac = j + 1; 1748 ac = j + 1;
1737 } 1749 }
1738 1750
1739 for (i = 0; i < ac; i++) { 1751 for (i = 0; i < ac; i++) {
1740 Buf_AddStr(&buf, av[i]); 1752 Buf_AddStr(&buf, av[i]);
1741 if (i != ac - 1) 1753 if (i != ac - 1)
1742 Buf_AddByte(&buf, ' '); 1754 Buf_AddByte(&buf, ' ');
1743 } 1755 }
1744 1756
1745 free(as); 1757 free(as);
1746 free(av); 1758 free(av);
1747 1759
1748 return Buf_Destroy(&buf, FALSE); 1760 return Buf_Destroy(&buf, FALSE);
1749} 1761}
1750 1762
1751/*- 1763/*-
1752 *----------------------------------------------------------------------- 1764 *-----------------------------------------------------------------------
1753 * VarRange -- 1765 * VarRange --
1754 * Return an integer sequence 1766 * Return an integer sequence
1755 * 1767 *
1756 * Input: 1768 * Input:
1757 * str String whose words provide default range 1769 * str String whose words provide default range
1758 * ac range length, if 0 use str words 1770 * ac range length, if 0 use str words
1759 * 1771 *
1760 * Side Effects: 1772 * Side Effects:
1761 * None. 1773 * None.
1762 * 1774 *
1763 *----------------------------------------------------------------------- 1775 *-----------------------------------------------------------------------
1764 */ 1776 */
1765static char * 1777static char *
1766VarRange(const char *str, int ac) 1778VarRange(const char *str, int ac)
1767{ 1779{
1768 Buffer buf; /* Buffer for new string */ 1780 Buffer buf; /* Buffer for new string */
1769 char **av; /* List of words to affect */ 1781 char **av; /* List of words to affect */
1770 char *as; /* Word list memory */ 1782 char *as; /* Word list memory */
1771 int i; 1783 int i;
1772 1784
1773 Buf_Init(&buf, 0); 1785 Buf_Init(&buf, 0);
1774 if (ac > 0) { 1786 if (ac > 0) {
1775 as = NULL; 1787 as = NULL;
1776 av = NULL; 1788 av = NULL;
1777 } else { 1789 } else {
1778 av = brk_string(str, &ac, FALSE, &as); 1790 av = brk_string(str, &ac, FALSE, &as);
1779 } 1791 }
1780 for (i = 0; i < ac; i++) { 1792 for (i = 0; i < ac; i++) {
1781 Buf_AddInt(&buf, 1 + i); 1793 Buf_AddInt(&buf, 1 + i);
1782 if (i != ac - 1) 1794 if (i != ac - 1)
1783 Buf_AddByte(&buf, ' '); 1795 Buf_AddByte(&buf, ' ');
1784 } 1796 }
1785 1797
1786 free(as); 1798 free(as);
1787 free(av); 1799 free(av);
1788 1800
1789 return Buf_Destroy(&buf, FALSE); 1801 return Buf_Destroy(&buf, FALSE);
1790} 1802}
1791 1803
1792 1804
1793/*- 1805/*-
1794 * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/ 1806 * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/
1795 * or the :@ modifier. Nested variables in the text are expanded unless 1807 * or the :@ modifier. Nested variables in the text are expanded unless
1796 * VARE_NOSUBST is set. 1808 * VARE_NOSUBST is set.
1797 * 1809 *
1798 * The text part is parsed until the next delimiter. To escape the delimiter, 1810 * The text part is parsed until the next delimiter. To escape the delimiter,
1799 * a backslash or a dollar, put a backslash before it. 1811 * a backslash or a dollar, put a backslash before it.
1800 * 1812 *
1801 * Return the expanded string or NULL if the delimiter was missing. 1813 * Return the expanded string or NULL if the delimiter was missing.
1802 * If pattern is specified, handle escaped ampersands and replace unescaped 1814 * If pattern is specified, handle escaped ampersands and replace unescaped
1803 * ampersands with the lhs of the pattern (for the :S and :C modifiers). 1815 * ampersands with the lhs of the pattern (for the :S and :C modifiers).
1804 * 1816 *
1805 * If length is specified, return the string length of the buffer. 1817 * If length is specified, return the string length of the buffer.
1806 * If mpflags is specified and the last character of the pattern is a $, 1818 * If mpflags is specified and the last character of the pattern is a $,
1807 * set the VARP_ANCHOR_END bit of mpflags. 1819 * set the VARP_ANCHOR_END bit of mpflags.
1808 */ 1820 */
1809static char * 1821static char *
1810ParseModifierPart(GNode *ctxt, const char **tstr, int delim, 1822ParseModifierPart(GNode *ctxt, const char **tstr, int delim,
1811 VarEvalFlags eflags, VarPatternFlags *mpflags, 1823 VarEvalFlags eflags, VarPatternFlags *mpflags,
1812 size_t *length, ModifyWord_SubstArgs *subst) 1824 size_t *length, ModifyWord_SubstArgs *subst)
1813{ 1825{
1814 const char *cp; 1826 const char *cp;
1815 char *rstr; 1827 char *rstr;
1816 Buffer buf; 1828 Buffer buf;
1817 size_t junk; 1829 size_t junk;
1818 VarEvalFlags errnum = eflags & VARE_UNDEFERR; 1830 VarEvalFlags errnum = eflags & VARE_UNDEFERR;
1819 1831
1820 Buf_Init(&buf, 0); 1832 Buf_Init(&buf, 0);
1821 if (length == NULL) 1833 if (length == NULL)
1822 length = &junk; 1834 length = &junk;
1823 1835
1824 /* 1836 /*
1825 * Skim through until the matching delimiter is found; 1837 * Skim through until the matching delimiter is found;
1826 * pick up variable substitutions on the way. Also allow 1838 * pick up variable substitutions on the way. Also allow
1827 * backslashes to quote the delimiter, $, and \, but don't 1839 * backslashes to quote the delimiter, $, and \, but don't
1828 * touch other backslashes. 1840 * touch other backslashes.
1829 */ 1841 */
1830 for (cp = *tstr; *cp != '\0' && *cp != delim; cp++) { 1842 for (cp = *tstr; *cp != '\0' && *cp != delim; cp++) {
1831 Boolean is_escaped = cp[0] == '\\' && (cp[1] == delim || 1843 Boolean is_escaped = cp[0] == '\\' && (cp[1] == delim ||
1832 cp[1] == '\\' || cp[1] == '$' || (subst != NULL && cp[1] == '&')); 1844 cp[1] == '\\' || cp[1] == '$' || (subst != NULL && cp[1] == '&'));
1833 if (is_escaped) { 1845 if (is_escaped) {
1834 Buf_AddByte(&buf, cp[1]); 1846 Buf_AddByte(&buf, cp[1]);
1835 cp++; 1847 cp++;
1836 } else if (*cp == '$') { 1848 } else if (*cp == '$') {
1837 if (cp[1] == delim) { /* Unescaped $ at end of pattern */ 1849 if (cp[1] == delim) { /* Unescaped $ at end of pattern */
1838 if (mpflags == NULL) 1850 if (mpflags == NULL)
1839 Buf_AddByte(&buf, *cp); 1851 Buf_AddByte(&buf, *cp);
1840 else 1852 else
1841 *mpflags |= VARP_ANCHOR_END; 1853 *mpflags |= VARP_ANCHOR_END;
1842 } else { 1854 } else {
1843 if (!(eflags & VARE_NOSUBST)) { 1855 if (!(eflags & VARE_NOSUBST)) {
1844 char *cp2; 1856 char *cp2;
1845 int len; 1857 int len;
1846 void *freeIt; 1858 void *freeIt;
1847 1859
1848 /* 1860 /*
1849 * If unescaped dollar sign not before the 1861 * If unescaped dollar sign not before the
1850 * delimiter, assume it's a variable 1862 * delimiter, assume it's a variable
1851 * substitution and recurse. 1863 * substitution and recurse.
1852 */ 1864 */
1853 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES), 1865 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES),
1854 &len, &freeIt); 1866 &len, &freeIt);
1855 Buf_AddStr(&buf, cp2); 1867 Buf_AddStr(&buf, cp2);
1856 free(freeIt); 1868 free(freeIt);
1857 cp += len - 1; 1869 cp += len - 1;
1858 } else { 1870 } else {
1859 const char *cp2 = &cp[1]; 1871 const char *cp2 = &cp[1];
1860 1872
1861 if (*cp2 == PROPEN || *cp2 == BROPEN) { 1873 if (*cp2 == PROPEN || *cp2 == BROPEN) {
1862 /* 1874 /*
1863 * Find the end of this variable reference 1875 * Find the end of this variable reference
1864 * and suck it in without further ado. 1876 * and suck it in without further ado.
1865 * It will be interpreted later. 1877 * It will be interpreted later.
1866 */ 1878 */
1867 int have = *cp2; 1879 int have = *cp2;
1868 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; 1880 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
1869 int depth = 1; 1881 int depth = 1;
1870 1882
1871 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { 1883 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
1872 if (cp2[-1] != '\\') { 1884 if (cp2[-1] != '\\') {
1873 if (*cp2 == have) 1885 if (*cp2 == have)
1874 ++depth; 1886 ++depth;
1875 if (*cp2 == want) 1887 if (*cp2 == want)
1876 --depth; 1888 --depth;
1877 } 1889 }
1878 } 1890 }
1879 Buf_AddBytesBetween(&buf, cp, cp2); 1891 Buf_AddBytesBetween(&buf, cp, cp2);
1880 cp = --cp2; 1892 cp = --cp2;
1881 } else 1893 } else
1882 Buf_AddByte(&buf, *cp); 1894 Buf_AddByte(&buf, *cp);
1883 } 1895 }
1884 } 1896 }
1885 } else if (subst != NULL && *cp == '&') 1897 } else if (subst != NULL && *cp == '&')
1886 Buf_AddBytes(&buf, subst->lhsLen, subst->lhs); 1898 Buf_AddBytes(&buf, subst->lhsLen, subst->lhs);
1887 else 1899 else
1888 Buf_AddByte(&buf, *cp); 1900 Buf_AddByte(&buf, *cp);
1889 } 1901 }
1890 1902
1891 if (*cp != delim) { 1903 if (*cp != delim) {
1892 *tstr = cp; 1904 *tstr = cp;
1893 *length = 0; 1905 *length = 0;
1894 return NULL; 1906 return NULL;
1895 } 1907 }
1896 1908
1897 *tstr = ++cp; 1909 *tstr = ++cp;
1898 *length = Buf_Size(&buf); 1910 *length = Buf_Size(&buf);
1899 rstr = Buf_Destroy(&buf, FALSE); 1911 rstr = Buf_Destroy(&buf, FALSE);
1900 if (DEBUG(VAR)) 1912 if (DEBUG(VAR))
1901 fprintf(debug_file, "Modifier part: \"%s\"\n", rstr); 1913 fprintf(debug_file, "Modifier part: \"%s\"\n", rstr);
1902 return rstr; 1914 return rstr;
1903} 1915}
1904 1916
1905/*- 1917/*-
1906 *----------------------------------------------------------------------- 1918 *-----------------------------------------------------------------------
1907 * VarQuote -- 1919 * VarQuote --
1908 * Quote shell meta-characters and space characters in the string 1920 * Quote shell meta-characters and space characters in the string
1909 * if quoteDollar is set, also quote and double any '$' characters. 1921 * if quoteDollar is set, also quote and double any '$' characters.
1910 * 1922 *
1911 * Results: 1923 * Results:
1912 * The quoted string 1924 * The quoted string
1913 * 1925 *
1914 * Side Effects: 1926 * Side Effects:
1915 * None. 1927 * None.
1916 * 1928 *
1917 *----------------------------------------------------------------------- 1929 *-----------------------------------------------------------------------
1918 */ 1930 */
1919static char * 1931static char *
1920VarQuote(char *str, Boolean quoteDollar) 1932VarQuote(char *str, Boolean quoteDollar)
1921{ 1933{
1922 Buffer buf; 1934 Buffer buf;
1923 Buf_Init(&buf, 0); 1935 Buf_Init(&buf, 0);
1924 1936
1925 for (; *str != '\0'; str++) { 1937 for (; *str != '\0'; str++) {
1926 if (*str == '\n') { 1938 if (*str == '\n') {
1927 const char *newline = Shell_GetNewline(); 1939 const char *newline = Shell_GetNewline();
1928 if (newline == NULL) 1940 if (newline == NULL)
1929 newline = "\\\n"; 1941 newline = "\\\n";
1930 Buf_AddStr(&buf, newline); 1942 Buf_AddStr(&buf, newline);
1931 continue; 1943 continue;
1932 } 1944 }
1933 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) 1945 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
1934 Buf_AddByte(&buf, '\\'); 1946 Buf_AddByte(&buf, '\\');
1935 Buf_AddByte(&buf, *str); 1947 Buf_AddByte(&buf, *str);
1936 if (quoteDollar && *str == '$') 1948 if (quoteDollar && *str == '$')
1937 Buf_AddStr(&buf, "\\$"); 1949 Buf_AddStr(&buf, "\\$");
1938 } 1950 }
1939 1951
1940 str = Buf_Destroy(&buf, FALSE); 1952 str = Buf_Destroy(&buf, FALSE);
1941 if (DEBUG(VAR)) 1953 if (DEBUG(VAR))
1942 fprintf(debug_file, "QuoteMeta: [%s]\n", str); 1954 fprintf(debug_file, "QuoteMeta: [%s]\n", str);
1943 return str; 1955 return str;
1944} 1956}
1945 1957
1946/*- 1958/*-
1947 *----------------------------------------------------------------------- 1959 *-----------------------------------------------------------------------
1948 * VarHash -- 1960 * VarHash --
1949 * Hash the string using the MurmurHash3 algorithm. 1961 * Hash the string using the MurmurHash3 algorithm.
1950 * Output is computed using 32bit Little Endian arithmetic. 1962 * Output is computed using 32bit Little Endian arithmetic.
1951 * 1963 *
1952 * Input: 1964 * Input:
1953 * str String to modify 1965 * str String to modify
1954 * 1966 *
1955 * Results: 1967 * Results:
1956 * Hash value of str, encoded as 8 hex digits. 1968 * Hash value of str, encoded as 8 hex digits.
1957 * 1969 *
1958 * Side Effects: 1970 * Side Effects:
1959 * None. 1971 * None.
1960 * 1972 *
1961 *----------------------------------------------------------------------- 1973 *-----------------------------------------------------------------------
1962 */ 1974 */
1963static char * 1975static char *
1964VarHash(const char *str) 1976VarHash(const char *str)
1965{ 1977{
1966 static const char hexdigits[16] = "0123456789abcdef"; 1978 static const char hexdigits[16] = "0123456789abcdef";
1967 Buffer buf; 1979 Buffer buf;
1968 size_t len, len2; 1980 size_t len, len2;
1969 const unsigned char *ustr = (const unsigned char *)str; 1981 const unsigned char *ustr = (const unsigned char *)str;
1970 uint32_t h, k, c1, c2; 1982 uint32_t h, k, c1, c2;
1971 1983
1972 h = 0x971e137bU; 1984 h = 0x971e137bU;
1973 c1 = 0x95543787U; 1985 c1 = 0x95543787U;
1974 c2 = 0x2ad7eb25U; 1986 c2 = 0x2ad7eb25U;
1975 len2 = strlen(str); 1987 len2 = strlen(str);
1976 1988
1977 for (len = len2; len; ) { 1989 for (len = len2; len; ) {
1978 k = 0; 1990 k = 0;
1979 switch (len) { 1991 switch (len) {
1980 default: 1992 default:
1981 k = ((uint32_t)ustr[3] << 24) | 1993 k = ((uint32_t)ustr[3] << 24) |
1982 ((uint32_t)ustr[2] << 16) | 1994 ((uint32_t)ustr[2] << 16) |
1983 ((uint32_t)ustr[1] << 8) | 1995 ((uint32_t)ustr[1] << 8) |
1984 (uint32_t)ustr[0]; 1996 (uint32_t)ustr[0];
1985 len -= 4; 1997 len -= 4;
1986 ustr += 4; 1998 ustr += 4;
1987 break; 1999 break;
1988 case 3: 2000 case 3:
1989 k |= (uint32_t)ustr[2] << 16; 2001 k |= (uint32_t)ustr[2] << 16;
1990 /* FALLTHROUGH */ 2002 /* FALLTHROUGH */
1991 case 2: 2003 case 2:
1992 k |= (uint32_t)ustr[1] << 8; 2004 k |= (uint32_t)ustr[1] << 8;
1993 /* FALLTHROUGH */ 2005 /* FALLTHROUGH */
1994 case 1: 2006 case 1:
1995 k |= (uint32_t)ustr[0]; 2007 k |= (uint32_t)ustr[0];
1996 len = 0; 2008 len = 0;
1997 } 2009 }
1998 c1 = c1 * 5 + 0x7b7d159cU; 2010 c1 = c1 * 5 + 0x7b7d159cU;
1999 c2 = c2 * 5 + 0x6bce6396U; 2011 c2 = c2 * 5 + 0x6bce6396U;
2000 k *= c1; 2012 k *= c1;
2001 k = (k << 11) ^ (k >> 21); 2013 k = (k << 11) ^ (k >> 21);
2002 k *= c2; 2014 k *= c2;
2003 h = (h << 13) ^ (h >> 19); 2015 h = (h << 13) ^ (h >> 19);
2004 h = h * 5 + 0x52dce729U; 2016 h = h * 5 + 0x52dce729U;
2005 h ^= k; 2017 h ^= k;
2006 } 2018 }
2007 h ^= len2; 2019 h ^= len2;
2008 h *= 0x85ebca6b; 2020 h *= 0x85ebca6b;
2009 h ^= h >> 13; 2021 h ^= h >> 13;
2010 h *= 0xc2b2ae35; 2022 h *= 0xc2b2ae35;
2011 h ^= h >> 16; 2023 h ^= h >> 16;
2012 2024
2013 Buf_Init(&buf, 0); 2025 Buf_Init(&buf, 0);
2014 for (len = 0; len < 8; ++len) { 2026 for (len = 0; len < 8; ++len) {
2015 Buf_AddByte(&buf, hexdigits[h & 15]); 2027 Buf_AddByte(&buf, hexdigits[h & 15]);
2016 h >>= 4; 2028 h >>= 4;
2017 } 2029 }
2018 2030
2019 return Buf_Destroy(&buf, FALSE); 2031 return Buf_Destroy(&buf, FALSE);
2020} 2032}
2021 2033
2022static char * 2034static char *
2023VarStrftime(const char *fmt, int zulu, time_t utc) 2035VarStrftime(const char *fmt, int zulu, time_t utc)
2024{ 2036{
2025 char buf[BUFSIZ]; 2037 char buf[BUFSIZ];
2026 2038
2027 if (!utc) 2039 if (!utc)
2028 time(&utc); 2040 time(&utc);
2029 if (!*fmt) 2041 if (!*fmt)
2030 fmt = "%c"; 2042 fmt = "%c";
2031 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); 2043 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2032 2044
2033 buf[sizeof(buf) - 1] = '\0'; 2045 buf[sizeof(buf) - 1] = '\0';
2034 return bmake_strdup(buf); 2046 return bmake_strdup(buf);
2035} 2047}
2036 2048
2037typedef struct { 2049typedef struct {
2038 /* const parameters */ 2050 /* const parameters */
2039 int startc; /* '\0' or '{' or '(' */ 2051 int startc; /* '\0' or '{' or '(' */
2040 int endc; 2052 int endc;
2041 Var *v; 2053 Var *v;
2042 GNode *ctxt; 2054 GNode *ctxt;
2043 VarEvalFlags eflags; 2055 VarEvalFlags eflags;
2044 int *lengthPtr; 2056 int *lengthPtr;
2045 void **freePtr; 2057 void **freePtr;
2046 2058
2047 /* read-write */ 2059 /* read-write */
2048 char *nstr; 2060 char *nstr;
2049 const char *start; 2061 const char *start;
2050 const char *cp; /* The position where parsing continues 2062 const char *cp; /* The position where parsing continues
2051 * after the current modifier. */ 2063 * after the current modifier. */
2052 char termc; /* Character which terminated scan */ 2064 char termc; /* Character which terminated scan */
2053 char missing_delim; /* For error reporting */ 2065 char missing_delim; /* For error reporting */
2054 int modifier; /* that we are processing */ 2066 int modifier; /* that we are processing */
2055 2067
2056 Byte sep; /* Word separator in expansions */ 2068 Byte sep; /* Word separator in expansions */
2057 Boolean oneBigWord; /* TRUE if we will treat the variable as a 2069 Boolean oneBigWord; /* TRUE if we will treat the variable as a
2058 * single big word, even if it contains 2070 * single big word, even if it contains
2059 * embedded spaces (as opposed to the 2071 * embedded spaces (as opposed to the
2060 * usual behaviour of treating it as 2072 * usual behaviour of treating it as
2061 * several space-separated words). */ 2073 * several space-separated words). */
2062 2074
2063 /* result */ 2075 /* result */
2064 char *newStr; /* New value to return */ 2076 char *newStr; /* New value to return */
2065} ApplyModifiersState; 2077} ApplyModifiersState;
2066 2078
2067/* we now have some modifiers with long names */ 2079/* we now have some modifiers with long names */
2068#define STRMOD_MATCH(s, want, n) \ 2080#define STRMOD_MATCH(s, want, n) \
2069 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':')) 2081 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
2070#define STRMOD_MATCHX(s, want, n) \ 2082#define STRMOD_MATCHX(s, want, n) \
2071 (strncmp(s, want, n) == 0 && \ 2083 (strncmp(s, want, n) == 0 && \
2072 (s[n] == st->endc || s[n] == ':' || s[n] == '=')) 2084 (s[n] == st->endc || s[n] == ':' || s[n] == '='))
2073#define CHARMOD_MATCH(c) (c == st->endc || c == ':') 2085#define CHARMOD_MATCH(c) (c == st->endc || c == ':')
2074 2086
2075/* :@var@...${var}...@ */ 2087/* :@var@...${var}...@ */
2076static Boolean 2088static Boolean
2077ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { 2089ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) {
2078 ModifyWord_LoopArgs args; 2090 ModifyWord_LoopArgs args;
2079 2091
2080 args.ctx = st->ctxt; 2092 args.ctx = st->ctxt;
2081 st->cp = mod + 1; 2093 st->cp = mod + 1;
2082 char delim = '@'; 2094 char delim = '@';
2083 args.tvar = ParseModifierPart(st->ctxt, &st->cp, delim, 2095 args.tvar = ParseModifierPart(st->ctxt, &st->cp, delim,
2084 st->eflags | VARE_NOSUBST, 2096 st->eflags | VARE_NOSUBST,
2085 NULL, NULL, NULL); 2097 NULL, NULL, NULL);
2086 if (args.tvar == NULL) { 2098 if (args.tvar == NULL) {
2087 st->missing_delim = delim; 2099 st->missing_delim = delim;
2088 return FALSE; 2100 return FALSE;
2089 } 2101 }
2090 2102
2091 args.str = ParseModifierPart(st->ctxt, &st->cp, delim, 2103 args.str = ParseModifierPart(st->ctxt, &st->cp, delim,
2092 st->eflags | VARE_NOSUBST, 2104 st->eflags | VARE_NOSUBST,
2093 NULL, NULL, NULL); 2105 NULL, NULL, NULL);
2094 if (args.str == NULL) { 2106 if (args.str == NULL) {
2095 st->missing_delim = delim; 2107 st->missing_delim = delim;
2096 return FALSE; 2108 return FALSE;
2097 } 2109 }
2098 2110
2099 st->termc = *st->cp; 2111 st->termc = *st->cp;
2100 2112
2101 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); 2113 args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES);
2102 int prev_sep = st->sep; 2114 int prev_sep = st->sep;
2103 st->sep = ' '; /* XXX: this is inconsistent */ 2115 st->sep = ' '; /* XXX: this is inconsistent */
2104 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2116 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2105 ModifyWord_Loop, &args); 2117 ModifyWord_Loop, &args);
2106 st->sep = prev_sep; 2118 st->sep = prev_sep;
2107 Var_Delete(args.tvar, st->ctxt); 2119 Var_Delete(args.tvar, st->ctxt);
2108 free(args.tvar); 2120 free(args.tvar);
2109 free(args.str); 2121 free(args.str);
2110 return TRUE; 2122 return TRUE;
2111} 2123}
2112 2124
2113/* :Ddefined or :Uundefined */ 2125/* :Ddefined or :Uundefined */
2114static void 2126static void
2115ApplyModifier_Defined(const char *mod, ApplyModifiersState *st) 2127ApplyModifier_Defined(const char *mod, ApplyModifiersState *st)
2116{ 2128{
2117 Buffer buf; /* Buffer for patterns */ 2129 Buffer buf; /* Buffer for patterns */
2118 VarEvalFlags neflags; 2130 VarEvalFlags neflags;
2119 2131
2120 if (st->eflags & VARE_WANTRES) { 2132 if (st->eflags & VARE_WANTRES) {
2121 Boolean wantres; 2133 Boolean wantres;
2122 if (*mod == 'U') 2134 if (*mod == 'U')
2123 wantres = ((st->v->flags & VAR_JUNK) != 0); 2135 wantres = ((st->v->flags & VAR_JUNK) != 0);
2124 else 2136 else
2125 wantres = ((st->v->flags & VAR_JUNK) == 0); 2137 wantres = ((st->v->flags & VAR_JUNK) == 0);
2126 neflags = st->eflags & ~VARE_WANTRES; 2138 neflags = st->eflags & ~VARE_WANTRES;
2127 if (wantres) 2139 if (wantres)
2128 neflags |= VARE_WANTRES; 2140 neflags |= VARE_WANTRES;
2129 } else 2141 } else
2130 neflags = st->eflags; 2142 neflags = st->eflags;
2131 2143
2132 /* 2144 /*
2133 * Pass through mod looking for 1) escaped delimiters, 2145 * Pass through mod looking for 1) escaped delimiters,
2134 * '$'s and backslashes (place the escaped character in 2146 * '$'s and backslashes (place the escaped character in
2135 * uninterpreted) and 2) unescaped $'s that aren't before 2147 * uninterpreted) and 2) unescaped $'s that aren't before
2136 * the delimiter (expand the variable substitution). 2148 * the delimiter (expand the variable substitution).
2137 * The result is left in the Buffer buf. 2149 * The result is left in the Buffer buf.
2138 */ 2150 */
2139 Buf_Init(&buf, 0); 2151 Buf_Init(&buf, 0);
2140 for (st->cp = mod + 1; 2152 for (st->cp = mod + 1;
2141 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0'; 2153 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
2142 st->cp++) { 2154 st->cp++) {
2143 if (*st->cp == '\\' && 2155 if (*st->cp == '\\' &&
2144 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc || 2156 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
2145 st->cp[1] == '\\')) { 2157 st->cp[1] == '\\')) {
2146 Buf_AddByte(&buf, st->cp[1]); 2158 Buf_AddByte(&buf, st->cp[1]);
2147 st->cp++; 2159 st->cp++;
2148 } else if (*st->cp == '$') { 2160 } else if (*st->cp == '$') {
2149 /* 2161 /*
2150 * If unescaped dollar sign, assume it's a 2162 * If unescaped dollar sign, assume it's a
2151 * variable substitution and recurse. 2163 * variable substitution and recurse.
2152 */ 2164 */
2153 char *cp2; 2165 char *cp2;
2154 int len; 2166 int len;
2155 void *freeIt; 2167 void *freeIt;
2156 2168
2157 cp2 = Var_Parse(st->cp, st->ctxt, neflags, &len, &freeIt); 2169 cp2 = Var_Parse(st->cp, st->ctxt, neflags, &len, &freeIt);
2158 Buf_AddStr(&buf, cp2); 2170 Buf_AddStr(&buf, cp2);
2159 free(freeIt); 2171 free(freeIt);
2160 st->cp += len - 1; 2172 st->cp += len - 1;
2161 } else { 2173 } else {
2162 Buf_AddByte(&buf, *st->cp); 2174 Buf_AddByte(&buf, *st->cp);
2163 } 2175 }
2164 } 2176 }
2165 2177
2166 st->termc = *st->cp; 2178 st->termc = *st->cp;
2167 2179
2168 if (st->v->flags & VAR_JUNK) 2180 if (st->v->flags & VAR_JUNK)
2169 st->v->flags |= VAR_KEEP; 2181 st->v->flags |= VAR_KEEP;
2170 if (neflags & VARE_WANTRES) { 2182 if (neflags & VARE_WANTRES) {
2171 st->newStr = Buf_Destroy(&buf, FALSE); 2183 st->newStr = Buf_Destroy(&buf, FALSE);
2172 } else { 2184 } else {
2173 st->newStr = st->nstr; 2185 st->newStr = st->nstr;
2174 Buf_Destroy(&buf, TRUE); 2186 Buf_Destroy(&buf, TRUE);
2175 } 2187 }
2176} 2188}
2177 2189
2178/* :gmtime */ 2190/* :gmtime */
2179static Boolean 2191static Boolean
2180ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) 2192ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st)
2181{ 2193{
2182 time_t utc; 2194 time_t utc;
2183 char *ep; 2195 char *ep;
2184 2196
2185 st->cp = mod + 1; /* make sure it is set */ 2197 st->cp = mod + 1; /* make sure it is set */
2186 if (!STRMOD_MATCHX(mod, "gmtime", 6)) 2198 if (!STRMOD_MATCHX(mod, "gmtime", 6))
2187 return FALSE; 2199 return FALSE;
2188 if (mod[6] == '=') { 2200 if (mod[6] == '=') {
2189 utc = strtoul(mod + 7, &ep, 10); 2201 utc = strtoul(mod + 7, &ep, 10);
2190 st->cp = ep; 2202 st->cp = ep;
2191 } else { 2203 } else {
2192 utc = 0; 2204 utc = 0;
2193 st->cp = mod + 6; 2205 st->cp = mod + 6;
2194 } 2206 }
2195 st->newStr = VarStrftime(st->nstr, 1, utc); 2207 st->newStr = VarStrftime(st->nstr, 1, utc);
2196 st->termc = *st->cp; 2208 st->termc = *st->cp;
2197 return TRUE; 2209 return TRUE;
2198} 2210}
2199 2211
2200/* :localtime */ 2212/* :localtime */
2201static Boolean 2213static Boolean
2202ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) 2214ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st)
2203{ 2215{
2204 time_t utc; 2216 time_t utc;
2205 char *ep; 2217 char *ep;
2206 2218
2207 st->cp = mod + 1; /* make sure it is set */ 2219 st->cp = mod + 1; /* make sure it is set */
2208 if (!STRMOD_MATCHX(mod, "localtime", 9)) 2220 if (!STRMOD_MATCHX(mod, "localtime", 9))
2209 return FALSE; 2221 return FALSE;
2210 2222
2211 if (mod[9] == '=') { 2223 if (mod[9] == '=') {
2212 utc = strtoul(mod + 10, &ep, 10); 2224 utc = strtoul(mod + 10, &ep, 10);
2213 st->cp = ep; 2225 st->cp = ep;
2214 } else { 2226 } else {
2215 utc = 0; 2227 utc = 0;
2216 st->cp = mod + 9; 2228 st->cp = mod + 9;
2217 } 2229 }
2218 st->newStr = VarStrftime(st->nstr, 0, utc); 2230 st->newStr = VarStrftime(st->nstr, 0, utc);
2219 st->termc = *st->cp; 2231 st->termc = *st->cp;
2220 return TRUE; 2232 return TRUE;
2221} 2233}
2222 2234
2223/* :hash */ 2235/* :hash */
2224static Boolean 2236static Boolean
2225ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) 2237ApplyModifier_Hash(const char *mod, ApplyModifiersState *st)
2226{ 2238{
2227 st->cp = mod + 1; /* make sure it is set */ 2239 st->cp = mod + 1; /* make sure it is set */
2228 if (!STRMOD_MATCH(mod, "hash", 4)) 2240 if (!STRMOD_MATCH(mod, "hash", 4))
2229 return FALSE; 2241 return FALSE;
2230 st->newStr = VarHash(st->nstr); 2242 st->newStr = VarHash(st->nstr);
2231 st->cp = mod + 4; 2243 st->cp = mod + 4;
2232 st->termc = *st->cp; 2244 st->termc = *st->cp;
2233 return TRUE; 2245 return TRUE;
2234} 2246}
2235 2247
2236/* :P */ 2248/* :P */
2237static void 2249static void
2238ApplyModifier_Path(const char *mod, ApplyModifiersState *st) 2250ApplyModifier_Path(const char *mod, ApplyModifiersState *st)
2239{ 2251{
2240 if ((st->v->flags & VAR_JUNK) != 0) 2252 if ((st->v->flags & VAR_JUNK) != 0)
2241 st->v->flags |= VAR_KEEP; 2253 st->v->flags |= VAR_KEEP;
2242 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); 2254 GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2243 if (gn == NULL || gn->type & OP_NOPATH) { 2255 if (gn == NULL || gn->type & OP_NOPATH) {
2244 st->newStr = NULL; 2256 st->newStr = NULL;
2245 } else if (gn->path) { 2257 } else if (gn->path) {
2246 st->newStr = bmake_strdup(gn->path); 2258 st->newStr = bmake_strdup(gn->path);
2247 } else { 2259 } else {
2248 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); 2260 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2249 } 2261 }
2250 if (!st->newStr) 2262 if (!st->newStr)
2251 st->newStr = bmake_strdup(st->v->name); 2263 st->newStr = bmake_strdup(st->v->name);
2252 st->cp = mod + 1; 2264 st->cp = mod + 1;
2253 st->termc = *st->cp; 2265 st->termc = *st->cp;
2254} 2266}
2255 2267
2256/* :!cmd! */ 2268/* :!cmd! */
2257static Boolean 2269static Boolean
2258ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) 2270ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st)
2259{ 2271{
2260 st->cp = mod + 1; 2272 st->cp = mod + 1;
2261 char delim = '!'; 2273 char delim = '!';
2262 char *cmd = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2274 char *cmd = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2263 NULL, NULL, NULL); 2275 NULL, NULL, NULL);
2264 if (cmd == NULL) { 2276 if (cmd == NULL) {
2265 st->missing_delim = delim; 2277 st->missing_delim = delim;
2266 return FALSE; 2278 return FALSE;
2267 } 2279 }
2268 2280
2269 const char *emsg = NULL; 2281 const char *emsg = NULL;
2270 if (st->eflags & VARE_WANTRES) 2282 if (st->eflags & VARE_WANTRES)
2271 st->newStr = Cmd_Exec(cmd, &emsg); 2283 st->newStr = Cmd_Exec(cmd, &emsg);
2272 else 2284 else
2273 st->newStr = varNoError; 2285 st->newStr = varNoError;
2274 free(cmd); 2286 free(cmd);
2275 2287
2276 if (emsg) 2288 if (emsg)
2277 Error(emsg, st->nstr); 2289 Error(emsg, st->nstr);
2278 2290
2279 st->termc = *st->cp; 2291 st->termc = *st->cp;
2280 if (st->v->flags & VAR_JUNK) 2292 if (st->v->flags & VAR_JUNK)
2281 st->v->flags |= VAR_KEEP; 2293 st->v->flags |= VAR_KEEP;
2282 return TRUE; 2294 return TRUE;
2283} 2295}
2284 2296
2285/* :range */ 2297/* :range */
2286static Boolean 2298static Boolean
2287ApplyModifier_Range(const char *mod, ApplyModifiersState *st) 2299ApplyModifier_Range(const char *mod, ApplyModifiersState *st)
2288{ 2300{
2289 int n; 2301 int n;
2290 char *ep; 2302 char *ep;
2291 2303
2292 st->cp = mod + 1; /* make sure it is set */ 2304 st->cp = mod + 1; /* make sure it is set */
2293 if (!STRMOD_MATCHX(mod, "range", 5)) 2305 if (!STRMOD_MATCHX(mod, "range", 5))
2294 return FALSE; 2306 return FALSE;
2295 2307
2296 if (mod[5] == '=') { 2308 if (mod[5] == '=') {
2297 n = strtoul(mod + 6, &ep, 10); 2309 n = strtoul(mod + 6, &ep, 10);
2298 st->cp = ep; 2310 st->cp = ep;
2299 } else { 2311 } else {
2300 n = 0; 2312 n = 0;
2301 st->cp = mod + 5; 2313 st->cp = mod + 5;
2302 } 2314 }
2303 st->newStr = VarRange(st->nstr, n); 2315 st->newStr = VarRange(st->nstr, n);
2304 st->termc = *st->cp; 2316 st->termc = *st->cp;
2305 return TRUE; 2317 return TRUE;
2306} 2318}
2307 2319
2308/* :Mpattern or :Npattern */ 2320/* :Mpattern or :Npattern */
2309static void 2321static void
2310ApplyModifier_Match(const char *mod, ApplyModifiersState *st) 2322ApplyModifier_Match(const char *mod, ApplyModifiersState *st)
2311{ 2323{
2312 Boolean copy = FALSE; /* pattern should be, or has been, copied */ 2324 Boolean copy = FALSE; /* pattern should be, or has been, copied */
2313 Boolean needSubst = FALSE; 2325 Boolean needSubst = FALSE;
2314 /* 2326 /*
2315 * In the loop below, ignore ':' unless we are at (or back to) the 2327 * In the loop below, ignore ':' unless we are at (or back to) the
2316 * original brace level. 2328 * original brace level.
2317 * XXX This will likely not work right if $() and ${} are intermixed. 2329 * XXX This will likely not work right if $() and ${} are intermixed.
2318 */ 2330 */
2319 int nest = 1; 2331 int nest = 1;
2320 for (st->cp = mod + 1; 2332 for (st->cp = mod + 1;
2321 *st->cp != '\0' && !(*st->cp == ':' && nest == 1); 2333 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2322 st->cp++) { 2334 st->cp++) {
2323 if (*st->cp == '\\' && 2335 if (*st->cp == '\\' &&
2324 (st->cp[1] == ':' || st->cp[1] == st->endc || 2336 (st->cp[1] == ':' || st->cp[1] == st->endc ||
2325 st->cp[1] == st->startc)) { 2337 st->cp[1] == st->startc)) {
2326 if (!needSubst) 2338 if (!needSubst)
2327 copy = TRUE; 2339 copy = TRUE;
2328 st->cp++; 2340 st->cp++;
2329 continue; 2341 continue;
2330 } 2342 }
2331 if (*st->cp == '$') 2343 if (*st->cp == '$')
2332 needSubst = TRUE; 2344 needSubst = TRUE;
2333 if (*st->cp == '(' || *st->cp == '{') 2345 if (*st->cp == '(' || *st->cp == '{')
2334 ++nest; 2346 ++nest;
2335 if (*st->cp == ')' || *st->cp == '}') { 2347 if (*st->cp == ')' || *st->cp == '}') {
2336 --nest; 2348 --nest;
2337 if (nest == 0) 2349 if (nest == 0)
2338 break; 2350 break;
2339 } 2351 }
2340 } 2352 }
2341 st->termc = *st->cp; 2353 st->termc = *st->cp;
2342 const char *endpat = st->cp; 2354 const char *endpat = st->cp;
2343 2355
2344 char *pattern = NULL; 2356 char *pattern = NULL;
2345 if (copy) { 2357 if (copy) {
2346 /* 2358 /*
2347 * Need to compress the \:'s out of the pattern, so 2359 * Need to compress the \:'s out of the pattern, so
2348 * allocate enough room to hold the uncompressed 2360 * allocate enough room to hold the uncompressed
2349 * pattern (note that st->cp started at mod+1, so 2361 * pattern (note that st->cp started at mod+1, so
2350 * st->cp - mod takes the null byte into account) and 2362 * st->cp - mod takes the null byte into account) and
2351 * compress the pattern into the space. 2363 * compress the pattern into the space.
2352 */ 2364 */
2353 pattern = bmake_malloc(st->cp - mod); 2365 pattern = bmake_malloc(st->cp - mod);
2354 char *cp2; 2366 char *cp2;
2355 for (cp2 = pattern, st->cp = mod + 1; 2367 for (cp2 = pattern, st->cp = mod + 1;
2356 st->cp < endpat; 2368 st->cp < endpat;
2357 st->cp++, cp2++) { 2369 st->cp++, cp2++) {
2358 if ((*st->cp == '\\') && (st->cp+1 < endpat) && 2370 if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2359 (st->cp[1] == ':' || st->cp[1] == st->endc)) 2371 (st->cp[1] == ':' || st->cp[1] == st->endc))
2360 st->cp++; 2372 st->cp++;
2361 *cp2 = *st->cp; 2373 *cp2 = *st->cp;
2362 } 2374 }
2363 *cp2 = '\0'; 2375 *cp2 = '\0';
2364 endpat = cp2; 2376 endpat = cp2;
2365 } else { 2377 } else {
2366 /* 2378 /*
2367 * Either Var_Subst or ModifyWords will need a 2379 * Either Var_Subst or ModifyWords will need a
2368 * nul-terminated string soon, so construct one now. 2380 * nul-terminated string soon, so construct one now.
2369 */ 2381 */
2370 pattern = bmake_strndup(mod + 1, endpat - (mod + 1)); 2382 pattern = bmake_strndup(mod + 1, endpat - (mod + 1));
2371 } 2383 }
2372 if (needSubst) { 2384 if (needSubst) {
2373 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2385 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2374 char *old_pattern = pattern; 2386 char *old_pattern = pattern;
2375 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags); 2387 pattern = Var_Subst(NULL, pattern, st->ctxt, st->eflags);
2376 free(old_pattern); 2388 free(old_pattern);
2377 } 2389 }
2378 if (DEBUG(VAR)) 2390 if (DEBUG(VAR))
2379 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", 2391 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2380 st->v->name, st->nstr, pattern); 2392 st->v->name, st->nstr, pattern);
2381 ModifyWordsCallback callback = mod[0] == 'M' 2393 ModifyWordsCallback callback = mod[0] == 'M'
2382 ? ModifyWord_Match : ModifyWord_NoMatch; 2394 ? ModifyWord_Match : ModifyWord_NoMatch;
2383 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2395 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2384 callback, pattern); 2396 callback, pattern);
2385 free(pattern); 2397 free(pattern);
2386} 2398}
2387 2399
2388/* :S,from,to, */ 2400/* :S,from,to, */
2389static Boolean 2401static Boolean
2390ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) 2402ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st)
2391{ 2403{
2392 ModifyWord_SubstArgs args; 2404 ModifyWord_SubstArgs args;
2393 Boolean oneBigWord = st->oneBigWord; 2405 Boolean oneBigWord = st->oneBigWord;
2394 char delim = mod[1]; 2406 char delim = mod[1];
2395 2407
2396 st->cp = mod + 2; 2408 st->cp = mod + 2;
2397 2409
2398 /* 2410 /*
2399 * If pattern begins with '^', it is anchored to the 2411 * If pattern begins with '^', it is anchored to the
2400 * start of the word -- skip over it and flag pattern. 2412 * start of the word -- skip over it and flag pattern.
2401 */ 2413 */
2402 args.pflags = 0; 2414 args.pflags = 0;
2403 if (*st->cp == '^') { 2415 if (*st->cp == '^') {
2404 args.pflags |= VARP_ANCHOR_START; 2416 args.pflags |= VARP_ANCHOR_START;
2405 st->cp++; 2417 st->cp++;
2406 } 2418 }
2407 2419
2408 char *lhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2420 char *lhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2409 &args.pflags, &args.lhsLen, NULL); 2421 &args.pflags, &args.lhsLen, NULL);
2410 if (lhs == NULL) { 2422 if (lhs == NULL) {
2411 st->missing_delim = delim; 2423 st->missing_delim = delim;
2412 return FALSE; 2424 return FALSE;
2413 } 2425 }
2414 args.lhs = lhs; 2426 args.lhs = lhs;
2415 2427
2416 char *rhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2428 char *rhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2417 NULL, &args.rhsLen, &args); 2429 NULL, &args.rhsLen, &args);
2418 if (rhs == NULL) { 2430 if (rhs == NULL) {
2419 st->missing_delim = delim; 2431 st->missing_delim = delim;
2420 return FALSE; 2432 return FALSE;
2421 } 2433 }
2422 args.rhs = rhs; 2434 args.rhs = rhs;
2423 2435
2424 /* 2436 /*
2425 * Check for global substitution. If 'g' after the final 2437 * Check for global substitution. If 'g' after the final
2426 * delimiter, substitution is global and is marked that 2438 * delimiter, substitution is global and is marked that
2427 * way. 2439 * way.
2428 */ 2440 */
2429 for (;; st->cp++) { 2441 for (;; st->cp++) {
2430 switch (*st->cp) { 2442 switch (*st->cp) {
2431 case 'g': 2443 case 'g':
2432 args.pflags |= VARP_SUB_GLOBAL; 2444 args.pflags |= VARP_SUB_GLOBAL;
2433 continue; 2445 continue;
2434 case '1': 2446 case '1':
2435 args.pflags |= VARP_SUB_ONE; 2447 args.pflags |= VARP_SUB_ONE;
2436 continue; 2448 continue;
2437 case 'W': 2449 case 'W':
2438 oneBigWord = TRUE; 2450 oneBigWord = TRUE;
2439 continue; 2451 continue;
2440 } 2452 }
2441 break; 2453 break;
2442 } 2454 }
2443 2455
2444 st->termc = *st->cp; 2456 st->termc = *st->cp;
2445 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2457 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2446 ModifyWord_Subst, &args); 2458 ModifyWord_Subst, &args);
2447 2459
2448 free(lhs); 2460 free(lhs);
2449 free(rhs); 2461 free(rhs);
2450 return TRUE; 2462 return TRUE;
2451} 2463}
2452 2464
2453#ifndef NO_REGEX 2465#ifndef NO_REGEX
2454 2466
2455/* :C,from,to, */ 2467/* :C,from,to, */
2456static Boolean 2468static Boolean
2457ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) 2469ApplyModifier_Regex(const char *mod, ApplyModifiersState *st)
2458{ 2470{
2459 ModifyWord_SubstRegexArgs args; 2471 ModifyWord_SubstRegexArgs args;
2460 2472
2461 args.pflags = 0; 2473 args.pflags = 0;
2462 Boolean oneBigWord = st->oneBigWord; 2474 Boolean oneBigWord = st->oneBigWord;
2463 char delim = mod[1]; 2475 char delim = mod[1];
2464 2476
2465 st->cp = mod + 2; 2477 st->cp = mod + 2;
2466 2478
2467 char *re = ParseModifierPart(st->ctxt, &st->cp, delim, 2479 char *re = ParseModifierPart(st->ctxt, &st->cp, delim,
2468 st->eflags, NULL, NULL, NULL); 2480 st->eflags, NULL, NULL, NULL);
2469 if (re == NULL) { 2481 if (re == NULL) {
2470 st->missing_delim = delim; 2482 st->missing_delim = delim;
2471 return FALSE; 2483 return FALSE;
2472 } 2484 }
2473 2485
2474 args.replace = ParseModifierPart(st->ctxt, &st->cp, delim, 2486 args.replace = ParseModifierPart(st->ctxt, &st->cp, delim,
2475 st->eflags, NULL, NULL, NULL); 2487 st->eflags, NULL, NULL, NULL);
2476 if (args.replace == NULL) { 2488 if (args.replace == NULL) {
2477 free(re); 2489 free(re);
2478 st->missing_delim = delim; 2490 st->missing_delim = delim;
2479 return FALSE; 2491 return FALSE;
2480 } 2492 }
2481 2493
2482 for (;; st->cp++) { 2494 for (;; st->cp++) {
2483 switch (*st->cp) { 2495 switch (*st->cp) {
2484 case 'g': 2496 case 'g':
2485 args.pflags |= VARP_SUB_GLOBAL; 2497 args.pflags |= VARP_SUB_GLOBAL;
2486 continue; 2498 continue;
2487 case '1': 2499 case '1':
2488 args.pflags |= VARP_SUB_ONE; 2500 args.pflags |= VARP_SUB_ONE;
2489 continue; 2501 continue;
2490 case 'W': 2502 case 'W':
2491 oneBigWord = TRUE; 2503 oneBigWord = TRUE;
2492 continue; 2504 continue;
2493 } 2505 }
2494 break; 2506 break;
2495 } 2507 }
2496 2508
2497 st->termc = *st->cp; 2509 st->termc = *st->cp;
2498 2510
2499 int error = regcomp(&args.re, re, REG_EXTENDED); 2511 int error = regcomp(&args.re, re, REG_EXTENDED);
2500 free(re); 2512 free(re);
2501 if (error) { 2513 if (error) {
2502 *st->lengthPtr = st->cp - st->start + 1; 2514 *st->lengthPtr = st->cp - st->start + 1;
2503 VarREError(error, &args.re, "RE substitution error"); 2515 VarREError(error, &args.re, "RE substitution error");
2504 free(args.replace); 2516 free(args.replace);
2505 return FALSE; 2517 return FALSE;
2506 } 2518 }
2507 2519
2508 args.nsub = args.re.re_nsub + 1; 2520 args.nsub = args.re.re_nsub + 1;
2509 if (args.nsub < 1) 2521 if (args.nsub < 1)
2510 args.nsub = 1; 2522 args.nsub = 1;
2511 if (args.nsub > 10) 2523 if (args.nsub > 10)
2512 args.nsub = 10; 2524 args.nsub = 10;
2513 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, 2525 st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr,
2514 ModifyWord_SubstRegex, &args); 2526 ModifyWord_SubstRegex, &args);
2515 regfree(&args.re); 2527 regfree(&args.re);
2516 free(args.replace); 2528 free(args.replace);
2517 return TRUE; 2529 return TRUE;
2518} 2530}
2519#endif 2531#endif
2520 2532
2521static void 2533static void
2522ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 2534ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2523{ 2535{
2524 SepBuf_AddBytes(buf, word, strlen(word)); 2536 SepBuf_AddStr(buf, word);
2525} 2537}
2526 2538
2527/* :ts<separator> */ 2539/* :ts<separator> */
2528static Boolean 2540static Boolean
2529ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) 2541ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st)
2530{ 2542{
2531 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { 2543 if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2532 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ 2544 /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */
2533 st->sep = sep[0]; 2545 st->sep = sep[0];
2534 st->cp = sep + 1; 2546 st->cp = sep + 1;
2535 } else if (sep[0] == st->endc || sep[0] == ':') { 2547 } else if (sep[0] == st->endc || sep[0] == ':') {
2536 /* ":ts<endc>" or ":ts:" */ 2548 /* ":ts<endc>" or ":ts:" */
2537 st->sep = '\0'; /* no separator */ 2549 st->sep = '\0'; /* no separator */
2538 st->cp = sep; 2550 st->cp = sep;
2539 } else if (sep[0] == '\\') { 2551 } else if (sep[0] == '\\') {
2540 const char *xp = sep + 1; 2552 const char *xp = sep + 1;
2541 int base = 8; /* assume octal */ 2553 int base = 8; /* assume octal */
2542 2554
2543 switch (sep[1]) { 2555 switch (sep[1]) {
2544 case 'n': 2556 case 'n':
2545 st->sep = '\n'; 2557 st->sep = '\n';
2546 st->cp = sep + 2; 2558 st->cp = sep + 2;
2547 break; 2559 break;
2548 case 't': 2560 case 't':
2549 st->sep = '\t'; 2561 st->sep = '\t';
2550 st->cp = sep + 2; 2562 st->cp = sep + 2;
2551 break; 2563 break;
2552 case 'x': 2564 case 'x':
2553 base = 16; 2565 base = 16;
2554 xp++; 2566 xp++;
2555 goto get_numeric; 2567 goto get_numeric;
2556 case '0': 2568 case '0':
2557 base = 0; 2569 base = 0;
2558 goto get_numeric; 2570 goto get_numeric;
2559 default: 2571 default:
2560 if (!isdigit((unsigned char)sep[1])) 2572 if (!isdigit((unsigned char)sep[1]))
2561 return FALSE; /* ":ts<backslash><unrecognised>". */ 2573 return FALSE; /* ":ts<backslash><unrecognised>". */
2562 2574
2563 char *end; 2575 char *end;
2564 get_numeric: 2576 get_numeric:
2565 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); 2577 st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base);
2566 if (*end != ':' && *end != st->endc) 2578 if (*end != ':' && *end != st->endc)
2567 return FALSE; 2579 return FALSE;
2568 st->cp = end; 2580 st->cp = end;
2569 break; 2581 break;
2570 } 2582 }
2571 } else { 2583 } else {
2572 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ 2584 return FALSE; /* Found ":ts<unrecognised><unrecognised>". */
2573 } 2585 }
2574 2586
2575 st->termc = *st->cp; 2587 st->termc = *st->cp;
2576 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2588 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2577 ModifyWord_Copy, NULL); 2589 ModifyWord_Copy, NULL);
2578 return TRUE; 2590 return TRUE;
2579} 2591}
2580 2592
2581/* :tA, :tu, :tl, :ts<separator>, etc. */ 2593/* :tA, :tu, :tl, :ts<separator>, etc. */
2582static Boolean 2594static Boolean
2583ApplyModifier_To(const char *mod, ApplyModifiersState *st) 2595ApplyModifier_To(const char *mod, ApplyModifiersState *st)
2584{ 2596{
2585 st->cp = mod + 1; /* make sure it is set */ 2597 st->cp = mod + 1; /* make sure it is set */
2586 if (mod[1] == st->endc || mod[1] == ':') 2598 if (mod[1] == st->endc || mod[1] == ':')
2587 return FALSE; /* Found ":t<endc>" or ":t:". */ 2599 return FALSE; /* Found ":t<endc>" or ":t:". */
2588 2600
2589 if (mod[1] == 's') 2601 if (mod[1] == 's')
2590 return ApplyModifier_ToSep(mod + 2, st); 2602 return ApplyModifier_ToSep(mod + 2, st);
2591 2603
2592 if (mod[2] != st->endc && mod[2] != ':') 2604 if (mod[2] != st->endc && mod[2] != ':')
2593 return FALSE; /* Found ":t<unrecognised><unrecognised>". */ 2605 return FALSE; /* Found ":t<unrecognised><unrecognised>". */
2594 2606
2595 /* Check for two-character options: ":tu", ":tl" */ 2607 /* Check for two-character options: ":tu", ":tl" */
2596 if (mod[1] == 'A') { /* absolute path */ 2608 if (mod[1] == 'A') { /* absolute path */
2597 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 2609 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2598 ModifyWord_Realpath, NULL); 2610 ModifyWord_Realpath, NULL);
2599 st->cp = mod + 2; 2611 st->cp = mod + 2;
2600 st->termc = *st->cp; 2612 st->termc = *st->cp;
2601 } else if (mod[1] == 'u') { 2613 } else if (mod[1] == 'u') {
2602 char *dp = bmake_strdup(st->nstr); 2614 char *dp = bmake_strdup(st->nstr);
2603 for (st->newStr = dp; *dp; dp++) 2615 for (st->newStr = dp; *dp; dp++)
2604 *dp = toupper((unsigned char)*dp); 2616 *dp = toupper((unsigned char)*dp);
2605 st->cp = mod + 2; 2617 st->cp = mod + 2;
2606 st->termc = *st->cp; 2618 st->termc = *st->cp;
2607 } else if (mod[1] == 'l') { 2619 } else if (mod[1] == 'l') {
2608 char *dp = bmake_strdup(st->nstr); 2620 char *dp = bmake_strdup(st->nstr);
2609 for (st->newStr = dp; *dp; dp++) 2621 for (st->newStr = dp; *dp; dp++)
2610 *dp = tolower((unsigned char)*dp); 2622 *dp = tolower((unsigned char)*dp);
2611 st->cp = mod + 2; 2623 st->cp = mod + 2;
2612 st->termc = *st->cp; 2624 st->termc = *st->cp;
2613 } else if (mod[1] == 'W' || mod[1] == 'w') { 2625 } else if (mod[1] == 'W' || mod[1] == 'w') {
2614 st->oneBigWord = mod[1] == 'W'; 2626 st->oneBigWord = mod[1] == 'W';
2615 st->newStr = st->nstr; 2627 st->newStr = st->nstr;
2616 st->cp = mod + 2; 2628 st->cp = mod + 2;
2617 st->termc = *st->cp; 2629 st->termc = *st->cp;
2618 } else { 2630 } else {
2619 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2631 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2620 return FALSE; 2632 return FALSE;
2621 } 2633 }
2622 return TRUE; 2634 return TRUE;
2623} 2635}
2624 2636
2625/* :[#], :[1], etc. */ 2637/* :[#], :[1], etc. */
2626static int 2638static int
2627ApplyModifier_Words(const char *mod, ApplyModifiersState *st) 2639ApplyModifier_Words(const char *mod, ApplyModifiersState *st)
2628{ 2640{
2629 st->cp = mod + 1; /* point to char after '[' */ 2641 st->cp = mod + 1; /* point to char after '[' */
2630 char delim = ']'; /* look for closing ']' */ 2642 char delim = ']'; /* look for closing ']' */
2631 char *estr = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2643 char *estr = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2632 NULL, NULL, NULL); 2644 NULL, NULL, NULL);
2633 if (estr == NULL) { 2645 if (estr == NULL) {
2634 st->missing_delim = delim; 2646 st->missing_delim = delim;
2635 return 'c'; 2647 return 'c';
2636 } 2648 }
2637 2649
2638 /* now st->cp points just after the closing ']' */ 2650 /* now st->cp points just after the closing ']' */
2639 if (st->cp[0] != ':' && st->cp[0] != st->endc) 2651 if (st->cp[0] != ':' && st->cp[0] != st->endc)
2640 goto bad_modifier; /* Found junk after ']' */ 2652 goto bad_modifier; /* Found junk after ']' */
2641 2653
2642 if (estr[0] == '\0') 2654 if (estr[0] == '\0')
2643 goto bad_modifier; /* empty square brackets in ":[]". */ 2655 goto bad_modifier; /* empty square brackets in ":[]". */
2644 2656
2645 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ 2657 if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2646 if (st->oneBigWord) { 2658 if (st->oneBigWord) {
2647 st->newStr = bmake_strdup("1"); 2659 st->newStr = bmake_strdup("1");
2648 } else { 2660 } else {
2649 /* XXX: brk_string() is a rather expensive 2661 /* XXX: brk_string() is a rather expensive
2650 * way of counting words. */ 2662 * way of counting words. */
2651 char *as; 2663 char *as;
2652 int ac; 2664 int ac;
2653 char **av = brk_string(st->nstr, &ac, FALSE, &as); 2665 char **av = brk_string(st->nstr, &ac, FALSE, &as);
2654 free(as); 2666 free(as);
2655 free(av); 2667 free(av);
2656 2668
2657 Buffer buf; 2669 Buffer buf;
2658 Buf_Init(&buf, 4); /* 3 digits + '\0' */ 2670 Buf_Init(&buf, 4); /* 3 digits + '\0' */
2659 Buf_AddInt(&buf, ac); 2671 Buf_AddInt(&buf, ac);
2660 st->newStr = Buf_Destroy(&buf, FALSE); 2672 st->newStr = Buf_Destroy(&buf, FALSE);
2661 } 2673 }
2662 goto ok; 2674 goto ok;
2663 } 2675 }
2664 2676
2665 if (estr[0] == '*' && estr[1] == '\0') { 2677 if (estr[0] == '*' && estr[1] == '\0') {
2666 /* Found ":[*]" */ 2678 /* Found ":[*]" */
2667 st->oneBigWord = TRUE; 2679 st->oneBigWord = TRUE;
2668 st->newStr = st->nstr; 2680 st->newStr = st->nstr;
2669 goto ok; 2681 goto ok;
2670 } 2682 }
2671 2683
2672 if (estr[0] == '@' && estr[1] == '\0') { 2684 if (estr[0] == '@' && estr[1] == '\0') {
2673 /* Found ":[@]" */ 2685 /* Found ":[@]" */
2674 st->oneBigWord = FALSE; 2686 st->oneBigWord = FALSE;
2675 st->newStr = st->nstr; 2687 st->newStr = st->nstr;
2676 goto ok; 2688 goto ok;
2677 } 2689 }
2678 2690
2679 /* 2691 /*
2680 * We expect estr to contain a single integer for :[N], or two integers 2692 * We expect estr to contain a single integer for :[N], or two integers
2681 * separated by ".." for :[start..end]. 2693 * separated by ".." for :[start..end].
2682 */ 2694 */
2683 char *ep; 2695 char *ep;
2684 int first = strtol(estr, &ep, 0); 2696 int first = strtol(estr, &ep, 0);
2685 int last; 2697 int last;
2686 if (ep == estr) /* Found junk instead of a number */ 2698 if (ep == estr) /* Found junk instead of a number */
2687 goto bad_modifier; 2699 goto bad_modifier;
2688 2700
2689 if (ep[0] == '\0') { /* Found only one integer in :[N] */ 2701 if (ep[0] == '\0') { /* Found only one integer in :[N] */
2690 last = first; 2702 last = first;
2691 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2703 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2692 /* Expecting another integer after ".." */ 2704 /* Expecting another integer after ".." */
2693 ep += 2; 2705 ep += 2;
2694 last = strtol(ep, &ep, 0); 2706 last = strtol(ep, &ep, 0);
2695 if (ep[0] != '\0') /* Found junk after ".." */ 2707 if (ep[0] != '\0') /* Found junk after ".." */
2696 goto bad_modifier; 2708 goto bad_modifier;
2697 } else 2709 } else
2698 goto bad_modifier; /* Found junk instead of ".." */ 2710 goto bad_modifier; /* Found junk instead of ".." */
2699 2711
2700 /* 2712 /*
2701 * Now seldata is properly filled in, but we still have to check for 0 as 2713 * Now seldata is properly filled in, but we still have to check for 0 as
2702 * a special case. 2714 * a special case.
2703 */ 2715 */
2704 if (first == 0 && last == 0) { 2716 if (first == 0 && last == 0) {
2705 /* ":[0]" or perhaps ":[0..0]" */ 2717 /* ":[0]" or perhaps ":[0..0]" */
2706 st->oneBigWord = TRUE; 2718 st->oneBigWord = TRUE;
2707 st->newStr = st->nstr; 2719 st->newStr = st->nstr;
2708 goto ok; 2720 goto ok;
2709 } 2721 }
2710 2722
2711 /* ":[0..N]" or ":[N..0]" */ 2723 /* ":[0..N]" or ":[N..0]" */
2712 if (first == 0 || last == 0) 2724 if (first == 0 || last == 0)
2713 goto bad_modifier; 2725 goto bad_modifier;
2714 2726
2715 /* Normal case: select the words described by seldata. */ 2727 /* Normal case: select the words described by seldata. */
2716 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); 2728 st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last);
2717 2729
2718ok: 2730ok:
2719 st->termc = *st->cp; 2731 st->termc = *st->cp;
2720 free(estr); 2732 free(estr);
2721 return 0; 2733 return 0;
2722 2734
2723bad_modifier: 2735bad_modifier:
2724 free(estr); 2736 free(estr);
2725 return 'b'; 2737 return 'b';
2726} 2738}
2727 2739
2728/* :O or :Ox */ 2740/* :O or :Ox */
2729static Boolean 2741static Boolean
2730ApplyModifier_Order(const char *mod, ApplyModifiersState *st) 2742ApplyModifier_Order(const char *mod, ApplyModifiersState *st)
2731{ 2743{
2732 char otype; 2744 char otype;
2733 2745
2734 st->cp = mod + 1; /* skip to the rest in any case */ 2746 st->cp = mod + 1; /* skip to the rest in any case */
2735 if (mod[1] == st->endc || mod[1] == ':') { 2747 if (mod[1] == st->endc || mod[1] == ':') {
2736 otype = 's'; 2748 otype = 's';
2737 st->termc = *st->cp; 2749 st->termc = *st->cp;
2738 } else if ((mod[1] == 'r' || mod[1] == 'x') && 2750 } else if ((mod[1] == 'r' || mod[1] == 'x') &&
2739 (mod[2] == st->endc || mod[2] == ':')) { 2751 (mod[2] == st->endc || mod[2] == ':')) {
2740 otype = mod[1]; 2752 otype = mod[1];
2741 st->cp = mod + 2; 2753 st->cp = mod + 2;
2742 st->termc = *st->cp; 2754 st->termc = *st->cp;
2743 } else { 2755 } else {
2744 return FALSE; 2756 return FALSE;
2745 } 2757 }
2746 st->newStr = VarOrder(st->nstr, otype); 2758 st->newStr = VarOrder(st->nstr, otype);
2747 return TRUE; 2759 return TRUE;
2748} 2760}
2749 2761
2750/* :? then : else */ 2762/* :? then : else */
2751static Boolean 2763static Boolean
2752ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) 2764ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st)
2753{ 2765{
2754 Boolean value = FALSE; 2766 Boolean value = FALSE;
2755 int cond_rc = 0; 2767 int cond_rc = 0;
2756 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; 2768 VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES;
2757 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; 2769 VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES;
2758 2770
2759 if (st->eflags & VARE_WANTRES) { 2771 if (st->eflags & VARE_WANTRES) {
2760 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); 2772 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
2761 if (cond_rc != COND_INVALID && value) 2773 if (cond_rc != COND_INVALID && value)
2762 then_eflags |= VARE_WANTRES; 2774 then_eflags |= VARE_WANTRES;
2763 if (cond_rc != COND_INVALID && !value) 2775 if (cond_rc != COND_INVALID && !value)
2764 else_eflags |= VARE_WANTRES; 2776 else_eflags |= VARE_WANTRES;
2765 } 2777 }
2766 2778
2767 st->cp = mod + 1; 2779 st->cp = mod + 1;
2768 char delim = ':'; 2780 char delim = ':';
2769 char *then_expr = ParseModifierPart( 2781 char *then_expr = ParseModifierPart(
2770 st->ctxt, &st->cp, delim, then_eflags, NULL, NULL, NULL); 2782 st->ctxt, &st->cp, delim, then_eflags, NULL, NULL, NULL);
2771 if (then_expr == NULL) { 2783 if (then_expr == NULL) {
2772 st->missing_delim = delim; 2784 st->missing_delim = delim;
2773 return FALSE; 2785 return FALSE;
2774 } 2786 }
2775 2787
2776 delim = st->endc; /* BRCLOSE or PRCLOSE */ 2788 delim = st->endc; /* BRCLOSE or PRCLOSE */
2777 char *else_expr = ParseModifierPart( 2789 char *else_expr = ParseModifierPart(
2778 st->ctxt, &st->cp, delim, else_eflags, NULL, NULL, NULL); 2790 st->ctxt, &st->cp, delim, else_eflags, NULL, NULL, NULL);
2779 if (else_expr == NULL) { 2791 if (else_expr == NULL) {
2780 st->missing_delim = delim; 2792 st->missing_delim = delim;
2781 return FALSE; 2793 return FALSE;
2782 } 2794 }
2783 2795
2784 st->termc = *--st->cp; 2796 st->termc = *--st->cp;
2785 if (cond_rc == COND_INVALID) { 2797 if (cond_rc == COND_INVALID) {
2786 Error("Bad conditional expression `%s' in %s?%s:%s", 2798 Error("Bad conditional expression `%s' in %s?%s:%s",
2787 st->v->name, st->v->name, then_expr, else_expr); 2799 st->v->name, st->v->name, then_expr, else_expr);
2788 return FALSE; 2800 return FALSE;
2789 } 2801 }
2790 2802
2791 if (value) { 2803 if (value) {
2792 st->newStr = then_expr; 2804 st->newStr = then_expr;
2793 free(else_expr); 2805 free(else_expr);
2794 } else { 2806 } else {
2795 st->newStr = else_expr; 2807 st->newStr = else_expr;
2796 free(then_expr); 2808 free(then_expr);
2797 } 2809 }
2798 if (st->v->flags & VAR_JUNK) 2810 if (st->v->flags & VAR_JUNK)
2799 st->v->flags |= VAR_KEEP; 2811 st->v->flags |= VAR_KEEP;
2800 return TRUE; 2812 return TRUE;
2801} 2813}
2802 2814
2803/* 2815/*
2804 * The ::= modifiers actually assign a value to the variable. 2816 * The ::= modifiers actually assign a value to the variable.
2805 * Their main purpose is in supporting modifiers of .for loop 2817 * Their main purpose is in supporting modifiers of .for loop
2806 * iterators and other obscure uses. They always expand to 2818 * iterators and other obscure uses. They always expand to
2807 * nothing. In a target rule that would otherwise expand to an 2819 * nothing. In a target rule that would otherwise expand to an
2808 * empty line they can be preceded with @: to keep make happy. 2820 * empty line they can be preceded with @: to keep make happy.
2809 * Eg. 2821 * Eg.
2810 * 2822 *
2811 * foo: .USE 2823 * foo: .USE
2812 * .for i in ${.TARGET} ${.TARGET:R}.gz 2824 * .for i in ${.TARGET} ${.TARGET:R}.gz
2813 * @: ${t::=$i} 2825 * @: ${t::=$i}
2814 * @echo blah ${t:T} 2826 * @echo blah ${t:T}
2815 * .endfor 2827 * .endfor
2816 * 2828 *
2817 * ::=<str> Assigns <str> as the new value of variable. 2829 * ::=<str> Assigns <str> as the new value of variable.
2818 * ::?=<str> Assigns <str> as value of variable if 2830 * ::?=<str> Assigns <str> as value of variable if
2819 * it was not already set. 2831 * it was not already set.
2820 * ::+=<str> Appends <str> to variable. 2832 * ::+=<str> Appends <str> to variable.
2821 * ::!=<cmd> Assigns output of <cmd> as the new value of 2833 * ::!=<cmd> Assigns output of <cmd> as the new value of
2822 * variable. 2834 * variable.
2823 */ 2835 */
2824static int 2836static int
2825ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) 2837ApplyModifier_Assign(const char *mod, ApplyModifiersState *st)
2826{ 2838{
2827 const char *op = mod + 1; 2839 const char *op = mod + 1;
2828 if (!(op[0] == '=' || 2840 if (!(op[0] == '=' ||
2829 (op[1] == '=' && 2841 (op[1] == '=' &&
2830 (op[0] == '!' || op[0] == '+' || op[0] == '?')))) 2842 (op[0] == '!' || op[0] == '+' || op[0] == '?'))))
2831 return 'd'; /* "::<unrecognised>" */ 2843 return 'd'; /* "::<unrecognised>" */
2832 2844
2833 GNode *v_ctxt; /* context where v belongs */ 2845 GNode *v_ctxt; /* context where v belongs */
2834 2846
2835 if (st->v->name[0] == 0) 2847 if (st->v->name[0] == 0)
2836 return 'b'; 2848 return 'b';
2837 2849
2838 v_ctxt = st->ctxt; 2850 v_ctxt = st->ctxt;
2839 char *sv_name = NULL; 2851 char *sv_name = NULL;
2840 if (st->v->flags & VAR_JUNK) { 2852 if (st->v->flags & VAR_JUNK) {
2841 /* 2853 /*
2842 * We need to bmake_strdup() it incase ParseModifierPart() recurses. 2854 * We need to bmake_strdup() it incase ParseModifierPart() recurses.
2843 */ 2855 */
2844 sv_name = st->v->name; 2856 sv_name = st->v->name;
2845 st->v->name = bmake_strdup(st->v->name); 2857 st->v->name = bmake_strdup(st->v->name);
2846 } else if (st->ctxt != VAR_GLOBAL) { 2858 } else if (st->ctxt != VAR_GLOBAL) {
2847 Var *gv = VarFind(st->v->name, st->ctxt, 0); 2859 Var *gv = VarFind(st->v->name, st->ctxt, 0);
2848 if (gv == NULL) 2860 if (gv == NULL)
2849 v_ctxt = VAR_GLOBAL; 2861 v_ctxt = VAR_GLOBAL;
2850 else 2862 else
2851 VarFreeEnv(gv, TRUE); 2863 VarFreeEnv(gv, TRUE);
2852 } 2864 }
2853 2865
2854 switch (op[0]) { 2866 switch (op[0]) {
2855 case '+': 2867 case '+':
2856 case '?': 2868 case '?':
2857 case '!': 2869 case '!':
2858 st->cp = mod + 3; 2870 st->cp = mod + 3;
2859 break; 2871 break;
2860 default: 2872 default:
2861 st->cp = mod + 2; 2873 st->cp = mod + 2;
2862 break; 2874 break;
2863 } 2875 }
2864 2876
2865 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; 2877 char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
2866 VarEvalFlags eflags = (st->eflags & VARE_WANTRES) ? 0 : VARE_NOSUBST; 2878 VarEvalFlags eflags = (st->eflags & VARE_WANTRES) ? 0 : VARE_NOSUBST;
2867 char *val = ParseModifierPart(st->ctxt, &st->cp, delim, 2879 char *val = ParseModifierPart(st->ctxt, &st->cp, delim,
2868 st->eflags | eflags, NULL, NULL, NULL); 2880 st->eflags | eflags, NULL, NULL, NULL);
2869 if (st->v->flags & VAR_JUNK) { 2881 if (st->v->flags & VAR_JUNK) {
2870 /* restore original name */ 2882 /* restore original name */
2871 free(st->v->name); 2883 free(st->v->name);
2872 st->v->name = sv_name; 2884 st->v->name = sv_name;
2873 } 2885 }
2874 if (val == NULL) { 2886 if (val == NULL) {
2875 st->missing_delim = delim; 2887 st->missing_delim = delim;
2876 return 'c'; 2888 return 'c';
2877 } 2889 }
2878 2890
2879 st->termc = *--st->cp; 2891 st->termc = *--st->cp;
2880 2892
2881 if (st->eflags & VARE_WANTRES) { 2893 if (st->eflags & VARE_WANTRES) {
2882 switch (op[0]) { 2894 switch (op[0]) {
2883 case '+': 2895 case '+':
2884 Var_Append(st->v->name, val, v_ctxt); 2896 Var_Append(st->v->name, val, v_ctxt);
2885 break; 2897 break;
2886 case '!': { 2898 case '!': {
2887 const char *emsg; 2899 const char *emsg;
2888 st->newStr = Cmd_Exec(val, &emsg); 2900 st->newStr = Cmd_Exec(val, &emsg);
2889 if (emsg) 2901 if (emsg)
2890 Error(emsg, st->nstr); 2902 Error(emsg, st->nstr);
2891 else 2903 else
2892 Var_Set(st->v->name, st->newStr, v_ctxt); 2904 Var_Set(st->v->name, st->newStr, v_ctxt);
2893 free(st->newStr); 2905 free(st->newStr);
2894 break; 2906 break;
2895 } 2907 }
2896 case '?': 2908 case '?':
2897 if ((st->v->flags & VAR_JUNK) == 0) 2909 if ((st->v->flags & VAR_JUNK) == 0)
2898 break; 2910 break;
2899 /* FALLTHROUGH */ 2911 /* FALLTHROUGH */
2900 default: 2912 default:
2901 Var_Set(st->v->name, val, v_ctxt); 2913 Var_Set(st->v->name, val, v_ctxt);
2902 break; 2914 break;
2903 } 2915 }
2904 } 2916 }
2905 free(val); 2917 free(val);
2906 st->newStr = varNoError; 2918 st->newStr = varNoError;
2907 return 0; 2919 return 0;
2908} 2920}
2909 2921
2910/* remember current value */ 2922/* remember current value */
2911static Boolean 2923static Boolean
2912ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) 2924ApplyModifier_Remember(const char *mod, ApplyModifiersState *st)
2913{ 2925{
2914 st->cp = mod + 1; /* make sure it is set */ 2926 st->cp = mod + 1; /* make sure it is set */
2915 if (!STRMOD_MATCHX(mod, "_", 1)) 2927 if (!STRMOD_MATCHX(mod, "_", 1))
2916 return FALSE; 2928 return FALSE;
2917 2929
2918 if (mod[1] == '=') { 2930 if (mod[1] == '=') {
2919 char *np; 2931 char *np;
2920 int n; 2932 int n;
2921 2933
2922 st->cp++; 2934 st->cp++;
2923 n = strcspn(st->cp, ":)}"); 2935 n = strcspn(st->cp, ":)}");
2924 np = bmake_strndup(st->cp, n + 1); 2936 np = bmake_strndup(st->cp, n + 1);
2925 np[n] = '\0'; 2937 np[n] = '\0';
2926 st->cp = mod + 2 + n; 2938 st->cp = mod + 2 + n;
2927 Var_Set(np, st->nstr, st->ctxt); 2939 Var_Set(np, st->nstr, st->ctxt);
2928 free(np); 2940 free(np);
2929 } else { 2941 } else {
2930 Var_Set("_", st->nstr, st->ctxt); 2942 Var_Set("_", st->nstr, st->ctxt);
2931 } 2943 }
2932 st->newStr = st->nstr; 2944 st->newStr = st->nstr;
2933 st->termc = *st->cp; 2945 st->termc = *st->cp;
2934 return TRUE; 2946 return TRUE;
2935} 2947}
2936 2948
2937#ifdef SYSVVARSUB 2949#ifdef SYSVVARSUB
2938/* :from=to */ 2950/* :from=to */
2939static int 2951static int
2940ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) 2952ApplyModifier_SysV(const char *mod, ApplyModifiersState *st)
2941{ 2953{
2942 Boolean eqFound = FALSE; 2954 Boolean eqFound = FALSE;
2943 2955
2944 /* 2956 /*
2945 * First we make a pass through the string trying 2957 * First we make a pass through the string trying
2946 * to verify it is a SYSV-make-style translation: 2958 * to verify it is a SYSV-make-style translation:
2947 * it must be: <string1>=<string2>) 2959 * it must be: <string1>=<string2>)
2948 */ 2960 */
2949 st->cp = mod; 2961 st->cp = mod;
2950 int nest = 1; 2962 int nest = 1;
2951 while (*st->cp != '\0' && nest > 0) { 2963 while (*st->cp != '\0' && nest > 0) {
2952 if (*st->cp == '=') { 2964 if (*st->cp == '=') {
2953 eqFound = TRUE; 2965 eqFound = TRUE;
2954 /* continue looking for st->endc */ 2966 /* continue looking for st->endc */
2955 } else if (*st->cp == st->endc) 2967 } else if (*st->cp == st->endc)
2956 nest--; 2968 nest--;
2957 else if (*st->cp == st->startc) 2969 else if (*st->cp == st->startc)
2958 nest++; 2970 nest++;
2959 if (nest > 0) 2971 if (nest > 0)
2960 st->cp++; 2972 st->cp++;
2961 } 2973 }
2962 if (*st->cp != st->endc || !eqFound) 2974 if (*st->cp != st->endc || !eqFound)
2963 return 0; 2975 return 0;
2964 2976
2965 char delim = '='; 2977 char delim = '=';
2966 st->cp = mod; 2978 st->cp = mod;
2967 char *lhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2979 char *lhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2968 NULL, NULL, NULL); 2980 NULL, NULL, NULL);
2969 if (lhs == NULL) { 2981 if (lhs == NULL) {
2970 st->missing_delim = delim; 2982 st->missing_delim = delim;
2971 return 'c'; 2983 return 'c';
2972 } 2984 }
2973 2985
2974 delim = st->endc; 2986 delim = st->endc;
2975 char *rhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags, 2987 char *rhs = ParseModifierPart(st->ctxt, &st->cp, delim, st->eflags,
2976 NULL, NULL, NULL); 2988 NULL, NULL, NULL);
2977 if (rhs == NULL) { 2989 if (rhs == NULL) {
2978 st->missing_delim = delim; 2990 st->missing_delim = delim;
2979 return 'c'; 2991 return 'c';
2980 } 2992 }
2981 2993
2982 /* 2994 /*
2983 * SYSV modifications happen through the whole 2995 * SYSV modifications happen through the whole
2984 * string. Note the pattern is anchored at the end. 2996 * string. Note the pattern is anchored at the end.
2985 */ 2997 */
2986 st->termc = *--st->cp; 2998 st->termc = *--st->cp;
2987 if (lhs[0] == '\0' && *st->nstr == '\0') { 2999 if (lhs[0] == '\0' && *st->nstr == '\0') {
2988 st->newStr = st->nstr; /* special case */ 3000 st->newStr = st->nstr; /* special case */
2989 } else { 3001 } else {
2990 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; 3002 ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
2991 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, 3003 st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr,
2992 ModifyWord_SYSVSubst, &args); 3004 ModifyWord_SYSVSubst, &args);
2993 } 3005 }
2994 free(lhs); 3006 free(lhs);
2995 free(rhs); 3007 free(rhs);
2996 return '='; 3008 return '=';
2997} 3009}
2998#endif 3010#endif
2999 3011
3000/* 3012/*
3001 * Now we need to apply any modifiers the user wants applied. 3013 * Now we need to apply any modifiers the user wants applied.
3002 * These are: 3014 * These are:
3003 * :M<pattern> words which match the given <pattern>. 3015 * :M<pattern> words which match the given <pattern>.
3004 * <pattern> is of the standard file 3016 * <pattern> is of the standard file
3005 * wildcarding form. 3017 * wildcarding form.
3006 * :N<pattern> words which do not match the given <pattern>. 3018 * :N<pattern> words which do not match the given <pattern>.
3007 * :S<d><pat1><d><pat2><d>[1gW] 3019 * :S<d><pat1><d><pat2><d>[1gW]
3008 * Substitute <pat2> for <pat1> in the value 3020 * Substitute <pat2> for <pat1> in the value
3009 * :C<d><pat1><d><pat2><d>[1gW] 3021 * :C<d><pat1><d><pat2><d>[1gW]
3010 * Substitute <pat2> for regex <pat1> in the value 3022 * Substitute <pat2> for regex <pat1> in the value
3011 * :H Substitute the head of each word 3023 * :H Substitute the head of each word
3012 * :T Substitute the tail of each word 3024 * :T Substitute the tail of each word
3013 * :E Substitute the extension (minus '.') of 3025 * :E Substitute the extension (minus '.') of
3014 * each word 3026 * each word
3015 * :R Substitute the root of each word 3027 * :R Substitute the root of each word
3016 * (pathname minus the suffix). 3028 * (pathname minus the suffix).
3017 * :O ("Order") Alphabeticaly sort words in variable. 3029 * :O ("Order") Alphabeticaly sort words in variable.
3018 * :Ox ("intermiX") Randomize words in variable. 3030 * :Ox ("intermiX") Randomize words in variable.
3019 * :u ("uniq") Remove adjacent duplicate words. 3031 * :u ("uniq") Remove adjacent duplicate words.
3020 * :tu Converts the variable contents to uppercase. 3032 * :tu Converts the variable contents to uppercase.
3021 * :tl Converts the variable contents to lowercase. 3033 * :tl Converts the variable contents to lowercase.
3022 * :ts[c] Sets varSpace - the char used to 3034 * :ts[c] Sets varSpace - the char used to
3023 * separate words to 'c'. If 'c' is 3035 * separate words to 'c'. If 'c' is
3024 * omitted then no separation is used. 3036 * omitted then no separation is used.
3025 * :tW Treat the variable contents as a single 3037 * :tW Treat the variable contents as a single
3026 * word, even if it contains spaces. 3038 * word, even if it contains spaces.
3027 * (Mnemonic: one big 'W'ord.) 3039 * (Mnemonic: one big 'W'ord.)
3028 * :tw Treat the variable contents as multiple 3040 * :tw Treat the variable contents as multiple
3029 * space-separated words. 3041 * space-separated words.
3030 * (Mnemonic: many small 'w'ords.) 3042 * (Mnemonic: many small 'w'ords.)
3031 * :[index] Select a single word from the value. 3043 * :[index] Select a single word from the value.
3032 * :[start..end] Select multiple words from the value. 3044 * :[start..end] Select multiple words from the value.
3033 * :[*] or :[0] Select the entire value, as a single 3045 * :[*] or :[0] Select the entire value, as a single
3034 * word. Equivalent to :tW. 3046 * word. Equivalent to :tW.
3035 * :[@] Select the entire value, as multiple 3047 * :[@] Select the entire value, as multiple
3036 * words. Undoes the effect of :[*]. 3048 * words. Undoes the effect of :[*].
3037 * Equivalent to :tw. 3049 * Equivalent to :tw.
3038 * :[#] Returns the number of words in the value. 3050 * :[#] Returns the number of words in the value.
3039 * 3051 *
3040 * :?<true-value>:<false-value> 3052 * :?<true-value>:<false-value>
3041 * If the variable evaluates to true, return 3053 * If the variable evaluates to true, return
3042 * true value, else return the second value. 3054 * true value, else return the second value.
3043 * :lhs=rhs Like :S, but the rhs goes to the end of 3055 * :lhs=rhs Like :S, but the rhs goes to the end of
3044 * the invocation. 3056 * the invocation.
3045 * :sh Treat the current value as a command 3057 * :sh Treat the current value as a command
3046 * to be run, new value is its output. 3058 * to be run, new value is its output.
3047 * The following added so we can handle ODE makefiles. 3059 * The following added so we can handle ODE makefiles.
3048 * :@<tmpvar>@<newval>@ 3060 * :@<tmpvar>@<newval>@
3049 * Assign a temporary local variable <tmpvar> 3061 * Assign a temporary local variable <tmpvar>
3050 * to the current value of each word in turn 3062 * to the current value of each word in turn
3051 * and replace each word with the result of 3063 * and replace each word with the result of
3052 * evaluating <newval> 3064 * evaluating <newval>
3053 * :D<newval> Use <newval> as value if variable defined 3065 * :D<newval> Use <newval> as value if variable defined
3054 * :U<newval> Use <newval> as value if variable undefined 3066 * :U<newval> Use <newval> as value if variable undefined
3055 * :L Use the name of the variable as the value. 3067 * :L Use the name of the variable as the value.
3056 * :P Use the path of the node that has the same 3068 * :P Use the path of the node that has the same
3057 * name as the variable as the value. This 3069 * name as the variable as the value. This
3058 * basically includes an implied :L so that 3070 * basically includes an implied :L so that
3059 * the common method of refering to the path 3071 * the common method of refering to the path
3060 * of your dependent 'x' in a rule is to use 3072 * of your dependent 'x' in a rule is to use
3061 * the form '${x:P}'. 3073 * the form '${x:P}'.
3062 * :!<cmd>! Run cmd much the same as :sh run's the 3074 * :!<cmd>! Run cmd much the same as :sh run's the
3063 * current value of the variable. 3075 * current value of the variable.
3064 * Assignment operators (see ApplyModifier_Assign). 3076 * Assignment operators (see ApplyModifier_Assign).
3065 */ 3077 */
3066static char * 3078static char *
3067ApplyModifiers(char *nstr, const char *tstr, 3079ApplyModifiers(char *nstr, const char *tstr,
3068 int const startc, int const endc, 3080 int const startc, int const endc,
3069 Var * const v, GNode * const ctxt, VarEvalFlags const eflags, 3081 Var * const v, GNode * const ctxt, VarEvalFlags const eflags,
3070 int * const lengthPtr, void ** const freePtr) 3082 int * const lengthPtr, void ** const freePtr)
3071{ 3083{
3072 ApplyModifiersState st = { 3084 ApplyModifiersState st = {
3073 startc, endc, v, ctxt, eflags, lengthPtr, freePtr, 3085 startc, endc, v, ctxt, eflags, lengthPtr, freePtr,
3074 nstr, tstr, tstr, 3086 nstr, tstr, tstr,
3075 '\0', '\0', 0, ' ', FALSE, NULL 3087 '\0', '\0', 0, ' ', FALSE, NULL
3076 }; 3088 };
3077 3089
3078 const char *p = tstr; 3090 const char *p = tstr;
3079 while (*p != '\0' && *p != endc) { 3091 while (*p != '\0' && *p != endc) {
3080 3092
3081 if (*p == '$') { 3093 if (*p == '$') {
3082 /* 3094 /*
3083 * We may have some complex modifiers in a variable. 3095 * We may have some complex modifiers in a variable.
3084 */ 3096 */
3085 void *freeIt; 3097 void *freeIt;
3086 char *rval; 3098 char *rval;
3087 int rlen; 3099 int rlen;
3088 int c; 3100 int c;
3089 3101
3090 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt); 3102 rval = Var_Parse(p, st.ctxt, st.eflags, &rlen, &freeIt);
3091 3103
3092 /* 3104 /*
3093 * If we have not parsed up to st.endc or ':', 3105 * If we have not parsed up to st.endc or ':',
3094 * we are not interested. 3106 * we are not interested.
3095 */ 3107 */
3096 if (rval != NULL && *rval && 3108 if (rval != NULL && *rval &&
3097 (c = p[rlen]) != '\0' && 3109 (c = p[rlen]) != '\0' &&
3098 c != ':' && 3110 c != ':' &&
3099 c != st.endc) { 3111 c != st.endc) {
3100 free(freeIt); 3112 free(freeIt);
3101 goto apply_mods; 3113 goto apply_mods;
3102 } 3114 }
3103 3115
3104 if (DEBUG(VAR)) { 3116 if (DEBUG(VAR)) {
3105 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", 3117 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3106 rval, rlen, p, rlen, p + rlen); 3118 rval, rlen, p, rlen, p + rlen);
3107 } 3119 }
3108 3120
3109 p += rlen; 3121 p += rlen;
3110 3122
3111 if (rval != NULL && *rval) { 3123 if (rval != NULL && *rval) {
3112 int used; 3124 int used;
3113 3125
3114 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v, 3126 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3115 st.ctxt, st.eflags, &used, st.freePtr); 3127 st.ctxt, st.eflags, &used, st.freePtr);
3116 if (st.nstr == var_Error 3128 if (st.nstr == var_Error
3117 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0) 3129 || (st.nstr == varNoError && (st.eflags & VARE_UNDEFERR) == 0)
3118 || strlen(rval) != (size_t) used) { 3130 || strlen(rval) != (size_t) used) {
3119 free(freeIt); 3131 free(freeIt);
3120 goto out; /* error already reported */ 3132 goto out; /* error already reported */
3121 } 3133 }
3122 } 3134 }
3123 free(freeIt); 3135 free(freeIt);
3124 if (*p == ':') 3136 if (*p == ':')
3125 p++; 3137 p++;
3126 else if (*p == '\0' && endc != '\0') { 3138 else if (*p == '\0' && endc != '\0') {
3127 Error("Unclosed variable specification after complex " 3139 Error("Unclosed variable specification after complex "
3128 "modifier (expecting '%c') for %s", st.endc, st.v->name); 3140 "modifier (expecting '%c') for %s", st.endc, st.v->name);
3129 goto out; 3141 goto out;
3130 } 3142 }
3131 continue; 3143 continue;
3132 } 3144 }
3133 apply_mods: 3145 apply_mods:
3134 if (DEBUG(VAR)) { 3146 if (DEBUG(VAR)) {
3135 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, 3147 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3136 *p, st.nstr); 3148 *p, st.nstr);
3137 } 3149 }
3138 st.newStr = var_Error; 3150 st.newStr = var_Error;
3139 switch ((st.modifier = *p)) { 3151 switch ((st.modifier = *p)) {
3140 case ':': 3152 case ':':
3141 { 3153 {
3142 int res = ApplyModifier_Assign(p, &st); 3154 int res = ApplyModifier_Assign(p, &st);
3143 if (res == 'b') 3155 if (res == 'b')
3144 goto bad_modifier; 3156 goto bad_modifier;
3145 if (res == 'c') 3157 if (res == 'c')
3146 goto cleanup; 3158 goto cleanup;
3147 if (res == 'd') 3159 if (res == 'd')
3148 goto default_case; 3160 goto default_case;
3149 break; 3161 break;
3150 } 3162 }
3151 case '@': 3163 case '@':
3152 if (!ApplyModifier_Loop(p, &st)) 3164 if (!ApplyModifier_Loop(p, &st))
3153 goto cleanup; 3165 goto cleanup;
3154 break; 3166 break;
3155 case '_': 3167 case '_':
3156 if (!ApplyModifier_Remember(p, &st)) 3168 if (!ApplyModifier_Remember(p, &st))
3157 goto default_case; 3169 goto default_case;
3158 break; 3170 break;
3159 case 'D': 3171 case 'D':
3160 case 'U': 3172 case 'U':
3161 ApplyModifier_Defined(p, &st); 3173 ApplyModifier_Defined(p, &st);
3162 break; 3174 break;
3163 case 'L': 3175 case 'L':
3164 { 3176 {
3165 if ((st.v->flags & VAR_JUNK) != 0) 3177 if ((st.v->flags & VAR_JUNK) != 0)
3166 st.v->flags |= VAR_KEEP; 3178 st.v->flags |= VAR_KEEP;
3167 st.newStr = bmake_strdup(st.v->name); 3179 st.newStr = bmake_strdup(st.v->name);
3168 st.cp = p + 1; 3180 st.cp = p + 1;
3169 st.termc = *st.cp; 3181 st.termc = *st.cp;
3170 break; 3182 break;
3171 } 3183 }
3172 case 'P': 3184 case 'P':
3173 ApplyModifier_Path(p, &st); 3185 ApplyModifier_Path(p, &st);
3174 break; 3186 break;
3175 case '!': 3187 case '!':
3176 if (!ApplyModifier_Exclam(p, &st)) 3188 if (!ApplyModifier_Exclam(p, &st))
3177 goto cleanup; 3189 goto cleanup;
3178 break; 3190 break;
3179 case '[': 3191 case '[':
3180 { 3192 {
3181 int res = ApplyModifier_Words(p, &st); 3193 int res = ApplyModifier_Words(p, &st);
3182 if (res == 'b') 3194 if (res == 'b')
3183 goto bad_modifier; 3195 goto bad_modifier;
3184 if (res == 'c') 3196 if (res == 'c')
3185 goto cleanup; 3197 goto cleanup;
3186 break; 3198 break;
3187 } 3199 }
3188 case 'g': 3200 case 'g':
3189 if (!ApplyModifier_Gmtime(p, &st)) 3201 if (!ApplyModifier_Gmtime(p, &st))
3190 goto default_case; 3202 goto default_case;
3191 break; 3203 break;
3192 case 'h': 3204 case 'h':
3193 if (!ApplyModifier_Hash(p, &st)) 3205 if (!ApplyModifier_Hash(p, &st))
3194 goto default_case; 3206 goto default_case;
3195 break; 3207 break;
3196 case 'l': 3208 case 'l':
3197 if (!ApplyModifier_Localtime(p, &st)) 3209 if (!ApplyModifier_Localtime(p, &st))
3198 goto default_case; 3210 goto default_case;
3199 break; 3211 break;
3200 case 't': 3212 case 't':
3201 if (!ApplyModifier_To(p, &st)) 3213 if (!ApplyModifier_To(p, &st))
3202 goto bad_modifier; 3214 goto bad_modifier;
3203 break; 3215 break;
3204 case 'N': 3216 case 'N':
3205 case 'M': 3217 case 'M':
3206 ApplyModifier_Match(p, &st); 3218 ApplyModifier_Match(p, &st);
3207 break; 3219 break;
3208 case 'S': 3220 case 'S':
3209 if (!ApplyModifier_Subst(p, &st)) 3221 if (!ApplyModifier_Subst(p, &st))
3210 goto cleanup; 3222 goto cleanup;
3211 break; 3223 break;
3212 case '?': 3224 case '?':
3213 if (!ApplyModifier_IfElse(p, &st)) 3225 if (!ApplyModifier_IfElse(p, &st))
3214 goto cleanup; 3226 goto cleanup;
3215 break; 3227 break;
3216#ifndef NO_REGEX 3228#ifndef NO_REGEX
3217 case 'C': 3229 case 'C':
3218 if (!ApplyModifier_Regex(p, &st)) 3230 if (!ApplyModifier_Regex(p, &st))
3219 goto cleanup; 3231 goto cleanup;
3220 break; 3232 break;
3221#endif 3233#endif
3222 case 'q': 3234 case 'q':
3223 case 'Q': 3235 case 'Q':
3224 if (p[1] == st.endc || p[1] == ':') { 3236 if (p[1] == st.endc || p[1] == ':') {
3225 st.newStr = VarQuote(st.nstr, st.modifier == 'q'); 3237 st.newStr = VarQuote(st.nstr, st.modifier == 'q');
3226 st.cp = p + 1; 3238 st.cp = p + 1;
3227 st.termc = *st.cp; 3239 st.termc = *st.cp;
3228 break; 3240 break;
3229 } 3241 }
3230 goto default_case; 3242 goto default_case;
3231 case 'T': 3243 case 'T':
3232 if (p[1] == st.endc || p[1] == ':') { 3244 if (p[1] == st.endc || p[1] == ':') {
3233 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3245 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3234 st.nstr, ModifyWord_Tail, NULL); 3246 st.nstr, ModifyWord_Tail, NULL);
3235 st.cp = p + 1; 3247 st.cp = p + 1;
3236 st.termc = *st.cp; 3248 st.termc = *st.cp;
3237 break; 3249 break;
3238 } 3250 }
3239 goto default_case; 3251 goto default_case;
3240 case 'H': 3252 case 'H':
3241 if (p[1] == st.endc || p[1] == ':') { 3253 if (p[1] == st.endc || p[1] == ':') {
3242 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3254 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3243 st.nstr, ModifyWord_Head, NULL); 3255 st.nstr, ModifyWord_Head, NULL);
3244 st.cp = p + 1; 3256 st.cp = p + 1;
3245 st.termc = *st.cp; 3257 st.termc = *st.cp;
3246 break; 3258 break;
3247 } 3259 }
3248 goto default_case; 3260 goto default_case;
3249 case 'E': 3261 case 'E':
3250 if (p[1] == st.endc || p[1] == ':') { 3262 if (p[1] == st.endc || p[1] == ':') {
3251 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3263 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3252 st.nstr, ModifyWord_Suffix, NULL); 3264 st.nstr, ModifyWord_Suffix, NULL);
3253 st.cp = p + 1; 3265 st.cp = p + 1;
3254 st.termc = *st.cp; 3266 st.termc = *st.cp;
3255 break; 3267 break;
3256 } 3268 }
3257 goto default_case; 3269 goto default_case;
3258 case 'R': 3270 case 'R':
3259 if (p[1] == st.endc || p[1] == ':') { 3271 if (p[1] == st.endc || p[1] == ':') {
3260 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, 3272 st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord,
3261 st.nstr, ModifyWord_Root, NULL); 3273 st.nstr, ModifyWord_Root, NULL);
3262 st.cp = p + 1; 3274 st.cp = p + 1;
3263 st.termc = *st.cp; 3275 st.termc = *st.cp;
3264 break; 3276 break;
3265 } 3277 }
3266 goto default_case; 3278 goto default_case;
3267 case 'r': 3279 case 'r':
3268 if (!ApplyModifier_Range(p, &st)) 3280 if (!ApplyModifier_Range(p, &st))
3269 goto default_case; 3281 goto default_case;
3270 break; 3282 break;
3271 case 'O': 3283 case 'O':
3272 if (!ApplyModifier_Order(p, &st)) 3284 if (!ApplyModifier_Order(p, &st))
3273 goto bad_modifier; 3285 goto bad_modifier;
3274 break; 3286 break;
3275 case 'u': 3287 case 'u':
3276 if (p[1] == st.endc || p[1] == ':') { 3288 if (p[1] == st.endc || p[1] == ':') {
3277 st.newStr = VarUniq(st.nstr); 3289 st.newStr = VarUniq(st.nstr);
3278 st.cp = p + 1; 3290 st.cp = p + 1;
3279 st.termc = *st.cp; 3291 st.termc = *st.cp;
3280 break; 3292 break;
3281 } 3293 }
3282 goto default_case; 3294 goto default_case;
3283#ifdef SUNSHCMD 3295#ifdef SUNSHCMD
3284 case 's': 3296 case 's':
3285 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { 3297 if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) {
3286 const char *emsg; 3298 const char *emsg;
3287 if (st.eflags & VARE_WANTRES) { 3299 if (st.eflags & VARE_WANTRES) {
3288 st.newStr = Cmd_Exec(st.nstr, &emsg); 3300 st.newStr = Cmd_Exec(st.nstr, &emsg);
3289 if (emsg) 3301 if (emsg)
3290 Error(emsg, st.nstr); 3302 Error(emsg, st.nstr);
3291 } else 3303 } else
3292 st.newStr = varNoError; 3304 st.newStr = varNoError;
3293 st.cp = p + 2; 3305 st.cp = p + 2;
3294 st.termc = *st.cp; 3306 st.termc = *st.cp;
3295 break; 3307 break;
3296 } 3308 }
3297 goto default_case; 3309 goto default_case;
3298#endif 3310#endif
3299 default: 3311 default:
3300 default_case: 3312 default_case:
3301 { 3313 {
3302#ifdef SYSVVARSUB 3314#ifdef SYSVVARSUB
3303 int res = ApplyModifier_SysV(p, &st); 3315 int res = ApplyModifier_SysV(p, &st);
3304 if (res == 'c') 3316 if (res == 'c')
3305 goto cleanup; 3317 goto cleanup;
3306 if (res != '=') 3318 if (res != '=')
3307#endif 3319#endif
3308 { 3320 {
3309 Error("Unknown modifier '%c'", *p); 3321 Error("Unknown modifier '%c'", *p);
3310 for (st.cp = p + 1; 3322 for (st.cp = p + 1;
3311 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; 3323 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3312 st.cp++) 3324 st.cp++)
3313 continue; 3325 continue;
3314 st.termc = *st.cp; 3326 st.termc = *st.cp;
3315 st.newStr = var_Error; 3327 st.newStr = var_Error;
3316 } 3328 }
3317 } 3329 }
3318 } 3330 }
3319 if (DEBUG(VAR)) { 3331 if (DEBUG(VAR)) {
3320 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", 3332 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3321 st.v->name, st.modifier, st.newStr); 3333 st.v->name, st.modifier, st.newStr);
3322 } 3334 }
3323 3335
3324 if (st.newStr != st.nstr) { 3336 if (st.newStr != st.nstr) {
3325 if (*st.freePtr) { 3337 if (*st.freePtr) {
3326 free(st.nstr); 3338 free(st.nstr);
3327 *st.freePtr = NULL; 3339 *st.freePtr = NULL;
3328 } 3340 }
3329 st.nstr = st.newStr; 3341 st.nstr = st.newStr;
3330 if (st.nstr != var_Error && st.nstr != varNoError) { 3342 if (st.nstr != var_Error && st.nstr != varNoError) {
3331 *st.freePtr = st.nstr; 3343 *st.freePtr = st.nstr;
3332 } 3344 }
3333 } 3345 }
3334 if (st.termc == '\0' && st.endc != '\0') { 3346 if (st.termc == '\0' && st.endc != '\0') {
3335 Error("Unclosed variable specification (expecting '%c') " 3347 Error("Unclosed variable specification (expecting '%c') "
3336 "for \"%s\" (value \"%s\") modifier %c", 3348 "for \"%s\" (value \"%s\") modifier %c",
3337 st.endc, st.v->name, st.nstr, st.modifier); 3349 st.endc, st.v->name, st.nstr, st.modifier);
3338 } else if (st.termc == ':') { 3350 } else if (st.termc == ':') {
3339 st.cp++; 3351 st.cp++;
3340 } 3352 }
3341 p = st.cp; 3353 p = st.cp;
3342 } 3354 }
3343out: 3355out:
3344 *st.lengthPtr = p - st.start; 3356 *st.lengthPtr = p - st.start;
3345 return st.nstr; 3357 return st.nstr;
3346 3358
3347bad_modifier: 3359bad_modifier:
3348 Error("Bad modifier `:%.*s' for %s", 3360 Error("Bad modifier `:%.*s' for %s",
3349 (int)strcspn(p, ":)}"), p, st.v->name); 3361 (int)strcspn(p, ":)}"), p, st.v->name);
3350 3362
3351cleanup: 3363cleanup:
3352 *st.lengthPtr = st.cp - st.start; 3364 *st.lengthPtr = st.cp - st.start;
3353 if (st.missing_delim != '\0') 3365 if (st.missing_delim != '\0')
3354 Error("Unclosed substitution for %s (%c missing)", 3366 Error("Unclosed substitution for %s (%c missing)",
3355 st.v->name, st.missing_delim); 3367 st.v->name, st.missing_delim);
3356 free(*st.freePtr); 3368 free(*st.freePtr);
3357 *st.freePtr = NULL; 3369 *st.freePtr = NULL;
3358 return var_Error; 3370 return var_Error;
3359} 3371}
3360 3372
3361/*- 3373/*-
3362 *----------------------------------------------------------------------- 3374 *-----------------------------------------------------------------------
3363 * Var_Parse -- 3375 * Var_Parse --
3364 * Given the start of a variable invocation, extract the variable 3376 * Given the start of a variable invocation, extract the variable
3365 * name and find its value, then modify it according to the 3377 * name and find its value, then modify it according to the
3366 * specification. 3378 * specification.
3367 * 3379 *
3368 * Input: 3380 * Input:
3369 * str The string to parse 3381 * str The string to parse
3370 * ctxt The context for the variable 3382 * ctxt The context for the variable
3371 * flags VARE_UNDEFERR if undefineds are an error 3383 * flags VARE_UNDEFERR if undefineds are an error
3372 * VARE_WANTRES if we actually want the result 3384 * VARE_WANTRES if we actually want the result
3373 * VARE_ASSIGN if we are in a := assignment 3385 * VARE_ASSIGN if we are in a := assignment
3374 * lengthPtr OUT: The length of the specification 3386 * lengthPtr OUT: The length of the specification
3375 * freePtr OUT: Non-NULL if caller should free *freePtr 3387 * freePtr OUT: Non-NULL if caller should free *freePtr
3376 * 3388 *
3377 * Results: 3389 * Results:
3378 * The (possibly-modified) value of the variable or var_Error if the 3390 * The (possibly-modified) value of the variable or var_Error if the
3379 * specification is invalid. The length of the specification is 3391 * specification is invalid. The length of the specification is
3380 * placed in *lengthPtr (for invalid specifications, this is just 3392 * placed in *lengthPtr (for invalid specifications, this is just
3381 * 2...?). 3393 * 2...?).
3382 * If *freePtr is non-NULL then it's a pointer that the caller 3394 * If *freePtr is non-NULL then it's a pointer that the caller
3383 * should pass to free() to free memory used by the result. 3395 * should pass to free() to free memory used by the result.
3384 * 3396 *
3385 * Side Effects: 3397 * Side Effects:
3386 * None. 3398 * None.
3387 * 3399 *
3388 *----------------------------------------------------------------------- 3400 *-----------------------------------------------------------------------
3389 */ 3401 */
3390/* coverity[+alloc : arg-*4] */ 3402/* coverity[+alloc : arg-*4] */
3391char * 3403char *
3392Var_Parse(const char *str, GNode *ctxt, VarEvalFlags flags, 3404Var_Parse(const char *str, GNode *ctxt, VarEvalFlags flags,
3393 int *lengthPtr, void **freePtr) 3405 int *lengthPtr, void **freePtr)
3394{ 3406{
3395 const char *tstr; /* Pointer into str */ 3407 const char *tstr; /* Pointer into str */
3396 Var *v; /* Variable in invocation */ 3408 Var *v; /* Variable in invocation */
3397 Boolean haveModifier; /* TRUE if have modifiers for the variable */ 3409 Boolean haveModifier; /* TRUE if have modifiers for the variable */
3398 char endc; /* Ending character when variable in parens 3410 char endc; /* Ending character when variable in parens
3399 * or braces */ 3411 * or braces */
3400 char startc; /* Starting character when variable in parens 3412 char startc; /* Starting character when variable in parens
3401 * or braces */ 3413 * or braces */
3402 int vlen; /* Length of variable name */ 3414 int vlen; /* Length of variable name */
3403 const char *start; /* Points to original start of str */ 3415 const char *start; /* Points to original start of str */
3404 char *nstr; /* New string, used during expansion */ 3416 char *nstr; /* New string, used during expansion */
3405 Boolean dynamic; /* TRUE if the variable is local and we're 3417 Boolean dynamic; /* TRUE if the variable is local and we're
3406 * expanding it in a non-local context. This 3418 * expanding it in a non-local context. This
3407 * is done to support dynamic sources. The 3419 * is done to support dynamic sources. The
3408 * result is just the invocation, unaltered */ 3420 * result is just the invocation, unaltered */
3409 const char *extramodifiers; /* extra modifiers to apply first */ 3421 const char *extramodifiers; /* extra modifiers to apply first */
3410 char name[2]; 3422 char name[2];
3411 3423
3412 *freePtr = NULL; 3424 *freePtr = NULL;
3413 extramodifiers = NULL; 3425 extramodifiers = NULL;
3414 dynamic = FALSE; 3426 dynamic = FALSE;
3415 start = str; 3427 start = str;
3416 3428
3417 startc = str[1]; 3429 startc = str[1];
3418 if (startc != PROPEN && startc != BROPEN) { 3430 if (startc != PROPEN && startc != BROPEN) {
3419 /* 3431 /*
3420 * If it's not bounded by braces of some sort, life is much simpler. 3432 * If it's not bounded by braces of some sort, life is much simpler.
3421 * We just need to check for the first character and return the 3433 * We just need to check for the first character and return the
3422 * value if it exists. 3434 * value if it exists.
3423 */ 3435 */
3424 3436
3425 /* Error out some really stupid names */ 3437 /* Error out some really stupid names */
3426 if (startc == '\0' || strchr(")}:$", startc)) { 3438 if (startc == '\0' || strchr(")}:$", startc)) {
3427 *lengthPtr = 1; 3439 *lengthPtr = 1;
3428 return var_Error; 3440 return var_Error;
3429 } 3441 }
3430 name[0] = startc; 3442 name[0] = startc;
3431 name[1] = '\0'; 3443 name[1] = '\0';
3432 3444
3433 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3445 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3434 if (v == NULL) { 3446 if (v == NULL) {
3435 *lengthPtr = 2; 3447 *lengthPtr = 2;
3436 3448
3437 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 3449 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3438 /* 3450 /*
3439 * If substituting a local variable in a non-local context, 3451 * If substituting a local variable in a non-local context,
3440 * assume it's for dynamic source stuff. We have to handle 3452 * assume it's for dynamic source stuff. We have to handle
3441 * this specially and return the longhand for the variable 3453 * this specially and return the longhand for the variable
3442 * with the dollar sign escaped so it makes it back to the 3454 * with the dollar sign escaped so it makes it back to the
3443 * caller. Only four of the local variables are treated 3455 * caller. Only four of the local variables are treated
3444 * specially as they are the only four that will be set 3456 * specially as they are the only four that will be set
3445 * when dynamic sources are expanded. 3457 * when dynamic sources are expanded.
3446 */ 3458 */
3447 switch (str[1]) { 3459 switch (str[1]) {
3448 case '@': 3460 case '@':
3449 return UNCONST("$(.TARGET)"); 3461 return UNCONST("$(.TARGET)");
3450 case '%': 3462 case '%':
3451 return UNCONST("$(.MEMBER)"); 3463 return UNCONST("$(.MEMBER)");
3452 case '*': 3464 case '*':
3453 return UNCONST("$(.PREFIX)"); 3465 return UNCONST("$(.PREFIX)");
3454 case '!': 3466 case '!':
3455 return UNCONST("$(.ARCHIVE)"); 3467 return UNCONST("$(.ARCHIVE)");
3456 } 3468 }
3457 } 3469 }
3458 return (flags & VARE_UNDEFERR) ? var_Error : varNoError; 3470 return (flags & VARE_UNDEFERR) ? var_Error : varNoError;
3459 } else { 3471 } else {
3460 haveModifier = FALSE; 3472 haveModifier = FALSE;
3461 tstr = &str[1]; 3473 tstr = &str[1];
3462 endc = str[1]; 3474 endc = str[1];
3463 } 3475 }
3464 } else { 3476 } else {
3465 Buffer buf; /* Holds the variable name */ 3477 Buffer buf; /* Holds the variable name */
3466 int depth = 1; 3478 int depth = 1;
3467 3479
3468 endc = startc == PROPEN ? PRCLOSE : BRCLOSE; 3480 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3469 Buf_Init(&buf, 0); 3481 Buf_Init(&buf, 0);
3470 3482
3471 /* 3483 /*
3472 * Skip to the end character or a colon, whichever comes first. 3484 * Skip to the end character or a colon, whichever comes first.
3473 */ 3485 */
3474 for (tstr = str + 2; *tstr != '\0'; tstr++) { 3486 for (tstr = str + 2; *tstr != '\0'; tstr++) {
3475 /* Track depth so we can spot parse errors. */ 3487 /* Track depth so we can spot parse errors. */
3476 if (*tstr == startc) 3488 if (*tstr == startc)
3477 depth++; 3489 depth++;
3478 if (*tstr == endc) { 3490 if (*tstr == endc) {
3479 if (--depth == 0) 3491 if (--depth == 0)
3480 break; 3492 break;
3481 } 3493 }
3482 if (depth == 1 && *tstr == ':') 3494 if (depth == 1 && *tstr == ':')
3483 break; 3495 break;
3484 /* A variable inside a variable, expand. */ 3496 /* A variable inside a variable, expand. */
3485 if (*tstr == '$') { 3497 if (*tstr == '$') {
3486 int rlen; 3498 int rlen;
3487 void *freeIt; 3499 void *freeIt;
3488 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); 3500 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
3489 if (rval != NULL) 3501 if (rval != NULL)
3490 Buf_AddStr(&buf, rval); 3502 Buf_AddStr(&buf, rval);
3491 free(freeIt); 3503 free(freeIt);
3492 tstr += rlen - 1; 3504 tstr += rlen - 1;
3493 } else 3505 } else
3494 Buf_AddByte(&buf, *tstr); 3506 Buf_AddByte(&buf, *tstr);
3495 } 3507 }
3496 if (*tstr == ':') { 3508 if (*tstr == ':') {
3497 haveModifier = TRUE; 3509 haveModifier = TRUE;
3498 } else if (*tstr == endc) { 3510 } else if (*tstr == endc) {
3499 haveModifier = FALSE; 3511 haveModifier = FALSE;
3500 } else { 3512 } else {
3501 /* 3513 /*
3502 * If we never did find the end character, return NULL 3514 * If we never did find the end character, return NULL
3503 * right now, setting the length to be the distance to 3515 * right now, setting the length to be the distance to
3504 * the end of the string, since that's what make does. 3516 * the end of the string, since that's what make does.
3505 */ 3517 */
3506 *lengthPtr = tstr - str; 3518 *lengthPtr = tstr - str;
3507 Buf_Destroy(&buf, TRUE); 3519 Buf_Destroy(&buf, TRUE);
3508 return var_Error; 3520 return var_Error;
3509 } 3521 }
3510 str = Buf_GetAll(&buf, &vlen); 3522 str = Buf_GetAll(&buf, &vlen);
3511 3523
3512 /* 3524 /*
3513 * At this point, str points into newly allocated memory from 3525 * At this point, str points into newly allocated memory from
3514 * buf, containing only the name of the variable. 3526 * buf, containing only the name of the variable.
3515 * 3527 *
3516 * start and tstr point into the const string that was pointed 3528 * start and tstr point into the const string that was pointed
3517 * to by the original value of the str parameter. start points 3529 * to by the original value of the str parameter. start points
3518 * to the '$' at the beginning of the string, while tstr points 3530 * to the '$' at the beginning of the string, while tstr points
3519 * to the char just after the end of the variable name -- this 3531 * to the char just after the end of the variable name -- this
3520 * will be '\0', ':', PRCLOSE, or BRCLOSE. 3532 * will be '\0', ':', PRCLOSE, or BRCLOSE.
3521 */ 3533 */
3522 3534
3523 v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 3535 v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);