From: Paul Eggert Date: Mon, 17 Jun 2024 23:16:29 +0000 (-0700) Subject: nstrftime: improve fix for NetBSD link errors X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=6c0315452bd677092aa2d85dc422a5a78e1903be;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index f0593b5e50..2ae4064d4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2024-06-17 Paul Eggert + + 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 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 . */ - -/* Written by Paul Eggert. */ - -#include - -#include - -#include -#include -#include - -#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 ]]) + 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