xref: /dragonfly/contrib/bmake/var.c (revision 2b7dbe20)
1 /*	$NetBSD: var.c,v 1.255 2020/07/04 17:41:04 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 #ifndef MAKE_NATIVE
72 static char rcsid[] = "$NetBSD: var.c,v 1.255 2020/07/04 17:41:04 rillig Exp $";
73 #else
74 #include <sys/cdefs.h>
75 #ifndef lint
76 #if 0
77 static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 3/19/94";
78 #else
79 __RCSID("$NetBSD: var.c,v 1.255 2020/07/04 17:41:04 rillig Exp $");
80 #endif
81 #endif /* not lint */
82 #endif
83 
84 /*-
85  * var.c --
86  *	Variable-handling functions
87  *
88  * Interface:
89  *	Var_Set		    Set the value of a variable in the given
90  *			    context. The variable is created if it doesn't
91  *			    yet exist. The value and variable name need not
92  *			    be preserved.
93  *
94  *	Var_Append	    Append more characters to an existing variable
95  *			    in the given context. The variable needn't
96  *			    exist already -- it will be created if it doesn't.
97  *			    A space is placed between the old value and the
98  *			    new one.
99  *
100  *	Var_Exists	    See if a variable exists.
101  *
102  *	Var_Value 	    Return the value of a variable in a context or
103  *			    NULL if the variable is undefined.
104  *
105  *	Var_Subst 	    Substitute either a single variable or all
106  *			    variables in a string, using the given context as
107  *			    the top-most one.
108  *
109  *	Var_Parse 	    Parse a variable expansion from a string and
110  *			    return the result and the number of characters
111  *			    consumed.
112  *
113  *	Var_Delete	    Delete a variable in a context.
114  *
115  *	Var_Init  	    Initialize this module.
116  *
117  * Debugging:
118  *	Var_Dump  	    Print out all variables defined in the given
119  *			    context.
120  *
121  * XXX: There's a lot of duplication in these functions.
122  */
123 
124 #include    <sys/stat.h>
125 #include    <sys/types.h>
126 #ifndef NO_REGEX
127 #include    <regex.h>
128 #endif
129 #include    <ctype.h>
130 #include    <stdlib.h>
131 #include    <limits.h>
132 #include    <time.h>
133 
134 #include    "make.h"
135 
136 #ifdef HAVE_STDINT_H
137 #include <stdint.h>
138 #endif
139 
140 #include    "buf.h"
141 #include    "dir.h"
142 #include    "job.h"
143 #include    "metachar.h"
144 
145 extern int makelevel;
146 /*
147  * This lets us tell if we have replaced the original environ
148  * (which we cannot free).
149  */
150 char **savedEnv = NULL;
151 
152 /*
153  * This is a harmless return value for Var_Parse that can be used by Var_Subst
154  * to determine if there was an error in parsing -- easier than returning
155  * a flag, as things outside this module don't give a hoot.
156  */
157 char var_Error[] = "";
158 
159 /*
160  * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for
161  * Var_Parse is not set. Why not just use a constant? Well, gcc likes
162  * to condense identical string instances...
163  */
164 static char varNoError[] = "";
165 
166 /*
167  * Traditionally we consume $$ during := like any other expansion.
168  * Other make's do not.
169  * This knob allows controlling the behavior.
170  * FALSE for old behavior.
171  * TRUE for new compatible.
172  */
173 #define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
174 static Boolean save_dollars = FALSE;
175 
176 /*
177  * Internally, variables are contained in four different contexts.
178  *	1) the environment. They may not be changed. If an environment
179  *	    variable is appended-to, the result is placed in the global
180  *	    context.
181  *	2) the global context. Variables set in the Makefile are located in
182  *	    the global context. It is the penultimate context searched when
183  *	    substituting.
184  *	3) the command-line context. All variables set on the command line
185  *	   are placed in this context. They are UNALTERABLE once placed here.
186  *	4) the local context. Each target has associated with it a context
187  *	   list. On this list are located the structures describing such
188  *	   local variables as $(@) and $(*)
189  * The four contexts are searched in the reverse order from which they are
190  * listed.
191  */
192 GNode          *VAR_INTERNAL;	/* variables from make itself */
193 GNode          *VAR_GLOBAL;	/* variables from the makefile */
194 GNode          *VAR_CMD;	/* variables defined on the command-line */
195 
196 #define FIND_CMD	0x1	/* look in VAR_CMD when searching */
197 #define FIND_GLOBAL	0x2	/* look in VAR_GLOBAL as well */
198 #define FIND_ENV  	0x4	/* look in the environment also */
199 
200 typedef enum {
201     VAR_IN_USE		= 0x01,	/* Variable's value is currently being used.
202 				 * Used to avoid endless recursion */
203     VAR_FROM_ENV	= 0x02,	/* Variable comes from the environment */
204     VAR_JUNK		= 0x04,	/* Variable is a junk variable that
205 				 * should be destroyed when done with
206 				 * it. Used by Var_Parse for undefined,
207 				 * modified variables */
208     VAR_KEEP		= 0x08,	/* Variable is VAR_JUNK, but we found
209 				 * a use for it in some modifier and
210 				 * the value is therefore valid */
211     VAR_EXPORTED	= 0x10,	/* Variable is exported */
212     VAR_REEXPORT	= 0x20,	/* Indicate if var needs re-export.
213 				 * This would be true if it contains $'s */
214     VAR_FROM_CMD	= 0x40	/* Variable came from command line */
215 } Var_Flags;
216 
217 typedef struct Var {
218     char          *name;	/* the variable's name */
219     Buffer	  val;		/* its value */
220     Var_Flags	  flags;    	/* miscellaneous status flags */
221 }  Var;
222 
223 /*
224  * Exporting vars is expensive so skip it if we can
225  */
226 #define VAR_EXPORTED_NONE	0
227 #define VAR_EXPORTED_YES	1
228 #define VAR_EXPORTED_ALL	2
229 static int var_exportedVars = VAR_EXPORTED_NONE;
230 /*
231  * We pass this to Var_Export when doing the initial export
232  * or after updating an exported var.
233  */
234 #define VAR_EXPORT_PARENT	1
235 /*
236  * We pass this to Var_Export1 to tell it to leave the value alone.
237  */
238 #define VAR_EXPORT_LITERAL	2
239 
240 typedef enum {
241 	VAR_SUB_GLOBAL	= 0x01,	/* Apply substitution globally */
242 	VAR_SUB_ONE	= 0x02,	/* Apply substitution to one word */
243 	VAR_SUB_MATCHED	= 0x04,	/* There was a match */
244 	VAR_MATCH_START	= 0x08,	/* Match at start of word */
245 	VAR_MATCH_END	= 0x10,	/* Match at end of word */
246 	VAR_NOSUBST	= 0x20	/* don't expand vars in VarGetPattern */
247 } VarPattern_Flags;
248 
249 typedef enum {
250 	VAR_NO_EXPORT	= 0x01	/* do not export */
251 } VarSet_Flags;
252 
253 typedef struct {
254     /*
255      * The following fields are set by Var_Parse() when it
256      * encounters modifiers that need to keep state for use by
257      * subsequent modifiers within the same variable expansion.
258      */
259     Byte	varSpace;	/* Word separator in expansions */
260     Boolean	oneBigWord;	/* TRUE if we will treat the variable as a
261 				 * single big word, even if it contains
262 				 * embedded spaces (as opposed to the
263 				 * usual behaviour of treating it as
264 				 * several space-separated words). */
265 } Var_Parse_State;
266 
267 /* struct passed as 'void *' to VarSubstitute() for ":S/lhs/rhs/",
268  * to VarSYSVMatch() for ":lhs=rhs". */
269 typedef struct {
270     const char   *lhs;		/* String to match */
271     int		  leftLen;	/* Length of string */
272     const char   *rhs;		/* Replacement string (w/ &'s removed) */
273     int		  rightLen;	/* Length of replacement */
274     VarPattern_Flags flags;
275 } VarPattern;
276 
277 /* struct passed as 'void *' to VarLoopExpand() for ":@tvar@str@" */
278 typedef struct {
279     GNode	*ctxt;		/* variable context */
280     char	*tvar;		/* name of temp var */
281     int		tvarLen;
282     char	*str;		/* string to expand */
283     int		strLen;
284     Varf_Flags	flags;
285 } VarLoop;
286 
287 #ifndef NO_REGEX
288 /* struct passed as 'void *' to VarRESubstitute() for ":C///" */
289 typedef struct {
290     regex_t	   re;
291     int		   nsub;
292     regmatch_t 	  *matches;
293     char 	  *replace;
294     int		   flags;
295 } VarREPattern;
296 #endif
297 
298 /* struct passed to VarSelectWords() for ":[start..end]" */
299 typedef struct {
300     int		start;		/* first word to select */
301     int		end;		/* last word to select */
302 } VarSelectWords_t;
303 
304 #define BROPEN	'{'
305 #define BRCLOSE	'}'
306 #define PROPEN	'('
307 #define PRCLOSE	')'
308 
309 /*-
310  *-----------------------------------------------------------------------
311  * VarFind --
312  *	Find the given variable in the given context and any other contexts
313  *	indicated.
314  *
315  * Input:
316  *	name		name to find
317  *	ctxt		context in which to find it
318  *	flags		FIND_GLOBAL set means to look in the
319  *			VAR_GLOBAL context as well. FIND_CMD set means
320  *			to look in the VAR_CMD context also. FIND_ENV
321  *			set means to look in the environment
322  *
323  * Results:
324  *	A pointer to the structure describing the desired variable or
325  *	NULL if the variable does not exist.
326  *
327  * Side Effects:
328  *	None
329  *-----------------------------------------------------------------------
330  */
331 static Var *
332 VarFind(const char *name, GNode *ctxt, int flags)
333 {
334     Hash_Entry         	*var;
335     Var			*v;
336 
337     /*
338      * If the variable name begins with a '.', it could very well be one of
339      * the local ones.  We check the name against all the local variables
340      * and substitute the short version in for 'name' if it matches one of
341      * them.
342      */
343     if (*name == '.' && isupper((unsigned char) name[1])) {
344 	switch (name[1]) {
345 	case 'A':
346 	    if (!strcmp(name, ".ALLSRC"))
347 		name = ALLSRC;
348 	    if (!strcmp(name, ".ARCHIVE"))
349 		name = ARCHIVE;
350 	    break;
351 	case 'I':
352 	    if (!strcmp(name, ".IMPSRC"))
353 		name = IMPSRC;
354 	    break;
355 	case 'M':
356 	    if (!strcmp(name, ".MEMBER"))
357 		name = MEMBER;
358 	    break;
359 	case 'O':
360 	    if (!strcmp(name, ".OODATE"))
361 		name = OODATE;
362 	    break;
363 	case 'P':
364 	    if (!strcmp(name, ".PREFIX"))
365 		name = PREFIX;
366 	    break;
367 	case 'T':
368 	    if (!strcmp(name, ".TARGET"))
369 		name = TARGET;
370 	    break;
371 	}
372     }
373 
374 #ifdef notyet
375     /* for compatibility with gmake */
376     if (name[0] == '^' && name[1] == '\0')
377 	name = ALLSRC;
378 #endif
379 
380     /*
381      * First look for the variable in the given context. If it's not there,
382      * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
383      * depending on the FIND_* flags in 'flags'
384      */
385     var = Hash_FindEntry(&ctxt->context, name);
386 
387     if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
388 	var = Hash_FindEntry(&VAR_CMD->context, name);
389     }
390     if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
391 	ctxt != VAR_GLOBAL)
392     {
393 	var = Hash_FindEntry(&VAR_GLOBAL->context, name);
394 	if (var == NULL && ctxt != VAR_INTERNAL) {
395 	    /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
396 	    var = Hash_FindEntry(&VAR_INTERNAL->context, name);
397 	}
398     }
399     if (var == NULL && (flags & FIND_ENV)) {
400 	char *env;
401 
402 	if ((env = getenv(name)) != NULL) {
403 	    int		len;
404 
405 	    v = bmake_malloc(sizeof(Var));
406 	    v->name = bmake_strdup(name);
407 
408 	    len = strlen(env);
409 
410 	    Buf_Init(&v->val, len + 1);
411 	    Buf_AddBytes(&v->val, len, env);
412 
413 	    v->flags = VAR_FROM_ENV;
414 	    return v;
415 	} else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
416 		   ctxt != VAR_GLOBAL)
417 	{
418 	    var = Hash_FindEntry(&VAR_GLOBAL->context, name);
419 	    if (var == NULL && ctxt != VAR_INTERNAL) {
420 		var = Hash_FindEntry(&VAR_INTERNAL->context, name);
421 	    }
422 	    if (var == NULL) {
423 		return NULL;
424 	    } else {
425 		return (Var *)Hash_GetValue(var);
426 	    }
427 	} else {
428 	    return NULL;
429 	}
430     } else if (var == NULL) {
431 	return NULL;
432     } else {
433 	return (Var *)Hash_GetValue(var);
434     }
435 }
436 
437 /*-
438  *-----------------------------------------------------------------------
439  * VarFreeEnv  --
440  *	If the variable is an environment variable, free it
441  *
442  * Input:
443  *	v		the variable
444  *	destroy		true if the value buffer should be destroyed.
445  *
446  * Results:
447  *	1 if it is an environment variable 0 ow.
448  *
449  * Side Effects:
450  *	The variable is free'ed if it is an environent variable.
451  *-----------------------------------------------------------------------
452  */
453 static Boolean
454 VarFreeEnv(Var *v, Boolean destroy)
455 {
456     if ((v->flags & VAR_FROM_ENV) == 0)
457 	return FALSE;
458     free(v->name);
459     Buf_Destroy(&v->val, destroy);
460     free(v);
461     return TRUE;
462 }
463 
464 /*-
465  *-----------------------------------------------------------------------
466  * VarAdd  --
467  *	Add a new variable of name name and value val to the given context
468  *
469  * Input:
470  *	name		name of variable to add
471  *	val		value to set it to
472  *	ctxt		context in which to set it
473  *
474  * Side Effects:
475  *	The new variable is placed at the front of the given context
476  *	The name and val arguments are duplicated so they may
477  *	safely be freed.
478  *-----------------------------------------------------------------------
479  */
480 static void
481 VarAdd(const char *name, const char *val, GNode *ctxt)
482 {
483     Var   	  *v;
484     int		  len;
485     Hash_Entry    *h;
486 
487     v = bmake_malloc(sizeof(Var));
488 
489     len = val ? strlen(val) : 0;
490     Buf_Init(&v->val, len + 1);
491     Buf_AddBytes(&v->val, len, val);
492 
493     v->flags = 0;
494 
495     h = Hash_CreateEntry(&ctxt->context, name, NULL);
496     Hash_SetValue(h, v);
497     v->name = h->name;
498     if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) {
499 	fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
500     }
501 }
502 
503 /*-
504  *-----------------------------------------------------------------------
505  * Var_Delete --
506  *	Remove a variable from a context.
507  *
508  * Side Effects:
509  *	The Var structure is removed and freed.
510  *
511  *-----------------------------------------------------------------------
512  */
513 void
514 Var_Delete(const char *name, GNode *ctxt)
515 {
516     Hash_Entry 	  *ln;
517     char *cp;
518 
519     if (strchr(name, '$')) {
520 	cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES);
521     } else {
522 	cp = __DECONST(char *,name); /* XXX */
523     }
524     ln = Hash_FindEntry(&ctxt->context, cp);
525     if (DEBUG(VAR)) {
526 	fprintf(debug_file, "%s:delete %s%s\n",
527 	    ctxt->name, cp, ln ? "" : " (not found)");
528     }
529     if (cp != name) {
530 	free(cp);
531     }
532     if (ln != NULL) {
533 	Var 	  *v;
534 
535 	v = (Var *)Hash_GetValue(ln);
536 	if ((v->flags & VAR_EXPORTED)) {
537 	    unsetenv(v->name);
538 	}
539 	if (strcmp(MAKE_EXPORTED, v->name) == 0) {
540 	    var_exportedVars = VAR_EXPORTED_NONE;
541 	}
542 	if (v->name != ln->name)
543 	    free(v->name);
544 	Hash_DeleteEntry(&ctxt->context, ln);
545 	Buf_Destroy(&v->val, TRUE);
546 	free(v);
547     }
548 }
549 
550 
551 /*
552  * Export a var.
553  * We ignore make internal variables (those which start with '.')
554  * Also we jump through some hoops to avoid calling setenv
555  * more than necessary since it can leak.
556  * We only manipulate flags of vars if 'parent' is set.
557  */
558 static int
559 Var_Export1(const char *name, int flags)
560 {
561     char tmp[BUFSIZ];
562     Var *v;
563     char *val = NULL;
564     int n;
565     int parent = (flags & VAR_EXPORT_PARENT);
566 
567     if (*name == '.')
568 	return 0;		/* skip internals */
569     if (!name[1]) {
570 	/*
571 	 * A single char.
572 	 * If it is one of the vars that should only appear in
573 	 * local context, skip it, else we can get Var_Subst
574 	 * into a loop.
575 	 */
576 	switch (name[0]) {
577 	case '@':
578 	case '%':
579 	case '*':
580 	case '!':
581 	    return 0;
582 	}
583     }
584     v = VarFind(name, VAR_GLOBAL, 0);
585     if (v == NULL) {
586 	return 0;
587     }
588     if (!parent &&
589 	(v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
590 	return 0;			/* nothing to do */
591     }
592     val = Buf_GetAll(&v->val, NULL);
593     if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
594 	if (parent) {
595 	    /*
596 	     * Flag this as something we need to re-export.
597 	     * No point actually exporting it now though,
598 	     * the child can do it at the last minute.
599 	     */
600 	    v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
601 	    return 1;
602 	}
603 	if (v->flags & VAR_IN_USE) {
604 	    /*
605 	     * We recursed while exporting in a child.
606 	     * This isn't going to end well, just skip it.
607 	     */
608 	    return 0;
609 	}
610 	n = snprintf(tmp, sizeof(tmp), "${%s}", name);
611 	if (n < (int)sizeof(tmp)) {
612 	    val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
613 	    setenv(name, val, 1);
614 	    free(val);
615 	}
616     } else {
617 	if (parent) {
618 	    v->flags &= ~VAR_REEXPORT;	/* once will do */
619 	}
620 	if (parent || !(v->flags & VAR_EXPORTED)) {
621 	    setenv(name, val, 1);
622 	}
623     }
624     /*
625      * This is so Var_Set knows to call Var_Export again...
626      */
627     if (parent) {
628 	v->flags |= VAR_EXPORTED;
629     }
630     return 1;
631 }
632 
633 static void
634 Var_ExportVars_callback(void *entry, void *unused MAKE_ATTR_UNUSED)
635 {
636     Var *var = entry;
637     Var_Export1(var->name, 0);
638 }
639 
640 /*
641  * This gets called from our children.
642  */
643 void
644 Var_ExportVars(void)
645 {
646     char tmp[BUFSIZ];
647     char *val;
648     int n;
649 
650     /*
651      * Several make's support this sort of mechanism for tracking
652      * recursion - but each uses a different name.
653      * We allow the makefiles to update MAKELEVEL and ensure
654      * children see a correctly incremented value.
655      */
656     snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
657     setenv(MAKE_LEVEL_ENV, tmp, 1);
658 
659     if (VAR_EXPORTED_NONE == var_exportedVars)
660 	return;
661 
662     if (VAR_EXPORTED_ALL == var_exportedVars) {
663 	/* Ouch! This is crazy... */
664 	Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL);
665 	return;
666     }
667     /*
668      * We have a number of exported vars,
669      */
670     n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
671     if (n < (int)sizeof(tmp)) {
672 	char **av;
673 	char *as;
674 	int ac;
675 	int i;
676 
677 	val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
678 	if (*val) {
679 	    av = brk_string(val, &ac, FALSE, &as);
680 	    for (i = 0; i < ac; i++) {
681 		Var_Export1(av[i], 0);
682 	    }
683 	    free(as);
684 	    free(av);
685 	}
686 	free(val);
687     }
688 }
689 
690 /*
691  * This is called when .export is seen or
692  * .MAKE.EXPORTED is modified.
693  * It is also called when any exported var is modified.
694  */
695 void
696 Var_Export(char *str, int isExport)
697 {
698     char *name;
699     char *val;
700     char **av;
701     char *as;
702     int flags;
703     int ac;
704     int i;
705 
706     if (isExport && (!str || !str[0])) {
707 	var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
708 	return;
709     }
710 
711     flags = 0;
712     if (strncmp(str, "-env", 4) == 0) {
713 	str += 4;
714     } else if (strncmp(str, "-literal", 8) == 0) {
715 	str += 8;
716 	flags |= VAR_EXPORT_LITERAL;
717     } else {
718 	flags |= VAR_EXPORT_PARENT;
719     }
720     val = Var_Subst(NULL, str, VAR_GLOBAL, VARF_WANTRES);
721     if (*val) {
722 	av = brk_string(val, &ac, FALSE, &as);
723 	for (i = 0; i < ac; i++) {
724 	    name = av[i];
725 	    if (!name[1]) {
726 		/*
727 		 * A single char.
728 		 * If it is one of the vars that should only appear in
729 		 * local context, skip it, else we can get Var_Subst
730 		 * into a loop.
731 		 */
732 		switch (name[0]) {
733 		case '@':
734 		case '%':
735 		case '*':
736 		case '!':
737 		    continue;
738 		}
739 	    }
740 	    if (Var_Export1(name, flags)) {
741 		if (VAR_EXPORTED_ALL != var_exportedVars)
742 		    var_exportedVars = VAR_EXPORTED_YES;
743 		if (isExport && (flags & VAR_EXPORT_PARENT)) {
744 		    Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
745 		}
746 	    }
747 	}
748 	free(as);
749 	free(av);
750     }
751     free(val);
752 }
753 
754 
755 /*
756  * This is called when .unexport[-env] is seen.
757  */
758 extern char **environ;
759 
760 void
761 Var_UnExport(char *str)
762 {
763     char tmp[BUFSIZ];
764     char *vlist;
765     char *cp;
766     Boolean unexport_env;
767     int n;
768 
769     if (!str || !str[0]) {
770 	return;			/* assert? */
771     }
772 
773     vlist = NULL;
774 
775     str += 8;
776     unexport_env = (strncmp(str, "-env", 4) == 0);
777     if (unexport_env) {
778 	char **newenv;
779 
780 	cp = getenv(MAKE_LEVEL_ENV);	/* we should preserve this */
781 	if (environ == savedEnv) {
782 	    /* we have been here before! */
783 	    newenv = bmake_realloc(environ, 2 * sizeof(char *));
784 	} else {
785 	    if (savedEnv) {
786 		free(savedEnv);
787 		savedEnv = NULL;
788 	    }
789 	    newenv = bmake_malloc(2 * sizeof(char *));
790 	}
791 	if (!newenv)
792 	    return;
793 	/* Note: we cannot safely free() the original environ. */
794 	environ = savedEnv = newenv;
795 	newenv[0] = NULL;
796 	newenv[1] = NULL;
797 	if (cp && *cp)
798 	    setenv(MAKE_LEVEL_ENV, cp, 1);
799     } else {
800 	for (; *str != '\n' && isspace((unsigned char) *str); str++)
801 	    continue;
802 	if (str[0] && str[0] != '\n') {
803 	    vlist = str;
804 	}
805     }
806 
807     if (!vlist) {
808 	/* Using .MAKE.EXPORTED */
809 	n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
810 	if (n < (int)sizeof(tmp)) {
811 	    vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
812 	}
813     }
814     if (vlist) {
815 	Var *v;
816 	char **av;
817 	char *as;
818 	int ac;
819 	int i;
820 
821 	av = brk_string(vlist, &ac, FALSE, &as);
822 	for (i = 0; i < ac; i++) {
823 	    v = VarFind(av[i], VAR_GLOBAL, 0);
824 	    if (!v)
825 		continue;
826 	    if (!unexport_env &&
827 		(v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
828 		unsetenv(v->name);
829 	    }
830 	    v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
831 	    /*
832 	     * If we are unexporting a list,
833 	     * remove each one from .MAKE.EXPORTED.
834 	     * If we are removing them all,
835 	     * just delete .MAKE.EXPORTED below.
836 	     */
837 	    if (vlist == str) {
838 		n = snprintf(tmp, sizeof(tmp),
839 			     "${" MAKE_EXPORTED ":N%s}", v->name);
840 		if (n < (int)sizeof(tmp)) {
841 		    cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
842 		    Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
843 		    free(cp);
844 		}
845 	    }
846 	}
847 	free(as);
848 	free(av);
849 	if (vlist != str) {
850 	    Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
851 	    free(vlist);
852 	}
853     }
854 }
855 
856 static void
857 Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
858 		   VarSet_Flags flags)
859 {
860     Var *v;
861     char *expanded_name = NULL;
862 
863     /*
864      * We only look for a variable in the given context since anything set
865      * here will override anything in a lower context, so there's not much
866      * point in searching them all just to save a bit of memory...
867      */
868     if (strchr(name, '$') != NULL) {
869 	expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
870 	if (expanded_name[0] == 0) {
871 	    if (DEBUG(VAR)) {
872 		fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
873 			"name expands to empty string - ignored\n",
874 			name, val);
875 	    }
876 	    free(expanded_name);
877 	    return;
878 	}
879 	name = expanded_name;
880     }
881     if (ctxt == VAR_GLOBAL) {
882 	v = VarFind(name, VAR_CMD, 0);
883 	if (v != NULL) {
884 	    if ((v->flags & VAR_FROM_CMD)) {
885 		if (DEBUG(VAR)) {
886 		    fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
887 		}
888 		goto out;
889 	    }
890 	    VarFreeEnv(v, TRUE);
891 	}
892     }
893     v = VarFind(name, ctxt, 0);
894     if (v == NULL) {
895 	if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
896 	    /*
897 	     * This var would normally prevent the same name being added
898 	     * to VAR_GLOBAL, so delete it from there if needed.
899 	     * Otherwise -V name may show the wrong value.
900 	     */
901 	    Var_Delete(name, VAR_GLOBAL);
902 	}
903 	VarAdd(name, val, ctxt);
904     } else {
905 	Buf_Empty(&v->val);
906 	if (val)
907 	    Buf_AddBytes(&v->val, strlen(val), val);
908 
909 	if (DEBUG(VAR)) {
910 	    fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
911 	}
912 	if ((v->flags & VAR_EXPORTED)) {
913 	    Var_Export1(name, VAR_EXPORT_PARENT);
914 	}
915     }
916     /*
917      * Any variables given on the command line are automatically exported
918      * to the environment (as per POSIX standard)
919      */
920     if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
921 	if (v == NULL) {
922 	    /* we just added it */
923 	    v = VarFind(name, ctxt, 0);
924 	}
925 	if (v != NULL)
926 	    v->flags |= VAR_FROM_CMD;
927 	/*
928 	 * If requested, don't export these in the environment
929 	 * individually.  We still put them in MAKEOVERRIDES so
930 	 * that the command-line settings continue to override
931 	 * Makefile settings.
932 	 */
933 	if (varNoExportEnv != TRUE)
934 	    setenv(name, val ? val : "", 1);
935 
936 	Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
937     }
938     if (*name == '.') {
939 	if (strcmp(name, SAVE_DOLLARS) == 0)
940 	    save_dollars = s2Boolean(val, save_dollars);
941     }
942 
943 out:
944     free(expanded_name);
945     if (v != NULL)
946 	VarFreeEnv(v, TRUE);
947 }
948 
949 /*-
950  *-----------------------------------------------------------------------
951  * Var_Set --
952  *	Set the variable name to the value val in the given context.
953  *
954  * Input:
955  *	name		name of variable to set
956  *	val		value to give to the variable
957  *	ctxt		context in which to set it
958  *
959  * Side Effects:
960  *	If the variable doesn't yet exist, a new record is created for it.
961  *	Else the old value is freed and the new one stuck in its place
962  *
963  * Notes:
964  *	The variable is searched for only in its context before being
965  *	created in that context. I.e. if the context is VAR_GLOBAL,
966  *	only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
967  *	VAR_CMD->context is searched. This is done to avoid the literally
968  *	thousands of unnecessary strcmp's that used to be done to
969  *	set, say, $(@) or $(<).
970  *	If the context is VAR_GLOBAL though, we check if the variable
971  *	was set in VAR_CMD from the command line and skip it if so.
972  *-----------------------------------------------------------------------
973  */
974 void
975 Var_Set(const char *name, const char *val, GNode *ctxt)
976 {
977     Var_Set_with_flags(name, val, ctxt, 0);
978 }
979 
980 /*-
981  *-----------------------------------------------------------------------
982  * Var_Append --
983  *	The variable of the given name has the given value appended to it in
984  *	the given context.
985  *
986  * Input:
987  *	name		name of variable to modify
988  *	val		String to append to it
989  *	ctxt		Context in which this should occur
990  *
991  * Side Effects:
992  *	If the variable doesn't exist, it is created. Else the strings
993  *	are concatenated (with a space in between).
994  *
995  * Notes:
996  *	Only if the variable is being sought in the global context is the
997  *	environment searched.
998  *	XXX: Knows its calling circumstances in that if called with ctxt
999  *	an actual target, it will only search that context since only
1000  *	a local variable could be being appended to. This is actually
1001  *	a big win and must be tolerated.
1002  *-----------------------------------------------------------------------
1003  */
1004 void
1005 Var_Append(const char *name, const char *val, GNode *ctxt)
1006 {
1007     Var *v;
1008     Hash_Entry *h;
1009     char *expanded_name = NULL;
1010 
1011     if (strchr(name, '$') != NULL) {
1012 	expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1013 	if (expanded_name[0] == 0) {
1014 	    if (DEBUG(VAR)) {
1015 		fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
1016 			"name expands to empty string - ignored\n",
1017 			name, val);
1018 	    }
1019 	    free(expanded_name);
1020 	    return;
1021 	}
1022 	name = expanded_name;
1023     }
1024 
1025     v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD|FIND_ENV) : 0);
1026 
1027     if (v == NULL) {
1028 	Var_Set(name, val, ctxt);
1029     } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
1030 	Buf_AddByte(&v->val, ' ');
1031 	Buf_AddBytes(&v->val, strlen(val), val);
1032 
1033 	if (DEBUG(VAR)) {
1034 	    fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
1035 		    Buf_GetAll(&v->val, NULL));
1036 	}
1037 
1038 	if (v->flags & VAR_FROM_ENV) {
1039 	    /*
1040 	     * If the original variable came from the environment, we
1041 	     * have to install it in the global context (we could place
1042 	     * it in the environment, but then we should provide a way to
1043 	     * export other variables...)
1044 	     */
1045 	    v->flags &= ~VAR_FROM_ENV;
1046 	    h = Hash_CreateEntry(&ctxt->context, name, NULL);
1047 	    Hash_SetValue(h, v);
1048 	}
1049     }
1050     free(expanded_name);
1051 }
1052 
1053 /*-
1054  *-----------------------------------------------------------------------
1055  * Var_Exists --
1056  *	See if the given variable exists.
1057  *
1058  * Input:
1059  *	name		Variable to find
1060  *	ctxt		Context in which to start search
1061  *
1062  * Results:
1063  *	TRUE if it does, FALSE if it doesn't
1064  *
1065  * Side Effects:
1066  *	None.
1067  *
1068  *-----------------------------------------------------------------------
1069  */
1070 Boolean
1071 Var_Exists(const char *name, GNode *ctxt)
1072 {
1073     Var		  *v;
1074     char          *cp;
1075 
1076     if ((cp = strchr(name, '$')) != NULL) {
1077 	cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1078     }
1079     v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
1080     free(cp);
1081     if (v == NULL) {
1082 	return FALSE;
1083     }
1084 
1085     (void)VarFreeEnv(v, TRUE);
1086     return TRUE;
1087 }
1088 
1089 /*-
1090  *-----------------------------------------------------------------------
1091  * Var_Value --
1092  *	Return the value of the named variable in the given context
1093  *
1094  * Input:
1095  *	name		name to find
1096  *	ctxt		context in which to search for it
1097  *
1098  * Results:
1099  *	The value if the variable exists, NULL if it doesn't
1100  *
1101  * Side Effects:
1102  *	None
1103  *-----------------------------------------------------------------------
1104  */
1105 char *
1106 Var_Value(const char *name, GNode *ctxt, char **frp)
1107 {
1108     Var *v;
1109 
1110     v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1111     *frp = NULL;
1112     if (v == NULL)
1113 	return NULL;
1114 
1115     char *p = (Buf_GetAll(&v->val, NULL));
1116     if (VarFreeEnv(v, FALSE))
1117 	*frp = p;
1118     return p;
1119 }
1120 
1121 
1122 /* This callback for VarModify gets a single word from an expression and
1123  * typically adds a modification of this word to the buffer. It may also do
1124  * nothing or add several words.
1125  *
1126  * If addSpaces is TRUE, it must add a space before adding anything else to
1127  * the buffer.
1128  *
1129  * It returns the addSpace value for the next call of this callback. Typical
1130  * return values are the current addSpaces or TRUE. */
1131 typedef Boolean (*VarModifyCallback)(GNode *ctxt, Var_Parse_State *vpstate,
1132     const char *word, Boolean addSpace, Buffer *buf, void *data);
1133 
1134 
1135 /* Callback function for VarModify to implement the :H modifier.
1136  * Add the dirname of the given word to the buffer. */
1137 static Boolean
1138 VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1139 	const char *word, Boolean addSpace, Buffer *buf,
1140 	void *dummy MAKE_ATTR_UNUSED)
1141 {
1142     const char *slash = strrchr(word, '/');
1143 
1144     if (addSpace && vpstate->varSpace)
1145 	Buf_AddByte(buf, vpstate->varSpace);
1146     if (slash != NULL)
1147 	Buf_AddBytes(buf, slash - word, word);
1148     else
1149 	Buf_AddByte(buf, '.');
1150 
1151     return TRUE;
1152 }
1153 
1154 /* Callback function for VarModify to implement the :T modifier.
1155  * Add the basename of the given word to the buffer. */
1156 static Boolean
1157 VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1158 	const char *word, Boolean addSpace, Buffer *buf,
1159 	void *dummy MAKE_ATTR_UNUSED)
1160 {
1161     const char *slash = strrchr(word, '/');
1162     const char *base = slash != NULL ? slash + 1 : word;
1163 
1164     if (addSpace && vpstate->varSpace)
1165 	Buf_AddByte(buf, vpstate->varSpace);
1166     Buf_AddBytes(buf, strlen(base), base);
1167     return TRUE;
1168 }
1169 
1170 /* Callback function for VarModify to implement the :E modifier.
1171  * Add the filename suffix of the given word to the buffer, if it exists. */
1172 static Boolean
1173 VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1174 	  const char *word, Boolean addSpace, Buffer *buf,
1175 	  void *dummy MAKE_ATTR_UNUSED)
1176 {
1177     const char *dot = strrchr(word, '.');
1178     if (dot == NULL)
1179 	return addSpace;
1180 
1181     if (addSpace && vpstate->varSpace)
1182 	Buf_AddByte(buf, vpstate->varSpace);
1183     Buf_AddBytes(buf, strlen(dot + 1), dot + 1);
1184     return TRUE;
1185 }
1186 
1187 /* Callback function for VarModify to implement the :R modifier.
1188  * Add the filename basename of the given word to the buffer. */
1189 static Boolean
1190 VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1191 	const char *word, Boolean addSpace, Buffer *buf,
1192 	void *dummy MAKE_ATTR_UNUSED)
1193 {
1194     char *dot = strrchr(word, '.');
1195     size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1196 
1197     if (addSpace && vpstate->varSpace)
1198 	Buf_AddByte(buf, vpstate->varSpace);
1199     Buf_AddBytes(buf, len, word);
1200     return TRUE;
1201 }
1202 
1203 /* Callback function for VarModify to implement the :M modifier.
1204  * Place the word in the buffer if it matches the given pattern. */
1205 static Boolean
1206 VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1207 	 const char *word, Boolean addSpace, Buffer *buf,
1208 	 void *data)
1209 {
1210     const char *pattern = data;
1211     if (DEBUG(VAR))
1212 	fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
1213     if (!Str_Match(word, pattern))
1214 	return addSpace;
1215     if (addSpace && vpstate->varSpace)
1216 	Buf_AddByte(buf, vpstate->varSpace);
1217     Buf_AddBytes(buf, strlen(word), word);
1218     return TRUE;
1219 }
1220 
1221 #ifdef SYSVVARSUB
1222 /* Callback function for VarModify to implement the :%.from=%.to modifier. */
1223 static Boolean
1224 VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
1225 	     const char *word, Boolean addSpace, Buffer *buf,
1226 	     void *data)
1227 {
1228     size_t len;
1229     char *ptr;
1230     Boolean hasPercent;
1231     VarPattern *pat = data;
1232 
1233     if (addSpace && vpstate->varSpace)
1234 	Buf_AddByte(buf, vpstate->varSpace);
1235 
1236     if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
1237 	char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
1238 	Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1239 	free(varexp);
1240     } else {
1241 	Buf_AddBytes(buf, strlen(word), word);
1242     }
1243 
1244     return TRUE;
1245 }
1246 #endif
1247 
1248 /* Callback function for VarModify to implement the :N modifier.
1249  * Place the word in the buffer if it doesn't match the given pattern. */
1250 static Boolean
1251 VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1252 	   const char *word, Boolean addSpace, Buffer *buf,
1253 	   void *data)
1254 {
1255     const char *pattern = data;
1256     if (Str_Match(word, pattern))
1257 	return addSpace;
1258     if (addSpace && vpstate->varSpace)
1259 	Buf_AddByte(buf, vpstate->varSpace);
1260     Buf_AddBytes(buf, strlen(word), word);
1261     return TRUE;
1262 }
1263 
1264 /* Callback function for VarModify to implement the :S,from,to, modifier.
1265  * Perform a string substitution on the given word. */
1266 static Boolean
1267 VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1268 	      const char *word, Boolean addSpace, Buffer *buf,
1269 	      void *data)
1270 {
1271     int wordLen = strlen(word);
1272     const char *cp;		/* General pointer */
1273     VarPattern *pattern = data;
1274 
1275     if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
1276 	(VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1277 	/*
1278 	 * Still substituting -- break it down into simple anchored cases
1279 	 * and if none of them fits, perform the general substitution case.
1280 	 */
1281 	if ((pattern->flags & VAR_MATCH_START) &&
1282 	    (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1283 	    /*
1284 	     * Anchored at start and beginning of word matches pattern
1285 	     */
1286 	    if ((pattern->flags & VAR_MATCH_END) &&
1287 	        (wordLen == pattern->leftLen)) {
1288 		/*
1289 		 * Also anchored at end and matches to the end (word
1290 		 * is same length as pattern) add space and rhs only
1291 		 * if rhs is non-null.
1292 		 */
1293 		if (pattern->rightLen != 0) {
1294 		    if (addSpace && vpstate->varSpace) {
1295 			Buf_AddByte(buf, vpstate->varSpace);
1296 		    }
1297 		    addSpace = TRUE;
1298 		    Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1299 		}
1300 		pattern->flags |= VAR_SUB_MATCHED;
1301 	    } else if (pattern->flags & VAR_MATCH_END) {
1302 		/*
1303 		 * Doesn't match to end -- copy word wholesale
1304 		 */
1305 		goto nosub;
1306 	    } else {
1307 		/*
1308 		 * Matches at start but need to copy in trailing characters
1309 		 */
1310 		if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) {
1311 		    if (addSpace && vpstate->varSpace) {
1312 			Buf_AddByte(buf, vpstate->varSpace);
1313 		    }
1314 		    addSpace = TRUE;
1315 		}
1316 		Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1317 		Buf_AddBytes(buf, wordLen - pattern->leftLen,
1318 			     (word + pattern->leftLen));
1319 		pattern->flags |= VAR_SUB_MATCHED;
1320 	    }
1321 	} else if (pattern->flags & VAR_MATCH_START) {
1322 	    /*
1323 	     * Had to match at start of word and didn't -- copy whole word.
1324 	     */
1325 	    goto nosub;
1326 	} else if (pattern->flags & VAR_MATCH_END) {
1327 	    /*
1328 	     * Anchored at end, Find only place match could occur (leftLen
1329 	     * characters from the end of the word) and see if it does. Note
1330 	     * that because the $ will be left at the end of the lhs, we have
1331 	     * to use strncmp.
1332 	     */
1333 	    cp = word + (wordLen - pattern->leftLen);
1334 	    if ((cp >= word) &&
1335 		(strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1336 		/*
1337 		 * Match found. If we will place characters in the buffer,
1338 		 * add a space before hand as indicated by addSpace, then
1339 		 * stuff in the initial, unmatched part of the word followed
1340 		 * by the right-hand-side.
1341 		 */
1342 		if (((cp - word) + pattern->rightLen) != 0) {
1343 		    if (addSpace && vpstate->varSpace) {
1344 			Buf_AddByte(buf, vpstate->varSpace);
1345 		    }
1346 		    addSpace = TRUE;
1347 		}
1348 		Buf_AddBytes(buf, cp - word, word);
1349 		Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1350 		pattern->flags |= VAR_SUB_MATCHED;
1351 	    } else {
1352 		/*
1353 		 * Had to match at end and didn't. Copy entire word.
1354 		 */
1355 		goto nosub;
1356 	    }
1357 	} else {
1358 	    /*
1359 	     * Pattern is unanchored: search for the pattern in the word using
1360 	     * String_FindSubstring, copying unmatched portions and the
1361 	     * right-hand-side for each match found, handling non-global
1362 	     * substitutions correctly, etc. When the loop is done, any
1363 	     * remaining part of the word (word and wordLen are adjusted
1364 	     * accordingly through the loop) is copied straight into the
1365 	     * buffer.
1366 	     * addSpace is set FALSE as soon as a space is added to the
1367 	     * buffer.
1368 	     */
1369 	    Boolean done;
1370 	    int origSize;
1371 
1372 	    done = FALSE;
1373 	    origSize = Buf_Size(buf);
1374 	    while (!done) {
1375 		cp = Str_FindSubstring(word, pattern->lhs);
1376 		if (cp != NULL) {
1377 		    if (addSpace && (((cp - word) + pattern->rightLen) != 0)) {
1378 			Buf_AddByte(buf, vpstate->varSpace);
1379 			addSpace = FALSE;
1380 		    }
1381 		    Buf_AddBytes(buf, cp - word, word);
1382 		    Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1383 		    wordLen -= (cp - word) + pattern->leftLen;
1384 		    word = cp + pattern->leftLen;
1385 		    if (wordLen == 0) {
1386 			done = TRUE;
1387 		    }
1388 		    if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
1389 			done = TRUE;
1390 		    }
1391 		    pattern->flags |= VAR_SUB_MATCHED;
1392 		} else {
1393 		    done = TRUE;
1394 		}
1395 	    }
1396 	    if (wordLen != 0) {
1397 		if (addSpace && vpstate->varSpace) {
1398 		    Buf_AddByte(buf, vpstate->varSpace);
1399 		}
1400 		Buf_AddBytes(buf, wordLen, word);
1401 	    }
1402 	    /*
1403 	     * If added characters to the buffer, need to add a space
1404 	     * before we add any more. If we didn't add any, just return
1405 	     * the previous value of addSpace.
1406 	     */
1407 	    return (Buf_Size(buf) != origSize) || addSpace;
1408 	}
1409 	return addSpace;
1410     }
1411 nosub:
1412     if (addSpace && vpstate->varSpace) {
1413 	Buf_AddByte(buf, vpstate->varSpace);
1414     }
1415     Buf_AddBytes(buf, wordLen, word);
1416     return TRUE;
1417 }
1418 
1419 #ifndef NO_REGEX
1420 /*-
1421  *-----------------------------------------------------------------------
1422  * VarREError --
1423  *	Print the error caused by a regcomp or regexec call.
1424  *
1425  * Side Effects:
1426  *	An error gets printed.
1427  *
1428  *-----------------------------------------------------------------------
1429  */
1430 static void
1431 VarREError(int reerr, regex_t *pat, const char *str)
1432 {
1433     char *errbuf;
1434     int errlen;
1435 
1436     errlen = regerror(reerr, pat, 0, 0);
1437     errbuf = bmake_malloc(errlen);
1438     regerror(reerr, pat, errbuf, errlen);
1439     Error("%s: %s", str, errbuf);
1440     free(errbuf);
1441 }
1442 
1443 /* Callback function for VarModify to implement the :C/from/to/ modifier.
1444  * Perform a regex substitution on the given word. */
1445 static Boolean
1446 VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
1447 		Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1448 		const char *word, Boolean addSpace, Buffer *buf,
1449 		void *data)
1450 {
1451     VarREPattern *pat = data;
1452     int xrv;
1453     const char *wp = word;
1454     char *rp;
1455     int added = 0;
1456     int flags = 0;
1457 
1458 #define MAYBE_ADD_SPACE()		\
1459 	if (addSpace && !added)		\
1460 	    Buf_AddByte(buf, ' ');	\
1461 	added = 1
1462 
1463     if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1464 	(VAR_SUB_ONE|VAR_SUB_MATCHED))
1465 	xrv = REG_NOMATCH;
1466     else {
1467     tryagain:
1468 	xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1469     }
1470 
1471     switch (xrv) {
1472     case 0:
1473 	pat->flags |= VAR_SUB_MATCHED;
1474 	if (pat->matches[0].rm_so > 0) {
1475 	    MAYBE_ADD_SPACE();
1476 	    Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1477 	}
1478 
1479 	for (rp = pat->replace; *rp; rp++) {
1480 	    if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1481 		MAYBE_ADD_SPACE();
1482 		Buf_AddByte(buf, rp[1]);
1483 		rp++;
1484 	    } else if ((*rp == '&') ||
1485 		((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
1486 		int n;
1487 		const char *subbuf;
1488 		int sublen;
1489 		char errstr[3];
1490 
1491 		if (*rp == '&') {
1492 		    n = 0;
1493 		    errstr[0] = '&';
1494 		    errstr[1] = '\0';
1495 		} else {
1496 		    n = rp[1] - '0';
1497 		    errstr[0] = '\\';
1498 		    errstr[1] = rp[1];
1499 		    errstr[2] = '\0';
1500 		    rp++;
1501 		}
1502 
1503 		if (n > pat->nsub) {
1504 		    Error("No subexpression %s", &errstr[0]);
1505 		    subbuf = "";
1506 		    sublen = 0;
1507 		} else if ((pat->matches[n].rm_so == -1) &&
1508 			   (pat->matches[n].rm_eo == -1)) {
1509 		    Error("No match for subexpression %s", &errstr[0]);
1510 		    subbuf = "";
1511 		    sublen = 0;
1512 		} else {
1513 		    subbuf = wp + pat->matches[n].rm_so;
1514 		    sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1515 		}
1516 
1517 		if (sublen > 0) {
1518 		    MAYBE_ADD_SPACE();
1519 		    Buf_AddBytes(buf, sublen, subbuf);
1520 		}
1521 	    } else {
1522 		MAYBE_ADD_SPACE();
1523 		Buf_AddByte(buf, *rp);
1524 	    }
1525 	}
1526 	wp += pat->matches[0].rm_eo;
1527 	if (pat->flags & VAR_SUB_GLOBAL) {
1528 	    flags |= REG_NOTBOL;
1529 	    if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1530 		MAYBE_ADD_SPACE();
1531 		Buf_AddByte(buf, *wp);
1532 		wp++;
1533 
1534 	    }
1535 	    if (*wp)
1536 		goto tryagain;
1537 	}
1538 	if (*wp) {
1539 	    MAYBE_ADD_SPACE();
1540 	    Buf_AddBytes(buf, strlen(wp), wp);
1541 	}
1542 	break;
1543     default:
1544 	VarREError(xrv, &pat->re, "Unexpected regex error");
1545 	/* fall through */
1546     case REG_NOMATCH:
1547 	if (*wp) {
1548 	    MAYBE_ADD_SPACE();
1549 	    Buf_AddBytes(buf, strlen(wp), wp);
1550 	}
1551 	break;
1552     }
1553     return addSpace || added;
1554 }
1555 #endif
1556 
1557 
1558 /* Callback function for VarModify to implement the :@var@...@ modifier of
1559  * ODE make. We set the temp variable named in pattern.lhs to word and
1560  * expand pattern.rhs. */
1561 static Boolean
1562 VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
1563 	      Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1564 	      const char *word, Boolean addSpace, Buffer *buf,
1565 	      void *data)
1566 {
1567     VarLoop *loop = data;
1568     char *s;
1569     int slen;
1570 
1571     if (*word) {
1572 	Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
1573 	s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags);
1574 	if (DEBUG(VAR)) {
1575 	    fprintf(debug_file,
1576 		    "VarLoopExpand: in \"%s\", replace \"%s\" with \"%s\" "
1577 		    "to \"%s\"\n",
1578 		    word, loop->tvar, loop->str, s ? s : "(null)");
1579 	}
1580 	if (s != NULL && *s != '\0') {
1581 	    if (addSpace && *s != '\n')
1582 		Buf_AddByte(buf, ' ');
1583 	    Buf_AddBytes(buf, (slen = strlen(s)), s);
1584 	    addSpace = (slen > 0 && s[slen - 1] != '\n');
1585 	}
1586 	free(s);
1587     }
1588     return addSpace;
1589 }
1590 
1591 
1592 /*-
1593  *-----------------------------------------------------------------------
1594  * VarSelectWords --
1595  *	Implements the :[start..end] modifier.
1596  *	This is a special case of VarModify since we want to be able
1597  *	to scan the list backwards if start > end.
1598  *
1599  * Input:
1600  *	str		String whose words should be trimmed
1601  *	seldata		words to select
1602  *
1603  * Results:
1604  *	A string of all the words selected.
1605  *
1606  * Side Effects:
1607  *	None.
1608  *
1609  *-----------------------------------------------------------------------
1610  */
1611 static char *
1612 VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1613 	       const char *str, VarSelectWords_t *seldata)
1614 {
1615     Buffer buf;			/* Buffer for the new string */
1616     Boolean addSpace;		/* TRUE if need to add a space to the
1617 				 * buffer before adding the trimmed
1618 				 * word */
1619     char **av;			/* word list */
1620     char *as;			/* word list memory */
1621     int ac, i;
1622     int start, end, step;
1623 
1624     Buf_Init(&buf, 0);
1625     addSpace = FALSE;
1626 
1627     if (vpstate->oneBigWord) {
1628 	/* fake what brk_string() would do if there were only one word */
1629 	ac = 1;
1630 	av = bmake_malloc((ac + 1) * sizeof(char *));
1631 	as = bmake_strdup(str);
1632 	av[0] = as;
1633 	av[1] = NULL;
1634     } else {
1635 	av = brk_string(str, &ac, FALSE, &as);
1636     }
1637 
1638     /*
1639      * Now sanitize seldata.
1640      * If seldata->start or seldata->end are negative, convert them to
1641      * the positive equivalents (-1 gets converted to argc, -2 gets
1642      * converted to (argc-1), etc.).
1643      */
1644     if (seldata->start < 0)
1645 	seldata->start = ac + seldata->start + 1;
1646     if (seldata->end < 0)
1647 	seldata->end = ac + seldata->end + 1;
1648 
1649     /*
1650      * We avoid scanning more of the list than we need to.
1651      */
1652     if (seldata->start > seldata->end) {
1653 	start = MIN(ac, seldata->start) - 1;
1654 	end = MAX(0, seldata->end - 1);
1655 	step = -1;
1656     } else {
1657 	start = MAX(0, seldata->start - 1);
1658 	end = MIN(ac, seldata->end);
1659 	step = 1;
1660     }
1661 
1662     for (i = start;
1663 	 (step < 0 && i >= end) || (step > 0 && i < end);
1664 	 i += step) {
1665 	if (av[i] && *av[i]) {
1666 	    if (addSpace && vpstate->varSpace) {
1667 		Buf_AddByte(&buf, vpstate->varSpace);
1668 	    }
1669 	    Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1670 	    addSpace = TRUE;
1671 	}
1672     }
1673 
1674     free(as);
1675     free(av);
1676 
1677     return Buf_Destroy(&buf, FALSE);
1678 }
1679 
1680 
1681 /* Callback function for VarModify to implement the :tA modifier.
1682  * Replace each word with the result of realpath() if successful. */
1683 static Boolean
1684 VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1685 	    const char *word, Boolean addSpace, Buffer *buf,
1686 	    void *patternp MAKE_ATTR_UNUSED)
1687 {
1688     struct stat st;
1689     char rbuf[MAXPATHLEN];
1690     char *rp;
1691 
1692     if (addSpace && vpstate->varSpace)
1693 	Buf_AddByte(buf, vpstate->varSpace);
1694     rp = cached_realpath(word, rbuf);
1695     if (rp && *rp == '/' && stat(rp, &st) == 0)
1696 	word = rp;
1697 
1698     Buf_AddBytes(buf, strlen(word), word);
1699     return TRUE;
1700 }
1701 
1702 /*-
1703  *-----------------------------------------------------------------------
1704  * Modify each of the words of the passed string using the given function.
1705  *
1706  * Input:
1707  *	str		String whose words should be trimmed
1708  *	modProc		Function to use to modify them
1709  *	data		Custom data for the modProc
1710  *
1711  * Results:
1712  *	A string of all the words modified appropriately.
1713  *
1714  * Side Effects:
1715  *	None.
1716  *
1717  *-----------------------------------------------------------------------
1718  */
1719 static char *
1720 VarModify(GNode *ctx, Var_Parse_State *vpstate,
1721     const char *str, VarModifyCallback modProc, void *datum)
1722 {
1723     Buffer buf;			/* Buffer for the new string */
1724     Boolean addSpace; 		/* TRUE if need to add a space to the
1725 				 * buffer before adding the trimmed word */
1726     char **av;			/* word list */
1727     char *as;			/* word list memory */
1728     int ac, i;
1729 
1730     Buf_Init(&buf, 0);
1731     addSpace = FALSE;
1732 
1733     if (vpstate->oneBigWord) {
1734 	/* fake what brk_string() would do if there were only one word */
1735 	ac = 1;
1736 	av = bmake_malloc((ac + 1) * sizeof(char *));
1737 	as = bmake_strdup(str);
1738 	av[0] = as;
1739 	av[1] = NULL;
1740     } else {
1741 	av = brk_string(str, &ac, FALSE, &as);
1742     }
1743 
1744     if (DEBUG(VAR)) {
1745 	fprintf(debug_file, "VarModify: split \"%s\" into %d words\n",
1746 		str, ac);
1747     }
1748 
1749     for (i = 0; i < ac; i++)
1750 	addSpace = modProc(ctx, vpstate, av[i], addSpace, &buf, datum);
1751 
1752     free(as);
1753     free(av);
1754 
1755     return Buf_Destroy(&buf, FALSE);
1756 }
1757 
1758 
1759 static int
1760 VarWordCompare(const void *a, const void *b)
1761 {
1762     int r = strcmp(*(const char * const *)a, *(const char * const *)b);
1763     return r;
1764 }
1765 
1766 static int
1767 VarWordCompareReverse(const void *a, const void *b)
1768 {
1769     int r = strcmp(*(const char * const *)b, *(const char * const *)a);
1770     return r;
1771 }
1772 
1773 /*-
1774  *-----------------------------------------------------------------------
1775  * VarOrder --
1776  *	Order the words in the string.
1777  *
1778  * Input:
1779  *	str		String whose words should be sorted.
1780  *	otype		How to order: s - sort, x - random.
1781  *
1782  * Results:
1783  *	A string containing the words ordered.
1784  *
1785  * Side Effects:
1786  *	None.
1787  *
1788  *-----------------------------------------------------------------------
1789  */
1790 static char *
1791 VarOrder(const char *str, const char otype)
1792 {
1793     Buffer buf;			/* Buffer for the new string */
1794     char **av;			/* word list [first word does not count] */
1795     char *as;			/* word list memory */
1796     int ac, i;
1797 
1798     Buf_Init(&buf, 0);
1799 
1800     av = brk_string(str, &ac, FALSE, &as);
1801 
1802     if (ac > 0) {
1803 	switch (otype) {
1804 	case 'r':		/* reverse sort alphabetically */
1805 	    qsort(av, ac, sizeof(char *), VarWordCompareReverse);
1806 	    break;
1807 	case 's':		/* sort alphabetically */
1808 	    qsort(av, ac, sizeof(char *), VarWordCompare);
1809 	    break;
1810 	case 'x':		/* randomize */
1811 	    {
1812 		/*
1813 		 * We will use [ac..2] range for mod factors. This will produce
1814 		 * random numbers in [(ac-1)..0] interval, and minimal
1815 		 * reasonable value for mod factor is 2 (the mod 1 will produce
1816 		 * 0 with probability 1).
1817 		 */
1818 		for (i = ac - 1; i > 0; i--) {
1819 		    int rndidx = random() % (i + 1);
1820 		    char *t = av[i];
1821 		    av[i] = av[rndidx];
1822 		    av[rndidx] = t;
1823 		}
1824 	    }
1825 	}
1826     }
1827 
1828     for (i = 0; i < ac; i++) {
1829 	Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1830 	if (i != ac - 1)
1831 	    Buf_AddByte(&buf, ' ');
1832     }
1833 
1834     free(as);
1835     free(av);
1836 
1837     return Buf_Destroy(&buf, FALSE);
1838 }
1839 
1840 
1841 /*-
1842  *-----------------------------------------------------------------------
1843  * VarUniq --
1844  *	Remove adjacent duplicate words.
1845  *
1846  * Input:
1847  *	str		String whose words should be sorted
1848  *
1849  * Results:
1850  *	A string containing the resulting words.
1851  *
1852  * Side Effects:
1853  *	None.
1854  *
1855  *-----------------------------------------------------------------------
1856  */
1857 static char *
1858 VarUniq(const char *str)
1859 {
1860     Buffer	  buf;		/* Buffer for new string */
1861     char 	**av;		/* List of words to affect */
1862     char 	 *as;		/* Word list memory */
1863     int 	  ac, i, j;
1864 
1865     Buf_Init(&buf, 0);
1866     av = brk_string(str, &ac, FALSE, &as);
1867 
1868     if (ac > 1) {
1869 	for (j = 0, i = 1; i < ac; i++)
1870 	    if (strcmp(av[i], av[j]) != 0 && (++j != i))
1871 		av[j] = av[i];
1872 	ac = j + 1;
1873     }
1874 
1875     for (i = 0; i < ac; i++) {
1876 	Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1877 	if (i != ac - 1)
1878 	    Buf_AddByte(&buf, ' ');
1879     }
1880 
1881     free(as);
1882     free(av);
1883 
1884     return Buf_Destroy(&buf, FALSE);
1885 }
1886 
1887 /*-
1888  *-----------------------------------------------------------------------
1889  * VarRange --
1890  *	Return an integer sequence
1891  *
1892  * Input:
1893  *	str		String whose words provide default range
1894  *	ac		range length, if 0 use str words
1895  *
1896  * Side Effects:
1897  *	None.
1898  *
1899  *-----------------------------------------------------------------------
1900  */
1901 static char *
1902 VarRange(const char *str, int ac)
1903 {
1904     Buffer	  buf;		/* Buffer for new string */
1905     char	  tmp[32];	/* each element */
1906     char 	**av;		/* List of words to affect */
1907     char 	 *as;		/* Word list memory */
1908     int 	  i, n;
1909 
1910     Buf_Init(&buf, 0);
1911     if (ac > 0) {
1912 	as = NULL;
1913 	av = NULL;
1914     } else {
1915 	av = brk_string(str, &ac, FALSE, &as);
1916     }
1917     for (i = 0; i < ac; i++) {
1918 	n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
1919 	if (n >= (int)sizeof(tmp))
1920 	    break;
1921 	Buf_AddBytes(&buf, n, tmp);
1922 	if (i != ac - 1)
1923 	    Buf_AddByte(&buf, ' ');
1924     }
1925 
1926     free(as);
1927     free(av);
1928 
1929     return Buf_Destroy(&buf, FALSE);
1930 }
1931 
1932 
1933 /*-
1934  *-----------------------------------------------------------------------
1935  * VarGetPattern --
1936  *	During the parsing of a part of a modifier such as :S or :@,
1937  *	pass through the tstr looking for 1) escaped delimiters,
1938  *	'$'s and backslashes (place the escaped character in
1939  *	uninterpreted) and 2) unescaped $'s that aren't before
1940  *	the delimiter (expand the variable substitution unless flags
1941  *	has VAR_NOSUBST set).
1942  *	Return the expanded string or NULL if the delimiter was missing
1943  *	If pattern is specified, handle escaped ampersands, and replace
1944  *	unescaped ampersands with the lhs of the pattern.
1945  *
1946  * Results:
1947  *	A string of all the words modified appropriately.
1948  *	If length is specified, return the string length of the buffer
1949  *	If flags is specified and the last character of the pattern is a
1950  *	$ set the VAR_MATCH_END bit of flags.
1951  *
1952  * Side Effects:
1953  *	None.
1954  *-----------------------------------------------------------------------
1955  */
1956 static char *
1957 VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1958 	      VarPattern_Flags flags, const char **tstr, int delim,
1959 	      VarPattern_Flags *vflags, int *length, VarPattern *pattern)
1960 {
1961     const char *cp;
1962     char *rstr;
1963     Buffer buf;
1964     int junk;
1965     int errnum = flags & VARF_UNDEFERR;
1966 
1967     Buf_Init(&buf, 0);
1968     if (length == NULL)
1969 	length = &junk;
1970 
1971 #define IS_A_MATCH(cp, delim) \
1972     ((cp[0] == '\\') && ((cp[1] == delim) ||  \
1973      (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
1974 
1975     /*
1976      * Skim through until the matching delimiter is found;
1977      * pick up variable substitutions on the way. Also allow
1978      * backslashes to quote the delimiter, $, and \, but don't
1979      * touch other backslashes.
1980      */
1981     for (cp = *tstr; *cp && (*cp != delim); cp++) {
1982 	if (IS_A_MATCH(cp, delim)) {
1983 	    Buf_AddByte(&buf, cp[1]);
1984 	    cp++;
1985 	} else if (*cp == '$') {
1986 	    if (cp[1] == delim) {
1987 		if (vflags == NULL)
1988 		    Buf_AddByte(&buf, *cp);
1989 		else
1990 		    /*
1991 		     * Unescaped $ at end of pattern => anchor
1992 		     * pattern at end.
1993 		     */
1994 		    *vflags |= VAR_MATCH_END;
1995 	    } else {
1996 		if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) {
1997 		    char   *cp2;
1998 		    int     len;
1999 		    void   *freeIt;
2000 
2001 		    /*
2002 		     * If unescaped dollar sign not before the
2003 		     * delimiter, assume it's a variable
2004 		     * substitution and recurse.
2005 		     */
2006 		    cp2 = Var_Parse(cp, ctxt, errnum | (flags & VARF_WANTRES),
2007 				    &len, &freeIt);
2008 		    Buf_AddBytes(&buf, strlen(cp2), cp2);
2009 		    free(freeIt);
2010 		    cp += len - 1;
2011 		} else {
2012 		    const char *cp2 = &cp[1];
2013 
2014 		    if (*cp2 == PROPEN || *cp2 == BROPEN) {
2015 			/*
2016 			 * Find the end of this variable reference
2017 			 * and suck it in without further ado.
2018 			 * It will be interpreted later.
2019 			 */
2020 			int have = *cp2;
2021 			int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
2022 			int depth = 1;
2023 
2024 			for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
2025 			    if (cp2[-1] != '\\') {
2026 				if (*cp2 == have)
2027 				    ++depth;
2028 				if (*cp2 == want)
2029 				    --depth;
2030 			    }
2031 			}
2032 			Buf_AddBytes(&buf, cp2 - cp, cp);
2033 			cp = --cp2;
2034 		    } else
2035 			Buf_AddByte(&buf, *cp);
2036 		}
2037 	    }
2038 	} else if (pattern && *cp == '&')
2039 	    Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs);
2040 	else
2041 	    Buf_AddByte(&buf, *cp);
2042     }
2043 
2044     if (*cp != delim) {
2045 	*tstr = cp;
2046 	*length = 0;
2047 	return NULL;
2048     }
2049 
2050     *tstr = ++cp;
2051     *length = Buf_Size(&buf);
2052     rstr = Buf_Destroy(&buf, FALSE);
2053     if (DEBUG(VAR))
2054 	fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr);
2055     return rstr;
2056 }
2057 
2058 /*-
2059  *-----------------------------------------------------------------------
2060  * VarQuote --
2061  *	Quote shell meta-characters and space characters in the string
2062  *	if quoteDollar is set, also quote and double any '$' characters.
2063  *
2064  * Results:
2065  *	The quoted string
2066  *
2067  * Side Effects:
2068  *	None.
2069  *
2070  *-----------------------------------------------------------------------
2071  */
2072 static char *
2073 VarQuote(char *str, Boolean quoteDollar)
2074 {
2075 
2076     Buffer  	  buf;
2077     const char	*newline;
2078     size_t nlen;
2079 
2080     if ((newline = Shell_GetNewline()) == NULL)
2081 	newline = "\\\n";
2082     nlen = strlen(newline);
2083 
2084     Buf_Init(&buf, 0);
2085 
2086     for (; *str != '\0'; str++) {
2087 	if (*str == '\n') {
2088 	    Buf_AddBytes(&buf, nlen, newline);
2089 	    continue;
2090 	}
2091 	if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
2092 	    Buf_AddByte(&buf, '\\');
2093 	Buf_AddByte(&buf, *str);
2094 	if (quoteDollar && *str == '$')
2095 	    Buf_AddBytes(&buf, 2, "\\$");
2096     }
2097 
2098     str = Buf_Destroy(&buf, FALSE);
2099     if (DEBUG(VAR))
2100 	fprintf(debug_file, "QuoteMeta: [%s]\n", str);
2101     return str;
2102 }
2103 
2104 /*-
2105  *-----------------------------------------------------------------------
2106  * VarHash --
2107  *      Hash the string using the MurmurHash3 algorithm.
2108  *      Output is computed using 32bit Little Endian arithmetic.
2109  *
2110  * Input:
2111  *	str		String to modify
2112  *
2113  * Results:
2114  *      Hash value of str, encoded as 8 hex digits.
2115  *
2116  * Side Effects:
2117  *      None.
2118  *
2119  *-----------------------------------------------------------------------
2120  */
2121 static char *
2122 VarHash(const char *str)
2123 {
2124     static const char    hexdigits[16] = "0123456789abcdef";
2125     Buffer         buf;
2126     size_t         len, len2;
2127     const unsigned char *ustr = (const unsigned char *)str;
2128     uint32_t       h, k, c1, c2;
2129 
2130     h  = 0x971e137bU;
2131     c1 = 0x95543787U;
2132     c2 = 0x2ad7eb25U;
2133     len2 = strlen(str);
2134 
2135     for (len = len2; len; ) {
2136 	k = 0;
2137 	switch (len) {
2138 	default:
2139 	    k = ((uint32_t)ustr[3] << 24) |
2140 		((uint32_t)ustr[2] << 16) |
2141 		((uint32_t)ustr[1] << 8) |
2142 		(uint32_t)ustr[0];
2143 	    len -= 4;
2144 	    ustr += 4;
2145 	    break;
2146 	case 3:
2147 	    k |= (uint32_t)ustr[2] << 16;
2148 	    /* FALLTHROUGH */
2149 	case 2:
2150 	    k |= (uint32_t)ustr[1] << 8;
2151 	    /* FALLTHROUGH */
2152 	case 1:
2153 	    k |= (uint32_t)ustr[0];
2154 	    len = 0;
2155 	}
2156 	c1 = c1 * 5 + 0x7b7d159cU;
2157 	c2 = c2 * 5 + 0x6bce6396U;
2158 	k *= c1;
2159 	k = (k << 11) ^ (k >> 21);
2160 	k *= c2;
2161 	h = (h << 13) ^ (h >> 19);
2162 	h = h * 5 + 0x52dce729U;
2163 	h ^= k;
2164     }
2165     h ^= len2;
2166     h *= 0x85ebca6b;
2167     h ^= h >> 13;
2168     h *= 0xc2b2ae35;
2169     h ^= h >> 16;
2170 
2171     Buf_Init(&buf, 0);
2172     for (len = 0; len < 8; ++len) {
2173 	Buf_AddByte(&buf, hexdigits[h & 15]);
2174 	h >>= 4;
2175     }
2176 
2177     return Buf_Destroy(&buf, FALSE);
2178 }
2179 
2180 static char *
2181 VarStrftime(const char *fmt, int zulu, time_t utc)
2182 {
2183     char buf[BUFSIZ];
2184 
2185     if (!utc)
2186 	time(&utc);
2187     if (!*fmt)
2188 	fmt = "%c";
2189     strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2190 
2191     buf[sizeof(buf) - 1] = '\0';
2192     return bmake_strdup(buf);
2193 }
2194 
2195 typedef struct {
2196     /* const parameters */
2197     int startc;
2198     int endc;
2199     Var *v;
2200     GNode *ctxt;
2201     int flags;
2202     int *lengthPtr;
2203     void **freePtr;
2204 
2205     /* read-write */
2206     char *nstr;
2207     const char *tstr;
2208     const char *start;
2209     const char *cp;		/* Secondary pointer into str (place marker
2210 				 * for tstr) */
2211     char termc;			/* Character which terminated scan */
2212     int cnt;			/* Used to count brace pairs when variable in
2213 				 * in parens or braces */
2214     char delim;
2215     int modifier;		/* that we are processing */
2216     Var_Parse_State parsestate;	/* Flags passed to helper functions */
2217 
2218     /* result */
2219     char *newStr;		/* New value to return */
2220 } ApplyModifiersState;
2221 
2222 /* we now have some modifiers with long names */
2223 #define STRMOD_MATCH(s, want, n) \
2224     (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
2225 #define STRMOD_MATCHX(s, want, n) \
2226     (strncmp(s, want, n) == 0 && \
2227      (s[n] == st->endc || s[n] == ':' || s[n] == '='))
2228 #define CHARMOD_MATCH(c) (c == st->endc || c == ':')
2229 
2230 /* :@var@...${var}...@ */
2231 static Boolean
2232 ApplyModifier_At(ApplyModifiersState *st) {
2233     VarLoop loop;
2234     VarPattern_Flags vflags = VAR_NOSUBST;
2235 
2236     st->cp = ++(st->tstr);
2237     st->delim = '@';
2238     loop.tvar = VarGetPattern(
2239 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2240 	&vflags, &loop.tvarLen, NULL);
2241     if (loop.tvar == NULL)
2242 	return FALSE;
2243 
2244     loop.str = VarGetPattern(
2245 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2246 	&vflags, &loop.strLen, NULL);
2247     if (loop.str == NULL)
2248 	return FALSE;
2249 
2250     st->termc = *st->cp;
2251     st->delim = '\0';
2252 
2253     loop.flags = st->flags & (VARF_UNDEFERR | VARF_WANTRES);
2254     loop.ctxt = st->ctxt;
2255     st->newStr = VarModify(
2256 	st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop);
2257     Var_Delete(loop.tvar, st->ctxt);
2258     free(loop.tvar);
2259     free(loop.str);
2260     return TRUE;
2261 }
2262 
2263 /* :Ddefined or :Uundefined */
2264 static void
2265 ApplyModifier_Defined(ApplyModifiersState *st)
2266 {
2267     Buffer buf;			/* Buffer for patterns */
2268     int nflags;
2269 
2270     if (st->flags & VARF_WANTRES) {
2271 	int wantres;
2272 	if (*st->tstr == 'U')
2273 	    wantres = ((st->v->flags & VAR_JUNK) != 0);
2274 	else
2275 	    wantres = ((st->v->flags & VAR_JUNK) == 0);
2276 	nflags = st->flags & ~VARF_WANTRES;
2277 	if (wantres)
2278 	    nflags |= VARF_WANTRES;
2279     } else
2280 	nflags = st->flags;
2281 
2282     /*
2283      * Pass through tstr looking for 1) escaped delimiters,
2284      * '$'s and backslashes (place the escaped character in
2285      * uninterpreted) and 2) unescaped $'s that aren't before
2286      * the delimiter (expand the variable substitution).
2287      * The result is left in the Buffer buf.
2288      */
2289     Buf_Init(&buf, 0);
2290     for (st->cp = st->tstr + 1;
2291 	 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
2292 	 st->cp++) {
2293 	if (*st->cp == '\\' &&
2294 	    (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
2295 	     st->cp[1] == '\\')) {
2296 	    Buf_AddByte(&buf, st->cp[1]);
2297 	    st->cp++;
2298 	} else if (*st->cp == '$') {
2299 	    /*
2300 	     * If unescaped dollar sign, assume it's a
2301 	     * variable substitution and recurse.
2302 	     */
2303 	    char    *cp2;
2304 	    int	    len;
2305 	    void    *freeIt;
2306 
2307 	    cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt);
2308 	    Buf_AddBytes(&buf, strlen(cp2), cp2);
2309 	    free(freeIt);
2310 	    st->cp += len - 1;
2311 	} else {
2312 	    Buf_AddByte(&buf, *st->cp);
2313 	}
2314     }
2315 
2316     st->termc = *st->cp;
2317 
2318     if ((st->v->flags & VAR_JUNK) != 0)
2319 	st->v->flags |= VAR_KEEP;
2320     if (nflags & VARF_WANTRES) {
2321 	st->newStr = Buf_Destroy(&buf, FALSE);
2322     } else {
2323 	st->newStr = st->nstr;
2324 	Buf_Destroy(&buf, TRUE);
2325     }
2326 }
2327 
2328 /* :gmtime */
2329 static Boolean
2330 ApplyModifier_Gmtime(ApplyModifiersState *st)
2331 {
2332     time_t utc;
2333     char *ep;
2334 
2335     st->cp = st->tstr + 1;	/* make sure it is set */
2336     if (!STRMOD_MATCHX(st->tstr, "gmtime", 6))
2337 	return FALSE;
2338     if (st->tstr[6] == '=') {
2339 	utc = strtoul(&st->tstr[7], &ep, 10);
2340 	st->cp = ep;
2341     } else {
2342 	utc = 0;
2343 	st->cp = st->tstr + 6;
2344     }
2345     st->newStr = VarStrftime(st->nstr, 1, utc);
2346     st->termc = *st->cp;
2347     return TRUE;
2348 }
2349 
2350 /* :localtime */
2351 static Boolean
2352 ApplyModifier_Localtime(ApplyModifiersState *st)
2353 {
2354     time_t utc;
2355     char *ep;
2356 
2357     st->cp = st->tstr + 1;	/* make sure it is set */
2358     if (!STRMOD_MATCHX(st->tstr, "localtime", 9))
2359 	return FALSE;
2360 
2361     if (st->tstr[9] == '=') {
2362 	utc = strtoul(&st->tstr[10], &ep, 10);
2363 	st->cp = ep;
2364     } else {
2365 	utc = 0;
2366 	st->cp = st->tstr + 9;
2367     }
2368     st->newStr = VarStrftime(st->nstr, 0, utc);
2369     st->termc = *st->cp;
2370     return TRUE;
2371 }
2372 
2373 /* :hash */
2374 static Boolean
2375 ApplyModifier_Hash(ApplyModifiersState *st)
2376 {
2377     st->cp = st->tstr + 1;	/* make sure it is set */
2378     if (!STRMOD_MATCH(st->tstr, "hash", 4))
2379 	return FALSE;
2380     st->newStr = VarHash(st->nstr);
2381     st->cp = st->tstr + 4;
2382     st->termc = *st->cp;
2383     return TRUE;
2384 }
2385 
2386 /* :P */
2387 static void
2388 ApplyModifier_Path(ApplyModifiersState *st)
2389 {
2390     GNode *gn;
2391 
2392     if ((st->v->flags & VAR_JUNK) != 0)
2393 	st->v->flags |= VAR_KEEP;
2394     gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2395     if (gn == NULL || gn->type & OP_NOPATH) {
2396 	st->newStr = NULL;
2397     } else if (gn->path) {
2398 	st->newStr = bmake_strdup(gn->path);
2399     } else {
2400 	st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2401     }
2402     if (!st->newStr)
2403 	st->newStr = bmake_strdup(st->v->name);
2404     st->cp = ++st->tstr;
2405     st->termc = *st->tstr;
2406 }
2407 
2408 /* :!cmd! */
2409 static Boolean
2410 ApplyModifier_Exclam(ApplyModifiersState *st)
2411 {
2412     const char *emsg;
2413     VarPattern pattern;
2414 
2415     pattern.flags = 0;
2416 
2417     st->delim = '!';
2418     emsg = NULL;
2419     st->cp = ++st->tstr;
2420     pattern.rhs = VarGetPattern(
2421 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2422 	NULL, &pattern.rightLen, NULL);
2423     if (pattern.rhs == NULL)
2424 	return FALSE;
2425     if (st->flags & VARF_WANTRES)
2426 	st->newStr = Cmd_Exec(pattern.rhs, &emsg);
2427     else
2428 	st->newStr = varNoError;
2429     free(UNCONST(pattern.rhs));
2430     if (emsg)
2431 	Error(emsg, st->nstr);
2432     st->termc = *st->cp;
2433     st->delim = '\0';
2434     if (st->v->flags & VAR_JUNK)
2435 	st->v->flags |= VAR_KEEP;
2436     return TRUE;
2437 }
2438 
2439 /* :range */
2440 static Boolean
2441 ApplyModifier_Range(ApplyModifiersState *st)
2442 {
2443     int n;
2444     char *ep;
2445 
2446     st->cp = st->tstr + 1;	/* make sure it is set */
2447     if (!STRMOD_MATCHX(st->tstr, "range", 5))
2448 	return FALSE;
2449 
2450     if (st->tstr[5] == '=') {
2451 	n = strtoul(&st->tstr[6], &ep, 10);
2452 	st->cp = ep;
2453     } else {
2454 	n = 0;
2455 	st->cp = st->tstr + 5;
2456     }
2457     st->newStr = VarRange(st->nstr, n);
2458     st->termc = *st->cp;
2459     return TRUE;
2460 }
2461 
2462 /* :Mpattern or :Npattern */
2463 static void
2464 ApplyModifier_Match(ApplyModifiersState *st)
2465 {
2466     char    *pattern;
2467     const char *endpat;		/* points just after end of pattern */
2468     char    *cp2;
2469     Boolean copy;		/* pattern should be, or has been, copied */
2470     Boolean needSubst;
2471     int nest;
2472 
2473     copy = FALSE;
2474     needSubst = FALSE;
2475     nest = 1;
2476     /*
2477      * In the loop below, ignore ':' unless we are at
2478      * (or back to) the original brace level.
2479      * XXX This will likely not work right if $() and ${}
2480      * are intermixed.
2481      */
2482     for (st->cp = st->tstr + 1;
2483 	 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2484 	 st->cp++) {
2485 	if (*st->cp == '\\' &&
2486 	    (st->cp[1] == ':' || st->cp[1] == st->endc ||
2487 	     st->cp[1] == st->startc)) {
2488 	    if (!needSubst)
2489 		copy = TRUE;
2490 	    st->cp++;
2491 	    continue;
2492 	}
2493 	if (*st->cp == '$')
2494 	    needSubst = TRUE;
2495 	if (*st->cp == '(' || *st->cp == '{')
2496 	    ++nest;
2497 	if (*st->cp == ')' || *st->cp == '}') {
2498 	    --nest;
2499 	    if (nest == 0)
2500 		break;
2501 	}
2502     }
2503     st->termc = *st->cp;
2504     endpat = st->cp;
2505     if (copy) {
2506 	/*
2507 	 * Need to compress the \:'s out of the pattern, so
2508 	 * allocate enough room to hold the uncompressed
2509 	 * pattern (note that st->cp started at st->tstr+1, so
2510 	 * st->cp - st->tstr takes the null byte into account) and
2511 	 * compress the pattern into the space.
2512 	 */
2513 	pattern = bmake_malloc(st->cp - st->tstr);
2514 	for (cp2 = pattern, st->cp = st->tstr + 1;
2515 	     st->cp < endpat;
2516 	     st->cp++, cp2++) {
2517 	    if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2518 		(st->cp[1] == ':' || st->cp[1] == st->endc))
2519 		st->cp++;
2520 	    *cp2 = *st->cp;
2521 	}
2522 	*cp2 = '\0';
2523 	endpat = cp2;
2524     } else {
2525 	/*
2526 	 * Either Var_Subst or VarModify will need a
2527 	 * nul-terminated string soon, so construct one now.
2528 	 */
2529 	pattern = bmake_strndup(st->tstr+1, endpat - (st->tstr + 1));
2530     }
2531     if (needSubst) {
2532 	/* pattern contains embedded '$', so use Var_Subst to expand it. */
2533 	cp2 = pattern;
2534 	pattern = Var_Subst(NULL, cp2, st->ctxt, st->flags);
2535 	free(cp2);
2536     }
2537     if (DEBUG(VAR))
2538 	fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2539 	    st->v->name, st->nstr, pattern);
2540     if (*st->tstr == 'M') {
2541 	st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarMatch,
2542 			       pattern);
2543     } else {
2544 	st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarNoMatch,
2545 			       pattern);
2546     }
2547     free(pattern);
2548 }
2549 
2550 /* :S,from,to, */
2551 static Boolean
2552 ApplyModifier_Subst(ApplyModifiersState *st)
2553 {
2554     VarPattern 	    pattern;
2555     Var_Parse_State tmpparsestate;
2556 
2557     pattern.flags = 0;
2558     tmpparsestate = st->parsestate;
2559     st->delim = st->tstr[1];
2560     st->tstr += 2;
2561 
2562     /*
2563      * If pattern begins with '^', it is anchored to the
2564      * start of the word -- skip over it and flag pattern.
2565      */
2566     if (*st->tstr == '^') {
2567 	pattern.flags |= VAR_MATCH_START;
2568 	st->tstr += 1;
2569     }
2570 
2571     st->cp = st->tstr;
2572     pattern.lhs = VarGetPattern(
2573 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2574 	&pattern.flags, &pattern.leftLen, NULL);
2575     if (pattern.lhs == NULL)
2576 	return FALSE;
2577 
2578     pattern.rhs = VarGetPattern(
2579 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2580 	NULL, &pattern.rightLen, &pattern);
2581     if (pattern.rhs == NULL)
2582 	return FALSE;
2583 
2584     /*
2585      * Check for global substitution. If 'g' after the final
2586      * delimiter, substitution is global and is marked that
2587      * way.
2588      */
2589     for (;; st->cp++) {
2590 	switch (*st->cp) {
2591 	case 'g':
2592 	    pattern.flags |= VAR_SUB_GLOBAL;
2593 	    continue;
2594 	case '1':
2595 	    pattern.flags |= VAR_SUB_ONE;
2596 	    continue;
2597 	case 'W':
2598 	    tmpparsestate.oneBigWord = TRUE;
2599 	    continue;
2600 	}
2601 	break;
2602     }
2603 
2604     st->termc = *st->cp;
2605     st->newStr = VarModify(
2606 	st->ctxt, &tmpparsestate, st->nstr, VarSubstitute, &pattern);
2607 
2608     /* Free the two strings. */
2609     free(UNCONST(pattern.lhs));
2610     free(UNCONST(pattern.rhs));
2611     st->delim = '\0';
2612     return TRUE;
2613 }
2614 
2615 #ifndef NO_REGEX
2616 /* :C,from,to, */
2617 static Boolean
2618 ApplyModifier_Regex(ApplyModifiersState *st)
2619 {
2620     VarREPattern    pattern;
2621     char           *re;
2622     int             error;
2623     Var_Parse_State tmpparsestate;
2624 
2625     pattern.flags = 0;
2626     tmpparsestate = st->parsestate;
2627     st->delim = st->tstr[1];
2628     st->tstr += 2;
2629 
2630     st->cp = st->tstr;
2631 
2632     re = VarGetPattern(
2633 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2634 	NULL, NULL, NULL);
2635     if (re == NULL)
2636 	return FALSE;
2637 
2638     pattern.replace = VarGetPattern(
2639 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2640 	NULL, NULL, NULL);
2641     if (pattern.replace == NULL) {
2642 	free(re);
2643 	return FALSE;
2644     }
2645 
2646     for (;; st->cp++) {
2647 	switch (*st->cp) {
2648 	case 'g':
2649 	    pattern.flags |= VAR_SUB_GLOBAL;
2650 	    continue;
2651 	case '1':
2652 	    pattern.flags |= VAR_SUB_ONE;
2653 	    continue;
2654 	case 'W':
2655 	    tmpparsestate.oneBigWord = TRUE;
2656 	    continue;
2657 	}
2658 	break;
2659     }
2660 
2661     st->termc = *st->cp;
2662 
2663     error = regcomp(&pattern.re, re, REG_EXTENDED);
2664     free(re);
2665     if (error) {
2666 	*st->lengthPtr = st->cp - st->start + 1;
2667 	VarREError(error, &pattern.re, "RE substitution error");
2668 	free(pattern.replace);
2669 	return FALSE;
2670     }
2671 
2672     pattern.nsub = pattern.re.re_nsub + 1;
2673     if (pattern.nsub < 1)
2674 	pattern.nsub = 1;
2675     if (pattern.nsub > 10)
2676 	pattern.nsub = 10;
2677     pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t));
2678     st->newStr = VarModify(
2679 	st->ctxt, &tmpparsestate, st->nstr, VarRESubstitute, &pattern);
2680     regfree(&pattern.re);
2681     free(pattern.replace);
2682     free(pattern.matches);
2683     st->delim = '\0';
2684     return TRUE;
2685 }
2686 #endif
2687 
2688 /* :tA, :tu, :tl, etc. */
2689 static Boolean
2690 ApplyModifier_To(ApplyModifiersState *st)
2691 {
2692     st->cp = st->tstr + 1;	/* make sure it is set */
2693     if (st->tstr[1] != st->endc && st->tstr[1] != ':') {
2694 	if (st->tstr[1] == 's') {
2695 	    /* Use the char (if any) at st->tstr[2] as the word separator. */
2696 	    VarPattern pattern;
2697 
2698 	    if (st->tstr[2] != st->endc &&
2699 		(st->tstr[3] == st->endc || st->tstr[3] == ':')) {
2700 		/* ":ts<unrecognised><endc>" or
2701 		 * ":ts<unrecognised>:" */
2702 		st->parsestate.varSpace = st->tstr[2];
2703 		st->cp = st->tstr + 3;
2704 	    } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2705 		/* ":ts<endc>" or ":ts:" */
2706 		st->parsestate.varSpace = 0;	/* no separator */
2707 		st->cp = st->tstr + 2;
2708 	    } else if (st->tstr[2] == '\\') {
2709 		const char *xp = &st->tstr[3];
2710 		int base = 8;	/* assume octal */
2711 
2712 		switch (st->tstr[3]) {
2713 		case 'n':
2714 		    st->parsestate.varSpace = '\n';
2715 		    st->cp = st->tstr + 4;
2716 		    break;
2717 		case 't':
2718 		    st->parsestate.varSpace = '\t';
2719 		    st->cp = st->tstr + 4;
2720 		    break;
2721 		case 'x':
2722 		    base = 16;
2723 		    xp++;
2724 		    goto get_numeric;
2725 		case '0':
2726 		    base = 0;
2727 		    goto get_numeric;
2728 		default:
2729 		    if (isdigit((unsigned char)st->tstr[3])) {
2730 			char *ep;
2731 		    get_numeric:
2732 			st->parsestate.varSpace = strtoul(xp, &ep, base);
2733 			if (*ep != ':' && *ep != st->endc)
2734 			    return FALSE;
2735 			st->cp = ep;
2736 		    } else {
2737 			/* ":ts<backslash><unrecognised>". */
2738 			return FALSE;
2739 		    }
2740 		    break;
2741 		}
2742 	    } else {
2743 		/* Found ":ts<unrecognised><unrecognised>". */
2744 		return FALSE;
2745 	    }
2746 
2747 	    st->termc = *st->cp;
2748 
2749 	    /*
2750 	     * We cannot be certain that VarModify will be used - even if there
2751 	     * is a subsequent modifier, so do a no-op VarSubstitute now to for
2752 	     * str to be re-expanded without the spaces.
2753 	     */
2754 	    pattern.flags = VAR_SUB_ONE;
2755 	    pattern.lhs = pattern.rhs = "\032";
2756 	    pattern.leftLen = pattern.rightLen = 1;
2757 
2758 	    st->newStr = VarModify(
2759 		st->ctxt, &st->parsestate, st->nstr, VarSubstitute, &pattern);
2760 	} else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2761 	    /* Check for two-character options: ":tu", ":tl" */
2762 	    if (st->tstr[1] == 'A') {	/* absolute path */
2763 		st->newStr = VarModify(
2764 			st->ctxt, &st->parsestate, st->nstr, VarRealpath, NULL);
2765 		st->cp = st->tstr + 2;
2766 		st->termc = *st->cp;
2767 	    } else if (st->tstr[1] == 'u') {
2768 		char *dp = bmake_strdup(st->nstr);
2769 		for (st->newStr = dp; *dp; dp++)
2770 		    *dp = toupper((unsigned char)*dp);
2771 		st->cp = st->tstr + 2;
2772 		st->termc = *st->cp;
2773 	    } else if (st->tstr[1] == 'l') {
2774 		char *dp = bmake_strdup(st->nstr);
2775 		for (st->newStr = dp; *dp; dp++)
2776 		    *dp = tolower((unsigned char)*dp);
2777 		st->cp = st->tstr + 2;
2778 		st->termc = *st->cp;
2779 	    } else if (st->tstr[1] == 'W' || st->tstr[1] == 'w') {
2780 		st->parsestate.oneBigWord = (st->tstr[1] == 'W');
2781 		st->newStr = st->nstr;
2782 		st->cp = st->tstr + 2;
2783 		st->termc = *st->cp;
2784 	    } else {
2785 		/* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
2786 		return FALSE;
2787 	    }
2788 	} else {
2789 	    /* Found ":t<unrecognised><unrecognised>". */
2790 	    return FALSE;
2791 	}
2792     } else {
2793 	/* Found ":t<endc>" or ":t:". */
2794 	return FALSE;
2795     }
2796     return TRUE;
2797 }
2798 
2799 /* :[#], :[1], etc. */
2800 static int
2801 ApplyModifier_Words(ApplyModifiersState *st)
2802 {
2803     /*
2804      * Look for the closing ']', recursively
2805      * expanding any embedded variables.
2806      *
2807      * estr is a pointer to the expanded result,
2808      * which we must free().
2809      */
2810     char *estr;
2811 
2812     st->cp = st->tstr + 1;	/* point to char after '[' */
2813     st->delim = ']';		/* look for closing ']' */
2814     estr = VarGetPattern(
2815 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2816 	NULL, NULL, NULL);
2817     if (estr == NULL)
2818 	return 'c';		/* report missing ']' */
2819     /* now st->cp points just after the closing ']' */
2820     st->delim = '\0';
2821     if (st->cp[0] != ':' && st->cp[0] != st->endc) {
2822 	/* Found junk after ']' */
2823 	free(estr);
2824 	return 'b';
2825     }
2826     if (estr[0] == '\0') {
2827 	/* Found empty square brackets in ":[]". */
2828 	free(estr);
2829 	return 'b';
2830     } else if (estr[0] == '#' && estr[1] == '\0') {
2831 	/* Found ":[#]" */
2832 
2833 	/*
2834 	 * We will need enough space for the decimal
2835 	 * representation of an int.  We calculate the
2836 	 * space needed for the octal representation,
2837 	 * and add enough slop to cope with a '-' sign
2838 	 * (which should never be needed) and a '\0'
2839 	 * string terminator.
2840 	 */
2841 	int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
2842 
2843 	st->newStr = bmake_malloc(newStrSize);
2844 	if (st->parsestate.oneBigWord) {
2845 	    strncpy(st->newStr, "1", newStrSize);
2846 	} else {
2847 	    /* XXX: brk_string() is a rather expensive
2848 	     * way of counting words. */
2849 	    char **av;
2850 	    char *as;
2851 	    int ac;
2852 
2853 	    av = brk_string(st->nstr, &ac, FALSE, &as);
2854 	    snprintf(st->newStr, newStrSize, "%d", ac);
2855 	    free(as);
2856 	    free(av);
2857 	}
2858 	st->termc = *st->cp;
2859 	free(estr);
2860 	return 0;
2861     } else if (estr[0] == '*' && estr[1] == '\0') {
2862 	/* Found ":[*]" */
2863 	st->parsestate.oneBigWord = TRUE;
2864 	st->newStr = st->nstr;
2865 	st->termc = *st->cp;
2866 	free(estr);
2867 	return 0;
2868     } else if (estr[0] == '@' && estr[1] == '\0') {
2869 	/* Found ":[@]" */
2870 	st->parsestate.oneBigWord = FALSE;
2871 	st->newStr = st->nstr;
2872 	st->termc = *st->cp;
2873 	free(estr);
2874 	return 0;
2875     } else {
2876 	char *ep;
2877 	/*
2878 	 * We expect estr to contain a single
2879 	 * integer for :[N], or two integers
2880 	 * separated by ".." for :[start..end].
2881 	 */
2882 	VarSelectWords_t seldata = { 0, 0 };
2883 
2884 	seldata.start = strtol(estr, &ep, 0);
2885 	if (ep == estr) {
2886 	    /* Found junk instead of a number */
2887 	    free(estr);
2888 	    return 'b';
2889 	} else if (ep[0] == '\0') {
2890 	    /* Found only one integer in :[N] */
2891 	    seldata.end = seldata.start;
2892 	} else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
2893 	    /* Expecting another integer after ".." */
2894 	    ep += 2;
2895 	    seldata.end = strtol(ep, &ep, 0);
2896 	    if (ep[0] != '\0') {
2897 		/* Found junk after ".." */
2898 		free(estr);
2899 		return 'b';
2900 	    }
2901 	} else {
2902 	    /* Found junk instead of ".." */
2903 	    free(estr);
2904 	    return 'b';
2905 	}
2906 	/*
2907 	 * Now seldata is properly filled in,
2908 	 * but we still have to check for 0 as
2909 	 * a special case.
2910 	 */
2911 	if (seldata.start == 0 && seldata.end == 0) {
2912 	    /* ":[0]" or perhaps ":[0..0]" */
2913 	    st->parsestate.oneBigWord = TRUE;
2914 	    st->newStr = st->nstr;
2915 	    st->termc = *st->cp;
2916 	    free(estr);
2917 	    return 0;
2918 	} else if (seldata.start == 0 || seldata.end == 0) {
2919 	    /* ":[0..N]" or ":[N..0]" */
2920 	    free(estr);
2921 	    return 'b';
2922 	}
2923 	/* Normal case: select the words described by seldata. */
2924 	st->newStr = VarSelectWords(
2925 	    st->ctxt, &st->parsestate, st->nstr, &seldata);
2926 
2927 	st->termc = *st->cp;
2928 	free(estr);
2929 	return 0;
2930     }
2931 }
2932 
2933 /* :O or :Ox */
2934 static Boolean
2935 ApplyModifier_Order(ApplyModifiersState *st)
2936 {
2937     char otype;
2938 
2939     st->cp = st->tstr + 1;	/* skip to the rest in any case */
2940     if (st->tstr[1] == st->endc || st->tstr[1] == ':') {
2941 	otype = 's';
2942 	st->termc = *st->cp;
2943     } else if ((st->tstr[1] == 'r' || st->tstr[1] == 'x') &&
2944 	       (st->tstr[2] == st->endc || st->tstr[2] == ':')) {
2945 	otype = st->tstr[1];
2946 	st->cp = st->tstr + 2;
2947 	st->termc = *st->cp;
2948     } else {
2949 	return FALSE;
2950     }
2951     st->newStr = VarOrder(st->nstr, otype);
2952     return TRUE;
2953 }
2954 
2955 /* :? then : else */
2956 static Boolean
2957 ApplyModifier_IfElse(ApplyModifiersState *st)
2958 {
2959     VarPattern pattern;
2960     Boolean value;
2961     int cond_rc;
2962     VarPattern_Flags lhs_flags, rhs_flags;
2963 
2964     /* find ':', and then substitute accordingly */
2965     if (st->flags & VARF_WANTRES) {
2966 	cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
2967 	if (cond_rc == COND_INVALID) {
2968 	    lhs_flags = rhs_flags = VAR_NOSUBST;
2969 	} else if (value) {
2970 	    lhs_flags = 0;
2971 	    rhs_flags = VAR_NOSUBST;
2972 	} else {
2973 	    lhs_flags = VAR_NOSUBST;
2974 	    rhs_flags = 0;
2975 	}
2976     } else {
2977 	/* we are just consuming and discarding */
2978 	cond_rc = value = 0;
2979 	lhs_flags = rhs_flags = VAR_NOSUBST;
2980     }
2981     pattern.flags = 0;
2982 
2983     st->cp = ++st->tstr;
2984     st->delim = ':';
2985     pattern.lhs = VarGetPattern(
2986 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2987 	&lhs_flags, &pattern.leftLen, NULL);
2988     if (pattern.lhs == NULL)
2989 	return FALSE;
2990 
2991     /* BROPEN or PROPEN */
2992     st->delim = st->endc;
2993     pattern.rhs = VarGetPattern(
2994 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2995 	&rhs_flags, &pattern.rightLen, NULL);
2996     if (pattern.rhs == NULL)
2997 	return FALSE;
2998 
2999     st->termc = *--st->cp;
3000     st->delim = '\0';
3001     if (cond_rc == COND_INVALID) {
3002 	Error("Bad conditional expression `%s' in %s?%s:%s",
3003 	    st->v->name, st->v->name, pattern.lhs, pattern.rhs);
3004 	return FALSE;
3005     }
3006 
3007     if (value) {
3008 	st->newStr = UNCONST(pattern.lhs);
3009 	free(UNCONST(pattern.rhs));
3010     } else {
3011 	st->newStr = UNCONST(pattern.rhs);
3012 	free(UNCONST(pattern.lhs));
3013     }
3014     if (st->v->flags & VAR_JUNK)
3015 	st->v->flags |= VAR_KEEP;
3016     return TRUE;
3017 }
3018 
3019 /* "::=", "::!=", "::+=", or "::?=" */
3020 static int
3021 ApplyModifier_Assign(ApplyModifiersState *st)
3022 {
3023     if (st->tstr[1] == '=' ||
3024 	(st->tstr[2] == '=' &&
3025 	 (st->tstr[1] == '!' || st->tstr[1] == '+' || st->tstr[1] == '?'))) {
3026 	GNode *v_ctxt;		/* context where v belongs */
3027 	const char *emsg;
3028 	char *sv_name;
3029 	VarPattern pattern;
3030 	int how;
3031 	VarPattern_Flags vflags;
3032 
3033 	if (st->v->name[0] == 0)
3034 	    return 'b';
3035 
3036 	v_ctxt = st->ctxt;
3037 	sv_name = NULL;
3038 	++st->tstr;
3039 	if (st->v->flags & VAR_JUNK) {
3040 	    /*
3041 	     * We need to bmake_strdup() it incase
3042 	     * VarGetPattern() recurses.
3043 	     */
3044 	    sv_name = st->v->name;
3045 	    st->v->name = bmake_strdup(st->v->name);
3046 	} else if (st->ctxt != VAR_GLOBAL) {
3047 	    Var *gv = VarFind(st->v->name, st->ctxt, 0);
3048 	    if (gv == NULL)
3049 		v_ctxt = VAR_GLOBAL;
3050 	    else
3051 		VarFreeEnv(gv, TRUE);
3052 	}
3053 
3054 	switch ((how = *st->tstr)) {
3055 	case '+':
3056 	case '?':
3057 	case '!':
3058 	    st->cp = &st->tstr[2];
3059 	    break;
3060 	default:
3061 	    st->cp = ++st->tstr;
3062 	    break;
3063 	}
3064 	st->delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
3065 	pattern.flags = 0;
3066 
3067 	vflags = (st->flags & VARF_WANTRES) ? 0 : VAR_NOSUBST;
3068 	pattern.rhs = VarGetPattern(
3069 	    st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3070 	    &vflags, &pattern.rightLen, NULL);
3071 	if (st->v->flags & VAR_JUNK) {
3072 	    /* restore original name */
3073 	    free(st->v->name);
3074 	    st->v->name = sv_name;
3075 	}
3076 	if (pattern.rhs == NULL)
3077 	    return 'c';
3078 
3079 	st->termc = *--st->cp;
3080 	st->delim = '\0';
3081 
3082 	if (st->flags & VARF_WANTRES) {
3083 	    switch (how) {
3084 	    case '+':
3085 		Var_Append(st->v->name, pattern.rhs, v_ctxt);
3086 		break;
3087 	    case '!':
3088 		st->newStr = Cmd_Exec(pattern.rhs, &emsg);
3089 		if (emsg)
3090 		    Error(emsg, st->nstr);
3091 		else
3092 		    Var_Set(st->v->name, st->newStr, v_ctxt);
3093 		free(st->newStr);
3094 		break;
3095 	    case '?':
3096 		if ((st->v->flags & VAR_JUNK) == 0)
3097 		    break;
3098 		/* FALLTHROUGH */
3099 	    default:
3100 		Var_Set(st->v->name, pattern.rhs, v_ctxt);
3101 		break;
3102 	    }
3103 	}
3104 	free(UNCONST(pattern.rhs));
3105 	st->newStr = varNoError;
3106 	return 0;
3107     }
3108     return 'd';			/* "::<unrecognised>" */
3109 }
3110 
3111 /* remember current value */
3112 static Boolean
3113 ApplyModifier_Remember(ApplyModifiersState *st)
3114 {
3115     st->cp = st->tstr + 1;	/* make sure it is set */
3116     if (!STRMOD_MATCHX(st->tstr, "_", 1))
3117 	return FALSE;
3118 
3119     if (st->tstr[1] == '=') {
3120 	char *np;
3121 	int n;
3122 
3123 	st->cp++;
3124 	n = strcspn(st->cp, ":)}");
3125 	np = bmake_strndup(st->cp, n + 1);
3126 	np[n] = '\0';
3127 	st->cp = st->tstr + 2 + n;
3128 	Var_Set(np, st->nstr, st->ctxt);
3129 	free(np);
3130     } else {
3131 	Var_Set("_", st->nstr, st->ctxt);
3132     }
3133     st->newStr = st->nstr;
3134     st->termc = *st->cp;
3135     return TRUE;
3136 }
3137 
3138 #ifdef SYSVVARSUB
3139 /* :from=to */
3140 static int
3141 ApplyModifier_SysV(ApplyModifiersState *st)
3142 {
3143     /*
3144      * This can either be a bogus modifier or a System-V
3145      * substitution command.
3146      */
3147     VarPattern      pattern;
3148     Boolean         eqFound = FALSE;
3149 
3150     pattern.flags = 0;
3151 
3152     /*
3153      * First we make a pass through the string trying
3154      * to verify it is a SYSV-make-style translation:
3155      * it must be: <string1>=<string2>)
3156      */
3157     st->cp = st->tstr;
3158     st->cnt = 1;
3159     while (*st->cp != '\0' && st->cnt) {
3160 	if (*st->cp == '=') {
3161 	    eqFound = TRUE;
3162 	    /* continue looking for st->endc */
3163 	} else if (*st->cp == st->endc)
3164 	    st->cnt--;
3165 	else if (*st->cp == st->startc)
3166 	    st->cnt++;
3167 	if (st->cnt)
3168 	    st->cp++;
3169     }
3170     if (*st->cp != st->endc || !eqFound)
3171 	return 0;
3172 
3173     st->delim = '=';
3174     st->cp = st->tstr;
3175     pattern.lhs = VarGetPattern(
3176 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3177 	&pattern.flags, &pattern.leftLen, NULL);
3178     if (pattern.lhs == NULL)
3179 	return 'c';
3180 
3181     st->delim = st->endc;
3182     pattern.rhs = VarGetPattern(
3183 	st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3184 	NULL, &pattern.rightLen, &pattern);
3185     if (pattern.rhs == NULL)
3186 	return 'c';
3187 
3188     /*
3189      * SYSV modifications happen through the whole
3190      * string. Note the pattern is anchored at the end.
3191      */
3192     st->termc = *--st->cp;
3193     st->delim = '\0';
3194     if (pattern.leftLen == 0 && *st->nstr == '\0') {
3195 	st->newStr = st->nstr;	/* special case */
3196     } else {
3197 	st->newStr = VarModify(
3198 	    st->ctxt, &st->parsestate, st->nstr, VarSYSVMatch, &pattern);
3199     }
3200     free(UNCONST(pattern.lhs));
3201     free(UNCONST(pattern.rhs));
3202     return '=';
3203 }
3204 #endif
3205 
3206 /*
3207  * Now we need to apply any modifiers the user wants applied.
3208  * These are:
3209  *  	  :M<pattern>	words which match the given <pattern>.
3210  *  			<pattern> is of the standard file
3211  *  			wildcarding form.
3212  *  	  :N<pattern>	words which do not match the given <pattern>.
3213  *  	  :S<d><pat1><d><pat2><d>[1gW]
3214  *  			Substitute <pat2> for <pat1> in the value
3215  *  	  :C<d><pat1><d><pat2><d>[1gW]
3216  *  			Substitute <pat2> for regex <pat1> in the value
3217  *  	  :H		Substitute the head of each word
3218  *  	  :T		Substitute the tail of each word
3219  *  	  :E		Substitute the extension (minus '.') of
3220  *  			each word
3221  *  	  :R		Substitute the root of each word
3222  *  			(pathname minus the suffix).
3223  *	  :O		("Order") Alphabeticaly sort words in variable.
3224  *	  :Ox		("intermiX") Randomize words in variable.
3225  *	  :u		("uniq") Remove adjacent duplicate words.
3226  *	  :tu		Converts the variable contents to uppercase.
3227  *	  :tl		Converts the variable contents to lowercase.
3228  *	  :ts[c]	Sets varSpace - the char used to
3229  *			separate words to 'c'. If 'c' is
3230  *			omitted then no separation is used.
3231  *	  :tW		Treat the variable contents as a single
3232  *			word, even if it contains spaces.
3233  *			(Mnemonic: one big 'W'ord.)
3234  *	  :tw		Treat the variable contents as multiple
3235  *			space-separated words.
3236  *			(Mnemonic: many small 'w'ords.)
3237  *	  :[index]	Select a single word from the value.
3238  *	  :[start..end]	Select multiple words from the value.
3239  *	  :[*] or :[0]	Select the entire value, as a single
3240  *			word.  Equivalent to :tW.
3241  *	  :[@]		Select the entire value, as multiple
3242  *			words.	Undoes the effect of :[*].
3243  *			Equivalent to :tw.
3244  *	  :[#]		Returns the number of words in the value.
3245  *
3246  *	  :?<true-value>:<false-value>
3247  *			If the variable evaluates to true, return
3248  *			true value, else return the second value.
3249  *    	  :lhs=rhs  	Like :S, but the rhs goes to the end of
3250  *    			the invocation.
3251  *	  :sh		Treat the current value as a command
3252  *			to be run, new value is its output.
3253  * The following added so we can handle ODE makefiles.
3254  *	  :@<tmpvar>@<newval>@
3255  *			Assign a temporary local variable <tmpvar>
3256  *			to the current value of each word in turn
3257  *			and replace each word with the result of
3258  *			evaluating <newval>
3259  *	  :D<newval>	Use <newval> as value if variable defined
3260  *	  :U<newval>	Use <newval> as value if variable undefined
3261  *	  :L		Use the name of the variable as the value.
3262  *	  :P		Use the path of the node that has the same
3263  *			name as the variable as the value.  This
3264  *			basically includes an implied :L so that
3265  *			the common method of refering to the path
3266  *			of your dependent 'x' in a rule is to use
3267  *			the form '${x:P}'.
3268  *	  :!<cmd>!	Run cmd much the same as :sh run's the
3269  *			current value of the variable.
3270  * The ::= modifiers, actually assign a value to the variable.
3271  * Their main purpose is in supporting modifiers of .for loop
3272  * iterators and other obscure uses.  They always expand to
3273  * nothing.  In a target rule that would otherwise expand to an
3274  * empty line they can be preceded with @: to keep make happy.
3275  * Eg.
3276  *
3277  * foo:	.USE
3278  * .for i in ${.TARGET} ${.TARGET:R}.gz
3279  * 	@: ${t::=$i}
3280  *	@echo blah ${t:T}
3281  * .endfor
3282  *
3283  *	  ::=<str>	Assigns <str> as the new value of variable.
3284  *	  ::?=<str>	Assigns <str> as value of variable if
3285  *			it was not already set.
3286  *	  ::+=<str>	Appends <str> to variable.
3287  *	  ::!=<cmd>	Assigns output of <cmd> as the new value of
3288  *			variable.
3289  */
3290 static char *
3291 ApplyModifiers(char *nstr, const char *tstr,
3292 	       int const startc, int const endc,
3293 	       Var * const v, GNode * const ctxt, int const flags,
3294 	       int * const lengthPtr, void ** const freePtr)
3295 {
3296     ApplyModifiersState st = {
3297 	startc, endc, v, ctxt, flags, lengthPtr, freePtr,
3298 	nstr, tstr, tstr, tstr,
3299 	'\0', 0, '\0', 0, {' ', FALSE}, NULL
3300     };
3301 
3302     while (*st.tstr && *st.tstr != st.endc) {
3303 
3304 	if (*st.tstr == '$') {
3305 	    /*
3306 	     * We may have some complex modifiers in a variable.
3307 	     */
3308 	    void *freeIt;
3309 	    char *rval;
3310 	    int rlen;
3311 	    int c;
3312 
3313 	    rval = Var_Parse(st.tstr, st.ctxt, st.flags, &rlen, &freeIt);
3314 
3315 	    /*
3316 	     * If we have not parsed up to st.endc or ':',
3317 	     * we are not interested.
3318 	     */
3319 	    if (rval != NULL && *rval &&
3320 		(c = st.tstr[rlen]) != '\0' &&
3321 		c != ':' &&
3322 		c != st.endc) {
3323 		free(freeIt);
3324 		goto apply_mods;
3325 	    }
3326 
3327 	    if (DEBUG(VAR)) {
3328 		fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3329 		       rval, rlen, st.tstr, rlen, st.tstr + rlen);
3330 	    }
3331 
3332 	    st.tstr += rlen;
3333 
3334 	    if (rval != NULL && *rval) {
3335 		int used;
3336 
3337 		st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3338 				      st.ctxt, st.flags, &used, st.freePtr);
3339 		if (st.nstr == var_Error
3340 		    || (st.nstr == varNoError && (st.flags & VARF_UNDEFERR) == 0)
3341 		    || strlen(rval) != (size_t) used) {
3342 		    free(freeIt);
3343 		    goto out;	/* error already reported */
3344 		}
3345 	    }
3346 	    free(freeIt);
3347 	    if (*st.tstr == ':')
3348 		st.tstr++;
3349 	    else if (!*st.tstr && st.endc) {
3350 		Error("Unclosed variable specification after complex "
3351 		    "modifier (expecting '%c') for %s", st.endc, st.v->name);
3352 		goto out;
3353 	    }
3354 	    continue;
3355 	}
3356     apply_mods:
3357 	if (DEBUG(VAR)) {
3358 	    fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3359 		*st.tstr, st.nstr);
3360 	}
3361 	st.newStr = var_Error;
3362 	switch ((st.modifier = *st.tstr)) {
3363 	case ':':
3364 	    {
3365 		int res = ApplyModifier_Assign(&st);
3366 		if (res == 'b')
3367 		    goto bad_modifier;
3368 		if (res == 'c')
3369 		    goto cleanup;
3370 		if (res == 'd')
3371 		    goto default_case;
3372 		break;
3373 	    }
3374 	case '@':
3375 	    ApplyModifier_At(&st);
3376 	    break;
3377 	case '_':
3378 	    if (!ApplyModifier_Remember(&st))
3379 		goto default_case;
3380 	    break;
3381 	case 'D':
3382 	case 'U':
3383 	    ApplyModifier_Defined(&st);
3384 	    break;
3385 	case 'L':
3386 	    {
3387 		if ((st.v->flags & VAR_JUNK) != 0)
3388 		    st.v->flags |= VAR_KEEP;
3389 		st.newStr = bmake_strdup(st.v->name);
3390 		st.cp = ++st.tstr;
3391 		st.termc = *st.tstr;
3392 		break;
3393 	    }
3394 	case 'P':
3395 	    ApplyModifier_Path(&st);
3396 	    break;
3397 	case '!':
3398 	    if (!ApplyModifier_Exclam(&st))
3399 		goto cleanup;
3400 	    break;
3401 	case '[':
3402 	    {
3403 		int res = ApplyModifier_Words(&st);
3404 		if (res == 'b')
3405 		    goto bad_modifier;
3406 		if (res == 'c')
3407 		    goto cleanup;
3408 		break;
3409 	    }
3410 	case 'g':
3411 	    if (!ApplyModifier_Gmtime(&st))
3412 		goto default_case;
3413 	    break;
3414 	case 'h':
3415 	    if (!ApplyModifier_Hash(&st))
3416 		goto default_case;
3417 	    break;
3418 	case 'l':
3419 	    if (!ApplyModifier_Localtime(&st))
3420 		goto default_case;
3421 	    break;
3422 	case 't':
3423 	    if (!ApplyModifier_To(&st))
3424 		goto bad_modifier;
3425 	    break;
3426 	case 'N':
3427 	case 'M':
3428 	    ApplyModifier_Match(&st);
3429 	    break;
3430 	case 'S':
3431 	    if (!ApplyModifier_Subst(&st))
3432 		goto cleanup;
3433 	    break;
3434 	case '?':
3435 	    if (!ApplyModifier_IfElse(&st))
3436 		goto cleanup;
3437 	    break;
3438 #ifndef NO_REGEX
3439 	case 'C':
3440 	    if (!ApplyModifier_Regex(&st))
3441 		goto cleanup;
3442 	    break;
3443 #endif
3444 	case 'q':
3445 	case 'Q':
3446 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3447 		st.newStr = VarQuote(st.nstr, st.modifier == 'q');
3448 		st.cp = st.tstr + 1;
3449 		st.termc = *st.cp;
3450 		break;
3451 	    }
3452 	    goto default_case;
3453 	case 'T':
3454 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3455 		st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarTail,
3456 				   NULL);
3457 		st.cp = st.tstr + 1;
3458 		st.termc = *st.cp;
3459 		break;
3460 	    }
3461 	    goto default_case;
3462 	case 'H':
3463 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3464 		st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarHead,
3465 				   NULL);
3466 		st.cp = st.tstr + 1;
3467 		st.termc = *st.cp;
3468 		break;
3469 	    }
3470 	    goto default_case;
3471 	case 'E':
3472 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3473 		st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarSuffix,
3474 				   NULL);
3475 		st.cp = st.tstr + 1;
3476 		st.termc = *st.cp;
3477 		break;
3478 	    }
3479 	    goto default_case;
3480 	case 'R':
3481 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3482 		st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarRoot,
3483 				   NULL);
3484 		st.cp = st.tstr + 1;
3485 		st.termc = *st.cp;
3486 		break;
3487 	    }
3488 	    goto default_case;
3489 	case 'r':
3490 	    if (!ApplyModifier_Range(&st))
3491 		goto default_case;
3492 	    break;
3493 	case 'O':
3494 	    if (!ApplyModifier_Order(&st))
3495 		goto bad_modifier;
3496 	    break;
3497 	case 'u':
3498 	    if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3499 		st.newStr = VarUniq(st.nstr);
3500 		st.cp = st.tstr + 1;
3501 		st.termc = *st.cp;
3502 		break;
3503 	    }
3504 	    goto default_case;
3505 #ifdef SUNSHCMD
3506 	case 's':
3507 	    if (st.tstr[1] == 'h' && (st.tstr[2] == st.endc || st.tstr[2] == ':')) {
3508 		const char *emsg;
3509 		if (st.flags & VARF_WANTRES) {
3510 		    st.newStr = Cmd_Exec(st.nstr, &emsg);
3511 		    if (emsg)
3512 			Error(emsg, st.nstr);
3513 		} else
3514 		    st.newStr = varNoError;
3515 		st.cp = st.tstr + 2;
3516 		st.termc = *st.cp;
3517 		break;
3518 	    }
3519 	    goto default_case;
3520 #endif
3521 	default:
3522 	default_case:
3523 	    {
3524 #ifdef SYSVVARSUB
3525 		int res = ApplyModifier_SysV(&st);
3526 		if (res == 'c')
3527 		    goto cleanup;
3528 		if (res != '=')
3529 #endif
3530 		{
3531 		    Error("Unknown modifier '%c'", *st.tstr);
3532 		    for (st.cp = st.tstr+1;
3533 			 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3534 			 st.cp++)
3535 			continue;
3536 		    st.termc = *st.cp;
3537 		    st.newStr = var_Error;
3538 		}
3539 	    }
3540 	}
3541 	if (DEBUG(VAR)) {
3542 	    fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3543 		st.v->name, st.modifier, st.newStr);
3544 	}
3545 
3546 	if (st.newStr != st.nstr) {
3547 	    if (*st.freePtr) {
3548 		free(st.nstr);
3549 		*st.freePtr = NULL;
3550 	    }
3551 	    st.nstr = st.newStr;
3552 	    if (st.nstr != var_Error && st.nstr != varNoError) {
3553 		*st.freePtr = st.nstr;
3554 	    }
3555 	}
3556 	if (st.termc == '\0' && st.endc != '\0') {
3557 	    Error("Unclosed variable specification (expecting '%c') "
3558 		"for \"%s\" (value \"%s\") modifier %c",
3559 		st.endc, st.v->name, st.nstr, st.modifier);
3560 	} else if (st.termc == ':') {
3561 	    st.cp++;
3562 	}
3563 	st.tstr = st.cp;
3564     }
3565 out:
3566     *st.lengthPtr = st.tstr - st.start;
3567     return st.nstr;
3568 
3569 bad_modifier:
3570     /* "{(" */
3571     Error("Bad modifier `:%.*s' for %s", (int)strcspn(st.tstr, ":)}"), st.tstr,
3572 	  st.v->name);
3573 
3574 cleanup:
3575     *st.lengthPtr = st.cp - st.start;
3576     if (st.delim != '\0')
3577 	Error("Unclosed substitution for %s (%c missing)",
3578 	      st.v->name, st.delim);
3579     free(*st.freePtr);
3580     *st.freePtr = NULL;
3581     return var_Error;
3582 }
3583 
3584 /*-
3585  *-----------------------------------------------------------------------
3586  * Var_Parse --
3587  *	Given the start of a variable invocation, extract the variable
3588  *	name and find its value, then modify it according to the
3589  *	specification.
3590  *
3591  * Input:
3592  *	str		The string to parse
3593  *	ctxt		The context for the variable
3594  *	flags		VARF_UNDEFERR	if undefineds are an error
3595  *			VARF_WANTRES	if we actually want the result
3596  *			VARF_ASSIGN	if we are in a := assignment
3597  *	lengthPtr	OUT: The length of the specification
3598  *	freePtr		OUT: Non-NULL if caller should free *freePtr
3599  *
3600  * Results:
3601  *	The (possibly-modified) value of the variable or var_Error if the
3602  *	specification is invalid. The length of the specification is
3603  *	placed in *lengthPtr (for invalid specifications, this is just
3604  *	2...?).
3605  *	If *freePtr is non-NULL then it's a pointer that the caller
3606  *	should pass to free() to free memory used by the result.
3607  *
3608  * Side Effects:
3609  *	None.
3610  *
3611  *-----------------------------------------------------------------------
3612  */
3613 /* coverity[+alloc : arg-*4] */
3614 char *
3615 Var_Parse(const char *str, GNode *ctxt, Varf_Flags flags,
3616 	  int *lengthPtr, void **freePtr)
3617 {
3618     const char	*tstr;		/* Pointer into str */
3619     Var		*v;		/* Variable in invocation */
3620     Boolean 	 haveModifier;	/* TRUE if have modifiers for the variable */
3621     char	 endc;		/* Ending character when variable in parens
3622 				 * or braces */
3623     char	 startc;	/* Starting character when variable in parens
3624 				 * or braces */
3625     int		 vlen;		/* Length of variable name */
3626     const char 	*start;		/* Points to original start of str */
3627     char	*nstr;		/* New string, used during expansion */
3628     Boolean	 dynamic;	/* TRUE if the variable is local and we're
3629 				 * expanding it in a non-local context. This
3630 				 * is done to support dynamic sources. The
3631 				 * result is just the invocation, unaltered */
3632     const char	*extramodifiers; /* extra modifiers to apply first */
3633     char	 name[2];
3634 
3635     *freePtr = NULL;
3636     extramodifiers = NULL;
3637     dynamic = FALSE;
3638     start = str;
3639 
3640     startc = str[1];
3641     if (startc != PROPEN && startc != BROPEN) {
3642 	/*
3643 	 * If it's not bounded by braces of some sort, life is much simpler.
3644 	 * We just need to check for the first character and return the
3645 	 * value if it exists.
3646 	 */
3647 
3648 	/* Error out some really stupid names */
3649 	if (startc == '\0' || strchr(")}:$", startc)) {
3650 	    *lengthPtr = 1;
3651 	    return var_Error;
3652 	}
3653 	name[0] = startc;
3654 	name[1] = '\0';
3655 
3656 	v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3657 	if (v == NULL) {
3658 	    *lengthPtr = 2;
3659 
3660 	    if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3661 		/*
3662 		 * If substituting a local variable in a non-local context,
3663 		 * assume it's for dynamic source stuff. We have to handle
3664 		 * this specially and return the longhand for the variable
3665 		 * with the dollar sign escaped so it makes it back to the
3666 		 * caller. Only four of the local variables are treated
3667 		 * specially as they are the only four that will be set
3668 		 * when dynamic sources are expanded.
3669 		 */
3670 		switch (str[1]) {
3671 		case '@':
3672 		    return UNCONST("$(.TARGET)");
3673 		case '%':
3674 		    return UNCONST("$(.MEMBER)");
3675 		case '*':
3676 		    return UNCONST("$(.PREFIX)");
3677 		case '!':
3678 		    return UNCONST("$(.ARCHIVE)");
3679 		}
3680 	    }
3681 	    return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3682 	} else {
3683 	    haveModifier = FALSE;
3684 	    tstr = &str[1];
3685 	    endc = str[1];
3686 	}
3687     } else {
3688 	Buffer buf;		/* Holds the variable name */
3689 	int depth = 1;
3690 
3691 	endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3692 	Buf_Init(&buf, 0);
3693 
3694 	/*
3695 	 * Skip to the end character or a colon, whichever comes first.
3696 	 */
3697 	for (tstr = str + 2; *tstr != '\0'; tstr++) {
3698 	    /* Track depth so we can spot parse errors. */
3699 	    if (*tstr == startc)
3700 		depth++;
3701 	    if (*tstr == endc) {
3702 		if (--depth == 0)
3703 		    break;
3704 	    }
3705 	    if (depth == 1 && *tstr == ':')
3706 		break;
3707 	    /* A variable inside a variable, expand. */
3708 	    if (*tstr == '$') {
3709 		int rlen;
3710 		void *freeIt;
3711 		char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
3712 		if (rval != NULL)
3713 		    Buf_AddBytes(&buf, strlen(rval), rval);
3714 		free(freeIt);
3715 		tstr += rlen - 1;
3716 	    } else
3717 		Buf_AddByte(&buf, *tstr);
3718 	}
3719 	if (*tstr == ':') {
3720 	    haveModifier = TRUE;
3721 	} else if (*tstr == endc) {
3722 	    haveModifier = FALSE;
3723 	} else {
3724 	    /*
3725 	     * If we never did find the end character, return NULL
3726 	     * right now, setting the length to be the distance to
3727 	     * the end of the string, since that's what make does.
3728 	     */
3729 	    *lengthPtr = tstr - str;
3730 	    Buf_Destroy(&buf, TRUE);
3731 	    return var_Error;
3732 	}
3733 	str = Buf_GetAll(&buf, &vlen);
3734 
3735 	/*
3736 	 * At this point, str points into newly allocated memory from
3737 	 * buf, containing only the name of the variable.
3738 	 *
3739 	 * start and tstr point into the const string that was pointed
3740 	 * to by the original value of the str parameter.  start points
3741 	 * to the '$' at the beginning of the string, while tstr points
3742 	 * to the char just after the end of the variable name -- this
3743 	 * will be '\0', ':', PRCLOSE, or BRCLOSE.
3744 	 */
3745 
3746 	v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3747 	/*
3748 	 * Check also for bogus D and F forms of local variables since we're
3749 	 * in a local context and the name is the right length.
3750 	 */
3751 	if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
3752 		(vlen == 2) && (str[1] == 'F' || str[1] == 'D') &&
3753 		strchr("@%?*!<>", str[0]) != NULL) {
3754 	    /*
3755 	     * Well, it's local -- go look for it.
3756 	     */
3757 	    name[0] = *str;
3758 	    name[1] = '\0';
3759 	    v = VarFind(name, ctxt, 0);
3760 
3761 	    if (v != NULL) {
3762 		if (str[1] == 'D') {
3763 		    extramodifiers = "H:";
3764 		} else { /* F */
3765 		    extramodifiers = "T:";
3766 		}
3767 	    }
3768 	}
3769 
3770 	if (v == NULL) {
3771 	    if (((vlen == 1) ||
3772 		 (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) &&
3773 		((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
3774 	    {
3775 		/*
3776 		 * If substituting a local variable in a non-local context,
3777 		 * assume it's for dynamic source stuff. We have to handle
3778 		 * this specially and return the longhand for the variable
3779 		 * with the dollar sign escaped so it makes it back to the
3780 		 * caller. Only four of the local variables are treated
3781 		 * specially as they are the only four that will be set
3782 		 * when dynamic sources are expanded.
3783 		 */
3784 		switch (*str) {
3785 		case '@':
3786 		case '%':
3787 		case '*':
3788 		case '!':
3789 		    dynamic = TRUE;
3790 		    break;
3791 		}
3792 	    } else if (vlen > 2 && *str == '.' &&
3793 		       isupper((unsigned char) str[1]) &&
3794 		       (ctxt == VAR_CMD || ctxt == VAR_GLOBAL))
3795 	    {
3796 		int len = vlen - 1;
3797 		if ((strncmp(str, ".TARGET", len) == 0) ||
3798 		    (strncmp(str, ".ARCHIVE", len) == 0) ||
3799 		    (strncmp(str, ".PREFIX", len) == 0) ||
3800 		    (strncmp(str, ".MEMBER", len) == 0))
3801 		{
3802 		    dynamic = TRUE;
3803 		}
3804 	    }
3805 
3806 	    if (!haveModifier) {
3807 		/*
3808 		 * No modifiers -- have specification length so we can return
3809 		 * now.
3810 		 */
3811 		*lengthPtr = tstr - start + 1;
3812 		if (dynamic) {
3813 		    char *pstr = bmake_strndup(start, *lengthPtr);
3814 		    *freePtr = pstr;
3815 		    Buf_Destroy(&buf, TRUE);
3816 		    return pstr;
3817 		} else {
3818 		    Buf_Destroy(&buf, TRUE);
3819 		    return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3820 		}
3821 	    } else {
3822 		/*
3823 		 * Still need to get to the end of the variable specification,
3824 		 * so kludge up a Var structure for the modifications
3825 		 */
3826 		v = bmake_malloc(sizeof(Var));
3827 		v->name = UNCONST(str);
3828 		Buf_Init(&v->val, 1);
3829 		v->flags = VAR_JUNK;
3830 		Buf_Destroy(&buf, FALSE);
3831 	    }
3832 	} else
3833 	    Buf_Destroy(&buf, TRUE);
3834     }
3835 
3836     if (v->flags & VAR_IN_USE) {
3837 	Fatal("Variable %s is recursive.", v->name);
3838 	/*NOTREACHED*/
3839     } else {
3840 	v->flags |= VAR_IN_USE;
3841     }
3842     /*
3843      * Before doing any modification, we have to make sure the value
3844      * has been fully expanded. If it looks like recursion might be
3845      * necessary (there's a dollar sign somewhere in the variable's value)
3846      * we just call Var_Subst to do any other substitutions that are
3847      * necessary. Note that the value returned by Var_Subst will have
3848      * been dynamically-allocated, so it will need freeing when we
3849      * return.
3850      */
3851     nstr = Buf_GetAll(&v->val, NULL);
3852     if (strchr(nstr, '$') != NULL && (flags & VARF_WANTRES) != 0) {
3853 	nstr = Var_Subst(NULL, nstr, ctxt, flags);
3854 	*freePtr = nstr;
3855     }
3856 
3857     v->flags &= ~VAR_IN_USE;
3858 
3859     if (nstr != NULL && (haveModifier || extramodifiers != NULL)) {
3860 	void *extraFree;
3861 	int used;
3862 
3863 	extraFree = NULL;
3864 	if (extramodifiers != NULL) {
3865 	    nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
3866 				  v, ctxt, flags, &used, &extraFree);
3867 	}
3868 
3869 	if (haveModifier) {
3870 	    /* Skip initial colon. */
3871 	    tstr++;
3872 
3873 	    nstr = ApplyModifiers(nstr, tstr, startc, endc,
3874 				  v, ctxt, flags, &used, freePtr);
3875 	    tstr += used;
3876 	    free(extraFree);
3877 	} else {
3878 	    *freePtr = extraFree;
3879 	}
3880     }
3881     *lengthPtr = tstr - start + (*tstr ? 1 : 0);
3882 
3883     if (v->flags & VAR_FROM_ENV) {
3884 	Boolean destroy = FALSE;
3885 
3886 	if (nstr != Buf_GetAll(&v->val, NULL)) {
3887 	    destroy = TRUE;
3888 	} else {
3889 	    /*
3890 	     * Returning the value unmodified, so tell the caller to free
3891 	     * the thing.
3892 	     */
3893 	    *freePtr = nstr;
3894 	}
3895 	VarFreeEnv(v, destroy);
3896     } else if (v->flags & VAR_JUNK) {
3897 	/*
3898 	 * Perform any free'ing needed and set *freePtr to NULL so the caller
3899 	 * doesn't try to free a static pointer.
3900 	 * If VAR_KEEP is also set then we want to keep str as is.
3901 	 */
3902 	if (!(v->flags & VAR_KEEP)) {
3903 	    if (*freePtr) {
3904 		free(nstr);
3905 		*freePtr = NULL;
3906 	    }
3907 	    if (dynamic) {
3908 		nstr = bmake_strndup(start, *lengthPtr);
3909 		*freePtr = nstr;
3910 	    } else {
3911 		nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3912 	    }
3913 	}
3914 	if (nstr != Buf_GetAll(&v->val, NULL))
3915 	    Buf_Destroy(&v->val, TRUE);
3916 	free(v->name);
3917 	free(v);
3918     }
3919     return nstr;
3920 }
3921 
3922 /*-
3923  *-----------------------------------------------------------------------
3924  * Var_Subst  --
3925  *	Substitute for all variables in the given string in the given context.
3926  *	If flags & VARF_UNDEFERR, Parse_Error will be called when an undefined
3927  *	variable is encountered.
3928  *
3929  * Input:
3930  *	var		Named variable || NULL for all
3931  *	str		the string which to substitute
3932  *	ctxt		the context wherein to find variables
3933  *	flags		VARF_UNDEFERR	if undefineds are an error
3934  *			VARF_WANTRES	if we actually want the result
3935  *			VARF_ASSIGN	if we are in a := assignment
3936  *
3937  * Results:
3938  *	The resulting string.
3939  *
3940  * Side Effects:
3941  *	None.
3942  *-----------------------------------------------------------------------
3943  */
3944 char *
3945 Var_Subst(const char *var, const char *str, GNode *ctxt, Varf_Flags flags)
3946 {
3947     Buffer	buf;		/* Buffer for forming things */
3948     char	*val;		/* Value to substitute for a variable */
3949     int		length;		/* Length of the variable invocation */
3950     Boolean	trailingBslash;	/* variable ends in \ */
3951     void	*freeIt = NULL;	/* Set if it should be freed */
3952     static Boolean errorReported; /* Set true if an error has already
3953 				 * been reported to prevent a plethora
3954 				 * of messages when recursing */
3955 
3956     Buf_Init(&buf, 0);
3957     errorReported = FALSE;
3958     trailingBslash = FALSE;
3959 
3960     while (*str) {
3961 	if (*str == '\n' && trailingBslash)
3962 	    Buf_AddByte(&buf, ' ');
3963 	if (var == NULL && (*str == '$') && (str[1] == '$')) {
3964 	    /*
3965 	     * A dollar sign may be escaped either with another dollar sign.
3966 	     * In such a case, we skip over the escape character and store the
3967 	     * dollar sign into the buffer directly.
3968 	     */
3969 	    if (save_dollars && (flags & VARF_ASSIGN))
3970 		Buf_AddByte(&buf, *str);
3971 	    str++;
3972 	    Buf_AddByte(&buf, *str);
3973 	    str++;
3974 	} else if (*str != '$') {
3975 	    /*
3976 	     * Skip as many characters as possible -- either to the end of
3977 	     * the string or to the next dollar sign (variable invocation).
3978 	     */
3979 	    const char *cp;
3980 
3981 	    for (cp = str++; *str != '$' && *str != '\0'; str++)
3982 		continue;
3983 	    Buf_AddBytes(&buf, str - cp, cp);
3984 	} else {
3985 	    if (var != NULL) {
3986 		int expand;
3987 		for (;;) {
3988 		    if (str[1] == '\0') {
3989 			/* A trailing $ is kind of a special case */
3990 			Buf_AddByte(&buf, str[0]);
3991 			str++;
3992 			expand = FALSE;
3993 		    } else if (str[1] != PROPEN && str[1] != BROPEN) {
3994 			if (str[1] != *var || strlen(var) > 1) {
3995 			    Buf_AddBytes(&buf, 2, str);
3996 			    str += 2;
3997 			    expand = FALSE;
3998 			} else
3999 			    expand = TRUE;
4000 			break;
4001 		    } else {
4002 			const char *p;
4003 
4004 			/* Scan up to the end of the variable name. */
4005 			for (p = &str[2]; *p &&
4006 			     *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
4007 			    if (*p == '$')
4008 				break;
4009 			/*
4010 			 * A variable inside the variable. We cannot expand
4011 			 * the external variable yet, so we try again with
4012 			 * the nested one
4013 			 */
4014 			if (*p == '$') {
4015 			    Buf_AddBytes(&buf, p - str, str);
4016 			    str = p;
4017 			    continue;
4018 			}
4019 
4020 			if (strncmp(var, str + 2, p - str - 2) != 0 ||
4021 			    var[p - str - 2] != '\0') {
4022 			    /*
4023 			     * Not the variable we want to expand, scan
4024 			     * until the next variable
4025 			     */
4026 			    for (; *p != '$' && *p != '\0'; p++)
4027 				continue;
4028 			    Buf_AddBytes(&buf, p - str, str);
4029 			    str = p;
4030 			    expand = FALSE;
4031 			} else
4032 			    expand = TRUE;
4033 			break;
4034 		    }
4035 		}
4036 		if (!expand)
4037 		    continue;
4038 	    }
4039 
4040 	    val = Var_Parse(str, ctxt, flags, &length, &freeIt);
4041 
4042 	    /*
4043 	     * When we come down here, val should either point to the
4044 	     * value of this variable, suitably modified, or be NULL.
4045 	     * Length should be the total length of the potential
4046 	     * variable invocation (from $ to end character...)
4047 	     */
4048 	    if (val == var_Error || val == varNoError) {
4049 		/*
4050 		 * If performing old-time variable substitution, skip over
4051 		 * the variable and continue with the substitution. Otherwise,
4052 		 * store the dollar sign and advance str so we continue with
4053 		 * the string...
4054 		 */
4055 		if (oldVars) {
4056 		    str += length;
4057 		} else if ((flags & VARF_UNDEFERR) || val == var_Error) {
4058 		    /*
4059 		     * If variable is undefined, complain and skip the
4060 		     * variable. The complaint will stop us from doing anything
4061 		     * when the file is parsed.
4062 		     */
4063 		    if (!errorReported) {
4064 			Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
4065 				    length, str);
4066 		    }
4067 		    str += length;
4068 		    errorReported = TRUE;
4069 		} else {
4070 		    Buf_AddByte(&buf, *str);
4071 		    str += 1;
4072 		}
4073 	    } else {
4074 		/*
4075 		 * We've now got a variable structure to store in. But first,
4076 		 * advance the string pointer.
4077 		 */
4078 		str += length;
4079 
4080 		/*
4081 		 * Copy all the characters from the variable value straight
4082 		 * into the new string.
4083 		 */
4084 		length = strlen(val);
4085 		Buf_AddBytes(&buf, length, val);
4086 		trailingBslash = length > 0 && val[length - 1] == '\\';
4087 	    }
4088 	    free(freeIt);
4089 	    freeIt = NULL;
4090 	}
4091     }
4092 
4093     return Buf_DestroyCompact(&buf);
4094 }
4095 
4096 /* Initialize the module. */
4097 void
4098 Var_Init(void)
4099 {
4100     VAR_INTERNAL = Targ_NewGN("Internal");
4101     VAR_GLOBAL = Targ_NewGN("Global");
4102     VAR_CMD = Targ_NewGN("Command");
4103 }
4104 
4105 
4106 void
4107 Var_End(void)
4108 {
4109 }
4110 
4111 
4112 /****************** PRINT DEBUGGING INFO *****************/
4113 static void
4114 VarPrintVar(void *vp, void *data MAKE_ATTR_UNUSED)
4115 {
4116     Var *v = (Var *)vp;
4117     fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
4118 }
4119 
4120 /*-
4121  *-----------------------------------------------------------------------
4122  * Var_Dump --
4123  *	print all variables in a context
4124  *-----------------------------------------------------------------------
4125  */
4126 void
4127 Var_Dump(GNode *ctxt)
4128 {
4129     Hash_ForEach(&ctxt->context, VarPrintVar, NULL);
4130 }
4131