Module Name:    src
Committed By:   rillig
Date:           Tue May  9 16:27:00 UTC 2023

Modified Files:
        src/usr.bin/make: var.c
        src/usr.bin/make/unit-tests: var-eval-short.exp var-eval-short.mk
            varmod-gmtime.exp varmod-gmtime.mk varmod-localtime.exp
            varmod-localtime.mk

Log Message:
make: allow ':gmtime' and ':localtime' with dynamic argument

This allows ${%Y:L:gmtime=${mtime}} instead of the indirect
${%Y:L:${:Ugmtime=${mtime}}}.

The direct form also prevents any ':' from the nested expression to be
interpreted as a separator, which doesn't matter for the ':gmtime' and
':localtime' modifiers but will prove useful for other modifiers that
follow the same pattern.


To generate a diff of this commit:
cvs rdiff -u -r1.1049 -r1.1050 src/usr.bin/make/var.c
cvs rdiff -u -r1.21 -r1.22 src/usr.bin/make/unit-tests/var-eval-short.exp
cvs rdiff -u -r1.8 -r1.9 src/usr.bin/make/unit-tests/var-eval-short.mk
cvs rdiff -u -r1.13 -r1.14 src/usr.bin/make/unit-tests/varmod-gmtime.exp
cvs rdiff -u -r1.11 -r1.12 src/usr.bin/make/unit-tests/varmod-gmtime.mk
cvs rdiff -u -r1.10 -r1.11 src/usr.bin/make/unit-tests/varmod-localtime.exp
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/make/unit-tests/varmod-localtime.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.1049 src/usr.bin/make/var.c:1.1050
--- src/usr.bin/make/var.c:1.1049	Tue Mar 28 14:39:31 2023
+++ src/usr.bin/make/var.c	Tue May  9 16:26:59 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.1050 2023/05/09 16:26:59 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -139,7 +139,7 @@
 #include "metachar.h"
 
 /*	"@(#)var.c	8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1050 2023/05/09 16:26:59 rillig Exp $");
 
 /*
  * Variables are defined using one of the VAR=value assignments.  Their
@@ -2188,6 +2188,8 @@ ParseModifierPartBalanced(const char **p
 static bool
 ParseModifierPartSubst(
     const char **pp,
+    /* If true, parse up to but excluding the next ':' or ch->endc. */
+    bool whole,
     char delim,
     VarEvalMode emode,
     ModChain *ch,
@@ -2205,11 +2207,14 @@ ParseModifierPartSubst(
 )
 {
 	const char *p;
+	char end1, end2;
 
 	p = *pp;
 	LazyBuf_Init(part, p);
 
-	while (*p != '\0' && *p != delim) {
+	end1 = whole ? ':' : delim;
+	end2 = whole ? ch->endc : delim;
+	while (*p != '\0' && *p != end1 && *p != end2) {
 		if (IsEscapedModifierPart(p, delim, subst)) {
 			LazyBuf_Add(part, p[1]);
 			p += 2;
@@ -2231,15 +2236,15 @@ ParseModifierPartSubst(
 			ParseModifierPartExpr(&p, part, ch, emode);
 	}
 
-	if (*p != delim) {
-		*pp = p;
+	*pp = p;
+	if (*p != end1 && *p != end2) {
 		Error("Unfinished modifier for \"%s\" ('%c' missing)",
-		    ch->expr->name, delim);
+		    ch->expr->name, end2);
 		LazyBuf_Done(part);
 		return false;
 	}
-
-	*pp = p + 1;
+	if (!whole)
+		(*pp)++;
 
 	{
 		Substring sub = LazyBuf_Get(part);
@@ -2272,7 +2277,8 @@ ParseModifierPart(
     LazyBuf *part
 )
 {
-	return ParseModifierPartSubst(pp, delim, emode, ch, part, NULL, NULL);
+	return ParseModifierPartSubst(pp, false, delim, emode, ch, part,
+	    NULL, NULL);
 }
 
 MAKE_INLINE bool
@@ -2568,11 +2574,23 @@ ApplyModifier_Time(const char **pp, ModC
 
 	if (args[0] == '=') {
 		const char *p = args + 1;
-		if (!TryParseTime(&p, &t)) {
-			Parse_Error(PARSE_FATAL,
-			    "Invalid time value at \"%s\"", p);
+		LazyBuf buf;
+		if (!ParseModifierPartSubst(&p, true, '\0', ch->expr->emode,
+		    ch, &buf, NULL, NULL))
 			return AMR_CLEANUP;
-		}
+		if (ModChain_ShouldEval(ch)) {
+			Substring arg = LazyBuf_Get(&buf);
+			const char *arg_p = arg.start;
+			if (!TryParseTime(&arg_p, &t) || arg_p != arg.end) {
+				Parse_Error(PARSE_FATAL,
+				    "Invalid time value \"%.*s\"",
+				    (int)Substring_Length(arg), arg.start);
+				LazyBuf_Done(&buf);
+				return AMR_CLEANUP;
+			}
+		} else
+			t = 0;
+		LazyBuf_Done(&buf);
 		*pp = p;
 	} else {
 		t = 0;
@@ -2862,13 +2880,13 @@ ApplyModifier_Subst(const char **pp, Mod
 		(*pp)++;
 	}
 
-	if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &lhsBuf,
-	    &args.pflags, NULL))
+	if (!ParseModifierPartSubst(pp,
+	    false, delim, ch->expr->emode, ch, &lhsBuf, &args.pflags, NULL))
 		return AMR_CLEANUP;
 	args.lhs = LazyBuf_Get(&lhsBuf);
 
-	if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &rhsBuf,
-	    NULL, &args)) {
+	if (!ParseModifierPartSubst(pp,
+	    false, delim, ch->expr->emode, ch, &rhsBuf, NULL, &args)) {
 		LazyBuf_Done(&lhsBuf);
 		return AMR_CLEANUP;
 	}

Index: src/usr.bin/make/unit-tests/var-eval-short.exp
diff -u src/usr.bin/make/unit-tests/var-eval-short.exp:1.21 src/usr.bin/make/unit-tests/var-eval-short.exp:1.22
--- src/usr.bin/make/unit-tests/var-eval-short.exp:1.21	Sat Feb 18 11:16:09 2023
+++ src/usr.bin/make/unit-tests/var-eval-short.exp	Tue May  9 16:27:00 2023
@@ -1,9 +1,5 @@
 make: "var-eval-short.mk" line 44: In the :@ modifier of "", the variable name "${FAIL}" must not contain a dollar
 make: "var-eval-short.mk" line 44: Malformed conditional (0 && ${:Uword:@${FAIL}@expr@})
-make: "var-eval-short.mk" line 84: Invalid time value at "${FAIL}}"
-make: "var-eval-short.mk" line 84: Malformed conditional (0 && ${:Uword:gmtime=${FAIL}})
-make: "var-eval-short.mk" line 98: Invalid time value at "${FAIL}}"
-make: "var-eval-short.mk" line 98: Malformed conditional (0 && ${:Uword:localtime=${FAIL}})
 CondParser_Eval: 0 && ${0:?${FAIL}then:${FAIL}else}
 Var_Parse: ${0:?${FAIL}then:${FAIL}else} (parse-only)
 Parsing modifier ${0:?...}
@@ -12,7 +8,7 @@ Modifier part: "${FAIL}then"
 Var_Parse: ${FAIL}else} (parse-only)
 Modifier part: "${FAIL}else"
 Result of ${0:?${FAIL}then:${FAIL}else} is "" (parse-only, defined)
-Parsing line 163: DEFINED=	defined
+Parsing line 165: DEFINED=	defined
 Global: DEFINED = defined
 CondParser_Eval: 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
 Var_Parse: ${DEFINED:L:?${FAIL}then:${FAIL}else} (parse-only)
@@ -24,7 +20,7 @@ Modifier part: "${FAIL}then"
 Var_Parse: ${FAIL}else} (parse-only)
 Modifier part: "${FAIL}else"
 Result of ${DEFINED:?${FAIL}then:${FAIL}else} is "defined" (parse-only, regular)
-Parsing line 166: .MAKEFLAGS: -d0
+Parsing line 168: .MAKEFLAGS: -d0
 ParseDependency(.MAKEFLAGS: -d0)
 Global: .MAKEFLAGS =  -r -k -d cpv -d
 Global: .MAKEFLAGS =  -r -k -d cpv -d 0

Index: src/usr.bin/make/unit-tests/var-eval-short.mk
diff -u src/usr.bin/make/unit-tests/var-eval-short.mk:1.8 src/usr.bin/make/unit-tests/var-eval-short.mk:1.9
--- src/usr.bin/make/unit-tests/var-eval-short.mk:1.8	Mon Dec 27 18:54:19 2021
+++ src/usr.bin/make/unit-tests/var-eval-short.mk	Tue May  9 16:27:00 2023
@@ -1,4 +1,4 @@
-# $NetBSD: var-eval-short.mk,v 1.8 2021/12/27 18:54:19 rillig Exp $
+# $NetBSD: var-eval-short.mk,v 1.9 2023/05/09 16:27:00 rillig Exp $
 #
 # Tests for each variable modifier to ensure that they only do the minimum
 # necessary computations.  If the result of the expression is irrelevant,
@@ -79,8 +79,9 @@ DEFINED=	# defined
 .if 0 && ${:Uword:E}
 .endif
 
-# As of 2021-03-14, the error 'Invalid time value: ${FAIL}}' is ok since
-# ':gmtime' does not expand its argument.
+# Before var.c 1.1050 from 2023-05-09, the ':gmtime' modifier produced the
+# error message 'Invalid time value: ${FAIL}}' since it did not expand its
+# argument.
 .if 0 && ${:Uword:gmtime=${FAIL}}
 .endif
 
@@ -93,8 +94,9 @@ DEFINED=	# defined
 .if 0 && ${value:L}
 .endif
 
-# As of 2021-03-14, the error 'Invalid time value: ${FAIL}}' is ok since
-# ':localtime' does not expand its argument.
+# Before var.c 1.1050 from 2023-05-09, the ':localtime' modifier produced the
+# error message 'Invalid time value: ${FAIL}}' since it did not expand its
+# argument.
 .if 0 && ${:Uword:localtime=${FAIL}}
 .endif
 

Index: src/usr.bin/make/unit-tests/varmod-gmtime.exp
diff -u src/usr.bin/make/unit-tests/varmod-gmtime.exp:1.13 src/usr.bin/make/unit-tests/varmod-gmtime.exp:1.14
--- src/usr.bin/make/unit-tests/varmod-gmtime.exp:1.13	Tue May  9 08:26:14 2023
+++ src/usr.bin/make/unit-tests/varmod-gmtime.exp	Tue May  9 16:27:00 2023
@@ -1,13 +1,13 @@
-make: "varmod-gmtime.mk" line 60: Invalid time value at "${:U1593536400}} != "mtime=11593536400}""
-make: "varmod-gmtime.mk" line 60: Malformed conditional (${%Y:L:gmtime=${:U1593536400}} != "mtime=11593536400}")
-make: "varmod-gmtime.mk" line 70: Invalid time value at "-1} != """
+make: "varmod-gmtime.mk" line 70: Invalid time value "-1"
 make: "varmod-gmtime.mk" line 70: Malformed conditional (${:L:gmtime=-1} != "")
-make: "varmod-gmtime.mk" line 79: Invalid time value at " 1} != """
+make: "varmod-gmtime.mk" line 79: Invalid time value " 1"
 make: "varmod-gmtime.mk" line 79: Malformed conditional (${:L:gmtime= 1} != "")
-make: "varmod-gmtime.mk" line 125: Invalid time value at "10000000000000000000000000000000} != """
+make: "varmod-gmtime.mk" line 125: Invalid time value "10000000000000000000000000000000"
 make: "varmod-gmtime.mk" line 125: Malformed conditional (${:L:gmtime=10000000000000000000000000000000} != "")
-make: "varmod-gmtime.mk" line 136: Invalid time value at "error} != """
+make: "varmod-gmtime.mk" line 136: Invalid time value "error"
 make: "varmod-gmtime.mk" line 136: Malformed conditional (${:L:gmtime=error} != "")
+make: "varmod-gmtime.mk" line 145: Invalid time value "100000S,1970,bad,"
+make: "varmod-gmtime.mk" line 145: Malformed conditional (${%Y:L:gmtime=100000S,1970,bad,} != "bad")
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1

Index: src/usr.bin/make/unit-tests/varmod-gmtime.mk
diff -u src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.11 src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.12
--- src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.11	Tue May  9 08:26:14 2023
+++ src/usr.bin/make/unit-tests/varmod-gmtime.mk	Tue May  9 16:27:00 2023
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-gmtime.mk,v 1.11 2023/05/09 08:26:14 rillig Exp $
+# $NetBSD: varmod-gmtime.mk,v 1.12 2023/05/09 16:27:00 rillig Exp $
 #
 # Tests for the :gmtime variable modifier, which formats a timestamp
 # using strftime(3) in UTC.
@@ -44,20 +44,20 @@
 .endif
 
 
-# As of 2020-08-16, it is not possible to pass the seconds via a
-# variable expression.  This is because parsing of the :gmtime
-# modifier stops at the '$' and returns to ApplyModifiers.
-#
-# There, a colon would be skipped but not a dollar.
-# Parsing therefore continues at the '$' of the ${:U159...}, looking
-# for an ordinary variable modifier.
-#
-# At this point, the ${:U} is expanded and interpreted as a variable
-# modifier, which results in the error message "Unknown modifier '1'".
-#
-# If ApplyModifier_Gmtime were to pass its argument through
-# ParseModifierPart, this would work.
-.if ${%Y:L:gmtime=${:U1593536400}} != "mtime=11593536400}"
+# Before var.c 1.1050 from 2023-05-09, it was not possible to pass the
+# seconds via a variable expression.
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+.if ${%Y:L:gmtime=${:U1593536400}} != "2020"
 .  error
 .endif
 
@@ -139,7 +139,7 @@
 .  error
 .endif
 
-# Before var.c 1.TODO from XXXX-XX-XX, the timestamp could be directly
+# Before var.c 1.1050 from 2023-05-09, the timestamp could be directly
 # followed by the next modifier, without a ':' separator.  This is the same
 # bug as for the ':L' and ':P' modifiers.
 .if ${%Y:L:gmtime=100000S,1970,bad,} != "bad"

Index: src/usr.bin/make/unit-tests/varmod-localtime.exp
diff -u src/usr.bin/make/unit-tests/varmod-localtime.exp:1.10 src/usr.bin/make/unit-tests/varmod-localtime.exp:1.11
--- src/usr.bin/make/unit-tests/varmod-localtime.exp:1.10	Tue May  9 08:26:14 2023
+++ src/usr.bin/make/unit-tests/varmod-localtime.exp	Tue May  9 16:27:00 2023
@@ -1,13 +1,13 @@
-make: "varmod-localtime.mk" line 60: Invalid time value at "${:U1593536400}} != "mtime=11593536400}""
-make: "varmod-localtime.mk" line 60: Malformed conditional (${%Y:L:localtime=${:U1593536400}} != "mtime=11593536400}")
-make: "varmod-localtime.mk" line 70: Invalid time value at "-1} != """
+make: "varmod-localtime.mk" line 70: Invalid time value "-1"
 make: "varmod-localtime.mk" line 70: Malformed conditional (${:L:localtime=-1} != "")
-make: "varmod-localtime.mk" line 79: Invalid time value at " 1} != """
+make: "varmod-localtime.mk" line 79: Invalid time value " 1"
 make: "varmod-localtime.mk" line 79: Malformed conditional (${:L:localtime= 1} != "")
-make: "varmod-localtime.mk" line 125: Invalid time value at "10000000000000000000000000000000} != """
+make: "varmod-localtime.mk" line 125: Invalid time value "10000000000000000000000000000000"
 make: "varmod-localtime.mk" line 125: Malformed conditional (${:L:localtime=10000000000000000000000000000000} != "")
-make: "varmod-localtime.mk" line 136: Invalid time value at "error} != """
+make: "varmod-localtime.mk" line 136: Invalid time value "error"
 make: "varmod-localtime.mk" line 136: Malformed conditional (${:L:localtime=error} != "")
+make: "varmod-localtime.mk" line 145: Invalid time value "100000S,1970,bad,"
+make: "varmod-localtime.mk" line 145: Malformed conditional (${%Y:L:localtime=100000S,1970,bad,} != "bad")
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1

Index: src/usr.bin/make/unit-tests/varmod-localtime.mk
diff -u src/usr.bin/make/unit-tests/varmod-localtime.mk:1.9 src/usr.bin/make/unit-tests/varmod-localtime.mk:1.10
--- src/usr.bin/make/unit-tests/varmod-localtime.mk:1.9	Tue May  9 08:26:14 2023
+++ src/usr.bin/make/unit-tests/varmod-localtime.mk	Tue May  9 16:27:00 2023
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-localtime.mk,v 1.9 2023/05/09 08:26:14 rillig Exp $
+# $NetBSD: varmod-localtime.mk,v 1.10 2023/05/09 16:27:00 rillig Exp $
 #
 # Tests for the :localtime variable modifier, which formats a timestamp
 # using strftime(3) in local time.
@@ -44,20 +44,20 @@
 .endif
 
 
-# As of 2020-08-16, it is not possible to pass the seconds via a
-# variable expression.  This is because parsing of the :localtime
-# modifier stops at the '$' and returns to ApplyModifiers.
-#
-# There, a colon would be skipped but not a dollar.
-# Parsing therefore continues at the '$' of the ${:U159...}, looking
-# for an ordinary variable modifier.
-#
-# At this point, the ${:U} is expanded and interpreted as a variable
-# modifier, which results in the error message "Unknown modifier '1'".
-#
-# If ApplyModifier_Localtime were to pass its argument through
-# ParseModifierPart, this would work.
-.if ${%Y:L:localtime=${:U1593536400}} != "mtime=11593536400}"
+# Before var.c 1.1050 from 2023-05-09, it was not possible to pass the
+# seconds via a variable expression.
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+# delete me
+.if ${%Y:L:localtime=${:U1593536400}} != "2020"
 .  error
 .endif
 
@@ -139,7 +139,7 @@
 .  error
 .endif
 
-# Before var.c 1.TODO from XXXX-XX-XX, the timestamp could be directly
+# Before var.c 1.1050 from 2023-05-09, the timestamp could be directly
 # followed by the next modifier, without a ':' separator.  This is the same
 # bug as for the ':L' and ':P' modifiers.
 .if ${%Y:L:localtime=100000S,1970,bad,} != "bad"

Reply via email to