Module Name:    src
Committed By:   rillig
Date:           Sat Aug 19 11:13:36 UTC 2023

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

Log Message:
make: work around bugs in gmtime on several platforms


To generate a diff of this commit:
cvs rdiff -u -r1.1061 -r1.1062 src/usr.bin/make/var.c
cvs rdiff -u -r1.17 -r1.18 src/usr.bin/make/unit-tests/varmod-gmtime.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.1061 src/usr.bin/make/var.c:1.1062
--- src/usr.bin/make/var.c:1.1061	Thu Aug 17 19:06:51 2023
+++ src/usr.bin/make/var.c	Sat Aug 19 11:13:35 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.1061 2023/08/17 19:06:51 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.1062 2023/08/19 11:13:35 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.1061 2023/08/17 19:06:51 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1062 2023/08/19 11:13:35 rillig Exp $");
 
 /*
  * Variables are defined using one of the VAR=value assignments.  Their
@@ -1886,7 +1886,24 @@ FormatTime(const char *fmt, time_t t, bo
 		time(&t);
 	if (*fmt == '\0')
 		fmt = "%c";
-	strftime(buf, sizeof buf, fmt, gmt ? gmtime(&t) : localtime(&t));
+	if (gmt) {
+		/*
+		 * Work around a buggy 'strftime' implementation on at least
+		 * NetBSD 10 and Linux/glibc-2.31, on which the value of '%s'
+		 * depends on the timezone from TZ; see varmod-gmtime.mk.
+		 */
+		const char *prev_tz_env = getenv("TZ");
+		char *prev_tz = prev_tz_env != NULL
+		    ? bmake_strdup(prev_tz_env) : NULL;
+		setenv("TZ", "UTC", 1);
+		strftime(buf, sizeof buf, fmt, localtime(&t));
+		if (prev_tz != NULL) {
+			setenv("TZ", prev_tz, 1);
+			free(prev_tz);
+		} else
+			unsetenv("TZ");
+	} else
+		strftime(buf, sizeof buf, fmt, localtime(&t));
 
 	buf[sizeof buf - 1] = '\0';
 	return bmake_strdup(buf);

Index: src/usr.bin/make/unit-tests/varmod-gmtime.mk
diff -u src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.17 src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.18
--- src/usr.bin/make/unit-tests/varmod-gmtime.mk:1.17	Sat Aug 19 10:33:32 2023
+++ src/usr.bin/make/unit-tests/varmod-gmtime.mk	Sat Aug 19 11:13:36 2023
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-gmtime.mk,v 1.17 2023/08/19 10:33:32 rillig Exp $
+# $NetBSD: varmod-gmtime.mk,v 1.18 2023/08/19 11:13:36 rillig Exp $
 #
 # Tests for the :gmtime variable modifier, which formats a timestamp
 # using strftime(3) in UTC.
@@ -146,13 +146,13 @@
 .endif
 
 
-# As of 2023-08-19, ':gmtime' but not ':localtime' reports wrong values for
-# '%s', depending on the operating system and the timezone, as demonstrated by
-# the following test program:
+# Before var.c 1.1062 from 2023-08-19, ':gmtime' but not ':localtime' reported
+# wrong values for '%s', depending on the operating system and the timezone,
+# as demonstrated by the following test program:
 #
 #	for mod in gmtime localtime; do
 #		for tz in UTC Europe/Berlin America/Los_Angeles; do
-#			TZ=$tz bmake -r -v "\${%F %T %z %s $mod $tz:L:$mod}"
+#			TZ=$tz ./make -r -f /dev/null -v "\${%F %T %z %s $mod $tz:L:$mod}"
 #		done
 #	done
 #
@@ -194,33 +194,30 @@
 #	* ':gmtime' reports the correct timezone offset '+0000'.
 #	* ':gmtime' reports different seconds since the Epoch, and the '%s'
 #	  value cannot be derived from the '%F %T %z' values.
-.if 0			# only for reference, due to platform differences
 export TZ=UTC
-.  for t in ${%s:L:gmtime} ${%s:L:localtime}
+.for t in ${%s:L:gmtime} ${%s:L:localtime}
 TIMESTAMPS+= $t
-.  endfor
+.endfor
 export TZ=Europe/Berlin
-.  for t in ${%s:L:gmtime} ${%s:L:localtime}
+.for t in ${%s:L:gmtime} ${%s:L:localtime}
 TIMESTAMPS+= $t
-.  endfor
+.endfor
 export TZ=UTC
-.  for t in ${%s:L:gmtime} ${%s:L:localtime}
+.for t in ${%s:L:gmtime} ${%s:L:localtime}
 TIMESTAMPS+= $t
-.  endfor
+.endfor
 export TZ=America/Los_Angeles
-.  for t in ${%s:L:gmtime} ${%s:L:localtime}
+.for t in ${%s:L:gmtime} ${%s:L:localtime}
 TIMESTAMPS+= $t
-.  endfor
+.endfor
 export TZ=UTC
-.  for t in ${%s:L:gmtime} ${%s:L:localtime}
+.for t in ${%s:L:gmtime} ${%s:L:localtime}
 TIMESTAMPS+= $t
-.  endfor
-.  info ${TIMESTAMPS:u}
-.  for a b in ${TIMESTAMPS:[1]} ${TIMESTAMPS:@t@$t $t@} ${TIMESTAMPS:[-1]}
-.    if $a > $b
-.      warning timestamp $a > $b
-.    endif
-.  endfor
-.endif
+.endfor
+.for a b in ${TIMESTAMPS:[1]} ${TIMESTAMPS:@t@$t $t@} ${TIMESTAMPS:[-1]}
+.  if $a > $b
+.    warning timestamp $a > $b
+.  endif
+.endfor
 
 all:

Reply via email to