On glibc 2.15 and Haiku (2022), I am seeing a test failure:
../../gltests/test-vasnwprintf-posix.c:521: assertion 'wcscmp (result,
L"0x1.922p+1 33") == 0 || wcscmp (result, L"0x3.244p+0 33") == 0 || wcscmp
(result, L"0x6.488p-1 33") == 0 || wcscmp (result, L"0xc.91p-2 33") == 0' failed
FAIL test-vasnwprintf-posix (exit status: 134)
Here, instead of L"0xc.91p-2 33", the result is L"0xc.c9p-2 33", which is
off by more than 2%.
The value is wrong for many more 'long double' arguments, as can be seen
from the attached test program and output.
Interestingly, for %a and %La in narrow format strings, and for %a in wide
format strings, there is no bug.
On the glibc side, the bug is fixed in glibc 2.17 and newer. Nevertheless,
I am adding the workaround since it affects many argument values and a
recent Haiku as well.
2023-04-07 Bruno Haible
vasnwprintf-posix: Work around %La bug in glibc 2.15 and Haiku.
* m4/printf.m4 (gl_SWPRINTF_DIRECTIVE_LA): New macro.
* m4/vasnprintf.m4 (gl_PREREQ_VASNWPRINTF): Invoke
gl_SWPRINTF_DIRECTIVE_LA and define NEED_WPRINTF_DIRECTIVE_LA
accordingly.
* lib/vasnprintf.c: When compiling vasnwprintf, if
NEED_WPRINTF_DIRECTIVE_LA, handle the %La and %LA directives ourselves.
* doc/posix-functions/swprintf.texi: Mention the %La bug.
diff --git a/doc/posix-functions/swprintf.texi
b/doc/posix-functions/swprintf.texi
index cd20d0e702..fe36bc215a 100644
--- a/doc/posix-functions/swprintf.texi
+++ b/doc/posix-functions/swprintf.texi
@@ -36,6 +36,12 @@ accommodate all Unicode characters.
@item
On Windows, this function does not take a buffer size as second argument.
@item
+This function produces wrong values for the @samp{La} directive
+on some platforms:
+glibc 2.15,
+@c https://dev.haiku-os.org/ticket/18353
+Haiku.
+@item
This function does not support size specifiers as in C23 (@code{w8},
@code{w16}, @code{w32}, @code{w64}, @code{wf8}, @code{wf16}, @code{wf32},
@code{wf64}) on some platforms:
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 6eb056d0e9..efd610ebe4 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -103,7 +103,7 @@
#include "attribute.h"
-#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE
+#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE ||
(NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include
# include "float+.h"
#endif
@@ -113,7 +113,7 @@
# include "isnand-nolibm.h"
#endif
-#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
+#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE ||
(NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include
# include "isnanl-nolibm.h"
# include "fpucw.h"
@@ -125,7 +125,7 @@
# include "printf-frexp.h"
#endif
-#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE ||
(NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include
# include "isnanl-nolibm.h"
# include "printf-frexpl.h"
@@ -357,7 +357,7 @@ local_wctomb (char *s, wchar_t wc)
# endif
#endif
-#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE ||
NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE ||
NEED_PRINTF_INFINITE_DOUBLE
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE ||
NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE ||
NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
/* Determine the decimal-point character according to the current locale. */
# ifndef decimal_point_char_defined
# define decimal_point_char_defined 1
@@ -3929,14 +3929,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
length += count;
}
#endif
-#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
|| (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
else if ((dp->conversion == 'a' || dp->conversion == 'A')
# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE &&
NEED_PRINTF_DOUBLE))
&& (0
# if NEED_PRINTF_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_DOUBLE
# endif
-# if NEED_PRINTF_LONG_DOUBLE
+# if NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA &&
WIDE_CHAR_VERSION)
|| a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
# endif
)
@@ -4056,7 +4056,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
p = tmp;
if (type == TYPE_LONGDOUBLE)
{
-# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
+# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE ||
(NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)