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