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

Reply via email to