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