Module Name:    src
Committed By:   rillig
Date:           Mon Mar 15 20:00:51 UTC 2021

Modified Files:
        src/usr.bin/make: var.c
        src/usr.bin/make/unit-tests: varmod-indirect.mk

Log Message:
make: rename ApplyModifiersState to ModChain

The new name accurately describes the structural element that holds such
properties as the separator character and whether the expression value
is considered a single word.  The old name ApplyModifiersState was too
long and was meant as a placeholder anyway, when I introduced it in
var.c 1.236 from 2020-07-03.


To generate a diff of this commit:
cvs rdiff -u -r1.890 -r1.891 src/usr.bin/make/var.c
cvs rdiff -u -r1.8 -r1.9 src/usr.bin/make/unit-tests/varmod-indirect.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.890 src/usr.bin/make/var.c:1.891
--- src/usr.bin/make/var.c:1.890	Mon Mar 15 19:15:04 2021
+++ src/usr.bin/make/var.c	Mon Mar 15 20:00:50 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.890 2021/03/15 19:15:04 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.891 2021/03/15 20:00:50 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -140,7 +140,7 @@
 #include "metachar.h"
 
 /*	"@(#)var.c	8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.890 2021/03/15 19:15:04 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.891 2021/03/15 20:00:50 rillig Exp $");
 
 typedef enum VarFlags {
 	VFL_NONE	= 0,
@@ -1831,7 +1831,7 @@ Words_JoinFree(Words words)
 
 	for (i = 0; i < words.len; i++) {
 		if (i != 0) {
-			/* XXX: Use st->sep instead of ' ', for consistency. */
+			/* XXX: Use ch->sep instead of ' ', for consistency. */
 			Buf_AddByte(&buf, ' ');
 		}
 		Buf_AddStr(&buf, words.words[i]);
@@ -1978,7 +1978,7 @@ VarStrftime(const char *fmt, Boolean zul
  *
  * If parsing succeeds, the parsing position *pp is updated to point to the
  * first character following the modifier, which typically is either ':' or
- * st->endc.  The modifier doesn't have to check for this delimiter character,
+ * ch->endc.  The modifier doesn't have to check for this delimiter character,
  * this is done by ApplyModifiers.
  *
  * XXX: As of 2020-11-15, some modifiers such as :S, :C, :P, :L do not
@@ -2012,7 +2012,7 @@ VarStrftime(const char *fmt, Boolean zul
  * Some modifiers such as ':sh' or '::=' have noticeable side effects though.
  *
  * Evaluating the modifier usually takes the current value of the variable
- * expression from st->expr->value, or the variable name from st->var->name
+ * expression from ch->expr->value, or the variable name from ch->var->name
  * and stores the result back in expr->value via Expr_SetValueOwn or
  * Expr_SetValueRefer.
  *
@@ -2079,7 +2079,7 @@ typedef struct Expr {
  *
  * See varmod-indirect.mk.
  */
-typedef struct ApplyModifiersState {
+typedef struct ModChain {
 	Expr *expr;
 	/* '\0' or '{' or '(' */
 	const char startc;
@@ -2093,7 +2093,7 @@ typedef struct ApplyModifiersState {
 	 * big word, possibly containing spaces.
 	 */
 	Boolean oneBigWord;
-} ApplyModifiersState;
+} ModChain;
 
 static void
 Expr_Define(Expr *expr)
@@ -2148,7 +2148,7 @@ ParseModifierPartSubst(
     const char **pp,
     char delim,
     VarEvalFlags eflags,
-    ApplyModifiersState *st,
+    ModChain *ch,
     char **out_part,
     /* Optionally stores the length of the returned string, just to save
      * another strlen call. */
@@ -2204,7 +2204,7 @@ ParseModifierPartSubst(
 			VarEvalFlags nested_eflags = eflags;
 			nested_eflags.keepDollar = FALSE;
 
-			(void)Var_Parse(&nested_p, st->expr->scope,
+			(void)Var_Parse(&nested_p, ch->expr->scope,
 			    nested_eflags, &nested_val);
 			/* TODO: handle errors */
 			Buf_AddStr(&buf, nested_val.str);
@@ -2255,7 +2255,7 @@ ParseModifierPartSubst(
 	if (*p != delim) {
 		*pp = p;
 		Error("Unfinished modifier for \"%s\" ('%c' missing)",
-		    st->expr->var->name.str, delim);
+		    ch->expr->var->name.str, delim);
 		*out_part = NULL;
 		return VPR_ERR;
 	}
@@ -2288,35 +2288,35 @@ ParseModifierPart(
     char delim,
     /* Flags for evaluating nested variables. */
     VarEvalFlags eflags,
-    ApplyModifiersState *st,
+    ModChain *ch,
     char **out_part
 )
 {
-	return ParseModifierPartSubst(pp, delim, eflags, st, out_part,
+	return ParseModifierPartSubst(pp, delim, eflags, ch, out_part,
 	    NULL, NULL, NULL);
 }
 
 MAKE_INLINE Boolean
-IsDelimiter(char ch, const ApplyModifiersState *st)
+IsDelimiter(char c, const ModChain *ch)
 {
-	return ch == ':' || ch == st->endc;
+	return c == ':' || c == ch->endc;
 }
 
 /* Test whether mod starts with modname, followed by a delimiter. */
 MAKE_INLINE Boolean
-ModMatch(const char *mod, const char *modname, const ApplyModifiersState *st)
+ModMatch(const char *mod, const char *modname, const ModChain *ch)
 {
 	size_t n = strlen(modname);
-	return strncmp(mod, modname, n) == 0 && IsDelimiter(mod[n], st);
+	return strncmp(mod, modname, n) == 0 && IsDelimiter(mod[n], ch);
 }
 
 /* Test whether mod starts with modname, followed by a delimiter or '='. */
 MAKE_INLINE Boolean
-ModMatchEq(const char *mod, const char *modname, const ApplyModifiersState *st)
+ModMatchEq(const char *mod, const char *modname, const ModChain *ch)
 {
 	size_t n = strlen(modname);
 	return strncmp(mod, modname, n) == 0 &&
-	       (IsDelimiter(mod[n], st) || mod[n] == '=');
+	       (IsDelimiter(mod[n], ch) || mod[n] == '=');
 }
 
 static Boolean
@@ -2387,18 +2387,18 @@ TryParseChar(const char **pp, int base, 
  * result back in the expression.
  */
 static void
-ModifyWords(ApplyModifiersState *st,
+ModifyWords(ModChain *ch,
 	    ModifyWordProc modifyWord, void *modifyWord_args,
 	    Boolean oneBigWord)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	const char *val = expr->value.str;
 	SepBuf result;
 	Words words;
 	size_t i;
 
 	if (oneBigWord) {
-		SepBuf_Init(&result, st->sep);
+		SepBuf_Init(&result, ch->sep);
 		modifyWord(val, &result, modifyWord_args);
 		goto done;
 	}
@@ -2408,7 +2408,7 @@ ModifyWords(ApplyModifiersState *st,
 	DEBUG2(VAR, "ModifyWords: split \"%s\" into %u words\n",
 	    val, (unsigned)words.len);
 
-	SepBuf_Init(&result, st->sep);
+	SepBuf_Init(&result, ch->sep);
 	for (i = 0; i < words.len; i++) {
 		modifyWord(words.words[i], &result, modifyWord_args);
 		if (result.buf.len > 0)
@@ -2423,9 +2423,9 @@ done:
 
 /* :@var@...${var}...@ */
 static ApplyModifierResult
-ApplyModifier_Loop(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Loop(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	struct ModifyWord_LoopArgs args;
 	char prev_sep;
 	VarParseResult res;
@@ -2433,7 +2433,7 @@ ApplyModifier_Loop(const char **pp, Appl
 	args.scope = expr->scope;
 
 	(*pp)++;		/* Skip the first '@' */
-	res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, st, &args.tvar);
+	res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &args.tvar);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 	if (opts.strict && strchr(args.tvar, '$') != NULL) {
@@ -2444,7 +2444,7 @@ ApplyModifier_Loop(const char **pp, Appl
 		return AMR_CLEANUP;
 	}
 
-	res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, st, &args.str);
+	res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &args.str);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
@@ -2453,10 +2453,10 @@ ApplyModifier_Loop(const char **pp, Appl
 
 	args.eflags = expr->eflags;
 	args.eflags.keepDollar = FALSE;
-	prev_sep = st->sep;
-	st->sep = ' ';		/* XXX: should be st->sep for consistency */
-	ModifyWords(st, ModifyWord_Loop, &args, st->oneBigWord);
-	st->sep = prev_sep;
+	prev_sep = ch->sep;
+	ch->sep = ' ';		/* XXX: should be ch->sep for consistency */
+	ModifyWords(ch, ModifyWord_Loop, &args, ch->oneBigWord);
+	ch->sep = prev_sep;
 	/* XXX: Consider restoring the previous variable instead of deleting. */
 	/*
 	 * XXX: The variable name should not be expanded here, see
@@ -2472,9 +2472,9 @@ done:
 
 /* :Ddefined or :Uundefined */
 static ApplyModifierResult
-ApplyModifier_Defined(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Defined(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	Buffer buf;
 	const char *p;
 
@@ -2485,7 +2485,7 @@ ApplyModifier_Defined(const char **pp, A
 
 	Buf_Init(&buf);
 	p = *pp + 1;
-	while (!IsDelimiter(*p, st) && *p != '\0') {
+	while (!IsDelimiter(*p, ch) && *p != '\0') {
 
 		/* XXX: This code is similar to the one in Var_Parse.
 		 * See if the code can be merged.
@@ -2495,7 +2495,7 @@ ApplyModifier_Defined(const char **pp, A
 		/* See Buf_AddEscaped in for.c. */
 		if (*p == '\\') {
 			char c = p[1];
-			if (IsDelimiter(c, st) || c == '$' || c == '\\') {
+			if (IsDelimiter(c, ch) || c == '$' || c == '\\') {
 				Buf_AddByte(&buf, c);
 				p += 2;
 				continue;
@@ -2532,9 +2532,9 @@ ApplyModifier_Defined(const char **pp, A
 
 /* :L */
 static ApplyModifierResult
-ApplyModifier_Literal(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Literal(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 
 	(*pp)++;
 
@@ -2567,12 +2567,12 @@ TryParseTime(const char **pp, time_t *ou
 
 /* :gmtime */
 static ApplyModifierResult
-ApplyModifier_Gmtime(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Gmtime(const char **pp, ModChain *ch)
 {
 	time_t utc;
 
 	const char *mod = *pp;
-	if (!ModMatchEq(mod, "gmtime", st))
+	if (!ModMatchEq(mod, "gmtime", ch))
 		return AMR_UNKNOWN;
 
 	if (mod[6] == '=') {
@@ -2588,21 +2588,21 @@ ApplyModifier_Gmtime(const char **pp, Ap
 		*pp = mod + 6;
 	}
 
-	if (st->expr->eflags.wantRes)
-		Expr_SetValueOwn(st->expr,
-		    VarStrftime(st->expr->value.str, TRUE, utc));
+	if (ch->expr->eflags.wantRes)
+		Expr_SetValueOwn(ch->expr,
+		    VarStrftime(ch->expr->value.str, TRUE, utc));
 
 	return AMR_OK;
 }
 
 /* :localtime */
 static ApplyModifierResult
-ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Localtime(const char **pp, ModChain *ch)
 {
 	time_t utc;
 
 	const char *mod = *pp;
-	if (!ModMatchEq(mod, "localtime", st))
+	if (!ModMatchEq(mod, "localtime", ch))
 		return AMR_UNKNOWN;
 
 	if (mod[9] == '=') {
@@ -2618,38 +2618,38 @@ ApplyModifier_Localtime(const char **pp,
 		*pp = mod + 9;
 	}
 
-	if (st->expr->eflags.wantRes)
-		Expr_SetValueOwn(st->expr,
-		    VarStrftime(st->expr->value.str, FALSE, utc));
+	if (ch->expr->eflags.wantRes)
+		Expr_SetValueOwn(ch->expr,
+		    VarStrftime(ch->expr->value.str, FALSE, utc));
 
 	return AMR_OK;
 }
 
 /* :hash */
 static ApplyModifierResult
-ApplyModifier_Hash(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Hash(const char **pp, ModChain *ch)
 {
-	if (!ModMatch(*pp, "hash", st))
+	if (!ModMatch(*pp, "hash", ch))
 		return AMR_UNKNOWN;
 	*pp += 4;
 
-	if (st->expr->eflags.wantRes)
-		Expr_SetValueOwn(st->expr, VarHash(st->expr->value.str));
+	if (ch->expr->eflags.wantRes)
+		Expr_SetValueOwn(ch->expr, VarHash(ch->expr->value.str));
 
 	return AMR_OK;
 }
 
 /* :P */
 static ApplyModifierResult
-ApplyModifier_Path(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Path(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	GNode *gn;
 	char *path;
 
 	(*pp)++;
 
-	if (!st->expr->eflags.wantRes)
+	if (!ch->expr->eflags.wantRes)
 		return AMR_OK;
 
 	Expr_Define(expr);
@@ -2672,15 +2672,15 @@ ApplyModifier_Path(const char **pp, Appl
 
 /* :!cmd! */
 static ApplyModifierResult
-ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st)
+ApplyModifier_ShellCommand(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	char *cmd;
 	const char *errfmt;
 	VarParseResult res;
 
 	(*pp)++;
-	res = ParseModifierPart(pp, '!', expr->eflags, st, &cmd);
+	res = ParseModifierPart(pp, '!', expr->eflags, ch, &cmd);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
@@ -2702,14 +2702,14 @@ ApplyModifier_ShellCommand(const char **
  * The :range=7 modifier generates an integer sequence from 1 to 7.
  */
 static ApplyModifierResult
-ApplyModifier_Range(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Range(const char **pp, ModChain *ch)
 {
 	size_t n;
 	Buffer buf;
 	size_t i;
 
 	const char *mod = *pp;
-	if (!ModMatchEq(mod, "range", st))
+	if (!ModMatchEq(mod, "range", ch))
 		return AMR_UNKNOWN;
 
 	if (mod[5] == '=') {
@@ -2726,11 +2726,11 @@ ApplyModifier_Range(const char **pp, App
 		*pp = mod + 5;
 	}
 
-	if (!st->expr->eflags.wantRes)
+	if (!ch->expr->eflags.wantRes)
 		return AMR_OK;
 
 	if (n == 0) {
-		Words words = Str_Words(st->expr->value.str, FALSE);
+		Words words = Str_Words(ch->expr->value.str, FALSE);
 		n = words.len;
 		Words_Free(words);
 	}
@@ -2739,23 +2739,23 @@ ApplyModifier_Range(const char **pp, App
 
 	for (i = 0; i < n; i++) {
 		if (i != 0) {
-			/* XXX: Use st->sep instead of ' ', for consistency. */
+			/* XXX: Use ch->sep instead of ' ', for consistency. */
 			Buf_AddByte(&buf, ' ');
 		}
 		Buf_AddInt(&buf, 1 + (int)i);
 	}
 
-	Expr_SetValueOwn(st->expr, Buf_DoneData(&buf));
+	Expr_SetValueOwn(ch->expr, Buf_DoneData(&buf));
 	return AMR_OK;
 }
 
 /* Parse a ':M' or ':N' modifier. */
 static void
-ParseModifier_Match(const char **pp, const ApplyModifiersState *st,
+ParseModifier_Match(const char **pp, const ModChain *ch,
 		    char **out_pattern)
 {
 	const char *mod = *pp;
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	Boolean copy = FALSE;	/* pattern should be, or has been, copied */
 	Boolean needSubst = FALSE;
 	const char *endpat;
@@ -2775,7 +2775,7 @@ ParseModifier_Match(const char **pp, con
 	const char *p;
 	for (p = mod + 1; *p != '\0' && !(*p == ':' && nest == 0); p++) {
 		if (*p == '\\' &&
-		    (IsDelimiter(p[1], st) || p[1] == st->startc)) {
+		    (IsDelimiter(p[1], ch) || p[1] == ch->startc)) {
 			if (!needSubst)
 				copy = TRUE;
 			p++;
@@ -2804,8 +2804,8 @@ ParseModifier_Match(const char **pp, con
 		src = mod + 1;
 		for (; src < endpat; src++, dst++) {
 			if (src[0] == '\\' && src + 1 < endpat &&
-			    /* XXX: st->startc is missing here; see above */
-			    IsDelimiter(src[1], st))
+			    /* XXX: ch->startc is missing here; see above */
+			    IsDelimiter(src[1], ch))
 				src++;
 			*dst = *src;
 		}
@@ -2829,17 +2829,17 @@ ParseModifier_Match(const char **pp, con
 
 /* :Mpattern or :Npattern */
 static ApplyModifierResult
-ApplyModifier_Match(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Match(const char **pp, ModChain *ch)
 {
 	const char mod = **pp;
 	char *pattern;
 
-	ParseModifier_Match(pp, st, &pattern);
+	ParseModifier_Match(pp, ch, &pattern);
 
-	if (st->expr->eflags.wantRes) {
+	if (ch->expr->eflags.wantRes) {
 		ModifyWordProc modifyWord =
 		    mod == 'M' ? ModifyWord_Match : ModifyWord_NoMatch;
-		ModifyWords(st, modifyWord, pattern, st->oneBigWord);
+		ModifyWords(ch, modifyWord, pattern, ch->oneBigWord);
 	}
 
 	free(pattern);
@@ -2863,7 +2863,7 @@ ParsePatternFlags(const char **pp, VarPa
 
 /* :S,from,to, */
 static ApplyModifierResult
-ApplyModifier_Subst(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Subst(const char **pp, ModChain *ch)
 {
 	struct ModifyWord_SubstArgs args;
 	char *lhs, *rhs;
@@ -2887,22 +2887,22 @@ ApplyModifier_Subst(const char **pp, App
 		(*pp)++;
 	}
 
-	res = ParseModifierPartSubst(pp, delim, st->expr->eflags, st, &lhs,
+	res = ParseModifierPartSubst(pp, delim, ch->expr->eflags, ch, &lhs,
 	    &args.lhsLen, &args.pflags, NULL);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 	args.lhs = lhs;
 
-	res = ParseModifierPartSubst(pp, delim, st->expr->eflags, st, &rhs,
+	res = ParseModifierPartSubst(pp, delim, ch->expr->eflags, ch, &rhs,
 	    &args.rhsLen, NULL, &args);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 	args.rhs = rhs;
 
-	oneBigWord = st->oneBigWord;
+	oneBigWord = ch->oneBigWord;
 	ParsePatternFlags(pp, &args.pflags, &oneBigWord);
 
-	ModifyWords(st, ModifyWord_Subst, &args, oneBigWord);
+	ModifyWords(ch, ModifyWord_Subst, &args, oneBigWord);
 
 	free(lhs);
 	free(rhs);
@@ -2913,7 +2913,7 @@ ApplyModifier_Subst(const char **pp, App
 
 /* :C,from,to, */
 static ApplyModifierResult
-ApplyModifier_Regex(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Regex(const char **pp, ModChain *ch)
 {
 	char *re;
 	struct ModifyWord_SubstRegexArgs args;
@@ -2930,11 +2930,11 @@ ApplyModifier_Regex(const char **pp, App
 
 	*pp += 2;
 
-	res = ParseModifierPart(pp, delim, st->expr->eflags, st, &re);
+	res = ParseModifierPart(pp, delim, ch->expr->eflags, ch, &re);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	res = ParseModifierPart(pp, delim, st->expr->eflags, st, &args.replace);
+	res = ParseModifierPart(pp, delim, ch->expr->eflags, ch, &args.replace);
 	if (args.replace == NULL) {
 		free(re);
 		return AMR_CLEANUP;
@@ -2942,10 +2942,10 @@ ApplyModifier_Regex(const char **pp, App
 
 	args.pflags = (VarPatternFlags){ FALSE, FALSE, FALSE, FALSE };
 	args.matched = FALSE;
-	oneBigWord = st->oneBigWord;
+	oneBigWord = ch->oneBigWord;
 	ParsePatternFlags(pp, &args.pflags, &oneBigWord);
 
-	if (!(st->expr->eflags.wantRes)) {
+	if (!(ch->expr->eflags.wantRes)) {
 		free(args.replace);
 		free(re);
 		return AMR_OK;
@@ -2963,7 +2963,7 @@ ApplyModifier_Regex(const char **pp, App
 	if (args.nsub > 10)
 		args.nsub = 10;
 
-	ModifyWords(st, ModifyWord_SubstRegex, &args, oneBigWord);
+	ModifyWords(ch, ModifyWord_SubstRegex, &args, oneBigWord);
 
 	regfree(&args.re);
 	free(args.replace);
@@ -2974,16 +2974,16 @@ ApplyModifier_Regex(const char **pp, App
 
 /* :Q, :q */
 static ApplyModifierResult
-ApplyModifier_Quote(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Quote(const char **pp, ModChain *ch)
 {
 	Boolean quoteDollar = **pp == 'q';
-	if (!IsDelimiter((*pp)[1], st))
+	if (!IsDelimiter((*pp)[1], ch))
 		return AMR_UNKNOWN;
 	(*pp)++;
 
-	if (st->expr->eflags.wantRes)
-		Expr_SetValueOwn(st->expr,
-		    VarQuote(st->expr->value.str, quoteDollar));
+	if (ch->expr->eflags.wantRes)
+		Expr_SetValueOwn(ch->expr,
+		    VarQuote(ch->expr->value.str, quoteDollar));
 
 	return AMR_OK;
 }
@@ -2997,7 +2997,7 @@ ModifyWord_Copy(const char *word, SepBuf
 
 /* :ts<separator> */
 static ApplyModifierResult
-ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st)
+ApplyModifier_ToSep(const char **pp, ModChain *ch)
 {
 	const char *sep = *pp + 2;
 
@@ -3009,16 +3009,16 @@ ApplyModifier_ToSep(const char **pp, App
 	 */
 
 	/* ":ts<any><endc>" or ":ts<any>:" */
-	if (sep[0] != st->endc && IsDelimiter(sep[1], st)) {
+	if (sep[0] != ch->endc && IsDelimiter(sep[1], ch)) {
 		*pp = sep + 1;
-		st->sep = sep[0];
+		ch->sep = sep[0];
 		goto ok;
 	}
 
 	/* ":ts<endc>" or ":ts:" */
-	if (IsDelimiter(sep[0], st)) {
+	if (IsDelimiter(sep[0], ch)) {
 		*pp = sep;
-		st->sep = '\0';	/* no separator */
+		ch->sep = '\0';	/* no separator */
 		goto ok;
 	}
 
@@ -3031,14 +3031,14 @@ ApplyModifier_ToSep(const char **pp, App
 	/* ":ts\n" */
 	if (sep[1] == 'n') {
 		*pp = sep + 2;
-		st->sep = '\n';
+		ch->sep = '\n';
 		goto ok;
 	}
 
 	/* ":ts\t" */
 	if (sep[1] == 't') {
 		*pp = sep + 2;
-		st->sep = '\t';
+		ch->sep = '\t';
 		goto ok;
 	}
 
@@ -3055,12 +3055,12 @@ ApplyModifier_ToSep(const char **pp, App
 			return AMR_BAD;	/* ":ts<backslash><unrecognised>". */
 		}
 
-		if (!TryParseChar(&p, base, &st->sep)) {
+		if (!TryParseChar(&p, base, &ch->sep)) {
 			Parse_Error(PARSE_FATAL,
 			    "Invalid character number: %s", p);
 			return AMR_CLEANUP;
 		}
-		if (!IsDelimiter(*p, st)) {
+		if (!IsDelimiter(*p, ch)) {
 			(*pp)++;	/* just for backwards compatibility */
 			return AMR_BAD;
 		}
@@ -3069,7 +3069,7 @@ ApplyModifier_ToSep(const char **pp, App
 	}
 
 ok:
-	ModifyWords(st, ModifyWord_Copy, NULL, st->oneBigWord);
+	ModifyWords(ch, ModifyWord_Copy, NULL, ch->oneBigWord);
 	return AMR_OK;
 }
 
@@ -3103,48 +3103,48 @@ str_tolower(const char *str)
 
 /* :tA, :tu, :tl, :ts<separator>, etc. */
 static ApplyModifierResult
-ApplyModifier_To(const char **pp, ApplyModifiersState *st)
+ApplyModifier_To(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	const char *mod = *pp;
 	assert(mod[0] == 't');
 
-	if (IsDelimiter(mod[1], st) || mod[1] == '\0') {
+	if (IsDelimiter(mod[1], ch) || mod[1] == '\0') {
 		*pp = mod + 1;
 		return AMR_BAD;	/* Found ":t<endc>" or ":t:". */
 	}
 
 	if (mod[1] == 's')
-		return ApplyModifier_ToSep(pp, st);
+		return ApplyModifier_ToSep(pp, ch);
 
-	if (!IsDelimiter(mod[2], st)) {			/* :t<unrecognized> */
+	if (!IsDelimiter(mod[2], ch)) {			/* :t<unrecognized> */
 		*pp = mod + 1;
 		return AMR_BAD;
 	}
 
 	if (mod[1] == 'A') {				/* :tA */
 		*pp = mod + 2;
-		ModifyWords(st, ModifyWord_Realpath, NULL, st->oneBigWord);
+		ModifyWords(ch, ModifyWord_Realpath, NULL, ch->oneBigWord);
 		return AMR_OK;
 	}
 
 	if (mod[1] == 'u') {				/* :tu */
 		*pp = mod + 2;
-		if (st->expr->eflags.wantRes)
+		if (ch->expr->eflags.wantRes)
 			Expr_SetValueOwn(expr, str_toupper(expr->value.str));
 		return AMR_OK;
 	}
 
 	if (mod[1] == 'l') {				/* :tl */
 		*pp = mod + 2;
-		if (st->expr->eflags.wantRes)
+		if (ch->expr->eflags.wantRes)
 			Expr_SetValueOwn(expr, str_tolower(expr->value.str));
 		return AMR_OK;
 	}
 
 	if (mod[1] == 'W' || mod[1] == 'w') {		/* :tW, :tw */
 		*pp = mod + 2;
-		st->oneBigWord = mod[1] == 'W';
+		ch->oneBigWord = mod[1] == 'W';
 		return AMR_OK;
 	}
 
@@ -3155,20 +3155,20 @@ ApplyModifier_To(const char **pp, ApplyM
 
 /* :[#], :[1], :[-1..1], etc. */
 static ApplyModifierResult
-ApplyModifier_Words(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Words(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	char *estr;
 	int first, last;
 	VarParseResult res;
 	const char *p;
 
 	(*pp)++;		/* skip the '[' */
-	res = ParseModifierPart(pp, ']', expr->eflags, st, &estr);
+	res = ParseModifierPart(pp, ']', expr->eflags, ch, &estr);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	if (!IsDelimiter(**pp, st))
+	if (!IsDelimiter(**pp, ch))
 		goto bad_modifier;		/* Found junk after ']' */
 
 	if (!(expr->eflags.wantRes))
@@ -3178,7 +3178,7 @@ ApplyModifier_Words(const char **pp, App
 		goto bad_modifier;			/* Found ":[]". */
 
 	if (estr[0] == '#' && estr[1] == '\0') {	/* Found ":[#]" */
-		if (st->oneBigWord) {
+		if (ch->oneBigWord) {
 			Expr_SetValueRefer(expr, "1");
 		} else {
 			Buffer buf;
@@ -3196,12 +3196,12 @@ ApplyModifier_Words(const char **pp, App
 	}
 
 	if (estr[0] == '*' && estr[1] == '\0') {	/* Found ":[*]" */
-		st->oneBigWord = TRUE;
+		ch->oneBigWord = TRUE;
 		goto ok;
 	}
 
 	if (estr[0] == '@' && estr[1] == '\0') {	/* Found ":[@]" */
-		st->oneBigWord = FALSE;
+		ch->oneBigWord = FALSE;
 		goto ok;
 	}
 
@@ -3229,7 +3229,7 @@ ApplyModifier_Words(const char **pp, App
 	 */
 	if (first == 0 && last == 0) {
 		/* ":[0]" or perhaps ":[0..0]" */
-		st->oneBigWord = TRUE;
+		ch->oneBigWord = TRUE;
 		goto ok;
 	}
 
@@ -3240,7 +3240,7 @@ ApplyModifier_Words(const char **pp, App
 	/* Normal case: select the words described by first and last. */
 	Expr_SetValueOwn(expr,
 	    VarSelectWords(expr->value.str, first, last,
-	        st->sep, st->oneBigWord));
+	        ch->sep, ch->oneBigWord));
 
 ok:
 	free(estr);
@@ -3278,7 +3278,7 @@ ShuffleStrings(char **strs, size_t n)
 
 /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
 static ApplyModifierResult
-ApplyModifier_Order(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Order(const char **pp, ModChain *ch)
 {
 	const char *mod = (*pp)++;	/* skip past the 'O' in any case */
 	Words words;
@@ -3286,34 +3286,34 @@ ApplyModifier_Order(const char **pp, App
 		ASC, DESC, SHUFFLE
 	} mode;
 
-	if (IsDelimiter(mod[1], st)) {
+	if (IsDelimiter(mod[1], ch)) {
 		mode = ASC;
 	} else if ((mod[1] == 'r' || mod[1] == 'x') &&
-	    IsDelimiter(mod[2], st)) {
+	    IsDelimiter(mod[2], ch)) {
 		(*pp)++;
 		mode = mod[1] == 'r' ? DESC : SHUFFLE;
 	} else
 		return AMR_BAD;
 
-	if (!st->expr->eflags.wantRes)
+	if (!ch->expr->eflags.wantRes)
 		return AMR_OK;
 
-	words = Str_Words(st->expr->value.str, FALSE);
+	words = Str_Words(ch->expr->value.str, FALSE);
 	if (mode == SHUFFLE)
 		ShuffleStrings(words.words, words.len);
 	else
 		qsort(words.words, words.len, sizeof words.words[0],
 		    mode == ASC ? str_cmp_asc : str_cmp_desc);
-	Expr_SetValueOwn(st->expr, Words_JoinFree(words));
+	Expr_SetValueOwn(ch->expr, Words_JoinFree(words));
 
 	return AMR_OK;
 }
 
 /* :? then : else */
 static ApplyModifierResult
-ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st)
+ApplyModifier_IfElse(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	char *then_expr, *else_expr;
 	VarParseResult res;
 
@@ -3331,15 +3331,15 @@ ApplyModifier_IfElse(const char **pp, Ap
 	}
 
 	(*pp)++;			/* skip past the '?' */
-	res = ParseModifierPart(pp, ':', then_eflags, st, &then_expr);
+	res = ParseModifierPart(pp, ':', then_eflags, ch, &then_expr);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	res = ParseModifierPart(pp, st->endc, else_eflags, st, &else_expr);
+	res = ParseModifierPart(pp, ch->endc, else_eflags, ch, &else_expr);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	(*pp)--;		/* Go back to the st->endc. */
+	(*pp)--;		/* Go back to the ch->endc. */
 
 	if (cond_rc == COND_INVALID) {
 		Error("Bad conditional expression `%s' in %s?%s:%s",
@@ -3385,9 +3385,9 @@ ApplyModifier_IfElse(const char **pp, Ap
  *			variable.
  */
 static ApplyModifierResult
-ApplyModifier_Assign(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Assign(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	GNode *scope;
 	char *val;
 	VarParseResult res;
@@ -3418,11 +3418,11 @@ ok:
 		break;
 	}
 
-	res = ParseModifierPart(pp, st->endc, expr->eflags, st, &val);
+	res = ParseModifierPart(pp, ch->endc, expr->eflags, ch, &val);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	(*pp)--;		/* Go back to the st->endc. */
+	(*pp)--;		/* Go back to the ch->endc. */
 
 	if (!expr->eflags.wantRes)
 		goto done;
@@ -3470,13 +3470,13 @@ done:
  * remember current value
  */
 static ApplyModifierResult
-ApplyModifier_Remember(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Remember(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	const char *mod = *pp;
 	FStr name;
 
-	if (!ModMatchEq(mod, "_", st))
+	if (!ModMatchEq(mod, "_", ch))
 		return AMR_UNKNOWN;
 
 	name = FStr_InitRefer("_");
@@ -3505,28 +3505,28 @@ ApplyModifier_Remember(const char **pp, 
  * for a single-letter modifier such as :H, :T.
  */
 static ApplyModifierResult
-ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st,
+ApplyModifier_WordFunc(const char **pp, ModChain *ch,
 		       ModifyWordProc modifyWord)
 {
-	if (!IsDelimiter((*pp)[1], st))
+	if (!IsDelimiter((*pp)[1], ch))
 		return AMR_UNKNOWN;
 	(*pp)++;
 
-	if (st->expr->eflags.wantRes)
-		ModifyWords(st, modifyWord, NULL, st->oneBigWord);
+	if (ch->expr->eflags.wantRes)
+		ModifyWords(ch, modifyWord, NULL, ch->oneBigWord);
 
 	return AMR_OK;
 }
 
 static ApplyModifierResult
-ApplyModifier_Unique(const char **pp, ApplyModifiersState *st)
+ApplyModifier_Unique(const char **pp, ModChain *ch)
 {
-	if (!IsDelimiter((*pp)[1], st))
+	if (!IsDelimiter((*pp)[1], ch))
 		return AMR_UNKNOWN;
 	(*pp)++;
 
-	if (st->expr->eflags.wantRes)
-		Expr_SetValueOwn(st->expr, VarUniq(st->expr->value.str));
+	if (ch->expr->eflags.wantRes)
+		Expr_SetValueOwn(ch->expr, VarUniq(ch->expr->value.str));
 
 	return AMR_OK;
 }
@@ -3534,9 +3534,9 @@ ApplyModifier_Unique(const char **pp, Ap
 #ifdef SYSVVARSUB
 /* :from=to */
 static ApplyModifierResult
-ApplyModifier_SysV(const char **pp, ApplyModifiersState *st)
+ApplyModifier_SysV(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	char *lhs, *rhs;
 	VarParseResult res;
 
@@ -3552,27 +3552,27 @@ ApplyModifier_SysV(const char **pp, Appl
 	while (*p != '\0' && depth > 0) {
 		if (*p == '=') {	/* XXX: should also test depth == 1 */
 			eqFound = TRUE;
-			/* continue looking for st->endc */
-		} else if (*p == st->endc)
+			/* continue looking for ch->endc */
+		} else if (*p == ch->endc)
 			depth--;
-		else if (*p == st->startc)
+		else if (*p == ch->startc)
 			depth++;
 		if (depth > 0)
 			p++;
 	}
-	if (*p != st->endc || !eqFound)
+	if (*p != ch->endc || !eqFound)
 		return AMR_UNKNOWN;
 
-	res = ParseModifierPart(pp, '=', expr->eflags, st, &lhs);
+	res = ParseModifierPart(pp, '=', expr->eflags, ch, &lhs);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
 	/* The SysV modifier lasts until the end of the variable expression. */
-	res = ParseModifierPart(pp, st->endc, expr->eflags, st, &rhs);
+	res = ParseModifierPart(pp, ch->endc, expr->eflags, ch, &rhs);
 	if (res != VPR_OK)
 		return AMR_CLEANUP;
 
-	(*pp)--;		/* Go back to the st->endc. */
+	(*pp)--;		/* Go back to the ch->endc. */
 
 	if (lhs[0] == '\0' && expr->value.str[0] == '\0') {
 		/* Do not turn an empty expression into non-empty. */
@@ -3580,7 +3580,7 @@ ApplyModifier_SysV(const char **pp, Appl
 		struct ModifyWord_SYSVSubstArgs args = {
 		    expr->scope, lhs, rhs
 		};
-		ModifyWords(st, ModifyWord_SYSVSubst, &args, st->oneBigWord);
+		ModifyWords(ch, ModifyWord_SYSVSubst, &args, ch->oneBigWord);
 	}
 	free(lhs);
 	free(rhs);
@@ -3591,11 +3591,11 @@ ApplyModifier_SysV(const char **pp, Appl
 #ifdef SUNSHCMD
 /* :sh */
 static ApplyModifierResult
-ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st)
+ApplyModifier_SunShell(const char **pp, ModChain *ch)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	const char *p = *pp;
-	if (!(p[1] == 'h' && IsDelimiter(p[2], st)))
+	if (!(p[1] == 'h' && IsDelimiter(p[2], ch)))
 		return AMR_UNKNOWN;
 	*pp = p + 2;
 
@@ -3612,11 +3612,11 @@ ApplyModifier_SunShell(const char **pp, 
 #endif
 
 static void
-LogBeforeApply(const ApplyModifiersState *st, const char *mod)
+LogBeforeApply(const ModChain *ch, const char *mod)
 {
-	const Expr *expr = st->expr;
+	const Expr *expr = ch->expr;
 	char vflags_str[VarFlags_ToStringSize];
-	Boolean is_single_char = mod[0] != '\0' && IsDelimiter(mod[1], st);
+	Boolean is_single_char = mod[0] != '\0' && IsDelimiter(mod[1], ch);
 
 	/* At this point, only the first character of the modifier can
 	 * be used since the end of the modifier is not yet known. */
@@ -3629,9 +3629,9 @@ LogBeforeApply(const ApplyModifiersState
 }
 
 static void
-LogAfterApply(const ApplyModifiersState *st, const char *p, const char *mod)
+LogAfterApply(const ModChain *ch, const char *p, const char *mod)
 {
-	const Expr *expr = st->expr;
+	const Expr *expr = ch->expr;
 	const char *value = expr->value.str;
 	char vflags_str[VarFlags_ToStringSize];
 	const char *quot = value == var_Error ? "" : "\"";
@@ -3645,67 +3645,67 @@ LogAfterApply(const ApplyModifiersState 
 }
 
 static ApplyModifierResult
-ApplyModifier(const char **pp, ApplyModifiersState *st)
+ApplyModifier(const char **pp, ModChain *ch)
 {
 	switch (**pp) {
 	case '!':
-		return ApplyModifier_ShellCommand(pp, st);
+		return ApplyModifier_ShellCommand(pp, ch);
 	case ':':
-		return ApplyModifier_Assign(pp, st);
+		return ApplyModifier_Assign(pp, ch);
 	case '?':
-		return ApplyModifier_IfElse(pp, st);
+		return ApplyModifier_IfElse(pp, ch);
 	case '@':
-		return ApplyModifier_Loop(pp, st);
+		return ApplyModifier_Loop(pp, ch);
 	case '[':
-		return ApplyModifier_Words(pp, st);
+		return ApplyModifier_Words(pp, ch);
 	case '_':
-		return ApplyModifier_Remember(pp, st);
+		return ApplyModifier_Remember(pp, ch);
 #ifndef NO_REGEX
 	case 'C':
-		return ApplyModifier_Regex(pp, st);
+		return ApplyModifier_Regex(pp, ch);
 #endif
 	case 'D':
-		return ApplyModifier_Defined(pp, st);
+		return ApplyModifier_Defined(pp, ch);
 	case 'E':
-		return ApplyModifier_WordFunc(pp, st, ModifyWord_Suffix);
+		return ApplyModifier_WordFunc(pp, ch, ModifyWord_Suffix);
 	case 'g':
-		return ApplyModifier_Gmtime(pp, st);
+		return ApplyModifier_Gmtime(pp, ch);
 	case 'H':
-		return ApplyModifier_WordFunc(pp, st, ModifyWord_Head);
+		return ApplyModifier_WordFunc(pp, ch, ModifyWord_Head);
 	case 'h':
-		return ApplyModifier_Hash(pp, st);
+		return ApplyModifier_Hash(pp, ch);
 	case 'L':
-		return ApplyModifier_Literal(pp, st);
+		return ApplyModifier_Literal(pp, ch);
 	case 'l':
-		return ApplyModifier_Localtime(pp, st);
+		return ApplyModifier_Localtime(pp, ch);
 	case 'M':
 	case 'N':
-		return ApplyModifier_Match(pp, st);
+		return ApplyModifier_Match(pp, ch);
 	case 'O':
-		return ApplyModifier_Order(pp, st);
+		return ApplyModifier_Order(pp, ch);
 	case 'P':
-		return ApplyModifier_Path(pp, st);
+		return ApplyModifier_Path(pp, ch);
 	case 'Q':
 	case 'q':
-		return ApplyModifier_Quote(pp, st);
+		return ApplyModifier_Quote(pp, ch);
 	case 'R':
-		return ApplyModifier_WordFunc(pp, st, ModifyWord_Root);
+		return ApplyModifier_WordFunc(pp, ch, ModifyWord_Root);
 	case 'r':
-		return ApplyModifier_Range(pp, st);
+		return ApplyModifier_Range(pp, ch);
 	case 'S':
-		return ApplyModifier_Subst(pp, st);
+		return ApplyModifier_Subst(pp, ch);
 #ifdef SUNSHCMD
 	case 's':
-		return ApplyModifier_SunShell(pp, st);
+		return ApplyModifier_SunShell(pp, ch);
 #endif
 	case 'T':
-		return ApplyModifier_WordFunc(pp, st, ModifyWord_Tail);
+		return ApplyModifier_WordFunc(pp, ch, ModifyWord_Tail);
 	case 't':
-		return ApplyModifier_To(pp, st);
+		return ApplyModifier_To(pp, ch);
 	case 'U':
-		return ApplyModifier_Defined(pp, st);
+		return ApplyModifier_Defined(pp, ch);
 	case 'u':
-		return ApplyModifier_Unique(pp, st);
+		return ApplyModifier_Unique(pp, ch);
 	default:
 		return AMR_UNKNOWN;
 	}
@@ -3732,20 +3732,20 @@ typedef enum ApplyModifiersIndirectResul
  * Multiple groups of indirect modifiers can be chained by separating them
  * with colons.  ${VAR:${M1}:${M2}} contains 2 indirect modifiers.
  *
- * If the variable expression is not followed by st->endc or ':', fall
+ * If the variable expression is not followed by ch->endc or ':', fall
  * back to trying the SysV modifier, such as in ${VAR:${FROM}=${TO}}.
  */
 static ApplyModifiersIndirectResult
-ApplyModifiersIndirect(ApplyModifiersState *st, const char **pp)
+ApplyModifiersIndirect(ModChain *ch, const char **pp)
 {
-	Expr *expr = st->expr;
+	Expr *expr = ch->expr;
 	const char *p = *pp;
 	FStr mods;
 
 	(void)Var_Parse(&p, expr->scope, expr->eflags, &mods);
 	/* TODO: handle errors */
 
-	if (mods.str[0] != '\0' && *p != '\0' && !IsDelimiter(*p, st)) {
+	if (mods.str[0] != '\0' && *p != '\0' && !IsDelimiter(*p, ch)) {
 		FStr_Done(&mods);
 		return AMIR_SYSV;
 	}
@@ -3766,10 +3766,10 @@ ApplyModifiersIndirect(ApplyModifiersSta
 
 	if (*p == ':')
 		p++;
-	else if (*p == '\0' && st->endc != '\0') {
+	else if (*p == '\0' && ch->endc != '\0') {
 		Error("Unclosed variable expression after indirect "
 		      "modifier, expecting '%c' for variable \"%s\"",
-		    st->endc, expr->var->name.str);
+		    ch->endc, expr->var->name.str);
 		*pp = p;
 		return AMIR_OUT;
 	}
@@ -3779,21 +3779,21 @@ ApplyModifiersIndirect(ApplyModifiersSta
 }
 
 static ApplyModifierResult
-ApplySingleModifier(const char **pp, ApplyModifiersState *st)
+ApplySingleModifier(const char **pp, ModChain *ch)
 {
 	ApplyModifierResult res;
 	const char *mod = *pp;
 	const char *p = *pp;
 
 	if (DEBUG(VAR))
-		LogBeforeApply(st, mod);
+		LogBeforeApply(ch, mod);
 
-	res = ApplyModifier(&p, st);
+	res = ApplyModifier(&p, ch);
 
 #ifdef SYSVVARSUB
 	if (res == AMR_UNKNOWN) {
 		assert(p == mod);
-		res = ApplyModifier_SysV(&p, st);
+		res = ApplyModifier_SysV(&p, ch);
 	}
 #endif
 
@@ -3804,11 +3804,11 @@ ApplySingleModifier(const char **pp, App
 		 * errors and leads to wrong results.
 		 * Parsing should rather stop here.
 		 */
-		for (p++; !IsDelimiter(*p, st) && *p != '\0'; p++)
+		for (p++; !IsDelimiter(*p, ch) && *p != '\0'; p++)
 			continue;
 		Parse_Error(PARSE_FATAL, "Unknown modifier \"%.*s\"",
 		    (int)(p - mod), mod);
-		Expr_SetValueRefer(st->expr, var_Error);
+		Expr_SetValueRefer(ch->expr, var_Error);
 	}
 	if (res == AMR_CLEANUP || res == AMR_BAD) {
 		*pp = p;
@@ -3816,18 +3816,18 @@ ApplySingleModifier(const char **pp, App
 	}
 
 	if (DEBUG(VAR))
-		LogAfterApply(st, p, mod);
+		LogAfterApply(ch, p, mod);
 
-	if (*p == '\0' && st->endc != '\0') {
+	if (*p == '\0' && ch->endc != '\0') {
 		Error(
 		    "Unclosed variable expression, expecting '%c' for "
 		    "modifier \"%.*s\" of variable \"%s\" with value \"%s\"",
-		    st->endc,
+		    ch->endc,
 		    (int)(p - mod), mod,
-		    st->expr->var->name.str, st->expr->value.str);
+		    ch->expr->var->name.str, ch->expr->value.str);
 	} else if (*p == ':') {
 		p++;
-	} else if (opts.strict && *p != '\0' && *p != st->endc) {
+	} else if (opts.strict && *p != '\0' && *p != ch->endc) {
 		Parse_Error(PARSE_FATAL,
 		    "Missing delimiter ':' after modifier \"%.*s\"",
 		    (int)(p - mod), mod);
@@ -3849,7 +3849,7 @@ ApplyModifiers(
     char endc		/* ')' or '}'; or '\0' for indirect modifiers */
 )
 {
-	ApplyModifiersState st = {
+	ModChain ch = {
 	    expr,
 	    startc,
 	    endc,
@@ -3868,7 +3868,7 @@ ApplyModifiers(
 	if (*p == '\0' && endc != '\0') {
 		Error(
 		    "Unclosed variable expression (expecting '%c') for \"%s\"",
-		    st.endc, expr->var->name.str);
+		    ch.endc, expr->var->name.str);
 		goto cleanup;
 	}
 
@@ -3877,7 +3877,7 @@ ApplyModifiers(
 
 		if (*p == '$') {
 			ApplyModifiersIndirectResult amir =
-			    ApplyModifiersIndirect(&st, &p);
+			    ApplyModifiersIndirect(&ch, &p);
 			if (amir == AMIR_CONTINUE)
 				continue;
 			if (amir == AMIR_OUT)
@@ -3891,7 +3891,7 @@ ApplyModifiers(
 
 		mod = p;
 
-		res = ApplySingleModifier(&p, &st);
+		res = ApplySingleModifier(&p, &ch);
 		if (res == AMR_CLEANUP)
 			goto cleanup;
 		if (res == AMR_BAD)

Index: src/usr.bin/make/unit-tests/varmod-indirect.mk
diff -u src/usr.bin/make/unit-tests/varmod-indirect.mk:1.8 src/usr.bin/make/unit-tests/varmod-indirect.mk:1.9
--- src/usr.bin/make/unit-tests/varmod-indirect.mk:1.8	Sun Feb 14 17:47:33 2021
+++ src/usr.bin/make/unit-tests/varmod-indirect.mk	Mon Mar 15 20:00:50 2021
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-indirect.mk,v 1.8 2021/02/14 17:47:33 rillig Exp $
+# $NetBSD: varmod-indirect.mk,v 1.9 2021/03/15 20:00:50 rillig Exp $
 #
 # Tests for indirect variable modifiers, such as in ${VAR:${M_modifiers}}.
 # These can be used for very basic purposes like converting a string to either
@@ -221,7 +221,7 @@ _:=	before ${UNDEF:${:UZ}} after
 # the ':M' since that is not part of the text from the indirect modifier.
 #
 # Implementation detail: when ApplyModifiersIndirect calls ApplyModifiers
-# (which creates a new ApplyModifiersState containing a fresh separator),
+# (which creates a new ModChain containing a fresh separator),
 # the outer separator character is not passed by reference to the inner
 # evaluation, therefore the scope of the inner separator ends after applying
 # the modifier ':ts*'.

Reply via email to