Sun Jul 19 15:47:10 2020 UTC ()
make(1): eliminate macro from VarGetPattern


(rillig)
diff -r1.262 -r1.263 src/usr.bin/make/var.c

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

--- src/usr.bin/make/var.c 2020/07/19 14:05:39 1.262
+++ src/usr.bin/make/var.c 2020/07/19 15:47:10 1.263
@@ -1,3073 +1,3071 @@ @@ -1,3073 +1,3071 @@
1/* $NetBSD: var.c,v 1.262 2020/07/19 14:05:39 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.263 2020/07/19 15:47:10 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.262 2020/07/19 14:05:39 rillig Exp $"; 72static char rcsid[] = "$NetBSD: var.c,v 1.263 2020/07/19 15:47:10 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.262 2020/07/19 14:05:39 rillig Exp $"); 79__RCSID("$NetBSD: var.c,v 1.263 2020/07/19 15:47:10 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. It is not related to 246 /* FIXME: This constant doesn't belong here. It is not related to
247 * pattern matching, and VarGetPattern is badly named as well. */ 247 * pattern matching, and VarGetPattern is badly named as well. */
248 VAR_NOSUBST = 0x20 /* don't expand vars in VarGetPattern */ 248 VAR_NOSUBST = 0x20 /* don't expand vars in VarGetPattern */
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 GNode *ctxt; /* variable context */ 281 GNode *ctxt; /* variable context */
282 char *tvar; /* name of temp var */ 282 char *tvar; /* name of temp var */
283 int tvarLen; 283 int tvarLen;
284 char *str; /* string to expand */ 284 char *str; /* string to expand */
285 int strLen; 285 int strLen;
286 VarEvalFlags flags; 286 VarEvalFlags flags;
287} VarLoop; 287} VarLoop;
288 288
289#ifndef NO_REGEX 289#ifndef NO_REGEX
290/* struct passed as 'void *' to VarRESubstitute() for ":C///" */ 290/* struct passed as 'void *' to VarRESubstitute() for ":C///" */
291typedef struct { 291typedef struct {
292 regex_t re; 292 regex_t re;
293 int nsub; 293 int nsub;
294 regmatch_t *matches; 294 regmatch_t *matches;
295 char *replace; 295 char *replace;
296 VarPatternFlags pflags; 296 VarPatternFlags pflags;
297} VarREPattern; 297} VarREPattern;
298#endif 298#endif
299 299
300/* struct passed to VarSelectWords() for ":[start..end]" */ 300/* struct passed to VarSelectWords() for ":[start..end]" */
301typedef struct { 301typedef struct {
302 int start; /* first word to select */ 302 int start; /* first word to select */
303 int end; /* last word to select */ 303 int end; /* last word to select */
304} VarSelectWords_t; 304} VarSelectWords_t;
305 305
306#define BROPEN '{' 306#define BROPEN '{'
307#define BRCLOSE '}' 307#define BRCLOSE '}'
308#define PROPEN '(' 308#define PROPEN '('
309#define PRCLOSE ')' 309#define PRCLOSE ')'
310 310
311/*- 311/*-
312 *----------------------------------------------------------------------- 312 *-----------------------------------------------------------------------
313 * VarFind -- 313 * VarFind --
314 * Find the given variable in the given context and any other contexts 314 * Find the given variable in the given context and any other contexts
315 * indicated. 315 * indicated.
316 * 316 *
317 * Input: 317 * Input:
318 * name name to find 318 * name name to find
319 * ctxt context in which to find it 319 * ctxt context in which to find it
320 * flags FIND_GLOBAL look in VAR_GLOBAL as well 320 * flags FIND_GLOBAL look in VAR_GLOBAL as well
321 * FIND_CMD look in VAR_CMD as well 321 * FIND_CMD look in VAR_CMD as well
322 * FIND_ENV look in the environment as well 322 * FIND_ENV look in the environment as well
323 * 323 *
324 * Results: 324 * Results:
325 * A pointer to the structure describing the desired variable or 325 * A pointer to the structure describing the desired variable or
326 * NULL if the variable does not exist. 326 * NULL if the variable does not exist.
327 * 327 *
328 * Side Effects: 328 * Side Effects:
329 * None 329 * None
330 *----------------------------------------------------------------------- 330 *-----------------------------------------------------------------------
331 */ 331 */
332static Var * 332static Var *
333VarFind(const char *name, GNode *ctxt, VarFindFlags flags) 333VarFind(const char *name, GNode *ctxt, VarFindFlags flags)
334{ 334{
335 Hash_Entry *var; 335 Hash_Entry *var;
336 Var *v; 336 Var *v;
337 337
338 /* 338 /*
339 * If the variable name begins with a '.', it could very well be one of 339 * If the variable name begins with a '.', it could very well be one of
340 * the local ones. We check the name against all the local variables 340 * the local ones. We check the name against all the local variables
341 * and substitute the short version in for 'name' if it matches one of 341 * and substitute the short version in for 'name' if it matches one of
342 * them. 342 * them.
343 */ 343 */
344 if (*name == '.' && isupper((unsigned char) name[1])) { 344 if (*name == '.' && isupper((unsigned char) name[1])) {
345 switch (name[1]) { 345 switch (name[1]) {
346 case 'A': 346 case 'A':
347 if (strcmp(name, ".ALLSRC") == 0) 347 if (strcmp(name, ".ALLSRC") == 0)
348 name = ALLSRC; 348 name = ALLSRC;
349 if (strcmp(name, ".ARCHIVE") == 0) 349 if (strcmp(name, ".ARCHIVE") == 0)
350 name = ARCHIVE; 350 name = ARCHIVE;
351 break; 351 break;
352 case 'I': 352 case 'I':
353 if (strcmp(name, ".IMPSRC") == 0) 353 if (strcmp(name, ".IMPSRC") == 0)
354 name = IMPSRC; 354 name = IMPSRC;
355 break; 355 break;
356 case 'M': 356 case 'M':
357 if (strcmp(name, ".MEMBER") == 0) 357 if (strcmp(name, ".MEMBER") == 0)
358 name = MEMBER; 358 name = MEMBER;
359 break; 359 break;
360 case 'O': 360 case 'O':
361 if (strcmp(name, ".OODATE") == 0) 361 if (strcmp(name, ".OODATE") == 0)
362 name = OODATE; 362 name = OODATE;
363 break; 363 break;
364 case 'P': 364 case 'P':
365 if (strcmp(name, ".PREFIX") == 0) 365 if (strcmp(name, ".PREFIX") == 0)
366 name = PREFIX; 366 name = PREFIX;
367 break; 367 break;
368 case 'T': 368 case 'T':
369 if (strcmp(name, ".TARGET") == 0) 369 if (strcmp(name, ".TARGET") == 0)
370 name = TARGET; 370 name = TARGET;
371 break; 371 break;
372 } 372 }
373 } 373 }
374 374
375#ifdef notyet 375#ifdef notyet
376 /* for compatibility with gmake */ 376 /* for compatibility with gmake */
377 if (name[0] == '^' && name[1] == '\0') 377 if (name[0] == '^' && name[1] == '\0')
378 name = ALLSRC; 378 name = ALLSRC;
379#endif 379#endif
380 380
381 /* 381 /*
382 * First look for the variable in the given context. If it's not there, 382 * First look for the variable in the given context. If it's not there,
383 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 383 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
384 * depending on the FIND_* flags in 'flags' 384 * depending on the FIND_* flags in 'flags'
385 */ 385 */
386 var = Hash_FindEntry(&ctxt->context, name); 386 var = Hash_FindEntry(&ctxt->context, name);
387 387
388 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) { 388 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
389 var = Hash_FindEntry(&VAR_CMD->context, name); 389 var = Hash_FindEntry(&VAR_CMD->context, name);
390 } 390 }
391 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && 391 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
392 ctxt != VAR_GLOBAL) 392 ctxt != VAR_GLOBAL)
393 { 393 {
394 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 394 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
395 if (var == NULL && ctxt != VAR_INTERNAL) { 395 if (var == NULL && ctxt != VAR_INTERNAL) {
396 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 396 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
397 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 397 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
398 } 398 }
399 } 399 }
400 if (var == NULL && (flags & FIND_ENV)) { 400 if (var == NULL && (flags & FIND_ENV)) {
401 char *env; 401 char *env;
402 402
403 if ((env = getenv(name)) != NULL) { 403 if ((env = getenv(name)) != NULL) {
404 int len; 404 int len;
405 405
406 v = bmake_malloc(sizeof(Var)); 406 v = bmake_malloc(sizeof(Var));
407 v->name = bmake_strdup(name); 407 v->name = bmake_strdup(name);
408 408
409 len = strlen(env); 409 len = strlen(env);
410 410
411 Buf_Init(&v->val, len + 1); 411 Buf_Init(&v->val, len + 1);
412 Buf_AddBytes(&v->val, len, env); 412 Buf_AddBytes(&v->val, len, env);
413 413
414 v->flags = VAR_FROM_ENV; 414 v->flags = VAR_FROM_ENV;
415 return v; 415 return v;
416 } else if (checkEnvFirst && (flags & FIND_GLOBAL) && 416 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
417 ctxt != VAR_GLOBAL) 417 ctxt != VAR_GLOBAL)
418 { 418 {
419 var = Hash_FindEntry(&VAR_GLOBAL->context, name); 419 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
420 if (var == NULL && ctxt != VAR_INTERNAL) { 420 if (var == NULL && ctxt != VAR_INTERNAL) {
421 var = Hash_FindEntry(&VAR_INTERNAL->context, name); 421 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
422 } 422 }
423 if (var == NULL) { 423 if (var == NULL) {
424 return NULL; 424 return NULL;
425 } else { 425 } else {
426 return (Var *)Hash_GetValue(var); 426 return (Var *)Hash_GetValue(var);
427 } 427 }
428 } else { 428 } else {
429 return NULL; 429 return NULL;
430 } 430 }
431 } else if (var == NULL) { 431 } else if (var == NULL) {
432 return NULL; 432 return NULL;
433 } else { 433 } else {
434 return (Var *)Hash_GetValue(var); 434 return (Var *)Hash_GetValue(var);
435 } 435 }
436} 436}
437 437
438/*- 438/*-
439 *----------------------------------------------------------------------- 439 *-----------------------------------------------------------------------
440 * VarFreeEnv -- 440 * VarFreeEnv --
441 * If the variable is an environment variable, free it 441 * If the variable is an environment variable, free it
442 * 442 *
443 * Input: 443 * Input:
444 * v the variable 444 * v the variable
445 * destroy true if the value buffer should be destroyed. 445 * destroy true if the value buffer should be destroyed.
446 * 446 *
447 * Results: 447 * Results:
448 * 1 if it is an environment variable 0 ow. 448 * 1 if it is an environment variable 0 ow.
449 * 449 *
450 * Side Effects: 450 * Side Effects:
451 * The variable is free'ed if it is an environent variable. 451 * The variable is free'ed if it is an environent variable.
452 *----------------------------------------------------------------------- 452 *-----------------------------------------------------------------------
453 */ 453 */
454static Boolean 454static Boolean
455VarFreeEnv(Var *v, Boolean destroy) 455VarFreeEnv(Var *v, Boolean destroy)
456{ 456{
457 if (!(v->flags & VAR_FROM_ENV)) 457 if (!(v->flags & VAR_FROM_ENV))
458 return FALSE; 458 return FALSE;
459 free(v->name); 459 free(v->name);
460 Buf_Destroy(&v->val, destroy); 460 Buf_Destroy(&v->val, destroy);
461 free(v); 461 free(v);
462 return TRUE; 462 return TRUE;
463} 463}
464 464
465/*- 465/*-
466 *----------------------------------------------------------------------- 466 *-----------------------------------------------------------------------
467 * VarAdd -- 467 * VarAdd --
468 * Add a new variable of name name and value val to the given context 468 * Add a new variable of name name and value val to the given context
469 * 469 *
470 * Input: 470 * Input:
471 * name name of variable to add 471 * name name of variable to add
472 * val value to set it to 472 * val value to set it to
473 * ctxt context in which to set it 473 * ctxt context in which to set it
474 * 474 *
475 * Side Effects: 475 * Side Effects:
476 * The new variable is placed at the front of the given context 476 * The new variable is placed at the front of the given context
477 * The name and val arguments are duplicated so they may 477 * The name and val arguments are duplicated so they may
478 * safely be freed. 478 * safely be freed.
479 *----------------------------------------------------------------------- 479 *-----------------------------------------------------------------------
480 */ 480 */
481static void 481static void
482VarAdd(const char *name, const char *val, GNode *ctxt) 482VarAdd(const char *name, const char *val, GNode *ctxt)
483{ 483{
484 Var *v; 484 Var *v;
485 int len; 485 int len;
486 Hash_Entry *h; 486 Hash_Entry *h;
487 487
488 v = bmake_malloc(sizeof(Var)); 488 v = bmake_malloc(sizeof(Var));
489 489
490 len = val != NULL ? strlen(val) : 0; 490 len = val != NULL ? strlen(val) : 0;
491 Buf_Init(&v->val, len + 1); 491 Buf_Init(&v->val, len + 1);
492 Buf_AddBytes(&v->val, len, val); 492 Buf_AddBytes(&v->val, len, val);
493 493
494 v->flags = 0; 494 v->flags = 0;
495 495
496 h = Hash_CreateEntry(&ctxt->context, name, NULL); 496 h = Hash_CreateEntry(&ctxt->context, name, NULL);
497 Hash_SetValue(h, v); 497 Hash_SetValue(h, v);
498 v->name = h->name; 498 v->name = h->name;
499 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) { 499 if (DEBUG(VAR) && !(ctxt->flags & INTERNAL)) {
500 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 500 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
501 } 501 }
502} 502}
503 503
504/*- 504/*-
505 *----------------------------------------------------------------------- 505 *-----------------------------------------------------------------------
506 * Var_Delete -- 506 * Var_Delete --
507 * Remove a variable from a context. 507 * Remove a variable from a context.
508 * 508 *
509 * Side Effects: 509 * Side Effects:
510 * The Var structure is removed and freed. 510 * The Var structure is removed and freed.
511 * 511 *
512 *----------------------------------------------------------------------- 512 *-----------------------------------------------------------------------
513 */ 513 */
514void 514void
515Var_Delete(const char *name, GNode *ctxt) 515Var_Delete(const char *name, GNode *ctxt)
516{ 516{
517 Hash_Entry *ln; 517 Hash_Entry *ln;
518 char *cp; 518 char *cp;
519 519
520 if (strchr(name, '$') != NULL) { 520 if (strchr(name, '$') != NULL) {
521 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES); 521 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARE_WANTRES);
522 } else { 522 } else {
523 cp = UNCONST(name); 523 cp = UNCONST(name);
524 } 524 }
525 ln = Hash_FindEntry(&ctxt->context, cp); 525 ln = Hash_FindEntry(&ctxt->context, cp);
526 if (DEBUG(VAR)) { 526 if (DEBUG(VAR)) {
527 fprintf(debug_file, "%s:delete %s%s\n", 527 fprintf(debug_file, "%s:delete %s%s\n",
528 ctxt->name, cp, ln ? "" : " (not found)"); 528 ctxt->name, cp, ln ? "" : " (not found)");
529 } 529 }
530 if (cp != name) 530 if (cp != name)
531 free(cp); 531 free(cp);
532 if (ln != NULL) { 532 if (ln != NULL) {
533 Var *v = (Var *)Hash_GetValue(ln); 533 Var *v = (Var *)Hash_GetValue(ln);
534 if (v->flags & VAR_EXPORTED) { 534 if (v->flags & VAR_EXPORTED) {
535 unsetenv(v->name); 535 unsetenv(v->name);
536 } 536 }
537 if (strcmp(MAKE_EXPORTED, v->name) == 0) { 537 if (strcmp(MAKE_EXPORTED, v->name) == 0) {
538 var_exportedVars = VAR_EXPORTED_NONE; 538 var_exportedVars = VAR_EXPORTED_NONE;
539 } 539 }
540 if (v->name != ln->name) 540 if (v->name != ln->name)
541 free(v->name); 541 free(v->name);
542 Hash_DeleteEntry(&ctxt->context, ln); 542 Hash_DeleteEntry(&ctxt->context, ln);
543 Buf_Destroy(&v->val, TRUE); 543 Buf_Destroy(&v->val, TRUE);
544 free(v); 544 free(v);
545 } 545 }
546} 546}
547 547
548 548
549/* 549/*
550 * Export a var. 550 * Export a var.
551 * We ignore make internal variables (those which start with '.') 551 * We ignore make internal variables (those which start with '.')
552 * Also we jump through some hoops to avoid calling setenv 552 * Also we jump through some hoops to avoid calling setenv
553 * more than necessary since it can leak. 553 * more than necessary since it can leak.
554 * We only manipulate flags of vars if 'parent' is set. 554 * We only manipulate flags of vars if 'parent' is set.
555 */ 555 */
556static int 556static int
557Var_Export1(const char *name, int flags) 557Var_Export1(const char *name, int flags)
558{ 558{
559 char tmp[BUFSIZ]; 559 char tmp[BUFSIZ];
560 Var *v; 560 Var *v;
561 char *val = NULL; 561 char *val = NULL;
562 int n; 562 int n;
563 int parent = (flags & VAR_EXPORT_PARENT); 563 int parent = (flags & VAR_EXPORT_PARENT);
564 564
565 if (*name == '.') 565 if (*name == '.')
566 return 0; /* skip internals */ 566 return 0; /* skip internals */
567 if (!name[1]) { 567 if (!name[1]) {
568 /* 568 /*
569 * A single char. 569 * A single char.
570 * If it is one of the vars that should only appear in 570 * If it is one of the vars that should only appear in
571 * local context, skip it, else we can get Var_Subst 571 * local context, skip it, else we can get Var_Subst
572 * into a loop. 572 * into a loop.
573 */ 573 */
574 switch (name[0]) { 574 switch (name[0]) {
575 case '@': 575 case '@':
576 case '%': 576 case '%':
577 case '*': 577 case '*':
578 case '!': 578 case '!':
579 return 0; 579 return 0;
580 } 580 }
581 } 581 }
582 v = VarFind(name, VAR_GLOBAL, 0); 582 v = VarFind(name, VAR_GLOBAL, 0);
583 if (v == NULL) 583 if (v == NULL)
584 return 0; 584 return 0;
585 if (!parent && 585 if (!parent &&
586 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { 586 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
587 return 0; /* nothing to do */ 587 return 0; /* nothing to do */
588 } 588 }
589 val = Buf_GetAll(&v->val, NULL); 589 val = Buf_GetAll(&v->val, NULL);
590 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { 590 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
591 if (parent) { 591 if (parent) {
592 /* 592 /*
593 * Flag this as something we need to re-export. 593 * Flag this as something we need to re-export.
594 * No point actually exporting it now though, 594 * No point actually exporting it now though,
595 * the child can do it at the last minute. 595 * the child can do it at the last minute.
596 */ 596 */
597 v->flags |= (VAR_EXPORTED|VAR_REEXPORT); 597 v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
598 return 1; 598 return 1;
599 } 599 }
600 if (v->flags & VAR_IN_USE) { 600 if (v->flags & VAR_IN_USE) {
601 /* 601 /*
602 * We recursed while exporting in a child. 602 * We recursed while exporting in a child.
603 * This isn't going to end well, just skip it. 603 * This isn't going to end well, just skip it.
604 */ 604 */
605 return 0; 605 return 0;
606 } 606 }
607 n = snprintf(tmp, sizeof(tmp), "${%s}", name); 607 n = snprintf(tmp, sizeof(tmp), "${%s}", name);
608 if (n < (int)sizeof(tmp)) { 608 if (n < (int)sizeof(tmp)) {
609 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 609 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
610 setenv(name, val, 1); 610 setenv(name, val, 1);
611 free(val); 611 free(val);
612 } 612 }
613 } else { 613 } else {
614 if (parent) { 614 if (parent) {
615 v->flags &= ~VAR_REEXPORT; /* once will do */ 615 v->flags &= ~VAR_REEXPORT; /* once will do */
616 } 616 }
617 if (parent || !(v->flags & VAR_EXPORTED)) { 617 if (parent || !(v->flags & VAR_EXPORTED)) {
618 setenv(name, val, 1); 618 setenv(name, val, 1);
619 } 619 }
620 } 620 }
621 /* 621 /*
622 * This is so Var_Set knows to call Var_Export again... 622 * This is so Var_Set knows to call Var_Export again...
623 */ 623 */
624 if (parent) { 624 if (parent) {
625 v->flags |= VAR_EXPORTED; 625 v->flags |= VAR_EXPORTED;
626 } 626 }
627 return 1; 627 return 1;
628} 628}
629 629
630static void 630static void
631Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED) 631Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
632{ 632{
633 Var *var = entry; 633 Var *var = entry;
634 Var_Export1(var->name, 0); 634 Var_Export1(var->name, 0);
635} 635}
636 636
637/* 637/*
638 * This gets called from our children. 638 * This gets called from our children.
639 */ 639 */
640void 640void
641Var_ExportVars(void) 641Var_ExportVars(void)
642{ 642{
643 char tmp[BUFSIZ]; 643 char tmp[BUFSIZ];
644 char *val; 644 char *val;
645 int n; 645 int n;
646 646
647 /* 647 /*
648 * Several make's support this sort of mechanism for tracking 648 * Several make's support this sort of mechanism for tracking
649 * recursion - but each uses a different name. 649 * recursion - but each uses a different name.
650 * We allow the makefiles to update MAKELEVEL and ensure 650 * We allow the makefiles to update MAKELEVEL and ensure
651 * children see a correctly incremented value. 651 * children see a correctly incremented value.
652 */ 652 */
653 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 653 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
654 setenv(MAKE_LEVEL_ENV, tmp, 1); 654 setenv(MAKE_LEVEL_ENV, tmp, 1);
655 655
656 if (VAR_EXPORTED_NONE == var_exportedVars) 656 if (VAR_EXPORTED_NONE == var_exportedVars)
657 return; 657 return;
658 658
659 if (VAR_EXPORTED_ALL == var_exportedVars) { 659 if (VAR_EXPORTED_ALL == var_exportedVars) {
660 /* Ouch! This is crazy... */ 660 /* Ouch! This is crazy... */
661 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); 661 Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
662 return; 662 return;
663 } 663 }
664 /* 664 /*
665 * We have a number of exported vars, 665 * We have a number of exported vars,
666 */ 666 */
667 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); 667 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
668 if (n < (int)sizeof(tmp)) { 668 if (n < (int)sizeof(tmp)) {
669 char **av; 669 char **av;
670 char *as; 670 char *as;
671 int ac; 671 int ac;
672 int i; 672 int i;
673 673
674 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 674 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
675 if (*val) { 675 if (*val) {
676 av = brk_string(val, &ac, FALSE, &as); 676 av = brk_string(val, &ac, FALSE, &as);
677 for (i = 0; i < ac; i++) 677 for (i = 0; i < ac; i++)
678 Var_Export1(av[i], 0); 678 Var_Export1(av[i], 0);
679 free(as); 679 free(as);
680 free(av); 680 free(av);
681 } 681 }
682 free(val); 682 free(val);
683 } 683 }
684} 684}
685 685
686/* 686/*
687 * This is called when .export is seen or 687 * This is called when .export is seen or
688 * .MAKE.EXPORTED is modified. 688 * .MAKE.EXPORTED is modified.
689 * It is also called when any exported var is modified. 689 * It is also called when any exported var is modified.
690 */ 690 */
691void 691void
692Var_Export(char *str, int isExport) 692Var_Export(char *str, int isExport)
693{ 693{
694 char *name; 694 char *name;
695 char *val; 695 char *val;
696 char **av; 696 char **av;
697 char *as; 697 char *as;
698 int flags; 698 int flags;
699 int ac; 699 int ac;
700 int i; 700 int i;
701 701
702 if (isExport && (!str || !str[0])) { 702 if (isExport && (!str || !str[0])) {
703 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 703 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
704 return; 704 return;
705 } 705 }
706 706
707 flags = 0; 707 flags = 0;
708 if (strncmp(str, "-env", 4) == 0) { 708 if (strncmp(str, "-env", 4) == 0) {
709 str += 4; 709 str += 4;
710 } else if (strncmp(str, "-literal", 8) == 0) { 710 } else if (strncmp(str, "-literal", 8) == 0) {
711 str += 8; 711 str += 8;
712 flags |= VAR_EXPORT_LITERAL; 712 flags |= VAR_EXPORT_LITERAL;
713 } else { 713 } else {
714 flags |= VAR_EXPORT_PARENT; 714 flags |= VAR_EXPORT_PARENT;
715 } 715 }
716 val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES); 716 val = Var_Subst(NULL, str, VAR_GLOBAL, VARE_WANTRES);
717 if (*val) { 717 if (*val) {
718 av = brk_string(val, &ac, FALSE, &as); 718 av = brk_string(val, &ac, FALSE, &as);
719 for (i = 0; i < ac; i++) { 719 for (i = 0; i < ac; i++) {
720 name = av[i]; 720 name = av[i];
721 if (!name[1]) { 721 if (!name[1]) {
722 /* 722 /*
723 * A single char. 723 * A single char.
724 * If it is one of the vars that should only appear in 724 * If it is one of the vars that should only appear in
725 * local context, skip it, else we can get Var_Subst 725 * local context, skip it, else we can get Var_Subst
726 * into a loop. 726 * into a loop.
727 */ 727 */
728 switch (name[0]) { 728 switch (name[0]) {
729 case '@': 729 case '@':
730 case '%': 730 case '%':
731 case '*': 731 case '*':
732 case '!': 732 case '!':
733 continue; 733 continue;
734 } 734 }
735 } 735 }
736 if (Var_Export1(name, flags)) { 736 if (Var_Export1(name, flags)) {
737 if (VAR_EXPORTED_ALL != var_exportedVars) 737 if (VAR_EXPORTED_ALL != var_exportedVars)
738 var_exportedVars = VAR_EXPORTED_YES; 738 var_exportedVars = VAR_EXPORTED_YES;
739 if (isExport && (flags & VAR_EXPORT_PARENT)) { 739 if (isExport && (flags & VAR_EXPORT_PARENT)) {
740 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 740 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
741 } 741 }
742 } 742 }
743 } 743 }
744 free(as); 744 free(as);
745 free(av); 745 free(av);
746 } 746 }
747 free(val); 747 free(val);
748} 748}
749 749
750 750
751extern char **environ; 751extern char **environ;
752 752
753/* 753/*
754 * This is called when .unexport[-env] is seen. 754 * This is called when .unexport[-env] is seen.
755 */ 755 */
756void 756void
757Var_UnExport(char *str) 757Var_UnExport(char *str)
758{ 758{
759 char tmp[BUFSIZ]; 759 char tmp[BUFSIZ];
760 char *vlist; 760 char *vlist;
761 char *cp; 761 char *cp;
762 Boolean unexport_env; 762 Boolean unexport_env;
763 int n; 763 int n;
764 764
765 if (str == NULL || str[0] == '\0') 765 if (str == NULL || str[0] == '\0')
766 return; /* assert? */ 766 return; /* assert? */
767 767
768 vlist = NULL; 768 vlist = NULL;
769 769
770 str += 8; 770 str += 8;
771 unexport_env = (strncmp(str, "-env", 4) == 0); 771 unexport_env = (strncmp(str, "-env", 4) == 0);
772 if (unexport_env) { 772 if (unexport_env) {
773 char **newenv; 773 char **newenv;
774 774
775 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 775 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
776 if (environ == savedEnv) { 776 if (environ == savedEnv) {
777 /* we have been here before! */ 777 /* we have been here before! */
778 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 778 newenv = bmake_realloc(environ, 2 * sizeof(char *));
779 } else { 779 } else {
780 if (savedEnv) { 780 if (savedEnv) {
781 free(savedEnv); 781 free(savedEnv);
782 savedEnv = NULL; 782 savedEnv = NULL;
783 } 783 }
784 newenv = bmake_malloc(2 * sizeof(char *)); 784 newenv = bmake_malloc(2 * sizeof(char *));
785 } 785 }
786 if (!newenv) 786 if (!newenv)
787 return; 787 return;
788 /* Note: we cannot safely free() the original environ. */ 788 /* Note: we cannot safely free() the original environ. */
789 environ = savedEnv = newenv; 789 environ = savedEnv = newenv;
790 newenv[0] = NULL; 790 newenv[0] = NULL;
791 newenv[1] = NULL; 791 newenv[1] = NULL;
792 if (cp && *cp) 792 if (cp && *cp)
793 setenv(MAKE_LEVEL_ENV, cp, 1); 793 setenv(MAKE_LEVEL_ENV, cp, 1);
794 } else { 794 } else {
795 for (; *str != '\n' && isspace((unsigned char) *str); str++) 795 for (; *str != '\n' && isspace((unsigned char) *str); str++)
796 continue; 796 continue;
797 if (str[0] && str[0] != '\n') { 797 if (str[0] && str[0] != '\n') {
798 vlist = str; 798 vlist = str;
799 } 799 }
800 } 800 }
801 801
802 if (!vlist) { 802 if (!vlist) {
803 /* Using .MAKE.EXPORTED */ 803 /* Using .MAKE.EXPORTED */
804 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, 804 vlist = Var_Subst(NULL, "${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
805 VARE_WANTRES); 805 VARE_WANTRES);
806 } 806 }
807 if (vlist) { 807 if (vlist) {
808 Var *v; 808 Var *v;
809 char **av; 809 char **av;
810 char *as; 810 char *as;
811 int ac; 811 int ac;
812 int i; 812 int i;
813 813
814 av = brk_string(vlist, &ac, FALSE, &as); 814 av = brk_string(vlist, &ac, FALSE, &as);
815 for (i = 0; i < ac; i++) { 815 for (i = 0; i < ac; i++) {
816 v = VarFind(av[i], VAR_GLOBAL, 0); 816 v = VarFind(av[i], VAR_GLOBAL, 0);
817 if (!v) 817 if (!v)
818 continue; 818 continue;
819 if (!unexport_env && 819 if (!unexport_env &&
820 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) 820 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED)
821 { 821 {
822 unsetenv(v->name); 822 unsetenv(v->name);
823 } 823 }
824 v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT); 824 v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
825 /* 825 /*
826 * If we are unexporting a list, 826 * If we are unexporting a list,
827 * remove each one from .MAKE.EXPORTED. 827 * remove each one from .MAKE.EXPORTED.
828 * If we are removing them all, 828 * If we are removing them all,
829 * just delete .MAKE.EXPORTED below. 829 * just delete .MAKE.EXPORTED below.
830 */ 830 */
831 if (vlist == str) { 831 if (vlist == str) {
832 n = snprintf(tmp, sizeof(tmp), 832 n = snprintf(tmp, sizeof(tmp),
833 "${" MAKE_EXPORTED ":N%s}", v->name); 833 "${" MAKE_EXPORTED ":N%s}", v->name);
834 if (n < (int)sizeof(tmp)) { 834 if (n < (int)sizeof(tmp)) {
835 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES); 835 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARE_WANTRES);
836 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 836 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
837 free(cp); 837 free(cp);
838 } 838 }
839 } 839 }
840 } 840 }
841 free(as); 841 free(as);
842 free(av); 842 free(av);
843 if (vlist != str) { 843 if (vlist != str) {
844 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 844 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
845 free(vlist); 845 free(vlist);
846 } 846 }
847 } 847 }
848} 848}
849 849
850static void 850static void
851Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 851Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
852 VarSet_Flags flags) 852 VarSet_Flags flags)
853{ 853{
854 Var *v; 854 Var *v;
855 char *expanded_name = NULL; 855 char *expanded_name = NULL;
856 856
857 /* 857 /*
858 * We only look for a variable in the given context since anything set 858 * We only look for a variable in the given context since anything set
859 * here will override anything in a lower context, so there's not much 859 * here will override anything in a lower context, so there's not much
860 * point in searching them all just to save a bit of memory... 860 * point in searching them all just to save a bit of memory...
861 */ 861 */
862 if (strchr(name, '$') != NULL) { 862 if (strchr(name, '$') != NULL) {
863 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 863 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
864 if (expanded_name[0] == '\0') { 864 if (expanded_name[0] == '\0') {
865 if (DEBUG(VAR)) { 865 if (DEBUG(VAR)) {
866 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " 866 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
867 "name expands to empty string - ignored\n", 867 "name expands to empty string - ignored\n",
868 name, val); 868 name, val);
869 } 869 }
870 free(expanded_name); 870 free(expanded_name);
871 return; 871 return;
872 } 872 }
873 name = expanded_name; 873 name = expanded_name;
874 } 874 }
875 if (ctxt == VAR_GLOBAL) { 875 if (ctxt == VAR_GLOBAL) {
876 v = VarFind(name, VAR_CMD, 0); 876 v = VarFind(name, VAR_CMD, 0);
877 if (v != NULL) { 877 if (v != NULL) {
878 if ((v->flags & VAR_FROM_CMD)) { 878 if ((v->flags & VAR_FROM_CMD)) {
879 if (DEBUG(VAR)) { 879 if (DEBUG(VAR)) {
880 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); 880 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
881 } 881 }
882 goto out; 882 goto out;
883 } 883 }
884 VarFreeEnv(v, TRUE); 884 VarFreeEnv(v, TRUE);
885 } 885 }
886 } 886 }
887 v = VarFind(name, ctxt, 0); 887 v = VarFind(name, ctxt, 0);
888 if (v == NULL) { 888 if (v == NULL) {
889 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 889 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
890 /* 890 /*
891 * This var would normally prevent the same name being added 891 * This var would normally prevent the same name being added
892 * to VAR_GLOBAL, so delete it from there if needed. 892 * to VAR_GLOBAL, so delete it from there if needed.
893 * Otherwise -V name may show the wrong value. 893 * Otherwise -V name may show the wrong value.
894 */ 894 */
895 Var_Delete(name, VAR_GLOBAL); 895 Var_Delete(name, VAR_GLOBAL);
896 } 896 }
897 VarAdd(name, val, ctxt); 897 VarAdd(name, val, ctxt);
898 } else { 898 } else {
899 Buf_Empty(&v->val); 899 Buf_Empty(&v->val);
900 if (val) 900 if (val)
901 Buf_AddBytes(&v->val, strlen(val), val); 901 Buf_AddBytes(&v->val, strlen(val), val);
902 902
903 if (DEBUG(VAR)) { 903 if (DEBUG(VAR)) {
904 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); 904 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
905 } 905 }
906 if ((v->flags & VAR_EXPORTED)) { 906 if ((v->flags & VAR_EXPORTED)) {
907 Var_Export1(name, VAR_EXPORT_PARENT); 907 Var_Export1(name, VAR_EXPORT_PARENT);
908 } 908 }
909 } 909 }
910 /* 910 /*
911 * Any variables given on the command line are automatically exported 911 * Any variables given on the command line are automatically exported
912 * to the environment (as per POSIX standard) 912 * to the environment (as per POSIX standard)
913 */ 913 */
914 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { 914 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
915 if (v == NULL) { 915 if (v == NULL) {
916 /* we just added it */ 916 /* we just added it */
917 v = VarFind(name, ctxt, 0); 917 v = VarFind(name, ctxt, 0);
918 } 918 }
919 if (v != NULL) 919 if (v != NULL)
920 v->flags |= VAR_FROM_CMD; 920 v->flags |= VAR_FROM_CMD;
921 /* 921 /*
922 * If requested, don't export these in the environment 922 * If requested, don't export these in the environment
923 * individually. We still put them in MAKEOVERRIDES so 923 * individually. We still put them in MAKEOVERRIDES so
924 * that the command-line settings continue to override 924 * that the command-line settings continue to override
925 * Makefile settings. 925 * Makefile settings.
926 */ 926 */
927 if (varNoExportEnv != TRUE) 927 if (varNoExportEnv != TRUE)
928 setenv(name, val ? val : "", 1); 928 setenv(name, val ? val : "", 1);
929 929
930 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 930 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
931 } 931 }
932 if (*name == '.') { 932 if (*name == '.') {
933 if (strcmp(name, SAVE_DOLLARS) == 0) 933 if (strcmp(name, SAVE_DOLLARS) == 0)
934 save_dollars = s2Boolean(val, save_dollars); 934 save_dollars = s2Boolean(val, save_dollars);
935 } 935 }
936 936
937out: 937out:
938 free(expanded_name); 938 free(expanded_name);
939 if (v != NULL) 939 if (v != NULL)
940 VarFreeEnv(v, TRUE); 940 VarFreeEnv(v, TRUE);
941} 941}
942 942
943/*- 943/*-
944 *----------------------------------------------------------------------- 944 *-----------------------------------------------------------------------
945 * Var_Set -- 945 * Var_Set --
946 * Set the variable name to the value val in the given context. 946 * Set the variable name to the value val in the given context.
947 * 947 *
948 * Input: 948 * Input:
949 * name name of variable to set 949 * name name of variable to set
950 * val value to give to the variable 950 * val value to give to the variable
951 * ctxt context in which to set it 951 * ctxt context in which to set it
952 * 952 *
953 * Side Effects: 953 * Side Effects:
954 * If the variable doesn't yet exist, a new record is created for it. 954 * If the variable doesn't yet exist, a new record is created for it.
955 * Else the old value is freed and the new one stuck in its place 955 * Else the old value is freed and the new one stuck in its place
956 * 956 *
957 * Notes: 957 * Notes:
958 * The variable is searched for only in its context before being 958 * The variable is searched for only in its context before being
959 * created in that context. I.e. if the context is VAR_GLOBAL, 959 * created in that context. I.e. if the context is VAR_GLOBAL,
960 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 960 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
961 * VAR_CMD->context is searched. This is done to avoid the literally 961 * VAR_CMD->context is searched. This is done to avoid the literally
962 * thousands of unnecessary strcmp's that used to be done to 962 * thousands of unnecessary strcmp's that used to be done to
963 * set, say, $(@) or $(<). 963 * set, say, $(@) or $(<).
964 * If the context is VAR_GLOBAL though, we check if the variable 964 * If the context is VAR_GLOBAL though, we check if the variable
965 * was set in VAR_CMD from the command line and skip it if so. 965 * was set in VAR_CMD from the command line and skip it if so.
966 *----------------------------------------------------------------------- 966 *-----------------------------------------------------------------------
967 */ 967 */
968void 968void
969Var_Set(const char *name, const char *val, GNode *ctxt) 969Var_Set(const char *name, const char *val, GNode *ctxt)
970{ 970{
971 Var_Set_with_flags(name, val, ctxt, 0); 971 Var_Set_with_flags(name, val, ctxt, 0);
972} 972}
973 973
974/*- 974/*-
975 *----------------------------------------------------------------------- 975 *-----------------------------------------------------------------------
976 * Var_Append -- 976 * Var_Append --
977 * The variable of the given name has the given value appended to it in 977 * The variable of the given name has the given value appended to it in
978 * the given context. 978 * the given context.
979 * 979 *
980 * Input: 980 * Input:
981 * name name of variable to modify 981 * name name of variable to modify
982 * val String to append to it 982 * val String to append to it
983 * ctxt Context in which this should occur 983 * ctxt Context in which this should occur
984 * 984 *
985 * Side Effects: 985 * Side Effects:
986 * If the variable doesn't exist, it is created. Else the strings 986 * If the variable doesn't exist, it is created. Else the strings
987 * are concatenated (with a space in between). 987 * are concatenated (with a space in between).
988 * 988 *
989 * Notes: 989 * Notes:
990 * Only if the variable is being sought in the global context is the 990 * Only if the variable is being sought in the global context is the
991 * environment searched. 991 * environment searched.
992 * XXX: Knows its calling circumstances in that if called with ctxt 992 * XXX: Knows its calling circumstances in that if called with ctxt
993 * an actual target, it will only search that context since only 993 * an actual target, it will only search that context since only
994 * a local variable could be being appended to. This is actually 994 * a local variable could be being appended to. This is actually
995 * a big win and must be tolerated. 995 * a big win and must be tolerated.
996 *----------------------------------------------------------------------- 996 *-----------------------------------------------------------------------
997 */ 997 */
998void 998void
999Var_Append(const char *name, const char *val, GNode *ctxt) 999Var_Append(const char *name, const char *val, GNode *ctxt)
1000{ 1000{
1001 Var *v; 1001 Var *v;
1002 Hash_Entry *h; 1002 Hash_Entry *h;
1003 char *expanded_name = NULL; 1003 char *expanded_name = NULL;
1004 1004
1005 if (strchr(name, '$') != NULL) { 1005 if (strchr(name, '$') != NULL) {
1006 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 1006 expanded_name = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
1007 if (expanded_name[0] == '\0') { 1007 if (expanded_name[0] == '\0') {
1008 if (DEBUG(VAR)) { 1008 if (DEBUG(VAR)) {
1009 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " 1009 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
1010 "name expands to empty string - ignored\n", 1010 "name expands to empty string - ignored\n",
1011 name, val); 1011 name, val);
1012 } 1012 }
1013 free(expanded_name); 1013 free(expanded_name);
1014 return; 1014 return;
1015 } 1015 }
1016 name = expanded_name; 1016 name = expanded_name;
1017 } 1017 }
1018 1018
1019 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); 1019 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0);
1020 1020
1021 if (v == NULL) { 1021 if (v == NULL) {
1022 Var_Set(name, val, ctxt); 1022 Var_Set(name, val, ctxt);
1023 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { 1023 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
1024 Buf_AddByte(&v->val, ' '); 1024 Buf_AddByte(&v->val, ' ');
1025 Buf_AddBytes(&v->val, strlen(val), val); 1025 Buf_AddBytes(&v->val, strlen(val), val);
1026 1026
1027 if (DEBUG(VAR)) { 1027 if (DEBUG(VAR)) {
1028 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, 1028 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
1029 Buf_GetAll(&v->val, NULL)); 1029 Buf_GetAll(&v->val, NULL));
1030 } 1030 }
1031 1031
1032 if (v->flags & VAR_FROM_ENV) { 1032 if (v->flags & VAR_FROM_ENV) {
1033 /* 1033 /*
1034 * If the original variable came from the environment, we 1034 * If the original variable came from the environment, we
1035 * have to install it in the global context (we could place 1035 * have to install it in the global context (we could place
1036 * it in the environment, but then we should provide a way to 1036 * it in the environment, but then we should provide a way to
1037 * export other variables...) 1037 * export other variables...)
1038 */ 1038 */
1039 v->flags &= ~VAR_FROM_ENV; 1039 v->flags &= ~VAR_FROM_ENV;
1040 h = Hash_CreateEntry(&ctxt->context, name, NULL); 1040 h = Hash_CreateEntry(&ctxt->context, name, NULL);
1041 Hash_SetValue(h, v); 1041 Hash_SetValue(h, v);
1042 } 1042 }
1043 } 1043 }
1044 free(expanded_name); 1044 free(expanded_name);
1045} 1045}
1046 1046
1047/*- 1047/*-
1048 *----------------------------------------------------------------------- 1048 *-----------------------------------------------------------------------
1049 * Var_Exists -- 1049 * Var_Exists --
1050 * See if the given variable exists. 1050 * See if the given variable exists.
1051 * 1051 *
1052 * Input: 1052 * Input:
1053 * name Variable to find 1053 * name Variable to find
1054 * ctxt Context in which to start search 1054 * ctxt Context in which to start search
1055 * 1055 *
1056 * Results: 1056 * Results:
1057 * TRUE if it does, FALSE if it doesn't 1057 * TRUE if it does, FALSE if it doesn't
1058 * 1058 *
1059 * Side Effects: 1059 * Side Effects:
1060 * None. 1060 * None.
1061 * 1061 *
1062 *----------------------------------------------------------------------- 1062 *-----------------------------------------------------------------------
1063 */ 1063 */
1064Boolean 1064Boolean
1065Var_Exists(const char *name, GNode *ctxt) 1065Var_Exists(const char *name, GNode *ctxt)
1066{ 1066{
1067 Var *v; 1067 Var *v;
1068 char *cp; 1068 char *cp;
1069 1069
1070 if ((cp = strchr(name, '$')) != NULL) 1070 if ((cp = strchr(name, '$')) != NULL)
1071 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES); 1071 cp = Var_Subst(NULL, name, ctxt, VARE_WANTRES);
1072 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); 1072 v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV);
1073 free(cp); 1073 free(cp);
1074 if (v == NULL) 1074 if (v == NULL)
1075 return FALSE; 1075 return FALSE;
1076 1076
1077 (void)VarFreeEnv(v, TRUE); 1077 (void)VarFreeEnv(v, TRUE);
1078 return TRUE; 1078 return TRUE;
1079} 1079}
1080 1080
1081/*- 1081/*-
1082 *----------------------------------------------------------------------- 1082 *-----------------------------------------------------------------------
1083 * Var_Value -- 1083 * Var_Value --
1084 * Return the value of the named variable in the given context 1084 * Return the value of the named variable in the given context
1085 * 1085 *
1086 * Input: 1086 * Input:
1087 * name name to find 1087 * name name to find
1088 * ctxt context in which to search for it 1088 * ctxt context in which to search for it
1089 * 1089 *
1090 * Results: 1090 * Results:
1091 * The value if the variable exists, NULL if it doesn't 1091 * The value if the variable exists, NULL if it doesn't
1092 * 1092 *
1093 * Side Effects: 1093 * Side Effects:
1094 * None 1094 * None
1095 *----------------------------------------------------------------------- 1095 *-----------------------------------------------------------------------
1096 */ 1096 */
1097char * 1097char *
1098Var_Value(const char *name, GNode *ctxt, char **frp) 1098Var_Value(const char *name, GNode *ctxt, char **frp)
1099{ 1099{
1100 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1100 Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1101 *frp = NULL; 1101 *frp = NULL;
1102 if (v == NULL) 1102 if (v == NULL)
1103 return NULL; 1103 return NULL;
1104 1104
1105 char *p = Buf_GetAll(&v->val, NULL); 1105 char *p = Buf_GetAll(&v->val, NULL);
1106 if (VarFreeEnv(v, FALSE)) 1106 if (VarFreeEnv(v, FALSE))
1107 *frp = p; 1107 *frp = p;
1108 return p; 1108 return p;
1109} 1109}
1110 1110
1111 1111
1112/* This callback for VarModify gets a single word from an expression and 1112/* This callback for VarModify gets a single word from an expression and
1113 * typically adds a modification of this word to the buffer. It may also do 1113 * typically adds a modification of this word to the buffer. It may also do
1114 * nothing or add several words. 1114 * nothing or add several words.
1115 * 1115 *
1116 * If addSpaces is TRUE, it must add a space before adding anything else to 1116 * If addSpaces is TRUE, it must add a space before adding anything else to
1117 * the buffer. 1117 * the buffer.
1118 * 1118 *
1119 * It returns the addSpace value for the next call of this callback. Typical 1119 * It returns the addSpace value for the next call of this callback. Typical
1120 * return values are the current addSpaces or TRUE. */ 1120 * return values are the current addSpaces or TRUE. */
1121typedef Boolean (*VarModifyCallback)(GNode *ctxt, Var_Parse_State *vpstate, 1121typedef Boolean (*VarModifyCallback)(GNode *ctxt, Var_Parse_State *vpstate,
1122 const char *word, Boolean addSpace, Buffer *buf, void *data); 1122 const char *word, Boolean addSpace, Buffer *buf, void *data);
1123 1123
1124 1124
1125/* Callback function for VarModify to implement the :H modifier. 1125/* Callback function for VarModify to implement the :H modifier.
1126 * Add the dirname of the given word to the buffer. */ 1126 * Add the dirname of the given word to the buffer. */
1127static Boolean 1127static Boolean
1128VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1128VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1129 const char *word, Boolean addSpace, Buffer *buf, 1129 const char *word, Boolean addSpace, Buffer *buf,
1130 void *dummy MAKE_ATTR_UNUSED) 1130 void *dummy MAKE_ATTR_UNUSED)
1131{ 1131{
1132 const char *slash = strrchr(word, '/'); 1132 const char *slash = strrchr(word, '/');
1133 1133
1134 if (addSpace && vpstate->varSpace) 1134 if (addSpace && vpstate->varSpace)
1135 Buf_AddByte(buf, vpstate->varSpace); 1135 Buf_AddByte(buf, vpstate->varSpace);
1136 if (slash != NULL) 1136 if (slash != NULL)
1137 Buf_AddBytes(buf, slash - word, word); 1137 Buf_AddBytes(buf, slash - word, word);
1138 else 1138 else
1139 Buf_AddByte(buf, '.'); 1139 Buf_AddByte(buf, '.');
1140 1140
1141 return TRUE; 1141 return TRUE;
1142} 1142}
1143 1143
1144/* Callback function for VarModify to implement the :T modifier. 1144/* Callback function for VarModify to implement the :T modifier.
1145 * Add the basename of the given word to the buffer. */ 1145 * Add the basename of the given word to the buffer. */
1146static Boolean 1146static Boolean
1147VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1147VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1148 const char *word, Boolean addSpace, Buffer *buf, 1148 const char *word, Boolean addSpace, Buffer *buf,
1149 void *dummy MAKE_ATTR_UNUSED) 1149 void *dummy MAKE_ATTR_UNUSED)
1150{ 1150{
1151 const char *slash = strrchr(word, '/'); 1151 const char *slash = strrchr(word, '/');
1152 const char *base = slash != NULL ? slash + 1 : word; 1152 const char *base = slash != NULL ? slash + 1 : word;
1153 1153
1154 if (addSpace && vpstate->varSpace != '\0') 1154 if (addSpace && vpstate->varSpace != '\0')
1155 Buf_AddByte(buf, vpstate->varSpace); 1155 Buf_AddByte(buf, vpstate->varSpace);
1156 Buf_AddBytes(buf, strlen(base), base); 1156 Buf_AddBytes(buf, strlen(base), base);
1157 return TRUE; 1157 return TRUE;
1158} 1158}
1159 1159
1160/* Callback function for VarModify to implement the :E modifier. 1160/* Callback function for VarModify to implement the :E modifier.
1161 * Add the filename suffix of the given word to the buffer, if it exists. */ 1161 * Add the filename suffix of the given word to the buffer, if it exists. */
1162static Boolean 1162static Boolean
1163VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1163VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1164 const char *word, Boolean addSpace, Buffer *buf, 1164 const char *word, Boolean addSpace, Buffer *buf,
1165 void *dummy MAKE_ATTR_UNUSED) 1165 void *dummy MAKE_ATTR_UNUSED)
1166{ 1166{
1167 const char *dot = strrchr(word, '.'); 1167 const char *dot = strrchr(word, '.');
1168 if (dot == NULL) 1168 if (dot == NULL)
1169 return addSpace; 1169 return addSpace;
1170 1170
1171 if (addSpace && vpstate->varSpace != '\0') 1171 if (addSpace && vpstate->varSpace != '\0')
1172 Buf_AddByte(buf, vpstate->varSpace); 1172 Buf_AddByte(buf, vpstate->varSpace);
1173 Buf_AddBytes(buf, strlen(dot + 1), dot + 1); 1173 Buf_AddBytes(buf, strlen(dot + 1), dot + 1);
1174 return TRUE; 1174 return TRUE;
1175} 1175}
1176 1176
1177/* Callback function for VarModify to implement the :R modifier. 1177/* Callback function for VarModify to implement the :R modifier.
1178 * Add the filename basename of the given word to the buffer. */ 1178 * Add the filename basename of the given word to the buffer. */
1179static Boolean 1179static Boolean
1180VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1180VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1181 const char *word, Boolean addSpace, Buffer *buf, 1181 const char *word, Boolean addSpace, Buffer *buf,
1182 void *dummy MAKE_ATTR_UNUSED) 1182 void *dummy MAKE_ATTR_UNUSED)
1183{ 1183{
1184 char *dot = strrchr(word, '.'); 1184 char *dot = strrchr(word, '.');
1185 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1185 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1186 1186
1187 if (addSpace && vpstate->varSpace != '\0') 1187 if (addSpace && vpstate->varSpace != '\0')
1188 Buf_AddByte(buf, vpstate->varSpace); 1188 Buf_AddByte(buf, vpstate->varSpace);
1189 Buf_AddBytes(buf, len, word); 1189 Buf_AddBytes(buf, len, word);
1190 return TRUE; 1190 return TRUE;
1191} 1191}
1192 1192
1193/* Callback function for VarModify to implement the :M modifier. 1193/* Callback function for VarModify to implement the :M modifier.
1194 * Place the word in the buffer if it matches the given pattern. */ 1194 * Place the word in the buffer if it matches the given pattern. */
1195static Boolean 1195static Boolean
1196VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1196VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1197 const char *word, Boolean addSpace, Buffer *buf, 1197 const char *word, Boolean addSpace, Buffer *buf,
1198 void *data) 1198 void *data)
1199{ 1199{
1200 const char *pattern = data; 1200 const char *pattern = data;
1201 if (DEBUG(VAR)) 1201 if (DEBUG(VAR))
1202 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern); 1202 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
1203 if (!Str_Match(word, pattern)) 1203 if (!Str_Match(word, pattern))
1204 return addSpace; 1204 return addSpace;
1205 if (addSpace && vpstate->varSpace != '\0') 1205 if (addSpace && vpstate->varSpace != '\0')
1206 Buf_AddByte(buf, vpstate->varSpace); 1206 Buf_AddByte(buf, vpstate->varSpace);
1207 Buf_AddBytes(buf, strlen(word), word); 1207 Buf_AddBytes(buf, strlen(word), word);
1208 return TRUE; 1208 return TRUE;
1209} 1209}
1210 1210
1211#ifdef SYSVVARSUB 1211#ifdef SYSVVARSUB
1212/*- 1212/*-
1213 *----------------------------------------------------------------------- 1213 *-----------------------------------------------------------------------
1214 * Str_SYSVMatch -- 1214 * Str_SYSVMatch --
1215 * Check word against pattern for a match (% is wild), 1215 * Check word against pattern for a match (% is wild),
1216 * 1216 *
1217 * Input: 1217 * Input:
1218 * word Word to examine 1218 * word Word to examine
1219 * pattern Pattern to examine against 1219 * pattern Pattern to examine against
1220 * len Number of characters to substitute 1220 * len Number of characters to substitute
1221 * 1221 *
1222 * Results: 1222 * Results:
1223 * Returns the beginning position of a match or null. The number 1223 * Returns the beginning position of a match or null. The number
1224 * of characters matched is returned in len. 1224 * of characters matched is returned in len.
1225 * 1225 *
1226 * Side Effects: 1226 * Side Effects:
1227 * None 1227 * None
1228 * 1228 *
1229 *----------------------------------------------------------------------- 1229 *-----------------------------------------------------------------------
1230 */ 1230 */
1231static char * 1231static char *
1232Str_SYSVMatch(const char *word, const char *pattern, size_t *len, 1232Str_SYSVMatch(const char *word, const char *pattern, size_t *len,
1233 Boolean *hasPercent) 1233 Boolean *hasPercent)
1234{ 1234{
1235 const char *p = pattern; 1235 const char *p = pattern;
1236 const char *w = word; 1236 const char *w = word;
1237 const char *m; 1237 const char *m;
1238 1238
1239 *hasPercent = FALSE; 1239 *hasPercent = FALSE;
1240 if (*p == '\0') { 1240 if (*p == '\0') {
1241 /* Null pattern is the whole string */ 1241 /* Null pattern is the whole string */
1242 *len = strlen(w); 1242 *len = strlen(w);
1243 return UNCONST(w); 1243 return UNCONST(w);
1244 } 1244 }
1245 1245
1246 if ((m = strchr(p, '%')) != NULL) { 1246 if ((m = strchr(p, '%')) != NULL) {
1247 *hasPercent = TRUE; 1247 *hasPercent = TRUE;
1248 if (*w == '\0') { 1248 if (*w == '\0') {
1249 /* empty word does not match pattern */ 1249 /* empty word does not match pattern */
1250 return NULL; 1250 return NULL;
1251 } 1251 }
1252 /* check that the prefix matches */ 1252 /* check that the prefix matches */
1253 for (; p != m && *w && *w == *p; w++, p++) 1253 for (; p != m && *w && *w == *p; w++, p++)
1254 continue; 1254 continue;
1255 1255
1256 if (p != m) 1256 if (p != m)
1257 return NULL; /* No match */ 1257 return NULL; /* No match */
1258 1258
1259 if (*++p == '\0') { 1259 if (*++p == '\0') {
1260 /* No more pattern, return the rest of the string */ 1260 /* No more pattern, return the rest of the string */
1261 *len = strlen(w); 1261 *len = strlen(w);
1262 return UNCONST(w); 1262 return UNCONST(w);
1263 } 1263 }
1264 } 1264 }
1265 1265
1266 m = w; 1266 m = w;
1267 1267
1268 /* Find a matching tail */ 1268 /* Find a matching tail */
1269 do 1269 do
1270 if (strcmp(p, w) == 0) { 1270 if (strcmp(p, w) == 0) {
1271 *len = w - m; 1271 *len = w - m;
1272 return UNCONST(m); 1272 return UNCONST(m);
1273 } 1273 }
1274 while (*w++ != '\0'); 1274 while (*w++ != '\0');
1275 1275
1276 return NULL; 1276 return NULL;
1277} 1277}
1278 1278
1279 1279
1280/*- 1280/*-
1281 *----------------------------------------------------------------------- 1281 *-----------------------------------------------------------------------
1282 * Str_SYSVSubst -- 1282 * Str_SYSVSubst --
1283 * Substitute '%' on the pattern with len characters from src. 1283 * Substitute '%' on the pattern with len characters from src.
1284 * If the pattern does not contain a '%' prepend len characters 1284 * If the pattern does not contain a '%' prepend len characters
1285 * from src. 1285 * from src.
1286 * 1286 *
1287 * Side Effects: 1287 * Side Effects:
1288 * Places result on buf 1288 * Places result on buf
1289 * 1289 *
1290 *----------------------------------------------------------------------- 1290 *-----------------------------------------------------------------------
1291 */ 1291 */
1292static void 1292static void
1293Str_SYSVSubst(Buffer *buf, const char *pat, const char *src, size_t len, 1293Str_SYSVSubst(Buffer *buf, const char *pat, const char *src, size_t len,
1294 Boolean lhsHasPercent) 1294 Boolean lhsHasPercent)
1295{ 1295{
1296 const char *m; 1296 const char *m;
1297 1297
1298 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) { 1298 if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) {
1299 /* Copy the prefix */ 1299 /* Copy the prefix */
1300 Buf_AddBytes(buf, m - pat, pat); 1300 Buf_AddBytes(buf, m - pat, pat);
1301 /* skip the % */ 1301 /* skip the % */
1302 pat = m + 1; 1302 pat = m + 1;
1303 } 1303 }
1304 if (m != NULL || !lhsHasPercent) { 1304 if (m != NULL || !lhsHasPercent) {
1305 /* Copy the pattern */ 1305 /* Copy the pattern */
1306 Buf_AddBytes(buf, len, src); 1306 Buf_AddBytes(buf, len, src);
1307 } 1307 }
1308 1308
1309 /* append the rest */ 1309 /* append the rest */
1310 Buf_AddBytes(buf, strlen(pat), pat); 1310 Buf_AddBytes(buf, strlen(pat), pat);
1311} 1311}
1312 1312
1313 1313
1314/* Callback function for VarModify to implement the :%.from=%.to modifier. */ 1314/* Callback function for VarModify to implement the :%.from=%.to modifier. */
1315static Boolean 1315static Boolean
1316VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, 1316VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
1317 const char *word, Boolean addSpace, Buffer *buf, 1317 const char *word, Boolean addSpace, Buffer *buf,
1318 void *data) 1318 void *data)
1319{ 1319{
1320 size_t len; 1320 size_t len;
1321 const char *ptr; 1321 const char *ptr;
1322 Boolean hasPercent; 1322 Boolean hasPercent;
1323 VarPattern *pat = data; 1323 VarPattern *pat = data;
1324 1324
1325 if (addSpace && vpstate->varSpace != '\0') 1325 if (addSpace && vpstate->varSpace != '\0')
1326 Buf_AddByte(buf, vpstate->varSpace); 1326 Buf_AddByte(buf, vpstate->varSpace);
1327 1327
1328 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) { 1328 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
1329 char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARE_WANTRES); 1329 char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARE_WANTRES);
1330 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent); 1330 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1331 free(varexp); 1331 free(varexp);
1332 } else { 1332 } else {
1333 Buf_AddBytes(buf, strlen(word), word); 1333 Buf_AddBytes(buf, strlen(word), word);
1334 } 1334 }
1335 1335
1336 return TRUE; 1336 return TRUE;
1337} 1337}
1338#endif 1338#endif
1339 1339
1340/* Callback function for VarModify to implement the :N modifier. 1340/* Callback function for VarModify to implement the :N modifier.
1341 * Place the word in the buffer if it doesn't match the given pattern. */ 1341 * Place the word in the buffer if it doesn't match the given pattern. */
1342static Boolean 1342static Boolean
1343VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1343VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1344 const char *word, Boolean addSpace, Buffer *buf, 1344 const char *word, Boolean addSpace, Buffer *buf,
1345 void *data) 1345 void *data)
1346{ 1346{
1347 const char *pattern = data; 1347 const char *pattern = data;
1348 if (Str_Match(word, pattern)) 1348 if (Str_Match(word, pattern))
1349 return addSpace; 1349 return addSpace;
1350 if (addSpace && vpstate->varSpace != '\0') 1350 if (addSpace && vpstate->varSpace != '\0')
1351 Buf_AddByte(buf, vpstate->varSpace); 1351 Buf_AddByte(buf, vpstate->varSpace);
1352 Buf_AddBytes(buf, strlen(word), word); 1352 Buf_AddBytes(buf, strlen(word), word);
1353 return TRUE; 1353 return TRUE;
1354} 1354}
1355 1355
1356/* Callback function for VarModify to implement the :S,from,to, modifier. 1356/* Callback function for VarModify to implement the :S,from,to, modifier.
1357 * Perform a string substitution on the given word. */ 1357 * Perform a string substitution on the given word. */
1358static Boolean 1358static Boolean
1359VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1359VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1360 const char *word, Boolean addSpace, Buffer *buf, 1360 const char *word, Boolean addSpace, Buffer *buf,
1361 void *data) 1361 void *data)
1362{ 1362{
1363 int wordLen = strlen(word); 1363 int wordLen = strlen(word);
1364 const char *cp; /* General pointer */ 1364 const char *cp; /* General pointer */
1365 VarPattern *pattern = data; 1365 VarPattern *pattern = data;
1366 1366
1367 if ((pattern->pflags & (VARP_SUB_ONE | VARP_SUB_MATCHED)) != 1367 if ((pattern->pflags & (VARP_SUB_ONE | VARP_SUB_MATCHED)) !=
1368 (VARP_SUB_ONE | VARP_SUB_MATCHED)) { 1368 (VARP_SUB_ONE | VARP_SUB_MATCHED)) {
1369 /* 1369 /*
1370 * Still substituting -- break it down into simple anchored cases 1370 * Still substituting -- break it down into simple anchored cases
1371 * and if none of them fits, perform the general substitution case. 1371 * and if none of them fits, perform the general substitution case.
1372 */ 1372 */
1373 if ((pattern->pflags & VARP_MATCH_START) && 1373 if ((pattern->pflags & VARP_MATCH_START) &&
1374 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { 1374 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1375 /* 1375 /*
1376 * Anchored at start and beginning of word matches pattern 1376 * Anchored at start and beginning of word matches pattern
1377 */ 1377 */
1378 if ((pattern->pflags & VARP_MATCH_END) && 1378 if ((pattern->pflags & VARP_MATCH_END) &&
1379 (wordLen == pattern->leftLen)) { 1379 (wordLen == pattern->leftLen)) {
1380 /* 1380 /*
1381 * Also anchored at end and matches to the end (word 1381 * Also anchored at end and matches to the end (word
1382 * is same length as pattern) add space and rhs only 1382 * is same length as pattern) add space and rhs only
1383 * if rhs is non-null. 1383 * if rhs is non-null.
1384 */ 1384 */
1385 if (pattern->rightLen != 0) { 1385 if (pattern->rightLen != 0) {
1386 if (addSpace && vpstate->varSpace != '\0') { 1386 if (addSpace && vpstate->varSpace != '\0') {
1387 Buf_AddByte(buf, vpstate->varSpace); 1387 Buf_AddByte(buf, vpstate->varSpace);
1388 } 1388 }
1389 addSpace = TRUE; 1389 addSpace = TRUE;
1390 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); 1390 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1391 } 1391 }
1392 pattern->pflags |= VARP_SUB_MATCHED; 1392 pattern->pflags |= VARP_SUB_MATCHED;
1393 } else if (pattern->pflags & VARP_MATCH_END) { 1393 } else if (pattern->pflags & VARP_MATCH_END) {
1394 /* 1394 /*
1395 * Doesn't match to end -- copy word wholesale 1395 * Doesn't match to end -- copy word wholesale
1396 */ 1396 */
1397 goto nosub; 1397 goto nosub;
1398 } else { 1398 } else {
1399 /* 1399 /*
1400 * Matches at start but need to copy in trailing characters 1400 * Matches at start but need to copy in trailing characters
1401 */ 1401 */
1402 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) { 1402 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) {
1403 if (addSpace && vpstate->varSpace != '\0') { 1403 if (addSpace && vpstate->varSpace != '\0') {
1404 Buf_AddByte(buf, vpstate->varSpace); 1404 Buf_AddByte(buf, vpstate->varSpace);
1405 } 1405 }
1406 addSpace = TRUE; 1406 addSpace = TRUE;
1407 } 1407 }
1408 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); 1408 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1409 Buf_AddBytes(buf, wordLen - pattern->leftLen, 1409 Buf_AddBytes(buf, wordLen - pattern->leftLen,
1410 (word + pattern->leftLen)); 1410 (word + pattern->leftLen));
1411 pattern->pflags |= VARP_SUB_MATCHED; 1411 pattern->pflags |= VARP_SUB_MATCHED;
1412 } 1412 }
1413 } else if (pattern->pflags & VARP_MATCH_START) { 1413 } else if (pattern->pflags & VARP_MATCH_START) {
1414 /* 1414 /*
1415 * Had to match at start of word and didn't -- copy whole word. 1415 * Had to match at start of word and didn't -- copy whole word.
1416 */ 1416 */
1417 goto nosub; 1417 goto nosub;
1418 } else if (pattern->pflags & VARP_MATCH_END) { 1418 } else if (pattern->pflags & VARP_MATCH_END) {
1419 /* 1419 /*
1420 * Anchored at end, Find only place match could occur (leftLen 1420 * Anchored at end, Find only place match could occur (leftLen
1421 * characters from the end of the word) and see if it does. Note 1421 * characters from the end of the word) and see if it does. Note
1422 * that because the $ will be left at the end of the lhs, we have 1422 * that because the $ will be left at the end of the lhs, we have
1423 * to use strncmp. 1423 * to use strncmp.
1424 */ 1424 */
1425 cp = word + (wordLen - pattern->leftLen); 1425 cp = word + (wordLen - pattern->leftLen);
1426 if ((cp >= word) && 1426 if ((cp >= word) &&
1427 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { 1427 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1428 /* 1428 /*
1429 * Match found. If we will place characters in the buffer, 1429 * Match found. If we will place characters in the buffer,
1430 * add a space before hand as indicated by addSpace, then 1430 * add a space before hand as indicated by addSpace, then
1431 * stuff in the initial, unmatched part of the word followed 1431 * stuff in the initial, unmatched part of the word followed
1432 * by the right-hand-side. 1432 * by the right-hand-side.
1433 */ 1433 */
1434 if (((cp - word) + pattern->rightLen) != 0) { 1434 if (((cp - word) + pattern->rightLen) != 0) {
1435 if (addSpace && vpstate->varSpace != '\0') { 1435 if (addSpace && vpstate->varSpace != '\0') {
1436 Buf_AddByte(buf, vpstate->varSpace); 1436 Buf_AddByte(buf, vpstate->varSpace);
1437 } 1437 }
1438 addSpace = TRUE; 1438 addSpace = TRUE;
1439 } 1439 }
1440 Buf_AddBytes(buf, cp - word, word); 1440 Buf_AddBytes(buf, cp - word, word);
1441 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); 1441 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1442 pattern->pflags |= VARP_SUB_MATCHED; 1442 pattern->pflags |= VARP_SUB_MATCHED;
1443 } else { 1443 } else {
1444 /* 1444 /*
1445 * Had to match at end and didn't. Copy entire word. 1445 * Had to match at end and didn't. Copy entire word.
1446 */ 1446 */
1447 goto nosub; 1447 goto nosub;
1448 } 1448 }
1449 } else { 1449 } else {
1450 /* 1450 /*
1451 * Pattern is unanchored: search for the pattern in the word using 1451 * Pattern is unanchored: search for the pattern in the word using
1452 * String_FindSubstring, copying unmatched portions and the 1452 * String_FindSubstring, copying unmatched portions and the
1453 * right-hand-side for each match found, handling non-global 1453 * right-hand-side for each match found, handling non-global
1454 * substitutions correctly, etc. When the loop is done, any 1454 * substitutions correctly, etc. When the loop is done, any
1455 * remaining part of the word (word and wordLen are adjusted 1455 * remaining part of the word (word and wordLen are adjusted
1456 * accordingly through the loop) is copied straight into the 1456 * accordingly through the loop) is copied straight into the
1457 * buffer. 1457 * buffer.
1458 * addSpace is set FALSE as soon as a space is added to the 1458 * addSpace is set FALSE as soon as a space is added to the
1459 * buffer. 1459 * buffer.
1460 */ 1460 */
1461 Boolean done; 1461 Boolean done;
1462 int origSize; 1462 int origSize;
1463 1463
1464 done = FALSE; 1464 done = FALSE;
1465 origSize = Buf_Size(buf); 1465 origSize = Buf_Size(buf);
1466 while (!done) { 1466 while (!done) {
1467 cp = Str_FindSubstring(word, pattern->lhs); 1467 cp = Str_FindSubstring(word, pattern->lhs);
1468 if (cp != NULL) { 1468 if (cp != NULL) {
1469 if (addSpace && (((cp - word) + pattern->rightLen) != 0)) { 1469 if (addSpace && (((cp - word) + pattern->rightLen) != 0)) {
1470 Buf_AddByte(buf, vpstate->varSpace); 1470 Buf_AddByte(buf, vpstate->varSpace);
1471 addSpace = FALSE; 1471 addSpace = FALSE;
1472 } 1472 }
1473 Buf_AddBytes(buf, cp - word, word); 1473 Buf_AddBytes(buf, cp - word, word);
1474 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); 1474 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1475 wordLen -= (cp - word) + pattern->leftLen; 1475 wordLen -= (cp - word) + pattern->leftLen;
1476 word = cp + pattern->leftLen; 1476 word = cp + pattern->leftLen;
1477 if (wordLen == 0) { 1477 if (wordLen == 0) {
1478 done = TRUE; 1478 done = TRUE;
1479 } 1479 }
1480 if ((pattern->pflags & VARP_SUB_GLOBAL) == 0) { 1480 if ((pattern->pflags & VARP_SUB_GLOBAL) == 0) {
1481 done = TRUE; 1481 done = TRUE;
1482 } 1482 }
1483 pattern->pflags |= VARP_SUB_MATCHED; 1483 pattern->pflags |= VARP_SUB_MATCHED;
1484 } else { 1484 } else {
1485 done = TRUE; 1485 done = TRUE;
1486 } 1486 }
1487 } 1487 }
1488 if (wordLen != 0) { 1488 if (wordLen != 0) {
1489 if (addSpace && vpstate->varSpace != '\0') { 1489 if (addSpace && vpstate->varSpace != '\0') {
1490 Buf_AddByte(buf, vpstate->varSpace); 1490 Buf_AddByte(buf, vpstate->varSpace);
1491 } 1491 }
1492 Buf_AddBytes(buf, wordLen, word); 1492 Buf_AddBytes(buf, wordLen, word);
1493 } 1493 }
1494 /* 1494 /*
1495 * If added characters to the buffer, need to add a space 1495 * If added characters to the buffer, need to add a space
1496 * before we add any more. If we didn't add any, just return 1496 * before we add any more. If we didn't add any, just return
1497 * the previous value of addSpace. 1497 * the previous value of addSpace.
1498 */ 1498 */
1499 return (Buf_Size(buf) != origSize) || addSpace; 1499 return (Buf_Size(buf) != origSize) || addSpace;
1500 } 1500 }
1501 return addSpace; 1501 return addSpace;
1502 } 1502 }
1503nosub: 1503nosub:
1504 if (addSpace && vpstate->varSpace != '\0') { 1504 if (addSpace && vpstate->varSpace != '\0') {
1505 Buf_AddByte(buf, vpstate->varSpace); 1505 Buf_AddByte(buf, vpstate->varSpace);
1506 } 1506 }
1507 Buf_AddBytes(buf, wordLen, word); 1507 Buf_AddBytes(buf, wordLen, word);
1508 return TRUE; 1508 return TRUE;
1509} 1509}
1510 1510
1511#ifndef NO_REGEX 1511#ifndef NO_REGEX
1512/*- 1512/*-
1513 *----------------------------------------------------------------------- 1513 *-----------------------------------------------------------------------
1514 * VarREError -- 1514 * VarREError --
1515 * Print the error caused by a regcomp or regexec call. 1515 * Print the error caused by a regcomp or regexec call.
1516 * 1516 *
1517 * Side Effects: 1517 * Side Effects:
1518 * An error gets printed. 1518 * An error gets printed.
1519 * 1519 *
1520 *----------------------------------------------------------------------- 1520 *-----------------------------------------------------------------------
1521 */ 1521 */
1522static void 1522static void
1523VarREError(int reerr, regex_t *pat, const char *str) 1523VarREError(int reerr, regex_t *pat, const char *str)
1524{ 1524{
1525 char *errbuf; 1525 char *errbuf;
1526 int errlen; 1526 int errlen;
1527 1527
1528 errlen = regerror(reerr, pat, 0, 0); 1528 errlen = regerror(reerr, pat, 0, 0);
1529 errbuf = bmake_malloc(errlen); 1529 errbuf = bmake_malloc(errlen);
1530 regerror(reerr, pat, errbuf, errlen); 1530 regerror(reerr, pat, errbuf, errlen);
1531 Error("%s: %s", str, errbuf); 1531 Error("%s: %s", str, errbuf);
1532 free(errbuf); 1532 free(errbuf);
1533} 1533}
1534 1534
1535/* Callback function for VarModify to implement the :C/from/to/ modifier. 1535/* Callback function for VarModify to implement the :C/from/to/ modifier.
1536 * Perform a regex substitution on the given word. */ 1536 * Perform a regex substitution on the given word. */
1537static Boolean 1537static Boolean
1538VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, 1538VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
1539 Var_Parse_State *vpstate MAKE_ATTR_UNUSED, 1539 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1540 const char *word, Boolean addSpace, Buffer *buf, 1540 const char *word, Boolean addSpace, Buffer *buf,
1541 void *data) 1541 void *data)
1542{ 1542{
1543 VarREPattern *pat = data; 1543 VarREPattern *pat = data;
1544 int xrv; 1544 int xrv;
1545 const char *wp = word; 1545 const char *wp = word;
1546 char *rp; 1546 char *rp;
1547 int added = 0; 1547 int added = 0;
1548 int flags = 0; 1548 int flags = 0;
1549 1549
1550#define MAYBE_ADD_SPACE() \ 1550#define MAYBE_ADD_SPACE() \
1551 if (addSpace && !added) \ 1551 if (addSpace && !added) \
1552 Buf_AddByte(buf, ' '); \ 1552 Buf_AddByte(buf, ' '); \
1553 added = 1 1553 added = 1
1554 1554
1555 if ((pat->pflags & (VARP_SUB_ONE | VARP_SUB_MATCHED)) == 1555 if ((pat->pflags & (VARP_SUB_ONE | VARP_SUB_MATCHED)) ==
1556 (VARP_SUB_ONE | VARP_SUB_MATCHED)) 1556 (VARP_SUB_ONE | VARP_SUB_MATCHED))
1557 xrv = REG_NOMATCH; 1557 xrv = REG_NOMATCH;
1558 else { 1558 else {
1559 tryagain: 1559 tryagain:
1560 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); 1560 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1561 } 1561 }
1562 1562
1563 switch (xrv) { 1563 switch (xrv) {
1564 case 0: 1564 case 0:
1565 pat->pflags |= VARP_SUB_MATCHED; 1565 pat->pflags |= VARP_SUB_MATCHED;
1566 if (pat->matches[0].rm_so > 0) { 1566 if (pat->matches[0].rm_so > 0) {
1567 MAYBE_ADD_SPACE(); 1567 MAYBE_ADD_SPACE();
1568 Buf_AddBytes(buf, pat->matches[0].rm_so, wp); 1568 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1569 } 1569 }
1570 1570
1571 for (rp = pat->replace; *rp; rp++) { 1571 for (rp = pat->replace; *rp; rp++) {
1572 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { 1572 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1573 MAYBE_ADD_SPACE(); 1573 MAYBE_ADD_SPACE();
1574 Buf_AddByte(buf, rp[1]); 1574 Buf_AddByte(buf, rp[1]);
1575 rp++; 1575 rp++;
1576 } else if ((*rp == '&') || 1576 } else if ((*rp == '&') ||
1577 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { 1577 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
1578 int n; 1578 int n;
1579 const char *subbuf; 1579 const char *subbuf;
1580 int sublen; 1580 int sublen;
1581 char errstr[3]; 1581 char errstr[3];
1582 1582
1583 if (*rp == '&') { 1583 if (*rp == '&') {
1584 n = 0; 1584 n = 0;
1585 errstr[0] = '&'; 1585 errstr[0] = '&';
1586 errstr[1] = '\0'; 1586 errstr[1] = '\0';
1587 } else { 1587 } else {
1588 n = rp[1] - '0'; 1588 n = rp[1] - '0';
1589 errstr[0] = '\\'; 1589 errstr[0] = '\\';
1590 errstr[1] = rp[1]; 1590 errstr[1] = rp[1];
1591 errstr[2] = '\0'; 1591 errstr[2] = '\0';
1592 rp++; 1592 rp++;
1593 } 1593 }
1594 1594
1595 if (n > pat->nsub) { 1595 if (n > pat->nsub) {
1596 Error("No subexpression %s", &errstr[0]); 1596 Error("No subexpression %s", &errstr[0]);
1597 subbuf = ""; 1597 subbuf = "";
1598 sublen = 0; 1598 sublen = 0;
1599 } else if ((pat->matches[n].rm_so == -1) && 1599 } else if ((pat->matches[n].rm_so == -1) &&
1600 (pat->matches[n].rm_eo == -1)) { 1600 (pat->matches[n].rm_eo == -1)) {
1601 Error("No match for subexpression %s", &errstr[0]); 1601 Error("No match for subexpression %s", &errstr[0]);
1602 subbuf = ""; 1602 subbuf = "";
1603 sublen = 0; 1603 sublen = 0;
1604 } else { 1604 } else {
1605 subbuf = wp + pat->matches[n].rm_so; 1605 subbuf = wp + pat->matches[n].rm_so;
1606 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; 1606 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1607 } 1607 }
1608 1608
1609 if (sublen > 0) { 1609 if (sublen > 0) {
1610 MAYBE_ADD_SPACE(); 1610 MAYBE_ADD_SPACE();
1611 Buf_AddBytes(buf, sublen, subbuf); 1611 Buf_AddBytes(buf, sublen, subbuf);
1612 } 1612 }
1613 } else { 1613 } else {
1614 MAYBE_ADD_SPACE(); 1614 MAYBE_ADD_SPACE();
1615 Buf_AddByte(buf, *rp); 1615 Buf_AddByte(buf, *rp);
1616 } 1616 }
1617 } 1617 }
1618 wp += pat->matches[0].rm_eo; 1618 wp += pat->matches[0].rm_eo;
1619 if (pat->pflags & VARP_SUB_GLOBAL) { 1619 if (pat->pflags & VARP_SUB_GLOBAL) {
1620 flags |= REG_NOTBOL; 1620 flags |= REG_NOTBOL;
1621 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { 1621 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1622 MAYBE_ADD_SPACE(); 1622 MAYBE_ADD_SPACE();
1623 Buf_AddByte(buf, *wp); 1623 Buf_AddByte(buf, *wp);
1624 wp++; 1624 wp++;
1625 1625
1626 } 1626 }
1627 if (*wp) 1627 if (*wp)
1628 goto tryagain; 1628 goto tryagain;
1629 } 1629 }
1630 if (*wp) { 1630 if (*wp) {
1631 MAYBE_ADD_SPACE(); 1631 MAYBE_ADD_SPACE();
1632 Buf_AddBytes(buf, strlen(wp), wp); 1632 Buf_AddBytes(buf, strlen(wp), wp);
1633 } 1633 }
1634 break; 1634 break;
1635 default: 1635 default:
1636 VarREError(xrv, &pat->re, "Unexpected regex error"); 1636 VarREError(xrv, &pat->re, "Unexpected regex error");
1637 /* fall through */ 1637 /* fall through */
1638 case REG_NOMATCH: 1638 case REG_NOMATCH:
1639 if (*wp) { 1639 if (*wp) {
1640 MAYBE_ADD_SPACE(); 1640 MAYBE_ADD_SPACE();
1641 Buf_AddBytes(buf, strlen(wp), wp); 1641 Buf_AddBytes(buf, strlen(wp), wp);
1642 } 1642 }
1643 break; 1643 break;
1644 } 1644 }
1645 return addSpace || added; 1645 return addSpace || added;
1646} 1646}
1647#endif 1647#endif
1648 1648
1649 1649
1650/* Callback function for VarModify to implement the :@var@...@ modifier of 1650/* Callback function for VarModify to implement the :@var@...@ modifier of
1651 * ODE make. We set the temp variable named in pattern.lhs to word and 1651 * ODE make. We set the temp variable named in pattern.lhs to word and
1652 * expand pattern.rhs. */ 1652 * expand pattern.rhs. */
1653static Boolean 1653static Boolean
1654VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, 1654VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
1655 Var_Parse_State *vpstate MAKE_ATTR_UNUSED, 1655 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1656 const char *word, Boolean addSpace, Buffer *buf, 1656 const char *word, Boolean addSpace, Buffer *buf,
1657 void *data) 1657 void *data)
1658{ 1658{
1659 VarLoop *loop = data; 1659 VarLoop *loop = data;
1660 char *s; 1660 char *s;
1661 int slen; 1661 int slen;
1662 1662
1663 if (*word) { 1663 if (*word) {
1664 Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT); 1664 Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
1665 s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags); 1665 s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags);
1666 if (DEBUG(VAR)) { 1666 if (DEBUG(VAR)) {
1667 fprintf(debug_file, 1667 fprintf(debug_file,
1668 "VarLoopExpand: in \"%s\", replace \"%s\" with \"%s\" " 1668 "VarLoopExpand: in \"%s\", replace \"%s\" with \"%s\" "
1669 "to \"%s\"\n", 1669 "to \"%s\"\n",
1670 word, loop->tvar, loop->str, s ? s : "(null)"); 1670 word, loop->tvar, loop->str, s ? s : "(null)");
1671 } 1671 }
1672 if (s != NULL && *s != '\0') { 1672 if (s != NULL && *s != '\0') {
1673 if (addSpace && *s != '\n') 1673 if (addSpace && *s != '\n')
1674 Buf_AddByte(buf, ' '); 1674 Buf_AddByte(buf, ' ');
1675 Buf_AddBytes(buf, (slen = strlen(s)), s); 1675 Buf_AddBytes(buf, (slen = strlen(s)), s);
1676 addSpace = (slen > 0 && s[slen - 1] != '\n'); 1676 addSpace = (slen > 0 && s[slen - 1] != '\n');
1677 } 1677 }
1678 free(s); 1678 free(s);
1679 } 1679 }
1680 return addSpace; 1680 return addSpace;
1681} 1681}
1682 1682
1683 1683
1684/*- 1684/*-
1685 *----------------------------------------------------------------------- 1685 *-----------------------------------------------------------------------
1686 * VarSelectWords -- 1686 * VarSelectWords --
1687 * Implements the :[start..end] modifier. 1687 * Implements the :[start..end] modifier.
1688 * This is a special case of VarModify since we want to be able 1688 * This is a special case of VarModify since we want to be able
1689 * to scan the list backwards if start > end. 1689 * to scan the list backwards if start > end.
1690 * 1690 *
1691 * Input: 1691 * Input:
1692 * str String whose words should be trimmed 1692 * str String whose words should be trimmed
1693 * seldata words to select 1693 * seldata words to select
1694 * 1694 *
1695 * Results: 1695 * Results:
1696 * A string of all the words selected. 1696 * A string of all the words selected.
1697 * 1697 *
1698 * Side Effects: 1698 * Side Effects:
1699 * None. 1699 * None.
1700 * 1700 *
1701 *----------------------------------------------------------------------- 1701 *-----------------------------------------------------------------------
1702 */ 1702 */
1703static char * 1703static char *
1704VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1704VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1705 const char *str, VarSelectWords_t *seldata) 1705 const char *str, VarSelectWords_t *seldata)
1706{ 1706{
1707 Buffer buf; /* Buffer for the new string */ 1707 Buffer buf; /* Buffer for the new string */
1708 Boolean addSpace; /* TRUE if need to add a space to the 1708 Boolean addSpace; /* TRUE if need to add a space to the
1709 * buffer before adding the trimmed 1709 * buffer before adding the trimmed
1710 * word */ 1710 * word */
1711 char **av; /* word list */ 1711 char **av; /* word list */
1712 char *as; /* word list memory */ 1712 char *as; /* word list memory */
1713 int ac, i; 1713 int ac, i;
1714 int start, end, step; 1714 int start, end, step;
1715 1715
1716 Buf_Init(&buf, 0); 1716 Buf_Init(&buf, 0);
1717 addSpace = FALSE; 1717 addSpace = FALSE;
1718 1718
1719 if (vpstate->oneBigWord) { 1719 if (vpstate->oneBigWord) {
1720 /* fake what brk_string() would do if there were only one word */ 1720 /* fake what brk_string() would do if there were only one word */
1721 ac = 1; 1721 ac = 1;
1722 av = bmake_malloc((ac + 1) * sizeof(char *)); 1722 av = bmake_malloc((ac + 1) * sizeof(char *));
1723 as = bmake_strdup(str); 1723 as = bmake_strdup(str);
1724 av[0] = as; 1724 av[0] = as;
1725 av[1] = NULL; 1725 av[1] = NULL;
1726 } else { 1726 } else {
1727 av = brk_string(str, &ac, FALSE, &as); 1727 av = brk_string(str, &ac, FALSE, &as);
1728 } 1728 }
1729 1729
1730 /* 1730 /*
1731 * Now sanitize seldata. 1731 * Now sanitize seldata.
1732 * If seldata->start or seldata->end are negative, convert them to 1732 * If seldata->start or seldata->end are negative, convert them to
1733 * the positive equivalents (-1 gets converted to argc, -2 gets 1733 * the positive equivalents (-1 gets converted to argc, -2 gets
1734 * converted to (argc-1), etc.). 1734 * converted to (argc-1), etc.).
1735 */ 1735 */
1736 if (seldata->start < 0) 1736 if (seldata->start < 0)
1737 seldata->start = ac + seldata->start + 1; 1737 seldata->start = ac + seldata->start + 1;
1738 if (seldata->end < 0) 1738 if (seldata->end < 0)
1739 seldata->end = ac + seldata->end + 1; 1739 seldata->end = ac + seldata->end + 1;
1740 1740
1741 /* 1741 /*
1742 * We avoid scanning more of the list than we need to. 1742 * We avoid scanning more of the list than we need to.
1743 */ 1743 */
1744 if (seldata->start > seldata->end) { 1744 if (seldata->start > seldata->end) {
1745 start = MIN(ac, seldata->start) - 1; 1745 start = MIN(ac, seldata->start) - 1;
1746 end = MAX(0, seldata->end - 1); 1746 end = MAX(0, seldata->end - 1);
1747 step = -1; 1747 step = -1;
1748 } else { 1748 } else {
1749 start = MAX(0, seldata->start - 1); 1749 start = MAX(0, seldata->start - 1);
1750 end = MIN(ac, seldata->end); 1750 end = MIN(ac, seldata->end);
1751 step = 1; 1751 step = 1;
1752 } 1752 }
1753 1753
1754 for (i = start; 1754 for (i = start;
1755 (step < 0 && i >= end) || (step > 0 && i < end); 1755 (step < 0 && i >= end) || (step > 0 && i < end);
1756 i += step) { 1756 i += step) {
1757 if (av[i] && *av[i]) { 1757 if (av[i] && *av[i]) {
1758 if (addSpace && vpstate->varSpace != '\0') { 1758 if (addSpace && vpstate->varSpace != '\0') {
1759 Buf_AddByte(&buf, vpstate->varSpace); 1759 Buf_AddByte(&buf, vpstate->varSpace);
1760 } 1760 }
1761 Buf_AddBytes(&buf, strlen(av[i]), av[i]); 1761 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1762 addSpace = TRUE; 1762 addSpace = TRUE;
1763 } 1763 }
1764 } 1764 }
1765 1765
1766 free(as); 1766 free(as);
1767 free(av); 1767 free(av);
1768 1768
1769 return Buf_Destroy(&buf, FALSE); 1769 return Buf_Destroy(&buf, FALSE);
1770} 1770}
1771 1771
1772 1772
1773/* Callback function for VarModify to implement the :tA modifier. 1773/* Callback function for VarModify to implement the :tA modifier.
1774 * Replace each word with the result of realpath() if successful. */ 1774 * Replace each word with the result of realpath() if successful. */
1775static Boolean 1775static Boolean
1776VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, 1776VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1777 const char *word, Boolean addSpace, Buffer *buf, 1777 const char *word, Boolean addSpace, Buffer *buf,
1778 void *patternp MAKE_ATTR_UNUSED) 1778 void *patternp MAKE_ATTR_UNUSED)
1779{ 1779{
1780 struct stat st; 1780 struct stat st;
1781 char rbuf[MAXPATHLEN]; 1781 char rbuf[MAXPATHLEN];
1782 char *rp; 1782 char *rp;
1783 1783
1784 if (addSpace && vpstate->varSpace != '\0') 1784 if (addSpace && vpstate->varSpace != '\0')
1785 Buf_AddByte(buf, vpstate->varSpace); 1785 Buf_AddByte(buf, vpstate->varSpace);
1786 rp = cached_realpath(word, rbuf); 1786 rp = cached_realpath(word, rbuf);
1787 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1787 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1788 word = rp; 1788 word = rp;
1789 1789
1790 Buf_AddBytes(buf, strlen(word), word); 1790 Buf_AddBytes(buf, strlen(word), word);
1791 return TRUE; 1791 return TRUE;
1792} 1792}
1793 1793
1794/*- 1794/*-
1795 *----------------------------------------------------------------------- 1795 *-----------------------------------------------------------------------
1796 * Modify each of the words of the passed string using the given function. 1796 * Modify each of the words of the passed string using the given function.
1797 * 1797 *
1798 * Input: 1798 * Input:
1799 * str String whose words should be trimmed 1799 * str String whose words should be trimmed
1800 * modProc Function to use to modify them 1800 * modProc Function to use to modify them
1801 * data Custom data for the modProc 1801 * data Custom data for the modProc
1802 * 1802 *
1803 * Results: 1803 * Results:
1804 * A string of all the words modified appropriately. 1804 * A string of all the words modified appropriately.
1805 * 1805 *
1806 * Side Effects: 1806 * Side Effects:
1807 * None. 1807 * None.
1808 * 1808 *
1809 *----------------------------------------------------------------------- 1809 *-----------------------------------------------------------------------
1810 */ 1810 */
1811static char * 1811static char *
1812VarModify(GNode *ctx, Var_Parse_State *vpstate, 1812VarModify(GNode *ctx, Var_Parse_State *vpstate,
1813 const char *str, VarModifyCallback modProc, void *datum) 1813 const char *str, VarModifyCallback modProc, void *datum)
1814{ 1814{
1815 Buffer buf; /* Buffer for the new string */ 1815 Buffer buf; /* Buffer for the new string */
1816 Boolean addSpace; /* TRUE if need to add a space to the 1816 Boolean addSpace; /* TRUE if need to add a space to the
1817 * buffer before adding the trimmed word */ 1817 * buffer before adding the trimmed word */
1818 char **av; /* word list */ 1818 char **av; /* word list */
1819 char *as; /* word list memory */ 1819 char *as; /* word list memory */
1820 int ac, i; 1820 int ac, i;
1821 1821
1822 Buf_Init(&buf, 0); 1822 Buf_Init(&buf, 0);
1823 addSpace = FALSE; 1823 addSpace = FALSE;
1824 1824
1825 if (vpstate->oneBigWord) { 1825 if (vpstate->oneBigWord) {
1826 /* fake what brk_string() would do if there were only one word */ 1826 /* fake what brk_string() would do if there were only one word */
1827 ac = 1; 1827 ac = 1;
1828 av = bmake_malloc((ac + 1) * sizeof(char *)); 1828 av = bmake_malloc((ac + 1) * sizeof(char *));
1829 as = bmake_strdup(str); 1829 as = bmake_strdup(str);
1830 av[0] = as; 1830 av[0] = as;
1831 av[1] = NULL; 1831 av[1] = NULL;
1832 } else { 1832 } else {
1833 av = brk_string(str, &ac, FALSE, &as); 1833 av = brk_string(str, &ac, FALSE, &as);
1834 } 1834 }
1835 1835
1836 if (DEBUG(VAR)) { 1836 if (DEBUG(VAR)) {
1837 fprintf(debug_file, "VarModify: split \"%s\" into %d words\n", 1837 fprintf(debug_file, "VarModify: split \"%s\" into %d words\n",
1838 str, ac); 1838 str, ac);
1839 } 1839 }
1840 1840
1841 for (i = 0; i < ac; i++) 1841 for (i = 0; i < ac; i++)
1842 addSpace = modProc(ctx, vpstate, av[i], addSpace, &buf, datum); 1842 addSpace = modProc(ctx, vpstate, av[i], addSpace, &buf, datum);
1843 1843
1844 free(as); 1844 free(as);
1845 free(av); 1845 free(av);
1846 1846
1847 return Buf_Destroy(&buf, FALSE); 1847 return Buf_Destroy(&buf, FALSE);
1848} 1848}
1849 1849
1850 1850
1851static int 1851static int
1852VarWordCompare(const void *a, const void *b) 1852VarWordCompare(const void *a, const void *b)
1853{ 1853{
1854 int r = strcmp(*(const char * const *)a, *(const char * const *)b); 1854 int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1855 return r; 1855 return r;
1856} 1856}
1857 1857
1858static int 1858static int
1859VarWordCompareReverse(const void *a, const void *b) 1859VarWordCompareReverse(const void *a, const void *b)
1860{ 1860{
1861 int r = strcmp(*(const char * const *)b, *(const char * const *)a); 1861 int r = strcmp(*(const char * const *)b, *(const char * const *)a);
1862 return r; 1862 return r;
1863} 1863}
1864 1864
1865/*- 1865/*-
1866 *----------------------------------------------------------------------- 1866 *-----------------------------------------------------------------------
1867 * VarOrder -- 1867 * VarOrder --
1868 * Order the words in the string. 1868 * Order the words in the string.
1869 * 1869 *
1870 * Input: 1870 * Input:
1871 * str String whose words should be sorted. 1871 * str String whose words should be sorted.
1872 * otype How to order: s - sort, x - random. 1872 * otype How to order: s - sort, x - random.
1873 * 1873 *
1874 * Results: 1874 * Results:
1875 * A string containing the words ordered. 1875 * A string containing the words ordered.
1876 * 1876 *
1877 * Side Effects: 1877 * Side Effects:
1878 * None. 1878 * None.
1879 * 1879 *
1880 *----------------------------------------------------------------------- 1880 *-----------------------------------------------------------------------
1881 */ 1881 */
1882static char * 1882static char *
1883VarOrder(const char *str, const char otype) 1883VarOrder(const char *str, const char otype)
1884{ 1884{
1885 Buffer buf; /* Buffer for the new string */ 1885 Buffer buf; /* Buffer for the new string */
1886 char **av; /* word list [first word does not count] */ 1886 char **av; /* word list [first word does not count] */
1887 char *as; /* word list memory */ 1887 char *as; /* word list memory */
1888 int ac, i; 1888 int ac, i;
1889 1889
1890 Buf_Init(&buf, 0); 1890 Buf_Init(&buf, 0);
1891 1891
1892 av = brk_string(str, &ac, FALSE, &as); 1892 av = brk_string(str, &ac, FALSE, &as);
1893 1893
1894 if (ac > 0) { 1894 if (ac > 0) {
1895 switch (otype) { 1895 switch (otype) {
1896 case 'r': /* reverse sort alphabetically */ 1896 case 'r': /* reverse sort alphabetically */
1897 qsort(av, ac, sizeof(char *), VarWordCompareReverse); 1897 qsort(av, ac, sizeof(char *), VarWordCompareReverse);
1898 break; 1898 break;
1899 case 's': /* sort alphabetically */ 1899 case 's': /* sort alphabetically */
1900 qsort(av, ac, sizeof(char *), VarWordCompare); 1900 qsort(av, ac, sizeof(char *), VarWordCompare);
1901 break; 1901 break;
1902 case 'x': /* randomize */ 1902 case 'x': /* randomize */
1903 { 1903 {
1904 /* 1904 /*
1905 * We will use [ac..2] range for mod factors. This will produce 1905 * We will use [ac..2] range for mod factors. This will produce
1906 * random numbers in [(ac-1)..0] interval, and minimal 1906 * random numbers in [(ac-1)..0] interval, and minimal
1907 * reasonable value for mod factor is 2 (the mod 1 will produce 1907 * reasonable value for mod factor is 2 (the mod 1 will produce
1908 * 0 with probability 1). 1908 * 0 with probability 1).
1909 */ 1909 */
1910 for (i = ac - 1; i > 0; i--) { 1910 for (i = ac - 1; i > 0; i--) {
1911 int rndidx = random() % (i + 1); 1911 int rndidx = random() % (i + 1);
1912 char *t = av[i]; 1912 char *t = av[i];
1913 av[i] = av[rndidx]; 1913 av[i] = av[rndidx];
1914 av[rndidx] = t; 1914 av[rndidx] = t;
1915 } 1915 }
1916 } 1916 }
1917 } 1917 }
1918 } 1918 }
1919 1919
1920 for (i = 0; i < ac; i++) { 1920 for (i = 0; i < ac; i++) {
1921 Buf_AddBytes(&buf, strlen(av[i]), av[i]); 1921 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1922 if (i != ac - 1) 1922 if (i != ac - 1)
1923 Buf_AddByte(&buf, ' '); 1923 Buf_AddByte(&buf, ' ');
1924 } 1924 }
1925 1925
1926 free(as); 1926 free(as);
1927 free(av); 1927 free(av);
1928 1928
1929 return Buf_Destroy(&buf, FALSE); 1929 return Buf_Destroy(&buf, FALSE);
1930} 1930}
1931 1931
1932 1932
1933/*- 1933/*-
1934 *----------------------------------------------------------------------- 1934 *-----------------------------------------------------------------------
1935 * VarUniq -- 1935 * VarUniq --
1936 * Remove adjacent duplicate words. 1936 * Remove adjacent duplicate words.
1937 * 1937 *
1938 * Input: 1938 * Input:
1939 * str String whose words should be sorted 1939 * str String whose words should be sorted
1940 * 1940 *
1941 * Results: 1941 * Results:
1942 * A string containing the resulting words. 1942 * A string containing the resulting words.
1943 * 1943 *
1944 * Side Effects: 1944 * Side Effects:
1945 * None. 1945 * None.
1946 * 1946 *
1947 *----------------------------------------------------------------------- 1947 *-----------------------------------------------------------------------
1948 */ 1948 */
1949static char * 1949static char *
1950VarUniq(const char *str) 1950VarUniq(const char *str)
1951{ 1951{
1952 Buffer buf; /* Buffer for new string */ 1952 Buffer buf; /* Buffer for new string */
1953 char **av; /* List of words to affect */ 1953 char **av; /* List of words to affect */
1954 char *as; /* Word list memory */ 1954 char *as; /* Word list memory */
1955 int ac, i, j; 1955 int ac, i, j;
1956 1956
1957 Buf_Init(&buf, 0); 1957 Buf_Init(&buf, 0);
1958 av = brk_string(str, &ac, FALSE, &as); 1958 av = brk_string(str, &ac, FALSE, &as);
1959 1959
1960 if (ac > 1) { 1960 if (ac > 1) {
1961 for (j = 0, i = 1; i < ac; i++) 1961 for (j = 0, i = 1; i < ac; i++)
1962 if (strcmp(av[i], av[j]) != 0 && (++j != i)) 1962 if (strcmp(av[i], av[j]) != 0 && (++j != i))
1963 av[j] = av[i]; 1963 av[j] = av[i];
1964 ac = j + 1; 1964 ac = j + 1;
1965 } 1965 }
1966 1966
1967 for (i = 0; i < ac; i++) { 1967 for (i = 0; i < ac; i++) {
1968 Buf_AddBytes(&buf, strlen(av[i]), av[i]); 1968 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1969 if (i != ac - 1) 1969 if (i != ac - 1)
1970 Buf_AddByte(&buf, ' '); 1970 Buf_AddByte(&buf, ' ');
1971 } 1971 }
1972 1972
1973 free(as); 1973 free(as);
1974 free(av); 1974 free(av);
1975 1975
1976 return Buf_Destroy(&buf, FALSE); 1976 return Buf_Destroy(&buf, FALSE);
1977} 1977}
1978 1978
1979/*- 1979/*-
1980 *----------------------------------------------------------------------- 1980 *-----------------------------------------------------------------------
1981 * VarRange -- 1981 * VarRange --
1982 * Return an integer sequence 1982 * Return an integer sequence
1983 * 1983 *
1984 * Input: 1984 * Input:
1985 * str String whose words provide default range 1985 * str String whose words provide default range
1986 * ac range length, if 0 use str words 1986 * ac range length, if 0 use str words
1987 * 1987 *
1988 * Side Effects: 1988 * Side Effects:
1989 * None. 1989 * None.
1990 * 1990 *
1991 *----------------------------------------------------------------------- 1991 *-----------------------------------------------------------------------
1992 */ 1992 */
1993static char * 1993static char *
1994VarRange(const char *str, int ac) 1994VarRange(const char *str, int ac)
1995{ 1995{
1996 Buffer buf; /* Buffer for new string */ 1996 Buffer buf; /* Buffer for new string */
1997 char tmp[32]; /* each element */ 1997 char tmp[32]; /* each element */
1998 char **av; /* List of words to affect */ 1998 char **av; /* List of words to affect */
1999 char *as; /* Word list memory */ 1999 char *as; /* Word list memory */
2000 int i, n; 2000 int i, n;
2001 2001
2002 Buf_Init(&buf, 0); 2002 Buf_Init(&buf, 0);
2003 if (ac > 0) { 2003 if (ac > 0) {
2004 as = NULL; 2004 as = NULL;
2005 av = NULL; 2005 av = NULL;
2006 } else { 2006 } else {
2007 av = brk_string(str, &ac, FALSE, &as); 2007 av = brk_string(str, &ac, FALSE, &as);
2008 } 2008 }
2009 for (i = 0; i < ac; i++) { 2009 for (i = 0; i < ac; i++) {
2010 n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); 2010 n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
2011 if (n >= (int)sizeof(tmp)) 2011 if (n >= (int)sizeof(tmp))
2012 break; 2012 break;
2013 Buf_AddBytes(&buf, n, tmp); 2013 Buf_AddBytes(&buf, n, tmp);
2014 if (i != ac - 1) 2014 if (i != ac - 1)
2015 Buf_AddByte(&buf, ' '); 2015 Buf_AddByte(&buf, ' ');
2016 } 2016 }
2017 2017
2018 free(as); 2018 free(as);
2019 free(av); 2019 free(av);
2020 2020
2021 return Buf_Destroy(&buf, FALSE); 2021 return Buf_Destroy(&buf, FALSE);
2022} 2022}
2023 2023
2024 2024
2025/*- 2025/*-
2026 *----------------------------------------------------------------------- 2026 *-----------------------------------------------------------------------
2027 * VarGetPattern -- 2027 * VarGetPattern --
2028 * During the parsing of a part of a modifier such as :S or :@, 2028 * During the parsing of a part of a modifier such as :S or :@,
2029 * pass through the tstr looking for 1) escaped delimiters, 2029 * pass through the tstr looking for 1) escaped delimiters,
2030 * '$'s and backslashes (place the escaped character in 2030 * '$'s and backslashes (place the escaped character in
2031 * uninterpreted) and 2) unescaped $'s that aren't before 2031 * uninterpreted) and 2) unescaped $'s that aren't before
2032 * the delimiter (expand the variable substitution unless flags 2032 * the delimiter (expand the variable substitution unless flags
2033 * has VAR_NOSUBST set). 2033 * has VAR_NOSUBST set).
2034 * Return the expanded string or NULL if the delimiter was missing 2034 * Return the expanded string or NULL if the delimiter was missing
2035 * If pattern is specified, handle escaped ampersands, and replace 2035 * If pattern is specified, handle escaped ampersands, and replace
2036 * unescaped ampersands with the lhs of the pattern. 2036 * unescaped ampersands with the lhs of the pattern.
2037 * 2037 *
2038 * Results: 2038 * Results:
2039 * A string of all the words modified appropriately. 2039 * A string of all the words modified appropriately.
2040 * If length is specified, return the string length of the buffer 2040 * If length is specified, return the string length of the buffer
2041 * If flags is specified and the last character of the pattern is a 2041 * If flags is specified and the last character of the pattern is a
2042 * $ set the VAR_MATCH_END bit of flags. 2042 * $ set the VAR_MATCH_END bit of flags.
2043 * 2043 *
2044 * Side Effects: 2044 * Side Effects:
2045 * None. 2045 * None.
2046 *----------------------------------------------------------------------- 2046 *-----------------------------------------------------------------------
2047 */ 2047 */
2048static char * 2048static char *
2049VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, 2049VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
2050 VarEvalFlags eflags, const char **tstr, int delim, 2050 VarEvalFlags eflags, const char **tstr, int delim,
2051 VarPatternFlags *mpflags, int *length, VarPattern *pattern) 2051 VarPatternFlags *mpflags, int *length, VarPattern *pattern)
2052{ 2052{
2053 const char *cp; 2053 const char *cp;
2054 char *rstr; 2054 char *rstr;
2055 Buffer buf; 2055 Buffer buf;
2056 int junk; 2056 int junk;
2057 VarEvalFlags errnum = eflags & VARE_UNDEFERR; 2057 VarEvalFlags errnum = eflags & VARE_UNDEFERR;
2058 2058
2059 Buf_Init(&buf, 0); 2059 Buf_Init(&buf, 0);
2060 if (length == NULL) 2060 if (length == NULL)
2061 length = &junk; 2061 length = &junk;
2062 2062
2063#define IS_A_MATCH(cp, delim) \ 
2064 ((cp[0] == '\\') && ((cp[1] == delim) || \ 
2065 (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&')))) 
2066 
2067 /* 2063 /*
2068 * Skim through until the matching delimiter is found; 2064 * Skim through until the matching delimiter is found;
2069 * pick up variable substitutions on the way. Also allow 2065 * pick up variable substitutions on the way. Also allow
2070 * backslashes to quote the delimiter, $, and \, but don't 2066 * backslashes to quote the delimiter, $, and \, but don't
2071 * touch other backslashes. 2067 * touch other backslashes.
2072 */ 2068 */
2073 for (cp = *tstr; *cp && (*cp != delim); cp++) { 2069 for (cp = *tstr; *cp && (*cp != delim); cp++) {
2074 if (IS_A_MATCH(cp, delim)) { 2070 Boolean is_escaped = cp[0] == '\\' && (cp[1] == delim ||
 2071 cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&'));
 2072 if (is_escaped) {
2075 Buf_AddByte(&buf, cp[1]); 2073 Buf_AddByte(&buf, cp[1]);
2076 cp++; 2074 cp++;
2077 } else if (*cp == '$') { 2075 } else if (*cp == '$') {
2078 if (cp[1] == delim) { 2076 if (cp[1] == delim) {
2079 if (mpflags == NULL) 2077 if (mpflags == NULL)
2080 Buf_AddByte(&buf, *cp); 2078 Buf_AddByte(&buf, *cp);
2081 else 2079 else
2082 /* 2080 /*
2083 * Unescaped $ at end of pattern => anchor 2081 * Unescaped $ at end of pattern => anchor
2084 * pattern at end. 2082 * pattern at end.
2085 */ 2083 */
2086 *mpflags |= VARP_MATCH_END; 2084 *mpflags |= VARP_MATCH_END;
2087 } else { 2085 } else {
2088 /* FIXME: mismatch between mpflags and VAR_NOSUBST */ 2086 /* FIXME: mismatch between mpflags and VAR_NOSUBST */
2089 if (mpflags == NULL || !(*mpflags & VAR_NOSUBST)) { 2087 if (mpflags == NULL || !(*mpflags & VAR_NOSUBST)) {
2090 char *cp2; 2088 char *cp2;
2091 int len; 2089 int len;
2092 void *freeIt; 2090 void *freeIt;
2093 2091
2094 /* 2092 /*
2095 * If unescaped dollar sign not before the 2093 * If unescaped dollar sign not before the
2096 * delimiter, assume it's a variable 2094 * delimiter, assume it's a variable
2097 * substitution and recurse. 2095 * substitution and recurse.
2098 */ 2096 */
2099 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES), 2097 cp2 = Var_Parse(cp, ctxt, errnum | (eflags & VARE_WANTRES),
2100 &len, &freeIt); 2098 &len, &freeIt);
2101 Buf_AddBytes(&buf, strlen(cp2), cp2); 2099 Buf_AddBytes(&buf, strlen(cp2), cp2);
2102 free(freeIt); 2100 free(freeIt);
2103 cp += len - 1; 2101 cp += len - 1;
2104 } else { 2102 } else {
2105 const char *cp2 = &cp[1]; 2103 const char *cp2 = &cp[1];
2106 2104
2107 if (*cp2 == PROPEN || *cp2 == BROPEN) { 2105 if (*cp2 == PROPEN || *cp2 == BROPEN) {
2108 /* 2106 /*
2109 * Find the end of this variable reference 2107 * Find the end of this variable reference
2110 * and suck it in without further ado. 2108 * and suck it in without further ado.
2111 * It will be interpreted later. 2109 * It will be interpreted later.
2112 */ 2110 */
2113 int have = *cp2; 2111 int have = *cp2;
2114 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; 2112 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
2115 int depth = 1; 2113 int depth = 1;
2116 2114
2117 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { 2115 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
2118 if (cp2[-1] != '\\') { 2116 if (cp2[-1] != '\\') {
2119 if (*cp2 == have) 2117 if (*cp2 == have)
2120 ++depth; 2118 ++depth;
2121 if (*cp2 == want) 2119 if (*cp2 == want)
2122 --depth; 2120 --depth;
2123 } 2121 }
2124 } 2122 }
2125 Buf_AddBytes(&buf, cp2 - cp, cp); 2123 Buf_AddBytes(&buf, cp2 - cp, cp);
2126 cp = --cp2; 2124 cp = --cp2;
2127 } else 2125 } else
2128 Buf_AddByte(&buf, *cp); 2126 Buf_AddByte(&buf, *cp);
2129 } 2127 }
2130 } 2128 }
2131 } else if (pattern && *cp == '&') 2129 } else if (pattern && *cp == '&')
2132 Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); 2130 Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs);
2133 else 2131 else
2134 Buf_AddByte(&buf, *cp); 2132 Buf_AddByte(&buf, *cp);
2135 } 2133 }
2136 2134
2137 if (*cp != delim) { 2135 if (*cp != delim) {
2138 *tstr = cp; 2136 *tstr = cp;
2139 *length = 0; 2137 *length = 0;
2140 return NULL; 2138 return NULL;
2141 } 2139 }
2142 2140
2143 *tstr = ++cp; 2141 *tstr = ++cp;
2144 *length = Buf_Size(&buf); 2142 *length = Buf_Size(&buf);
2145 rstr = Buf_Destroy(&buf, FALSE); 2143 rstr = Buf_Destroy(&buf, FALSE);
2146 if (DEBUG(VAR)) 2144 if (DEBUG(VAR))
2147 fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); 2145 fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr);
2148 return rstr; 2146 return rstr;
2149} 2147}
2150 2148
2151/*- 2149/*-
2152 *----------------------------------------------------------------------- 2150 *-----------------------------------------------------------------------
2153 * VarQuote -- 2151 * VarQuote --
2154 * Quote shell meta-characters and space characters in the string 2152 * Quote shell meta-characters and space characters in the string
2155 * if quoteDollar is set, also quote and double any '$' characters. 2153 * if quoteDollar is set, also quote and double any '$' characters.
2156 * 2154 *
2157 * Results: 2155 * Results:
2158 * The quoted string 2156 * The quoted string
2159 * 2157 *
2160 * Side Effects: 2158 * Side Effects:
2161 * None. 2159 * None.
2162 * 2160 *
2163 *----------------------------------------------------------------------- 2161 *-----------------------------------------------------------------------
2164 */ 2162 */
2165static char * 2163static char *
2166VarQuote(char *str, Boolean quoteDollar) 2164VarQuote(char *str, Boolean quoteDollar)
2167{ 2165{
2168 2166
2169 Buffer buf; 2167 Buffer buf;
2170 const char *newline; 2168 const char *newline;
2171 size_t nlen; 2169 size_t nlen;
2172 2170
2173 if ((newline = Shell_GetNewline()) == NULL) 2171 if ((newline = Shell_GetNewline()) == NULL)
2174 newline = "\\\n"; 2172 newline = "\\\n";
2175 nlen = strlen(newline); 2173 nlen = strlen(newline);
2176 2174
2177 Buf_Init(&buf, 0); 2175 Buf_Init(&buf, 0);
2178 2176
2179 for (; *str != '\0'; str++) { 2177 for (; *str != '\0'; str++) {
2180 if (*str == '\n') { 2178 if (*str == '\n') {
2181 Buf_AddBytes(&buf, nlen, newline); 2179 Buf_AddBytes(&buf, nlen, newline);
2182 continue; 2180 continue;
2183 } 2181 }
2184 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) 2182 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
2185 Buf_AddByte(&buf, '\\'); 2183 Buf_AddByte(&buf, '\\');
2186 Buf_AddByte(&buf, *str); 2184 Buf_AddByte(&buf, *str);
2187 if (quoteDollar && *str == '$') 2185 if (quoteDollar && *str == '$')
2188 Buf_AddBytes(&buf, 2, "\\$"); 2186 Buf_AddBytes(&buf, 2, "\\$");
2189 } 2187 }
2190 2188
2191 str = Buf_Destroy(&buf, FALSE); 2189 str = Buf_Destroy(&buf, FALSE);
2192 if (DEBUG(VAR)) 2190 if (DEBUG(VAR))
2193 fprintf(debug_file, "QuoteMeta: [%s]\n", str); 2191 fprintf(debug_file, "QuoteMeta: [%s]\n", str);
2194 return str; 2192 return str;
2195} 2193}
2196 2194
2197/*- 2195/*-
2198 *----------------------------------------------------------------------- 2196 *-----------------------------------------------------------------------
2199 * VarHash -- 2197 * VarHash --
2200 * Hash the string using the MurmurHash3 algorithm. 2198 * Hash the string using the MurmurHash3 algorithm.
2201 * Output is computed using 32bit Little Endian arithmetic. 2199 * Output is computed using 32bit Little Endian arithmetic.
2202 * 2200 *
2203 * Input: 2201 * Input:
2204 * str String to modify 2202 * str String to modify
2205 * 2203 *
2206 * Results: 2204 * Results:
2207 * Hash value of str, encoded as 8 hex digits. 2205 * Hash value of str, encoded as 8 hex digits.
2208 * 2206 *
2209 * Side Effects: 2207 * Side Effects:
2210 * None. 2208 * None.
2211 * 2209 *
2212 *----------------------------------------------------------------------- 2210 *-----------------------------------------------------------------------
2213 */ 2211 */
2214static char * 2212static char *
2215VarHash(const char *str) 2213VarHash(const char *str)
2216{ 2214{
2217 static const char hexdigits[16] = "0123456789abcdef"; 2215 static const char hexdigits[16] = "0123456789abcdef";
2218 Buffer buf; 2216 Buffer buf;
2219 size_t len, len2; 2217 size_t len, len2;
2220 const unsigned char *ustr = (const unsigned char *)str; 2218 const unsigned char *ustr = (const unsigned char *)str;
2221 uint32_t h, k, c1, c2; 2219 uint32_t h, k, c1, c2;
2222 2220
2223 h = 0x971e137bU; 2221 h = 0x971e137bU;
2224 c1 = 0x95543787U; 2222 c1 = 0x95543787U;
2225 c2 = 0x2ad7eb25U; 2223 c2 = 0x2ad7eb25U;
2226 len2 = strlen(str); 2224 len2 = strlen(str);
2227 2225
2228 for (len = len2; len; ) { 2226 for (len = len2; len; ) {
2229 k = 0; 2227 k = 0;
2230 switch (len) { 2228 switch (len) {
2231 default: 2229 default:
2232 k = ((uint32_t)ustr[3] << 24) | 2230 k = ((uint32_t)ustr[3] << 24) |
2233 ((uint32_t)ustr[2] << 16) | 2231 ((uint32_t)ustr[2] << 16) |
2234 ((uint32_t)ustr[1] << 8) | 2232 ((uint32_t)ustr[1] << 8) |
2235 (uint32_t)ustr[0]; 2233 (uint32_t)ustr[0];
2236 len -= 4; 2234 len -= 4;
2237 ustr += 4; 2235 ustr += 4;
2238 break; 2236 break;
2239 case 3: 2237 case 3:
2240 k |= (uint32_t)ustr[2] << 16; 2238 k |= (uint32_t)ustr[2] << 16;
2241 /* FALLTHROUGH */ 2239 /* FALLTHROUGH */
2242 case 2: 2240 case 2:
2243 k |= (uint32_t)ustr[1] << 8; 2241 k |= (uint32_t)ustr[1] << 8;
2244 /* FALLTHROUGH */ 2242 /* FALLTHROUGH */
2245 case 1: 2243 case 1:
2246 k |= (uint32_t)ustr[0]; 2244 k |= (uint32_t)ustr[0];
2247 len = 0; 2245 len = 0;
2248 } 2246 }
2249 c1 = c1 * 5 + 0x7b7d159cU; 2247 c1 = c1 * 5 + 0x7b7d159cU;
2250 c2 = c2 * 5 + 0x6bce6396U; 2248 c2 = c2 * 5 + 0x6bce6396U;
2251 k *= c1; 2249 k *= c1;
2252 k = (k << 11) ^ (k >> 21); 2250 k = (k << 11) ^ (k >> 21);
2253 k *= c2; 2251 k *= c2;
2254 h = (h << 13) ^ (h >> 19); 2252 h = (h << 13) ^ (h >> 19);
2255 h = h * 5 + 0x52dce729U; 2253 h = h * 5 + 0x52dce729U;
2256 h ^= k; 2254 h ^= k;
2257 } 2255 }
2258 h ^= len2; 2256 h ^= len2;
2259 h *= 0x85ebca6b; 2257 h *= 0x85ebca6b;
2260 h ^= h >> 13; 2258 h ^= h >> 13;
2261 h *= 0xc2b2ae35; 2259 h *= 0xc2b2ae35;
2262 h ^= h >> 16; 2260 h ^= h >> 16;
2263 2261
2264 Buf_Init(&buf, 0); 2262 Buf_Init(&buf, 0);
2265 for (len = 0; len < 8; ++len) { 2263 for (len = 0; len < 8; ++len) {
2266 Buf_AddByte(&buf, hexdigits[h & 15]); 2264 Buf_AddByte(&buf, hexdigits[h & 15]);
2267 h >>= 4; 2265 h >>= 4;
2268 } 2266 }
2269 2267
2270 return Buf_Destroy(&buf, FALSE); 2268 return Buf_Destroy(&buf, FALSE);
2271} 2269}
2272 2270
2273static char * 2271static char *
2274VarStrftime(const char *fmt, int zulu, time_t utc) 2272VarStrftime(const char *fmt, int zulu, time_t utc)
2275{ 2273{
2276 char buf[BUFSIZ]; 2274 char buf[BUFSIZ];
2277 2275
2278 if (!utc) 2276 if (!utc)
2279 time(&utc); 2277 time(&utc);
2280 if (!*fmt) 2278 if (!*fmt)
2281 fmt = "%c"; 2279 fmt = "%c";
2282 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); 2280 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2283 2281
2284 buf[sizeof(buf) - 1] = '\0'; 2282 buf[sizeof(buf) - 1] = '\0';
2285 return bmake_strdup(buf); 2283 return bmake_strdup(buf);
2286} 2284}
2287 2285
2288typedef struct { 2286typedef struct {
2289 /* const parameters */ 2287 /* const parameters */
2290 int startc; 2288 int startc;
2291 int endc; 2289 int endc;
2292 Var *v; 2290 Var *v;
2293 GNode *ctxt; 2291 GNode *ctxt;
2294 int flags; 2292 int flags;
2295 int *lengthPtr; 2293 int *lengthPtr;
2296 void **freePtr; 2294 void **freePtr;
2297 2295
2298 /* read-write */ 2296 /* read-write */
2299 char *nstr; 2297 char *nstr;
2300 const char *tstr; 2298 const char *tstr;
2301 const char *start; 2299 const char *start;
2302 const char *cp; /* Secondary pointer into str (place marker 2300 const char *cp; /* Secondary pointer into str (place marker
2303 * for tstr) */ 2301 * for tstr) */
2304 char termc; /* Character which terminated scan */ 2302 char termc; /* Character which terminated scan */
2305 char delim; 2303 char delim;
2306 int modifier; /* that we are processing */ 2304 int modifier; /* that we are processing */
2307 Var_Parse_State parsestate; /* Flags passed to helper functions */ 2305 Var_Parse_State parsestate; /* Flags passed to helper functions */
2308 2306
2309 /* result */ 2307 /* result */
2310 char *newStr; /* New value to return */ 2308 char *newStr; /* New value to return */
2311} ApplyModifiersState; 2309} ApplyModifiersState;
2312 2310
2313/* we now have some modifiers with long names */ 2311/* we now have some modifiers with long names */
2314#define STRMOD_MATCH(s, want, n) \ 2312#define STRMOD_MATCH(s, want, n) \
2315 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':')) 2313 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
2316#define STRMOD_MATCHX(s, want, n) \ 2314#define STRMOD_MATCHX(s, want, n) \
2317 (strncmp(s, want, n) == 0 && \ 2315 (strncmp(s, want, n) == 0 && \
2318 (s[n] == st->endc || s[n] == ':' || s[n] == '=')) 2316 (s[n] == st->endc || s[n] == ':' || s[n] == '='))
2319#define CHARMOD_MATCH(c) (c == st->endc || c == ':') 2317#define CHARMOD_MATCH(c) (c == st->endc || c == ':')
2320 2318
2321/* :@var@...${var}...@ */ 2319/* :@var@...${var}...@ */
2322static Boolean 2320static Boolean
2323ApplyModifier_At(ApplyModifiersState *st) { 2321ApplyModifier_At(ApplyModifiersState *st) {
2324 VarLoop loop; 2322 VarLoop loop;
2325 VarPatternFlags pflags = VAR_NOSUBST; /* FIXME: mismatch between pflags and VAR_NOSUBST */ 2323 VarPatternFlags pflags = VAR_NOSUBST; /* FIXME: mismatch between pflags and VAR_NOSUBST */
2326 2324
2327 st->cp = ++st->tstr; 2325 st->cp = ++st->tstr;
2328 st->delim = '@'; 2326 st->delim = '@';
2329 loop.tvar = VarGetPattern( 2327 loop.tvar = VarGetPattern(
2330 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2328 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2331 &pflags, &loop.tvarLen, NULL); 2329 &pflags, &loop.tvarLen, NULL);
2332 if (loop.tvar == NULL) 2330 if (loop.tvar == NULL)
2333 return FALSE; 2331 return FALSE;
2334 2332
2335 loop.str = VarGetPattern( 2333 loop.str = VarGetPattern(
2336 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2334 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2337 &pflags, &loop.strLen, NULL); 2335 &pflags, &loop.strLen, NULL);
2338 if (loop.str == NULL) 2336 if (loop.str == NULL)
2339 return FALSE; 2337 return FALSE;
2340 2338
2341 st->termc = *st->cp; 2339 st->termc = *st->cp;
2342 st->delim = '\0'; 2340 st->delim = '\0';
2343 2341
2344 loop.flags = st->flags & (VARE_UNDEFERR | VARE_WANTRES); 2342 loop.flags = st->flags & (VARE_UNDEFERR | VARE_WANTRES);
2345 loop.ctxt = st->ctxt; 2343 loop.ctxt = st->ctxt;
2346 st->newStr = VarModify( 2344 st->newStr = VarModify(
2347 st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop); 2345 st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop);
2348 Var_Delete(loop.tvar, st->ctxt); 2346 Var_Delete(loop.tvar, st->ctxt);
2349 free(loop.tvar); 2347 free(loop.tvar);
2350 free(loop.str); 2348 free(loop.str);
2351 return TRUE; 2349 return TRUE;
2352} 2350}
2353 2351
2354/* :Ddefined or :Uundefined */ 2352/* :Ddefined or :Uundefined */
2355static void 2353static void
2356ApplyModifier_Defined(ApplyModifiersState *st) 2354ApplyModifier_Defined(ApplyModifiersState *st)
2357{ 2355{
2358 Buffer buf; /* Buffer for patterns */ 2356 Buffer buf; /* Buffer for patterns */
2359 int nflags; 2357 int nflags;
2360 2358
2361 if (st->flags & VARE_WANTRES) { 2359 if (st->flags & VARE_WANTRES) {
2362 int wantres; 2360 int wantres;
2363 if (*st->tstr == 'U') 2361 if (*st->tstr == 'U')
2364 wantres = ((st->v->flags & VAR_JUNK) != 0); 2362 wantres = ((st->v->flags & VAR_JUNK) != 0);
2365 else 2363 else
2366 wantres = ((st->v->flags & VAR_JUNK) == 0); 2364 wantres = ((st->v->flags & VAR_JUNK) == 0);
2367 nflags = st->flags & ~VARE_WANTRES; 2365 nflags = st->flags & ~VARE_WANTRES;
2368 if (wantres) 2366 if (wantres)
2369 nflags |= VARE_WANTRES; 2367 nflags |= VARE_WANTRES;
2370 } else 2368 } else
2371 nflags = st->flags; 2369 nflags = st->flags;
2372 2370
2373 /* 2371 /*
2374 * Pass through tstr looking for 1) escaped delimiters, 2372 * Pass through tstr looking for 1) escaped delimiters,
2375 * '$'s and backslashes (place the escaped character in 2373 * '$'s and backslashes (place the escaped character in
2376 * uninterpreted) and 2) unescaped $'s that aren't before 2374 * uninterpreted) and 2) unescaped $'s that aren't before
2377 * the delimiter (expand the variable substitution). 2375 * the delimiter (expand the variable substitution).
2378 * The result is left in the Buffer buf. 2376 * The result is left in the Buffer buf.
2379 */ 2377 */
2380 Buf_Init(&buf, 0); 2378 Buf_Init(&buf, 0);
2381 for (st->cp = st->tstr + 1; 2379 for (st->cp = st->tstr + 1;
2382 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0'; 2380 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
2383 st->cp++) { 2381 st->cp++) {
2384 if (*st->cp == '\\' && 2382 if (*st->cp == '\\' &&
2385 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc || 2383 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
2386 st->cp[1] == '\\')) { 2384 st->cp[1] == '\\')) {
2387 Buf_AddByte(&buf, st->cp[1]); 2385 Buf_AddByte(&buf, st->cp[1]);
2388 st->cp++; 2386 st->cp++;
2389 } else if (*st->cp == '$') { 2387 } else if (*st->cp == '$') {
2390 /* 2388 /*
2391 * If unescaped dollar sign, assume it's a 2389 * If unescaped dollar sign, assume it's a
2392 * variable substitution and recurse. 2390 * variable substitution and recurse.
2393 */ 2391 */
2394 char *cp2; 2392 char *cp2;
2395 int len; 2393 int len;
2396 void *freeIt; 2394 void *freeIt;
2397 2395
2398 cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt); 2396 cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt);
2399 Buf_AddBytes(&buf, strlen(cp2), cp2); 2397 Buf_AddBytes(&buf, strlen(cp2), cp2);
2400 free(freeIt); 2398 free(freeIt);
2401 st->cp += len - 1; 2399 st->cp += len - 1;
2402 } else { 2400 } else {
2403 Buf_AddByte(&buf, *st->cp); 2401 Buf_AddByte(&buf, *st->cp);
2404 } 2402 }
2405 } 2403 }
2406 2404
2407 st->termc = *st->cp; 2405 st->termc = *st->cp;
2408 2406
2409 if (st->v->flags & VAR_JUNK) 2407 if (st->v->flags & VAR_JUNK)
2410 st->v->flags |= VAR_KEEP; 2408 st->v->flags |= VAR_KEEP;
2411 if (nflags & VARE_WANTRES) { 2409 if (nflags & VARE_WANTRES) {
2412 st->newStr = Buf_Destroy(&buf, FALSE); 2410 st->newStr = Buf_Destroy(&buf, FALSE);
2413 } else { 2411 } else {
2414 st->newStr = st->nstr; 2412 st->newStr = st->nstr;
2415 Buf_Destroy(&buf, TRUE); 2413 Buf_Destroy(&buf, TRUE);
2416 } 2414 }
2417} 2415}
2418 2416
2419/* :gmtime */ 2417/* :gmtime */
2420static Boolean 2418static Boolean
2421ApplyModifier_Gmtime(ApplyModifiersState *st) 2419ApplyModifier_Gmtime(ApplyModifiersState *st)
2422{ 2420{
2423 time_t utc; 2421 time_t utc;
2424 char *ep; 2422 char *ep;
2425 2423
2426 st->cp = st->tstr + 1; /* make sure it is set */ 2424 st->cp = st->tstr + 1; /* make sure it is set */
2427 if (!STRMOD_MATCHX(st->tstr, "gmtime", 6)) 2425 if (!STRMOD_MATCHX(st->tstr, "gmtime", 6))
2428 return FALSE; 2426 return FALSE;
2429 if (st->tstr[6] == '=') { 2427 if (st->tstr[6] == '=') {
2430 utc = strtoul(&st->tstr[7], &ep, 10); 2428 utc = strtoul(&st->tstr[7], &ep, 10);
2431 st->cp = ep; 2429 st->cp = ep;
2432 } else { 2430 } else {
2433 utc = 0; 2431 utc = 0;
2434 st->cp = st->tstr + 6; 2432 st->cp = st->tstr + 6;
2435 } 2433 }
2436 st->newStr = VarStrftime(st->nstr, 1, utc); 2434 st->newStr = VarStrftime(st->nstr, 1, utc);
2437 st->termc = *st->cp; 2435 st->termc = *st->cp;
2438 return TRUE; 2436 return TRUE;
2439} 2437}
2440 2438
2441/* :localtime */ 2439/* :localtime */
2442static Boolean 2440static Boolean
2443ApplyModifier_Localtime(ApplyModifiersState *st) 2441ApplyModifier_Localtime(ApplyModifiersState *st)
2444{ 2442{
2445 time_t utc; 2443 time_t utc;
2446 char *ep; 2444 char *ep;
2447 2445
2448 st->cp = st->tstr + 1; /* make sure it is set */ 2446 st->cp = st->tstr + 1; /* make sure it is set */
2449 if (!STRMOD_MATCHX(st->tstr, "localtime", 9)) 2447 if (!STRMOD_MATCHX(st->tstr, "localtime", 9))
2450 return FALSE; 2448 return FALSE;
2451 2449
2452 if (st->tstr[9] == '=') { 2450 if (st->tstr[9] == '=') {
2453 utc = strtoul(&st->tstr[10], &ep, 10); 2451 utc = strtoul(&st->tstr[10], &ep, 10);
2454 st->cp = ep; 2452 st->cp = ep;
2455 } else { 2453 } else {
2456 utc = 0; 2454 utc = 0;
2457 st->cp = st->tstr + 9; 2455 st->cp = st->tstr + 9;
2458 } 2456 }
2459 st->newStr = VarStrftime(st->nstr, 0, utc); 2457 st->newStr = VarStrftime(st->nstr, 0, utc);
2460 st->termc = *st->cp; 2458 st->termc = *st->cp;
2461 return TRUE; 2459 return TRUE;
2462} 2460}
2463 2461
2464/* :hash */ 2462/* :hash */
2465static Boolean 2463static Boolean
2466ApplyModifier_Hash(ApplyModifiersState *st) 2464ApplyModifier_Hash(ApplyModifiersState *st)
2467{ 2465{
2468 st->cp = st->tstr + 1; /* make sure it is set */ 2466 st->cp = st->tstr + 1; /* make sure it is set */
2469 if (!STRMOD_MATCH(st->tstr, "hash", 4)) 2467 if (!STRMOD_MATCH(st->tstr, "hash", 4))
2470 return FALSE; 2468 return FALSE;
2471 st->newStr = VarHash(st->nstr); 2469 st->newStr = VarHash(st->nstr);
2472 st->cp = st->tstr + 4; 2470 st->cp = st->tstr + 4;
2473 st->termc = *st->cp; 2471 st->termc = *st->cp;
2474 return TRUE; 2472 return TRUE;
2475} 2473}
2476 2474
2477/* :P */ 2475/* :P */
2478static void 2476static void
2479ApplyModifier_Path(ApplyModifiersState *st) 2477ApplyModifier_Path(ApplyModifiersState *st)
2480{ 2478{
2481 GNode *gn; 2479 GNode *gn;
2482 2480
2483 if ((st->v->flags & VAR_JUNK) != 0) 2481 if ((st->v->flags & VAR_JUNK) != 0)
2484 st->v->flags |= VAR_KEEP; 2482 st->v->flags |= VAR_KEEP;
2485 gn = Targ_FindNode(st->v->name, TARG_NOCREATE); 2483 gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2486 if (gn == NULL || gn->type & OP_NOPATH) { 2484 if (gn == NULL || gn->type & OP_NOPATH) {
2487 st->newStr = NULL; 2485 st->newStr = NULL;
2488 } else if (gn->path) { 2486 } else if (gn->path) {
2489 st->newStr = bmake_strdup(gn->path); 2487 st->newStr = bmake_strdup(gn->path);
2490 } else { 2488 } else {
2491 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); 2489 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2492 } 2490 }
2493 if (!st->newStr) 2491 if (!st->newStr)
2494 st->newStr = bmake_strdup(st->v->name); 2492 st->newStr = bmake_strdup(st->v->name);
2495 st->cp = ++st->tstr; 2493 st->cp = ++st->tstr;
2496 st->termc = *st->tstr; 2494 st->termc = *st->tstr;
2497} 2495}
2498 2496
2499/* :!cmd! */ 2497/* :!cmd! */
2500static Boolean 2498static Boolean
2501ApplyModifier_Exclam(ApplyModifiersState *st) 2499ApplyModifier_Exclam(ApplyModifiersState *st)
2502{ 2500{
2503 const char *emsg; 2501 const char *emsg;
2504 VarPattern pattern; 2502 VarPattern pattern;
2505 2503
2506 pattern.pflags = 0; 2504 pattern.pflags = 0;
2507 2505
2508 st->delim = '!'; 2506 st->delim = '!';
2509 emsg = NULL; 2507 emsg = NULL;
2510 st->cp = ++st->tstr; 2508 st->cp = ++st->tstr;
2511 pattern.rhs = VarGetPattern( 2509 pattern.rhs = VarGetPattern(
2512 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2510 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2513 NULL, &pattern.rightLen, NULL); 2511 NULL, &pattern.rightLen, NULL);
2514 if (pattern.rhs == NULL) 2512 if (pattern.rhs == NULL)
2515 return FALSE; 2513 return FALSE;
2516 if (st->flags & VARE_WANTRES) 2514 if (st->flags & VARE_WANTRES)
2517 st->newStr = Cmd_Exec(pattern.rhs, &emsg); 2515 st->newStr = Cmd_Exec(pattern.rhs, &emsg);
2518 else 2516 else
2519 st->newStr = varNoError; 2517 st->newStr = varNoError;
2520 free(UNCONST(pattern.rhs)); 2518 free(UNCONST(pattern.rhs));
2521 if (emsg) 2519 if (emsg)
2522 Error(emsg, st->nstr); 2520 Error(emsg, st->nstr);
2523 st->termc = *st->cp; 2521 st->termc = *st->cp;
2524 st->delim = '\0'; 2522 st->delim = '\0';
2525 if (st->v->flags & VAR_JUNK) 2523 if (st->v->flags & VAR_JUNK)
2526 st->v->flags |= VAR_KEEP; 2524 st->v->flags |= VAR_KEEP;
2527 return TRUE; 2525 return TRUE;
2528} 2526}
2529 2527
2530/* :range */ 2528/* :range */
2531static Boolean 2529static Boolean
2532ApplyModifier_Range(ApplyModifiersState *st) 2530ApplyModifier_Range(ApplyModifiersState *st)
2533{ 2531{
2534 int n; 2532 int n;
2535 char *ep; 2533 char *ep;
2536 2534
2537 st->cp = st->tstr + 1; /* make sure it is set */ 2535 st->cp = st->tstr + 1; /* make sure it is set */
2538 if (!STRMOD_MATCHX(st->tstr, "range", 5)) 2536 if (!STRMOD_MATCHX(st->tstr, "range", 5))
2539 return FALSE; 2537 return FALSE;
2540 2538
2541 if (st->tstr[5] == '=') { 2539 if (st->tstr[5] == '=') {
2542 n = strtoul(&st->tstr[6], &ep, 10); 2540 n = strtoul(&st->tstr[6], &ep, 10);
2543 st->cp = ep; 2541 st->cp = ep;
2544 } else { 2542 } else {
2545 n = 0; 2543 n = 0;
2546 st->cp = st->tstr + 5; 2544 st->cp = st->tstr + 5;
2547 } 2545 }
2548 st->newStr = VarRange(st->nstr, n); 2546 st->newStr = VarRange(st->nstr, n);
2549 st->termc = *st->cp; 2547 st->termc = *st->cp;
2550 return TRUE; 2548 return TRUE;
2551} 2549}
2552 2550
2553/* :Mpattern or :Npattern */ 2551/* :Mpattern or :Npattern */
2554static void 2552static void
2555ApplyModifier_Match(ApplyModifiersState *st) 2553ApplyModifier_Match(ApplyModifiersState *st)
2556{ 2554{
2557 char *pattern; 2555 char *pattern;
2558 const char *endpat; /* points just after end of pattern */ 2556 const char *endpat; /* points just after end of pattern */
2559 char *cp2; 2557 char *cp2;
2560 Boolean copy; /* pattern should be, or has been, copied */ 2558 Boolean copy; /* pattern should be, or has been, copied */
2561 Boolean needSubst; 2559 Boolean needSubst;
2562 int nest; 2560 int nest;
2563 2561
2564 copy = FALSE; 2562 copy = FALSE;
2565 needSubst = FALSE; 2563 needSubst = FALSE;
2566 nest = 1; 2564 nest = 1;
2567 /* 2565 /*
2568 * In the loop below, ignore ':' unless we are at 2566 * In the loop below, ignore ':' unless we are at
2569 * (or back to) the original brace level. 2567 * (or back to) the original brace level.
2570 * XXX This will likely not work right if $() and ${} 2568 * XXX This will likely not work right if $() and ${}
2571 * are intermixed. 2569 * are intermixed.
2572 */ 2570 */
2573 for (st->cp = st->tstr + 1; 2571 for (st->cp = st->tstr + 1;
2574 *st->cp != '\0' && !(*st->cp == ':' && nest == 1); 2572 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2575 st->cp++) { 2573 st->cp++) {
2576 if (*st->cp == '\\' && 2574 if (*st->cp == '\\' &&
2577 (st->cp[1] == ':' || st->cp[1] == st->endc || 2575 (st->cp[1] == ':' || st->cp[1] == st->endc ||
2578 st->cp[1] == st->startc)) { 2576 st->cp[1] == st->startc)) {
2579 if (!needSubst) 2577 if (!needSubst)
2580 copy = TRUE; 2578 copy = TRUE;
2581 st->cp++; 2579 st->cp++;
2582 continue; 2580 continue;
2583 } 2581 }
2584 if (*st->cp == '$') 2582 if (*st->cp == '$')
2585 needSubst = TRUE; 2583 needSubst = TRUE;
2586 if (*st->cp == '(' || *st->cp == '{') 2584 if (*st->cp == '(' || *st->cp == '{')
2587 ++nest; 2585 ++nest;
2588 if (*st->cp == ')' || *st->cp == '}') { 2586 if (*st->cp == ')' || *st->cp == '}') {
2589 --nest; 2587 --nest;
2590 if (nest == 0) 2588 if (nest == 0)
2591 break; 2589 break;
2592 } 2590 }
2593 } 2591 }
2594 st->termc = *st->cp; 2592 st->termc = *st->cp;
2595 endpat = st->cp; 2593 endpat = st->cp;
2596 if (copy) { 2594 if (copy) {
2597 /* 2595 /*
2598 * Need to compress the \:'s out of the pattern, so 2596 * Need to compress the \:'s out of the pattern, so
2599 * allocate enough room to hold the uncompressed 2597 * allocate enough room to hold the uncompressed
2600 * pattern (note that st->cp started at st->tstr+1, so 2598 * pattern (note that st->cp started at st->tstr+1, so
2601 * st->cp - st->tstr takes the null byte into account) and 2599 * st->cp - st->tstr takes the null byte into account) and
2602 * compress the pattern into the space. 2600 * compress the pattern into the space.
2603 */ 2601 */
2604 pattern = bmake_malloc(st->cp - st->tstr); 2602 pattern = bmake_malloc(st->cp - st->tstr);
2605 for (cp2 = pattern, st->cp = st->tstr + 1; 2603 for (cp2 = pattern, st->cp = st->tstr + 1;
2606 st->cp < endpat; 2604 st->cp < endpat;
2607 st->cp++, cp2++) { 2605 st->cp++, cp2++) {
2608 if ((*st->cp == '\\') && (st->cp+1 < endpat) && 2606 if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2609 (st->cp[1] == ':' || st->cp[1] == st->endc)) 2607 (st->cp[1] == ':' || st->cp[1] == st->endc))
2610 st->cp++; 2608 st->cp++;
2611 *cp2 = *st->cp; 2609 *cp2 = *st->cp;
2612 } 2610 }
2613 *cp2 = '\0'; 2611 *cp2 = '\0';
2614 endpat = cp2; 2612 endpat = cp2;
2615 } else { 2613 } else {
2616 /* 2614 /*
2617 * Either Var_Subst or VarModify will need a 2615 * Either Var_Subst or VarModify will need a
2618 * nul-terminated string soon, so construct one now. 2616 * nul-terminated string soon, so construct one now.
2619 */ 2617 */
2620 pattern = bmake_strndup(st->tstr+1, endpat - (st->tstr + 1)); 2618 pattern = bmake_strndup(st->tstr+1, endpat - (st->tstr + 1));
2621 } 2619 }
2622 if (needSubst) { 2620 if (needSubst) {
2623 /* pattern contains embedded '$', so use Var_Subst to expand it. */ 2621 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2624 cp2 = pattern; 2622 cp2 = pattern;
2625 pattern = Var_Subst(NULL, cp2, st->ctxt, st->flags); 2623 pattern = Var_Subst(NULL, cp2, st->ctxt, st->flags);
2626 free(cp2); 2624 free(cp2);
2627 } 2625 }
2628 if (DEBUG(VAR)) 2626 if (DEBUG(VAR))
2629 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", 2627 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2630 st->v->name, st->nstr, pattern); 2628 st->v->name, st->nstr, pattern);
2631 if (*st->tstr == 'M') { 2629 if (*st->tstr == 'M') {
2632 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarMatch, 2630 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarMatch,
2633 pattern); 2631 pattern);
2634 } else { 2632 } else {
2635 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarNoMatch, 2633 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarNoMatch,
2636 pattern); 2634 pattern);
2637 } 2635 }
2638 free(pattern); 2636 free(pattern);
2639} 2637}
2640 2638
2641/* :S,from,to, */ 2639/* :S,from,to, */
2642static Boolean 2640static Boolean
2643ApplyModifier_Subst(ApplyModifiersState *st) 2641ApplyModifier_Subst(ApplyModifiersState *st)
2644{ 2642{
2645 VarPattern pattern; 2643 VarPattern pattern;
2646 Var_Parse_State tmpparsestate; 2644 Var_Parse_State tmpparsestate;
2647 2645
2648 pattern.pflags = 0; 2646 pattern.pflags = 0;
2649 tmpparsestate = st->parsestate; 2647 tmpparsestate = st->parsestate;
2650 st->delim = st->tstr[1]; 2648 st->delim = st->tstr[1];
2651 st->tstr += 2; 2649 st->tstr += 2;
2652 2650
2653 /* 2651 /*
2654 * If pattern begins with '^', it is anchored to the 2652 * If pattern begins with '^', it is anchored to the
2655 * start of the word -- skip over it and flag pattern. 2653 * start of the word -- skip over it and flag pattern.
2656 */ 2654 */
2657 if (*st->tstr == '^') { 2655 if (*st->tstr == '^') {
2658 pattern.pflags |= VARP_MATCH_START; 2656 pattern.pflags |= VARP_MATCH_START;
2659 st->tstr++; 2657 st->tstr++;
2660 } 2658 }
2661 2659
2662 st->cp = st->tstr; 2660 st->cp = st->tstr;
2663 pattern.lhs = VarGetPattern( 2661 pattern.lhs = VarGetPattern(
2664 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2662 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2665 &pattern.pflags, &pattern.leftLen, NULL); 2663 &pattern.pflags, &pattern.leftLen, NULL);
2666 if (pattern.lhs == NULL) 2664 if (pattern.lhs == NULL)
2667 return FALSE; 2665 return FALSE;
2668 2666
2669 pattern.rhs = VarGetPattern( 2667 pattern.rhs = VarGetPattern(
2670 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2668 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2671 NULL, &pattern.rightLen, &pattern); 2669 NULL, &pattern.rightLen, &pattern);
2672 if (pattern.rhs == NULL) 2670 if (pattern.rhs == NULL)
2673 return FALSE; 2671 return FALSE;
2674 2672
2675 /* 2673 /*
2676 * Check for global substitution. If 'g' after the final 2674 * Check for global substitution. If 'g' after the final
2677 * delimiter, substitution is global and is marked that 2675 * delimiter, substitution is global and is marked that
2678 * way. 2676 * way.
2679 */ 2677 */
2680 for (;; st->cp++) { 2678 for (;; st->cp++) {
2681 switch (*st->cp) { 2679 switch (*st->cp) {
2682 case 'g': 2680 case 'g':
2683 pattern.pflags |= VARP_SUB_GLOBAL; 2681 pattern.pflags |= VARP_SUB_GLOBAL;
2684 continue; 2682 continue;
2685 case '1': 2683 case '1':
2686 pattern.pflags |= VARP_SUB_ONE; 2684 pattern.pflags |= VARP_SUB_ONE;
2687 continue; 2685 continue;
2688 case 'W': 2686 case 'W':
2689 tmpparsestate.oneBigWord = TRUE; 2687 tmpparsestate.oneBigWord = TRUE;
2690 continue; 2688 continue;
2691 } 2689 }
2692 break; 2690 break;
2693 } 2691 }
2694 2692
2695 st->termc = *st->cp; 2693 st->termc = *st->cp;
2696 st->newStr = VarModify( 2694 st->newStr = VarModify(
2697 st->ctxt, &tmpparsestate, st->nstr, VarSubstitute, &pattern); 2695 st->ctxt, &tmpparsestate, st->nstr, VarSubstitute, &pattern);
2698 2696
2699 /* Free the two strings. */ 2697 /* Free the two strings. */
2700 free(UNCONST(pattern.lhs)); 2698 free(UNCONST(pattern.lhs));
2701 free(UNCONST(pattern.rhs)); 2699 free(UNCONST(pattern.rhs));
2702 st->delim = '\0'; 2700 st->delim = '\0';
2703 return TRUE; 2701 return TRUE;
2704} 2702}
2705 2703
2706#ifndef NO_REGEX 2704#ifndef NO_REGEX
2707/* :C,from,to, */ 2705/* :C,from,to, */
2708static Boolean 2706static Boolean
2709ApplyModifier_Regex(ApplyModifiersState *st) 2707ApplyModifier_Regex(ApplyModifiersState *st)
2710{ 2708{
2711 VarREPattern pattern; 2709 VarREPattern pattern;
2712 char *re; 2710 char *re;
2713 int error; 2711 int error;
2714 Var_Parse_State tmpparsestate; 2712 Var_Parse_State tmpparsestate;
2715 2713
2716 pattern.pflags = 0; 2714 pattern.pflags = 0;
2717 tmpparsestate = st->parsestate; 2715 tmpparsestate = st->parsestate;
2718 st->delim = st->tstr[1]; 2716 st->delim = st->tstr[1];
2719 st->tstr += 2; 2717 st->tstr += 2;
2720 2718
2721 st->cp = st->tstr; 2719 st->cp = st->tstr;
2722 2720
2723 re = VarGetPattern( 2721 re = VarGetPattern(
2724 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2722 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2725 NULL, NULL, NULL); 2723 NULL, NULL, NULL);
2726 if (re == NULL) 2724 if (re == NULL)
2727 return FALSE; 2725 return FALSE;
2728 2726
2729 pattern.replace = VarGetPattern( 2727 pattern.replace = VarGetPattern(
2730 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2728 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2731 NULL, NULL, NULL); 2729 NULL, NULL, NULL);
2732 if (pattern.replace == NULL) { 2730 if (pattern.replace == NULL) {
2733 free(re); 2731 free(re);
2734 return FALSE; 2732 return FALSE;
2735 } 2733 }
2736 2734
2737 for (;; st->cp++) { 2735 for (;; st->cp++) {
2738 switch (*st->cp) { 2736 switch (*st->cp) {
2739 case 'g': 2737 case 'g':
2740 pattern.pflags |= VARP_SUB_GLOBAL; 2738 pattern.pflags |= VARP_SUB_GLOBAL;
2741 continue; 2739 continue;
2742 case '1': 2740 case '1':
2743 pattern.pflags |= VARP_SUB_ONE; 2741 pattern.pflags |= VARP_SUB_ONE;
2744 continue; 2742 continue;
2745 case 'W': 2743 case 'W':
2746 tmpparsestate.oneBigWord = TRUE; 2744 tmpparsestate.oneBigWord = TRUE;
2747 continue; 2745 continue;
2748 } 2746 }
2749 break; 2747 break;
2750 } 2748 }
2751 2749
2752 st->termc = *st->cp; 2750 st->termc = *st->cp;
2753 2751
2754 error = regcomp(&pattern.re, re, REG_EXTENDED); 2752 error = regcomp(&pattern.re, re, REG_EXTENDED);
2755 free(re); 2753 free(re);
2756 if (error) { 2754 if (error) {
2757 *st->lengthPtr = st->cp - st->start + 1; 2755 *st->lengthPtr = st->cp - st->start + 1;
2758 VarREError(error, &pattern.re, "RE substitution error"); 2756 VarREError(error, &pattern.re, "RE substitution error");
2759 free(pattern.replace); 2757 free(pattern.replace);
2760 return FALSE; 2758 return FALSE;
2761 } 2759 }
2762 2760
2763 pattern.nsub = pattern.re.re_nsub + 1; 2761 pattern.nsub = pattern.re.re_nsub + 1;
2764 if (pattern.nsub < 1) 2762 if (pattern.nsub < 1)
2765 pattern.nsub = 1; 2763 pattern.nsub = 1;
2766 if (pattern.nsub > 10) 2764 if (pattern.nsub > 10)
2767 pattern.nsub = 10; 2765 pattern.nsub = 10;
2768 pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t)); 2766 pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t));
2769 st->newStr = VarModify( 2767 st->newStr = VarModify(
2770 st->ctxt, &tmpparsestate, st->nstr, VarRESubstitute, &pattern); 2768 st->ctxt, &tmpparsestate, st->nstr, VarRESubstitute, &pattern);
2771 regfree(&pattern.re); 2769 regfree(&pattern.re);
2772 free(pattern.replace); 2770 free(pattern.replace);
2773 free(pattern.matches); 2771 free(pattern.matches);
2774 st->delim = '\0'; 2772 st->delim = '\0';
2775 return TRUE; 2773 return TRUE;
2776} 2774}
2777#endif 2775#endif
2778 2776
2779/* :tA, :tu, :tl, etc. */ 2777/* :tA, :tu, :tl, etc. */
2780static Boolean 2778static Boolean
2781ApplyModifier_To(ApplyModifiersState *st) 2779ApplyModifier_To(ApplyModifiersState *st)
2782{ 2780{
2783 st->cp = st->tstr + 1; /* make sure it is set */ 2781 st->cp = st->tstr + 1; /* make sure it is set */
2784 if (st->tstr[1] != st->endc && st->tstr[1] != ':') { 2782 if (st->tstr[1] != st->endc && st->tstr[1] != ':') {
2785 if (st->tstr[1] == 's') { 2783 if (st->tstr[1] == 's') {
2786 /* Use the char (if any) at st->tstr[2] as the word separator. */ 2784 /* Use the char (if any) at st->tstr[2] as the word separator. */
2787 VarPattern pattern; 2785 VarPattern pattern;
2788 2786
2789 if (st->tstr[2] != st->endc && 2787 if (st->tstr[2] != st->endc &&
2790 (st->tstr[3] == st->endc || st->tstr[3] == ':')) { 2788 (st->tstr[3] == st->endc || st->tstr[3] == ':')) {
2791 /* ":ts<unrecognised><endc>" or 2789 /* ":ts<unrecognised><endc>" or
2792 * ":ts<unrecognised>:" */ 2790 * ":ts<unrecognised>:" */
2793 st->parsestate.varSpace = st->tstr[2]; 2791 st->parsestate.varSpace = st->tstr[2];
2794 st->cp = st->tstr + 3; 2792 st->cp = st->tstr + 3;
2795 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') { 2793 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2796 /* ":ts<endc>" or ":ts:" */ 2794 /* ":ts<endc>" or ":ts:" */
2797 st->parsestate.varSpace = 0; /* no separator */ 2795 st->parsestate.varSpace = 0; /* no separator */
2798 st->cp = st->tstr + 2; 2796 st->cp = st->tstr + 2;
2799 } else if (st->tstr[2] == '\\') { 2797 } else if (st->tstr[2] == '\\') {
2800 const char *xp = &st->tstr[3]; 2798 const char *xp = &st->tstr[3];
2801 int base = 8; /* assume octal */ 2799 int base = 8; /* assume octal */
2802 2800
2803 switch (st->tstr[3]) { 2801 switch (st->tstr[3]) {
2804 case 'n': 2802 case 'n':
2805 st->parsestate.varSpace = '\n'; 2803 st->parsestate.varSpace = '\n';
2806 st->cp = st->tstr + 4; 2804 st->cp = st->tstr + 4;
2807 break; 2805 break;
2808 case 't': 2806 case 't':
2809 st->parsestate.varSpace = '\t'; 2807 st->parsestate.varSpace = '\t';
2810 st->cp = st->tstr + 4; 2808 st->cp = st->tstr + 4;
2811 break; 2809 break;
2812 case 'x': 2810 case 'x':
2813 base = 16; 2811 base = 16;
2814 xp++; 2812 xp++;
2815 goto get_numeric; 2813 goto get_numeric;
2816 case '0': 2814 case '0':
2817 base = 0; 2815 base = 0;
2818 goto get_numeric; 2816 goto get_numeric;
2819 default: 2817 default:
2820 if (isdigit((unsigned char)st->tstr[3])) { 2818 if (isdigit((unsigned char)st->tstr[3])) {
2821 char *ep; 2819 char *ep;
2822 get_numeric: 2820 get_numeric:
2823 st->parsestate.varSpace = strtoul(xp, &ep, base); 2821 st->parsestate.varSpace = strtoul(xp, &ep, base);
2824 if (*ep != ':' && *ep != st->endc) 2822 if (*ep != ':' && *ep != st->endc)
2825 return FALSE; 2823 return FALSE;
2826 st->cp = ep; 2824 st->cp = ep;
2827 } else { 2825 } else {
2828 /* ":ts<backslash><unrecognised>". */ 2826 /* ":ts<backslash><unrecognised>". */
2829 return FALSE; 2827 return FALSE;
2830 } 2828 }
2831 break; 2829 break;
2832 } 2830 }
2833 } else { 2831 } else {
2834 /* Found ":ts<unrecognised><unrecognised>". */ 2832 /* Found ":ts<unrecognised><unrecognised>". */
2835 return FALSE; 2833 return FALSE;
2836 } 2834 }
2837 2835
2838 st->termc = *st->cp; 2836 st->termc = *st->cp;
2839 2837
2840 /* 2838 /*
2841 * We cannot be certain that VarModify will be used - even if there 2839 * We cannot be certain that VarModify will be used - even if there
2842 * is a subsequent modifier, so do a no-op VarSubstitute now to for 2840 * is a subsequent modifier, so do a no-op VarSubstitute now to for
2843 * str to be re-expanded without the spaces. 2841 * str to be re-expanded without the spaces.
2844 */ 2842 */
2845 pattern.pflags = VARP_SUB_ONE; 2843 pattern.pflags = VARP_SUB_ONE;
2846 pattern.lhs = pattern.rhs = "\032"; 2844 pattern.lhs = pattern.rhs = "\032";
2847 pattern.leftLen = pattern.rightLen = 1; 2845 pattern.leftLen = pattern.rightLen = 1;
2848 2846
2849 st->newStr = VarModify( 2847 st->newStr = VarModify(
2850 st->ctxt, &st->parsestate, st->nstr, VarSubstitute, &pattern); 2848 st->ctxt, &st->parsestate, st->nstr, VarSubstitute, &pattern);
2851 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') { 2849 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2852 /* Check for two-character options: ":tu", ":tl" */ 2850 /* Check for two-character options: ":tu", ":tl" */
2853 if (st->tstr[1] == 'A') { /* absolute path */ 2851 if (st->tstr[1] == 'A') { /* absolute path */
2854 st->newStr = VarModify( 2852 st->newStr = VarModify(
2855 st->ctxt, &st->parsestate, st->nstr, VarRealpath, NULL); 2853 st->ctxt, &st->parsestate, st->nstr, VarRealpath, NULL);
2856 st->cp = st->tstr + 2; 2854 st->cp = st->tstr + 2;
2857 st->termc = *st->cp; 2855 st->termc = *st->cp;
2858 } else if (st->tstr[1] == 'u') { 2856 } else if (st->tstr[1] == 'u') {
2859 char *dp = bmake_strdup(st->nstr); 2857 char *dp = bmake_strdup(st->nstr);
2860 for (st->newStr = dp; *dp; dp++) 2858 for (st->newStr = dp; *dp; dp++)
2861 *dp = toupper((unsigned char)*dp); 2859 *dp = toupper((unsigned char)*dp);
2862 st->cp = st->tstr + 2; 2860 st->cp = st->tstr + 2;
2863 st->termc = *st->cp; 2861 st->termc = *st->cp;
2864 } else if (st->tstr[1] == 'l') { 2862 } else if (st->tstr[1] == 'l') {
2865 char *dp = bmake_strdup(st->nstr); 2863 char *dp = bmake_strdup(st->nstr);
2866 for (st->newStr = dp; *dp; dp++) 2864 for (st->newStr = dp; *dp; dp++)
2867 *dp = tolower((unsigned char)*dp); 2865 *dp = tolower((unsigned char)*dp);
2868 st->cp = st->tstr + 2; 2866 st->cp = st->tstr + 2;
2869 st->termc = *st->cp; 2867 st->termc = *st->cp;
2870 } else if (st->tstr[1] == 'W' || st->tstr[1] == 'w') { 2868 } else if (st->tstr[1] == 'W' || st->tstr[1] == 'w') {
2871 st->parsestate.oneBigWord = (st->tstr[1] == 'W'); 2869 st->parsestate.oneBigWord = (st->tstr[1] == 'W');
2872 st->newStr = st->nstr; 2870 st->newStr = st->nstr;
2873 st->cp = st->tstr + 2; 2871 st->cp = st->tstr + 2;
2874 st->termc = *st->cp; 2872 st->termc = *st->cp;
2875 } else { 2873 } else {
2876 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ 2874 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2877 return FALSE; 2875 return FALSE;
2878 } 2876 }
2879 } else { 2877 } else {
2880 /* Found ":t<unrecognised><unrecognised>". */ 2878 /* Found ":t<unrecognised><unrecognised>". */
2881 return FALSE; 2879 return FALSE;
2882 } 2880 }
2883 } else { 2881 } else {
2884 /* Found ":t<endc>" or ":t:". */ 2882 /* Found ":t<endc>" or ":t:". */
2885 return FALSE; 2883 return FALSE;
2886 } 2884 }
2887 return TRUE; 2885 return TRUE;
2888} 2886}
2889 2887
2890/* :[#], :[1], etc. */ 2888/* :[#], :[1], etc. */
2891static int 2889static int
2892ApplyModifier_Words(ApplyModifiersState *st) 2890ApplyModifier_Words(ApplyModifiersState *st)
2893{ 2891{
2894 /* 2892 /*
2895 * Look for the closing ']', recursively 2893 * Look for the closing ']', recursively
2896 * expanding any embedded variables. 2894 * expanding any embedded variables.
2897 * 2895 *
2898 * estr is a pointer to the expanded result, 2896 * estr is a pointer to the expanded result,
2899 * which we must free(). 2897 * which we must free().
2900 */ 2898 */
2901 char *estr; 2899 char *estr;
2902 2900
2903 st->cp = st->tstr + 1; /* point to char after '[' */ 2901 st->cp = st->tstr + 1; /* point to char after '[' */
2904 st->delim = ']'; /* look for closing ']' */ 2902 st->delim = ']'; /* look for closing ']' */
2905 estr = VarGetPattern( 2903 estr = VarGetPattern(
2906 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 2904 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2907 NULL, NULL, NULL); 2905 NULL, NULL, NULL);
2908 if (estr == NULL) 2906 if (estr == NULL)
2909 return 'c'; /* report missing ']' */ 2907 return 'c'; /* report missing ']' */
2910 /* now st->cp points just after the closing ']' */ 2908 /* now st->cp points just after the closing ']' */
2911 st->delim = '\0'; 2909 st->delim = '\0';
2912 if (st->cp[0] != ':' && st->cp[0] != st->endc) { 2910 if (st->cp[0] != ':' && st->cp[0] != st->endc) {
2913 /* Found junk after ']' */ 2911 /* Found junk after ']' */
2914 free(estr); 2912 free(estr);
2915 return 'b'; 2913 return 'b';
2916 } 2914 }
2917 if (estr[0] == '\0') { 2915 if (estr[0] == '\0') {
2918 /* Found empty square brackets in ":[]". */ 2916 /* Found empty square brackets in ":[]". */
2919 free(estr); 2917 free(estr);
2920 return 'b'; 2918 return 'b';
2921 } else if (estr[0] == '#' && estr[1] == '\0') { 2919 } else if (estr[0] == '#' && estr[1] == '\0') {
2922 /* Found ":[#]" */ 2920 /* Found ":[#]" */
2923 2921
2924 /* 2922 /*
2925 * We will need enough space for the decimal 2923 * We will need enough space for the decimal
2926 * representation of an int. We calculate the 2924 * representation of an int. We calculate the
2927 * space needed for the octal representation, 2925 * space needed for the octal representation,
2928 * and add enough slop to cope with a '-' sign 2926 * and add enough slop to cope with a '-' sign
2929 * (which should never be needed) and a '\0' 2927 * (which should never be needed) and a '\0'
2930 * string terminator. 2928 * string terminator.
2931 */ 2929 */
2932 int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2; 2930 int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
2933 2931
2934 st->newStr = bmake_malloc(newStrSize); 2932 st->newStr = bmake_malloc(newStrSize);
2935 if (st->parsestate.oneBigWord) { 2933 if (st->parsestate.oneBigWord) {
2936 strncpy(st->newStr, "1", newStrSize); 2934 strncpy(st->newStr, "1", newStrSize);
2937 } else { 2935 } else {
2938 /* XXX: brk_string() is a rather expensive 2936 /* XXX: brk_string() is a rather expensive
2939 * way of counting words. */ 2937 * way of counting words. */
2940 char **av; 2938 char **av;
2941 char *as; 2939 char *as;
2942 int ac; 2940 int ac;
2943 2941
2944 av = brk_string(st->nstr, &ac, FALSE, &as); 2942 av = brk_string(st->nstr, &ac, FALSE, &as);
2945 snprintf(st->newStr, newStrSize, "%d", ac); 2943 snprintf(st->newStr, newStrSize, "%d", ac);
2946 free(as); 2944 free(as);
2947 free(av); 2945 free(av);
2948 } 2946 }
2949 st->termc = *st->cp; 2947 st->termc = *st->cp;
2950 free(estr); 2948 free(estr);
2951 return 0; 2949 return 0;
2952 } else if (estr[0] == '*' && estr[1] == '\0') { 2950 } else if (estr[0] == '*' && estr[1] == '\0') {
2953 /* Found ":[*]" */ 2951 /* Found ":[*]" */
2954 st->parsestate.oneBigWord = TRUE; 2952 st->parsestate.oneBigWord = TRUE;
2955 st->newStr = st->nstr; 2953 st->newStr = st->nstr;
2956 st->termc = *st->cp; 2954 st->termc = *st->cp;
2957 free(estr); 2955 free(estr);
2958 return 0; 2956 return 0;
2959 } else if (estr[0] == '@' && estr[1] == '\0') { 2957 } else if (estr[0] == '@' && estr[1] == '\0') {
2960 /* Found ":[@]" */ 2958 /* Found ":[@]" */
2961 st->parsestate.oneBigWord = FALSE; 2959 st->parsestate.oneBigWord = FALSE;
2962 st->newStr = st->nstr; 2960 st->newStr = st->nstr;
2963 st->termc = *st->cp; 2961 st->termc = *st->cp;
2964 free(estr); 2962 free(estr);
2965 return 0; 2963 return 0;
2966 } else { 2964 } else {
2967 char *ep; 2965 char *ep;
2968 /* 2966 /*
2969 * We expect estr to contain a single 2967 * We expect estr to contain a single
2970 * integer for :[N], or two integers 2968 * integer for :[N], or two integers
2971 * separated by ".." for :[start..end]. 2969 * separated by ".." for :[start..end].
2972 */ 2970 */
2973 VarSelectWords_t seldata = { 0, 0 }; 2971 VarSelectWords_t seldata = { 0, 0 };
2974 2972
2975 seldata.start = strtol(estr, &ep, 0); 2973 seldata.start = strtol(estr, &ep, 0);
2976 if (ep == estr) { 2974 if (ep == estr) {
2977 /* Found junk instead of a number */ 2975 /* Found junk instead of a number */
2978 free(estr); 2976 free(estr);
2979 return 'b'; 2977 return 'b';
2980 } else if (ep[0] == '\0') { 2978 } else if (ep[0] == '\0') {
2981 /* Found only one integer in :[N] */ 2979 /* Found only one integer in :[N] */
2982 seldata.end = seldata.start; 2980 seldata.end = seldata.start;
2983 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') { 2981 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2984 /* Expecting another integer after ".." */ 2982 /* Expecting another integer after ".." */
2985 ep += 2; 2983 ep += 2;
2986 seldata.end = strtol(ep, &ep, 0); 2984 seldata.end = strtol(ep, &ep, 0);
2987 if (ep[0] != '\0') { 2985 if (ep[0] != '\0') {
2988 /* Found junk after ".." */ 2986 /* Found junk after ".." */
2989 free(estr); 2987 free(estr);
2990 return 'b'; 2988 return 'b';
2991 } 2989 }
2992 } else { 2990 } else {
2993 /* Found junk instead of ".." */ 2991 /* Found junk instead of ".." */
2994 free(estr); 2992 free(estr);
2995 return 'b'; 2993 return 'b';
2996 } 2994 }
2997 /* 2995 /*
2998 * Now seldata is properly filled in, 2996 * Now seldata is properly filled in,
2999 * but we still have to check for 0 as 2997 * but we still have to check for 0 as
3000 * a special case. 2998 * a special case.
3001 */ 2999 */
3002 if (seldata.start == 0 && seldata.end == 0) { 3000 if (seldata.start == 0 && seldata.end == 0) {
3003 /* ":[0]" or perhaps ":[0..0]" */ 3001 /* ":[0]" or perhaps ":[0..0]" */
3004 st->parsestate.oneBigWord = TRUE; 3002 st->parsestate.oneBigWord = TRUE;
3005 st->newStr = st->nstr; 3003 st->newStr = st->nstr;
3006 st->termc = *st->cp; 3004 st->termc = *st->cp;
3007 free(estr); 3005 free(estr);
3008 return 0; 3006 return 0;
3009 } else if (seldata.start == 0 || seldata.end == 0) { 3007 } else if (seldata.start == 0 || seldata.end == 0) {
3010 /* ":[0..N]" or ":[N..0]" */ 3008 /* ":[0..N]" or ":[N..0]" */
3011 free(estr); 3009 free(estr);
3012 return 'b'; 3010 return 'b';
3013 } 3011 }
3014 /* Normal case: select the words described by seldata. */ 3012 /* Normal case: select the words described by seldata. */
3015 st->newStr = VarSelectWords( 3013 st->newStr = VarSelectWords(
3016 st->ctxt, &st->parsestate, st->nstr, &seldata); 3014 st->ctxt, &st->parsestate, st->nstr, &seldata);
3017 3015
3018 st->termc = *st->cp; 3016 st->termc = *st->cp;
3019 free(estr); 3017 free(estr);
3020 return 0; 3018 return 0;
3021 } 3019 }
3022} 3020}
3023 3021
3024/* :O or :Ox */ 3022/* :O or :Ox */
3025static Boolean 3023static Boolean
3026ApplyModifier_Order(ApplyModifiersState *st) 3024ApplyModifier_Order(ApplyModifiersState *st)
3027{ 3025{
3028 char otype; 3026 char otype;
3029 3027
3030 st->cp = st->tstr + 1; /* skip to the rest in any case */ 3028 st->cp = st->tstr + 1; /* skip to the rest in any case */
3031 if (st->tstr[1] == st->endc || st->tstr[1] == ':') { 3029 if (st->tstr[1] == st->endc || st->tstr[1] == ':') {
3032 otype = 's'; 3030 otype = 's';
3033 st->termc = *st->cp; 3031 st->termc = *st->cp;
3034 } else if ((st->tstr[1] == 'r' || st->tstr[1] == 'x') && 3032 } else if ((st->tstr[1] == 'r' || st->tstr[1] == 'x') &&
3035 (st->tstr[2] == st->endc || st->tstr[2] == ':')) { 3033 (st->tstr[2] == st->endc || st->tstr[2] == ':')) {
3036 otype = st->tstr[1]; 3034 otype = st->tstr[1];
3037 st->cp = st->tstr + 2; 3035 st->cp = st->tstr + 2;
3038 st->termc = *st->cp; 3036 st->termc = *st->cp;
3039 } else { 3037 } else {
3040 return FALSE; 3038 return FALSE;
3041 } 3039 }
3042 st->newStr = VarOrder(st->nstr, otype); 3040 st->newStr = VarOrder(st->nstr, otype);
3043 return TRUE; 3041 return TRUE;
3044} 3042}
3045 3043
3046/* :? then : else */ 3044/* :? then : else */
3047static Boolean 3045static Boolean
3048ApplyModifier_IfElse(ApplyModifiersState *st) 3046ApplyModifier_IfElse(ApplyModifiersState *st)
3049{ 3047{
3050 Boolean value; 3048 Boolean value;
3051 int cond_rc; 3049 int cond_rc;
3052 VarPatternFlags then_flags, else_flags; 3050 VarPatternFlags then_flags, else_flags;
3053 /* FIXME: IfElse has nothing to do with VarPatternFlags */ 3051 /* FIXME: IfElse has nothing to do with VarPatternFlags */
3054 3052
3055 /* find ':', and then substitute accordingly */ 3053 /* find ':', and then substitute accordingly */
3056 if (st->flags & VARE_WANTRES) { 3054 if (st->flags & VARE_WANTRES) {
3057 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); 3055 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
3058 then_flags = cond_rc != COND_INVALID && value ? 0 : VAR_NOSUBST; 3056 then_flags = cond_rc != COND_INVALID && value ? 0 : VAR_NOSUBST;
3059 else_flags = cond_rc != COND_INVALID && !value ? 0 : VAR_NOSUBST; 3057 else_flags = cond_rc != COND_INVALID && !value ? 0 : VAR_NOSUBST;
3060 } else { 3058 } else {
3061 /* we are just consuming and discarding */ 3059 /* we are just consuming and discarding */
3062 cond_rc = value = 0; 3060 cond_rc = value = 0;
3063 then_flags = else_flags = VAR_NOSUBST; 3061 then_flags = else_flags = VAR_NOSUBST;
3064 } 3062 }
3065 3063
3066 st->cp = ++st->tstr; 3064 st->cp = ++st->tstr;
3067 st->delim = ':'; 3065 st->delim = ':';
3068 int then_len; 3066 int then_len;
3069 char *then_expr = VarGetPattern( 3067 char *then_expr = VarGetPattern(
3070 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim, 3068 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3071 &then_flags, &then_len, NULL); 3069 &then_flags, &then_len, NULL);
3072 if (then_expr == NULL) 3070 if (then_expr == NULL)
3073 return FALSE; 3071 return FALSE;