Sun Jul 19 19:27:08 2020 UTC ()
make(1): fix off-by-one error in :C modifier

Previously this off-by-one error had invoked undefined behavior.
Until today there was no corresponding unit test though.


(rillig)
diff -r1.270 -r1.271 src/usr.bin/make/var.c
diff -r1.16 -r1.17 src/usr.bin/make/unit-tests/modmisc.exp

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

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

cvs diff -r1.16 -r1.17 src/usr.bin/make/unit-tests/modmisc.exp (switch to unified diff)

--- src/usr.bin/make/unit-tests/modmisc.exp 2020/07/19 17:24:22 1.16
+++ src/usr.bin/make/unit-tests/modmisc.exp 2020/07/19 19:27:08 1.17
@@ -1,64 +1,72 @@ @@ -1,64 +1,72 @@
1path=':/bin:/tmp::/:.:/no/such/dir:.' 1path=':/bin:/tmp::/:.:/no/such/dir:.'
2path='/bin:/tmp:/:/no/such/dir' 2path='/bin:/tmp:/:/no/such/dir'
3path='/bin:/tmp:/:/no/such/dir' 3path='/bin:/tmp:/:/no/such/dir'
4path='/bin':'/tmp':'/':'/no/such/dir' 4path='/bin':'/tmp':'/':'/no/such/dir'
5path='/bin':'/tmp':'/':'/no/such/dir' 5path='/bin':'/tmp':'/':'/no/such/dir'
6path_/usr/xbin=/opt/xbin/ 6path_/usr/xbin=/opt/xbin/
7paths=/bin /tmp / /no/such/dir /opt/xbin 7paths=/bin /tmp / /no/such/dir /opt/xbin
8PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN 8PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
9The answer is 42 9The answer is 42
10dirname of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'a/b . . a.b . . . . .' 10dirname of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'a/b . . a.b . . . . .'
11basename of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c def a.b.c c a a.a .gitignore a a.a' 11basename of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c def a.b.c c a a.a .gitignore a a.a'
12suffix of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c b/c a gitignore a' 12suffix of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c b/c a gitignore a'
13root of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'a/b/c def a.b a a a a a' 13root of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'a/b/c def a.b a a a a a'
14S: 14S:
15C: 15C:
16@: 16@:
17S:empty 17S:empty
18C:empty 18C:empty
19@: 19@:
20:a b b c: 20:a b b c:
21:a b b c: 21:a b b c:
22: b c: 22: b c:
23:a c: 23:a c:
24:x__ 3 x__ 3: 24:x__ 3 x__ 3:
25:a b b c: 25:a b b c:
26:a b b c: 26:a b b c:
27: b c: 27: b c:
28make: RE substitution error: (details omitted) 28make: RE substitution error: (details omitted)
29make: Unclosed substitution for (, missing) 29make: Unclosed substitution for (, missing)
30:C,word,____,:Q}: 30:C,word,____,:Q}:
31:a c: 31:a c:
32:x__ 3 x__ 3: 32:x__ 3 x__ 3:
33:+one+ +two+ +three+: 33:+one+ +two+ +three+:
34mod-at-resolve:w1d2d3w w2i3w w1i2d3 2i${RES3}w w1d2d3 2i${RES3} 1i${RES2}w: 34mod-at-resolve:w1d2d3w w2i3w w1i2d3 2i${RES3}w w1d2d3 2i${RES3} 1i${RES2}w:
35mod-at-dollar:(1) (2) (3). 35mod-at-dollar:(1) (2) (3).
36mod-at-dollar:(1) (2) (3). 36mod-at-dollar:(1) (2) (3).
37mod-at-dollar:() () (). 37mod-at-dollar:() () ().
38mod-subst-dollar:$1: 38mod-subst-dollar:$1:
39mod-subst-dollar:$2: 39mod-subst-dollar:$2:
40mod-subst-dollar:$3: 40mod-subst-dollar:$3:
41mod-subst-dollar:$4: 41mod-subst-dollar:$4:
42mod-subst-dollar:$5: 42mod-subst-dollar:$5:
43mod-subst-dollar:$6: 43mod-subst-dollar:$6:
44mod-subst-dollar:$7: 44mod-subst-dollar:$7:
45mod-subst-dollar:$8: 45mod-subst-dollar:$8:
46mod-subst-dollar:U8: 46mod-subst-dollar:U8:
47mod-subst-dollar:$$$$: 47mod-subst-dollar:$$$$:
48mod-loop-dollar:1: 48mod-loop-dollar:1:
49mod-loop-dollar:${word}: 49mod-loop-dollar:${word}:
50mod-loop-dollar:$3$: 50mod-loop-dollar:$3$:
51mod-loop-dollar:$${word}$: 51mod-loop-dollar:$${word}$:
52mod-loop-dollar:$$5$$: 52mod-loop-dollar:$$5$$:
53mod-loop-dollar:$$${word}$$: 53mod-loop-dollar:$$${word}$$:
54mod-C-limits:00-ok:1 2323 45456 54mod-C-limits:00-ok:1 2323 45456
 55make: No subexpression \1
 56make: No subexpression \1
 57make: No subexpression \1
 58make: No subexpression \1
55mod-C-limits:11-missing:1 6 59mod-C-limits:11-missing:1 6
56mod-C-limits:11-ok:1 22 446 60mod-C-limits:11-ok:1 22 446
57make: No subexpression \2 61make: No subexpression \2
58make: No subexpression \2 62make: No subexpression \2
59make: No subexpression \2 63make: No subexpression \2
60make: No subexpression \2 64make: No subexpression \2
61mod-C-limits:22-missing:1 6 65mod-C-limits:22-missing:1 6
 66make: No subexpression \2
 67make: No subexpression \2
 68make: No subexpression \2
 69make: No subexpression \2
62mod-C-limits:22-missing:1 6 70mod-C-limits:22-missing:1 6
63mod-C-limits:22-ok:1 33 556 71mod-C-limits:22-ok:1 33 556
64exit status 0 72exit status 0