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