xref: /freebsd/contrib/bmake/var.c (revision 3110d4ebd6c0848cf5e25890d01791bb407e2a9b)
1 /*	$NetBSD: var.c,v 1.781 2021/01/10 23:59:53 rillig Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Adam de Boor.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
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
20  *    without specific prior written permission.
21  *
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
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1989 by Berkeley Softworks
37  * All rights reserved.
38  *
39  * This code is derived from software contributed to Berkeley by
40  * Adam de Boor.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *	This product includes software developed by the University of
53  *	California, Berkeley and 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
56  *    without specific prior written permission.
57  *
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
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
68  * SUCH DAMAGE.
69  */
70 
71 /*
72  * Handling of variables and the expressions formed from them.
73  *
74  * Variables are set using lines of the form VAR=value.  Both the variable
75  * name and the value can contain references to other variables, by using
76  * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77  *
78  * Interface:
79  *	Var_Init	Initialize this module.
80  *
81  *	Var_End		Clean up the module.
82  *
83  *	Var_Set		Set the value of the variable, creating it if
84  *			necessary.
85  *
86  *	Var_Append	Append more characters to the variable, creating it if
87  *			necessary. A space is placed between the old value and
88  *			the new one.
89  *
90  *	Var_Exists	See if a variable exists.
91  *
92  *	Var_Value	Return the unexpanded value of a variable, or NULL if
93  *			the variable is undefined.
94  *
95  *	Var_Subst	Substitute all variable expressions in a string.
96  *
97  *	Var_Parse	Parse a variable expression such as ${VAR:Mpattern}.
98  *
99  *	Var_Delete	Delete a variable.
100  *
101  *	Var_ReexportVars
102  *			Export some or even all variables to the environment
103  *			of this process and its child processes.
104  *
105  *	Var_Export	Export the variable to the environment of this process
106  *			and its child processes.
107  *
108  *	Var_UnExport	Don't export the variable anymore.
109  *
110  * Debugging:
111  *	Var_Stats	Print out hashing statistics if in -dh mode.
112  *
113  *	Var_Dump	Print out all variables defined in the given context.
114  *
115  * XXX: There's a lot of duplication in these functions.
116  */
117 
118 #include <sys/stat.h>
119 #include <sys/types.h>
120 #ifndef NO_REGEX
121 #include <regex.h>
122 #endif
123 
124 #include "make.h"
125 
126 #include <errno.h>
127 #ifdef HAVE_INTTYPES_H
128 #include <inttypes.h>
129 #elif defined(HAVE_STDINT_H)
130 #include <stdint.h>
131 #endif
132 #ifdef HAVE_LIMITS_H
133 #include <limits.h>
134 #endif
135 #include <time.h>
136 
137 #include "dir.h"
138 #include "job.h"
139 #include "metachar.h"
140 
141 /*	"@(#)var.c	8.3 (Berkeley) 3/19/94" */
142 MAKE_RCSID("$NetBSD: var.c,v 1.781 2021/01/10 23:59:53 rillig Exp $");
143 
144 typedef enum VarFlags {
145 	VAR_NONE	= 0,
146 
147 	/*
148 	 * The variable's value is currently being used by Var_Parse or
149 	 * Var_Subst.  This marker is used to avoid endless recursion.
150 	 */
151 	VAR_IN_USE = 0x01,
152 
153 	/*
154 	 * The variable comes from the environment.
155 	 * These variables are not registered in any GNode, therefore they
156 	 * must be freed as soon as they are not used anymore.
157 	 */
158 	VAR_FROM_ENV = 0x02,
159 
160 	/*
161 	 * The variable is exported to the environment, to be used by child
162 	 * processes.
163 	 */
164 	VAR_EXPORTED = 0x10,
165 
166 	/*
167 	 * At the point where this variable was exported, it contained an
168 	 * unresolved reference to another variable.  Before any child
169 	 * process is started, it needs to be exported again, in the hope
170 	 * that the referenced variable can then be resolved.
171 	 */
172 	VAR_REEXPORT = 0x20,
173 
174 	/* The variable came from the command line. */
175 	VAR_FROM_CMD = 0x40,
176 
177 	/*
178 	 * The variable value cannot be changed anymore, and the variable
179 	 * cannot be deleted.  Any attempts to do so are silently ignored,
180 	 * they are logged with -dv though.
181 	 */
182 	VAR_READONLY = 0x80
183 } VarFlags;
184 
185 /*
186  * Variables are defined using one of the VAR=value assignments.  Their
187  * value can be queried by expressions such as $V, ${VAR}, or with modifiers
188  * such as ${VAR:S,from,to,g:Q}.
189  *
190  * There are 3 kinds of variables: context variables, environment variables,
191  * undefined variables.
192  *
193  * Context variables are stored in a GNode.context.  The only way to undefine
194  * a context variable is using the .undef directive.  In particular, it must
195  * not be possible to undefine a variable during the evaluation of an
196  * expression, or Var.name might point nowhere.
197  *
198  * Environment variables are temporary.  They are returned by VarFind, and
199  * after using them, they must be freed using VarFreeEnv.
200  *
201  * Undefined variables occur during evaluation of variable expressions such
202  * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
203  */
204 typedef struct Var {
205 	/*
206 	 * The name of the variable, once set, doesn't change anymore.
207 	 * For context variables, it aliases the corresponding HashEntry name.
208 	 * For environment and undefined variables, it is allocated.
209 	 */
210 	FStr name;
211 
212 	/* The unexpanded value of the variable. */
213 	Buffer val;
214 	/* Miscellaneous status flags. */
215 	VarFlags flags;
216 } Var;
217 
218 /*
219  * Exporting vars is expensive so skip it if we can
220  */
221 typedef enum VarExportedMode {
222 	VAR_EXPORTED_NONE,
223 	VAR_EXPORTED_SOME,
224 	VAR_EXPORTED_ALL
225 } VarExportedMode;
226 
227 typedef enum UnexportWhat {
228 	UNEXPORT_NAMED,
229 	UNEXPORT_ALL,
230 	UNEXPORT_ENV
231 } UnexportWhat;
232 
233 /* Flags for pattern matching in the :S and :C modifiers */
234 typedef enum VarPatternFlags {
235 	VARP_NONE		= 0,
236 	/* Replace as often as possible ('g') */
237 	VARP_SUB_GLOBAL		= 1 << 0,
238 	/* Replace only once ('1') */
239 	VARP_SUB_ONE		= 1 << 1,
240 	/* Match at start of word ('^') */
241 	VARP_ANCHOR_START	= 1 << 2,
242 	/* Match at end of word ('$') */
243 	VARP_ANCHOR_END		= 1 << 3
244 } VarPatternFlags;
245 
246 /* SepBuf is a string being built from words, interleaved with separators. */
247 typedef struct SepBuf {
248 	Buffer buf;
249 	Boolean needSep;
250 	/* Usually ' ', but see the ':ts' modifier. */
251 	char sep;
252 } SepBuf;
253 
254 
255 ENUM_FLAGS_RTTI_4(VarEvalFlags,
256 		  VARE_UNDEFERR, VARE_WANTRES, VARE_KEEP_DOLLAR,
257 		  VARE_KEEP_UNDEF);
258 
259 /*
260  * This lets us tell if we have replaced the original environ
261  * (which we cannot free).
262  */
263 char **savedEnv = NULL;
264 
265 /*
266  * Special return value for Var_Parse, indicating a parse error.  It may be
267  * caused by an undefined variable, a syntax error in a modifier or
268  * something entirely different.
269  */
270 char var_Error[] = "";
271 
272 /*
273  * Special return value for Var_Parse, indicating an undefined variable in
274  * a case where VARE_UNDEFERR is not set.  This undefined variable is
275  * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
276  * be deferred until it is defined in an actual target.
277  */
278 static char varUndefined[] = "";
279 
280 /*
281  * Traditionally this make consumed $$ during := like any other expansion.
282  * Other make's do not, and this make follows straight since 2016-01-09.
283  *
284  * This knob allows controlling the behavior.
285  * FALSE to consume $$ during := assignment.
286  * TRUE to preserve $$ during := assignment.
287  */
288 #define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
289 static Boolean save_dollars = FALSE;
290 
291 /*
292  * Internally, variables are contained in four different contexts.
293  *	1) the environment. They cannot be changed. If an environment
294  *	   variable is appended to, the result is placed in the global
295  *	   context.
296  *	2) the global context. Variables set in the makefiles are located
297  *	   here.
298  *	3) the command-line context. All variables set on the command line
299  *	   are placed in this context.
300  *	4) the local context. Each target has associated with it a context
301  *	   list. On this list are located the structures describing such
302  *	   local variables as $(@) and $(*)
303  * The four contexts are searched in the reverse order from which they are
304  * listed (but see opts.checkEnvFirst).
305  */
306 GNode          *VAR_INTERNAL;	/* variables from make itself */
307 GNode          *VAR_GLOBAL;	/* variables from the makefile */
308 GNode          *VAR_CMDLINE;	/* variables defined on the command-line */
309 
310 ENUM_FLAGS_RTTI_6(VarFlags,
311 		  VAR_IN_USE, VAR_FROM_ENV,
312 		  VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
313 
314 static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
315 
316 
317 static Var *
318 VarNew(FStr name, const char *value, VarFlags flags)
319 {
320 	size_t value_len = strlen(value);
321 	Var *var = bmake_malloc(sizeof *var);
322 	var->name = name;
323 	Buf_InitSize(&var->val, value_len + 1);
324 	Buf_AddBytes(&var->val, value, value_len);
325 	var->flags = flags;
326 	return var;
327 }
328 
329 static const char *
330 CanonicalVarname(const char *name)
331 {
332 	if (*name == '.' && ch_isupper(name[1])) {
333 		switch (name[1]) {
334 		case 'A':
335 			if (strcmp(name, ".ALLSRC") == 0)
336 				name = ALLSRC;
337 			if (strcmp(name, ".ARCHIVE") == 0)
338 				name = ARCHIVE;
339 			break;
340 		case 'I':
341 			if (strcmp(name, ".IMPSRC") == 0)
342 				name = IMPSRC;
343 			break;
344 		case 'M':
345 			if (strcmp(name, ".MEMBER") == 0)
346 				name = MEMBER;
347 			break;
348 		case 'O':
349 			if (strcmp(name, ".OODATE") == 0)
350 				name = OODATE;
351 			break;
352 		case 'P':
353 			if (strcmp(name, ".PREFIX") == 0)
354 				name = PREFIX;
355 			break;
356 		case 'S':
357 			if (strcmp(name, ".SHELL") == 0) {
358 				if (shellPath == NULL)
359 					Shell_Init();
360 			}
361 			break;
362 		case 'T':
363 			if (strcmp(name, ".TARGET") == 0)
364 				name = TARGET;
365 			break;
366 		}
367 	}
368 
369 	/* GNU make has an additional alias $^ == ${.ALLSRC}. */
370 
371 	return name;
372 }
373 
374 static Var *
375 GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
376 {
377 	return HashTable_FindValueHash(&ctxt->vars, varname, hash);
378 }
379 
380 /*
381  * Find the variable in the context, and maybe in other contexts as well.
382  *
383  * Input:
384  *	name		name to find, is not expanded any further
385  *	ctxt		context in which to look first
386  *	elsewhere	TRUE to look in other contexts as well
387  *
388  * Results:
389  *	The found variable, or NULL if the variable does not exist.
390  *	If the variable is an environment variable, it must be freed using
391  *	VarFreeEnv after use.
392  */
393 static Var *
394 VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
395 {
396 	Var *var;
397 	unsigned int nameHash;
398 
399 	/*
400 	 * If the variable name begins with a '.', it could very well be
401 	 * one of the local ones.  We check the name against all the local
402 	 * variables and substitute the short version in for 'name' if it
403 	 * matches one of them.
404 	 */
405 	name = CanonicalVarname(name);
406 	nameHash = Hash_Hash(name);
407 
408 	/* First look for the variable in the given context. */
409 	var = GNode_FindVar(ctxt, name, nameHash);
410 	if (!elsewhere)
411 		return var;
412 
413 	/*
414 	 * The variable was not found in the given context.
415 	 * Now look for it in the other contexts as well.
416 	 */
417 	if (var == NULL && ctxt != VAR_CMDLINE)
418 		var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
419 
420 	if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
421 		var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
422 		if (var == NULL && ctxt != VAR_INTERNAL) {
423 			/* VAR_INTERNAL is subordinate to VAR_GLOBAL */
424 			var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
425 		}
426 	}
427 
428 	if (var == NULL) {
429 		char *env;
430 
431 		if ((env = getenv(name)) != NULL) {
432 			char *varname = bmake_strdup(name);
433 			return VarNew(FStr_InitOwn(varname), env, VAR_FROM_ENV);
434 		}
435 
436 		if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
437 			var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
438 			if (var == NULL && ctxt != VAR_INTERNAL)
439 				var = GNode_FindVar(VAR_INTERNAL, name,
440 				    nameHash);
441 			return var;
442 		}
443 
444 		return NULL;
445 	}
446 
447 	return var;
448 }
449 
450 /*
451  * If the variable is an environment variable, free it.
452  *
453  * Input:
454  *	v		the variable
455  *	freeValue	true if the variable value should be freed as well
456  *
457  * Results:
458  *	TRUE if it is an environment variable, FALSE otherwise.
459  */
460 static Boolean
461 VarFreeEnv(Var *v, Boolean freeValue)
462 {
463 	if (!(v->flags & VAR_FROM_ENV))
464 		return FALSE;
465 
466 	FStr_Done(&v->name);
467 	Buf_Destroy(&v->val, freeValue);
468 	free(v);
469 	return TRUE;
470 }
471 
472 /*
473  * Add a new variable of the given name and value to the given context.
474  * The name and val arguments are duplicated so they may safely be freed.
475  */
476 static void
477 VarAdd(const char *name, const char *val, GNode *ctxt, VarSetFlags flags)
478 {
479 	HashEntry *he = HashTable_CreateEntry(&ctxt->vars, name, NULL);
480 	Var *v = VarNew(FStr_InitRefer(/* aliased to */ he->key), val,
481 	    flags & VAR_SET_READONLY ? VAR_READONLY : VAR_NONE);
482 	HashEntry_Set(he, v);
483 	if (!(ctxt->flags & INTERNAL))
484 		DEBUG3(VAR, "%s:%s = %s\n", ctxt->name, name, val);
485 }
486 
487 /*
488  * Remove a variable from a context, freeing all related memory as well.
489  * The variable name is kept as-is, it is not expanded.
490  */
491 void
492 Var_DeleteVar(const char *varname, GNode *ctxt)
493 {
494 	HashEntry *he = HashTable_FindEntry(&ctxt->vars, varname);
495 	Var *v;
496 
497 	if (he == NULL) {
498 		DEBUG2(VAR, "%s:delete %s (not found)\n", ctxt->name, varname);
499 		return;
500 	}
501 
502 	DEBUG2(VAR, "%s:delete %s\n", ctxt->name, varname);
503 	v = HashEntry_Get(he);
504 	if (v->flags & VAR_EXPORTED)
505 		unsetenv(v->name.str);
506 	if (strcmp(v->name.str, MAKE_EXPORTED) == 0)
507 		var_exportedVars = VAR_EXPORTED_NONE;
508 	assert(v->name.freeIt == NULL);
509 	HashTable_DeleteEntry(&ctxt->vars, he);
510 	Buf_Destroy(&v->val, TRUE);
511 	free(v);
512 }
513 
514 /*
515  * Remove a variable from a context, freeing all related memory as well.
516  * The variable name is expanded once.
517  */
518 void
519 Var_Delete(const char *name, GNode *ctxt)
520 {
521 	FStr varname = FStr_InitRefer(name);
522 
523 	if (strchr(varname.str, '$') != NULL) {
524 		char *expanded;
525 		(void)Var_Subst(varname.str, VAR_GLOBAL, VARE_WANTRES,
526 		    &expanded);
527 		/* TODO: handle errors */
528 		varname = FStr_InitOwn(expanded);
529 	}
530 
531 	Var_DeleteVar(varname.str, ctxt);
532 	FStr_Done(&varname);
533 }
534 
535 /*
536  * Undefine one or more variables from the global scope.
537  * The argument is expanded exactly once and then split into words.
538  */
539 void
540 Var_Undef(const char *arg)
541 {
542 	VarParseResult vpr;
543 	char *expanded;
544 	Words varnames;
545 	size_t i;
546 
547 	if (arg[0] == '\0') {
548 		Parse_Error(PARSE_FATAL,
549 		    "The .undef directive requires an argument");
550 		return;
551 	}
552 
553 	vpr = Var_Subst(arg, VAR_GLOBAL, VARE_WANTRES, &expanded);
554 	if (vpr != VPR_OK) {
555 		Parse_Error(PARSE_FATAL,
556 		    "Error in variable names to be undefined");
557 		return;
558 	}
559 
560 	varnames = Str_Words(expanded, FALSE);
561 	if (varnames.len == 1 && varnames.words[0][0] == '\0')
562 		varnames.len = 0;
563 
564 	for (i = 0; i < varnames.len; i++) {
565 		const char *varname = varnames.words[i];
566 		Var_DeleteVar(varname, VAR_GLOBAL);
567 	}
568 
569 	Words_Free(varnames);
570 	free(expanded);
571 }
572 
573 static Boolean
574 MayExport(const char *name)
575 {
576 	if (name[0] == '.')
577 		return FALSE;	/* skip internals */
578 	if (name[0] == '-')
579 		return FALSE;	/* skip misnamed variables */
580 	if (name[1] == '\0') {
581 		/*
582 		 * A single char.
583 		 * If it is one of the vars that should only appear in
584 		 * local context, skip it, else we can get Var_Subst
585 		 * into a loop.
586 		 */
587 		switch (name[0]) {
588 		case '@':
589 		case '%':
590 		case '*':
591 		case '!':
592 			return FALSE;
593 		}
594 	}
595 	return TRUE;
596 }
597 
598 static Boolean
599 ExportVarEnv(Var *v)
600 {
601 	const char *name = v->name.str;
602 	char *val = v->val.data;
603 	char *expr;
604 
605 	if ((v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
606 		return FALSE;	/* nothing to do */
607 
608 	if (strchr(val, '$') == NULL) {
609 		if (!(v->flags & VAR_EXPORTED))
610 			setenv(name, val, 1);
611 		return TRUE;
612 	}
613 
614 	if (v->flags & VAR_IN_USE) {
615 		/*
616 		 * We recursed while exporting in a child.
617 		 * This isn't going to end well, just skip it.
618 		 */
619 		return FALSE;
620 	}
621 
622 	/* XXX: name is injected without escaping it */
623 	expr = str_concat3("${", name, "}");
624 	(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
625 	/* TODO: handle errors */
626 	setenv(name, val, 1);
627 	free(val);
628 	free(expr);
629 	return TRUE;
630 }
631 
632 static Boolean
633 ExportVarPlain(Var *v)
634 {
635 	if (strchr(v->val.data, '$') == NULL) {
636 		setenv(v->name.str, v->val.data, 1);
637 		v->flags |= VAR_EXPORTED;
638 		v->flags &= ~(unsigned)VAR_REEXPORT;
639 		return TRUE;
640 	}
641 
642 	/*
643 	 * Flag the variable as something we need to re-export.
644 	 * No point actually exporting it now though,
645 	 * the child process can do it at the last minute.
646 	 */
647 	v->flags |= VAR_EXPORTED | VAR_REEXPORT;
648 	return TRUE;
649 }
650 
651 static Boolean
652 ExportVarLiteral(Var *v)
653 {
654 	if ((v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
655 		return FALSE;
656 
657 	if (!(v->flags & VAR_EXPORTED))
658 		setenv(v->name.str, v->val.data, 1);
659 
660 	return TRUE;
661 }
662 
663 /*
664  * Export a single variable.
665  *
666  * We ignore make internal variables (those which start with '.').
667  * Also we jump through some hoops to avoid calling setenv
668  * more than necessary since it can leak.
669  * We only manipulate flags of vars if 'parent' is set.
670  */
671 static Boolean
672 ExportVar(const char *name, VarExportMode mode)
673 {
674 	Var *v;
675 
676 	if (!MayExport(name))
677 		return FALSE;
678 
679 	v = VarFind(name, VAR_GLOBAL, FALSE);
680 	if (v == NULL)
681 		return FALSE;
682 
683 	if (mode == VEM_ENV)
684 		return ExportVarEnv(v);
685 	else if (mode == VEM_PLAIN)
686 		return ExportVarPlain(v);
687 	else
688 		return ExportVarLiteral(v);
689 }
690 
691 /*
692  * Actually export the variables that have been marked as needing to be
693  * re-exported.
694  */
695 void
696 Var_ReexportVars(void)
697 {
698 	char *xvarnames;
699 
700 	/*
701 	 * Several make implementations support this sort of mechanism for
702 	 * tracking recursion - but each uses a different name.
703 	 * We allow the makefiles to update MAKELEVEL and ensure
704 	 * children see a correctly incremented value.
705 	 */
706 	char tmp[BUFSIZ];
707 	snprintf(tmp, sizeof tmp, "%d", makelevel + 1);
708 	setenv(MAKE_LEVEL_ENV, tmp, 1);
709 
710 	if (var_exportedVars == VAR_EXPORTED_NONE)
711 		return;
712 
713 	if (var_exportedVars == VAR_EXPORTED_ALL) {
714 		HashIter hi;
715 
716 		/* Ouch! Exporting all variables at once is crazy... */
717 		HashIter_Init(&hi, &VAR_GLOBAL->vars);
718 		while (HashIter_Next(&hi) != NULL) {
719 			Var *var = hi.entry->value;
720 			ExportVar(var->name.str, VEM_ENV);
721 		}
722 		return;
723 	}
724 
725 	(void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
726 	    &xvarnames);
727 	/* TODO: handle errors */
728 	if (xvarnames[0] != '\0') {
729 		Words varnames = Str_Words(xvarnames, FALSE);
730 		size_t i;
731 
732 		for (i = 0; i < varnames.len; i++)
733 			ExportVar(varnames.words[i], VEM_ENV);
734 		Words_Free(varnames);
735 	}
736 	free(xvarnames);
737 }
738 
739 static void
740 ExportVars(const char *varnames, Boolean isExport, VarExportMode mode)
741 {
742 	Words words = Str_Words(varnames, FALSE);
743 	size_t i;
744 
745 	if (words.len == 1 && words.words[0][0] == '\0')
746 		words.len = 0;
747 
748 	for (i = 0; i < words.len; i++) {
749 		const char *varname = words.words[i];
750 		if (!ExportVar(varname, mode))
751 			continue;
752 
753 		if (var_exportedVars == VAR_EXPORTED_NONE)
754 			var_exportedVars = VAR_EXPORTED_SOME;
755 
756 		if (isExport && mode == VEM_PLAIN)
757 			Var_Append(MAKE_EXPORTED, varname, VAR_GLOBAL);
758 	}
759 	Words_Free(words);
760 }
761 
762 static void
763 ExportVarsExpand(const char *uvarnames, Boolean isExport, VarExportMode mode)
764 {
765 	char *xvarnames;
766 
767 	(void)Var_Subst(uvarnames, VAR_GLOBAL, VARE_WANTRES, &xvarnames);
768 	/* TODO: handle errors */
769 	ExportVars(xvarnames, isExport, mode);
770 	free(xvarnames);
771 }
772 
773 /* Export the named variables, or all variables. */
774 void
775 Var_Export(VarExportMode mode, const char *varnames)
776 {
777 	if (mode == VEM_PLAIN && varnames[0] == '\0') {
778 		var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
779 		return;
780 	}
781 
782 	ExportVarsExpand(varnames, TRUE, mode);
783 }
784 
785 void
786 Var_ExportVars(const char *varnames)
787 {
788 	ExportVarsExpand(varnames, FALSE, VEM_PLAIN);
789 }
790 
791 
792 extern char **environ;
793 
794 static void
795 ClearEnv(void)
796 {
797 	const char *cp;
798 	char **newenv;
799 
800 	cp = getenv(MAKE_LEVEL_ENV);	/* we should preserve this */
801 	if (environ == savedEnv) {
802 		/* we have been here before! */
803 		newenv = bmake_realloc(environ, 2 * sizeof(char *));
804 	} else {
805 		if (savedEnv != NULL) {
806 			free(savedEnv);
807 			savedEnv = NULL;
808 		}
809 		newenv = bmake_malloc(2 * sizeof(char *));
810 	}
811 
812 	/* Note: we cannot safely free() the original environ. */
813 	environ = savedEnv = newenv;
814 	newenv[0] = NULL;
815 	newenv[1] = NULL;
816 	if (cp != NULL && *cp != '\0')
817 		setenv(MAKE_LEVEL_ENV, cp, 1);
818 }
819 
820 static void
821 GetVarnamesToUnexport(Boolean isEnv, const char *arg,
822 		      FStr *out_varnames, UnexportWhat *out_what)
823 {
824 	UnexportWhat what;
825 	FStr varnames = FStr_InitRefer("");
826 
827 	if (isEnv) {
828 		if (arg[0] != '\0') {
829 			Parse_Error(PARSE_FATAL,
830 			    "The directive .unexport-env does not take "
831 			    "arguments");
832 		}
833 		what = UNEXPORT_ENV;
834 
835 	} else {
836 		what = arg[0] != '\0' ? UNEXPORT_NAMED : UNEXPORT_ALL;
837 		if (what == UNEXPORT_NAMED)
838 			varnames = FStr_InitRefer(arg);
839 	}
840 
841 	if (what != UNEXPORT_NAMED) {
842 		char *expanded;
843 		/* Using .MAKE.EXPORTED */
844 		(void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL,
845 		    VARE_WANTRES, &expanded);
846 		/* TODO: handle errors */
847 		varnames = FStr_InitOwn(expanded);
848 	}
849 
850 	*out_varnames = varnames;
851 	*out_what = what;
852 }
853 
854 static void
855 UnexportVar(const char *varname, UnexportWhat what)
856 {
857 	Var *v = VarFind(varname, VAR_GLOBAL, FALSE);
858 	if (v == NULL) {
859 		DEBUG1(VAR, "Not unexporting \"%s\" (not found)\n", varname);
860 		return;
861 	}
862 
863 	DEBUG1(VAR, "Unexporting \"%s\"\n", varname);
864 	if (what != UNEXPORT_ENV &&
865 	    (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
866 		unsetenv(v->name.str);
867 	v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
868 
869 	if (what == UNEXPORT_NAMED) {
870 		/* Remove the variable names from .MAKE.EXPORTED. */
871 		/* XXX: v->name is injected without escaping it */
872 		char *expr = str_concat3("${" MAKE_EXPORTED ":N",
873 		    v->name.str, "}");
874 		char *cp;
875 		(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
876 		/* TODO: handle errors */
877 		Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
878 		free(cp);
879 		free(expr);
880 	}
881 }
882 
883 static void
884 UnexportVars(FStr *varnames, UnexportWhat what)
885 {
886 	size_t i;
887 	Words words;
888 
889 	if (what == UNEXPORT_ENV)
890 		ClearEnv();
891 
892 	words = Str_Words(varnames->str, FALSE);
893 	for (i = 0; i < words.len; i++) {
894 		const char *varname = words.words[i];
895 		UnexportVar(varname, what);
896 	}
897 	Words_Free(words);
898 
899 	if (what != UNEXPORT_NAMED)
900 		Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
901 }
902 
903 /*
904  * This is called when .unexport[-env] is seen.
905  *
906  * str must have the form "unexport[-env] varname...".
907  */
908 void
909 Var_UnExport(Boolean isEnv, const char *arg)
910 {
911 	UnexportWhat what;
912 	FStr varnames;
913 
914 	GetVarnamesToUnexport(isEnv, arg, &varnames, &what);
915 	UnexportVars(&varnames, what);
916 	FStr_Done(&varnames);
917 }
918 
919 /* Set the variable to the value; the name is not expanded. */
920 static void
921 SetVar(const char *name, const char *val, GNode *ctxt, VarSetFlags flags)
922 {
923 	Var *v;
924 
925 	if (ctxt == VAR_GLOBAL) {
926 		v = VarFind(name, VAR_CMDLINE, FALSE);
927 		if (v != NULL) {
928 			if (v->flags & VAR_FROM_CMD) {
929 				DEBUG3(VAR, "%s:%s = %s ignored!\n",
930 				    ctxt->name, name, val);
931 				return;
932 			}
933 			VarFreeEnv(v, TRUE);
934 		}
935 	}
936 
937 	/*
938 	 * We only look for a variable in the given context since anything set
939 	 * here will override anything in a lower context, so there's not much
940 	 * point in searching them all just to save a bit of memory...
941 	 */
942 	v = VarFind(name, ctxt, FALSE);
943 	if (v == NULL) {
944 		if (ctxt == VAR_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) {
945 			/*
946 			 * This var would normally prevent the same name being
947 			 * added to VAR_GLOBAL, so delete it from there if
948 			 * needed. Otherwise -V name may show the wrong value.
949 			 */
950 			/* XXX: name is expanded for the second time */
951 			Var_Delete(name, VAR_GLOBAL);
952 		}
953 		VarAdd(name, val, ctxt, flags);
954 	} else {
955 		if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
956 			DEBUG3(VAR, "%s:%s = %s ignored (read-only)\n",
957 			    ctxt->name, name, val);
958 			return;
959 		}
960 		Buf_Empty(&v->val);
961 		Buf_AddStr(&v->val, val);
962 
963 		DEBUG3(VAR, "%s:%s = %s\n", ctxt->name, name, val);
964 		if (v->flags & VAR_EXPORTED)
965 			ExportVar(name, VEM_PLAIN);
966 	}
967 	/*
968 	 * Any variables given on the command line are automatically exported
969 	 * to the environment (as per POSIX standard)
970 	 * Other than internals.
971 	 */
972 	if (ctxt == VAR_CMDLINE && !(flags & VAR_SET_NO_EXPORT) &&
973 	    name[0] != '.') {
974 		if (v == NULL)
975 			v = VarFind(name, ctxt, FALSE); /* we just added it */
976 		v->flags |= VAR_FROM_CMD;
977 
978 		/*
979 		 * If requested, don't export these in the environment
980 		 * individually.  We still put them in MAKEOVERRIDES so
981 		 * that the command-line settings continue to override
982 		 * Makefile settings.
983 		 */
984 		if (!opts.varNoExportEnv)
985 			setenv(name, val, 1);
986 
987 		Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
988 	}
989 	if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
990 		save_dollars = ParseBoolean(val, save_dollars);
991 
992 	if (v != NULL)
993 		VarFreeEnv(v, TRUE);
994 }
995 
996 /* See Var_Set for documentation. */
997 void
998 Var_SetWithFlags(const char *name, const char *val, GNode *ctxt,
999 		 VarSetFlags flags)
1000 {
1001 	const char *unexpanded_name = name;
1002 	FStr varname = FStr_InitRefer(name);
1003 
1004 	assert(val != NULL);
1005 
1006 	if (strchr(varname.str, '$') != NULL) {
1007 		char *expanded;
1008 		(void)Var_Subst(varname.str, ctxt, VARE_WANTRES, &expanded);
1009 		/* TODO: handle errors */
1010 		varname = FStr_InitOwn(expanded);
1011 	}
1012 
1013 	if (varname.str[0] == '\0') {
1014 		DEBUG2(VAR, "Var_Set(\"%s\", \"%s\", ...) "
1015 			    "name expands to empty string - ignored\n",
1016 		    unexpanded_name, val);
1017 	} else
1018 		SetVar(varname.str, val, ctxt, flags);
1019 
1020 	FStr_Done(&varname);
1021 }
1022 
1023 /*
1024  * Set the variable name to the value val in the given context.
1025  *
1026  * If the variable doesn't yet exist, it is created.
1027  * Otherwise the new value overwrites and replaces the old value.
1028  *
1029  * Input:
1030  *	name		name of the variable to set, is expanded once
1031  *	val		value to give to the variable
1032  *	ctxt		context in which to set it
1033  */
1034 void
1035 Var_Set(const char *name, const char *val, GNode *ctxt)
1036 {
1037 	Var_SetWithFlags(name, val, ctxt, VAR_SET_NONE);
1038 }
1039 
1040 /*
1041  * The variable of the given name has the given value appended to it in the
1042  * given context.
1043  *
1044  * If the variable doesn't exist, it is created. Otherwise the strings are
1045  * concatenated, with a space in between.
1046  *
1047  * Input:
1048  *	name		name of the variable to modify, is expanded once
1049  *	val		string to append to it
1050  *	ctxt		context in which this should occur
1051  *
1052  * Notes:
1053  *	Only if the variable is being sought in the global context is the
1054  *	environment searched.
1055  *	XXX: Knows its calling circumstances in that if called with ctxt
1056  *	an actual target, it will only search that context since only
1057  *	a local variable could be being appended to. This is actually
1058  *	a big win and must be tolerated.
1059  */
1060 void
1061 Var_Append(const char *name, const char *val, GNode *ctxt)
1062 {
1063 	char *name_freeIt = NULL;
1064 	Var *v;
1065 
1066 	assert(val != NULL);
1067 
1068 	if (strchr(name, '$') != NULL) {
1069 		const char *unexpanded_name = name;
1070 		(void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
1071 		/* TODO: handle errors */
1072 		name = name_freeIt;
1073 		if (name[0] == '\0') {
1074 			DEBUG2(VAR, "Var_Append(\"%s\", \"%s\", ...) "
1075 				    "name expands to empty string - ignored\n",
1076 			    unexpanded_name, val);
1077 			free(name_freeIt);
1078 			return;
1079 		}
1080 	}
1081 
1082 	v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
1083 
1084 	if (v == NULL) {
1085 		/* XXX: name is expanded for the second time */
1086 		Var_Set(name, val, ctxt);
1087 	} else if (v->flags & VAR_READONLY) {
1088 		DEBUG1(VAR, "Ignoring append to %s since it is read-only\n",
1089 		    name);
1090 	} else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
1091 		Buf_AddByte(&v->val, ' ');
1092 		Buf_AddStr(&v->val, val);
1093 
1094 		DEBUG3(VAR, "%s:%s = %s\n",
1095 		    ctxt->name, name, Buf_GetAll(&v->val, NULL));
1096 
1097 		if (v->flags & VAR_FROM_ENV) {
1098 			/*
1099 			 * If the original variable came from the environment,
1100 			 * we have to install it in the global context (we
1101 			 * could place it in the environment, but then we
1102 			 * should provide a way to export other variables...)
1103 			 */
1104 			v->flags &= ~(unsigned)VAR_FROM_ENV;
1105 			/*
1106 			 * This is the only place where a variable is
1107 			 * created whose v->name is not the same as
1108 			 * ctxt->context->key.
1109 			 */
1110 			HashTable_Set(&ctxt->vars, name, v);
1111 		}
1112 	}
1113 	free(name_freeIt);
1114 }
1115 
1116 /*
1117  * See if the given variable exists, in the given context or in other
1118  * fallback contexts.
1119  *
1120  * Input:
1121  *	name		Variable to find, is expanded once
1122  *	ctxt		Context in which to start search
1123  */
1124 Boolean
1125 Var_Exists(const char *name, GNode *ctxt)
1126 {
1127 	FStr varname = FStr_InitRefer(name);
1128 	Var *v;
1129 
1130 	if (strchr(varname.str, '$') != NULL) {
1131 		char *expanded;
1132 		(void)Var_Subst(varname.str, ctxt, VARE_WANTRES, &expanded);
1133 		/* TODO: handle errors */
1134 		varname = FStr_InitOwn(expanded);
1135 	}
1136 
1137 	v = VarFind(varname.str, ctxt, TRUE);
1138 	FStr_Done(&varname);
1139 	if (v == NULL)
1140 		return FALSE;
1141 
1142 	(void)VarFreeEnv(v, TRUE);
1143 	return TRUE;
1144 }
1145 
1146 /*
1147  * Return the unexpanded value of the given variable in the given context,
1148  * or the usual contexts.
1149  *
1150  * Input:
1151  *	name		name to find, is not expanded any further
1152  *	ctxt		context in which to search for it
1153  *
1154  * Results:
1155  *	The value if the variable exists, NULL if it doesn't.
1156  *	If the returned value is not NULL, the caller must free
1157  *	out_freeIt when the returned value is no longer needed.
1158  */
1159 FStr
1160 Var_Value(const char *name, GNode *ctxt)
1161 {
1162 	Var *v = VarFind(name, ctxt, TRUE);
1163 	char *value;
1164 
1165 	if (v == NULL)
1166 		return FStr_InitRefer(NULL);
1167 
1168 	value = Buf_GetAll(&v->val, NULL);
1169 	return VarFreeEnv(v, FALSE)
1170 	    ? FStr_InitOwn(value)
1171 	    : FStr_InitRefer(value);
1172 }
1173 
1174 /*
1175  * Return the unexpanded variable value from this node, without trying to look
1176  * up the variable in any other context.
1177  */
1178 const char *
1179 Var_ValueDirect(const char *name, GNode *ctxt)
1180 {
1181 	Var *v = VarFind(name, ctxt, FALSE);
1182 	return v != NULL ? Buf_GetAll(&v->val, NULL) : NULL;
1183 }
1184 
1185 
1186 static void
1187 SepBuf_Init(SepBuf *buf, char sep)
1188 {
1189 	Buf_InitSize(&buf->buf, 32);
1190 	buf->needSep = FALSE;
1191 	buf->sep = sep;
1192 }
1193 
1194 static void
1195 SepBuf_Sep(SepBuf *buf)
1196 {
1197 	buf->needSep = TRUE;
1198 }
1199 
1200 static void
1201 SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1202 {
1203 	if (mem_size == 0)
1204 		return;
1205 	if (buf->needSep && buf->sep != '\0') {
1206 		Buf_AddByte(&buf->buf, buf->sep);
1207 		buf->needSep = FALSE;
1208 	}
1209 	Buf_AddBytes(&buf->buf, mem, mem_size);
1210 }
1211 
1212 static void
1213 SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1214 {
1215 	SepBuf_AddBytes(buf, start, (size_t)(end - start));
1216 }
1217 
1218 static void
1219 SepBuf_AddStr(SepBuf *buf, const char *str)
1220 {
1221 	SepBuf_AddBytes(buf, str, strlen(str));
1222 }
1223 
1224 static char *
1225 SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1226 {
1227 	return Buf_Destroy(&buf->buf, free_buf);
1228 }
1229 
1230 
1231 /*
1232  * This callback for ModifyWords gets a single word from a variable expression
1233  * and typically adds a modification of this word to the buffer. It may also
1234  * do nothing or add several words.
1235  *
1236  * For example, in ${:Ua b c:M*2}, the callback is called 3 times, once for
1237  * each word of "a b c".
1238  */
1239 typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1240 
1241 
1242 /*
1243  * Callback for ModifyWords to implement the :H modifier.
1244  * Add the dirname of the given word to the buffer.
1245  */
1246 /*ARGSUSED*/
1247 static void
1248 ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1249 {
1250 	const char *slash = strrchr(word, '/');
1251 	if (slash != NULL)
1252 		SepBuf_AddBytesBetween(buf, word, slash);
1253 	else
1254 		SepBuf_AddStr(buf, ".");
1255 }
1256 
1257 /*
1258  * Callback for ModifyWords to implement the :T modifier.
1259  * Add the basename of the given word to the buffer.
1260  */
1261 /*ARGSUSED*/
1262 static void
1263 ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1264 {
1265 	SepBuf_AddStr(buf, str_basename(word));
1266 }
1267 
1268 /*
1269  * Callback for ModifyWords to implement the :E modifier.
1270  * Add the filename suffix of the given word to the buffer, if it exists.
1271  */
1272 /*ARGSUSED*/
1273 static void
1274 ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1275 {
1276 	const char *lastDot = strrchr(word, '.');
1277 	if (lastDot != NULL)
1278 		SepBuf_AddStr(buf, lastDot + 1);
1279 }
1280 
1281 /*
1282  * Callback for ModifyWords to implement the :R modifier.
1283  * Add the basename of the given word to the buffer.
1284  */
1285 /*ARGSUSED*/
1286 static void
1287 ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1288 {
1289 	const char *lastDot = strrchr(word, '.');
1290 	size_t len = lastDot != NULL ? (size_t)(lastDot - word) : strlen(word);
1291 	SepBuf_AddBytes(buf, word, len);
1292 }
1293 
1294 /*
1295  * Callback for ModifyWords to implement the :M modifier.
1296  * Place the word in the buffer if it matches the given pattern.
1297  */
1298 static void
1299 ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1300 {
1301 	const char *pattern = data;
1302 	DEBUG2(VAR, "VarMatch [%s] [%s]\n", word, pattern);
1303 	if (Str_Match(word, pattern))
1304 		SepBuf_AddStr(buf, word);
1305 }
1306 
1307 /*
1308  * Callback for ModifyWords to implement the :N modifier.
1309  * Place the word in the buffer if it doesn't match the given pattern.
1310  */
1311 static void
1312 ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1313 {
1314 	const char *pattern = data;
1315 	if (!Str_Match(word, pattern))
1316 		SepBuf_AddStr(buf, word);
1317 }
1318 
1319 #ifdef SYSVVARSUB
1320 
1321 /*
1322  * Check word against pattern for a match (% is a wildcard).
1323  *
1324  * Input:
1325  *	word		Word to examine
1326  *	pattern		Pattern to examine against
1327  *
1328  * Results:
1329  *	Returns the start of the match, or NULL.
1330  *	out_match_len returns the length of the match, if any.
1331  *	out_hasPercent returns whether the pattern contains a percent.
1332  */
1333 static const char *
1334 SysVMatch(const char *word, const char *pattern,
1335 	  size_t *out_match_len, Boolean *out_hasPercent)
1336 {
1337 	const char *p = pattern;
1338 	const char *w = word;
1339 	const char *percent;
1340 	size_t w_len;
1341 	size_t p_len;
1342 	const char *w_tail;
1343 
1344 	*out_hasPercent = FALSE;
1345 	percent = strchr(p, '%');
1346 	if (percent != NULL) {	/* ${VAR:...%...=...} */
1347 		*out_hasPercent = TRUE;
1348 		if (w[0] == '\0')
1349 			return NULL;	/* empty word does not match pattern */
1350 
1351 		/* check that the prefix matches */
1352 		for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1353 			continue;
1354 		if (p != percent)
1355 			return NULL;	/* No match */
1356 
1357 		p++;		/* Skip the percent */
1358 		if (*p == '\0') {
1359 			/* No more pattern, return the rest of the string */
1360 			*out_match_len = strlen(w);
1361 			return w;
1362 		}
1363 	}
1364 
1365 	/* Test whether the tail matches */
1366 	w_len = strlen(w);
1367 	p_len = strlen(p);
1368 	if (w_len < p_len)
1369 		return NULL;
1370 
1371 	w_tail = w + w_len - p_len;
1372 	if (memcmp(p, w_tail, p_len) != 0)
1373 		return NULL;
1374 
1375 	*out_match_len = (size_t)(w_tail - w);
1376 	return w;
1377 }
1378 
1379 struct ModifyWord_SYSVSubstArgs {
1380 	GNode *ctx;
1381 	const char *lhs;
1382 	const char *rhs;
1383 };
1384 
1385 /* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1386 static void
1387 ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1388 {
1389 	const struct ModifyWord_SYSVSubstArgs *args = data;
1390 	char *rhs_expanded;
1391 	const char *rhs;
1392 	const char *percent;
1393 
1394 	size_t match_len;
1395 	Boolean lhsPercent;
1396 	const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent);
1397 	if (match == NULL) {
1398 		SepBuf_AddStr(buf, word);
1399 		return;
1400 	}
1401 
1402 	/*
1403 	 * Append rhs to the buffer, substituting the first '%' with the
1404 	 * match, but only if the lhs had a '%' as well.
1405 	 */
1406 
1407 	(void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1408 	/* TODO: handle errors */
1409 
1410 	rhs = rhs_expanded;
1411 	percent = strchr(rhs, '%');
1412 
1413 	if (percent != NULL && lhsPercent) {
1414 		/* Copy the prefix of the replacement pattern */
1415 		SepBuf_AddBytesBetween(buf, rhs, percent);
1416 		rhs = percent + 1;
1417 	}
1418 	if (percent != NULL || !lhsPercent)
1419 		SepBuf_AddBytes(buf, match, match_len);
1420 
1421 	/* Append the suffix of the replacement pattern */
1422 	SepBuf_AddStr(buf, rhs);
1423 
1424 	free(rhs_expanded);
1425 }
1426 #endif
1427 
1428 
1429 struct ModifyWord_SubstArgs {
1430 	const char *lhs;
1431 	size_t lhsLen;
1432 	const char *rhs;
1433 	size_t rhsLen;
1434 	VarPatternFlags pflags;
1435 	Boolean matched;
1436 };
1437 
1438 /*
1439  * Callback for ModifyWords to implement the :S,from,to, modifier.
1440  * Perform a string substitution on the given word.
1441  */
1442 static void
1443 ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1444 {
1445 	size_t wordLen = strlen(word);
1446 	struct ModifyWord_SubstArgs *args = data;
1447 	const char *match;
1448 
1449 	if ((args->pflags & VARP_SUB_ONE) && args->matched)
1450 		goto nosub;
1451 
1452 	if (args->pflags & VARP_ANCHOR_START) {
1453 		if (wordLen < args->lhsLen ||
1454 		    memcmp(word, args->lhs, args->lhsLen) != 0)
1455 			goto nosub;
1456 
1457 		if ((args->pflags & VARP_ANCHOR_END) && wordLen != args->lhsLen)
1458 			goto nosub;
1459 
1460 		/* :S,^prefix,replacement, or :S,^whole$,replacement, */
1461 		SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1462 		SepBuf_AddBytes(buf, word + args->lhsLen,
1463 		    wordLen - args->lhsLen);
1464 		args->matched = TRUE;
1465 		return;
1466 	}
1467 
1468 	if (args->pflags & VARP_ANCHOR_END) {
1469 		const char *start;
1470 
1471 		if (wordLen < args->lhsLen)
1472 			goto nosub;
1473 
1474 		start = word + (wordLen - args->lhsLen);
1475 		if (memcmp(start, args->lhs, args->lhsLen) != 0)
1476 			goto nosub;
1477 
1478 		/* :S,suffix$,replacement, */
1479 		SepBuf_AddBytesBetween(buf, word, start);
1480 		SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1481 		args->matched = TRUE;
1482 		return;
1483 	}
1484 
1485 	if (args->lhs[0] == '\0')
1486 		goto nosub;
1487 
1488 	/* unanchored case, may match more than once */
1489 	while ((match = strstr(word, args->lhs)) != NULL) {
1490 		SepBuf_AddBytesBetween(buf, word, match);
1491 		SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1492 		args->matched = TRUE;
1493 		wordLen -= (size_t)(match - word) + args->lhsLen;
1494 		word += (size_t)(match - word) + args->lhsLen;
1495 		if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1496 			break;
1497 	}
1498 nosub:
1499 	SepBuf_AddBytes(buf, word, wordLen);
1500 }
1501 
1502 #ifndef NO_REGEX
1503 /* Print the error caused by a regcomp or regexec call. */
1504 static void
1505 VarREError(int reerr, const regex_t *pat, const char *str)
1506 {
1507 	size_t errlen = regerror(reerr, pat, NULL, 0);
1508 	char *errbuf = bmake_malloc(errlen);
1509 	regerror(reerr, pat, errbuf, errlen);
1510 	Error("%s: %s", str, errbuf);
1511 	free(errbuf);
1512 }
1513 
1514 struct ModifyWord_SubstRegexArgs {
1515 	regex_t re;
1516 	size_t nsub;
1517 	char *replace;
1518 	VarPatternFlags pflags;
1519 	Boolean matched;
1520 };
1521 
1522 /*
1523  * Callback for ModifyWords to implement the :C/from/to/ modifier.
1524  * Perform a regex substitution on the given word.
1525  */
1526 static void
1527 ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1528 {
1529 	struct ModifyWord_SubstRegexArgs *args = data;
1530 	int xrv;
1531 	const char *wp = word;
1532 	char *rp;
1533 	int flags = 0;
1534 	regmatch_t m[10];
1535 
1536 	if ((args->pflags & VARP_SUB_ONE) && args->matched)
1537 		goto nosub;
1538 
1539 tryagain:
1540 	xrv = regexec(&args->re, wp, args->nsub, m, flags);
1541 
1542 	switch (xrv) {
1543 	case 0:
1544 		args->matched = TRUE;
1545 		SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1546 
1547 		for (rp = args->replace; *rp != '\0'; rp++) {
1548 			if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1549 				SepBuf_AddBytes(buf, rp + 1, 1);
1550 				rp++;
1551 				continue;
1552 			}
1553 
1554 			if (*rp == '&') {
1555 				SepBuf_AddBytesBetween(buf,
1556 				    wp + m[0].rm_so, wp + m[0].rm_eo);
1557 				continue;
1558 			}
1559 
1560 			if (*rp != '\\' || !ch_isdigit(rp[1])) {
1561 				SepBuf_AddBytes(buf, rp, 1);
1562 				continue;
1563 			}
1564 
1565 			{	/* \0 to \9 backreference */
1566 				size_t n = (size_t)(rp[1] - '0');
1567 				rp++;
1568 
1569 				if (n >= args->nsub) {
1570 					Error("No subexpression \\%u",
1571 					    (unsigned)n);
1572 				} else if (m[n].rm_so == -1) {
1573 					Error(
1574 					    "No match for subexpression \\%u",
1575 					    (unsigned)n);
1576 				} else {
1577 					SepBuf_AddBytesBetween(buf,
1578 					    wp + m[n].rm_so, wp + m[n].rm_eo);
1579 				}
1580 			}
1581 		}
1582 
1583 		wp += m[0].rm_eo;
1584 		if (args->pflags & VARP_SUB_GLOBAL) {
1585 			flags |= REG_NOTBOL;
1586 			if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1587 				SepBuf_AddBytes(buf, wp, 1);
1588 				wp++;
1589 			}
1590 			if (*wp != '\0')
1591 				goto tryagain;
1592 		}
1593 		if (*wp != '\0')
1594 			SepBuf_AddStr(buf, wp);
1595 		break;
1596 	default:
1597 		VarREError(xrv, &args->re, "Unexpected regex error");
1598 		/* FALLTHROUGH */
1599 	case REG_NOMATCH:
1600 	nosub:
1601 		SepBuf_AddStr(buf, wp);
1602 		break;
1603 	}
1604 }
1605 #endif
1606 
1607 
1608 struct ModifyWord_LoopArgs {
1609 	GNode *ctx;
1610 	char *tvar;		/* name of temporary variable */
1611 	char *str;		/* string to expand */
1612 	VarEvalFlags eflags;
1613 };
1614 
1615 /* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1616 static void
1617 ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1618 {
1619 	const struct ModifyWord_LoopArgs *args;
1620 	char *s;
1621 
1622 	if (word[0] == '\0')
1623 		return;
1624 
1625 	args = data;
1626 	Var_SetWithFlags(args->tvar, word, args->ctx, VAR_SET_NO_EXPORT);
1627 	(void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1628 	/* TODO: handle errors */
1629 
1630 	DEBUG4(VAR, "ModifyWord_Loop: "
1631 		    "in \"%s\", replace \"%s\" with \"%s\" to \"%s\"\n",
1632 	    word, args->tvar, args->str, s);
1633 
1634 	if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1635 		buf->needSep = FALSE;
1636 	SepBuf_AddStr(buf, s);
1637 	free(s);
1638 }
1639 
1640 
1641 /*
1642  * The :[first..last] modifier selects words from the expression.
1643  * It can also reverse the words.
1644  */
1645 static char *
1646 VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1647 	       int last)
1648 {
1649 	Words words;
1650 	int len, start, end, step;
1651 	int i;
1652 
1653 	SepBuf buf;
1654 	SepBuf_Init(&buf, sep);
1655 
1656 	if (oneBigWord) {
1657 		/* fake what Str_Words() would do if there were only one word */
1658 		words.len = 1;
1659 		words.words = bmake_malloc(
1660 		    (words.len + 1) * sizeof(words.words[0]));
1661 		words.freeIt = bmake_strdup(str);
1662 		words.words[0] = words.freeIt;
1663 		words.words[1] = NULL;
1664 	} else {
1665 		words = Str_Words(str, FALSE);
1666 	}
1667 
1668 	/*
1669 	 * Now sanitize the given range.  If first or last are negative,
1670 	 * convert them to the positive equivalents (-1 gets converted to len,
1671 	 * -2 gets converted to (len - 1), etc.).
1672 	 */
1673 	len = (int)words.len;
1674 	if (first < 0)
1675 		first += len + 1;
1676 	if (last < 0)
1677 		last += len + 1;
1678 
1679 	/* We avoid scanning more of the list than we need to. */
1680 	if (first > last) {
1681 		start = (first > len ? len : first) - 1;
1682 		end = last < 1 ? 0 : last - 1;
1683 		step = -1;
1684 	} else {
1685 		start = first < 1 ? 0 : first - 1;
1686 		end = last > len ? len : last;
1687 		step = 1;
1688 	}
1689 
1690 	for (i = start; (step < 0) == (i >= end); i += step) {
1691 		SepBuf_AddStr(&buf, words.words[i]);
1692 		SepBuf_Sep(&buf);
1693 	}
1694 
1695 	Words_Free(words);
1696 
1697 	return SepBuf_Destroy(&buf, FALSE);
1698 }
1699 
1700 
1701 /*
1702  * Callback for ModifyWords to implement the :tA modifier.
1703  * Replace each word with the result of realpath() if successful.
1704  */
1705 /*ARGSUSED*/
1706 static void
1707 ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1708 {
1709 	struct stat st;
1710 	char rbuf[MAXPATHLEN];
1711 
1712 	const char *rp = cached_realpath(word, rbuf);
1713 	if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1714 		word = rp;
1715 
1716 	SepBuf_AddStr(buf, word);
1717 }
1718 
1719 /*
1720  * Modify each of the words of the passed string using the given function.
1721  *
1722  * Input:
1723  *	str		String whose words should be modified
1724  *	modifyWord	Function that modifies a single word
1725  *	modifyWord_args Custom arguments for modifyWord
1726  *
1727  * Results:
1728  *	A string of all the words modified appropriately.
1729  */
1730 static char *
1731 ModifyWords(const char *str,
1732 	    ModifyWordsCallback modifyWord, void *modifyWord_args,
1733 	    Boolean oneBigWord, char sep)
1734 {
1735 	SepBuf result;
1736 	Words words;
1737 	size_t i;
1738 
1739 	if (oneBigWord) {
1740 		SepBuf_Init(&result, sep);
1741 		modifyWord(str, &result, modifyWord_args);
1742 		return SepBuf_Destroy(&result, FALSE);
1743 	}
1744 
1745 	SepBuf_Init(&result, sep);
1746 
1747 	words = Str_Words(str, FALSE);
1748 
1749 	DEBUG2(VAR, "ModifyWords: split \"%s\" into %u words\n",
1750 	    str, (unsigned)words.len);
1751 
1752 	for (i = 0; i < words.len; i++) {
1753 		modifyWord(words.words[i], &result, modifyWord_args);
1754 		if (Buf_Len(&result.buf) > 0)
1755 			SepBuf_Sep(&result);
1756 	}
1757 
1758 	Words_Free(words);
1759 
1760 	return SepBuf_Destroy(&result, FALSE);
1761 }
1762 
1763 
1764 static char *
1765 Words_JoinFree(Words words)
1766 {
1767 	Buffer buf;
1768 	size_t i;
1769 
1770 	Buf_Init(&buf);
1771 
1772 	for (i = 0; i < words.len; i++) {
1773 		if (i != 0) {
1774 			/* XXX: Use st->sep instead of ' ', for consistency. */
1775 			Buf_AddByte(&buf, ' ');
1776 		}
1777 		Buf_AddStr(&buf, words.words[i]);
1778 	}
1779 
1780 	Words_Free(words);
1781 
1782 	return Buf_Destroy(&buf, FALSE);
1783 }
1784 
1785 /* Remove adjacent duplicate words. */
1786 static char *
1787 VarUniq(const char *str)
1788 {
1789 	Words words = Str_Words(str, FALSE);
1790 
1791 	if (words.len > 1) {
1792 		size_t i, j;
1793 		for (j = 0, i = 1; i < words.len; i++)
1794 			if (strcmp(words.words[i], words.words[j]) != 0 &&
1795 			    (++j != i))
1796 				words.words[j] = words.words[i];
1797 		words.len = j + 1;
1798 	}
1799 
1800 	return Words_JoinFree(words);
1801 }
1802 
1803 
1804 /*
1805  * Quote shell meta-characters and space characters in the string.
1806  * If quoteDollar is set, also quote and double any '$' characters.
1807  */
1808 static char *
1809 VarQuote(const char *str, Boolean quoteDollar)
1810 {
1811 	Buffer buf;
1812 	Buf_Init(&buf);
1813 
1814 	for (; *str != '\0'; str++) {
1815 		if (*str == '\n') {
1816 			const char *newline = Shell_GetNewline();
1817 			if (newline == NULL)
1818 				newline = "\\\n";
1819 			Buf_AddStr(&buf, newline);
1820 			continue;
1821 		}
1822 		if (ch_isspace(*str) || is_shell_metachar((unsigned char)*str))
1823 			Buf_AddByte(&buf, '\\');
1824 		Buf_AddByte(&buf, *str);
1825 		if (quoteDollar && *str == '$')
1826 			Buf_AddStr(&buf, "\\$");
1827 	}
1828 
1829 	return Buf_Destroy(&buf, FALSE);
1830 }
1831 
1832 /*
1833  * Compute the 32-bit hash of the given string, using the MurmurHash3
1834  * algorithm. Output is encoded as 8 hex digits, in Little Endian order.
1835  */
1836 static char *
1837 VarHash(const char *str)
1838 {
1839 	static const char hexdigits[16] = "0123456789abcdef";
1840 	const unsigned char *ustr = (const unsigned char *)str;
1841 
1842 	uint32_t h = 0x971e137bU;
1843 	uint32_t c1 = 0x95543787U;
1844 	uint32_t c2 = 0x2ad7eb25U;
1845 	size_t len2 = strlen(str);
1846 
1847 	char *buf;
1848 	size_t i;
1849 
1850 	size_t len;
1851 	for (len = len2; len != 0;) {
1852 		uint32_t k = 0;
1853 		switch (len) {
1854 		default:
1855 			k = ((uint32_t)ustr[3] << 24) |
1856 			    ((uint32_t)ustr[2] << 16) |
1857 			    ((uint32_t)ustr[1] << 8) |
1858 			    (uint32_t)ustr[0];
1859 			len -= 4;
1860 			ustr += 4;
1861 			break;
1862 		case 3:
1863 			k |= (uint32_t)ustr[2] << 16;
1864 			/* FALLTHROUGH */
1865 		case 2:
1866 			k |= (uint32_t)ustr[1] << 8;
1867 			/* FALLTHROUGH */
1868 		case 1:
1869 			k |= (uint32_t)ustr[0];
1870 			len = 0;
1871 		}
1872 		c1 = c1 * 5 + 0x7b7d159cU;
1873 		c2 = c2 * 5 + 0x6bce6396U;
1874 		k *= c1;
1875 		k = (k << 11) ^ (k >> 21);
1876 		k *= c2;
1877 		h = (h << 13) ^ (h >> 19);
1878 		h = h * 5 + 0x52dce729U;
1879 		h ^= k;
1880 	}
1881 	h ^= (uint32_t)len2;
1882 	h *= 0x85ebca6b;
1883 	h ^= h >> 13;
1884 	h *= 0xc2b2ae35;
1885 	h ^= h >> 16;
1886 
1887 	buf = bmake_malloc(9);
1888 	for (i = 0; i < 8; i++) {
1889 		buf[i] = hexdigits[h & 0x0f];
1890 		h >>= 4;
1891 	}
1892 	buf[8] = '\0';
1893 	return buf;
1894 }
1895 
1896 static char *
1897 VarStrftime(const char *fmt, Boolean zulu, time_t tim)
1898 {
1899 	char buf[BUFSIZ];
1900 
1901 	if (tim == 0)
1902 		time(&tim);
1903 	if (*fmt == '\0')
1904 		fmt = "%c";
1905 	strftime(buf, sizeof buf, fmt, zulu ? gmtime(&tim) : localtime(&tim));
1906 
1907 	buf[sizeof buf - 1] = '\0';
1908 	return bmake_strdup(buf);
1909 }
1910 
1911 /*
1912  * The ApplyModifier functions take an expression that is being evaluated.
1913  * Their task is to apply a single modifier to the expression.
1914  * To do this, they parse the modifier and its parameters from pp and apply
1915  * the parsed modifier to the current value of the expression, generating a
1916  * new value from it.
1917  *
1918  * The modifier typically lasts until the next ':', or a closing '}' or ')'
1919  * (taken from st->endc), or the end of the string (parse error).
1920  *
1921  * The high-level behavior of these functions is:
1922  *
1923  * 1. parse the modifier
1924  * 2. evaluate the modifier
1925  * 3. housekeeping
1926  *
1927  * Parsing the modifier
1928  *
1929  * If parsing succeeds, the parsing position *pp is updated to point to the
1930  * first character following the modifier, which typically is either ':' or
1931  * st->endc.  The modifier doesn't have to check for this delimiter character,
1932  * this is done by ApplyModifiers.
1933  *
1934  * XXX: As of 2020-11-15, some modifiers such as :S, :C, :P, :L do not
1935  * need to be followed by a ':' or endc; this was an unintended mistake.
1936  *
1937  * If parsing fails because of a missing delimiter (as in the :S, :C or :@
1938  * modifiers), return AMR_CLEANUP.
1939  *
1940  * If parsing fails because the modifier is unknown, return AMR_UNKNOWN to
1941  * try the SysV modifier ${VAR:from=to} as fallback.  This should only be
1942  * done as long as there have been no side effects from evaluating nested
1943  * variables, to avoid evaluating them more than once.  In this case, the
1944  * parsing position may or may not be updated.  (XXX: Why not? The original
1945  * parsing position is well-known in ApplyModifiers.)
1946  *
1947  * If parsing fails and the SysV modifier ${VAR:from=to} should not be used
1948  * as a fallback, either issue an error message using Error or Parse_Error
1949  * and then return AMR_CLEANUP, or return AMR_BAD for the default error
1950  * message.  Both of these return values will stop processing the variable
1951  * expression.  (XXX: As of 2020-08-23, evaluation of the whole string
1952  * continues nevertheless after skipping a few bytes, which essentially is
1953  * undefined behavior.  Not in the sense of C, but still it's impossible to
1954  * predict what happens in the parser.)
1955  *
1956  * Evaluating the modifier
1957  *
1958  * After parsing, the modifier is evaluated.  The side effects from evaluating
1959  * nested variable expressions in the modifier text often already happen
1960  * during parsing though.
1961  *
1962  * Evaluating the modifier usually takes the current value of the variable
1963  * expression from st->val, or the variable name from st->var->name and stores
1964  * the result in st->newVal.
1965  *
1966  * If evaluating fails (as of 2020-08-23), an error message is printed using
1967  * Error.  This function has no side-effects, it really just prints the error
1968  * message.  Processing the expression continues as if everything were ok.
1969  * XXX: This should be fixed by adding proper error handling to Var_Subst,
1970  * Var_Parse, ApplyModifiers and ModifyWords.
1971  *
1972  * Housekeeping
1973  *
1974  * Some modifiers such as :D and :U turn undefined expressions into defined
1975  * expressions (see VEF_UNDEF, VEF_DEF).
1976  *
1977  * Some modifiers need to free some memory.
1978  */
1979 
1980 typedef enum VarExprFlags {
1981 	VEF_NONE	= 0,
1982 	/* The variable expression is based on an undefined variable. */
1983 	VEF_UNDEF = 0x01,
1984 	/*
1985 	 * The variable expression started as an undefined expression, but one
1986 	 * of the modifiers (such as :D or :U) has turned the expression from
1987 	 * undefined to defined.
1988 	 */
1989 	VEF_DEF = 0x02
1990 } VarExprFlags;
1991 
1992 ENUM_FLAGS_RTTI_2(VarExprFlags,
1993 		  VEF_UNDEF, VEF_DEF);
1994 
1995 
1996 typedef struct ApplyModifiersState {
1997 	/* '\0' or '{' or '(' */
1998 	const char startc;
1999 	/* '\0' or '}' or ')' */
2000 	const char endc;
2001 	Var *const var;
2002 	GNode *const ctxt;
2003 	const VarEvalFlags eflags;
2004 	/*
2005 	 * The new value of the expression, after applying the modifier,
2006 	 * never NULL.
2007 	 */
2008 	FStr newVal;
2009 	/* Word separator in expansions (see the :ts modifier). */
2010 	char sep;
2011 	/*
2012 	 * TRUE if some modifiers that otherwise split the variable value
2013 	 * into words, like :S and :C, treat the variable value as a single
2014 	 * big word, possibly containing spaces.
2015 	 */
2016 	Boolean oneBigWord;
2017 	VarExprFlags exprFlags;
2018 } ApplyModifiersState;
2019 
2020 static void
2021 ApplyModifiersState_Define(ApplyModifiersState *st)
2022 {
2023 	if (st->exprFlags & VEF_UNDEF)
2024 		st->exprFlags |= VEF_DEF;
2025 }
2026 
2027 typedef enum ApplyModifierResult {
2028 	/* Continue parsing */
2029 	AMR_OK,
2030 	/* Not a match, try other modifiers as well */
2031 	AMR_UNKNOWN,
2032 	/* Error out with "Bad modifier" message */
2033 	AMR_BAD,
2034 	/* Error out without error message */
2035 	AMR_CLEANUP
2036 } ApplyModifierResult;
2037 
2038 /*
2039  * Allow backslashes to escape the delimiter, $, and \, but don't touch other
2040  * backslashes.
2041  */
2042 static Boolean
2043 IsEscapedModifierPart(const char *p, char delim,
2044 		      struct ModifyWord_SubstArgs *subst)
2045 {
2046 	if (p[0] != '\\')
2047 		return FALSE;
2048 	if (p[1] == delim || p[1] == '\\' || p[1] == '$')
2049 		return TRUE;
2050 	return p[1] == '&' && subst != NULL;
2051 }
2052 
2053 /* See ParseModifierPart */
2054 static VarParseResult
2055 ParseModifierPartSubst(
2056     const char **pp,
2057     char delim,
2058     VarEvalFlags eflags,
2059     ApplyModifiersState *st,
2060     char **out_part,
2061     /* Optionally stores the length of the returned string, just to save
2062      * another strlen call. */
2063     size_t *out_length,
2064     /* For the first part of the :S modifier, sets the VARP_ANCHOR_END flag
2065      * if the last character of the pattern is a $. */
2066     VarPatternFlags *out_pflags,
2067     /* For the second part of the :S modifier, allow ampersands to be
2068      * escaped and replace unescaped ampersands with subst->lhs. */
2069     struct ModifyWord_SubstArgs *subst
2070 )
2071 {
2072 	Buffer buf;
2073 	const char *p;
2074 
2075 	Buf_Init(&buf);
2076 
2077 	/*
2078 	 * Skim through until the matching delimiter is found; pick up
2079 	 * variable expressions on the way.
2080 	 */
2081 	p = *pp;
2082 	while (*p != '\0' && *p != delim) {
2083 		const char *varstart;
2084 
2085 		if (IsEscapedModifierPart(p, delim, subst)) {
2086 			Buf_AddByte(&buf, p[1]);
2087 			p += 2;
2088 			continue;
2089 		}
2090 
2091 		if (*p != '$') {	/* Unescaped, simple text */
2092 			if (subst != NULL && *p == '&')
2093 				Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
2094 			else
2095 				Buf_AddByte(&buf, *p);
2096 			p++;
2097 			continue;
2098 		}
2099 
2100 		if (p[1] == delim) {	/* Unescaped $ at end of pattern */
2101 			if (out_pflags != NULL)
2102 				*out_pflags |= VARP_ANCHOR_END;
2103 			else
2104 				Buf_AddByte(&buf, *p);
2105 			p++;
2106 			continue;
2107 		}
2108 
2109 		if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
2110 			const char *nested_p = p;
2111 			FStr nested_val;
2112 			VarEvalFlags nested_eflags =
2113 			    eflags & ~(unsigned)VARE_KEEP_DOLLAR;
2114 
2115 			(void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
2116 			    &nested_val);
2117 			/* TODO: handle errors */
2118 			Buf_AddStr(&buf, nested_val.str);
2119 			FStr_Done(&nested_val);
2120 			p += nested_p - p;
2121 			continue;
2122 		}
2123 
2124 		/*
2125 		 * XXX: This whole block is very similar to Var_Parse without
2126 		 * VARE_WANTRES.  There may be subtle edge cases though that
2127 		 * are not yet covered in the unit tests and that are parsed
2128 		 * differently, depending on whether they are evaluated or
2129 		 * not.
2130 		 *
2131 		 * This subtle difference is not documented in the manual
2132 		 * page, neither is the difference between parsing :D and
2133 		 * :M documented. No code should ever depend on these
2134 		 * details, but who knows.
2135 		 */
2136 
2137 		varstart = p;	/* Nested variable, only parsed */
2138 		if (p[1] == '(' || p[1] == '{') {
2139 			/*
2140 			 * Find the end of this variable reference
2141 			 * and suck it in without further ado.
2142 			 * It will be interpreted later.
2143 			 */
2144 			char startc = p[1];
2145 			int endc = startc == '(' ? ')' : '}';
2146 			int depth = 1;
2147 
2148 			for (p += 2; *p != '\0' && depth > 0; p++) {
2149 				if (p[-1] != '\\') {
2150 					if (*p == startc)
2151 						depth++;
2152 					if (*p == endc)
2153 						depth--;
2154 				}
2155 			}
2156 			Buf_AddBytesBetween(&buf, varstart, p);
2157 		} else {
2158 			Buf_AddByte(&buf, *varstart);
2159 			p++;
2160 		}
2161 	}
2162 
2163 	if (*p != delim) {
2164 		*pp = p;
2165 		Error("Unfinished modifier for %s ('%c' missing)",
2166 		    st->var->name.str, delim);
2167 		*out_part = NULL;
2168 		return VPR_ERR;
2169 	}
2170 
2171 	*pp = ++p;
2172 	if (out_length != NULL)
2173 		*out_length = Buf_Len(&buf);
2174 
2175 	*out_part = Buf_Destroy(&buf, FALSE);
2176 	DEBUG1(VAR, "Modifier part: \"%s\"\n", *out_part);
2177 	return VPR_OK;
2178 }
2179 
2180 /*
2181  * Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
2182  * the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
2183  * including the next unescaped delimiter.  The delimiter, as well as the
2184  * backslash or the dollar, can be escaped with a backslash.
2185  *
2186  * Return the parsed (and possibly expanded) string, or NULL if no delimiter
2187  * was found.  On successful return, the parsing position pp points right
2188  * after the delimiter.  The delimiter is not included in the returned
2189  * value though.
2190  */
2191 static VarParseResult
2192 ParseModifierPart(
2193     /* The parsing position, updated upon return */
2194     const char **pp,
2195     /* Parsing stops at this delimiter */
2196     char delim,
2197     /* Flags for evaluating nested variables; if VARE_WANTRES is not set,
2198      * the text is only parsed. */
2199     VarEvalFlags eflags,
2200     ApplyModifiersState *st,
2201     char **out_part
2202 )
2203 {
2204 	return ParseModifierPartSubst(pp, delim, eflags, st, out_part,
2205 	    NULL, NULL, NULL);
2206 }
2207 
2208 /* Test whether mod starts with modname, followed by a delimiter. */
2209 MAKE_INLINE Boolean
2210 ModMatch(const char *mod, const char *modname, char endc)
2211 {
2212 	size_t n = strlen(modname);
2213 	return strncmp(mod, modname, n) == 0 &&
2214 	       (mod[n] == endc || mod[n] == ':');
2215 }
2216 
2217 /* Test whether mod starts with modname, followed by a delimiter or '='. */
2218 MAKE_INLINE Boolean
2219 ModMatchEq(const char *mod, const char *modname, char endc)
2220 {
2221 	size_t n = strlen(modname);
2222 	return strncmp(mod, modname, n) == 0 &&
2223 	       (mod[n] == endc || mod[n] == ':' || mod[n] == '=');
2224 }
2225 
2226 static Boolean
2227 TryParseIntBase0(const char **pp, int *out_num)
2228 {
2229 	char *end;
2230 	long n;
2231 
2232 	errno = 0;
2233 	n = strtol(*pp, &end, 0);
2234 	if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE)
2235 		return FALSE;
2236 	if (n < INT_MIN || n > INT_MAX)
2237 		return FALSE;
2238 
2239 	*pp = end;
2240 	*out_num = (int)n;
2241 	return TRUE;
2242 }
2243 
2244 static Boolean
2245 TryParseSize(const char **pp, size_t *out_num)
2246 {
2247 	char *end;
2248 	unsigned long n;
2249 
2250 	if (!ch_isdigit(**pp))
2251 		return FALSE;
2252 
2253 	errno = 0;
2254 	n = strtoul(*pp, &end, 10);
2255 	if (n == ULONG_MAX && errno == ERANGE)
2256 		return FALSE;
2257 	if (n > SIZE_MAX)
2258 		return FALSE;
2259 
2260 	*pp = end;
2261 	*out_num = (size_t)n;
2262 	return TRUE;
2263 }
2264 
2265 static Boolean
2266 TryParseChar(const char **pp, int base, char *out_ch)
2267 {
2268 	char *end;
2269 	unsigned long n;
2270 
2271 	if (!ch_isalnum(**pp))
2272 		return FALSE;
2273 
2274 	errno = 0;
2275 	n = strtoul(*pp, &end, base);
2276 	if (n == ULONG_MAX && errno == ERANGE)
2277 		return FALSE;
2278 	if (n > UCHAR_MAX)
2279 		return FALSE;
2280 
2281 	*pp = end;
2282 	*out_ch = (char)n;
2283 	return TRUE;
2284 }
2285 
2286 /* :@var@...${var}...@ */
2287 static ApplyModifierResult
2288 ApplyModifier_Loop(const char **pp, const char *val, ApplyModifiersState *st)
2289 {
2290 	struct ModifyWord_LoopArgs args;
2291 	char prev_sep;
2292 	VarParseResult res;
2293 
2294 	args.ctx = st->ctxt;
2295 
2296 	(*pp)++;		/* Skip the first '@' */
2297 	res = ParseModifierPart(pp, '@', VARE_NONE, st, &args.tvar);
2298 	if (res != VPR_OK)
2299 		return AMR_CLEANUP;
2300 	if (opts.strict && strchr(args.tvar, '$') != NULL) {
2301 		Parse_Error(PARSE_FATAL,
2302 		    "In the :@ modifier of \"%s\", the variable name \"%s\" "
2303 		    "must not contain a dollar.",
2304 		    st->var->name.str, args.tvar);
2305 		return AMR_CLEANUP;
2306 	}
2307 
2308 	res = ParseModifierPart(pp, '@', VARE_NONE, st, &args.str);
2309 	if (res != VPR_OK)
2310 		return AMR_CLEANUP;
2311 
2312 	args.eflags = st->eflags & ~(unsigned)VARE_KEEP_DOLLAR;
2313 	prev_sep = st->sep;
2314 	st->sep = ' ';		/* XXX: should be st->sep for consistency */
2315 	st->newVal = FStr_InitOwn(
2316 	    ModifyWords(val, ModifyWord_Loop, &args, st->oneBigWord, st->sep));
2317 	st->sep = prev_sep;
2318 	/* XXX: Consider restoring the previous variable instead of deleting. */
2319 	Var_Delete(args.tvar, st->ctxt);
2320 	free(args.tvar);
2321 	free(args.str);
2322 	return AMR_OK;
2323 }
2324 
2325 /* :Ddefined or :Uundefined */
2326 static ApplyModifierResult
2327 ApplyModifier_Defined(const char **pp, const char *val, ApplyModifiersState *st)
2328 {
2329 	Buffer buf;
2330 	const char *p;
2331 
2332 	VarEvalFlags eflags = VARE_NONE;
2333 	if (st->eflags & VARE_WANTRES)
2334 		if ((**pp == 'D') == !(st->exprFlags & VEF_UNDEF))
2335 			eflags = st->eflags;
2336 
2337 	Buf_Init(&buf);
2338 	p = *pp + 1;
2339 	while (*p != st->endc && *p != ':' && *p != '\0') {
2340 
2341 		/* XXX: This code is similar to the one in Var_Parse.
2342 		 * See if the code can be merged.
2343 		 * See also ApplyModifier_Match. */
2344 
2345 		/* Escaped delimiter or other special character */
2346 		if (*p == '\\') {
2347 			char c = p[1];
2348 			if (c == st->endc || c == ':' || c == '$' ||
2349 			    c == '\\') {
2350 				Buf_AddByte(&buf, c);
2351 				p += 2;
2352 				continue;
2353 			}
2354 		}
2355 
2356 		/* Nested variable expression */
2357 		if (*p == '$') {
2358 			FStr nested_val;
2359 
2360 			(void)Var_Parse(&p, st->ctxt, eflags, &nested_val);
2361 			/* TODO: handle errors */
2362 			Buf_AddStr(&buf, nested_val.str);
2363 			FStr_Done(&nested_val);
2364 			continue;
2365 		}
2366 
2367 		/* Ordinary text */
2368 		Buf_AddByte(&buf, *p);
2369 		p++;
2370 	}
2371 	*pp = p;
2372 
2373 	ApplyModifiersState_Define(st);
2374 
2375 	if (eflags & VARE_WANTRES) {
2376 		st->newVal = FStr_InitOwn(Buf_Destroy(&buf, FALSE));
2377 	} else {
2378 		st->newVal = FStr_InitRefer(val);
2379 		Buf_Destroy(&buf, TRUE);
2380 	}
2381 	return AMR_OK;
2382 }
2383 
2384 /* :L */
2385 static ApplyModifierResult
2386 ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
2387 {
2388 	ApplyModifiersState_Define(st);
2389 	st->newVal = FStr_InitOwn(bmake_strdup(st->var->name.str));
2390 	(*pp)++;
2391 	return AMR_OK;
2392 }
2393 
2394 static Boolean
2395 TryParseTime(const char **pp, time_t *out_time)
2396 {
2397 	char *end;
2398 	unsigned long n;
2399 
2400 	if (!ch_isdigit(**pp))
2401 		return FALSE;
2402 
2403 	errno = 0;
2404 	n = strtoul(*pp, &end, 10);
2405 	if (n == ULONG_MAX && errno == ERANGE)
2406 		return FALSE;
2407 
2408 	*pp = end;
2409 	*out_time = (time_t)n;	/* ignore possible truncation for now */
2410 	return TRUE;
2411 }
2412 
2413 /* :gmtime */
2414 static ApplyModifierResult
2415 ApplyModifier_Gmtime(const char **pp, const char *val, ApplyModifiersState *st)
2416 {
2417 	time_t utc;
2418 
2419 	const char *mod = *pp;
2420 	if (!ModMatchEq(mod, "gmtime", st->endc))
2421 		return AMR_UNKNOWN;
2422 
2423 	if (mod[6] == '=') {
2424 		const char *arg = mod + 7;
2425 		if (!TryParseTime(&arg, &utc)) {
2426 			Parse_Error(PARSE_FATAL,
2427 			    "Invalid time value: %s", mod + 7);
2428 			return AMR_CLEANUP;
2429 		}
2430 		*pp = arg;
2431 	} else {
2432 		utc = 0;
2433 		*pp = mod + 6;
2434 	}
2435 	st->newVal = FStr_InitOwn(VarStrftime(val, TRUE, utc));
2436 	return AMR_OK;
2437 }
2438 
2439 /* :localtime */
2440 static ApplyModifierResult
2441 ApplyModifier_Localtime(const char **pp, const char *val,
2442 			ApplyModifiersState *st)
2443 {
2444 	time_t utc;
2445 
2446 	const char *mod = *pp;
2447 	if (!ModMatchEq(mod, "localtime", st->endc))
2448 		return AMR_UNKNOWN;
2449 
2450 	if (mod[9] == '=') {
2451 		const char *arg = mod + 10;
2452 		if (!TryParseTime(&arg, &utc)) {
2453 			Parse_Error(PARSE_FATAL,
2454 			    "Invalid time value: %s", mod + 10);
2455 			return AMR_CLEANUP;
2456 		}
2457 		*pp = arg;
2458 	} else {
2459 		utc = 0;
2460 		*pp = mod + 9;
2461 	}
2462 	st->newVal = FStr_InitOwn(VarStrftime(val, FALSE, utc));
2463 	return AMR_OK;
2464 }
2465 
2466 /* :hash */
2467 static ApplyModifierResult
2468 ApplyModifier_Hash(const char **pp, const char *val, ApplyModifiersState *st)
2469 {
2470 	if (!ModMatch(*pp, "hash", st->endc))
2471 		return AMR_UNKNOWN;
2472 
2473 	st->newVal = FStr_InitOwn(VarHash(val));
2474 	*pp += 4;
2475 	return AMR_OK;
2476 }
2477 
2478 /* :P */
2479 static ApplyModifierResult
2480 ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
2481 {
2482 	GNode *gn;
2483 	char *path;
2484 
2485 	ApplyModifiersState_Define(st);
2486 
2487 	gn = Targ_FindNode(st->var->name.str);
2488 	if (gn == NULL || gn->type & OP_NOPATH) {
2489 		path = NULL;
2490 	} else if (gn->path != NULL) {
2491 		path = bmake_strdup(gn->path);
2492 	} else {
2493 		SearchPath *searchPath = Suff_FindPath(gn);
2494 		path = Dir_FindFile(st->var->name.str, searchPath);
2495 	}
2496 	if (path == NULL)
2497 		path = bmake_strdup(st->var->name.str);
2498 	st->newVal = FStr_InitOwn(path);
2499 
2500 	(*pp)++;
2501 	return AMR_OK;
2502 }
2503 
2504 /* :!cmd! */
2505 static ApplyModifierResult
2506 ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
2507 {
2508 	char *cmd;
2509 	const char *errfmt;
2510 	VarParseResult res;
2511 
2512 	(*pp)++;
2513 	res = ParseModifierPart(pp, '!', st->eflags, st, &cmd);
2514 	if (res != VPR_OK)
2515 		return AMR_CLEANUP;
2516 
2517 	errfmt = NULL;
2518 	if (st->eflags & VARE_WANTRES)
2519 		st->newVal = FStr_InitOwn(Cmd_Exec(cmd, &errfmt));
2520 	else
2521 		st->newVal = FStr_InitRefer("");
2522 	if (errfmt != NULL)
2523 		Error(errfmt, cmd);	/* XXX: why still return AMR_OK? */
2524 	free(cmd);
2525 
2526 	ApplyModifiersState_Define(st);
2527 	return AMR_OK;
2528 }
2529 
2530 /*
2531  * The :range modifier generates an integer sequence as long as the words.
2532  * The :range=7 modifier generates an integer sequence from 1 to 7.
2533  */
2534 static ApplyModifierResult
2535 ApplyModifier_Range(const char **pp, const char *val, ApplyModifiersState *st)
2536 {
2537 	size_t n;
2538 	Buffer buf;
2539 	size_t i;
2540 
2541 	const char *mod = *pp;
2542 	if (!ModMatchEq(mod, "range", st->endc))
2543 		return AMR_UNKNOWN;
2544 
2545 	if (mod[5] == '=') {
2546 		const char *p = mod + 6;
2547 		if (!TryParseSize(&p, &n)) {
2548 			Parse_Error(PARSE_FATAL,
2549 			    "Invalid number: %s", mod + 6);
2550 			return AMR_CLEANUP;
2551 		}
2552 		*pp = p;
2553 	} else {
2554 		n = 0;
2555 		*pp = mod + 5;
2556 	}
2557 
2558 	if (n == 0) {
2559 		Words words = Str_Words(val, FALSE);
2560 		n = words.len;
2561 		Words_Free(words);
2562 	}
2563 
2564 	Buf_Init(&buf);
2565 
2566 	for (i = 0; i < n; i++) {
2567 		if (i != 0) {
2568 			/* XXX: Use st->sep instead of ' ', for consistency. */
2569 			Buf_AddByte(&buf, ' ');
2570 		}
2571 		Buf_AddInt(&buf, 1 + (int)i);
2572 	}
2573 
2574 	st->newVal = FStr_InitOwn(Buf_Destroy(&buf, FALSE));
2575 	return AMR_OK;
2576 }
2577 
2578 /* :Mpattern or :Npattern */
2579 static ApplyModifierResult
2580 ApplyModifier_Match(const char **pp, const char *val, ApplyModifiersState *st)
2581 {
2582 	const char *mod = *pp;
2583 	Boolean copy = FALSE;	/* pattern should be, or has been, copied */
2584 	Boolean needSubst = FALSE;
2585 	const char *endpat;
2586 	char *pattern;
2587 	ModifyWordsCallback callback;
2588 
2589 	/*
2590 	 * In the loop below, ignore ':' unless we are at (or back to) the
2591 	 * original brace level.
2592 	 * XXX: This will likely not work right if $() and ${} are intermixed.
2593 	 */
2594 	/* XXX: This code is similar to the one in Var_Parse.
2595 	 * See if the code can be merged.
2596 	 * See also ApplyModifier_Defined. */
2597 	int nest = 0;
2598 	const char *p;
2599 	for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
2600 		if (*p == '\\' &&
2601 		    (p[1] == ':' || p[1] == st->endc || p[1] == st->startc)) {
2602 			if (!needSubst)
2603 				copy = TRUE;
2604 			p++;
2605 			continue;
2606 		}
2607 		if (*p == '$')
2608 			needSubst = TRUE;
2609 		if (*p == '(' || *p == '{')
2610 			nest++;
2611 		if (*p == ')' || *p == '}') {
2612 			nest--;
2613 			if (nest < 0)
2614 				break;
2615 		}
2616 	}
2617 	*pp = p;
2618 	endpat = p;
2619 
2620 	if (copy) {
2621 		char *dst;
2622 		const char *src;
2623 
2624 		/* Compress the \:'s out of the pattern. */
2625 		pattern = bmake_malloc((size_t)(endpat - (mod + 1)) + 1);
2626 		dst = pattern;
2627 		src = mod + 1;
2628 		for (; src < endpat; src++, dst++) {
2629 			if (src[0] == '\\' && src + 1 < endpat &&
2630 			    /* XXX: st->startc is missing here; see above */
2631 			    (src[1] == ':' || src[1] == st->endc))
2632 				src++;
2633 			*dst = *src;
2634 		}
2635 		*dst = '\0';
2636 	} else {
2637 		pattern = bmake_strsedup(mod + 1, endpat);
2638 	}
2639 
2640 	if (needSubst) {
2641 		char *old_pattern = pattern;
2642 		(void)Var_Subst(pattern, st->ctxt, st->eflags, &pattern);
2643 		/* TODO: handle errors */
2644 		free(old_pattern);
2645 	}
2646 
2647 	DEBUG3(VAR, "Pattern[%s] for [%s] is [%s]\n",
2648 	    st->var->name.str, val, pattern);
2649 
2650 	callback = mod[0] == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
2651 	st->newVal = FStr_InitOwn(ModifyWords(val, callback, pattern,
2652 	    st->oneBigWord, st->sep));
2653 	free(pattern);
2654 	return AMR_OK;
2655 }
2656 
2657 /* :S,from,to, */
2658 static ApplyModifierResult
2659 ApplyModifier_Subst(const char **pp, const char *val, ApplyModifiersState *st)
2660 {
2661 	struct ModifyWord_SubstArgs args;
2662 	char *lhs, *rhs;
2663 	Boolean oneBigWord;
2664 	VarParseResult res;
2665 
2666 	char delim = (*pp)[1];
2667 	if (delim == '\0') {
2668 		Error("Missing delimiter for :S modifier");
2669 		(*pp)++;
2670 		return AMR_CLEANUP;
2671 	}
2672 
2673 	*pp += 2;
2674 
2675 	args.pflags = VARP_NONE;
2676 	args.matched = FALSE;
2677 
2678 	/*
2679 	 * If pattern begins with '^', it is anchored to the
2680 	 * start of the word -- skip over it and flag pattern.
2681 	 */
2682 	if (**pp == '^') {
2683 		args.pflags |= VARP_ANCHOR_START;
2684 		(*pp)++;
2685 	}
2686 
2687 	res = ParseModifierPartSubst(pp, delim, st->eflags, st, &lhs,
2688 	    &args.lhsLen, &args.pflags, NULL);
2689 	if (res != VPR_OK)
2690 		return AMR_CLEANUP;
2691 	args.lhs = lhs;
2692 
2693 	res = ParseModifierPartSubst(pp, delim, st->eflags, st, &rhs,
2694 	    &args.rhsLen, NULL, &args);
2695 	if (res != VPR_OK)
2696 		return AMR_CLEANUP;
2697 	args.rhs = rhs;
2698 
2699 	oneBigWord = st->oneBigWord;
2700 	for (;; (*pp)++) {
2701 		switch (**pp) {
2702 		case 'g':
2703 			args.pflags |= VARP_SUB_GLOBAL;
2704 			continue;
2705 		case '1':
2706 			args.pflags |= VARP_SUB_ONE;
2707 			continue;
2708 		case 'W':
2709 			oneBigWord = TRUE;
2710 			continue;
2711 		}
2712 		break;
2713 	}
2714 
2715 	st->newVal = FStr_InitOwn(ModifyWords(val, ModifyWord_Subst, &args,
2716 	    oneBigWord, st->sep));
2717 
2718 	free(lhs);
2719 	free(rhs);
2720 	return AMR_OK;
2721 }
2722 
2723 #ifndef NO_REGEX
2724 
2725 /* :C,from,to, */
2726 static ApplyModifierResult
2727 ApplyModifier_Regex(const char **pp, const char *val, ApplyModifiersState *st)
2728 {
2729 	char *re;
2730 	struct ModifyWord_SubstRegexArgs args;
2731 	Boolean oneBigWord;
2732 	int error;
2733 	VarParseResult res;
2734 
2735 	char delim = (*pp)[1];
2736 	if (delim == '\0') {
2737 		Error("Missing delimiter for :C modifier");
2738 		(*pp)++;
2739 		return AMR_CLEANUP;
2740 	}
2741 
2742 	*pp += 2;
2743 
2744 	res = ParseModifierPart(pp, delim, st->eflags, st, &re);
2745 	if (res != VPR_OK)
2746 		return AMR_CLEANUP;
2747 
2748 	res = ParseModifierPart(pp, delim, st->eflags, st, &args.replace);
2749 	if (args.replace == NULL) {
2750 		free(re);
2751 		return AMR_CLEANUP;
2752 	}
2753 
2754 	args.pflags = VARP_NONE;
2755 	args.matched = FALSE;
2756 	oneBigWord = st->oneBigWord;
2757 	for (;; (*pp)++) {
2758 		switch (**pp) {
2759 		case 'g':
2760 			args.pflags |= VARP_SUB_GLOBAL;
2761 			continue;
2762 		case '1':
2763 			args.pflags |= VARP_SUB_ONE;
2764 			continue;
2765 		case 'W':
2766 			oneBigWord = TRUE;
2767 			continue;
2768 		}
2769 		break;
2770 	}
2771 
2772 	error = regcomp(&args.re, re, REG_EXTENDED);
2773 	free(re);
2774 	if (error != 0) {
2775 		VarREError(error, &args.re, "Regex compilation error");
2776 		free(args.replace);
2777 		return AMR_CLEANUP;
2778 	}
2779 
2780 	args.nsub = args.re.re_nsub + 1;
2781 	if (args.nsub > 10)
2782 		args.nsub = 10;
2783 	st->newVal = FStr_InitOwn(
2784 	    ModifyWords(val, ModifyWord_SubstRegex, &args,
2785 		oneBigWord, st->sep));
2786 	regfree(&args.re);
2787 	free(args.replace);
2788 	return AMR_OK;
2789 }
2790 
2791 #endif
2792 
2793 /* :Q, :q */
2794 static ApplyModifierResult
2795 ApplyModifier_Quote(const char **pp, const char *val, ApplyModifiersState *st)
2796 {
2797 	if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
2798 		st->newVal = FStr_InitOwn(VarQuote(val, **pp == 'q'));
2799 		(*pp)++;
2800 		return AMR_OK;
2801 	} else
2802 		return AMR_UNKNOWN;
2803 }
2804 
2805 /*ARGSUSED*/
2806 static void
2807 ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
2808 {
2809 	SepBuf_AddStr(buf, word);
2810 }
2811 
2812 /* :ts<separator> */
2813 static ApplyModifierResult
2814 ApplyModifier_ToSep(const char **pp, const char *val, ApplyModifiersState *st)
2815 {
2816 	const char *sep = *pp + 2;
2817 
2818 	/* ":ts<any><endc>" or ":ts<any>:" */
2819 	if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) {
2820 		st->sep = sep[0];
2821 		*pp = sep + 1;
2822 		goto ok;
2823 	}
2824 
2825 	/* ":ts<endc>" or ":ts:" */
2826 	if (sep[0] == st->endc || sep[0] == ':') {
2827 		st->sep = '\0';	/* no separator */
2828 		*pp = sep;
2829 		goto ok;
2830 	}
2831 
2832 	/* ":ts<unrecognised><unrecognised>". */
2833 	if (sep[0] != '\\') {
2834 		(*pp)++;	/* just for backwards compatibility */
2835 		return AMR_BAD;
2836 	}
2837 
2838 	/* ":ts\n" */
2839 	if (sep[1] == 'n') {
2840 		st->sep = '\n';
2841 		*pp = sep + 2;
2842 		goto ok;
2843 	}
2844 
2845 	/* ":ts\t" */
2846 	if (sep[1] == 't') {
2847 		st->sep = '\t';
2848 		*pp = sep + 2;
2849 		goto ok;
2850 	}
2851 
2852 	/* ":ts\x40" or ":ts\100" */
2853 	{
2854 		const char *p = sep + 1;
2855 		int base = 8;	/* assume octal */
2856 
2857 		if (sep[1] == 'x') {
2858 			base = 16;
2859 			p++;
2860 		} else if (!ch_isdigit(sep[1])) {
2861 			(*pp)++;	/* just for backwards compatibility */
2862 			return AMR_BAD;	/* ":ts<backslash><unrecognised>". */
2863 		}
2864 
2865 		if (!TryParseChar(&p, base, &st->sep)) {
2866 			Parse_Error(PARSE_FATAL,
2867 			    "Invalid character number: %s", p);
2868 			return AMR_CLEANUP;
2869 		}
2870 		if (*p != ':' && *p != st->endc) {
2871 			(*pp)++;	/* just for backwards compatibility */
2872 			return AMR_BAD;
2873 		}
2874 
2875 		*pp = p;
2876 	}
2877 
2878 ok:
2879 	st->newVal = FStr_InitOwn(
2880 	    ModifyWords(val, ModifyWord_Copy, NULL, st->oneBigWord, st->sep));
2881 	return AMR_OK;
2882 }
2883 
2884 static char *
2885 str_toupper(const char *str)
2886 {
2887 	char *res;
2888 	size_t i, len;
2889 
2890 	len = strlen(str);
2891 	res = bmake_malloc(len + 1);
2892 	for (i = 0; i < len + 1; i++)
2893 		res[i] = ch_toupper(str[i]);
2894 
2895 	return res;
2896 }
2897 
2898 static char *
2899 str_tolower(const char *str)
2900 {
2901 	char *res;
2902 	size_t i, len;
2903 
2904 	len = strlen(str);
2905 	res = bmake_malloc(len + 1);
2906 	for (i = 0; i < len + 1; i++)
2907 		res[i] = ch_tolower(str[i]);
2908 
2909 	return res;
2910 }
2911 
2912 /* :tA, :tu, :tl, :ts<separator>, etc. */
2913 static ApplyModifierResult
2914 ApplyModifier_To(const char **pp, const char *val, ApplyModifiersState *st)
2915 {
2916 	const char *mod = *pp;
2917 	assert(mod[0] == 't');
2918 
2919 	if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') {
2920 		*pp = mod + 1;
2921 		return AMR_BAD;	/* Found ":t<endc>" or ":t:". */
2922 	}
2923 
2924 	if (mod[1] == 's')
2925 		return ApplyModifier_ToSep(pp, val, st);
2926 
2927 	if (mod[2] != st->endc && mod[2] != ':') {
2928 		*pp = mod + 1;
2929 		return AMR_BAD;	/* Found ":t<unrecognised><unrecognised>". */
2930 	}
2931 
2932 	/* Check for two-character options: ":tu", ":tl" */
2933 	if (mod[1] == 'A') {	/* absolute path */
2934 		st->newVal = FStr_InitOwn(
2935 		    ModifyWords(val, ModifyWord_Realpath, NULL,
2936 		        st->oneBigWord, st->sep));
2937 		*pp = mod + 2;
2938 		return AMR_OK;
2939 	}
2940 
2941 	if (mod[1] == 'u') {	/* :tu */
2942 		st->newVal = FStr_InitOwn(str_toupper(val));
2943 		*pp = mod + 2;
2944 		return AMR_OK;
2945 	}
2946 
2947 	if (mod[1] == 'l') {	/* :tl */
2948 		st->newVal = FStr_InitOwn(str_tolower(val));
2949 		*pp = mod + 2;
2950 		return AMR_OK;
2951 	}
2952 
2953 	if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */
2954 		st->oneBigWord = mod[1] == 'W';
2955 		st->newVal = FStr_InitRefer(val);
2956 		*pp = mod + 2;
2957 		return AMR_OK;
2958 	}
2959 
2960 	/* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2961 	*pp = mod + 1;
2962 	return AMR_BAD;
2963 }
2964 
2965 /* :[#], :[1], :[-1..1], etc. */
2966 static ApplyModifierResult
2967 ApplyModifier_Words(const char **pp, const char *val, ApplyModifiersState *st)
2968 {
2969 	char *estr;
2970 	int first, last;
2971 	VarParseResult res;
2972 	const char *p;
2973 
2974 	(*pp)++;		/* skip the '[' */
2975 	res = ParseModifierPart(pp, ']', st->eflags, st, &estr);
2976 	if (res != VPR_OK)
2977 		return AMR_CLEANUP;
2978 
2979 	/* now *pp points just after the closing ']' */
2980 	if (**pp != ':' && **pp != st->endc)
2981 		goto bad_modifier;	/* Found junk after ']' */
2982 
2983 	if (estr[0] == '\0')
2984 		goto bad_modifier;	/* empty square brackets in ":[]". */
2985 
2986 	if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */
2987 		if (st->oneBigWord) {
2988 			st->newVal = FStr_InitRefer("1");
2989 		} else {
2990 			Buffer buf;
2991 
2992 			Words words = Str_Words(val, FALSE);
2993 			size_t ac = words.len;
2994 			Words_Free(words);
2995 
2996 			/* 3 digits + '\0' is usually enough */
2997 			Buf_InitSize(&buf, 4);
2998 			Buf_AddInt(&buf, (int)ac);
2999 			st->newVal = FStr_InitOwn(Buf_Destroy(&buf, FALSE));
3000 		}
3001 		goto ok;
3002 	}
3003 
3004 	if (estr[0] == '*' && estr[1] == '\0') {
3005 		/* Found ":[*]" */
3006 		st->oneBigWord = TRUE;
3007 		st->newVal = FStr_InitRefer(val);
3008 		goto ok;
3009 	}
3010 
3011 	if (estr[0] == '@' && estr[1] == '\0') {
3012 		/* Found ":[@]" */
3013 		st->oneBigWord = FALSE;
3014 		st->newVal = FStr_InitRefer(val);
3015 		goto ok;
3016 	}
3017 
3018 	/*
3019 	 * We expect estr to contain a single integer for :[N], or two
3020 	 * integers separated by ".." for :[start..end].
3021 	 */
3022 	p = estr;
3023 	if (!TryParseIntBase0(&p, &first))
3024 		goto bad_modifier;	/* Found junk instead of a number */
3025 
3026 	if (p[0] == '\0') {		/* Found only one integer in :[N] */
3027 		last = first;
3028 	} else if (p[0] == '.' && p[1] == '.' && p[2] != '\0') {
3029 		/* Expecting another integer after ".." */
3030 		p += 2;
3031 		if (!TryParseIntBase0(&p, &last) || *p != '\0')
3032 			goto bad_modifier; /* Found junk after ".." */
3033 	} else
3034 		goto bad_modifier;	/* Found junk instead of ".." */
3035 
3036 	/*
3037 	 * Now first and last are properly filled in, but we still have to
3038 	 * check for 0 as a special case.
3039 	 */
3040 	if (first == 0 && last == 0) {
3041 		/* ":[0]" or perhaps ":[0..0]" */
3042 		st->oneBigWord = TRUE;
3043 		st->newVal = FStr_InitRefer(val);
3044 		goto ok;
3045 	}
3046 
3047 	/* ":[0..N]" or ":[N..0]" */
3048 	if (first == 0 || last == 0)
3049 		goto bad_modifier;
3050 
3051 	/* Normal case: select the words described by first and last. */
3052 	st->newVal = FStr_InitOwn(
3053 	    VarSelectWords(st->sep, st->oneBigWord, val, first, last));
3054 
3055 ok:
3056 	free(estr);
3057 	return AMR_OK;
3058 
3059 bad_modifier:
3060 	free(estr);
3061 	return AMR_BAD;
3062 }
3063 
3064 static int
3065 str_cmp_asc(const void *a, const void *b)
3066 {
3067 	return strcmp(*(const char *const *)a, *(const char *const *)b);
3068 }
3069 
3070 static int
3071 str_cmp_desc(const void *a, const void *b)
3072 {
3073 	return strcmp(*(const char *const *)b, *(const char *const *)a);
3074 }
3075 
3076 static void
3077 ShuffleStrings(char **strs, size_t n)
3078 {
3079 	size_t i;
3080 
3081 	for (i = n - 1; i > 0; i--) {
3082 		size_t rndidx = (size_t)random() % (i + 1);
3083 		char *t = strs[i];
3084 		strs[i] = strs[rndidx];
3085 		strs[rndidx] = t;
3086 	}
3087 }
3088 
3089 /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
3090 static ApplyModifierResult
3091 ApplyModifier_Order(const char **pp, const char *val, ApplyModifiersState *st)
3092 {
3093 	const char *mod = (*pp)++;	/* skip past the 'O' in any case */
3094 
3095 	Words words = Str_Words(val, FALSE);
3096 
3097 	if (mod[1] == st->endc || mod[1] == ':') {
3098 		/* :O sorts ascending */
3099 		qsort(words.words, words.len, sizeof words.words[0],
3100 		    str_cmp_asc);
3101 
3102 	} else if ((mod[1] == 'r' || mod[1] == 'x') &&
3103 		   (mod[2] == st->endc || mod[2] == ':')) {
3104 		(*pp)++;
3105 
3106 		if (mod[1] == 'r') {	/* :Or sorts descending */
3107 			qsort(words.words, words.len, sizeof words.words[0],
3108 			    str_cmp_desc);
3109 		} else
3110 			ShuffleStrings(words.words, words.len);
3111 	} else {
3112 		Words_Free(words);
3113 		return AMR_BAD;
3114 	}
3115 
3116 	st->newVal = FStr_InitOwn(Words_JoinFree(words));
3117 	return AMR_OK;
3118 }
3119 
3120 /* :? then : else */
3121 static ApplyModifierResult
3122 ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
3123 {
3124 	char *then_expr, *else_expr;
3125 	VarParseResult res;
3126 
3127 	Boolean value = FALSE;
3128 	VarEvalFlags then_eflags = VARE_NONE;
3129 	VarEvalFlags else_eflags = VARE_NONE;
3130 
3131 	int cond_rc = COND_PARSE;	/* anything other than COND_INVALID */
3132 	if (st->eflags & VARE_WANTRES) {
3133 		cond_rc = Cond_EvalCondition(st->var->name.str, &value);
3134 		if (cond_rc != COND_INVALID && value)
3135 			then_eflags = st->eflags;
3136 		if (cond_rc != COND_INVALID && !value)
3137 			else_eflags = st->eflags;
3138 	}
3139 
3140 	(*pp)++;			/* skip past the '?' */
3141 	res = ParseModifierPart(pp, ':', then_eflags, st, &then_expr);
3142 	if (res != VPR_OK)
3143 		return AMR_CLEANUP;
3144 
3145 	res = ParseModifierPart(pp, st->endc, else_eflags, st, &else_expr);
3146 	if (res != VPR_OK)
3147 		return AMR_CLEANUP;
3148 
3149 	(*pp)--;
3150 	if (cond_rc == COND_INVALID) {
3151 		Error("Bad conditional expression `%s' in %s?%s:%s",
3152 		    st->var->name.str, st->var->name.str, then_expr, else_expr);
3153 		return AMR_CLEANUP;
3154 	}
3155 
3156 	if (value) {
3157 		st->newVal = FStr_InitOwn(then_expr);
3158 		free(else_expr);
3159 	} else {
3160 		st->newVal = FStr_InitOwn(else_expr);
3161 		free(then_expr);
3162 	}
3163 	ApplyModifiersState_Define(st);
3164 	return AMR_OK;
3165 }
3166 
3167 /*
3168  * The ::= modifiers actually assign a value to the variable.
3169  * Their main purpose is in supporting modifiers of .for loop
3170  * iterators and other obscure uses.  They always expand to
3171  * nothing.  In a target rule that would otherwise expand to an
3172  * empty line they can be preceded with @: to keep make happy.
3173  * Eg.
3174  *
3175  * foo:	.USE
3176  * .for i in ${.TARGET} ${.TARGET:R}.gz
3177  *	@: ${t::=$i}
3178  *	@echo blah ${t:T}
3179  * .endfor
3180  *
3181  *	  ::=<str>	Assigns <str> as the new value of variable.
3182  *	  ::?=<str>	Assigns <str> as value of variable if
3183  *			it was not already set.
3184  *	  ::+=<str>	Appends <str> to variable.
3185  *	  ::!=<cmd>	Assigns output of <cmd> as the new value of
3186  *			variable.
3187  */
3188 static ApplyModifierResult
3189 ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
3190 {
3191 	GNode *ctxt;
3192 	char delim;
3193 	char *val;
3194 	VarParseResult res;
3195 
3196 	const char *mod = *pp;
3197 	const char *op = mod + 1;
3198 
3199 	if (op[0] == '=')
3200 		goto ok;
3201 	if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=')
3202 		goto ok;
3203 	return AMR_UNKNOWN;	/* "::<unrecognised>" */
3204 ok:
3205 
3206 	if (st->var->name.str[0] == '\0') {
3207 		*pp = mod + 1;
3208 		return AMR_BAD;
3209 	}
3210 
3211 	ctxt = st->ctxt;	/* context where v belongs */
3212 	if (!(st->exprFlags & VEF_UNDEF) && st->ctxt != VAR_GLOBAL) {
3213 		Var *gv = VarFind(st->var->name.str, st->ctxt, FALSE);
3214 		if (gv == NULL)
3215 			ctxt = VAR_GLOBAL;
3216 		else
3217 			VarFreeEnv(gv, TRUE);
3218 	}
3219 
3220 	switch (op[0]) {
3221 	case '+':
3222 	case '?':
3223 	case '!':
3224 		*pp = mod + 3;
3225 		break;
3226 	default:
3227 		*pp = mod + 2;
3228 		break;
3229 	}
3230 
3231 	delim = st->startc == '(' ? ')' : '}';
3232 	res = ParseModifierPart(pp, delim, st->eflags, st, &val);
3233 	if (res != VPR_OK)
3234 		return AMR_CLEANUP;
3235 
3236 	(*pp)--;
3237 
3238 	if (st->eflags & VARE_WANTRES) {
3239 		switch (op[0]) {
3240 		case '+':
3241 			Var_Append(st->var->name.str, val, ctxt);
3242 			break;
3243 		case '!': {
3244 			const char *errfmt;
3245 			char *cmd_output = Cmd_Exec(val, &errfmt);
3246 			if (errfmt != NULL)
3247 				Error(errfmt, val);
3248 			else
3249 				Var_Set(st->var->name.str, cmd_output, ctxt);
3250 			free(cmd_output);
3251 			break;
3252 		}
3253 		case '?':
3254 			if (!(st->exprFlags & VEF_UNDEF))
3255 				break;
3256 			/* FALLTHROUGH */
3257 		default:
3258 			Var_Set(st->var->name.str, val, ctxt);
3259 			break;
3260 		}
3261 	}
3262 	free(val);
3263 	st->newVal = FStr_InitRefer("");
3264 	return AMR_OK;
3265 }
3266 
3267 /*
3268  * :_=...
3269  * remember current value
3270  */
3271 static ApplyModifierResult
3272 ApplyModifier_Remember(const char **pp, const char *val,
3273 		       ApplyModifiersState *st)
3274 {
3275 	const char *mod = *pp;
3276 	if (!ModMatchEq(mod, "_", st->endc))
3277 		return AMR_UNKNOWN;
3278 
3279 	if (mod[1] == '=') {
3280 		size_t n = strcspn(mod + 2, ":)}");
3281 		char *name = bmake_strldup(mod + 2, n);
3282 		Var_Set(name, val, st->ctxt);
3283 		free(name);
3284 		*pp = mod + 2 + n;
3285 	} else {
3286 		Var_Set("_", val, st->ctxt);
3287 		*pp = mod + 1;
3288 	}
3289 	st->newVal = FStr_InitRefer(val);
3290 	return AMR_OK;
3291 }
3292 
3293 /*
3294  * Apply the given function to each word of the variable value,
3295  * for a single-letter modifier such as :H, :T.
3296  */
3297 static ApplyModifierResult
3298 ApplyModifier_WordFunc(const char **pp, const char *val,
3299 		       ApplyModifiersState *st, ModifyWordsCallback modifyWord)
3300 {
3301 	char delim = (*pp)[1];
3302 	if (delim != st->endc && delim != ':')
3303 		return AMR_UNKNOWN;
3304 
3305 	st->newVal = FStr_InitOwn(ModifyWords(val, modifyWord, NULL,
3306 	    st->oneBigWord, st->sep));
3307 	(*pp)++;
3308 	return AMR_OK;
3309 }
3310 
3311 static ApplyModifierResult
3312 ApplyModifier_Unique(const char **pp, const char *val, ApplyModifiersState *st)
3313 {
3314 	if ((*pp)[1] == st->endc || (*pp)[1] == ':') {
3315 		st->newVal = FStr_InitOwn(VarUniq(val));
3316 		(*pp)++;
3317 		return AMR_OK;
3318 	} else
3319 		return AMR_UNKNOWN;
3320 }
3321 
3322 #ifdef SYSVVARSUB
3323 /* :from=to */
3324 static ApplyModifierResult
3325 ApplyModifier_SysV(const char **pp, const char *val, ApplyModifiersState *st)
3326 {
3327 	char *lhs, *rhs;
3328 	VarParseResult res;
3329 
3330 	const char *mod = *pp;
3331 	Boolean eqFound = FALSE;
3332 
3333 	/*
3334 	 * First we make a pass through the string trying to verify it is a
3335 	 * SysV-make-style translation. It must be: <lhs>=<rhs>
3336 	 */
3337 	int depth = 1;
3338 	const char *p = mod;
3339 	while (*p != '\0' && depth > 0) {
3340 		if (*p == '=') {	/* XXX: should also test depth == 1 */
3341 			eqFound = TRUE;
3342 			/* continue looking for st->endc */
3343 		} else if (*p == st->endc)
3344 			depth--;
3345 		else if (*p == st->startc)
3346 			depth++;
3347 		if (depth > 0)
3348 			p++;
3349 	}
3350 	if (*p != st->endc || !eqFound)
3351 		return AMR_UNKNOWN;
3352 
3353 	res = ParseModifierPart(pp, '=', st->eflags, st, &lhs);
3354 	if (res != VPR_OK)
3355 		return AMR_CLEANUP;
3356 
3357 	/* The SysV modifier lasts until the end of the variable expression. */
3358 	res = ParseModifierPart(pp, st->endc, st->eflags, st, &rhs);
3359 	if (res != VPR_OK)
3360 		return AMR_CLEANUP;
3361 
3362 	(*pp)--;
3363 	if (lhs[0] == '\0' && val[0] == '\0') {
3364 		st->newVal = FStr_InitRefer(val); /* special case */
3365 	} else {
3366 		struct ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs };
3367 		st->newVal = FStr_InitOwn(
3368 		    ModifyWords(val, ModifyWord_SYSVSubst, &args,
3369 			st->oneBigWord, st->sep));
3370 	}
3371 	free(lhs);
3372 	free(rhs);
3373 	return AMR_OK;
3374 }
3375 #endif
3376 
3377 #ifdef SUNSHCMD
3378 /* :sh */
3379 static ApplyModifierResult
3380 ApplyModifier_SunShell(const char **pp, const char *val,
3381 		       ApplyModifiersState *st)
3382 {
3383 	const char *p = *pp;
3384 	if (p[1] == 'h' && (p[2] == st->endc || p[2] == ':')) {
3385 		if (st->eflags & VARE_WANTRES) {
3386 			const char *errfmt;
3387 			st->newVal = FStr_InitOwn(Cmd_Exec(val, &errfmt));
3388 			if (errfmt != NULL)
3389 				Error(errfmt, val);
3390 		} else
3391 			st->newVal = FStr_InitRefer("");
3392 		*pp = p + 2;
3393 		return AMR_OK;
3394 	} else
3395 		return AMR_UNKNOWN;
3396 }
3397 #endif
3398 
3399 static void
3400 LogBeforeApply(const ApplyModifiersState *st, const char *mod, char endc,
3401 	       const char *val)
3402 {
3403 	char eflags_str[VarEvalFlags_ToStringSize];
3404 	char vflags_str[VarFlags_ToStringSize];
3405 	char exprflags_str[VarExprFlags_ToStringSize];
3406 	Boolean is_single_char = mod[0] != '\0' &&
3407 				 (mod[1] == endc || mod[1] == ':');
3408 
3409 	/* At this point, only the first character of the modifier can
3410 	 * be used since the end of the modifier is not yet known. */
3411 	debug_printf("Applying ${%s:%c%s} to \"%s\" (%s, %s, %s)\n",
3412 	    st->var->name.str, mod[0], is_single_char ? "" : "...", val,
3413 	    Enum_FlagsToString(eflags_str, sizeof eflags_str,
3414 		st->eflags, VarEvalFlags_ToStringSpecs),
3415 	    Enum_FlagsToString(vflags_str, sizeof vflags_str,
3416 		st->var->flags, VarFlags_ToStringSpecs),
3417 	    Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3418 		st->exprFlags,
3419 		VarExprFlags_ToStringSpecs));
3420 }
3421 
3422 static void
3423 LogAfterApply(ApplyModifiersState *st, const char *p, const char *mod)
3424 {
3425 	char eflags_str[VarEvalFlags_ToStringSize];
3426 	char vflags_str[VarFlags_ToStringSize];
3427 	char exprflags_str[VarExprFlags_ToStringSize];
3428 	const char *quot = st->newVal.str == var_Error ? "" : "\"";
3429 	const char *newVal =
3430 	    st->newVal.str == var_Error ? "error" : st->newVal.str;
3431 
3432 	debug_printf("Result of ${%s:%.*s} is %s%s%s (%s, %s, %s)\n",
3433 	    st->var->name.str, (int)(p - mod), mod, quot, newVal, quot,
3434 	    Enum_FlagsToString(eflags_str, sizeof eflags_str,
3435 		st->eflags, VarEvalFlags_ToStringSpecs),
3436 	    Enum_FlagsToString(vflags_str, sizeof vflags_str,
3437 		st->var->flags, VarFlags_ToStringSpecs),
3438 	    Enum_FlagsToString(exprflags_str, sizeof exprflags_str,
3439 		st->exprFlags,
3440 		VarExprFlags_ToStringSpecs));
3441 }
3442 
3443 static ApplyModifierResult
3444 ApplyModifier(const char **pp, const char *val, ApplyModifiersState *st)
3445 {
3446 	switch (**pp) {
3447 	case ':':
3448 		return ApplyModifier_Assign(pp, st);
3449 	case '@':
3450 		return ApplyModifier_Loop(pp, val, st);
3451 	case '_':
3452 		return ApplyModifier_Remember(pp, val, st);
3453 	case 'D':
3454 	case 'U':
3455 		return ApplyModifier_Defined(pp, val, st);
3456 	case 'L':
3457 		return ApplyModifier_Literal(pp, st);
3458 	case 'P':
3459 		return ApplyModifier_Path(pp, st);
3460 	case '!':
3461 		return ApplyModifier_ShellCommand(pp, st);
3462 	case '[':
3463 		return ApplyModifier_Words(pp, val, st);
3464 	case 'g':
3465 		return ApplyModifier_Gmtime(pp, val, st);
3466 	case 'h':
3467 		return ApplyModifier_Hash(pp, val, st);
3468 	case 'l':
3469 		return ApplyModifier_Localtime(pp, val, st);
3470 	case 't':
3471 		return ApplyModifier_To(pp, val, st);
3472 	case 'N':
3473 	case 'M':
3474 		return ApplyModifier_Match(pp, val, st);
3475 	case 'S':
3476 		return ApplyModifier_Subst(pp, val, st);
3477 	case '?':
3478 		return ApplyModifier_IfElse(pp, st);
3479 #ifndef NO_REGEX
3480 	case 'C':
3481 		return ApplyModifier_Regex(pp, val, st);
3482 #endif
3483 	case 'q':
3484 	case 'Q':
3485 		return ApplyModifier_Quote(pp, val, st);
3486 	case 'T':
3487 		return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Tail);
3488 	case 'H':
3489 		return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Head);
3490 	case 'E':
3491 		return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Suffix);
3492 	case 'R':
3493 		return ApplyModifier_WordFunc(pp, val, st, ModifyWord_Root);
3494 	case 'r':
3495 		return ApplyModifier_Range(pp, val, st);
3496 	case 'O':
3497 		return ApplyModifier_Order(pp, val, st);
3498 	case 'u':
3499 		return ApplyModifier_Unique(pp, val, st);
3500 #ifdef SUNSHCMD
3501 	case 's':
3502 		return ApplyModifier_SunShell(pp, val, st);
3503 #endif
3504 	default:
3505 		return AMR_UNKNOWN;
3506 	}
3507 }
3508 
3509 static FStr ApplyModifiers(const char **, FStr, char, char, Var *,
3510 			    VarExprFlags *, GNode *, VarEvalFlags);
3511 
3512 typedef enum ApplyModifiersIndirectResult {
3513 	/* The indirect modifiers have been applied successfully. */
3514 	AMIR_CONTINUE,
3515 	/* Fall back to the SysV modifier. */
3516 	AMIR_APPLY_MODS,
3517 	/* Error out. */
3518 	AMIR_OUT
3519 } ApplyModifiersIndirectResult;
3520 
3521 /*
3522  * While expanding a variable expression, expand and apply indirect modifiers,
3523  * such as in ${VAR:${M_indirect}}.
3524  *
3525  * All indirect modifiers of a group must come from a single variable
3526  * expression.  ${VAR:${M1}} is valid but ${VAR:${M1}${M2}} is not.
3527  *
3528  * Multiple groups of indirect modifiers can be chained by separating them
3529  * with colons.  ${VAR:${M1}:${M2}} contains 2 indirect modifiers.
3530  *
3531  * If the variable expression is not followed by st->endc or ':', fall
3532  * back to trying the SysV modifier, such as in ${VAR:${FROM}=${TO}}.
3533  *
3534  * The expression ${VAR:${M1}${M2}} is not treated as an indirect
3535  * modifier, and it is neither a SysV modifier but a parse error.
3536  */
3537 static ApplyModifiersIndirectResult
3538 ApplyModifiersIndirect(ApplyModifiersState *st, const char **pp,
3539 		       FStr *inout_value)
3540 {
3541 	const char *p = *pp;
3542 	FStr mods;
3543 
3544 	(void)Var_Parse(&p, st->ctxt, st->eflags, &mods);
3545 	/* TODO: handle errors */
3546 
3547 	if (mods.str[0] != '\0' && *p != '\0' && *p != ':' && *p != st->endc) {
3548 		FStr_Done(&mods);
3549 		return AMIR_APPLY_MODS;
3550 	}
3551 
3552 	DEBUG3(VAR, "Indirect modifier \"%s\" from \"%.*s\"\n",
3553 	    mods.str, (int)(p - *pp), *pp);
3554 
3555 	if (mods.str[0] != '\0') {
3556 		const char *modsp = mods.str;
3557 		FStr newVal = ApplyModifiers(&modsp, *inout_value, '\0', '\0',
3558 		    st->var, &st->exprFlags, st->ctxt, st->eflags);
3559 		*inout_value = newVal;
3560 		if (newVal.str == var_Error || *modsp != '\0') {
3561 			FStr_Done(&mods);
3562 			*pp = p;
3563 			return AMIR_OUT;	/* error already reported */
3564 		}
3565 	}
3566 	FStr_Done(&mods);
3567 
3568 	if (*p == ':')
3569 		p++;
3570 	else if (*p == '\0' && st->endc != '\0') {
3571 		Error("Unclosed variable specification after complex "
3572 		      "modifier (expecting '%c') for %s",
3573 		    st->endc, st->var->name.str);
3574 		*pp = p;
3575 		return AMIR_OUT;
3576 	}
3577 
3578 	*pp = p;
3579 	return AMIR_CONTINUE;
3580 }
3581 
3582 static ApplyModifierResult
3583 ApplySingleModifier(ApplyModifiersState *st, const char *mod, char endc,
3584 		    const char **pp, FStr *inout_value)
3585 {
3586 	ApplyModifierResult res;
3587 	const char *p = *pp;
3588 	const char *const val = inout_value->str;
3589 
3590 	if (DEBUG(VAR))
3591 		LogBeforeApply(st, mod, endc, val);
3592 
3593 	res = ApplyModifier(&p, val, st);
3594 
3595 #ifdef SYSVVARSUB
3596 	if (res == AMR_UNKNOWN) {
3597 		assert(p == mod);
3598 		res = ApplyModifier_SysV(&p, val, st);
3599 	}
3600 #endif
3601 
3602 	if (res == AMR_UNKNOWN) {
3603 		Parse_Error(PARSE_FATAL, "Unknown modifier '%c'", *mod);
3604 		/*
3605 		 * Guess the end of the current modifier.
3606 		 * XXX: Skipping the rest of the modifier hides
3607 		 * errors and leads to wrong results.
3608 		 * Parsing should rather stop here.
3609 		 */
3610 		for (p++; *p != ':' && *p != st->endc && *p != '\0'; p++)
3611 			continue;
3612 		st->newVal = FStr_InitRefer(var_Error);
3613 	}
3614 	if (res == AMR_CLEANUP || res == AMR_BAD) {
3615 		*pp = p;
3616 		return res;
3617 	}
3618 
3619 	if (DEBUG(VAR))
3620 		LogAfterApply(st, p, mod);
3621 
3622 	if (st->newVal.str != val) {
3623 		FStr_Done(inout_value);
3624 		*inout_value = st->newVal;
3625 	}
3626 	if (*p == '\0' && st->endc != '\0') {
3627 		Error(
3628 		    "Unclosed variable specification (expecting '%c') "
3629 		    "for \"%s\" (value \"%s\") modifier %c",
3630 		    st->endc, st->var->name.str, inout_value->str, *mod);
3631 	} else if (*p == ':') {
3632 		p++;
3633 	} else if (opts.strict && *p != '\0' && *p != endc) {
3634 		Parse_Error(PARSE_FATAL,
3635 		    "Missing delimiter ':' after modifier \"%.*s\"",
3636 		    (int)(p - mod), mod);
3637 		/*
3638 		 * TODO: propagate parse error to the enclosing
3639 		 * expression
3640 		 */
3641 	}
3642 	*pp = p;
3643 	return AMR_OK;
3644 }
3645 
3646 /* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */
3647 static FStr
3648 ApplyModifiers(
3649     const char **pp,		/* the parsing position, updated upon return */
3650     FStr value,			/* the current value of the expression */
3651     char startc,		/* '(' or '{', or '\0' for indirect modifiers */
3652     char endc,			/* ')' or '}', or '\0' for indirect modifiers */
3653     Var *v,
3654     VarExprFlags *exprFlags,
3655     GNode *ctxt,		/* for looking up and modifying variables */
3656     VarEvalFlags eflags
3657 )
3658 {
3659 	ApplyModifiersState st = {
3660 	    startc, endc, v, ctxt, eflags,
3661 	    FStr_InitRefer(var_Error), /* .newVal */
3662 	    ' ',		/* .sep */
3663 	    FALSE,		/* .oneBigWord */
3664 	    *exprFlags		/* .exprFlags */
3665 	};
3666 	const char *p;
3667 	const char *mod;
3668 
3669 	assert(startc == '(' || startc == '{' || startc == '\0');
3670 	assert(endc == ')' || endc == '}' || endc == '\0');
3671 	assert(value.str != NULL);
3672 
3673 	p = *pp;
3674 
3675 	if (*p == '\0' && endc != '\0') {
3676 		Error(
3677 		    "Unclosed variable expression (expecting '%c') for \"%s\"",
3678 		    st.endc, st.var->name.str);
3679 		goto cleanup;
3680 	}
3681 
3682 	while (*p != '\0' && *p != endc) {
3683 		ApplyModifierResult res;
3684 
3685 		if (*p == '$') {
3686 			ApplyModifiersIndirectResult amir;
3687 			amir = ApplyModifiersIndirect(&st, &p, &value);
3688 			if (amir == AMIR_CONTINUE)
3689 				continue;
3690 			if (amir == AMIR_OUT)
3691 				break;
3692 		}
3693 
3694 		/* default value, in case of errors */
3695 		st.newVal = FStr_InitRefer(var_Error);
3696 		mod = p;
3697 
3698 		res = ApplySingleModifier(&st, mod, endc, &p, &value);
3699 		if (res == AMR_CLEANUP)
3700 			goto cleanup;
3701 		if (res == AMR_BAD)
3702 			goto bad_modifier;
3703 	}
3704 
3705 	*pp = p;
3706 	assert(value.str != NULL); /* Use var_Error or varUndefined instead. */
3707 	*exprFlags = st.exprFlags;
3708 	return value;
3709 
3710 bad_modifier:
3711 	/* XXX: The modifier end is only guessed. */
3712 	Error("Bad modifier `:%.*s' for %s",
3713 	    (int)strcspn(mod, ":)}"), mod, st.var->name.str);
3714 
3715 cleanup:
3716 	*pp = p;
3717 	FStr_Done(&value);
3718 	*exprFlags = st.exprFlags;
3719 	return FStr_InitRefer(var_Error);
3720 }
3721 
3722 /*
3723  * Only four of the local variables are treated specially as they are the
3724  * only four that will be set when dynamic sources are expanded.
3725  */
3726 static Boolean
3727 VarnameIsDynamic(const char *name, size_t len)
3728 {
3729 	if (len == 1 || (len == 2 && (name[1] == 'F' || name[1] == 'D'))) {
3730 		switch (name[0]) {
3731 		case '@':
3732 		case '%':
3733 		case '*':
3734 		case '!':
3735 			return TRUE;
3736 		}
3737 		return FALSE;
3738 	}
3739 
3740 	if ((len == 7 || len == 8) && name[0] == '.' && ch_isupper(name[1])) {
3741 		return strcmp(name, ".TARGET") == 0 ||
3742 		       strcmp(name, ".ARCHIVE") == 0 ||
3743 		       strcmp(name, ".PREFIX") == 0 ||
3744 		       strcmp(name, ".MEMBER") == 0;
3745 	}
3746 
3747 	return FALSE;
3748 }
3749 
3750 static const char *
3751 UndefinedShortVarValue(char varname, const GNode *ctxt)
3752 {
3753 	if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL) {
3754 		/*
3755 		 * If substituting a local variable in a non-local context,
3756 		 * assume it's for dynamic source stuff. We have to handle
3757 		 * this specially and return the longhand for the variable
3758 		 * with the dollar sign escaped so it makes it back to the
3759 		 * caller. Only four of the local variables are treated
3760 		 * specially as they are the only four that will be set
3761 		 * when dynamic sources are expanded.
3762 		 */
3763 		switch (varname) {
3764 		case '@':
3765 			return "$(.TARGET)";
3766 		case '%':
3767 			return "$(.MEMBER)";
3768 		case '*':
3769 			return "$(.PREFIX)";
3770 		case '!':
3771 			return "$(.ARCHIVE)";
3772 		}
3773 	}
3774 	return NULL;
3775 }
3776 
3777 /*
3778  * Parse a variable name, until the end character or a colon, whichever
3779  * comes first.
3780  */
3781 static char *
3782 ParseVarname(const char **pp, char startc, char endc,
3783 	     GNode *ctxt, VarEvalFlags eflags,
3784 	     size_t *out_varname_len)
3785 {
3786 	Buffer buf;
3787 	const char *p = *pp;
3788 	int depth = 1;
3789 
3790 	Buf_Init(&buf);
3791 
3792 	while (*p != '\0') {
3793 		/* Track depth so we can spot parse errors. */
3794 		if (*p == startc)
3795 			depth++;
3796 		if (*p == endc) {
3797 			if (--depth == 0)
3798 				break;
3799 		}
3800 		if (*p == ':' && depth == 1)
3801 			break;
3802 
3803 		/* A variable inside a variable, expand. */
3804 		if (*p == '$') {
3805 			FStr nested_val;
3806 			(void)Var_Parse(&p, ctxt, eflags, &nested_val);
3807 			/* TODO: handle errors */
3808 			Buf_AddStr(&buf, nested_val.str);
3809 			FStr_Done(&nested_val);
3810 		} else {
3811 			Buf_AddByte(&buf, *p);
3812 			p++;
3813 		}
3814 	}
3815 	*pp = p;
3816 	*out_varname_len = Buf_Len(&buf);
3817 	return Buf_Destroy(&buf, FALSE);
3818 }
3819 
3820 static VarParseResult
3821 ValidShortVarname(char varname, const char *start)
3822 {
3823 	switch (varname) {
3824 	case '\0':
3825 	case ')':
3826 	case '}':
3827 	case ':':
3828 	case '$':
3829 		break;		/* and continue below */
3830 	default:
3831 		return VPR_OK;
3832 	}
3833 
3834 	if (!opts.strict)
3835 		return VPR_ERR;	/* XXX: Missing error message */
3836 
3837 	if (varname == '$')
3838 		Parse_Error(PARSE_FATAL,
3839 		    "To escape a dollar, use \\$, not $$, at \"%s\"", start);
3840 	else if (varname == '\0')
3841 		Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
3842 	else
3843 		Parse_Error(PARSE_FATAL,
3844 		    "Invalid variable name '%c', at \"%s\"", varname, start);
3845 
3846 	return VPR_ERR;
3847 }
3848 
3849 /*
3850  * Parse a single-character variable name such as $V or $@.
3851  * Return whether to continue parsing.
3852  */
3853 static Boolean
3854 ParseVarnameShort(char startc, const char **pp, GNode *ctxt,
3855 		  VarEvalFlags eflags,
3856 		  VarParseResult *out_FALSE_res, const char **out_FALSE_val,
3857 		  Var **out_TRUE_var)
3858 {
3859 	char name[2];
3860 	Var *v;
3861 	VarParseResult vpr;
3862 
3863 	/*
3864 	 * If it's not bounded by braces of some sort, life is much simpler.
3865 	 * We just need to check for the first character and return the
3866 	 * value if it exists.
3867 	 */
3868 
3869 	vpr = ValidShortVarname(startc, *pp);
3870 	if (vpr != VPR_OK) {
3871 		(*pp)++;
3872 		*out_FALSE_val = var_Error;
3873 		*out_FALSE_res = vpr;
3874 		return FALSE;
3875 	}
3876 
3877 	name[0] = startc;
3878 	name[1] = '\0';
3879 	v = VarFind(name, ctxt, TRUE);
3880 	if (v == NULL) {
3881 		const char *val;
3882 		*pp += 2;
3883 
3884 		val = UndefinedShortVarValue(startc, ctxt);
3885 		if (val == NULL)
3886 			val = eflags & VARE_UNDEFERR ? var_Error : varUndefined;
3887 
3888 		if (opts.strict && val == var_Error) {
3889 			Parse_Error(PARSE_FATAL,
3890 			    "Variable \"%s\" is undefined", name);
3891 			*out_FALSE_res = VPR_ERR;
3892 			*out_FALSE_val = val;
3893 			return FALSE;
3894 		}
3895 
3896 		/*
3897 		 * XXX: This looks completely wrong.
3898 		 *
3899 		 * If undefined expressions are not allowed, this should
3900 		 * rather be VPR_ERR instead of VPR_UNDEF, together with an
3901 		 * error message.
3902 		 *
3903 		 * If undefined expressions are allowed, this should rather
3904 		 * be VPR_UNDEF instead of VPR_OK.
3905 		 */
3906 		*out_FALSE_res = eflags & VARE_UNDEFERR ? VPR_UNDEF : VPR_OK;
3907 		*out_FALSE_val = val;
3908 		return FALSE;
3909 	}
3910 
3911 	*out_TRUE_var = v;
3912 	return TRUE;
3913 }
3914 
3915 /* Find variables like @F or <D. */
3916 static Var *
3917 FindLocalLegacyVar(const char *varname, size_t namelen, GNode *ctxt,
3918 		   const char **out_extraModifiers)
3919 {
3920 	/* Only resolve these variables if ctxt is a "real" target. */
3921 	if (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL)
3922 		return NULL;
3923 
3924 	if (namelen != 2)
3925 		return NULL;
3926 	if (varname[1] != 'F' && varname[1] != 'D')
3927 		return NULL;
3928 	if (strchr("@%?*!<>", varname[0]) == NULL)
3929 		return NULL;
3930 
3931 	{
3932 		char name[] = { varname[0], '\0' };
3933 		Var *v = VarFind(name, ctxt, FALSE);
3934 
3935 		if (v != NULL) {
3936 			if (varname[1] == 'D') {
3937 				*out_extraModifiers = "H:";
3938 			} else { /* F */
3939 				*out_extraModifiers = "T:";
3940 			}
3941 		}
3942 		return v;
3943 	}
3944 }
3945 
3946 static VarParseResult
3947 EvalUndefined(Boolean dynamic, const char *start, const char *p, char *varname,
3948 	      VarEvalFlags eflags,
3949 	      FStr *out_val)
3950 {
3951 	if (dynamic) {
3952 		*out_val = FStr_InitOwn(bmake_strsedup(start, p));
3953 		free(varname);
3954 		return VPR_OK;
3955 	}
3956 
3957 	if ((eflags & VARE_UNDEFERR) && opts.strict) {
3958 		Parse_Error(PARSE_FATAL,
3959 		    "Variable \"%s\" is undefined", varname);
3960 		free(varname);
3961 		*out_val = FStr_InitRefer(var_Error);
3962 		return VPR_ERR;
3963 	}
3964 
3965 	if (eflags & VARE_UNDEFERR) {
3966 		free(varname);
3967 		*out_val = FStr_InitRefer(var_Error);
3968 		return VPR_UNDEF;	/* XXX: Should be VPR_ERR instead. */
3969 	}
3970 
3971 	free(varname);
3972 	*out_val = FStr_InitRefer(varUndefined);
3973 	return VPR_OK;
3974 }
3975 
3976 /*
3977  * Parse a long variable name enclosed in braces or parentheses such as $(VAR)
3978  * or ${VAR}, up to the closing brace or parenthesis, or in the case of
3979  * ${VAR:Modifiers}, up to the ':' that starts the modifiers.
3980  * Return whether to continue parsing.
3981  */
3982 static Boolean
3983 ParseVarnameLong(
3984 	const char *p,
3985 	char startc,
3986 	GNode *ctxt,
3987 	VarEvalFlags eflags,
3988 
3989 	const char **out_FALSE_pp,
3990 	VarParseResult *out_FALSE_res,
3991 	FStr *out_FALSE_val,
3992 
3993 	char *out_TRUE_endc,
3994 	const char **out_TRUE_p,
3995 	Var **out_TRUE_v,
3996 	Boolean *out_TRUE_haveModifier,
3997 	const char **out_TRUE_extraModifiers,
3998 	Boolean *out_TRUE_dynamic,
3999 	VarExprFlags *out_TRUE_exprFlags
4000 )
4001 {
4002 	size_t namelen;
4003 	char *varname;
4004 	Var *v;
4005 	Boolean haveModifier;
4006 	Boolean dynamic = FALSE;
4007 
4008 	const char *const start = p;
4009 	char endc = startc == '(' ? ')' : '}';
4010 
4011 	p += 2;			/* skip "${" or "$(" or "y(" */
4012 	varname = ParseVarname(&p, startc, endc, ctxt, eflags, &namelen);
4013 
4014 	if (*p == ':') {
4015 		haveModifier = TRUE;
4016 	} else if (*p == endc) {
4017 		haveModifier = FALSE;
4018 	} else {
4019 		Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname);
4020 		free(varname);
4021 		*out_FALSE_pp = p;
4022 		*out_FALSE_val = FStr_InitRefer(var_Error);
4023 		*out_FALSE_res = VPR_ERR;
4024 		return FALSE;
4025 	}
4026 
4027 	v = VarFind(varname, ctxt, TRUE);
4028 
4029 	/* At this point, p points just after the variable name,
4030 	 * either at ':' or at endc. */
4031 
4032 	if (v == NULL) {
4033 		v = FindLocalLegacyVar(varname, namelen, ctxt,
4034 		    out_TRUE_extraModifiers);
4035 	}
4036 
4037 	if (v == NULL) {
4038 		/*
4039 		 * Defer expansion of dynamic variables if they appear in
4040 		 * non-local context since they are not defined there.
4041 		 */
4042 		dynamic = VarnameIsDynamic(varname, namelen) &&
4043 			  (ctxt == VAR_CMDLINE || ctxt == VAR_GLOBAL);
4044 
4045 		if (!haveModifier) {
4046 			p++;	/* skip endc */
4047 			*out_FALSE_pp = p;
4048 			*out_FALSE_res = EvalUndefined(dynamic, start, p,
4049 			    varname, eflags, out_FALSE_val);
4050 			return FALSE;
4051 		}
4052 
4053 		/*
4054 		 * The variable expression is based on an undefined variable.
4055 		 * Nevertheless it needs a Var, for modifiers that access the
4056 		 * variable name, such as :L or :?.
4057 		 *
4058 		 * Most modifiers leave this expression in the "undefined"
4059 		 * state (VEF_UNDEF), only a few modifiers like :D, :U, :L,
4060 		 * :P turn this undefined expression into a defined
4061 		 * expression (VEF_DEF).
4062 		 *
4063 		 * At the end, after applying all modifiers, if the expression
4064 		 * is still undefined, Var_Parse will return an empty string
4065 		 * instead of the actually computed value.
4066 		 */
4067 		v = VarNew(FStr_InitOwn(varname), "", VAR_NONE);
4068 		*out_TRUE_exprFlags = VEF_UNDEF;
4069 	} else
4070 		free(varname);
4071 
4072 	*out_TRUE_endc = endc;
4073 	*out_TRUE_p = p;
4074 	*out_TRUE_v = v;
4075 	*out_TRUE_haveModifier = haveModifier;
4076 	*out_TRUE_dynamic = dynamic;
4077 	return TRUE;
4078 }
4079 
4080 /* Free the environment variable now since we own it. */
4081 static void
4082 FreeEnvVar(void **out_val_freeIt, Var *v, const char *value)
4083 {
4084 	char *varValue = Buf_Destroy(&v->val, FALSE);
4085 	if (value == varValue)
4086 		*out_val_freeIt = varValue;
4087 	else
4088 		free(varValue);
4089 
4090 	FStr_Done(&v->name);
4091 	free(v);
4092 }
4093 
4094 /*
4095  * Given the start of a variable expression (such as $v, $(VAR),
4096  * ${VAR:Mpattern}), extract the variable name and value, and the modifiers,
4097  * if any.  While doing that, apply the modifiers to the value of the
4098  * expression, forming its final value.  A few of the modifiers such as :!cmd!
4099  * or ::= have side effects.
4100  *
4101  * Input:
4102  *	*pp		The string to parse.
4103  *			When parsing a condition in ParseEmptyArg, it may also
4104  *			point to the "y" of "empty(VARNAME:Modifiers)", which
4105  *			is syntactically the same.
4106  *	ctxt		The context for finding variables
4107  *	eflags		Control the exact details of parsing
4108  *
4109  * Output:
4110  *	*pp		The position where to continue parsing.
4111  *			TODO: After a parse error, the value of *pp is
4112  *			unspecified.  It may not have been updated at all,
4113  *			point to some random character in the string, to the
4114  *			location of the parse error, or at the end of the
4115  *			string.
4116  *	*out_val	The value of the variable expression, never NULL.
4117  *	*out_val	var_Error if there was a parse error.
4118  *	*out_val	var_Error if the base variable of the expression was
4119  *			undefined, eflags contains VARE_UNDEFERR, and none of
4120  *			the modifiers turned the undefined expression into a
4121  *			defined expression.
4122  *			XXX: It is not guaranteed that an error message has
4123  *			been printed.
4124  *	*out_val	varUndefined if the base variable of the expression
4125  *			was undefined, eflags did not contain VARE_UNDEFERR,
4126  *			and none of the modifiers turned the undefined
4127  *			expression into a defined expression.
4128  *			XXX: It is not guaranteed that an error message has
4129  *			been printed.
4130  *	*out_val_freeIt	Must be freed by the caller after using *out_val.
4131  */
4132 /* coverity[+alloc : arg-*4] */
4133 VarParseResult
4134 Var_Parse(const char **pp, GNode *ctxt, VarEvalFlags eflags, FStr *out_val)
4135 {
4136 	const char *p = *pp;
4137 	const char *const start = p;
4138 	/* TRUE if have modifiers for the variable. */
4139 	Boolean haveModifier;
4140 	/* Starting character if variable in parens or braces. */
4141 	char startc;
4142 	/* Ending character if variable in parens or braces. */
4143 	char endc;
4144 	/*
4145 	 * TRUE if the variable is local and we're expanding it in a
4146 	 * non-local context. This is done to support dynamic sources.
4147 	 * The result is just the expression, unaltered.
4148 	 */
4149 	Boolean dynamic;
4150 	const char *extramodifiers;
4151 	Var *v;
4152 	FStr value;
4153 	char eflags_str[VarEvalFlags_ToStringSize];
4154 	VarExprFlags exprFlags = VEF_NONE;
4155 
4156 	DEBUG2(VAR, "Var_Parse: %s with %s\n", start,
4157 	    Enum_FlagsToString(eflags_str, sizeof eflags_str, eflags,
4158 		VarEvalFlags_ToStringSpecs));
4159 
4160 	*out_val = FStr_InitRefer(NULL);
4161 	extramodifiers = NULL;	/* extra modifiers to apply first */
4162 	dynamic = FALSE;
4163 
4164 	/*
4165 	 * Appease GCC, which thinks that the variable might not be
4166 	 * initialized.
4167 	 */
4168 	endc = '\0';
4169 
4170 	startc = p[1];
4171 	if (startc != '(' && startc != '{') {
4172 		VarParseResult res;
4173 		if (!ParseVarnameShort(startc, pp, ctxt, eflags, &res,
4174 		    &out_val->str, &v))
4175 			return res;
4176 		haveModifier = FALSE;
4177 		p++;
4178 	} else {
4179 		VarParseResult res;
4180 		if (!ParseVarnameLong(p, startc, ctxt, eflags,
4181 		    pp, &res, out_val,
4182 		    &endc, &p, &v, &haveModifier, &extramodifiers,
4183 		    &dynamic, &exprFlags))
4184 			return res;
4185 	}
4186 
4187 	if (v->flags & VAR_IN_USE)
4188 		Fatal("Variable %s is recursive.", v->name.str);
4189 
4190 	/*
4191 	 * XXX: This assignment creates an alias to the current value of the
4192 	 * variable.  This means that as long as the value of the expression
4193 	 * stays the same, the value of the variable must not change.
4194 	 * Using the '::=' modifier, it could be possible to do exactly this.
4195 	 * At the bottom of this function, the resulting value is compared to
4196 	 * the then-current value of the variable.  This might also invoke
4197 	 * undefined behavior.
4198 	 */
4199 	value = FStr_InitRefer(Buf_GetAll(&v->val, NULL));
4200 
4201 	/*
4202 	 * Before applying any modifiers, expand any nested expressions from
4203 	 * the variable value.
4204 	 */
4205 	if (strchr(value.str, '$') != NULL && (eflags & VARE_WANTRES)) {
4206 		char *expanded;
4207 		VarEvalFlags nested_eflags = eflags;
4208 		if (opts.strict)
4209 			nested_eflags &= ~(unsigned)VARE_UNDEFERR;
4210 		v->flags |= VAR_IN_USE;
4211 		(void)Var_Subst(value.str, ctxt, nested_eflags, &expanded);
4212 		v->flags &= ~(unsigned)VAR_IN_USE;
4213 		/* TODO: handle errors */
4214 		value = FStr_InitOwn(expanded);
4215 	}
4216 
4217 	if (haveModifier || extramodifiers != NULL) {
4218 		if (extramodifiers != NULL) {
4219 			const char *em = extramodifiers;
4220 			value = ApplyModifiers(&em, value, '\0', '\0',
4221 			    v, &exprFlags, ctxt, eflags);
4222 		}
4223 
4224 		if (haveModifier) {
4225 			p++;	/* Skip initial colon. */
4226 
4227 			value = ApplyModifiers(&p, value, startc, endc,
4228 			    v, &exprFlags, ctxt, eflags);
4229 		}
4230 	}
4231 
4232 	if (*p != '\0')		/* Skip past endc if possible. */
4233 		p++;
4234 
4235 	*pp = p;
4236 
4237 	if (v->flags & VAR_FROM_ENV) {
4238 		FreeEnvVar(&value.freeIt, v, value.str);
4239 
4240 	} else if (exprFlags & VEF_UNDEF) {
4241 		if (!(exprFlags & VEF_DEF)) {
4242 			FStr_Done(&value);
4243 			if (dynamic) {
4244 				value = FStr_InitOwn(bmake_strsedup(start, p));
4245 			} else {
4246 				/*
4247 				 * The expression is still undefined,
4248 				 * therefore discard the actual value and
4249 				 * return an error marker instead.
4250 				 */
4251 				value = FStr_InitRefer(eflags & VARE_UNDEFERR
4252 				    ? var_Error : varUndefined);
4253 			}
4254 		}
4255 		if (value.str != Buf_GetAll(&v->val, NULL))
4256 			Buf_Destroy(&v->val, TRUE);
4257 		FStr_Done(&v->name);
4258 		free(v);
4259 	}
4260 	*out_val = (FStr){ value.str, value.freeIt };
4261 	return VPR_OK;		/* XXX: Is not correct in all cases */
4262 }
4263 
4264 static void
4265 VarSubstDollarDollar(const char **pp, Buffer *res, VarEvalFlags eflags)
4266 {
4267 	/*
4268 	 * A dollar sign may be escaped with another dollar
4269 	 * sign.
4270 	 */
4271 	if (save_dollars && (eflags & VARE_KEEP_DOLLAR))
4272 		Buf_AddByte(res, '$');
4273 	Buf_AddByte(res, '$');
4274 	*pp += 2;
4275 }
4276 
4277 static void
4278 VarSubstExpr(const char **pp, Buffer *buf, GNode *ctxt,
4279 	     VarEvalFlags eflags, Boolean *inout_errorReported)
4280 {
4281 	const char *p = *pp;
4282 	const char *nested_p = p;
4283 	FStr val;
4284 
4285 	(void)Var_Parse(&nested_p, ctxt, eflags, &val);
4286 	/* TODO: handle errors */
4287 
4288 	if (val.str == var_Error || val.str == varUndefined) {
4289 		if (!(eflags & VARE_KEEP_UNDEF)) {
4290 			p = nested_p;
4291 		} else if ((eflags & VARE_UNDEFERR) || val.str == var_Error) {
4292 
4293 			/*
4294 			 * XXX: This condition is wrong.  If val == var_Error,
4295 			 * this doesn't necessarily mean there was an undefined
4296 			 * variable.  It could equally well be a parse error;
4297 			 * see unit-tests/varmod-order.exp.
4298 			 */
4299 
4300 			/*
4301 			 * If variable is undefined, complain and skip the
4302 			 * variable. The complaint will stop us from doing
4303 			 * anything when the file is parsed.
4304 			 */
4305 			if (!*inout_errorReported) {
4306 				Parse_Error(PARSE_FATAL,
4307 				    "Undefined variable \"%.*s\"",
4308 				    (int)(size_t)(nested_p - p), p);
4309 			}
4310 			p = nested_p;
4311 			*inout_errorReported = TRUE;
4312 		} else {
4313 			/* Copy the initial '$' of the undefined expression,
4314 			 * thereby deferring expansion of the expression, but
4315 			 * expand nested expressions if already possible.
4316 			 * See unit-tests/varparse-undef-partial.mk. */
4317 			Buf_AddByte(buf, *p);
4318 			p++;
4319 		}
4320 	} else {
4321 		p = nested_p;
4322 		Buf_AddStr(buf, val.str);
4323 	}
4324 
4325 	FStr_Done(&val);
4326 
4327 	*pp = p;
4328 }
4329 
4330 /*
4331  * Skip as many characters as possible -- either to the end of the string
4332  * or to the next dollar sign (variable expression).
4333  */
4334 static void
4335 VarSubstPlain(const char **pp, Buffer *res)
4336 {
4337 	const char *p = *pp;
4338 	const char *start = p;
4339 
4340 	for (p++; *p != '$' && *p != '\0'; p++)
4341 		continue;
4342 	Buf_AddBytesBetween(res, start, p);
4343 	*pp = p;
4344 }
4345 
4346 /*
4347  * Expand all variable expressions like $V, ${VAR}, $(VAR:Modifiers) in the
4348  * given string.
4349  *
4350  * Input:
4351  *	str		The string in which the variable expressions are
4352  *			expanded.
4353  *	ctxt		The context in which to start searching for
4354  *			variables.  The other contexts are searched as well.
4355  *	eflags		Special effects during expansion.
4356  */
4357 VarParseResult
4358 Var_Subst(const char *str, GNode *ctxt, VarEvalFlags eflags, char **out_res)
4359 {
4360 	const char *p = str;
4361 	Buffer res;
4362 
4363 	/* Set true if an error has already been reported,
4364 	 * to prevent a plethora of messages when recursing */
4365 	/* XXX: Why is the 'static' necessary here? */
4366 	static Boolean errorReported;
4367 
4368 	Buf_Init(&res);
4369 	errorReported = FALSE;
4370 
4371 	while (*p != '\0') {
4372 		if (p[0] == '$' && p[1] == '$')
4373 			VarSubstDollarDollar(&p, &res, eflags);
4374 		else if (p[0] == '$')
4375 			VarSubstExpr(&p, &res, ctxt, eflags, &errorReported);
4376 		else
4377 			VarSubstPlain(&p, &res);
4378 	}
4379 
4380 	*out_res = Buf_DestroyCompact(&res);
4381 	return VPR_OK;
4382 }
4383 
4384 /* Initialize the variables module. */
4385 void
4386 Var_Init(void)
4387 {
4388 	VAR_INTERNAL = GNode_New("Internal");
4389 	VAR_GLOBAL = GNode_New("Global");
4390 	VAR_CMDLINE = GNode_New("Command");
4391 }
4392 
4393 /* Clean up the variables module. */
4394 void
4395 Var_End(void)
4396 {
4397 	Var_Stats();
4398 }
4399 
4400 void
4401 Var_Stats(void)
4402 {
4403 	HashTable_DebugStats(&VAR_GLOBAL->vars, "VAR_GLOBAL");
4404 }
4405 
4406 /* Print all variables in a context, sorted by name. */
4407 void
4408 Var_Dump(GNode *ctxt)
4409 {
4410 	Vector /* of const char * */ vec;
4411 	HashIter hi;
4412 	size_t i;
4413 	const char **varnames;
4414 
4415 	Vector_Init(&vec, sizeof(const char *));
4416 
4417 	HashIter_Init(&hi, &ctxt->vars);
4418 	while (HashIter_Next(&hi) != NULL)
4419 		*(const char **)Vector_Push(&vec) = hi.entry->key;
4420 	varnames = vec.items;
4421 
4422 	qsort(varnames, vec.len, sizeof varnames[0], str_cmp_asc);
4423 
4424 	for (i = 0; i < vec.len; i++) {
4425 		const char *varname = varnames[i];
4426 		Var *var = HashTable_FindValue(&ctxt->vars, varname);
4427 		debug_printf("%-16s = %s\n",
4428 		    varname, Buf_GetAll(&var->val, NULL));
4429 	}
4430 
4431 	Vector_Done(&vec);
4432 }
4433