Thanks for reporting and fixing that. For NetBSD, a better fix is to use
the native timezone_t, so that Gnulib doesn't need to set and later
restore TZ. I attempted to do by installing the attached.From 17432773bb157fe9bd11137edd42cd7be35e1dea Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Mon, 17 Jun 2024 16:16:29 -0700
Subject: [PATCH] nstrftime: improve fix for NetBSD link errors
This makes the NetBSD code thread-safe and presumably faster.
* lib/strftime.c (HAVE_NATIVE_TIME_Z): New macro.
(__strftime_internal): If HAVE_NATIVE_TIME_Z, use strftime_lz
or strftime_z instead of setting and reverting TZ.
* lib/time-internal.c: Remove, reverting recent change.
* lib/time_rz.c, modules/time_rz: Also revert recent changes,
since the relevant functions can now remain private to time_rz.c.
* m4/c-nstrftime.m4 (gl_C_GNU_STRFTIME): Check for strftime_lz.
* m4/nstrftime.m4 (gl_FUNC_GNU_STRFTIME): Check for strftime_z.
---
ChangeLog | 13 +++++
lib/strftime.c | 16 +++++-
lib/time-internal.c | 116 --------------------------------------------
lib/time_rz.c | 78 +++++++++++++++++++++++++++++
m4/c-nstrftime.m4 | 4 +-
m4/nstrftime.m4 | 3 +-
modules/time_rz | 12 ++---
7 files changed, 116 insertions(+), 126 deletions(-)
delete mode 100644 lib/time-internal.c
diff --git a/ChangeLog b/ChangeLog
index f0593b5e50..2ae4064d4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-06-17 Paul Eggert <egg...@cs.ucla.edu>
+
+ nstrftime: improve fix for NetBSD link errors
+ This makes the NetBSD code thread-safe and presumably faster.
+ * lib/strftime.c (HAVE_NATIVE_TIME_Z): New macro.
+ (__strftime_internal): If HAVE_NATIVE_TIME_Z, use strftime_lz
+ or strftime_z instead of setting and reverting TZ.
+ * lib/time-internal.c: Remove, reverting recent change.
+ * lib/time_rz.c, modules/time_rz: Also revert recent changes,
+ since the relevant functions can now remain private to time_rz.c.
+ * m4/c-nstrftime.m4 (gl_C_GNU_STRFTIME): Check for strftime_lz.
+ * m4/nstrftime.m4 (gl_FUNC_GNU_STRFTIME): Check for strftime_z.
+
2024-06-17 Bruno Haible <br...@clisp.org>
vasnprintf: Fix test failure on Cygwin.
diff --git a/lib/strftime.c b/lib/strftime.c
index e422267913..2db6603a23 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -38,6 +38,8 @@
# include "time-internal.h"
#endif
+#define HAVE_NATIVE_TIME_Z (USE_C_LOCALE ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z)
+
/* Whether to require GNU behavior for AM and PM indicators, even on
other platforms. This matters only in non-C locales.
The default is to require it; you can override this via
@@ -1336,6 +1338,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
*u++ = format_char;
*u = '\0';
+# if !HAVE_NATIVE_TIME_Z
timezone_t old_tz = NULL;
if (set_and_revert_tz)
{
@@ -1343,16 +1346,27 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
if (!old_tz)
return 0;
}
-# if USE_C_LOCALE && HAVE_STRFTIME_L
+# endif
+# if USE_C_LOCALE && (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
locale_t locale = c_locale ();
if (!locale)
return 0; /* errno is set here */
+# if HAVE_STRFTIME_LZ
+ len = strftime_lz (tz, ubuf, sizeof ubuf, ufmt, tp, locale);
+# else
len = strftime_l (ubuf, sizeof ubuf, ufmt, tp, locale);
+# endif
# else
+# if HAVE_STRFTIME_Z
+ len = strftime_z (tz, ubuf, sizeof ubuf, ufmt, tp);
+# else
len = strftime (ubuf, sizeof ubuf, ufmt, tp);
+# endif
# endif
+# if !HAVE_NATIVE_TIME_Z
if (old_tz && !revert_tz (old_tz))
return 0;
+# endif
}
if (len != 0)
{
diff --git a/lib/time-internal.c b/lib/time-internal.c
deleted file mode 100644
index dab67c762f..0000000000
--- a/lib/time-internal.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Time zone internal functions
-
- Copyright 2015-2024 Free Software Foundation, Inc.
-
- This file is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This file is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
-
-/* Written by Paul Eggert. */
-
-#include <config.h>
-
-#include <time.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "flexmember.h"
-#include "time-internal.h"
-
-/* Get and set the TZ environment variable. These functions can be
- overridden by programs like Emacs that manage their own environment. */
-
-#ifndef getenv_TZ
-static char *
-getenv_TZ (void)
-{
- return getenv ("TZ");
-}
-#endif
-
-#ifndef setenv_TZ
-static int
-setenv_TZ (char const *tz)
-{
- return tz ? setenv ("TZ", tz, 1) : unsetenv ("TZ");
-}
-#endif
-
-#if !HAVE_TIMEZONE_T
-static const char *
-tzgetname (timezone_t tz, int isdst)
-{
- return tz->tz_is_set ? tz->abbrs : NULL;
-}
-#endif
-
-/* Change the environment to match the specified timezone_t value.
- Return true if successful, false (setting errno) otherwise. */
-static bool
-change_env (timezone_t tz)
-{
- if (setenv_TZ (tzgetname (tz, 0)) != 0)
- return false;
- tzset ();
- return true;
-}
-
-/* Temporarily set the time zone to TZ, which must not be null.
- Return LOCAL_TZ if the time zone setting is already correct.
- Otherwise return a newly allocated time zone representing the old
- setting, or NULL (setting errno) on failure. */
-timezone_t
-set_tz (timezone_t tz)
-{
- char *env_tz = getenv_TZ ();
- const char *tz_name = tzgetname (tz, 0);
- if (env_tz
- ? tz_name != NULL && strcmp (tz_name, env_tz) == 0
- : tz_name == NULL)
- return local_tz;
- else
- {
- timezone_t old_tz = tzalloc (env_tz);
- if (!old_tz)
- return old_tz;
- if (! change_env (tz))
- {
- int saved_errno = errno;
- tzfree (old_tz);
- errno = saved_errno;
- return NULL;
- }
- return old_tz;
- }
-}
-
-/* Restore an old setting returned by set_tz. It must not be null.
- Return true (preserving errno) if successful, false (setting errno)
- otherwise. */
-bool
-revert_tz (timezone_t tz)
-{
- if (tz == local_tz)
- return true;
- else
- {
- int saved_errno = errno;
- bool ok = change_env (tz);
- if (!ok)
- saved_errno = errno;
- tzfree (tz);
- errno = saved_errno;
- return ok;
- }
-}
diff --git a/lib/time_rz.c b/lib/time_rz.c
index ab4ba61e28..a6523e1285 100644
--- a/lib/time_rz.c
+++ b/lib/time_rz.c
@@ -138,6 +138,84 @@ tzfree (timezone_t tz)
}
}
+/* Get and set the TZ environment variable. These functions can be
+ overridden by programs like Emacs that manage their own environment. */
+
+#ifndef getenv_TZ
+static char *
+getenv_TZ (void)
+{
+ return getenv ("TZ");
+}
+#endif
+
+#ifndef setenv_TZ
+static int
+setenv_TZ (char const *tz)
+{
+ return tz ? setenv ("TZ", tz, 1) : unsetenv ("TZ");
+}
+#endif
+
+/* Change the environment to match the specified timezone_t value.
+ Return true if successful, false (setting errno) otherwise. */
+static bool
+change_env (timezone_t tz)
+{
+ if (setenv_TZ (tz->tz_is_set ? tz->abbrs : NULL) != 0)
+ return false;
+ tzset ();
+ return true;
+}
+
+/* Temporarily set the time zone to TZ, which must not be null.
+ Return LOCAL_TZ if the time zone setting is already correct.
+ Otherwise return a newly allocated time zone representing the old
+ setting, or NULL (setting errno) on failure. */
+timezone_t
+set_tz (timezone_t tz)
+{
+ char *env_tz = getenv_TZ ();
+ if (env_tz
+ ? tz->tz_is_set && strcmp (tz->abbrs, env_tz) == 0
+ : !tz->tz_is_set)
+ return local_tz;
+ else
+ {
+ timezone_t old_tz = tzalloc (env_tz);
+ if (!old_tz)
+ return old_tz;
+ if (! change_env (tz))
+ {
+ int saved_errno = errno;
+ tzfree (old_tz);
+ errno = saved_errno;
+ return NULL;
+ }
+ return old_tz;
+ }
+}
+
+/* Restore an old setting returned by set_tz. It must not be null.
+ Return true (preserving errno) if successful, false (setting errno)
+ otherwise. */
+bool
+revert_tz (timezone_t tz)
+{
+ if (tz == local_tz)
+ return true;
+ else
+ {
+ int saved_errno = errno;
+ bool ok = change_env (tz);
+ if (!ok)
+ saved_errno = errno;
+ tzfree (tz);
+ errno = saved_errno;
+ return ok;
+ }
+}
+
/* Use time zone TZ to compute localtime_r (T, TM). */
struct tm *
localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
diff --git a/m4/c-nstrftime.m4 b/m4/c-nstrftime.m4
index fbc18ce8c7..1b77adf388 100644
--- a/m4/c-nstrftime.m4
+++ b/m4/c-nstrftime.m4
@@ -1,5 +1,5 @@
# c-nstrftime.m4
-# serial 2
+# serial 3
dnl Copyright (C) 1996-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -16,4 +16,6 @@ AC_DEFUN([gl_C_GNU_STRFTIME],
dnl macOS >= 10.4, FreeBSD >= 9.0, NetBSD >= 8.0, OpenBSD >= 6.2, Minix >= 3.3,
dnl AIX >= 7.2, Solaris >= 11.4, Cygwin >= 2.6, Android API level >= 21.
gl_CHECK_FUNCS_ANDROID([strftime_l], [[#include <time.h>]])
+ dnl strftime_lz exists on NetBSD >= 8.0.
+ AC_CHECK_FUNCS_ONCE([strftime_lz])
])
diff --git a/m4/nstrftime.m4 b/m4/nstrftime.m4
index 8c855c4163..534507d300 100644
--- a/m4/nstrftime.m4
+++ b/m4/nstrftime.m4
@@ -1,5 +1,5 @@
# nstrftime.m4
-# serial 39
+# serial 40
dnl Copyright (C) 1996-1997, 1999-2007, 2009-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -12,4 +12,5 @@ AC_DEFUN([gl_FUNC_GNU_STRFTIME],
AC_REQUIRE([AC_C_RESTRICT])
AC_REQUIRE([gl_TM_GMTOFF])
+ AC_CHECK_FUNCS_ONCE([strftime_z])
])
diff --git a/modules/time_rz b/modules/time_rz
index aafc6fafe9..f487e24c6b 100644
--- a/modules/time_rz
+++ b/modules/time_rz
@@ -3,7 +3,6 @@ Reentrant time zone functions: localtime_rz, mktime_z, etc.
Files:
lib/time-internal.h
-lib/time-internal.c
lib/time_rz.c
m4/time_rz.m4
@@ -11,14 +10,14 @@ Depends-on:
c99
extensions
time-h
-flexmember
-setenv
-stdbool
-tzset
-unsetenv
+flexmember [test $HAVE_TIMEZONE_T = 0]
idx [test $HAVE_TIMEZONE_T = 0]
+setenv [test $HAVE_TIMEZONE_T = 0]
+stdbool [test $HAVE_TIMEZONE_T = 0]
time_r [test $HAVE_TIMEZONE_T = 0]
timegm [test $HAVE_TIMEZONE_T = 0]
+tzset [test $HAVE_TIMEZONE_T = 0]
+unsetenv [test $HAVE_TIMEZONE_T = 0]
configure.ac:
gl_TIME_RZ
@@ -26,7 +25,6 @@ gl_CONDITIONAL([GL_COND_OBJ_TIME_RZ], [test $HAVE_TIMEZONE_T = 0])
gl_TIME_MODULE_INDICATOR([time_rz])
Makefile.am:
-lib_SOURCES += time-internal.c
if GL_COND_OBJ_TIME_RZ
lib_SOURCES += time_rz.c
endif
--
2.43.0