From a5b127b8bc19524a137047a700621e8cee7b7269 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 30 Jun 2024 00:08:28 +0100 Subject: [PATCH] Update from Gnulib by running admin/merge-gnulib * m4/wchar_t.m4: Remove; no longer needed. (cherry picked from commit 4a8c8021cc311626fbfa55e68c524195ce466738) --- build-aux/gitlog-to-changelog | 2 +- build-aux/install-sh | 8 +- lib/acl-internal.c | 15 +- lib/gnulib.mk.in | 17 +- lib/stddef.in.h | 5 - lib/stdio.in.h | 145 ++++++++++++- lib/strftime.c | 395 ++++++++++++++++++++++++---------- lib/time-internal.h | 21 +- lib/time.in.h | 17 ++ lib/time_rz.c | 44 +--- lib/timespec-add.c | 30 +-- lib/timespec-sub.c | 29 +-- m4/canonicalize.m4 | 8 +- m4/gnulib-comp.m4 | 1 - m4/largefile.m4 | 6 +- m4/nstrftime.m4 | 6 +- m4/readlinkat.m4 | 4 +- m4/stddef_h.m4 | 9 +- m4/stdio_h.m4 | 8 +- m4/time_h.m4 | 3 +- m4/time_rz.m4 | 3 +- m4/tm_gmtoff.m4 | 26 ++- m4/wchar_t.m4 | 25 --- 23 files changed, 558 insertions(+), 269 deletions(-) delete mode 100644 m4/wchar_t.m4 diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog index 16a9405a7cb..49e7ef95cef 100755 --- a/build-aux/gitlog-to-changelog +++ b/build-aux/gitlog-to-changelog @@ -495,7 +495,7 @@ sub git_dir_option($) # Complain about any unused entry in the --amend=F specified file. my $fail = 0; - foreach my $sha (keys %$amend_code) + foreach my $sha (sort keys %$amend_code) { warn "$ME:$amend_file: unused entry: $sha\n"; $fail = 1; diff --git a/build-aux/install-sh b/build-aux/install-sh index 7c56c9c0151..b1d7a6f67f6 100755 --- a/build-aux/install-sh +++ b/build-aux/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2023-11-23.18; # UTC +scriptversion=2024-06-19.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -170,7 +170,7 @@ while test $# -ne 0; do -T) is_target_a_directory=never;; - --version) echo "$0 $scriptversion"; exit $?;; + --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; --) shift break;; @@ -345,7 +345,7 @@ do ' 0 # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directly in world-writable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && @@ -353,7 +353,7 @@ do exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. + # Check for POSIX incompatibility with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. diff --git a/lib/acl-internal.c b/lib/acl-internal.c index 9ebb6e544b0..ae5398306af 100644 --- a/lib/acl-internal.c +++ b/lib/acl-internal.c @@ -89,6 +89,14 @@ acl_access_nontrivial (acl_t acl) group:Administrators:rwx mask::r-x other::r-x + or + user::rwx + group::r-x + group:SYSTEM:rwx + group:Administrators:rwx + group:Users:rwx + mask::rwx + other::r-x */ case ACL_GROUP: { @@ -105,9 +113,12 @@ acl_access_nontrivial (acl_t acl) /* Ignore the ace if the group_sid is one of - S-1-5-18 (group "SYSTEM") - S-1-5-32-544 (group "Administrators") - Cf. */ + - S-1-5-32-545 (group "Users") + Cf. + and look at the output of the 'mkgroup' command. */ ignorable = (strcmp (group_sid, "S-1-5-18") == 0 - || strcmp (group_sid, "S-1-5-32-544") == 0); + || strcmp (group_sid, "S-1-5-32-544") == 0 + || strcmp (group_sid, "S-1-5-32-545") == 0); } } if (!ignorable) diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 832b245edc2..948269e744d 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -545,6 +545,7 @@ GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@ GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@ GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@ GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@ +GL_GNULIB_OBSTACK_ZPRINTF = @GL_GNULIB_OBSTACK_ZPRINTF@ GL_GNULIB_OPEN = @GL_GNULIB_OPEN@ GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@ GL_GNULIB_OPENDIR = @GL_GNULIB_OPENDIR@ @@ -645,6 +646,7 @@ GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@ GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@ GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@ GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@ +GL_GNULIB_TZNAME = @GL_GNULIB_TZNAME@ GL_GNULIB_TZSET = @GL_GNULIB_TZSET@ GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@ GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@ @@ -656,6 +658,7 @@ GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@ GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@ GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@ GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@ +GL_GNULIB_VAZSPRINTF = @GL_GNULIB_VAZSPRINTF@ GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@ GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@ GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@ @@ -665,8 +668,12 @@ GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@ GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@ GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@ GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ +GL_GNULIB_VZSNPRINTF = @GL_GNULIB_VZSNPRINTF@ +GL_GNULIB_VZSPRINTF = @GL_GNULIB_VZSPRINTF@ GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ +GL_GNULIB_ZSNPRINTF = @GL_GNULIB_ZSNPRINTF@ +GL_GNULIB_ZSPRINTF = @GL_GNULIB_ZSPRINTF@ GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ GL_STDC_BIT_CEIL = @GL_STDC_BIT_CEIL@ GL_STDC_BIT_FLOOR = @GL_STDC_BIT_FLOOR@ @@ -928,7 +935,6 @@ HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ HAVE_VASPRINTF = @HAVE_VASPRINTF@ HAVE_VDPRINTF = @HAVE_VDPRINTF@ HAVE_WCHAR_H = @HAVE_WCHAR_H@ -HAVE_WCHAR_T = @HAVE_WCHAR_T@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_XSERVER = @HAVE_XSERVER@ HAVE__EXIT = @HAVE__EXIT@ @@ -1412,6 +1418,7 @@ XSYNC_CFLAGS = @XSYNC_CFLAGS@ XSYNC_LIBS = @XSYNC_LIBS@ XWIDGETS_OBJ = @XWIDGETS_OBJ@ X_TOOLKIT_TYPE = @X_TOOLKIT_TYPE@ +ZIP = @ZIP@ ZIPALIGN = @ZIPALIGN@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ @@ -3200,7 +3207,6 @@ stddef.h: stddef.in.h $(top_builddir)/config.status -e 's|@''STDDEF_NOT_IDEMPOTENT''@|$(STDDEF_NOT_IDEMPOTENT)|g' \ -e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \ -e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \ - -e 's|@''HAVE_WCHAR_T''@|$(HAVE_WCHAR_T)|g' \ $(srcdir)/stddef.in.h > $@-t $(AM_V_at)mv $@-t $@ else @@ -3305,6 +3311,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \ -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \ -e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \ + -e 's/@''GNULIB_OBSTACK_ZPRINTF''@/$(GL_GNULIB_OBSTACK_ZPRINTF)/g' \ -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \ -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \ -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \ @@ -3323,6 +3330,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \ -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \ -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \ + -e 's/@''GNULIB_VAZSPRINTF''@/$(GL_GNULIB_VAZSPRINTF)/g' \ -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \ -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \ -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \ @@ -3332,6 +3340,10 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \ -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \ -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \ + -e 's/@''GNULIB_VZSNPRINTF''@/$(GL_GNULIB_VZSNPRINTF)/g' \ + -e 's/@''GNULIB_VZSPRINTF''@/$(GL_GNULIB_VZSPRINTF)/g' \ + -e 's/@''GNULIB_ZSNPRINTF''@/$(GL_GNULIB_ZSNPRINTF)/g' \ + -e 's/@''GNULIB_ZSPRINTF''@/$(GL_GNULIB_ZSPRINTF)/g' \ -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \ -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \ -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \ @@ -4005,6 +4017,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_TIMESPEC_GETRES''@/$(GL_GNULIB_TIMESPEC_GETRES)/g' \ -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \ -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \ + -e 's/@''GNULIB_TZNAME''@/$(GL_GNULIB_TZNAME)/g' \ -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \ -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \ -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \ diff --git a/lib/stddef.in.h b/lib/stddef.in.h index 63bb500e262..0abc4497043 100644 --- a/lib/stddef.in.h +++ b/lib/stddef.in.h @@ -149,11 +149,6 @@ typedef long max_align_t; # endif #endif -/* Some platforms lack wchar_t. */ -#if !@HAVE_WCHAR_T@ -# define wchar_t int -#endif - /* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is a hack in case the configure-time test was done with g++ even though we are currently compiling with gcc. diff --git a/lib/stdio.in.h b/lib/stdio.in.h index 1c0c9661bfe..cf2d8c999bc 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -1075,13 +1075,39 @@ _GL_CXXALIASWARN (getw); # endif #endif +#if @GNULIB_OBSTACK_ZPRINTF@ +struct obstack; +/* Grows an obstack with formatted output. Returns the number of + bytes added to OBS. No trailing nul byte is added, and the + object should be closed with obstack_finish before use. + Upon memory allocation error, calls obstack_alloc_failed_handler. + Upon other error, returns -1 with errno set. + + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is through + obstack_alloc_failed_handler. */ +_GL_FUNCDECL_SYS (obstack_zprintf, ptrdiff_t, + (struct obstack *obs, const char *format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (obstack_zprintf, ptrdiff_t, + (struct obstack *obs, const char *format, ...)); +_GL_FUNCDECL_SYS (obstack_vzprintf, ptrdiff_t, + (struct obstack *obs, const char *format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (obstack_vzprintf, ptrdiff_t, + (struct obstack *obs, const char *format, va_list args)); +#endif + #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@ struct obstack; -/* Grow an obstack with formatted output. Return the number of +/* Grows an obstack with formatted output. Returns the number of bytes added to OBS. No trailing nul byte is added, and the - object should be closed with obstack_finish before use. Upon - memory allocation error, call obstack_alloc_failed_handler. Upon - other error, return -1. */ + object should be closed with obstack_finish before use. + Upon memory allocation error, calls obstack_alloc_failed_handler. + Upon other error, returns -1. */ # if @REPLACE_OBSTACK_PRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define obstack_printf rpl_obstack_printf @@ -1433,7 +1459,31 @@ _GL_CXXALIASWARN (scanf); # endif #endif +#if @GNULIB_ZSNPRINTF@ +/* Prints formatted output to string STR. Similar to sprintf, but the + additional parameter SIZE limits how much is written into STR. + STR may be NULL, in which case nothing will be written. + Returns the string length of the formatted string (which may be larger + than SIZE). Upon failure, returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is ENOMEM. */ +_GL_FUNCDECL_SYS (zsnprintf, ptrdiff_t, + (char *restrict str, size_t size, + const char *restrict format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4) + _GL_ARG_NONNULL ((3))); +_GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t, + (char *restrict str, size_t size, + const char *restrict format, ...)); +#endif + #if @GNULIB_SNPRINTF@ +/* Prints formatted output to string STR. Similar to sprintf, but the + additional parameter SIZE limits how much is written into STR. + STR may be NULL, in which case nothing will be written. + Returns the string length of the formatted string (which may be larger + than SIZE). Upon failure, returns a negative value. */ # if @REPLACE_SNPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define snprintf rpl_snprintf @@ -1470,6 +1520,23 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - " # endif #endif +#if @GNULIB_ZSPRINTF@ +/* Prints formatted output to string STR. + Returns the string length of the formatted string. Upon failure, + returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is ENOMEM. */ +_GL_FUNCDECL_SYS (zsprintf, ptrdiff_t, + (char *restrict str, + const char *restrict format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (zsprintf, ptrdiff_t, + (char *restrict str, + const char *restrict format, ...)); +#endif + /* Some people would argue that all sprintf uses should be warned about (for example, OpenBSD issues a link warning for it), since it can cause security holes due to buffer overruns. @@ -1480,6 +1547,9 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - " GNULIB_POSIXCHECK is defined. */ #if @GNULIB_SPRINTF_POSIX@ +/* Prints formatted output to string STR. + Returns the string length of the formatted string. Upon failure, + returns a negative value. */ # if @REPLACE_SPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define sprintf rpl_sprintf @@ -1559,6 +1629,29 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - " # endif #endif +#if @GNULIB_VAZSPRINTF@ +/* Prints formatted output to a string dynamically allocated with malloc(). + If the memory allocation succeeds, it stores the address of the string in + *RESULT and returns the number of resulting bytes, excluding the trailing + NUL. Upon memory allocation error, or some other error, it returns -1 + with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is ENOMEM. */ +_GL_FUNCDECL_SYS (azsprintf, ptrdiff_t, + (char **result, const char *format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (azsprintf, ptrdiff_t, + (char **result, const char *format, ...)); +_GL_FUNCDECL_SYS (vazsprintf, ptrdiff_t, + (char **result, const char *format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (vazsprintf, ptrdiff_t, + (char **result, const char *format, va_list args)); +#endif + #if @GNULIB_VASPRINTF@ /* Write formatted output to a string dynamically allocated with malloc(). If the memory allocation succeeds, store the address of the string in @@ -1769,7 +1862,31 @@ _GL_CXXALIASWARN (vscanf); # endif #endif +#if @GNULIB_VZSNPRINTF@ +/* Prints formatted output to string STR. Similar to sprintf, but the + additional parameter SIZE limits how much is written into STR. + STR may be NULL, in which case nothing will be written. + Returns the string length of the formatted string (which may be larger + than SIZE). Upon failure, returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is ENOMEM. */ +_GL_FUNCDECL_SYS (vzsnprintf, ptrdiff_t, + (char *restrict str, size_t size, + const char *restrict format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) + _GL_ARG_NONNULL ((3))); +_GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t, + (char *restrict str, size_t size, + const char *restrict format, va_list args)); +#endif + #if @GNULIB_VSNPRINTF@ +/* Prints formatted output to string STR. Similar to vsprintf, but the + additional parameter SIZE limits how much is written into STR. + STR may be NULL, in which case nothing will be written. + Returns the string length of the formatted string (which may be larger + than SIZE). Upon failure, returns a negative value. */ # if @REPLACE_VSNPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define vsnprintf rpl_vsnprintf @@ -1806,7 +1923,27 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - " # endif #endif +#if @GNULIB_VZSPRINTF@ +/* Prints formatted output to string STR. + Returns the string length of the formatted string. Upon failure, + returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure code is ENOMEM. */ +_GL_FUNCDECL_SYS (vzsprintf, ptrdiff_t, + (char *restrict str, + const char *restrict format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t, + (char *restrict str, + const char *restrict format, va_list args)); +#endif + #if @GNULIB_VSPRINTF_POSIX@ +/* Prints formatted output to string STR. + Returns the string length of the formatted string. Upon failure, + returns a negative value. */ # if @REPLACE_VSPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define vsprintf rpl_vsprintf diff --git a/lib/strftime.c b/lib/strftime.c index 5f1e76833f7..9b1b27a1fc8 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -25,9 +25,8 @@ #ifdef _LIBC # define USE_IN_EXTENDED_LOCALE_MODEL 1 # define HAVE_STRUCT_ERA_ENTRY 1 -# define HAVE_TM_GMTOFF 1 +# define HAVE_STRUCT_TM_TM_GMTOFF 1 # define HAVE_STRUCT_TM_TM_ZONE 1 -# define HAVE_TZNAME 1 # include "../locale/localeinfo.h" #else # include @@ -60,10 +59,6 @@ #include #include -#if HAVE_TZNAME && !HAVE_DECL_TZNAME -extern char *tzname[]; -#endif - /* Do multibyte processing if multibyte encodings are supported, unless multibyte sequences are safe in formats. Multibyte sequences are safe if they cannot contain byte sequences that look like format @@ -87,18 +82,16 @@ extern char *tzname[]; #endif #include +#include #include #include #include #include -#if USE_C_LOCALE && HAVE_STRFTIME_L -# include -#endif - #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM -# include # include "localename.h" +#elif defined _WIN32 && !defined __CYGWIN__ +# include #endif #include "attribute.h" @@ -377,6 +370,15 @@ memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM) #endif +/* Note: We assume that HAVE_STRFTIME_LZ implies HAVE_STRFTIME_L. + Otherwise, we would have to write (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ) + instead of HAVE_STRFTIME_L everywhere. */ + +/* Define to 1 if we can use the system's native functions that takes a + timezone_t argument. As of 2024, this is only true on NetBSD. */ +#define HAVE_NATIVE_TIME_Z \ + (USE_C_LOCALE && HAVE_STRFTIME_L ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z) + #if USE_C_LOCALE && HAVE_STRFTIME_L /* Cache for the C locale object. @@ -396,6 +398,27 @@ c_locale (void) #endif +#if HAVE_NATIVE_TIME_Z + +/* On NetBSD a null tz has undefined behavior, so use a non-null tz. + Cache the UTC time zone object in a volatile variable for improved + thread safety. This is good enough in practice, although in theory + stdatomic.h should be used. */ +static volatile timezone_t utc_timezone_cache; + +/* Return the UTC time zone object, or (timezone_t) 0 with errno set + if it cannot be created. */ +static timezone_t +utc_timezone (void) +{ + timezone_t tz = utc_timezone_cache; + if (!tz) + utc_timezone_cache = tz = tzalloc ("UTC0"); + return tz; +} + +#endif + #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM @@ -747,7 +770,7 @@ should_remove_ampm (void) #endif -#if ! HAVE_TM_GMTOFF +#if ! HAVE_STRUCT_TM_TM_GMTOFF /* Yield the difference between *A and *B, measured in seconds, ignoring leap seconds. */ # define tm_diff ftime_tm_diff @@ -772,7 +795,7 @@ tm_diff (const struct tm *a, const struct tm *b) + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec)); } -#endif /* ! HAVE_TM_GMTOFF */ +#endif @@ -810,9 +833,9 @@ static CHAR_T const c_month_names[][sizeof "September"] = #endif -/* When compiling this file, GNU applications can #define my_strftime - to a symbol (typically nstrftime) to get an extended strftime with - extra arguments TZ and NS. */ +/* When compiling this file, Gnulib-using applications should #define + my_strftime to a symbol (typically nstrftime) to name their + extended strftime with extra arguments TZ and NS. */ #ifdef my_strftime # define extra_args , tz, ns @@ -837,6 +860,200 @@ static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t) bool, enum pad_style, int, bool * extra_args_spec LOCALE_PARAM); +#if !defined _LIBC \ + && (!(USE_C_LOCALE && !HAVE_STRFTIME_L) || !HAVE_STRUCT_TM_TM_ZONE) + +/* Make sure we're calling the actual underlying strftime. + In some cases, time.h contains something like + "#define strftime rpl_strftime". */ +# ifdef strftime +# undef strftime +# endif + +/* Assuming the time zone is TZ, store into UBUF, of size UBUFSIZE, a + ' ' followed by the result of calling strftime with the format + "%MF" where M is MODIFIER (or is omitted if !MODIFIER) and F is + FORMAT_CHAR, along with the time information specified by *TP. + Return the number of bytes stored if successful, zero otherwise. */ +static size_t +underlying_strftime (timezone_t tz, char *ubuf, size_t ubufsize, + char modifier, char format_char, struct tm const *tp) +{ + /* The relevant information is available only via the + underlying strftime implementation, so use that. */ + char ufmt[5]; + char *u = ufmt; + + /* The space helps distinguish strftime failure from empty + output. */ + *u++ = ' '; + *u++ = '%'; + *u = modifier; + u += !!modifier; + *u++ = format_char; + *u = '\0'; + +# if HAVE_NATIVE_TIME_Z + if (!tz) + { + tz = utc_timezone (); + if (!tz) + return 0; /* errno is set here */ + } +# endif + +# if !HAVE_NATIVE_TIME_Z + if (tz && tz != local_tz) + { + tz = set_tz (tz); + if (!tz) + return 0; + } +# endif + + size_t len; +# if USE_C_LOCALE && HAVE_STRFTIME_L + locale_t locale = c_locale (); + if (!locale) + return 0; /* errno is set here */ +# if HAVE_STRFTIME_LZ + len = strftime_lz (tz, ubuf, ubufsize, ufmt, tp, locale); +# else + len = strftime_l (ubuf, ubufsize, ufmt, tp, locale); +# endif +# else +# if HAVE_STRFTIME_Z + len = strftime_z (tz, ubuf, ubufsize, ufmt, tp); +# else + len = strftime (ubuf, ubufsize, ufmt, tp); +# endif +# endif + +# if !HAVE_NATIVE_TIME_Z + if (tz && !revert_tz (tz)) + return 0; +# endif + + if (len != 0) + { +# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) \ + || defined __NetBSD__ || defined __sun) + /* glibc < 2.31, NetBSD, Solaris */ + if (format_char == 'c') + { + /* The output of the strftime %c directive consists of the + date, the time, and the time zone. But the time zone is + wrong, since neither TZ nor ZONE was passed as argument. + Therefore, remove the the last space-delimited word. + In order not to accidentally remove a date or a year + (that contains no letter) or an AM/PM indicator (that has + length 2), remove that last word only if it contains a + letter and has length >= 3. */ + char *space; + for (space = ubuf + len - 1; *space != ' '; space--) + continue; + if (space > ubuf) + { + /* Found a space. */ + if (strlen (space + 1) >= 3) + { + /* The last word has length >= 3. */ + bool found_letter = false; + const char *p; + for (p = space + 1; *p != '\0'; p++) + if ((*p >= 'A' && *p <= 'Z') + || (*p >= 'a' && *p <= 'z')) + { + found_letter = true; + break; + } + if (found_letter) + { + /* The last word contains a letter. */ + *space = '\0'; + len = space - ubuf; + } + } + } + } +# if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM + /* The output of the strftime %p and %r directives contains + an AM/PM indicator even for locales where it is not + suitable, such as French. Remove this indicator. */ + if (format_char == 'p') + { + bool found_ampm = (len > 1); + if (found_ampm && should_remove_ampm ()) + { + ubuf[1] = '\0'; + len = 1; + } + } + else if (format_char == 'r') + { + char last_char = ubuf[len - 1]; + bool found_ampm = !(last_char >= '0' && last_char <= '9'); + if (found_ampm && should_remove_ampm ()) + { + char *space; + for (space = ubuf + len - 1; *space != ' '; space--) + continue; + if (space > ubuf) + { + *space = '\0'; + len = space - ubuf; + } + } + } +# endif +# endif + } + return len; +} +#endif + +/* Return a time zone abbreviation for TZ. Use BUF, of size BUFSIZE, + to store it if needed. If MODIFIER use the strftime format + "%mZ" to format it, where m is the MODIFIER; otherwise + use plain "%Z". Format an abbreviation appropriate for + TP and EXTRA_ARGS_SPEC. Return the empty string on failure. */ +static char const * +get_tm_zone (timezone_t tz, char *ubuf, int ubufsize, int modifier, + struct tm const *tp) +{ +#if HAVE_STRUCT_TM_TM_ZONE + /* The POSIX test suite assumes that setting + the environment variable TZ to a new value before calling strftime() + will influence the result (the %Z format) even if the information in + *TP is computed with a totally different time zone. + This is bogus: though POSIX allows bad behavior like this, + POSIX does not require it. Do the right thing instead. */ + return tp->tm_zone; +#else + if (!tz) + return "UTC"; + +# if !HAVE_NATIVE_TIME_Z + timezone_t old_tz = tz; + if (tz != local_tz) + { + old_tz = set_tz (tz); + if (!old_tz) + return ""; + } +# endif + + int zsize = underlying_strftime (tz, ubuf, ubufsize, 0, 'Z', tp); + +# if !HAVE_NATIVE_TIME_Z + if (!revert_tz (old_tz)) + return ""; +# endif + + return zsize ? ubuf + 1 : ""; +#endif +} + /* Write information from TP into S according to the format string FORMAT, writing no more that MAXSIZE characters (including the terminating '\0') and returning number of @@ -927,10 +1144,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11)) # define ap_len 2 #endif -#if HAVE_TZNAME - char **tzname_vec = tzname; -#endif - const char *zone; size_t i = 0; STREAM_OR_CHAR_T *p = s; const CHAR_T *f; @@ -938,47 +1151,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) const char *format_end = NULL; #endif - zone = NULL; -#if HAVE_STRUCT_TM_TM_ZONE - /* The POSIX test suite assumes that setting - the environment variable TZ to a new value before calling strftime() - will influence the result (the %Z format) even if the information in - TP is computed with a totally different time zone. - This is bogus: though POSIX allows bad behavior like this, - POSIX does not require it. Do the right thing instead. */ - zone = (const char *) tp->tm_zone; -#endif -#if HAVE_TZNAME - if (!tz) - { - if (! (zone && *zone)) - zone = "GMT"; - } - else - { -# if !HAVE_STRUCT_TM_TM_ZONE - /* Infer the zone name from *TZ instead of from TZNAME. */ - tzname_vec = tz->tzname_copy; -# endif - } - /* The tzset() call might have changed the value. */ - if (!(zone && *zone) && tp->tm_isdst >= 0) - { - /* POSIX.1 requires that local time zone information be used as - though strftime called tzset. */ -# ifndef my_strftime - if (!*tzset_called) - { - tzset (); - *tzset_called = true; - } -# endif - zone = tzname_vec[tp->tm_isdst != 0]; - } -#endif - if (! zone) - zone = ""; - if (hour12 > 12) hour12 -= 12; else @@ -1293,7 +1465,21 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) subfmt = L_("%a %b %e %H:%M:%S %Y"); #elif defined _WIN32 && !defined __CYGWIN__ /* On native Windows, "%c" is "%d/%m/%Y %H:%M:%S" by default. */ - subfmt = L_("%a %b %e %H:%M:%S %Y"); + bool is_c_locale; + /* This code is equivalent to is_c_locale = !hard_locale (LC_TIME). */ +# if defined _MSC_VER + const wchar_t *locale = _wsetlocale (LC_TIME, NULL); + is_c_locale = + (wcscmp (locale, L"C") == 0 || wcscmp (locale, L"POSIX") == 0); +# else + const char *locale = setlocale (LC_TIME, NULL); + is_c_locale = + (strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0); +# endif + if (is_c_locale) + subfmt = L_("%a %b %e %H:%M:%S %Y"); + else + subfmt = L_("%a %e %b %Y %H:%M:%S"); #else goto underlying_strftime; #endif @@ -1314,40 +1500,13 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) } break; -#if !((defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY) || (USE_C_LOCALE && !HAVE_STRFTIME_L)) +#if !defined _LIBC && !(USE_C_LOCALE && !HAVE_STRFTIME_L) underlying_strftime: { - /* The relevant information is available only via the - underlying strftime implementation, so use that. */ - char ufmt[5]; - char *u = ufmt; char ubuf[1024]; /* enough for any single format in practice */ size_t len; - /* Make sure we're calling the actual underlying strftime. - In some cases, config.h contains something like - "#define strftime rpl_strftime". */ -# ifdef strftime -# undef strftime - size_t strftime (char *, size_t, const char *, struct tm const *); -# endif - - /* The space helps distinguish strftime failure from empty - output. */ - *u++ = ' '; - *u++ = '%'; - if (modifier != 0) - *u++ = modifier; - *u++ = format_char; - *u = '\0'; - -# if USE_C_LOCALE /* implies HAVE_STRFTIME_L */ - locale_t locale = c_locale (); - if (!locale) - return 0; /* errno is set here */ - len = strftime_l (ubuf, sizeof ubuf, ufmt, tp, locale); -# else - len = strftime (ubuf, sizeof ubuf, ufmt, tp); -# endif + len = underlying_strftime (tz, ubuf, sizeof ubuf, + modifier, format_char, tp); if (len != 0) { # if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) || defined __NetBSD__ || defined __sun /* glibc < 2.31, NetBSD, Solaris */ @@ -1715,7 +1874,8 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) #elif USE_C_LOCALE && !HAVE_STRFTIME_L subfmt = L_("%I:%M:%S %p"); goto subformat; -#elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || (defined _WIN32 && !defined __CYGWIN__) +#elif ((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ \ + || (defined _WIN32 && !defined __CYGWIN__)) /* macOS, FreeBSD, native Windows strftime() may produce empty output for "%r". */ subfmt = L_("%I:%M:%S %p"); @@ -1927,8 +2087,30 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) to_lowcase = true; } + { + char const *zone; +#ifdef _LIBC + zone = tp->tm_zone; + /* The tzset() call might have changed the value. */ + if (!(zone && *zone) && tp->tm_isdst >= 0) + { + /* POSIX.1 requires that local time zone information be used as + though strftime called tzset. */ + if (!*tzset_called) + { + tzset (); + *tzset_called = true; + } + zone = tp->tm_isdst <= 1 ? tzname[tp->tm_isdst] : "?"; + } + if (! zone) + zone = ""; +#else + char zonebuf[128]; /* Enough for any time zone abbreviation. */ + zone = get_tm_zone (tz, zonebuf, sizeof zonebuf, modifier, tp); +#endif + #ifdef COMPILE_WIDE - { /* The zone string is always given in multibyte form. We have to convert it to wide character. */ size_t w = pad == NO_PAD || width < 0 ? 0 : width; @@ -1956,10 +2138,10 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) p += incr; } i += incr; - } #else - cpy (strlen (zone), zone); + cpy (strlen (zone), zone); #endif + } break; case L_(':'): @@ -1984,7 +2166,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) int hour_diff; int min_diff; int sec_diff; -#if HAVE_TM_GMTOFF +#if HAVE_STRUCT_TM_TM_GMTOFF diff = tp->tm_gmtoff; #else if (!tz) @@ -1995,16 +2177,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) struct tm ltm; time_t lt; - /* POSIX.1 requires that local time zone information be used as - though strftime called tzset. */ -# ifndef my_strftime - if (!*tzset_called) - { - tzset (); - *tzset_called = true; - } -# endif - ltm = *tp; ltm.tm_wday = -1; lt = mktime_z (tz, <m); @@ -2014,7 +2186,14 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) } #endif - negative_number = diff < 0 || (diff == 0 && *zone == '-'); + negative_number = diff < 0; + if (diff == 0) + { + char zonebuf[128]; /* Enough for any time zone abbreviation. */ + negative_number = (*get_tm_zone (tz, zonebuf, sizeof zonebuf, + 0, tp) + == '-'); + } hour_diff = diff / 60 / 60; min_diff = diff / 60 % 60; sec_diff = diff % 60; diff --git a/lib/time-internal.h b/lib/time-internal.h index 816684a1172..3d778ba50ec 100644 --- a/lib/time-internal.h +++ b/lib/time-internal.h @@ -17,6 +17,9 @@ /* Written by Paul Eggert. */ +/* This file is for Gnulib internal use only. + Applications should not use it. */ + /* A time zone rule. */ struct tm_zone { @@ -24,12 +27,6 @@ struct tm_zone members are zero. */ struct tm_zone *next; -#if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE - /* Copies of recent strings taken from tzname[0] and tzname[1]. - The copies are in ABBRS, so that they survive tzset. Null if unknown. */ - char *tzname_copy[2]; -#endif - /* If nonzero, the rule represents the TZ environment variable set to the first "abbreviation" (this may be the empty string). Otherwise, it represents an unset TZ. */ @@ -41,9 +38,17 @@ struct tm_zone actually a TZ environment value) may be empty. Otherwise all strings must be nonempty. - Abbreviations are stored here because otherwise the values of - tm_zone and/or tzname would be dead after changing TZ and calling + Abbreviations are stored here even on platforms with tm_zone, because + otherwise tm_zone values would be dead after changing TZ and calling tzset. Abbreviations never move once allocated, and are live until tzfree is called. */ char abbrs[FLEXIBLE_ARRAY_MEMBER]; }; + +timezone_t set_tz (timezone_t); +bool revert_tz (timezone_t); + +/* Magic cookie timezone_t value, for local time. It differs from + NULL and from all other timezone_t values. Only the address + matters; the pointer is never dereferenced. */ +#define local_tz ((timezone_t) 1) diff --git a/lib/time.in.h b/lib/time.in.h index df99c8abca9..b91018937ad 100644 --- a/lib/time.in.h +++ b/lib/time.in.h @@ -122,6 +122,23 @@ struct __time_t_must_be_integral { # endif # endif +# if @GNULIB_TZNAME@ +/* tzname[0..1]: Abbreviated time zone names, set by the tzset() function. */ +# if NEED_DECL_TZNAME +extern +# ifdef __cplusplus + "C" +# endif + char *tzname[]; +# endif +# if defined _WIN32 && !defined __CYGWIN__ +/* On native Windows, map 'tzname' to '_tzname' etc., so that -loldnames is not + required. */ +# undef tzname +# define tzname _tzname +# endif +# endif + /* Set *TS to the current time, and return BASE. Upon failure, return 0. */ # if @GNULIB_TIMESPEC_GET@ diff --git a/lib/time_rz.c b/lib/time_rz.c index 468d7539ce1..a6523e1285b 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -44,11 +44,6 @@ enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; used. */ enum { ABBR_SIZE_MIN = DEFAULT_MXFAST - offsetof (struct tm_zone, abbrs) }; -/* Magic cookie timezone_t value, for local time. It differs from - NULL and from all other timezone_t values. Only the address - matters; the pointer is never dereferenced. */ -static timezone_t const local_tz = (timezone_t) 1; - /* Copy to ABBRS the abbreviation at ABBR with size ABBR_SIZE (this includes its trailing null byte). Append an extra null byte to mark the end of ABBRS. */ @@ -70,9 +65,6 @@ tzalloc (char const *name) if (tz) { tz->next = NULL; -#if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE - tz->tzname_copy[0] = tz->tzname_copy[1] = NULL; -#endif tz->tz_is_set = !!name; tz->abbrs[0] = '\0'; if (name) @@ -81,33 +73,16 @@ tzalloc (char const *name) return tz; } -/* Save into TZ any nontrivial time zone abbreviation used by TM, and - update *TM (if HAVE_STRUCT_TM_TM_ZONE) or *TZ (if - !HAVE_STRUCT_TM_TM_ZONE && HAVE_TZNAME) if they use the abbreviation. +/* If HAVE_STRUCT_TM_TM_ZONE, save into TZ any nontrivial time zone + abbreviation used by TM, and update *TM to contain the saved abbreviation. Return true if successful, false (setting errno) otherwise. */ static bool save_abbr (timezone_t tz, struct tm *tm) { -#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME - char const *zone = NULL; +#if HAVE_STRUCT_TM_TM_ZONE + char const *zone = tm->tm_zone; char *zone_copy = (char *) ""; -# if HAVE_TZNAME - int tzname_index = -1; -# endif - -# if HAVE_STRUCT_TM_TM_ZONE - zone = tm->tm_zone; -# endif - -# if HAVE_TZNAME - if (! (zone && *zone) && 0 <= tm->tm_isdst) - { - tzname_index = tm->tm_isdst != 0; - zone = tzname[tzname_index]; - } -# endif - /* No need to replace null zones, or zones within the struct tm. */ if (!zone || ((char *) tm <= zone && zone < (char *) (tm + 1))) return true; @@ -144,12 +119,7 @@ save_abbr (timezone_t tz, struct tm *tm) } /* Replace the zone name so that its lifetime matches that of TZ. */ -# if HAVE_STRUCT_TM_TM_ZONE tm->tm_zone = zone_copy; -# else - if (0 <= tzname_index) - tz->tzname_copy[tzname_index] = zone_copy; -# endif #endif return true; @@ -202,7 +172,7 @@ change_env (timezone_t tz) 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. */ -static timezone_t +timezone_t set_tz (timezone_t tz) { char *env_tz = getenv_TZ (); @@ -229,7 +199,7 @@ set_tz (timezone_t tz) /* Restore an old setting returned by set_tz. It must not be null. Return true (preserving errno) if successful, false (setting errno) otherwise. */ -static bool +bool revert_tz (timezone_t tz) { if (tz == local_tz) @@ -302,9 +272,7 @@ mktime_z (timezone_t tz, struct tm *tm) tm_1.tm_isdst = tm->tm_isdst; time_t t = mktime (&tm_1); bool ok = 0 <= tm_1.tm_yday; -#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME ok = ok && save_abbr (tz, &tm_1); -#endif if (revert_tz (old_tz) && ok) { *tm = tm_1; diff --git a/lib/timespec-add.c b/lib/timespec-add.c index e10c19842cd..50683187117 100644 --- a/lib/timespec-add.c +++ b/lib/timespec-add.c @@ -29,34 +29,22 @@ struct timespec timespec_add (struct timespec a, struct timespec b) { - time_t rs = a.tv_sec; - time_t bs = b.tv_sec; - int ns = a.tv_nsec + b.tv_nsec; - int nsd = ns - TIMESPEC_HZ; - int rns = ns; - - if (0 <= nsd) - { - rns = nsd; - time_t bs1; - if (!ckd_add (&bs1, bs, 1)) - bs = bs1; - else if (rs < 0) - rs++; - else - goto high_overflow; - } - - if (ckd_add (&rs, rs, bs)) + int nssum = a.tv_nsec + b.tv_nsec; + int carry = TIMESPEC_HZ <= nssum; + time_t rs; + int rns; + bool v = ckd_add (&rs, a.tv_sec, b.tv_sec); + if (v == ckd_add (&rs, rs, carry)) + rns = nssum - TIMESPEC_HZ * carry; + else { - if (bs < 0) + if ((TYPE_MINIMUM (time_t) + TYPE_MAXIMUM (time_t)) / 2 < rs) { rs = TYPE_MINIMUM (time_t); rns = 0; } else { - high_overflow: rs = TYPE_MAXIMUM (time_t); rns = TIMESPEC_HZ - 1; } diff --git a/lib/timespec-sub.c b/lib/timespec-sub.c index 315cc638369..f6d948780e4 100644 --- a/lib/timespec-sub.c +++ b/lib/timespec-sub.c @@ -30,28 +30,17 @@ struct timespec timespec_sub (struct timespec a, struct timespec b) { - time_t rs = a.tv_sec; - time_t bs = b.tv_sec; - int ns = a.tv_nsec - b.tv_nsec; - int rns = ns; - - if (ns < 0) - { - rns = ns + TIMESPEC_HZ; - time_t bs1; - if (!ckd_add (&bs1, bs, 1)) - bs = bs1; - else if (- TYPE_SIGNED (time_t) < rs) - rs--; - else - goto low_overflow; - } - - if (ckd_sub (&rs, rs, bs)) + int nsdiff = a.tv_nsec - b.tv_nsec; + bool borrow = nsdiff < 0; + time_t rs; + int rns; + bool v = ckd_sub (&rs, a.tv_sec, b.tv_sec); + if (v == ckd_sub (&rs, rs, borrow)) + rns = nsdiff + TIMESPEC_HZ * borrow; + else { - if (0 < bs) + if ((TYPE_MINIMUM (time_t) + TYPE_MAXIMUM (time_t)) / 2 < rs) { - low_overflow: rs = TYPE_MINIMUM (time_t); rns = 0; } diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4 index b63391a6ad7..ec7aac47089 100644 --- a/m4/canonicalize.m4 +++ b/m4/canonicalize.m4 @@ -1,5 +1,5 @@ # canonicalize.m4 -# serial 39 +# serial 40 dnl Copyright (C) 2003-2007, 2009-2024 Free Software Foundation, Inc. @@ -113,7 +113,7 @@ AC_DEFUN([gl_FUNC_REALPATH_WORKS], result |= 2; free (name); } - /* This test fails on Cygwin 2.9. */ + /* This test fails on macOS 14, Cygwin 2.9. */ #if HAVE_LSTAT { char *name = realpath ("conftest.l/../conftest.a", NULL); @@ -122,7 +122,7 @@ AC_DEFUN([gl_FUNC_REALPATH_WORKS], free (name); } #endif - /* This test fails on Mac OS X 10.13, OpenBSD 6.0. */ + /* This test fails on macOS 14, OpenBSD 6.0. */ { char *name = realpath ("conftest.a/", NULL); if (name != NULL) @@ -163,6 +163,8 @@ AC_DEFUN([gl_FUNC_REALPATH_WORKS], *-gnu* | gnu*) gl_cv_func_realpath_works="guessing yes" ;; # Guess 'nearly' on musl systems. *-musl*) gl_cv_func_realpath_works="guessing nearly" ;; + # Guess no on macOS. + darwin*) gl_cv_func_realpath_works="guessing no" ;; # Guess no on Cygwin. cygwin*) gl_cv_func_realpath_works="guessing no" ;; # Guess no on native Windows. diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 9af4b3a9fc8..6c49edac932 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -1646,7 +1646,6 @@ AC_DEFUN([gl_FILE_LIST], [ m4/vararrays.m4 m4/warn-on-use.m4 m4/warnings.m4 - m4/wchar_t.m4 m4/wint_t.m4 m4/xattr.m4 m4/zzgnulib.m4 diff --git a/m4/largefile.m4 b/m4/largefile.m4 index 2f824089b0a..28813483594 100644 --- a/m4/largefile.m4 +++ b/m4/largefile.m4 @@ -1,5 +1,5 @@ # largefile.m4 -# serial 1 +# serial 2 dnl Copyright 1992-1996, 1998-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, @@ -88,7 +88,7 @@ m4_define([_AC_SYS_YEAR2038_OPTIONS], m4_normalize( # If you change this macro you may also need to change # _AC_SYS_YEAR2038_OPTIONS. AC_DEFUN([_AC_SYS_YEAR2038_PROBE], -[AC_CACHE_CHECK([for $CPPFLAGS option for timestamps after 2038], +[AC_CACHE_CHECK([for $CC option to support timestamps after 2038], [ac_cv_sys_year2038_opts], [ac_save_CPPFLAGS="$CPPFLAGS" ac_opt_found=no @@ -234,7 +234,7 @@ m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize( # If you change this macro you may also need to change # _AC_SYS_LARGEFILE_OPTIONS. AC_DEFUN([_AC_SYS_LARGEFILE_PROBE], -[AC_CACHE_CHECK([for $CPPFLAGS option for large files], +[AC_CACHE_CHECK([for $CC option to support large files], [ac_cv_sys_largefile_opts], [ac_save_CPPFLAGS=$CPPFLAGS ac_opt_found=no diff --git a/m4/nstrftime.m4 b/m4/nstrftime.m4 index f73bca40ec1..534507d300b 100644 --- a/m4/nstrftime.m4 +++ b/m4/nstrftime.m4 @@ -1,5 +1,5 @@ # nstrftime.m4 -# serial 38 +# 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, @@ -11,8 +11,6 @@ AC_DEFUN([gl_FUNC_GNU_STRFTIME], [ AC_REQUIRE([AC_C_RESTRICT]) - # This defines (or not) HAVE_TZNAME and HAVE_STRUCT_TM_TM_ZONE. - AC_REQUIRE([AC_STRUCT_TIMEZONE]) - AC_REQUIRE([gl_TM_GMTOFF]) + AC_CHECK_FUNCS_ONCE([strftime_z]) ]) diff --git a/m4/readlinkat.m4 b/m4/readlinkat.m4 index 1f091e8b636..4c4e3588e0a 100644 --- a/m4/readlinkat.m4 +++ b/m4/readlinkat.m4 @@ -1,5 +1,5 @@ # readlinkat.m4 -# serial 9 +# serial 10 dnl Copyright (C) 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, @@ -34,7 +34,7 @@ AC_DEFUN([gl_FUNC_READLINKAT], [gl_cv_decl_readlinkat_works=no]) ]) # Assume readlinkat has the same bugs as readlink, - # as is the case on OS X 10.10 with trailing slashes. + # as is the case on macOS 14 with trailing slashes. case $gl_cv_decl_readlinkat_works,$gl_cv_func_readlink_trailing_slash,$gl_cv_func_readlink_truncate in *yes,*yes,*yes) ;; diff --git a/m4/stddef_h.m4 b/m4/stddef_h.m4 index 998fe12fa83..c7f75b37fa0 100644 --- a/m4/stddef_h.m4 +++ b/m4/stddef_h.m4 @@ -1,5 +1,5 @@ # stddef_h.m4 -# serial 16 +# serial 17 dnl Copyright (C) 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, @@ -10,7 +10,6 @@ dnl A placeholder for , for platforms that have issues. AC_DEFUN_ONCE([gl_STDDEF_H], [ AC_REQUIRE([gl_STDDEF_H_DEFAULTS]) - AC_REQUIRE([gt_TYPE_WCHAR_T]) dnl Persuade OpenBSD to declare max_align_t. AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) @@ -52,11 +51,6 @@ AC_DEFUN_ONCE([gl_STDDEF_H], GL_GENERATE_STDDEF_H=true fi - if test $gt_cv_c_wchar_t = no; then - HAVE_WCHAR_T=0 - GL_GENERATE_STDDEF_H=true - fi - AC_CACHE_CHECK([whether NULL can be used in arbitrary expressions], [gl_cv_decl_null_works], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include @@ -148,5 +142,4 @@ AC_DEFUN([gl_STDDEF_H_DEFAULTS], STDDEF_NOT_IDEMPOTENT=0; AC_SUBST([STDDEF_NOT_IDEMPOTENT]) REPLACE_NULL=0; AC_SUBST([REPLACE_NULL]) HAVE_MAX_ALIGN_T=1; AC_SUBST([HAVE_MAX_ALIGN_T]) - HAVE_WCHAR_T=1; AC_SUBST([HAVE_WCHAR_T]) ]) diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 8eb5816ad7e..10e1fbb8aa9 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,5 +1,5 @@ # stdio_h.m4 -# serial 63 +# serial 69 dnl Copyright (C) 2007-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, @@ -159,6 +159,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_ZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN]) @@ -177,6 +178,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VAZSPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF]) @@ -186,6 +188,10 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSPRINTF]) dnl Support Microsoft deprecated alias function names by default. gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1]) diff --git a/m4/time_h.m4 b/m4/time_h.m4 index d2f3c9701cb..4ca7305792c 100644 --- a/m4/time_h.m4 +++ b/m4/time_h.m4 @@ -1,5 +1,5 @@ # time_h.m4 -# serial 25 +# serial 26 dnl Copyright (C) 2000-2001, 2003-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, @@ -145,6 +145,7 @@ AC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GETRES]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_R]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_RZ]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZNAME]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZSET]) dnl Support Microsoft deprecated alias function names by default. gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TZSET], [1]) diff --git a/m4/time_rz.m4 b/m4/time_rz.m4 index 8f45f2b1d3d..9613597aca0 100644 --- a/m4/time_rz.m4 +++ b/m4/time_rz.m4 @@ -1,5 +1,5 @@ # time_rz.m4 -# serial 1 +# serial 2 dnl Copyright (C) 2015-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, @@ -13,7 +13,6 @@ AC_DEFUN([gl_TIME_RZ], [ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([gl_TIME_H_DEFAULTS]) - AC_REQUIRE([AC_STRUCT_TIMEZONE]) # On Mac OS X 10.6, localtime loops forever with some time_t values. # See Bug#27706, Bug#27736, and diff --git a/m4/tm_gmtoff.m4 b/m4/tm_gmtoff.m4 index 0c7dcb2a09a..3d97edb7a7f 100644 --- a/m4/tm_gmtoff.m4 +++ b/m4/tm_gmtoff.m4 @@ -1,15 +1,29 @@ # tm_gmtoff.m4 -# serial 3 +# serial 5 dnl Copyright (C) 2002, 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, dnl with or without modifications, as long as this notice is preserved. +dnl Check for tm_gmtoff and tm_zone in struct tm, and #define +dnl HAVE_STRUCT_TM_TM_GMTOFF and HAVE_STRUCT_TM_TM_ZONE accordingly. +dnl Most code that needs one needs the other, so there seemed little +dnl point to having two macros to check them individually. +dnl Although all platforms that we know of have either both members or +dnl neither member, check for the two members separately just in case. +dnl +dnl These days this macro is more useful than AC_STRUCT_TIMEZONE, which also +dnl checks for the obsolescent tzname and does not check for tm_gmtoff. AC_DEFUN([gl_TM_GMTOFF], [ - AC_CHECK_MEMBER([struct tm.tm_gmtoff], - [AC_DEFINE([HAVE_TM_GMTOFF], [1], - [Define if struct tm has the tm_gmtoff member.])], - , - [#include ]) + AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.tm_zone], [], [], + [[#include + ]]) + + dnl Backward compatibility with 2024-and-earlier versions of this macro. + AS_IF([test "$ac_cv_member_struct_tm_tm_gmtoff" = yes], + [AC_DEFINE([HAVE_TM_GMTOFF], [1], + [Define if struct tm has the tm_gmtoff member. + This macro is obsolete. + New code should use HAVE_STRUCT_TM_TM_GMTOFF.])]) ]) diff --git a/m4/wchar_t.m4 b/m4/wchar_t.m4 deleted file mode 100644 index 968832cb296..00000000000 --- a/m4/wchar_t.m4 +++ /dev/null @@ -1,25 +0,0 @@ -# wchar_t.m4 -# serial 4 (gettext-0.18.2) -dnl Copyright (C) 2002-2003, 2008-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, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. -dnl Test whether has the 'wchar_t' type. -dnl Prerequisite: AC_PROG_CC - -AC_DEFUN([gt_TYPE_WCHAR_T], -[ - AC_CACHE_CHECK([for wchar_t], [gt_cv_c_wchar_t], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[#include - wchar_t foo = (wchar_t)'\0';]], - [[]])], - [gt_cv_c_wchar_t=yes], - [gt_cv_c_wchar_t=no])]) - if test $gt_cv_c_wchar_t = yes; then - AC_DEFINE([HAVE_WCHAR_T], [1], [Define if you have the 'wchar_t' type.]) - fi -]) -- 2.39.2