summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2025-07-29 15:00:36 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2025-07-29 15:06:14 -0700
commit3797484608c5bba2057d819215e6ce4d48cacf94 (patch)
tree73062bb3010a6ec4748211e28257c68340665dd4 /lib
parent354f9ba754a973f400249bb203060193d6f984e0 (diff)
Update from Gnulib by running admin/merge-gnulib
Diffstat (limited to 'lib')
-rw-r--r--lib/_Noreturn.h3
-rw-r--r--lib/fpending.c2
-rw-r--r--lib/ftoastr.c10
-rw-r--r--lib/gnulib.mk.in11
-rw-r--r--lib/stdio-impl.h29
-rw-r--r--lib/strftime.c166
-rw-r--r--lib/strftime.h9
-rw-r--r--lib/string.in.h58
8 files changed, 219 insertions, 69 deletions
diff --git a/lib/_Noreturn.h b/lib/_Noreturn.h
index 8e63387914c..d42f15eee62 100644
--- a/lib/_Noreturn.h
+++ b/lib/_Noreturn.h
@@ -27,7 +27,8 @@
This rare bug can be worked around by compiling with 'clang -D_Noreturn=',
though the workaround may generate many false-alarm warnings. */
#ifndef _Noreturn
-# if 201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)
+# if ((!defined __cplusplus || defined __clang__) \
+ && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)))
/* _Noreturn works as-is. */
# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \
|| 0x5110 <= __SUNPRO_C)
diff --git a/lib/fpending.c b/lib/fpending.c
index be8a9877349..529bc7f6517 100644
--- a/lib/fpending.c
+++ b/lib/fpending.c
@@ -39,7 +39,7 @@ __fpending (FILE *fp)
#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
/* GNU libc, BeOS, Haiku, Linux libc5 */
return fp->_IO_write_ptr - fp->_IO_write_base;
-#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
+#elif defined __sferror || defined __OpenBSD__ || defined __DragonFly__ || defined __ANDROID__
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */
return fp_->_p - fp_->_bf._base;
#elif defined __EMX__ /* emx+gcc */
diff --git a/lib/ftoastr.c b/lib/ftoastr.c
index 250b840365e..2438ffe837f 100644
--- a/lib/ftoastr.c
+++ b/lib/ftoastr.c
@@ -114,10 +114,12 @@ FTOASTR (char *buf, size_t bufsize, int flags, int width, FLOAT x)
/* The following method is simple but slow.
For ideas about speeding things up, please see:
- Andrysco M, Jhala R, Lerner S. Printing floating-point numbers:
- a faster, always correct method. ACM SIGPLAN notices - POPL '16.
- 2016;51(1):555-67 <https://doi.org/10.1145/2914770.2837654>; draft at
- <https://cseweb.ucsd.edu/~lerner/papers/fp-printing-popl16.pdf>. */
+ Jeon J. Dragonbox: a new floating-point binary-to-decimal
+ conversion algorithm. 2024. <https://github.com/jk-jeon/dragonbox/>.
+ Used in {fmt} <https://github.com/fmtlib/fmt>.
+
+ Adams U. Ryū: fast float-to-string conversion.
+ PLDI 2018. 270–282. <https://doi.org/10.1145/3192366.3192369>. */
PROMOTED_FLOAT promoted_x = x;
char format[sizeof "%-+ 0*.*Lg"];
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index bb147b69eed..b3774a648b8 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -49,6 +49,7 @@
# --avoid=iswxdigit \
# --avoid=langinfo-h \
# --avoid=libgmp-mpq \
+# --avoid=localcharset \
# --avoid=locale-h \
# --avoid=localename-unsafe-limited \
# --avoid=lock \
@@ -144,7 +145,7 @@
# mktime \
# nanosleep \
# nproc \
-# nstrftime \
+# nstrftime-limited \
# pathmax \
# pipe2 \
# pselect \
@@ -2836,17 +2837,17 @@ EXTRA_DIST += nproc.h
endif
## end gnulib module nproc
-## begin gnulib module nstrftime
-ifeq (,$(OMIT_GNULIB_MODULE_nstrftime))
+## begin gnulib module nstrftime-limited
+ifeq (,$(OMIT_GNULIB_MODULE_nstrftime-limited))
libgnu_a_SOURCES += nstrftime.c
-EXTRA_DIST += strftime.c strftime.h
+EXTRA_DIST += calendar-ethiopian.h calendar-persian.h calendar-thai.h calendars.h strftime.c strftime.h
EXTRA_libgnu_a_SOURCES += strftime.c
endif
-## end gnulib module nstrftime
+## end gnulib module nstrftime-limited
## begin gnulib module open
ifeq (,$(OMIT_GNULIB_MODULE_open))
diff --git a/lib/stdio-impl.h b/lib/stdio-impl.h
index 4b4263fe908..4abf9e68b23 100644
--- a/lib/stdio-impl.h
+++ b/lib/stdio-impl.h
@@ -82,7 +82,7 @@
#include <errno.h> /* For detecting Plan9. */
-#if defined __sferror || defined __DragonFly__ || defined __ANDROID__
+#if defined __sferror || defined __OpenBSD__ || defined __DragonFly__ || defined __ANDROID__
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
# if defined __DragonFly__ /* DragonFly */
@@ -108,13 +108,15 @@
# define _flags pub._flags
# define _r pub._r
# define _w pub._w
-# elif defined __ANDROID__ /* Android */
-# ifdef __LP64__
+# elif defined __ANDROID__ || defined __OpenBSD__ /* Android, OpenBSD */
+# if defined __LP64__ && !defined __OpenBSD__
# define _gl_flags_file_t int
# else
# define _gl_flags_file_t short
# endif
-# ifdef __LP64__
+# if defined __OpenBSD__
+# define _gl_file_offset_t fpos_t
+# elif defined __LP64__
# define _gl_file_offset_t int64_t
# else
/* see https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
@@ -122,10 +124,12 @@
# endif
/* Up to this commit from 2015-10-12
<https://android.googlesource.com/platform/bionic.git/+/f0141dfab10a4b332769d52fa76631a64741297a>
- the innards of FILE were public, and fp_ub could be defined like for OpenBSD,
+ the innards of FILE were public,
see <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/fileext.h>
and <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/local.h>.
- After this commit, the innards of FILE are hidden. */
+ After this commit, the innards of FILE are hidden. Likewise for OpenBSD
+ up to this commit from 2025-07-16
+ <https://github.com/openbsd/src/commit/b7f6c2eb760a2da367dd51d539ef06f5f3553790>. */
# define fp_ ((struct { unsigned char *_p; \
int _r; \
int _w; \
@@ -152,9 +156,8 @@
# define fp_ fp
# endif
-# if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __OpenBSD__ || defined __minix /* NetBSD >= 1.5ZA, OpenBSD, Minix 3 */
+# if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __minix /* NetBSD >= 1.5ZA, Minix 3 */
/* See <https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
- and <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
and <https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/master/lib/libc/stdio/fileext.h> */
struct __sfileext
{
@@ -162,7 +165,7 @@
/* More fields, not relevant here. */
};
# define fp_ub ((struct __sfileext *) fp->_ext._base)->_ub
-# elif defined __ANDROID__ /* Android */
+# elif defined __ANDROID__ || defined __OpenBSD__ /* Android, OpenBSD */
struct __sfileext
{
struct { unsigned char *_base; size_t _size; } _ub; /* ungetc buffer */
@@ -175,9 +178,11 @@
# define HASUB(fp) (fp_ub._base != NULL)
-# if defined __ANDROID__ /* Android */
- /* Needed after this commit from 2016-01-25
- <https://android.googlesource.com/platform/bionic.git/+/e70e0e9267d069bf56a5078c99307e08a7280de7> */
+# if defined __ANDROID__ || defined __OpenBSD__ /* Android, OpenBSD */
+ /* Needed after this Android commit from 2016-01-25
+ <https://android.googlesource.com/platform/bionic.git/+/e70e0e9267d069bf56a5078c99307e08a7280de7>
+ And after this OpenBSD commit from 2025-07-16
+ <https://github.com/openbsd/src/commit/b7f6c2eb760a2da367dd51d539ef06f5f3553790>. */
# ifndef __SEOF
# define __SLBF 1
# define __SNBF 2
diff --git a/lib/strftime.c b/lib/strftime.c
index 64a1f0456a2..537172d8be6 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -53,7 +53,7 @@
/* 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
- AC_DEFINE([REQUIRE_GNUISH_STRFTIME_AM_PM], 1) and if you do that
+ AC_DEFINE([REQUIRE_GNUISH_STRFTIME_AM_PM], [false]) and if you do that
you may be able to omit Gnulib's localename module and its dependencies. */
#ifndef REQUIRE_GNUISH_STRFTIME_AM_PM
# define REQUIRE_GNUISH_STRFTIME_AM_PM true
@@ -63,6 +63,25 @@
# define REQUIRE_GNUISH_STRFTIME_AM_PM false
#endif
+/* Whether to include support for non-Gregorian calendars (outside of the scope
+ of ISO C, POSIX, and glibc). This matters only in non-C locales.
+ The default is to include it, except on platforms where retrieving the locale
+ name drags in too many dependencies
+ (LOCALENAME_ENHANCE_LOCALE_FUNCS || !SETLOCALE_NULL_ONE_MTSAFE).
+ You can override this via
+ AC_DEFINE([SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME], [false])
+ and if you do that you may be able to omit Gnulib's localename module and its
+ dependencies. */
+#ifndef SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+# define SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME true
+#endif
+#if defined _LIBC || (HAVE_ONLY_C_LOCALE || USE_C_LOCALE) \
+ || ((defined __OpenBSD__ || defined _AIX || defined __ANDROID__) \
+ && !GNULIB_NSTRFTIME)
+# undef SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+# define SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME false
+#endif
+
#if HAVE_ONLY_C_LOCALE || USE_C_LOCALE
# include "c-ctype.h"
#else
@@ -78,14 +97,8 @@
C library on the various platforms (UTF-8, GB2312, GBK, CP936,
GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
- cannot occur in a multibyte character except in the first byte.
-
- The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
- this encoding has never been seen in real-life use, so we ignore
- it. */
-#if !(defined __osf__ && 0)
-# define MULTIBYTE_IS_FORMAT_SAFE 1
-#endif
+ cannot occur in a multibyte character except in the first byte. */
+#define MULTIBYTE_IS_FORMAT_SAFE 1
#define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
#if DO_MULTIBYTE
@@ -164,6 +177,16 @@ enum pad_style
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#endif
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+/* Support for non-Gregorian calendars. */
+# include "localcharset.h"
+# include "localename.h"
+# include "calendars.h"
+# define CAL_ARGS(x,y) x, y,
+#else
+# define CAL_ARGS(x,y) /* empty */
+#endif
+
#ifdef _LIBC
# define mktime_z(tz, tm) mktime (tm)
@@ -873,6 +896,8 @@ static CHAR_T const c_month_names[][sizeof "September"] =
static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
const CHAR_T *, const struct tm *,
+ CAL_ARGS (const struct calendar *,
+ struct calendar_date *)
bool, enum pad_style, int, bool *
extra_args_spec LOCALE_PARAM);
@@ -1087,9 +1112,36 @@ my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
const CHAR_T *format,
const struct tm *tp extra_args_spec LOCALE_PARAM)
{
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ /* Recognize whether to use a non-Gregorian calendar. */
+ const struct calendar *cal = NULL;
+ struct calendar_date caldate;
+ if (strcmp (locale_charset (), "UTF-8") == 0)
+ {
+ const char *loc = gl_locale_name_unsafe (LC_TIME, "LC_TIME");
+ if (strlen (loc) >= 5 && !(loc[5] >= 'A' && loc[5] <= 'Z'))
+ {
+ if (memcmp (loc, "th_TH", 5) == 0)
+ cal = &thai_calendar;
+ else if (memcmp (loc, "fa_IR", 5) == 0)
+ cal = &persian_calendar;
+ else if (memcmp (loc, "am_ET", 5) == 0)
+ cal = &ethiopian_calendar;
+ if (cal != NULL)
+ {
+ if (cal->from_gregorian (&caldate,
+ tp->tm_year + 1900,
+ tp->tm_mon,
+ tp->tm_mday) < 0)
+ cal = NULL;
+ }
+ }
+ }
+#endif
bool tzset_called = false;
- return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
- ZERO_PAD, -1,
+ return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp,
+ CAL_ARGS (cal, &caldate)
+ false, ZERO_PAD, -1,
&tzset_called extra_args LOCALE_ARG);
}
libc_hidden_def (my_strftime)
@@ -1101,7 +1153,10 @@ libc_hidden_def (my_strftime)
static size_t
__strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
const CHAR_T *format,
- const struct tm *tp, bool upcase,
+ const struct tm *tp,
+ CAL_ARGS (const struct calendar *cal,
+ struct calendar_date *caldate)
+ bool upcase,
enum pad_style yr_spec, int width, bool *tzset_called
extra_args_spec LOCALE_PARAM)
{
@@ -1113,7 +1168,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
#endif
int saved_errno = errno;
- int hour12 = tp->tm_hour;
+
#ifdef _NL_CURRENT
/* We cannot make the following values variables since we must delay
the evaluation of these values until really needed since some
@@ -1173,6 +1228,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
const char *format_end = NULL;
#endif
+ int hour12 = tp->tm_hour;
if (hour12 > 12)
hour12 -= 12;
else
@@ -1189,6 +1245,9 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
bool negative_number; /* The number is negative. */
bool always_output_a_sign; /* +/- should always be output. */
int tz_colon_mask; /* Bitmask of where ':' should appear. */
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ unsigned int digits_base = '0'; /* '0' or some UCS-2 value. */
+#endif
const CHAR_T *subfmt;
CHAR_T *bufp;
CHAR_T buf[1
@@ -1436,6 +1495,14 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
}
if (modifier == L_('E'))
goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ {
+ cpy (STRLEN (caldate->month_names[caldate->month].abbrev),
+ caldate->month_names[caldate->month].abbrev);
+ break;
+ }
+#endif
#ifdef _NL_CURRENT
if (modifier == L_('O'))
cpy (aam_len, a_altmonth);
@@ -1460,6 +1527,14 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
to_uppcase = true;
to_lowcase = false;
}
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ {
+ cpy (STRLEN (caldate->month_names[caldate->month].full),
+ caldate->month_names[caldate->month].full);
+ break;
+ }
+#endif
#ifdef _NL_CURRENT
if (modifier == L_('O'))
cpy (STRLEN (f_altmonth), f_altmonth);
@@ -1511,13 +1586,17 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
subformat_width:
{
size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
- subfmt, tp, to_uppcase,
- pad, subwidth, tzset_called
+ subfmt, tp,
+ CAL_ARGS (cal, caldate)
+ to_uppcase, pad, subwidth,
+ tzset_called
extra_args LOCALE_ARG);
add (len, __strftime_internal (p,
STRFTIME_ARG (maxsize - i)
- subfmt, tp, to_uppcase,
- pad, subwidth, tzset_called
+ subfmt, tp,
+ CAL_ARGS (cal, caldate)
+ to_uppcase, pad, subwidth,
+ tzset_called
extra_args LOCALE_ARG));
}
break;
@@ -1639,6 +1718,13 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
case L_('x'):
if (modifier == L_('O'))
goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ {
+ subfmt = cal->d_fmt;
+ goto subformat;
+ }
+#endif
#ifdef _NL_CURRENT
if (! (modifier == L_('E')
&& (*(subfmt =
@@ -1652,6 +1738,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
#else
goto underlying_strftime;
#endif
+
case L_('D'):
if (modifier != 0)
goto bad_format;
@@ -1662,12 +1749,20 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
if (modifier == L_('E'))
goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ DO_NUMBER (2, caldate->day);
+#endif
DO_NUMBER (2, tp->tm_mday);
case L_('e'):
if (modifier == L_('E'))
goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ DO_NUMBER_SPACEPAD (2, caldate->day);
+#endif
DO_NUMBER_SPACEPAD (2, tp->tm_mday);
/* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
@@ -1709,7 +1804,10 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
negating it. */
if (modifier == L_('O') && !negative_number)
{
-#ifdef _NL_CURRENT
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ digits_base = cal->alt_digits_base;
+#elif defined _NL_CURRENT
/* Get the locale specific alternate representation of
the number. If none exist NULL is returned. */
const CHAR_T *cp = nl_get_alt_digit (u_number_value
@@ -1724,9 +1822,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
break;
}
}
-#elif HAVE_ONLY_C_LOCALE || (USE_C_LOCALE && !HAVE_STRFTIME_L)
-#else
- goto underlying_strftime;
#endif
}
@@ -1740,7 +1835,13 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
if (tz_colon_mask & 1)
*--bufp = ':';
tz_colon_mask >>= 1;
- *--bufp = u_number_value % 10 + L_('0');
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ *--bufp = u_number_value % 10 + (digits_base & 0xFF);
+ if (digits_base >= 0x100)
+ *--bufp = digits_base >> 8;
+#else
+ *--bufp = u_number_value % 10 + '0';
+#endif
u_number_value /= 10;
}
while (u_number_value != 0 || tz_colon_mask != 0);
@@ -1755,8 +1856,13 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
CHAR_T sign_char = (negative_number ? L_('-')
: always_output_a_sign ? L_('+')
: 0);
- int numlen = buf + sizeof buf / sizeof buf[0] - bufp;
- int shortage = width - !!sign_char - numlen;
+ int number_bytes = buf + sizeof buf / sizeof buf[0] - bufp;
+ int number_digits = number_bytes;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (digits_base >= 0x100)
+ number_digits = number_bytes / 2;
+#endif
+ int shortage = width - !!sign_char - number_digits;
int padding = pad == NO_PAD || shortage <= 0 ? 0 : shortage;
if (sign_char)
@@ -1772,7 +1878,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
width--;
}
- cpy (numlen, bufp);
+ cpy (number_bytes, bufp);
}
break;
@@ -1833,6 +1939,10 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
if (modifier == L_('E'))
goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ DO_SIGNED_NUMBER (2, false, caldate->month + 1U);
+#endif
DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
#ifndef _LIBC
@@ -2070,9 +2180,11 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
goto underlying_strftime;
#endif
}
- if (modifier == L_('O'))
- goto bad_format;
+#if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME
+ if (cal != NULL)
+ DO_YEARISH (4, false, caldate->year);
+#endif
DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE,
tp->tm_year + (unsigned int) TM_YEAR_BASE);
diff --git a/lib/strftime.h b/lib/strftime.h
index 3b7e20f236a..a76c98c9c82 100644
--- a/lib/strftime.h
+++ b/lib/strftime.h
@@ -59,6 +59,15 @@ extern "C" {
date and time: %c
time zone: %z %Z
nanosecond %N
+ In locales with non-Gregorian calendars, the following conversions don't
+ apply in the expected way:
+ date:
+ century %C
+ year %y
+ week-based year %G %g
+ week in year %U %W %V
+ day in year %j
+ year, month, day %D
Store the result, as a string with a trailing NUL character, at the
beginning of the array __S[0..__MAXSIZE-1] and return the length of
diff --git a/lib/string.in.h b/lib/string.in.h
index e3d94b76c17..9a039c7ba06 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -214,65 +214,85 @@ _GL_EXTERN_C void free (void *);
/* Declarations for ISO C N3322. */
#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
+# ifndef memcpy
_GL_EXTERN_C void *memcpy (void *__dest, const void *__src, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
+# endif
+# ifndef memccpy
_GL_EXTERN_C void *memccpy (void *__dest, const void *__src, int __c, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 4)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 4);
+# endif
+# ifndef memmove
_GL_EXTERN_C void *memmove (void *__dest, const void *__src, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
+# endif
+# ifndef strncpy
_GL_EXTERN_C char *strncpy (char *__dest, const char *__src, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
+# endif
+# ifndef strndup
_GL_EXTERN_C char *strndup (const char *__s, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2);
+# endif
+# ifndef strncat
_GL_EXTERN_C char *strncat (char *__dest, const char *__src, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
+# endif
+# ifndef memcmp
_GL_EXTERN_C int memcmp (const void *__s1, const void *__s2, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
+# endif
+# ifndef strncmp
_GL_EXTERN_C int strncmp (const char *__s1, const char *__s2, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
-# ifndef __cplusplus
+# endif
+# if !defined memchr && !defined __cplusplus
_GL_EXTERN_C void *memchr (const void *__s, int __c, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
_GL_EXTERN_C void *memrchr (const void *__s, int __c, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
# endif
+# ifndef memset
_GL_EXTERN_C void *memset (void *__s, int __c, size_t __n)
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
+# endif
+# ifndef memset_explicit
_GL_EXTERN_C void *memset_explicit (void *__s, int __c, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
+# endif
#endif