public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio
@ 2018-11-15 21:45 Gabriel F. T. Gomes
  2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
                   ` (7 more replies)
  0 siblings, 8 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:45 UTC (permalink / raw)
  To: libc-alpha

Patches 2, 3, and 5 did not change, but since they depend on previous
patches in this set, I'm sending them again for completeness.

I added a `Changed since v2' section to each patch in the set describing
the changes.  But I didn't mention the removal of DCO's signed-off-by in
each one of them to avoid repetition.

Also, I'm using `git format-patch -M90% -C', as suggested by Adhemerval.

Thank you.

Zack Weinberg (7):
  Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  Add __v*printf_internal with flags arguments
  Add __vsyslog_internal, with same flags as __v*printf_internal.
  Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.

 argp/argp-fmtstream.c                            |    3 +-
 argp/argp-help.c                                 |    4 +-
 argp/argp-namefrob.h                             |    2 -
 debug/Makefile                                   |    2 +-
 debug/asprintf_chk.c                             |   20 +-
 debug/dprintf_chk.c                              |   20 +-
 debug/fprintf_chk.c                              |   20 +-
 debug/fwprintf_chk.c                             |   20 +-
 debug/obprintf_chk.c                             |   96 +-
 debug/printf_chk.c                               |   20 +-
 debug/snprintf_chk.c                             |   24 +-
 debug/sprintf_chk.c                              |   25 +-
 debug/swprintf_chk.c                             |   27 +-
 debug/vasprintf_chk.c                            |   68 +-
 debug/vdprintf_chk.c                             |   37 +-
 debug/vfprintf_chk.c                             |   21 +-
 debug/vfwprintf_chk.c                            |   21 +-
 stdio-common/scanf.c => debug/vobprintf_chk.c    |   25 +-
 debug/vprintf_chk.c                              |   20 +-
 debug/vsnprintf_chk.c                            |   46 +-
 debug/vsprintf_chk.c                             |   69 +-
 debug/vswprintf_chk.c                            |   51 +-
 debug/vwprintf_chk.c                             |   21 +-
 debug/wprintf_chk.c                              |   21 +-
 hurd/vpprintf.c                                  |    2 +-
 include/stdio.h                                  |    8 -
 include/sys/syslog.h                             |   19 +-
 include/wchar.h                                  |   12 -
 libio/fwprintf.c                                 |    2 +-
 libio/iolibio.h                                  |    8 -
 libio/iovdprintf.c                               |   13 +-
 libio/iovsprintf.c                               |   66 +-
 libio/iovsscanf.c                                |   12 +-
 libio/iovswscanf.c                               |   14 +-
 libio/libio.h                                    |    8 -
 libio/libioP.h                                   |   97 +-
 libio/obprintf.c                                 |   19 +-
 libio/strfile.h                                  |   33 +-
 libio/swprintf.c                                 |    2 +-
 libio/swscanf.c                                  |   10 +-
 libio/vasprintf.c                                |   20 +-
 libio/vscanf.c                                   |    2 +-
 libio/vsnprintf.c                                |   16 +-
 libio/vswprintf.c                                |   16 +-
 libio/vwprintf.c                                 |    2 +-
 libio/vwscanf.c                                  |    2 +-
 libio/wprintf.c                                  |    2 +-
 libio/wscanf.c                                   |    2 +-
 misc/syslog.c                                    |   36 +-
 stdio-common/Makefile                            |    4 +-
 stdio-common/Versions                            |    3 +
 stdio-common/asprintf.c                          |    6 +-
 stdio-common/dprintf.c                           |    5 +-
 stdio-common/fprintf.c                           |    2 +-
 stdio-common/fxprintf.c                          |    4 +-
 stdio-common/{isoc99_scanf.c => iovfscanf.c}     |   36 +-
 stdio-common/{isoc99_scanf.c => iovfwscanf.c}    |   36 +-
 stdio-common/isoc99_fscanf.c                     |    7 +-
 stdio-common/isoc99_scanf.c                      |   12 +-
 stdio-common/isoc99_sscanf.c                     |    8 +-
 stdio-common/isoc99_vfscanf.c                    |    9 +-
 stdio-common/isoc99_vscanf.c                     |    9 +-
 stdio-common/isoc99_vsscanf.c                    |   16 +-
 stdio-common/printf.c                            |    3 +-
 stdio-common/scanf.c                             |    2 +-
 stdio-common/snprintf.c                          |    4 +-
 stdio-common/sprintf.c                           |    4 +-
 stdio-common/sscanf.c                            |   12 +-
 stdio-common/{vfprintf.c => vfprintf-internal.c} |   60 +-
 stdio-common/vfprintf.c                          | 2351 +----------------
 stdio-common/{vfscanf.c => vfscanf-internal.c}   |   42 +-
 stdio-common/vfscanf.c                           | 3042 +---------------------
 stdio-common/vfwprintf-internal.c                |    2 +
 stdio-common/vfwprintf.c                         |   28 +-
 stdio-common/vfwscanf-internal.c                 |    2 +
 stdio-common/vfwscanf.c                          |   28 +-
 stdio-common/vprintf.c                           |    4 +-
 stdlib/strfrom-skeleton.c                        |    2 +-
 sysdeps/generic/math_ldbl_opt.h                  |    5 +-
 sysdeps/generic/stdio-lock.h                     |    7 -
 sysdeps/ieee754/ldbl-opt/Makefile                |    2 +-
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h         |   13 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |  773 +++---
 sysdeps/nptl/stdio-lock.h                        |    7 -
 wcsmbs/isoc99_fwscanf.c                          |    7 +-
 wcsmbs/isoc99_swscanf.c                          |   11 +-
 wcsmbs/isoc99_vfwscanf.c                         |    9 +-
 wcsmbs/isoc99_vswscanf.c                         |   15 +-
 wcsmbs/isoc99_vwscanf.c                          |    9 +-
 wcsmbs/isoc99_wscanf.c                           |    7 +-
 90 files changed, 1004 insertions(+), 6710 deletions(-)
 copy stdio-common/scanf.c => debug/vobprintf_chk.c (61%)
 copy stdio-common/{isoc99_scanf.c => iovfscanf.c} (54%)
 copy stdio-common/{isoc99_scanf.c => iovfwscanf.c} (54%)
 copy stdio-common/{vfprintf.c => vfprintf-internal.c} (98%)
 copy stdio-common/{vfscanf.c => vfscanf-internal.c} (98%)
 create mode 100644 stdio-common/vfwprintf-internal.c
 create mode 100644 stdio-common/vfwscanf-internal.c

-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
  2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
  2018-11-15 21:46 ` [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal " Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-22 18:00   ` Adhemerval Zanella
  2018-11-15 21:46 ` [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Gabriel F. T. Gomes
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changes since v2

  - None, but dependent on previous patch in the set, thus resending.

Changed since v1:

  - Fixed white-space errors.
  - Removed internal declaration of __vsyslog_chk, because it's no
    longer called from within libc.  There's a call to it in the inline
    definition of vsyslog in bits/syslog.h, but that definition is only
    inlined in user code with:
      #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
  - Removed libc_hidden_def and libc_hidden_proto for vsyslog, as it is
    never called internally (it never was).
  - Added attribute_hidden to the internal declaration of
    __vsyslog_internal.  Here are the objdumps of one internal call,
    before and after this change, on a 32-bits powerpc machine:
    Without attribute_hidden:
      $ objdump -d --reloc SYSLOG-PRISTINE-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 17
      000fc790 <vsyslog@@GLIBC_2.4>:
         fc790:       94 21 ff f0     stwu    r1,-16(r1)
         fc794:       38 c0 00 00     li      r6,0
         fc798:       7c 08 02 a6     mflr    r0
         fc79c:       42 9f 00 05     bcl     20,4*cr7+so,fc7a0 <vsyslog@@GLIBC_2.4+0x10>
         fc7a0:       93 c1 00 08     stw     r30,8(r1)
         fc7a4:       90 01 00 14     stw     r0,20(r1)
         fc7a8:       7f c8 02 a6     mflr    r30
         fc7ac:       3f de 00 0a     addis   r30,r30,10
         fc7b0:       3b de 38 54     addi    r30,r30,14420
         fc7b4:       4b ff f9 9d     bl      fc150 <__vsyslog_internal>
         fc7b8:       80 01 00 14     lwz     r0,20(r1)
         fc7bc:       83 c1 00 08     lwz     r30,8(r1)
         fc7c0:       38 21 00 10     addi    r1,r1,16
         fc7c4:       7c 08 03 a6     mtlr    r0
         fc7c8:       4e 80 00 20     blr
         fc7cc:       60 00 00 00     nop
    With attribute_hidden:
      $ objdump -d --reloc SYSLOG-PATCHED-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 5
      000fc780 <vsyslog@@GLIBC_2.4>:
         fc780:       38 c0 00 00     li      r6,0
         fc784:       4b ff f9 cc     b       fc150 <__vsyslog_internal>
         fc788:       60 00 00 00     nop
         fc78c:       60 00 00 00     nop

-- 8< --
__nldbl___vsyslog_chk will ultimately want to pass PRINTF_LDBL_IS_DBL
down to __vfprintf_internal *as well as* possibly setting PRINTF_FORTIFY.
To make that possible, we need a __vsyslog_internal that takes the
same flags as printf.  The code in misc/syslog.c does also get a
little simpler.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* misc/syslog.c: Include libioP.h, not iolibio.h.
	(__vsyslog_internal): New function with the former body of
	__vsyslog_chk; takes mode_flags argument same as
	__v*printf_internal.  Call __vfprintf_internal directly.

	(__vsyslog_chk): Now a wrapper around __vsyslog_internal.
	Remove libc_hidden_def.
	(__syslog, __syslog_chk): Use __vsyslog_internal.
	(__vsyslog): Move to just below __syslog.  Use __vsyslog_internal.

	* include/sys/syslog.h: Add multiple inclusion guard.
	Add prototype for __vsyslog_internal.
	Remove declaration and libc_hidden_proto for __vsyslog_chk.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl___vsyslog_chk):
	Use __vsyslog_internal.
---
 include/sys/syslog.h                    | 19 ++++++++++-------
 misc/syslog.c                           | 36 +++++++++++++++++----------------
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c |  2 +-
 3 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 3be3189ed1..89d3479ebc 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -1,11 +1,16 @@
+#ifndef _LIBC_SYS_SYSLOG_H
+#define _LIBC_SYS_SYSLOG_H 1
 #include <misc/sys/syslog.h>
-
 #ifndef _ISOMAC
+
 libc_hidden_proto (syslog)
-libc_hidden_proto (vsyslog)
 
-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
-			   __gnuc_va_list __ap)
-     __attribute__ ((__format__ (__printf__, 3, 0)));
-libc_hidden_proto (__vsyslog_chk)
-#endif
+/* __vsyslog_internal uses the same mode_flags bits as
+   __v*printf_internal; see libio/libioP.h.  */
+extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list ap,
+				unsigned int mode_flags)
+     attribute_hidden
+     __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#endif /* _ISOMAC */
+#endif /* syslog.h */
diff --git a/misc/syslog.c b/misc/syslog.c
index 644dbe80ec..3a15da41ce 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -53,7 +53,7 @@ static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
 
 #include <stdarg.h>
 
-#include <libio/iolibio.h>
+#include <libio/libioP.h>
 #include <math_ldbl_opt.h>
 
 #include <kernel-features.h>
@@ -114,24 +114,38 @@ __syslog(int pri, const char *fmt, ...)
 	va_list ap;
 
 	va_start(ap, fmt);
-	__vsyslog_chk(pri, -1, fmt, ap);
+	__vsyslog_internal(pri, fmt, ap, 0);
 	va_end(ap);
 }
 ldbl_hidden_def (__syslog, syslog)
 ldbl_strong_alias (__syslog, syslog)
 
+void
+__vsyslog(int pri, const char *fmt, va_list ap)
+{
+	__vsyslog_internal(pri, fmt, ap, 0);
+}
+ldbl_weak_alias (__vsyslog, vsyslog)
+
 void
 __syslog_chk(int pri, int flag, const char *fmt, ...)
 {
 	va_list ap;
 
 	va_start(ap, fmt);
-	__vsyslog_chk(pri, flag, fmt, ap);
+	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
 	va_end(ap);
 }
 
 void
 __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
+{
+	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
+}
+
+void
+__vsyslog_internal(int pri, const char *fmt, va_list ap,
+		   unsigned int mode_flags)
 {
 	struct tm now_tm;
 	time_t now;
@@ -215,11 +229,8 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
 	    __set_errno (saved_errno);
 
 	    /* We have the header.  Print the user's format into the
-               buffer.  */
-	    if (flag == -1)
-	      vfprintf (f, fmt, ap);
-	    else
-	      __vfprintf_chk (f, flag, fmt, ap);
+	       buffer.  */
+	    __vfprintf_internal (f, fmt, ap, mode_flags);
 
 	    /* Close the memory stream; this will finalize the data
 	       into a malloc'd buffer in BUF.  */
@@ -316,15 +327,6 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
 	if (buf != failbuf)
 		free (buf);
 }
-libc_hidden_def (__vsyslog_chk)
-
-void
-__vsyslog(int pri, const char *fmt, va_list ap)
-{
-  __vsyslog_chk (pri, -1, fmt, ap);
-}
-ldbl_hidden_def (__vsyslog, vsyslog)
-ldbl_weak_alias (__vsyslog, vsyslog)
 
 static struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index bda84af0bb..958bbc1834 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -843,7 +843,7 @@ attribute_compat_text_section
 __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
 {
   set_no_long_double ();
-  __vsyslog_chk (pri, flag, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
 }
 libc_hidden_def (__nldbl___vsyslog_chk)
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
                   ` (2 preceding siblings ...)
  2018-11-15 21:46 ` [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-22 17:38   ` Adhemerval Zanella
  2018-11-15 21:46 ` [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319) Gabriel F. T. Gomes
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changes since v2

  - None, but dependent on previous patch in the set, thus resending.

Changes since v1:

  - Cleared VARGARSn comments.
  - Added signed-off-by statements.

-- 8< --
Change the callers of __vfscanf_internal and __vfwscanf_internal that
want C99-compliant behavior to communicate this via the new flags
argument, rather than setting bits on the FILE object.  This also
means these functions do not need to do their own locking.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* stdio-common/isoc99_scanf.c
	* stdio-common/isoc99_fscanf.c
	* stdio-common/isoc99_sscanf.c
	* stdio-common/isoc99_vscanf.c
	* stdio-common/isoc99_vfscanf.c
	* stdio-common/isoc99_vsscanf.c
	* wcsmbs/isoc99_wscanf.c
	* wcsmbs/isoc99_fwscanf.c
	* wcsmbs/isoc99_swscanf.c
	* wcsmbs/isoc99_vwscanf.c
	* wcsmbs/isoc99_vfwscanf.c
	* wcsmbs/isoc99_vswscanf.c:
	Pass SCANF_ISOC99_A to __vfscanf_internal and/or __vfwscanf_internal.
	Do not set _IO_FLAGS2_SCANF_STD on the FILE passed to that function.
	No need to lock and unlock the FILE passed to that function.

	* stdio-common/vfscanf-internal.c
	(__vfscanf_internal, __vfwscanf_internal):
	Don't look at _IO_FLAGS2_SCANF_STD.
	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct)
	(_IO_release_lock): Don't clear _IO_FLAGS2_SCANF_STD.
	* libio/libio.h (_IO_FLAGS2_SCANF_STD): Delete.
---
 libio/libio.h                   |  1 -
 libio/libioP.h                  |  5 ++---
 stdio-common/isoc99_fscanf.c    |  7 +------
 stdio-common/isoc99_scanf.c     | 12 +-----------
 stdio-common/isoc99_sscanf.c    |  3 +--
 stdio-common/isoc99_vfscanf.c   |  9 +--------
 stdio-common/isoc99_vscanf.c    |  9 +--------
 stdio-common/isoc99_vsscanf.c   |  3 +--
 stdio-common/vfscanf-internal.c |  2 --
 wcsmbs/isoc99_fwscanf.c         |  7 +------
 wcsmbs/isoc99_swscanf.c         |  3 +--
 wcsmbs/isoc99_vfwscanf.c        |  9 +--------
 wcsmbs/isoc99_vswscanf.c        |  3 +--
 wcsmbs/isoc99_vwscanf.c         |  9 +--------
 wcsmbs/isoc99_wscanf.c          |  7 +------
 15 files changed, 14 insertions(+), 75 deletions(-)

diff --git a/libio/libio.h b/libio/libio.h
index d4eba2df54..30cb7d784f 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -92,7 +92,6 @@ typedef union
 #define _IO_FLAGS2_NOTCANCEL 2
 #define _IO_FLAGS2_FORTIFY 4
 #define _IO_FLAGS2_USER_WBUF 8
-#define _IO_FLAGS2_SCANF_STD 16
 #define _IO_FLAGS2_NOCLOSE 32
 #define _IO_FLAGS2_CLOEXEC 64
 #define _IO_FLAGS2_NEED_LOCK 128
diff --git a/libio/libioP.h b/libio/libioP.h
index 525dce19ee..9e971cb96b 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -786,7 +786,7 @@ __attribute__ ((__always_inline__))
 _IO_acquire_lock_clear_flags2_fct (FILE **p)
 {
   FILE *fp = *p;
-  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY | _IO_FLAGS2_SCANF_STD);
+  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
   if ((fp->_flags & _IO_USER_LOCK) == 0)
     _IO_funlockfile (fp);
 }
@@ -800,8 +800,7 @@ _IO_acquire_lock_clear_flags2_fct (FILE **p)
     FILE *_IO_acquire_lock_file = (_fp)
 # define _IO_release_lock(_fp)						      \
     if (_IO_acquire_lock_file != NULL)					      \
-      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY		      \
-                                          | _IO_FLAGS2_SCANF_STD);	      \
+      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
   } while (0)
 #endif
 
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 4210d11f2b..d7b5993f3e 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -20,20 +20,15 @@
 #include <stdio.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_fscanf (FILE *stream, const char *format, ...)
 {
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfscanf_internal (stream, format, arg, 0);
+  done = __vfscanf_internal (stream, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stream);
   return done;
 }
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index 64c873eed9..3998322ea1 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -19,26 +19,16 @@
 #include <stdio.h>
 #include <libioP.h>
 
-
 /* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
 __isoc99_scanf (const char *format, ...)
 {
   va_list arg;
   int done;
 
-#ifdef _IO_MTSAFE_IO
-  _IO_acquire_lock_clear_flags2 (stdin);
-#endif
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfscanf_internal (stdin, format, arg, 0);
+  done = __vfscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-#ifdef _IO_MTSAFE_IO
-  _IO_release_lock (stdin);
-#endif
   return done;
 }
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 2c89a03fe9..c9e5103b81 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -26,10 +26,9 @@ __isoc99_sscanf (const char *s, const char *format, ...)
   int done;
   _IO_strfile sf;
   FILE *f = _IO_strfile_read (&sf, s);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __vfscanf_internal (f, format, arg, 0);
+  done = __vfscanf_internal (f, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index c96ca831ae..3c59c60b3e 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -19,16 +19,9 @@
 #include <stdio.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfscanf_internal (stream, format, args, 0);
-  _IO_release_lock (stream);
-  return done;
+  return __vfscanf_internal (stream, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vfscanf)
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 72ae72ddee..fc5d609ae7 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -19,15 +19,8 @@
 #include <stdio.h>
 
 /* Read formatted input from STDIN according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_vscanf (const char *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfscanf_internal (stdin, format, args, 0);
-  _IO_release_lock (stdin);
-  return done;
+  return __vfscanf_internal (stdin, format, args, SCANF_ISOC99_A);
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index 02bc0f50e6..dfc394bb51 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -31,7 +31,6 @@ __isoc99_vsscanf (const char *string, const char *format, va_list args)
 {
   _IO_strfile sf;
   FILE *f = _IO_strfile_read (&sf, string);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  return __vfscanf_internal (f, format, args, 0);
+  return __vfscanf_internal (f, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 13a7a300b7..f0072d8682 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -335,8 +335,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
   /* Temporarily honor the environmental mode bits.  */
   if (__ldbl_is_dbl)
     mode_flags |= SCANF_LDBL_IS_DBL;
-  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
-    mode_flags |= SCANF_ISOC99_A;
 
 #ifdef __va_copy
   __va_copy (arg, argptr);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 00b07dd48e..5829607916 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -21,20 +21,15 @@
 #include <wchar.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfwscanf_internal (stream, format, arg, 0);
+  done = __vfwscanf_internal (stream, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stream);
   return done;
 }
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index 40401d0aa1..f90e56d97f 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -28,10 +28,9 @@ __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
   _IO_strfile sf;
   struct _IO_wide_data wd;
   FILE *f = _IO_strfile_readw (&sf, &wd, s);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __vfwscanf_internal (f, format, arg, 0);
+  done = __vfwscanf_internal (f, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
   return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index f70c6b596d..715d354b5a 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -20,16 +20,9 @@
 #include <wchar.h>
 
 /* Read formatted input from STREAM according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stream);
-  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfwscanf_internal (stream, format, args, 0);
-  _IO_release_lock (stream);
-  return done;
+  return __vfwscanf_internal (stream, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vfwscanf)
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index b91eb651a3..0d8ef7611a 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -33,7 +33,6 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
   _IO_strfile sf;
   struct _IO_wide_data wd;
   FILE *f = _IO_strfile_readw (&sf, &wd, string);
-  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  return __vfwscanf_internal (f, format, args, 0);
+  return __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
 }
 libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index eb22c8acae..3ac3182608 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -20,15 +20,8 @@
 #include <wchar.h>
 
 /* Read formatted input from STDIN according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_vwscanf (const wchar_t *format, va_list args)
 {
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = __vfwscanf_internal (stdin, format, args, 0);
-  _IO_release_lock (stdin);
-  return done;
+  return __vfwscanf_internal (stdin, format, args, SCANF_ISOC99_A);
 }
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index 59f80d78fb..b9418f7912 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -22,20 +22,15 @@
 
 
 /* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
 __isoc99_wscanf (const wchar_t *format, ...)
 {
   va_list arg;
   int done;
 
-  _IO_acquire_lock_clear_flags2 (stdin);
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
   va_start (arg, format);
-  done = __vfwscanf_internal (stdin, format, arg, 0);
+  done = __vfwscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
   va_end (arg);
 
-  _IO_release_lock (stdin);
   return done;
 }
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
  2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-16 18:34   ` Gabriel F. T. Gomes
  2018-11-22 17:35   ` Adhemerval Zanella
  2018-11-15 21:46 ` [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal Gabriel F. T. Gomes
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changed since v2:

  - Expand comments about SCANF_LDBL_IS_DBL and SCANF_ISOC99_A.
  - Remove parameter-less macros LDBL_DISTINCT and USE_ISOC99_A.  Paste
    their code directly where it is used.
  - Use Static_assert rather than `...' in ldbl_compat_symbol.
  - Fix copyright statements.

Changed since v1:

  - Added one line comment to new files.
  - In nldbl-compat.c, added explanation for the need to use
    '#if SHLIB_COMPAT' within 'if LONG_DOUBLE_COMPAT'.  Also moved the
    block further down, for stylistic reasons [1].
  - Added attribute_hidden to the internal (libioP.h) declarations of
    __vfscanf_internal and __vfwscanf_internal [2].
  - Added comment explaining the reason for the use of SHLIB_COMPAT on
    stdio-common/iovfscanf.c and stdio-common/iovfwscanf.c.
  - Converted the definition of ldbl_compat_symbol from an expansion of
    compat_symbol to '...', because ldbl_compat_symbol is also not
    supposed to be used outside of '#if SHLIB_COMPAT' statements.  In my
    opinion, it's better to make this clear in the definition of
    ldbl_compat_symbol itself, rather than having to go to the
    definition of compat_symbol to learn this (if people think that this
    is not the best option, I can revert this change (In that case, the
    definition of ldbl_compat_symbol could be moved outside the '#if
    SHARED' block).  Added a comment with this explanation.
  - Added signed-off-by statements.
  - Replaced 2.28 with 2.29 to adjust for the next release.

Not changed since v1:

  - Florian suggested that the need for ldbl_compat_symbol is
    questionable, because we could define LONG_DOUBLE_COMPAT_VERSION to
    GLIBC_2_0 by default (pretending that the long double transition
    happened for all other platforms), then use it in compat_symbol
    calls, which would create the compat symbols for _IO_vfscanf and
    _IO_vfwscanf with that version.
    That would work, because all the functions that will use
    ldbl_compat_symbol after this patch set were actually introduced
    before GLIBC_2_0.  However, for newer functions, such as swscanf,
    that wouldn't work, if we ever need to do something similar.

Additional note for review:

  - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
    original patch would be vey hard, because git doesn't detect the
    filename change.  To make review a little easier, I did as Zack did
    and manually edited the diff.  I'll reply to this thread and attach
    the original patch if someone wants to apply it.
    (ping me if I forget it)

[1] https://sourceware.org/ml/libc-alpha/2018-03/msg00309.html

[2] As a result, internal calls to __vfscanf_internal, on powerpc, do
    not use the PLT, the following blocks show the difference:

    Without __attribute__ (hidden):
      $ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
      0014ea00 <__nldbl___vfscanf>:
        14ea00:       94 21 ff f0     stwu    r1,-16(r1)
        14ea04:       38 c0 00 01     li      r6,1
        14ea08:       7c 08 02 a6     mflr    r0
        14ea0c:       42 9f 00 05     bcl     20,4*cr7+so,14ea10 <__nldbl___vfscanf+0x10>
        14ea10:       93 c1 00 08     stw     r30,8(r1)
        14ea14:       90 01 00 14     stw     r0,20(r1)
        14ea18:       7f c8 02 a6     mflr    r30
        14ea1c:       3f de 00 05     addis   r30,r30,5
        14ea20:       3b de 15 e4     addi    r30,r30,5604
        14ea24:       4b f0 b8 0d     bl      5a230 <__vfscanf_internal>
        14ea28:       80 01 00 14     lwz     r0,20(r1)
        14ea2c:       83 c1 00 08     lwz     r30,8(r1)
        14ea30:       38 21 00 10     addi    r1,r1,16
        14ea34:       7c 08 03 a6     mtlr    r0
        14ea38:       4e 80 00 20     blr
        14ea3c:       60 00 00 00     nop

    With __attribute__ (hidden):
      $ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
      0014e8b0 <__nldbl___vfscanf>:
        14e8b0:       38 c0 00 01     li      r6,1
        14e8b4:       4b f0 b8 bc     b       5a170 <__vfscanf_internal>
        14e8b8:       60 00 00 00     nop
        14e8bc:       60 00 00 00     nop

-- 8< --
There are two flags currently defined: SCANF_LDBL_IS_DBL is the mode
used by __nldbl_ scanf variants, and SCANF_ISOC99_A is the mode used
by __isoc99_ scanf variants.  In this patch, the new functions honor
these flag bits if they're set, but they still also look at the
corresponding bits of environmental state, and callers all pass zero.

The new functions do *not* have the "errp" argument possessed by
_IO_vfscanf and _IO_vfwscanf.  All internal callers passed NULL for
that argument.  External callers could theoretically exist, so I
preserved wrappers, but they are flagged as compat symbols and they
don't preserve the three-way distinction among types of errors that
was formerly exposed.  These functions probably should have been in
the list of deprecated _IO_ symbols in 2.27 NEWS -- they're not just
aliases for vfscanf and vfwscanf.

(It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
Please check that part of the patch very carefully, I am still not
confident I understand all of the details of ldbl-opt.)

This patch also introduces helper inlines in libio/strfile.h that
encapsulate the process of initializing an _IO_strfile object for
reading.  This allows us to call __vfscanf_internal directly from
sscanf, and __vfwscanf_internal directly from swscanf, without
duplicating the initialization code.  (Previously, they called their
v-counterparts, but that won't work if we want to control *both* C99
mode and ldbl-is-dbl mode using the flags argument to__vfscanf_internal.)
It's still a little awkward, especially for wide strfiles, but it's
much better than what we had.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
	(__vfscanf_internal, __vfwscanf_internal): New function prototypes.
	* libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
	* libio/strfile.h: Add multiple inclusion guard.
	(_IO_strfile_read, _IO_strfile_readw): New inline functions.

	* sysdeps/generic/math_ldbl_opt.h: Include shlib-compat.h, for
	consistency with the other version of this file.
	(ldbl_compat_symbol): New macro.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h (ldbl_compat_symbol):
	New macro.

	* stdio-common/vfscanf-internal.c: Rename from vfscanf.c.
	Define __vfscanf_internal or __vfwscanf_internal, depending on
	COMPILE_WSCANF; don't define any other public symbols.
	Remove errval and code to set errp.
	Temporarily check __ldbl_is_dbl and _IO_FLAGS2_SCANF_STD as well
	as the mode_flags argument.
	(encode_error, conv_error, input_error): Don't set errval.
	* stdio-common/vfwscanf-internal.c: Rename from vfwscanf.c.
	Include vfscanf-internal.c.
	* stdio-common/vfscanf.c: New file defining the public entry
	point vfscanf, which calls __vfscanf_internal.
	* stdio-common/vfwscanf.c: New file defining the public entry
	point vfwscanf, which calls __vfwscanf_internal.

	* stdio-common/iovfscanf.c: New file.
	* stdio-common/iovfwscanf.c: Likewise.

	* stdio-common/Makefile (routines): Add vfscanf-internal,
	vfwscanf-internal, iovfscanf, iovfwscanf.
	* stdio-common/Versions: Mention GLIBC_2.29, so that
	it can be used in SHLIB_COMPAT expressions.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl__IO_vfscanf):
	Wrap definition and compat_symbol line in #if SHLIB_COMPAT.
	Call __vfscanf_internal, instead of _IO_vfscanf.
	(__nldbl___vfscanf): Call __vfscanf_internal, instead of
	_IO_vfscanf.
	(__nldbl_vfwscanf): Call __vfwscanf_internal, instead of
	_IO_vfwscanf.

	* libio/iovsscanf.c: Clean up includes, when possible.  Use
	_IO_strfile_read or _IO_strfile_readw, when needed.  Call
	__vfscanf_internal or __vfwscanf_internal directly.
	* libio/iovswscanf.c: Likewise.
	* libio/swscanf.c: Likewise.
	* libio/vscanf.c: Likewise.
	* libio/vwscanf.c: Likewise.
	* libio/wscanf.c: Likewise.
	* stdio-common/isoc99_fscanf.c: Likewise.
	* stdio-common/isoc99_scanf.c: Likewise.
	* stdio-common/isoc99_sscanf.c: Likewise.
	* stdio-common/isoc99_vfscanf.c: Likewise.
	* stdio-common/isoc99_vscanf.c: Likewise.
	* stdio-common/isoc99_vsscanf.c: Likewise.
	* stdio-common/scanf.c: Likewise.
	* stdio-common/sscanf.c: Likewise.
	* wcsmbs/isoc99_fwscanf.c: Likewise.
	* wcsmbs/isoc99_swscanf.c: Likewise.
	* wcsmbs/isoc99_vfwscanf.c: Likewise.
	* wcsmbs/isoc99_vswscanf.c: Likewise.
	* wcsmbs/isoc99_vwscanf.c: Likewise.
	* wcsmbs/isoc99_wscanf.c: Likewise.
---
 libio/iovsscanf.c                              |   12 +-
 libio/iovswscanf.c                             |   14 +-
 libio/libio.h                                  |    1 -
 libio/libioP.h                                 |   22 +
 libio/strfile.h                                |   33 +-
 libio/swscanf.c                                |   10 +-
 libio/vscanf.c                                 |    2 +-
 libio/vwscanf.c                                |    2 +-
 libio/wscanf.c                                 |    2 +-
 stdio-common/Makefile                          |    3 +-
 stdio-common/Versions                          |    3 +
 stdio-common/{isoc99_scanf.c => iovfscanf.c}   |   36 +-
 stdio-common/{isoc99_scanf.c => iovfwscanf.c}  |   36 +-
 stdio-common/isoc99_fscanf.c                   |    2 +-
 stdio-common/isoc99_scanf.c                    |    2 +-
 stdio-common/isoc99_sscanf.c                   |    9 +-
 stdio-common/isoc99_vfscanf.c                  |    2 +-
 stdio-common/isoc99_vscanf.c                   |    2 +-
 stdio-common/isoc99_vsscanf.c                  |   17 +-
 stdio-common/scanf.c                           |    2 +-
 stdio-common/sscanf.c                          |   12 +-
 stdio-common/{vfscanf.c => vfscanf-internal.c} |   48 +-
 stdio-common/vfscanf.c                         | 3042 +-----------------------
 stdio-common/vfwscanf-internal.c               |    2 +
 stdio-common/vfwscanf.c                        |   28 +-
 sysdeps/generic/math_ldbl_opt.h                |    4 +
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h       |    6 +
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c        |   17 +-
 wcsmbs/isoc99_fwscanf.c                        |    2 +-
 wcsmbs/isoc99_swscanf.c                        |   12 +-
 wcsmbs/isoc99_vfwscanf.c                       |    2 +-
 wcsmbs/isoc99_vswscanf.c                       |   16 +-
 wcsmbs/isoc99_vwscanf.c                        |    2 +-
 wcsmbs/isoc99_wscanf.c                         |    2 +-
 34 files changed, 204 insertions(+), 3203 deletions(-)
 copy stdio-common/{isoc99_scanf.c => iovfscanf.c} (54%)
 copy stdio-common/{isoc99_scanf.c => iovfwscanf.c} (54%)
 copy stdio-common/{vfscanf.c => vfscanf-internal.c} (98%)
 create mode 100644 stdio-common/vfwscanf-internal.c

diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index e56ab8bd7d..ee6a99ec6a 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -24,22 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
 #include "strfile.h"
 
 int
 _IO_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  return __vfscanf_internal (f, format, args, 0);
 }
 ldbl_weak_alias (_IO_vsscanf, __vsscanf)
 ldbl_weak_alias (_IO_vsscanf, vsscanf)
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
index 5bd1c88412..cb9cbe15cc 100644
--- a/libio/iovswscanf.c
+++ b/libio/iovswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
-#include "strfile.h"
 #include <wchar.h>
+#include "strfile.h"
 
 int
 __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__vswscanf)
 ldbl_hidden_def (__vswscanf, vswscanf)
diff --git a/libio/libio.h b/libio/libio.h
index 00f9169613..d4eba2df54 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
 libc_hidden_proto (_IO_putc)
 libc_hidden_proto (_IO_sgetn)
 libc_hidden_proto (_IO_vfprintf)
-libc_hidden_proto (_IO_vfscanf)
 
 #ifdef _IO_MTSAFE_IO
 # undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index df2633d858..525dce19ee 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,28 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 
 #endif /* _G_HAVE_MMAP */
 
+/* Flags for __vfscanf_internal and __vfwscanf_internal.
+
+   SCANF_LDBL_IS_DBL indicates whether long double values are to be
+   handled as having the same format as double, in which case the flag
+   should be set to one, or as another format, otherwise.
+
+   SCANF_ISOC99_A, when set to one, indicates that the ISO C99 or POSIX
+   behavior of the scanf functions is to be used, i.e. automatic
+   allocation for input strings with %as, %aS and %a[, a GNU extension,
+   is disabled. This is the behavior that the __isoc99_scanf family of
+   functions use.  When the flag is set to zero, automatic allocation is
+   enabled.  */
+#define SCANF_LDBL_IS_DBL 0x0001
+#define SCANF_ISOC99_A    0x0002
+
+extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
+			       unsigned int flags)
+  attribute_hidden;
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+				unsigned int flags)
+  attribute_hidden;
+
 extern int _IO_vscanf (const char *, va_list) __THROW;
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 75caac2af5..62900a7128 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -24,7 +24,9 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <stdio.h>
+#ifndef STRFILE_H_
+#define STRFILE_H_
+
 #include "libioP.h"
 
 typedef void *(*_IO_alloc_type) (size_t);
@@ -80,3 +82,32 @@ typedef struct
 } _IO_wstrnfile;
 
 extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
+
+/* Initialize an _IO_strfile SF to read from narrow string STRING, and
+   return the corresponding FILE object.  It is not necessary to fclose
+   the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_read (_IO_strfile *sf, const char *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+  _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
+  _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
+   string STRING, and return the corresponding FILE object.  It is not
+   necessary to fclose the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
+                   const wchar_t *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
+  _IO_fwide (&sf->_sbf._f, 1);
+  _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+#endif /* strfile.h.  */
diff --git a/libio/swscanf.c b/libio/swscanf.c
index c8686bcbaf..90f721cc51 100644
--- a/libio/swscanf.c
+++ b/libio/swscanf.c
@@ -15,20 +15,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <wchar.h>
+#include "strfile.h"
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
 
   va_start (arg, format);
-  done = __vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/vscanf.c b/libio/vscanf.c
index 9c27122c27..a3e2dd43f2 100644
--- a/libio/vscanf.c
+++ b/libio/vscanf.c
@@ -32,6 +32,6 @@
 int
 _IO_vscanf (const char *format, va_list args)
 {
-  return _IO_vfscanf (_IO_stdin, format, args, NULL);
+  return __vfscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_weak_alias (_IO_vscanf, vscanf)
diff --git a/libio/vwscanf.c b/libio/vwscanf.c
index 0d5f558758..7af770c8c3 100644
--- a/libio/vwscanf.c
+++ b/libio/vwscanf.c
@@ -30,6 +30,6 @@
 int
 __vwscanf (const wchar_t *format, va_list args)
 {
-  return _IO_vfwscanf (_IO_stdin, format, args, NULL);
+  return __vfwscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_strong_alias (__vwscanf, vwscanf)
diff --git a/libio/wscanf.c b/libio/wscanf.c
index c8cdad0acd..fe27ff6fa6 100644
--- a/libio/wscanf.c
+++ b/libio/wscanf.c
@@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index a10f12ab3c..f3b3ceddbd 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -39,7 +39,8 @@ routines	:=							      \
 	flockfile ftrylockfile funlockfile				      \
 	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
 	isoc99_vsscanf							      \
-	psiginfo gentempfd
+	psiginfo gentempfd						      \
+	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
 
 aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
 
diff --git a/stdio-common/Versions b/stdio-common/Versions
index b8217578c8..522f302198 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -60,6 +60,9 @@ libc {
   GLIBC_2.28 {
     renameat2;
   }
+  GLIBC_2.29 {
+    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) used in iovfscanf.c etc.
+  }
   GLIBC_PRIVATE {
     # global variables
     _itoa_lower_digits;
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfscanf.c
similarity index 54%
copy from stdio-common/isoc99_scanf.c
copy to stdio-common/iovfscanf.c
index bf7dbe86bb..77e698f665 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/iovfscanf.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Implementation and symbols for _IO_vfscanf.
+   Copyright (C) 2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,30 +16,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
+#include <shlib-compat.h>
 
+/* This function is provided for ports older than GLIBC 2.29 because
+   external callers could theoretically exist.  Newer ports do not need,
+   since it is not part of the API.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
 
-/* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
-__isoc99_scanf (const char *format, ...)
+attribute_compat_text_section
+__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
 {
-  va_list arg;
-  int done;
-
-#ifdef _IO_MTSAFE_IO
-  _IO_acquire_lock_clear_flags2 (stdin);
-#endif
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
-  va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
-  va_end (arg);
+  int rv = __vfscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
 
-#ifdef _IO_MTSAFE_IO
-  _IO_release_lock (stdin);
 #endif
-  return done;
-}
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfwscanf.c
similarity index 54%
copy from stdio-common/isoc99_scanf.c
copy to stdio-common/iovfwscanf.c
index bf7dbe86bb..26a57788cb 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/iovfwscanf.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Implementation and symbols for _IO_vfwscanf.
+   Copyright (C) 1991-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,30 +16,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
+#include <shlib-compat.h>
 
+/* This function is provided for ports older than GLIBC 2.29 because
+   external callers could theoretically exist.  Newer ports do not need,
+   since it is not part of the API.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
 
-/* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
-__isoc99_scanf (const char *format, ...)
+attribute_compat_text_section
+__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
 {
-  va_list arg;
-  int done;
-
-#ifdef _IO_MTSAFE_IO
-  _IO_acquire_lock_clear_flags2 (stdin);
-#endif
-  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
-  va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
-  va_end (arg);
+  int rv = __vfwscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
 
-#ifdef _IO_MTSAFE_IO
-  _IO_release_lock (stdin);
 #endif
-  return done;
-}
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 9cdf85e679..4210d11f2b 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stream, format, arg, NULL);
+  done = __vfscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index bf7dbe86bb..64c873eed9 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
 #ifdef _IO_MTSAFE_IO
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 56a60a2c05..2c89a03fe9 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,19 +16,20 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
 int
 __isoc99_sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stream, format, args, NULL);
+  done = __vfscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 0b747f85ba..72ae72ddee 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stdin, format, args, NULL);
+  done = __vfscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index ac85ef2d0d..02bc0f50e6 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -24,23 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
-#include <stdio.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
index e61b5f1ad3..de38d70353 100644
--- a/stdio-common/scanf.c
+++ b/stdio-common/scanf.c
@@ -30,7 +30,7 @@ __scanf (const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
index 88cd641798..e25e9c27a5 100644
--- a/stdio-common/sscanf.c
+++ b/stdio-common/sscanf.c
@@ -16,26 +16,24 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
 
   va_start (arg, format);
-  done = __vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
 }
 ldbl_hidden_def (__sscanf, sscanf)
 ldbl_strong_alias (__sscanf, sscanf)
-#undef _IO_sscanf
-/* This is for libg++.  */
 ldbl_strong_alias (__sscanf, _IO_sscanf)
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
similarity index 98%
copy from stdio-common/vfscanf.c
copy to stdio-common/vfscanf-internal.c
index 1ce836a324..13a7a300b7 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Internal functions for the *scanf* implementation.
+   Copyright (C) 1991-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -132,16 +133,13 @@
 #include "printf-parse.h" /* Use read_int.  */
 
 #define encode_error() do {						      \
-			  errval = 4;					      \
 			  __set_errno (EILSEQ);				      \
 			  goto errout;					      \
 			} while (0)
 #define conv_error()	do {						      \
-			  errval = 2;					      \
 			  goto errout;					      \
 			} while (0)
 #define input_error()	do {						      \
-			  errval = 1;					      \
 			  if (done == 0) done = EOF;			      \
 			  goto errout;					      \
 			} while (0)
@@ -267,12 +265,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
    Return the number of assignments made, or -1 for an input error.  */
 #ifdef COMPILE_WSCANF
 int
-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
-	      int *errp)
+__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
+                     unsigned int mode_flags)
 #else
 int
-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
-		      int *errp)
+__vfscanf_internal (FILE *s, const char *format, va_list argptr,
+                    unsigned int mode_flags)
 #endif
 {
   va_list arg;
@@ -283,7 +281,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   WINT_T c = 0;	/* Last char read.  */
   int width;		/* Maximum field width.  */
   int flags;		/* Modifiers for current format element.  */
-  int errval = 0;
 #ifndef COMPILE_WSCANF
   locale_t loc = _NL_CURRENT_LOCALE;
   struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
@@ -335,6 +332,12 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   struct char_buffer charbuf;
   scratch_buffer_init (&charbuf.scratch);
 
+  /* Temporarily honor the environmental mode bits.  */
+  if (__ldbl_is_dbl)
+    mode_flags |= SCANF_LDBL_IS_DBL;
+  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+    mode_flags |= SCANF_ISOC99_A;
+
 #ifdef __va_copy
   __va_copy (arg, argptr);
 #else
@@ -566,7 +569,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	    }
 	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
 	     supported at all.  */
-	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+	  if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))
 	    {
 	      --f;
 	      break;
@@ -2423,7 +2426,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      done = EOF;
 	      goto errout;
 	    }
-	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
+	  if ((flags & LONGDBL) \
+	      && __glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
 	    {
 	      long double d = __strtold_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
@@ -3018,8 +3022,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   UNLOCK_STREAM (s);
 
   scratch_buffer_free (&charbuf.scratch);
-  if (errp != NULL)
-    *errp |= errval;
 
   if (__glibc_unlikely (done == EOF))
     {
@@ -3045,23 +3047,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
     }
   return done;
 }
-
-#ifdef COMPILE_WSCANF
-int
-__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
-{
-  return _IO_vfwscanf (s, format, argptr, NULL);
-}
-ldbl_weak_alias (__vfwscanf, vfwscanf)
-#else
-int
-___vfscanf (FILE *s, const char *format, va_list argptr)
-{
-  return _IO_vfscanf_internal (s, format, argptr, NULL);
-}
-ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_strong_alias (___vfscanf, __vfscanf)
-ldbl_hidden_def (___vfscanf, __vfscanf)
-ldbl_weak_alias (___vfscanf, vfscanf)
-#endif
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 1ce836a324..5eedca8340 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -15,3053 +15,13 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-#include <libc-diag.h>
-#include <libc-lock.h>
-#include <locale/localeinfo.h>
-#include <scratch_buffer.h>
-
-#ifdef	__GNUC__
-# define HAVE_LONGLONG
-# define LONGLONG	long long
-#else
-# define LONGLONG	long
-#endif
-
-/* Determine whether we have to handle `long long' at all.  */
-#if LONG_MAX == LONG_LONG_MAX
-# define need_longlong	0
-#else
-# define need_longlong	1
-#endif
-
-/* Determine whether we have to handle `long'.  */
-#if INT_MAX == LONG_MAX
-# define need_long	0
-#else
-# define need_long	1
-#endif
-
-/* Those are flags in the conversion format. */
-#define LONG		0x0001	/* l: long or double */
-#define LONGDBL		0x0002	/* L: long long or long double */
-#define SHORT		0x0004	/* h: short */
-#define SUPPRESS	0x0008	/* *: suppress assignment */
-#define POINTER		0x0010	/* weird %p pointer (`fake hex') */
-#define NOSKIP		0x0020	/* do not skip blanks */
-#define NUMBER_SIGNED	0x0040	/* signed integer */
-#define GROUP		0x0080	/* ': group numbers */
-#define GNU_MALLOC	0x0100	/* a: malloc strings */
-#define CHAR		0x0200	/* hh: char */
-#define I18N		0x0400	/* I: use locale's digits */
-#define HEXA_FLOAT	0x0800	/* hexadecimal float */
-#define READ_POINTER	0x1000	/* this is a pointer value */
-#define POSIX_MALLOC	0x2000	/* m: malloc strings */
-#define MALLOC		(GNU_MALLOC | POSIX_MALLOC)
-
-#include <locale/localeinfo.h>
 #include <libioP.h>
 
-#ifdef COMPILE_WSCANF
-# define ungetc(c, s)	((void) (c == WEOF				      \
-				 || (--read_in,				      \
-				     _IO_sputbackwc (s, c))))
-# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
-					 _IO_sputbackwc (s, c)))
-# define inchar()	(c == WEOF ? ((errno = inchar_errno), WEOF)	      \
-			 : ((c = _IO_getwc_unlocked (s)),		      \
-			    (void) (c != WEOF				      \
-				    ? ++read_in				      \
-				    : (size_t) (inchar_errno = errno)), c))
-
-# define ISSPACE(Ch)	  iswspace (Ch)
-# define ISDIGIT(Ch)	  iswdigit (Ch)
-# define ISXDIGIT(Ch)	  iswxdigit (Ch)
-# define TOLOWER(Ch)	  towlower (Ch)
-# define ORIENT	  if (_IO_fwide (s, 1) != 1) return WEOF
-# define __strtoll_internal	__wcstoll_internal
-# define __strtoull_internal	__wcstoull_internal
-# define __strtol_internal	__wcstol_internal
-# define __strtoul_internal	__wcstoul_internal
-# define __strtold_internal	__wcstold_internal
-# define __strtod_internal	__wcstod_internal
-# define __strtof_internal	__wcstof_internal
-
-# define L_(Str)	L##Str
-# define CHAR_T		wchar_t
-# define UCHAR_T	unsigned int
-# define WINT_T		wint_t
-# undef EOF
-# define EOF		WEOF
-#else
-# define ungetc(c, s)	((void) ((int) c == EOF				      \
-				 || (--read_in,				      \
-				     _IO_sputbackc (s, (unsigned char) c))))
-# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
-					 _IO_sputbackc (s, (unsigned char) c)))
-# define inchar()	(c == EOF ? ((errno = inchar_errno), EOF)	      \
-			 : ((c = _IO_getc_unlocked (s)),		      \
-			    (void) (c != EOF				      \
-				    ? ++read_in				      \
-				    : (size_t) (inchar_errno = errno)), c))
-# define ISSPACE(Ch)	  __isspace_l (Ch, loc)
-# define ISDIGIT(Ch)	  __isdigit_l (Ch, loc)
-# define ISXDIGIT(Ch)	  __isxdigit_l (Ch, loc)
-# define TOLOWER(Ch)	  __tolower_l ((unsigned char) (Ch), loc)
-# define ORIENT	  if (_IO_vtable_offset (s) == 0			      \
-			      && _IO_fwide (s, -1) != -1)		      \
-			    return EOF
-
-# define L_(Str)	Str
-# define CHAR_T		char
-# define UCHAR_T	unsigned char
-# define WINT_T		int
-#endif
-
-#include "printf-parse.h" /* Use read_int.  */
-
-#define encode_error() do {						      \
-			  errval = 4;					      \
-			  __set_errno (EILSEQ);				      \
-			  goto errout;					      \
-			} while (0)
-#define conv_error()	do {						      \
-			  errval = 2;					      \
-			  goto errout;					      \
-			} while (0)
-#define input_error()	do {						      \
-			  errval = 1;					      \
-			  if (done == 0) done = EOF;			      \
-			  goto errout;					      \
-			} while (0)
-#define add_ptr_to_free(ptr)						      \
-  do									      \
-    {									      \
-      if (ptrs_to_free == NULL						      \
-	  || ptrs_to_free->count == (sizeof (ptrs_to_free->ptrs)	      \
-				     / sizeof (ptrs_to_free->ptrs[0])))	      \
-	{								      \
-	  struct ptrs_to_free *new_ptrs = alloca (sizeof (*ptrs_to_free));    \
-	  new_ptrs->count = 0;						      \
-	  new_ptrs->next = ptrs_to_free;				      \
-	  ptrs_to_free = new_ptrs;					      \
-	}								      \
-      ptrs_to_free->ptrs[ptrs_to_free->count++] = (ptr);		      \
-    }									      \
-  while (0)
-#define ARGCHECK(s, format)						      \
-  do									      \
-    {									      \
-      /* Check file argument for consistence.  */			      \
-      CHECK_FILE (s, EOF);						      \
-      if (s->_flags & _IO_NO_READS)					      \
-	{								      \
-	  __set_errno (EBADF);						      \
-	  return EOF;							      \
-	}								      \
-      else if (format == NULL)						      \
-	{								      \
-	  __set_errno (EINVAL);						      \
-	  return EOF;							      \
-	}								      \
-    } while (0)
-#define LOCK_STREAM(S)							      \
-  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, (S)); \
-  _IO_flockfile (S)
-#define UNLOCK_STREAM(S)						      \
-  _IO_funlockfile (S);							      \
-  __libc_cleanup_region_end (0)
-
-struct ptrs_to_free
-{
-  size_t count;
-  struct ptrs_to_free *next;
-  char **ptrs[32];
-};
-
-struct char_buffer {
-  CHAR_T *current;
-  CHAR_T *end;
-  struct scratch_buffer scratch;
-};
-
-/* Returns a pointer to the first CHAR_T object in the buffer.  Only
-   valid if char_buffer_add (BUFFER, CH) has been called and
-   char_buffer_error (BUFFER) is false.  */
-static inline CHAR_T *
-char_buffer_start (const struct char_buffer *buffer)
-{
-  return (CHAR_T *) buffer->scratch.data;
-}
-
-/* Returns the number of CHAR_T objects in the buffer.  Only valid if
-   char_buffer_error (BUFFER) is false.  */
-static inline size_t
-char_buffer_size (const struct char_buffer *buffer)
-{
-  return buffer->current - char_buffer_start (buffer);
-}
-
-/* Reinitializes BUFFER->current and BUFFER->end to cover the entire
-   scratch buffer.  */
-static inline void
-char_buffer_rewind (struct char_buffer *buffer)
-{
-  buffer->current = char_buffer_start (buffer);
-  buffer->end = buffer->current + buffer->scratch.length / sizeof (CHAR_T);
-}
-
-/* Returns true if a previous call to char_buffer_add (BUFFER, CH)
-   failed.  */
-static inline bool
-char_buffer_error (const struct char_buffer *buffer)
-{
-  return __glibc_unlikely (buffer->current == NULL);
-}
-
-/* Slow path for char_buffer_add.  */
-static void
-char_buffer_add_slow (struct char_buffer *buffer, CHAR_T ch)
-{
-  if (char_buffer_error (buffer))
-    return;
-  size_t offset = buffer->end - (CHAR_T *) buffer->scratch.data;
-  if (!scratch_buffer_grow_preserve (&buffer->scratch))
-    {
-      buffer->current = NULL;
-      buffer->end = NULL;
-      return;
-    }
-  char_buffer_rewind (buffer);
-  buffer->current += offset;
-  *buffer->current++ = ch;
-}
-
-/* Adds CH to BUFFER.  This function does not report any errors, check
-   for them with char_buffer_error.  */
-static inline void
-char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
-  __attribute__ ((always_inline));
-static inline void
-char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
-{
-  if (__glibc_unlikely (buffer->current == buffer->end))
-    char_buffer_add_slow (buffer, ch);
-  else
-    *buffer->current++ = ch;
-}
-
-/* Read formatted input from S according to the format string
-   FORMAT, using the argument list in ARG.
-   Return the number of assignments made, or -1 for an input error.  */
-#ifdef COMPILE_WSCANF
-int
-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
-	      int *errp)
-#else
-int
-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
-		      int *errp)
-#endif
-{
-  va_list arg;
-  const CHAR_T *f = format;
-  UCHAR_T fc;	/* Current character of the format.  */
-  WINT_T done = 0;	/* Assignments done.  */
-  size_t read_in = 0;	/* Chars read in.  */
-  WINT_T c = 0;	/* Last char read.  */
-  int width;		/* Maximum field width.  */
-  int flags;		/* Modifiers for current format element.  */
-  int errval = 0;
-#ifndef COMPILE_WSCANF
-  locale_t loc = _NL_CURRENT_LOCALE;
-  struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
-#endif
-
-  /* Errno of last failed inchar call.  */
-  int inchar_errno = 0;
-  /* Status for reading F-P nums.  */
-  char got_digit, got_dot, got_e, got_sign;
-  /* If a [...] is a [^...].  */
-  CHAR_T not_in;
-#define exp_char not_in
-  /* Base for integral numbers.  */
-  int base;
-  /* Decimal point character.  */
-#ifdef COMPILE_WSCANF
-  wint_t decimal;
-#else
-  const char *decimal;
-#endif
-  /* The thousands character of the current locale.  */
-#ifdef COMPILE_WSCANF
-  wint_t thousands;
-#else
-  const char *thousands;
-#endif
-  struct ptrs_to_free *ptrs_to_free = NULL;
-  /* State for the conversions.  */
-  mbstate_t state;
-  /* Integral holding variables.  */
-  union
-    {
-      long long int q;
-      unsigned long long int uq;
-      long int l;
-      unsigned long int ul;
-    } num;
-  /* Character-buffer pointer.  */
-  char *str = NULL;
-  wchar_t *wstr = NULL;
-  char **strptr = NULL;
-  ssize_t strsize = 0;
-  /* We must not react on white spaces immediately because they can
-     possibly be matched even if in the input stream no character is
-     available anymore.  */
-  int skip_space = 0;
-  /* Workspace.  */
-  CHAR_T *tw;			/* Temporary pointer.  */
-  struct char_buffer charbuf;
-  scratch_buffer_init (&charbuf.scratch);
-
-#ifdef __va_copy
-  __va_copy (arg, argptr);
-#else
-  arg = (va_list) argptr;
-#endif
-
-#ifdef ORIENT
-  ORIENT;
-#endif
-
-  ARGCHECK (s, format);
-
- {
-#ifndef COMPILE_WSCANF
-   struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
-#endif
-
-   /* Figure out the decimal point character.  */
-#ifdef COMPILE_WSCANF
-   decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
-#else
-   decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
-#endif
-   /* Figure out the thousands separator character.  */
-#ifdef COMPILE_WSCANF
-   thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
-#else
-   thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
-   if (*thousands == '\0')
-     thousands = NULL;
-#endif
- }
-
-  /* Lock the stream.  */
-  LOCK_STREAM (s);
-
-
-#ifndef COMPILE_WSCANF
-  /* From now on we use `state' to convert the format string.  */
-  memset (&state, '\0', sizeof (state));
-#endif
-
-  /* Run through the format string.  */
-  while (*f != '\0')
-    {
-      unsigned int argpos;
-      /* Extract the next argument, which is of type TYPE.
-	 For a %N$... spec, this is the Nth argument from the beginning;
-	 otherwise it is the next argument after the state now in ARG.  */
-#ifdef __va_copy
-# define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
-			 ({ unsigned int pos = argpos;			      \
-			    va_list arg;				      \
-			    __va_copy (arg, argptr);			      \
-			    while (--pos > 0)				      \
-			      (void) va_arg (arg, void *);		      \
-			    va_arg (arg, type);				      \
-			  }))
-#else
-# if 0
-      /* XXX Possible optimization.  */
-#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
-			 ({ va_list arg = (va_list) argptr;		      \
-			    arg = (va_list) ((char *) arg		      \
-					     + (argpos - 1)		      \
-					     * __va_rounded_size (void *));   \
-			    va_arg (arg, type);				      \
-			 }))
-# else
-#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
-			 ({ unsigned int pos = argpos;			      \
-			    va_list arg = (va_list) argptr;		      \
-			    while (--pos > 0)				      \
-			      (void) va_arg (arg, void *);		      \
-			    va_arg (arg, type);				      \
-			  }))
-# endif
-#endif
-
-#ifndef COMPILE_WSCANF
-      if (!isascii ((unsigned char) *f))
-	{
-	  /* Non-ASCII, may be a multibyte.  */
-	  int len = __mbrlen (f, strlen (f), &state);
-	  if (len > 0)
-	    {
-	      do
-		{
-		  c = inchar ();
-		  if (__glibc_unlikely (c == EOF))
-		    input_error ();
-		  else if (c != (unsigned char) *f++)
-		    {
-		      ungetc_not_eof (c, s);
-		      conv_error ();
-		    }
-		}
-	      while (--len > 0);
-	      continue;
-	    }
-	}
-#endif
-
-      fc = *f++;
-      if (fc != '%')
-	{
-	  /* Remember to skip spaces.  */
-	  if (ISSPACE (fc))
-	    {
-	      skip_space = 1;
-	      continue;
-	    }
-
-	  /* Read a character.  */
-	  c = inchar ();
-
-	  /* Characters other than format specs must just match.  */
-	  if (__glibc_unlikely (c == EOF))
-	    input_error ();
-
-	  /* We saw white space char as the last character in the format
-	     string.  Now it's time to skip all leading white space.  */
-	  if (skip_space)
-	    {
-	      while (ISSPACE (c))
-		if (__glibc_unlikely (inchar () == EOF))
-		  input_error ();
-	      skip_space = 0;
-	    }
-
-	  if (__glibc_unlikely (c != fc))
-	    {
-	      ungetc (c, s);
-	      conv_error ();
-	    }
-
-	  continue;
-	}
-
-      /* This is the start of the conversion string. */
-      flags = 0;
-
-      /* Initialize state of modifiers.  */
-      argpos = 0;
-
-      /* Prepare temporary buffer.  */
-      char_buffer_rewind (&charbuf);
-
-      /* Check for a positional parameter specification.  */
-      if (ISDIGIT ((UCHAR_T) *f))
-	{
-	  argpos = read_int ((const UCHAR_T **) &f);
-	  if (*f == L_('$'))
-	    ++f;
-	  else
-	    {
-	      /* Oops; that was actually the field width.  */
-	      width = argpos;
-	      argpos = 0;
-	      goto got_width;
-	    }
-	}
-
-      /* Check for the assignment-suppressing, the number grouping flag,
-	 and the signal to use the locale's digit representation.  */
-      while (*f == L_('*') || *f == L_('\'') || *f == L_('I'))
-	switch (*f++)
-	  {
-	  case L_('*'):
-	    flags |= SUPPRESS;
-	    break;
-	  case L_('\''):
-#ifdef COMPILE_WSCANF
-	    if (thousands != L'\0')
-#else
-	    if (thousands != NULL)
-#endif
-	      flags |= GROUP;
-	    break;
-	  case L_('I'):
-	    flags |= I18N;
-	    break;
-	  }
-
-      /* Find the maximum field width.  */
-      width = 0;
-      if (ISDIGIT ((UCHAR_T) *f))
-	width = read_int ((const UCHAR_T **) &f);
-    got_width:
-      if (width == 0)
-	width = -1;
-
-      /* Check for type modifiers.  */
-      switch (*f++)
-	{
-	case L_('h'):
-	  /* ints are short ints or chars.  */
-	  if (*f == L_('h'))
-	    {
-	      ++f;
-	      flags |= CHAR;
-	    }
-	  else
-	    flags |= SHORT;
-	  break;
-	case L_('l'):
-	  if (*f == L_('l'))
-	    {
-	      /* A double `l' is equivalent to an `L'.  */
-	      ++f;
-	      flags |= LONGDBL | LONG;
-	    }
-	  else
-	    /* ints are long ints.  */
-	    flags |= LONG;
-	  break;
-	case L_('q'):
-	case L_('L'):
-	  /* doubles are long doubles, and ints are long long ints.  */
-	  flags |= LONGDBL | LONG;
-	  break;
-	case L_('a'):
-	  /* The `a' is used as a flag only if followed by `s', `S' or
-	     `['.  */
-	  if (*f != L_('s') && *f != L_('S') && *f != L_('['))
-	    {
-	      --f;
-	      break;
-	    }
-	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
-	     supported at all.  */
-	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
-	    {
-	      --f;
-	      break;
-	    }
-	  /* String conversions (%s, %[) take a `char **'
-	     arg and fill it in with a malloc'd pointer.  */
-	  flags |= GNU_MALLOC;
-	  break;
-	case L_('m'):
-	  flags |= POSIX_MALLOC;
-	  if (*f == L_('l'))
-	    {
-	      ++f;
-	      flags |= LONG;
-	    }
-	  break;
-	case L_('z'):
-	  if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
-	    flags |= LONGDBL;
-	  else if (sizeof (size_t) > sizeof (unsigned int))
-	    flags |= LONG;
-	  break;
-	case L_('j'):
-	  if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))
-	    flags |= LONGDBL;
-	  else if (sizeof (uintmax_t) > sizeof (unsigned int))
-	    flags |= LONG;
-	  break;
-	case L_('t'):
-	  if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))
-	    flags |= LONGDBL;
-	  else if (sizeof (ptrdiff_t) > sizeof (int))
-	    flags |= LONG;
-	  break;
-	default:
-	  /* Not a recognized modifier.  Backup.  */
-	  --f;
-	  break;
-	}
-
-      /* End of the format string?  */
-      if (__glibc_unlikely (*f == L_('\0')))
-	conv_error ();
-
-      /* Find the conversion specifier.  */
-      fc = *f++;
-      if (skip_space || (fc != L_('[') && fc != L_('c')
-			 && fc != L_('C') && fc != L_('n')))
-	{
-	  /* Eat whitespace.  */
-	  int save_errno = errno;
-	  __set_errno (0);
-	  do
-	    /* We add the additional test for EOF here since otherwise
-	       inchar will restore the old errno value which might be
-	       EINTR but does not indicate an interrupt since nothing
-	       was read at this time.  */
-	    if (__builtin_expect ((c == EOF || inchar () == EOF)
-				  && errno == EINTR, 0))
-	      input_error ();
-	  while (ISSPACE (c));
-	  __set_errno (save_errno);
-	  ungetc (c, s);
-	  skip_space = 0;
-	}
-
-      switch (fc)
-	{
-	case L_('%'):	/* Must match a literal '%'.  */
-	  c = inchar ();
-	  if (__glibc_unlikely (c == EOF))
-	    input_error ();
-	  if (__glibc_unlikely (c != fc))
-	    {
-	      ungetc_not_eof (c, s);
-	      conv_error ();
-	    }
-	  break;
-
-	case L_('n'):	/* Answer number of assignments done.  */
-	  /* Corrigendum 1 to ISO C 1990 describes the allowed flags
-	     with the 'n' conversion specifier.  */
-	  if (!(flags & SUPPRESS))
-	    {
-	      /* Don't count the read-ahead.  */
-	      if (need_longlong && (flags & LONGDBL))
-		*ARG (long long int *) = read_in;
-	      else if (need_long && (flags & LONG))
-		*ARG (long int *) = read_in;
-	      else if (flags & SHORT)
-		*ARG (short int *) = read_in;
-	      else if (!(flags & CHAR))
-		*ARG (int *) = read_in;
-	      else
-		*ARG (char *) = read_in;
-
-#ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1
-	      /* We have a severe problem here.  The ISO C standard
-		 contradicts itself in explaining the effect of the %n
-		 format in `scanf'.  While in ISO C:1990 and the ISO C
-		 Amendement 1:1995 the result is described as
-
-		   Execution of a %n directive does not effect the
-		   assignment count returned at the completion of
-		   execution of the f(w)scanf function.
-
-		 in ISO C Corrigendum 1:1994 the following was added:
-
-		   Subclause 7.9.6.2
-		   Add the following fourth example:
-		     In:
-		       #include <stdio.h>
-		       int d1, d2, n1, n2, i;
-		       i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
-		     the value 123 is assigned to d1 and the value3 to n1.
-		     Because %n can never get an input failure the value
-		     of 3 is also assigned to n2.  The value of d2 is not
-		     affected.  The value 3 is assigned to i.
-
-		 We go for now with the historically correct code from ISO C,
-		 i.e., we don't count the %n assignments.  When it ever
-		 should proof to be wrong just remove the #ifdef above.  */
-	      ++done;
-#endif
-	    }
-	  break;
-
-	case L_('c'):	/* Match characters.  */
-	  if ((flags & LONG) == 0)
-	    {
-	      if (width == -1)
-		width = 1;
-
-#define STRING_ARG(Str, Type, Width)					      \
-	      do if (!(flags & SUPPRESS))				      \
-		{							      \
-		  if (flags & MALLOC)					      \
-		    {							      \
-		      /* The string is to be stored in a malloc'd buffer.  */ \
-		      /* For %mS using char ** is actually wrong, but	      \
-			 shouldn't make a difference on any arch glibc	      \
-			 supports and would unnecessarily complicate	      \
-			 things. */					      \
-		      strptr = ARG (char **);				      \
-		      if (strptr == NULL)				      \
-			conv_error ();					      \
-		      /* Allocate an initial buffer.  */		      \
-		      strsize = Width;					      \
-		      *strptr = (char *) malloc (strsize * sizeof (Type));    \
-		      Str = (Type *) *strptr;				      \
-		      if (Str != NULL)					      \
-			add_ptr_to_free (strptr);			      \
-		      else if (flags & POSIX_MALLOC)			      \
-			{						      \
-			  done = EOF;					      \
-			  goto errout;					      \
-			}						      \
-		    }							      \
-		  else							      \
-		    Str = ARG (Type *);					      \
-		  if (Str == NULL)					      \
-		    conv_error ();					      \
-		} while (0)
-#ifdef COMPILE_WSCANF
-	      STRING_ARG (str, char, 100);
-#else
-	      STRING_ARG (str, char, (width > 1024 ? 1024 : width));
-#endif
-
-	      c = inchar ();
-	      if (__glibc_unlikely (c == EOF))
-		input_error ();
-
-#ifdef COMPILE_WSCANF
-	      /* We have to convert the wide character(s) into multibyte
-		 characters and store the result.  */
-	      memset (&state, '\0', sizeof (state));
-
-	      do
-		{
-		  size_t n;
-
-		  if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
-		      && *strptr + strsize - str <= MB_LEN_MAX)
-		    {
-		      /* We have to enlarge the buffer if the `m' flag
-			 was given.  */
-		      size_t strleng = str - *strptr;
-		      char *newstr;
-
-		      newstr = (char *) realloc (*strptr, strsize * 2);
-		      if (newstr == NULL)
-			{
-			  /* Can't allocate that much.  Last-ditch effort.  */
-			  newstr = (char *) realloc (*strptr,
-						     strleng + MB_LEN_MAX);
-			  if (newstr == NULL)
-			    {
-			      /* c can't have `a' flag, only `m'.  */
-			      done = EOF;
-			      goto errout;
-			    }
-			  else
-			    {
-			      *strptr = newstr;
-			      str = newstr + strleng;
-			      strsize = strleng + MB_LEN_MAX;
-			    }
-			}
-		      else
-			{
-			  *strptr = newstr;
-			  str = newstr + strleng;
-			  strsize *= 2;
-			}
-		    }
-
-		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
-		  if (__glibc_unlikely (n == (size_t) -1))
-		    /* No valid wide character.  */
-		    input_error ();
-
-		  /* Increment the output pointer.  Even if we don't
-		     write anything.  */
-		  str += n;
-		}
-	      while (--width > 0 && inchar () != EOF);
-#else
-	      if (!(flags & SUPPRESS))
-		{
-		  do
-		    {
-		      if ((flags & MALLOC)
-			  && (char *) str == *strptr + strsize)
-			{
-			  /* Enlarge the buffer.  */
-			  size_t newsize
-			    = strsize
-			      + (strsize >= width ? width - 1 : strsize);
-
-			  str = (char *) realloc (*strptr, newsize);
-			  if (str == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      str = (char *) realloc (*strptr, strsize + 1);
-			      if (str == NULL)
-				{
-				  /* c can't have `a' flag, only `m'.  */
-				  done = EOF;
-				  goto errout;
-				}
-			      else
-				{
-				  *strptr = (char *) str;
-				  str += strsize;
-				  ++strsize;
-				}
-			    }
-			  else
-			    {
-			      *strptr = (char *) str;
-			      str += strsize;
-			      strsize = newsize;
-			    }
-			}
-		      *str++ = c;
-		    }
-		  while (--width > 0 && inchar () != EOF);
-		}
-	      else
-		while (--width > 0 && inchar () != EOF);
-#endif
-
-	      if (!(flags & SUPPRESS))
-		{
-		  if ((flags & MALLOC) && str - *strptr != strsize)
-		    {
-		      char *cp = (char *) realloc (*strptr, str - *strptr);
-		      if (cp != NULL)
-			*strptr = cp;
-		    }
-		  strptr = NULL;
-		  ++done;
-		}
-
-	      break;
-	    }
-	  /* FALLTHROUGH */
-	case L_('C'):
-	  if (width == -1)
-	    width = 1;
-
-	  STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
-
-	  c = inchar ();
-	  if (__glibc_unlikely (c == EOF))
-	    input_error ();
-
-#ifdef COMPILE_WSCANF
-	  /* Just store the incoming wide characters.  */
-	  if (!(flags & SUPPRESS))
-	    {
-	      do
-		{
-		  if ((flags & MALLOC)
-		      && wstr == (wchar_t *) *strptr + strsize)
-		    {
-		      size_t newsize
-			= strsize + (strsize > width ? width - 1 : strsize);
-		      /* Enlarge the buffer.  */
-		      wstr = (wchar_t *) realloc (*strptr,
-						  newsize * sizeof (wchar_t));
-		      if (wstr == NULL)
-			{
-			  /* Can't allocate that much.  Last-ditch effort.  */
-			  wstr = (wchar_t *) realloc (*strptr,
-						      (strsize + 1)
-						      * sizeof (wchar_t));
-			  if (wstr == NULL)
-			    {
-			      /* C or lc can't have `a' flag, only `m'
-				 flag.  */
-			      done = EOF;
-			      goto errout;
-			    }
-			  else
-			    {
-			      *strptr = (char *) wstr;
-			      wstr += strsize;
-			      ++strsize;
-			    }
-			}
-		      else
-			{
-			  *strptr = (char *) wstr;
-			  wstr += strsize;
-			  strsize = newsize;
-			}
-		    }
-		  *wstr++ = c;
-		}
-	      while (--width > 0 && inchar () != EOF);
-	    }
-	  else
-	    while (--width > 0 && inchar () != EOF);
-#else
-	  {
-	    /* We have to convert the multibyte input sequence to wide
-	       characters.  */
-	    char buf[1];
-	    mbstate_t cstate;
-
-	    memset (&cstate, '\0', sizeof (cstate));
-
-	    do
-	      {
-		/* This is what we present the mbrtowc function first.  */
-		buf[0] = c;
-
-		if (!(flags & SUPPRESS) && (flags & MALLOC)
-		    && wstr == (wchar_t *) *strptr + strsize)
-		  {
-		    size_t newsize
-		      = strsize + (strsize > width ? width - 1 : strsize);
-		    /* Enlarge the buffer.  */
-		    wstr = (wchar_t *) realloc (*strptr,
-						newsize * sizeof (wchar_t));
-		    if (wstr == NULL)
-		      {
-			/* Can't allocate that much.  Last-ditch effort.  */
-			wstr = (wchar_t *) realloc (*strptr,
-						    ((strsize + 1)
-						     * sizeof (wchar_t)));
-			if (wstr == NULL)
-			  {
-			    /* C or lc can't have `a' flag, only `m' flag.  */
-			    done = EOF;
-			    goto errout;
-			  }
-			else
-			  {
-			    *strptr = (char *) wstr;
-			    wstr += strsize;
-			    ++strsize;
-			  }
-		      }
-		    else
-		      {
-			*strptr = (char *) wstr;
-			wstr += strsize;
-			strsize = newsize;
-		      }
-		  }
-
-		while (1)
-		  {
-		    size_t n;
-
-		    n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
-				   buf, 1, &cstate);
-
-		    if (n == (size_t) -2)
-		      {
-			/* Possibly correct character, just not enough
-			   input.  */
-			if (__glibc_unlikely (inchar () == EOF))
-			  encode_error ();
-
-			buf[0] = c;
-			continue;
-		      }
-
-		    if (__glibc_unlikely (n != 1))
-		      encode_error ();
-
-		    /* We have a match.  */
-		    break;
-		  }
-
-		/* Advance the result pointer.  */
-		++wstr;
-	      }
-	    while (--width > 0 && inchar () != EOF);
-	  }
-#endif
-
-	  if (!(flags & SUPPRESS))
-	    {
-	      if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
-		{
-		  wchar_t *cp = (wchar_t *) realloc (*strptr,
-						     ((wstr
-						       - (wchar_t *) *strptr)
-						      * sizeof (wchar_t)));
-		  if (cp != NULL)
-		    *strptr = (char *) cp;
-		}
-	      strptr = NULL;
-
-	      ++done;
-	    }
-
-	  break;
-
-	case L_('s'):		/* Read a string.  */
-	  if (!(flags & LONG))
-	    {
-	      STRING_ARG (str, char, 100);
-
-	      c = inchar ();
-	      if (__glibc_unlikely (c == EOF))
-		input_error ();
-
-#ifdef COMPILE_WSCANF
-	      memset (&state, '\0', sizeof (state));
-#endif
-
-	      do
-		{
-		  if (ISSPACE (c))
-		    {
-		      ungetc_not_eof (c, s);
-		      break;
-		    }
-
-#ifdef COMPILE_WSCANF
-		  /* This is quite complicated.  We have to convert the
-		     wide characters into multibyte characters and then
-		     store them.  */
-		  {
-		    size_t n;
-
-		    if (!(flags & SUPPRESS) && (flags & MALLOC)
-			&& *strptr + strsize - str <= MB_LEN_MAX)
-		      {
-			/* We have to enlarge the buffer if the `a' or `m'
-			   flag was given.  */
-			size_t strleng = str - *strptr;
-			char *newstr;
-
-			newstr = (char *) realloc (*strptr, strsize * 2);
-			if (newstr == NULL)
-			  {
-			    /* Can't allocate that much.  Last-ditch
-			       effort.  */
-			    newstr = (char *) realloc (*strptr,
-						       strleng + MB_LEN_MAX);
-			    if (newstr == NULL)
-			      {
-				if (flags & POSIX_MALLOC)
-				  {
-				    done = EOF;
-				    goto errout;
-				  }
-				/* We lose.  Oh well.  Terminate the
-				   string and stop converting,
-				   so at least we don't skip any input.  */
-				((char *) (*strptr))[strleng] = '\0';
-				strptr = NULL;
-				++done;
-				conv_error ();
-			      }
-			    else
-			      {
-				*strptr = newstr;
-				str = newstr + strleng;
-				strsize = strleng + MB_LEN_MAX;
-			      }
-			  }
-			else
-			  {
-			    *strptr = newstr;
-			    str = newstr + strleng;
-			    strsize *= 2;
-			  }
-		      }
-
-		    n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c,
-				   &state);
-		    if (__glibc_unlikely (n == (size_t) -1))
-		      encode_error ();
-
-		    assert (n <= MB_LEN_MAX);
-		    str += n;
-		  }
-#else
-		  /* This is easy.  */
-		  if (!(flags & SUPPRESS))
-		    {
-		      *str++ = c;
-		      if ((flags & MALLOC)
-			  && (char *) str == *strptr + strsize)
-			{
-			  /* Enlarge the buffer.  */
-			  str = (char *) realloc (*strptr, 2 * strsize);
-			  if (str == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      str = (char *) realloc (*strptr, strsize + 1);
-			      if (str == NULL)
-				{
-				  if (flags & POSIX_MALLOC)
-				    {
-				      done = EOF;
-				      goto errout;
-				    }
-				  /* We lose.  Oh well.  Terminate the
-				     string and stop converting,
-				     so at least we don't skip any input.  */
-				  ((char *) (*strptr))[strsize - 1] = '\0';
-				  strptr = NULL;
-				  ++done;
-				  conv_error ();
-				}
-			      else
-				{
-				  *strptr = (char *) str;
-				  str += strsize;
-				  ++strsize;
-				}
-			    }
-			  else
-			    {
-			      *strptr = (char *) str;
-			      str += strsize;
-			      strsize *= 2;
-			    }
-			}
-		    }
-#endif
-		}
-	      while ((width <= 0 || --width > 0) && inchar () != EOF);
-
-	      if (!(flags & SUPPRESS))
-		{
-#ifdef COMPILE_WSCANF
-		  /* We have to emit the code to get into the initial
-		     state.  */
-		  char buf[MB_LEN_MAX];
-		  size_t n = __wcrtomb (buf, L'\0', &state);
-		  if (n > 0 && (flags & MALLOC)
-		      && str + n >= *strptr + strsize)
-		    {
-		      /* Enlarge the buffer.  */
-		      size_t strleng = str - *strptr;
-		      char *newstr;
-
-		      newstr = (char *) realloc (*strptr, strleng + n + 1);
-		      if (newstr == NULL)
-			{
-			  if (flags & POSIX_MALLOC)
-			    {
-			      done = EOF;
-			      goto errout;
-			    }
-			  /* We lose.  Oh well.  Terminate the string
-			     and stop converting, so at least we don't
-			     skip any input.  */
-			  ((char *) (*strptr))[strleng] = '\0';
-			  strptr = NULL;
-			  ++done;
-			  conv_error ();
-			}
-		      else
-			{
-			  *strptr = newstr;
-			  str = newstr + strleng;
-			  strsize = strleng + n + 1;
-			}
-		    }
-
-		  str = __mempcpy (str, buf, n);
-#endif
-		  *str++ = '\0';
-
-		  if ((flags & MALLOC) && str - *strptr != strsize)
-		    {
-		      char *cp = (char *) realloc (*strptr, str - *strptr);
-		      if (cp != NULL)
-			*strptr = cp;
-		    }
-		  strptr = NULL;
-
-		  ++done;
-		}
-	      break;
-	    }
-	  /* FALLTHROUGH */
-
-	case L_('S'):
-	  {
-#ifndef COMPILE_WSCANF
-	    mbstate_t cstate;
-#endif
-
-	    /* Wide character string.  */
-	    STRING_ARG (wstr, wchar_t, 100);
-
-	    c = inchar ();
-	    if (__builtin_expect (c == EOF,  0))
-	      input_error ();
-
-#ifndef COMPILE_WSCANF
-	    memset (&cstate, '\0', sizeof (cstate));
-#endif
-
-	    do
-	      {
-		if (ISSPACE (c))
-		  {
-		    ungetc_not_eof (c, s);
-		    break;
-		  }
-
-#ifdef COMPILE_WSCANF
-		/* This is easy.  */
-		if (!(flags & SUPPRESS))
-		  {
-		    *wstr++ = c;
-		    if ((flags & MALLOC)
-			&& wstr == (wchar_t *) *strptr + strsize)
-		      {
-			/* Enlarge the buffer.  */
-			wstr = (wchar_t *) realloc (*strptr,
-						    (2 * strsize)
-						    * sizeof (wchar_t));
-			if (wstr == NULL)
-			  {
-			    /* Can't allocate that much.  Last-ditch
-			       effort.  */
-			    wstr = (wchar_t *) realloc (*strptr,
-							(strsize + 1)
-							* sizeof (wchar_t));
-			    if (wstr == NULL)
-			      {
-				if (flags & POSIX_MALLOC)
-				  {
-				    done = EOF;
-				    goto errout;
-				  }
-				/* We lose.  Oh well.  Terminate the string
-				   and stop converting, so at least we don't
-				   skip any input.  */
-				((wchar_t *) (*strptr))[strsize - 1] = L'\0';
-				strptr = NULL;
-				++done;
-				conv_error ();
-			      }
-			    else
-			      {
-				*strptr = (char *) wstr;
-				wstr += strsize;
-				++strsize;
-			      }
-			  }
-			else
-			  {
-			    *strptr = (char *) wstr;
-			    wstr += strsize;
-			    strsize *= 2;
-			  }
-		      }
-		  }
-#else
-		{
-		  char buf[1];
-
-		  buf[0] = c;
-
-		  while (1)
-		    {
-		      size_t n;
-
-		      n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
-				     buf, 1, &cstate);
-
-		      if (n == (size_t) -2)
-			{
-			  /* Possibly correct character, just not enough
-			     input.  */
-			  if (__glibc_unlikely (inchar () == EOF))
-			    encode_error ();
-
-			  buf[0] = c;
-			  continue;
-			}
-
-		      if (__glibc_unlikely (n != 1))
-			encode_error ();
-
-		      /* We have a match.  */
-		      ++wstr;
-		      break;
-		    }
-
-		  if (!(flags & SUPPRESS) && (flags & MALLOC)
-		      && wstr == (wchar_t *) *strptr + strsize)
-		    {
-		      /* Enlarge the buffer.  */
-		      wstr = (wchar_t *) realloc (*strptr,
-						  (2 * strsize
-						   * sizeof (wchar_t)));
-		      if (wstr == NULL)
-			{
-			  /* Can't allocate that much.  Last-ditch effort.  */
-			  wstr = (wchar_t *) realloc (*strptr,
-						      ((strsize + 1)
-						       * sizeof (wchar_t)));
-			  if (wstr == NULL)
-			    {
-			      if (flags & POSIX_MALLOC)
-				{
-				  done = EOF;
-				  goto errout;
-				}
-			      /* We lose.  Oh well.  Terminate the
-				 string and stop converting, so at
-				 least we don't skip any input.  */
-			      ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
-			      strptr = NULL;
-			      ++done;
-			      conv_error ();
-			    }
-			  else
-			    {
-			      *strptr = (char *) wstr;
-			      wstr += strsize;
-			      ++strsize;
-			    }
-			}
-		      else
-			{
-			  *strptr = (char *) wstr;
-			  wstr += strsize;
-			  strsize *= 2;
-			}
-		    }
-		}
-#endif
-	      }
-	    while ((width <= 0 || --width > 0) && inchar () != EOF);
-
-	    if (!(flags & SUPPRESS))
-	      {
-		*wstr++ = L'\0';
-
-		if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
-		  {
-		    wchar_t *cp = (wchar_t *) realloc (*strptr,
-						       ((wstr
-							 - (wchar_t *) *strptr)
-							* sizeof(wchar_t)));
-		    if (cp != NULL)
-		      *strptr = (char *) cp;
-		  }
-		strptr = NULL;
-
-		++done;
-	      }
-	  }
-	  break;
-
-	case L_('x'):	/* Hexadecimal integer.  */
-	case L_('X'):	/* Ditto.  */
-	  base = 16;
-	  goto number;
-
-	case L_('o'):	/* Octal integer.  */
-	  base = 8;
-	  goto number;
-
-	case L_('u'):	/* Unsigned decimal integer.  */
-	  base = 10;
-	  goto number;
-
-	case L_('d'):	/* Signed decimal integer.  */
-	  base = 10;
-	  flags |= NUMBER_SIGNED;
-	  goto number;
-
-	case L_('i'):	/* Generic number.  */
-	  base = 0;
-	  flags |= NUMBER_SIGNED;
-
-	number:
-	  c = inchar ();
-	  if (__glibc_unlikely (c == EOF))
-	    input_error ();
-
-	  /* Check for a sign.  */
-	  if (c == L_('-') || c == L_('+'))
-	    {
-	      char_buffer_add (&charbuf, c);
-	      if (width > 0)
-		--width;
-	      c = inchar ();
-	    }
-
-	  /* Look for a leading indication of base.  */
-	  if (width != 0 && c == L_('0'))
-	    {
-	      if (width > 0)
-		--width;
-
-	      char_buffer_add (&charbuf, c);
-	      c = inchar ();
-
-	      if (width != 0 && TOLOWER (c) == L_('x'))
-		{
-		  if (base == 0)
-		    base = 16;
-		  if (base == 16)
-		    {
-		      if (width > 0)
-			--width;
-		      c = inchar ();
-		    }
-		}
-	      else if (base == 0)
-		base = 8;
-	    }
-
-	  if (base == 0)
-	    base = 10;
-
-	  if (base == 10 && __builtin_expect ((flags & I18N) != 0, 0))
-	    {
-	      int from_level;
-	      int to_level;
-	      int level;
-#ifdef COMPILE_WSCANF
-	      const wchar_t *wcdigits[10];
-	      const wchar_t *wcdigits_extended[10];
-#else
-	      const char *mbdigits[10];
-	      const char *mbdigits_extended[10];
-#endif
-	      /*  "to_inpunct" is a map from ASCII digits to their
-		  equivalent in locale. This is defined for locales
-		  which use an extra digits set.  */
-	      wctrans_t map = __wctrans ("to_inpunct");
-	      int n;
-
-	      from_level = 0;
-#ifdef COMPILE_WSCANF
-	      to_level = _NL_CURRENT_WORD (LC_CTYPE,
-					   _NL_CTYPE_INDIGITS_WC_LEN) - 1;
-#else
-	      to_level = (uint32_t) curctype->values[_NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_MB_LEN)].word - 1;
-#endif
-
-	      /* Get the alternative digit forms if there are any.  */
-	      if (__glibc_unlikely (map != NULL))
-		{
-		  /*  Adding new level for extra digits set in locale file.  */
-		  ++to_level;
-
-		  for (n = 0; n < 10; ++n)
-		    {
-#ifdef COMPILE_WSCANF
-		      wcdigits[n] = (const wchar_t *)
-			_NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
-
-		      wchar_t *wc_extended = (wchar_t *)
-			alloca ((to_level + 2) * sizeof (wchar_t));
-		      __wmemcpy (wc_extended, wcdigits[n], to_level);
-		      wc_extended[to_level] = __towctrans (L'0' + n, map);
-		      wc_extended[to_level + 1] = '\0';
-		      wcdigits_extended[n] = wc_extended;
-#else
-		      mbdigits[n]
-			= curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
-
-		      /*  Get the equivalent wide char in map.  */
-		      wint_t extra_wcdigit = __towctrans (L'0' + n, map);
-
-		      /*  Convert it to multibyte representation.  */
-		      mbstate_t state;
-		      memset (&state, '\0', sizeof (state));
-
-		      char extra_mbdigit[MB_LEN_MAX];
-		      size_t mblen
-			= __wcrtomb (extra_mbdigit, extra_wcdigit, &state);
-
-		      if (mblen == (size_t) -1)
-			{
-			  /*  Ignore this new level.  */
-			  map = NULL;
-			  break;
-			}
-
-		      /*  Calculate the length of mbdigits[n].  */
-		      const char *last_char = mbdigits[n];
-		      for (level = 0; level < to_level; ++level)
-			last_char = strchr (last_char, '\0') + 1;
-
-		      size_t mbdigits_len = last_char - mbdigits[n];
-
-		      /*  Allocate memory for extended multibyte digit.  */
-		      char *mb_extended;
-		      mb_extended = (char *) alloca (mbdigits_len + mblen + 1);
-
-		      /*  And get the mbdigits + extra_digit string.  */
-		      *(char *) __mempcpy (__mempcpy (mb_extended, mbdigits[n],
-						      mbdigits_len),
-					   extra_mbdigit, mblen) = '\0';
-		      mbdigits_extended[n] = mb_extended;
-#endif
-		    }
-		}
-
-	      /* Read the number into workspace.  */
-	      while (c != EOF && width != 0)
-		{
-		  /* In this round we get the pointer to the digit strings
-		     and also perform the first round of comparisons.  */
-		  for (n = 0; n < 10; ++n)
-		    {
-		      /* Get the string for the digits with value N.  */
-#ifdef COMPILE_WSCANF
-
-		      /* wcdigits_extended[] is fully set in the loop
-			 above, but the test for "map != NULL" is done
-			 inside the loop here and outside the loop there.  */
-		      DIAG_PUSH_NEEDS_COMMENT;
-		      DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized");
-
-		      if (__glibc_unlikely (map != NULL))
-			wcdigits[n] = wcdigits_extended[n];
-		      else
-			wcdigits[n] = (const wchar_t *)
-			  _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
-		      wcdigits[n] += from_level;
-
-		      DIAG_POP_NEEDS_COMMENT;
-
-		      if (c == (wint_t) *wcdigits[n])
-			{
-			  to_level = from_level;
-			  break;
-			}
-
-		      /* Advance the pointer to the next string.  */
-		      ++wcdigits[n];
-#else
-		      const char *cmpp;
-		      int avail = width > 0 ? width : INT_MAX;
-
-		      if (__glibc_unlikely (map != NULL))
-			mbdigits[n] = mbdigits_extended[n];
-		      else
-			mbdigits[n]
-			  = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
-
-		      for (level = 0; level < from_level; level++)
-			mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
-
-		      cmpp = mbdigits[n];
-		      while ((unsigned char) *cmpp == c && avail >= 0)
-			{
-			  if (*++cmpp == '\0')
-			    break;
-			  else
-			    {
-			      if (avail == 0 || inchar () == EOF)
-				break;
-			      --avail;
-			    }
-			}
-
-		      if (*cmpp == '\0')
-			{
-			  if (width > 0)
-			    width = avail;
-			  to_level = from_level;
-			  break;
-			}
-
-		      /* We are pushing all read characters back.  */
-		      if (cmpp > mbdigits[n])
-			{
-			  ungetc (c, s);
-			  while (--cmpp > mbdigits[n])
-			    ungetc_not_eof ((unsigned char) *cmpp, s);
-			  c = (unsigned char) *cmpp;
-			}
-
-		      /* Advance the pointer to the next string.  */
-		      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
-#endif
-		    }
-
-		  if (n == 10)
-		    {
-		      /* Have not yet found the digit.  */
-		      for (level = from_level + 1; level <= to_level; ++level)
-			{
-			  /* Search all ten digits of this level.  */
-			  for (n = 0; n < 10; ++n)
-			    {
-#ifdef COMPILE_WSCANF
-			      if (c == (wint_t) *wcdigits[n])
-				break;
-
-			      /* Advance the pointer to the next string.  */
-			      ++wcdigits[n];
-#else
-			      const char *cmpp;
-			      int avail = width > 0 ? width : INT_MAX;
-
-			      cmpp = mbdigits[n];
-			      while ((unsigned char) *cmpp == c && avail >= 0)
-				{
-				  if (*++cmpp == '\0')
-				    break;
-				  else
-				    {
-				      if (avail == 0 || inchar () == EOF)
-					break;
-				      --avail;
-				    }
-				}
-
-			      if (*cmpp == '\0')
-				{
-				  if (width > 0)
-				    width = avail;
-				  break;
-				}
-
-			      /* We are pushing all read characters back.  */
-			      if (cmpp > mbdigits[n])
-				{
-				  ungetc (c, s);
-				  while (--cmpp > mbdigits[n])
-				    ungetc_not_eof ((unsigned char) *cmpp, s);
-				  c = (unsigned char) *cmpp;
-				}
-
-			      /* Advance the pointer to the next string.  */
-			      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
-#endif
-			    }
-
-			  if (n < 10)
-			    {
-			      /* Found it.  */
-			      from_level = level;
-			      to_level = level;
-			      break;
-			    }
-			}
-		    }
-
-		  if (n < 10)
-		    c = L_('0') + n;
-		  else if (flags & GROUP)
-		    {
-		      /* Try matching against the thousands separator.  */
-#ifdef COMPILE_WSCANF
-		      if (c != thousands)
-			  break;
-#else
-		      const char *cmpp = thousands;
-		      int avail = width > 0 ? width : INT_MAX;
-
-		      while ((unsigned char) *cmpp == c && avail >= 0)
-			{
-			  char_buffer_add (&charbuf, c);
-			  if (*++cmpp == '\0')
-			    break;
-			  else
-			    {
-			      if (avail == 0 || inchar () == EOF)
-				break;
-			      --avail;
-			    }
-			}
-
-		      if (char_buffer_error (&charbuf))
-			{
-			  __set_errno (ENOMEM);
-			  done = EOF;
-			  goto errout;
-			}
-
-		      if (*cmpp != '\0')
-			{
-			  /* We are pushing all read characters back.  */
-			  if (cmpp > thousands)
-			    {
-			      charbuf.current -= cmpp - thousands;
-			      ungetc (c, s);
-			      while (--cmpp > thousands)
-				ungetc_not_eof ((unsigned char) *cmpp, s);
-			      c = (unsigned char) *cmpp;
-			    }
-			  break;
-			}
-
-		      if (width > 0)
-			width = avail;
-
-		      /* The last thousands character will be added back by
-			 the char_buffer_add below.  */
-		      --charbuf.current;
-#endif
-		    }
-		  else
-		    break;
-
-		  char_buffer_add (&charbuf, c);
-		  if (width > 0)
-		    --width;
-
-		  c = inchar ();
-		}
-	    }
-	  else
-	    /* Read the number into workspace.  */
-	    while (c != EOF && width != 0)
-	      {
-		if (base == 16)
-		  {
-		    if (!ISXDIGIT (c))
-		      break;
-		  }
-		else if (!ISDIGIT (c) || (int) (c - L_('0')) >= base)
-		  {
-		    if (base == 10 && (flags & GROUP))
-		      {
-			/* Try matching against the thousands separator.  */
-#ifdef COMPILE_WSCANF
-			if (c != thousands)
-			  break;
-#else
-			const char *cmpp = thousands;
-			int avail = width > 0 ? width : INT_MAX;
-
-			while ((unsigned char) *cmpp == c && avail >= 0)
-			  {
-			    char_buffer_add (&charbuf, c);
-			    if (*++cmpp == '\0')
-			      break;
-			    else
-			      {
-				if (avail == 0 || inchar () == EOF)
-				  break;
-				--avail;
-			      }
-			  }
-
-			if (char_buffer_error (&charbuf))
-			  {
-			    __set_errno (ENOMEM);
-			    done = EOF;
-			    goto errout;
-			  }
-
-			if (*cmpp != '\0')
-			  {
-			    /* We are pushing all read characters back.  */
-			    if (cmpp > thousands)
-			      {
-				charbuf.current -= cmpp - thousands;
-				ungetc (c, s);
-				while (--cmpp > thousands)
-				  ungetc_not_eof ((unsigned char) *cmpp, s);
-				c = (unsigned char) *cmpp;
-			      }
-			    break;
-			  }
-
-			if (width > 0)
-			  width = avail;
-
-			/* The last thousands character will be added back by
-			   the char_buffer_add below.  */
-			--charbuf.current;
-#endif
-		      }
-		    else
-		      break;
-		  }
-		char_buffer_add (&charbuf, c);
-		if (width > 0)
-		  --width;
-
-		c = inchar ();
-	      }
-
-	  if (char_buffer_error (&charbuf))
-	    {
-	      __set_errno (ENOMEM);
-	      done = EOF;
-	      goto errout;
-	    }
-
-	  if (char_buffer_size (&charbuf) == 0
-	      || (char_buffer_size (&charbuf) == 1
-		  && (char_buffer_start (&charbuf)[0] == L_('+')
-		      || char_buffer_start (&charbuf)[0] == L_('-'))))
-	    {
-	      /* There was no number.  If we are supposed to read a pointer
-		 we must recognize "(nil)" as well.  */
-	      if (__builtin_expect (char_buffer_size (&charbuf) == 0
-				    && (flags & READ_POINTER)
-				    && (width < 0 || width >= 5)
-				    && c == '('
-				    && TOLOWER (inchar ()) == L_('n')
-				    && TOLOWER (inchar ()) == L_('i')
-				    && TOLOWER (inchar ()) == L_('l')
-				    && inchar () == L_(')'), 1))
-		/* We must produce the value of a NULL pointer.  A single
-		   '0' digit is enough.  */
-		  char_buffer_add (&charbuf, L_('0'));
-	      else
-		{
-		  /* The last read character is not part of the number
-		     anymore.  */
-		  ungetc (c, s);
-
-		  conv_error ();
-		}
-	    }
-	  else
-	    /* The just read character is not part of the number anymore.  */
-	    ungetc (c, s);
-
-	  /* Convert the number.  */
-	  char_buffer_add (&charbuf, L_('\0'));
-	  if (char_buffer_error (&charbuf))
-	    {
-	      __set_errno (ENOMEM);
-	      done = EOF;
-	      goto errout;
-	    }
-	  if (need_longlong && (flags & LONGDBL))
-	    {
-	      if (flags & NUMBER_SIGNED)
-		num.q = __strtoll_internal
-		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
-	      else
-		num.uq = __strtoull_internal
-		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
-	    }
-	  else
-	    {
-	      if (flags & NUMBER_SIGNED)
-		num.l = __strtol_internal
-		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
-	      else
-		num.ul = __strtoul_internal
-		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
-	    }
-	  if (__glibc_unlikely (char_buffer_start (&charbuf) == tw))
-	    conv_error ();
-
-	  if (!(flags & SUPPRESS))
-	    {
-	      if (flags & NUMBER_SIGNED)
-		{
-		  if (need_longlong && (flags & LONGDBL))
-		    *ARG (LONGLONG int *) = num.q;
-		  else if (need_long && (flags & LONG))
-		    *ARG (long int *) = num.l;
-		  else if (flags & SHORT)
-		    *ARG (short int *) = (short int) num.l;
-		  else if (!(flags & CHAR))
-		    *ARG (int *) = (int) num.l;
-		  else
-		    *ARG (signed char *) = (signed char) num.ul;
-		}
-	      else
-		{
-		  if (need_longlong && (flags & LONGDBL))
-		    *ARG (unsigned LONGLONG int *) = num.uq;
-		  else if (need_long && (flags & LONG))
-		    *ARG (unsigned long int *) = num.ul;
-		  else if (flags & SHORT)
-		    *ARG (unsigned short int *)
-		      = (unsigned short int) num.ul;
-		  else if (!(flags & CHAR))
-		    *ARG (unsigned int *) = (unsigned int) num.ul;
-		  else
-		    *ARG (unsigned char *) = (unsigned char) num.ul;
-		}
-	      ++done;
-	    }
-	  break;
-
-	case L_('e'):	/* Floating-point numbers.  */
-	case L_('E'):
-	case L_('f'):
-	case L_('F'):
-	case L_('g'):
-	case L_('G'):
-	case L_('a'):
-	case L_('A'):
-	  c = inchar ();
-	  if (width > 0)
-	    --width;
-	  if (__glibc_unlikely (c == EOF))
-	    input_error ();
-
-	  got_digit = got_dot = got_e = got_sign = 0;
-
-	  /* Check for a sign.  */
-	  if (c == L_('-') || c == L_('+'))
-	    {
-	      got_sign = 1;
-	      char_buffer_add (&charbuf, c);
-	      if (__glibc_unlikely (width == 0 || inchar () == EOF))
-		/* EOF is only an input error before we read any chars.  */
-		conv_error ();
-	      if (width > 0)
-		--width;
-	    }
-
-	  /* Take care for the special arguments "nan" and "inf".  */
-	  if (TOLOWER (c) == L_('n'))
-	    {
-	      /* Maybe "nan".  */
-	      char_buffer_add (&charbuf, c);
-	      if (__builtin_expect (width == 0
-				    || inchar () == EOF
-				    || TOLOWER (c) != L_('a'), 0))
-		conv_error ();
-	      if (width > 0)
-		--width;
-	      char_buffer_add (&charbuf, c);
-	      if (__builtin_expect (width == 0
-				    || inchar () == EOF
-				    || TOLOWER (c) != L_('n'), 0))
-		conv_error ();
-	      if (width > 0)
-		--width;
-	      char_buffer_add (&charbuf, c);
-	      /* It is "nan".  */
-	      goto scan_float;
-	    }
-	  else if (TOLOWER (c) == L_('i'))
-	    {
-	      /* Maybe "inf" or "infinity".  */
-	      char_buffer_add (&charbuf, c);
-	      if (__builtin_expect (width == 0
-				    || inchar () == EOF
-				    || TOLOWER (c) != L_('n'), 0))
-		conv_error ();
-	      if (width > 0)
-		--width;
-	      char_buffer_add (&charbuf, c);
-	      if (__builtin_expect (width == 0
-				    || inchar () == EOF
-				    || TOLOWER (c) != L_('f'), 0))
-		conv_error ();
-	      if (width > 0)
-		--width;
-	      char_buffer_add (&charbuf, c);
-	      /* It is as least "inf".  */
-	      if (width != 0 && inchar () != EOF)
-		{
-		  if (TOLOWER (c) == L_('i'))
-		    {
-		      if (width > 0)
-			--width;
-		      /* Now we have to read the rest as well.  */
-		      char_buffer_add (&charbuf, c);
-		      if (__builtin_expect (width == 0
-					    || inchar () == EOF
-					    || TOLOWER (c) != L_('n'), 0))
-			conv_error ();
-		      if (width > 0)
-			--width;
-		      char_buffer_add (&charbuf, c);
-		      if (__builtin_expect (width == 0
-					    || inchar () == EOF
-					    || TOLOWER (c) != L_('i'), 0))
-			conv_error ();
-		      if (width > 0)
-			--width;
-		      char_buffer_add (&charbuf, c);
-		      if (__builtin_expect (width == 0
-					    || inchar () == EOF
-					    || TOLOWER (c) != L_('t'), 0))
-			conv_error ();
-		      if (width > 0)
-			--width;
-		      char_buffer_add (&charbuf, c);
-		      if (__builtin_expect (width == 0
-					    || inchar () == EOF
-					    || TOLOWER (c) != L_('y'), 0))
-			conv_error ();
-		      if (width > 0)
-			--width;
-		      char_buffer_add (&charbuf, c);
-		    }
-		  else
-		    /* Never mind.  */
-		    ungetc (c, s);
-		}
-	      goto scan_float;
-	    }
-
-	  exp_char = L_('e');
-	  if (width != 0 && c == L_('0'))
-	    {
-	      char_buffer_add (&charbuf, c);
-	      c = inchar ();
-	      if (width > 0)
-		--width;
-	      if (width != 0 && TOLOWER (c) == L_('x'))
-		{
-		  /* It is a number in hexadecimal format.  */
-		  char_buffer_add (&charbuf, c);
-
-		  flags |= HEXA_FLOAT;
-		  exp_char = L_('p');
-
-		  /* Grouping is not allowed.  */
-		  flags &= ~GROUP;
-		  c = inchar ();
-		  if (width > 0)
-		    --width;
-		}
-	      else
-		got_digit = 1;
-	    }
-
-	  while (1)
-	    {
-	      if (char_buffer_error (&charbuf))
-		{
-		  __set_errno (ENOMEM);
-		  done = EOF;
-		  goto errout;
-		}
-	      if (ISDIGIT (c))
-		{
-		  char_buffer_add (&charbuf, c);
-		  got_digit = 1;
-		}
-	      else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c))
-		{
-		  char_buffer_add (&charbuf, c);
-		  got_digit = 1;
-		}
-	      else if (got_e && charbuf.current[-1] == exp_char
-		       && (c == L_('-') || c == L_('+')))
-		char_buffer_add (&charbuf, c);
-	      else if (got_digit && !got_e
-		       && (CHAR_T) TOLOWER (c) == exp_char)
-		{
-		  char_buffer_add (&charbuf, exp_char);
-		  got_e = got_dot = 1;
-		}
-	      else
-		{
-#ifdef COMPILE_WSCANF
-		  if (! got_dot && c == decimal)
-		    {
-		      char_buffer_add (&charbuf, c);
-		      got_dot = 1;
-		    }
-		  else if ((flags & GROUP) != 0 && ! got_dot && c == thousands)
-		    char_buffer_add (&charbuf, c);
-		  else
-		    {
-		      /* The last read character is not part of the number
-			 anymore.  */
-		      ungetc (c, s);
-		      break;
-		    }
-#else
-		  const char *cmpp = decimal;
-		  int avail = width > 0 ? width : INT_MAX;
-
-		  if (! got_dot)
-		    {
-		      while ((unsigned char) *cmpp == c && avail >= 0)
-			if (*++cmpp == '\0')
-			  break;
-			else
-			  {
-			    if (avail == 0 || inchar () == EOF)
-			      break;
-			    --avail;
-			  }
-		    }
-
-		  if (*cmpp == '\0')
-		    {
-		      /* Add all the characters.  */
-		      for (cmpp = decimal; *cmpp != '\0'; ++cmpp)
-			char_buffer_add (&charbuf, (unsigned char) *cmpp);
-		      if (width > 0)
-			width = avail;
-		      got_dot = 1;
-		    }
-		  else
-		    {
-		      /* Figure out whether it is a thousands separator.
-			 There is one problem: we possibly read more than
-			 one character.  We cannot push them back but since
-			 we know that parts of the `decimal' string matched,
-			 we can compare against it.  */
-		      const char *cmp2p = thousands;
-
-		      if ((flags & GROUP) != 0 && ! got_dot)
-			{
-			  while (cmp2p - thousands < cmpp - decimal
-				 && *cmp2p == decimal[cmp2p - thousands])
-			    ++cmp2p;
-			  if (cmp2p - thousands == cmpp - decimal)
-			    {
-			      while ((unsigned char) *cmp2p == c && avail >= 0)
-				if (*++cmp2p == '\0')
-				  break;
-				else
-				  {
-				    if (avail == 0 || inchar () == EOF)
-				      break;
-				    --avail;
-				  }
-			    }
-			}
-
-		      if (cmp2p != NULL && *cmp2p == '\0')
-			{
-			  /* Add all the characters.  */
-			  for (cmpp = thousands; *cmpp != '\0'; ++cmpp)
-			    char_buffer_add (&charbuf, (unsigned char) *cmpp);
-			  if (width > 0)
-			    width = avail;
-			}
-		      else
-			{
-			  /* The last read character is not part of the number
-			     anymore.  */
-			  ungetc (c, s);
-			  break;
-			}
-		    }
-#endif
-		}
-
-	      if (width == 0 || inchar () == EOF)
-		break;
-
-	      if (width > 0)
-		--width;
-	    }
-
-	  if (char_buffer_error (&charbuf))
-	    {
-	      __set_errno (ENOMEM);
-	      done = EOF;
-	      goto errout;
-	    }
-
-	  wctrans_t map;
-	  if (__builtin_expect ((flags & I18N) != 0, 0)
-	      /* Hexadecimal floats make no sense, fixing localized
-		 digits with ASCII letters.  */
-	      && !(flags & HEXA_FLOAT)
-	      /* Minimum requirement.  */
-	      && (char_buffer_size (&charbuf) == got_sign || got_dot)
-	      && (map = __wctrans ("to_inpunct")) != NULL)
-	    {
-	      /* Reget the first character.  */
-	      inchar ();
-
-	      /* Localized digits, decimal points, and thousands
-		 separator.  */
-	      wint_t wcdigits[12];
-
-	      /* First get decimal equivalent to check if we read it
-		 or not.  */
-	      wcdigits[11] = __towctrans (L'.', map);
-
-	      /* If we have not read any character or have just read
-		 locale decimal point which matches the decimal point
-		 for localized FP numbers, then we may have localized
-		 digits.  Note, we test GOT_DOT above.  */
-#ifdef COMPILE_WSCANF
-	      if (char_buffer_size (&charbuf) == got_sign
-		  || (char_buffer_size (&charbuf) == got_sign + 1
-		      && wcdigits[11] == decimal))
-#else
-	      char mbdigits[12][MB_LEN_MAX + 1];
-
-	      mbstate_t state;
-	      memset (&state, '\0', sizeof (state));
-
-	      bool match_so_far = char_buffer_size (&charbuf) == got_sign;
-	      size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
-	      if (mblen != (size_t) -1)
-		{
-		  mbdigits[11][mblen] = '\0';
-		  match_so_far |=
-		    (char_buffer_size (&charbuf) == strlen (decimal) + got_sign
-		     && strcmp (decimal, mbdigits[11]) == 0);
-		}
-	      else
-		{
-		  size_t decimal_len = strlen (decimal);
-		  /* This should always be the case but the data comes
-		     from a file.  */
-		  if (decimal_len <= MB_LEN_MAX)
-		    {
-		      match_so_far |= (char_buffer_size (&charbuf)
-				       == decimal_len + got_sign);
-		      memcpy (mbdigits[11], decimal, decimal_len + 1);
-		    }
-		  else
-		    match_so_far = false;
-		}
-
-	      if (match_so_far)
-#endif
-		{
-		  bool have_locthousands = (flags & GROUP) != 0;
-
-		  /* Now get the digits and the thousands-sep equivalents.  */
-		  for (int n = 0; n < 11; ++n)
-		    {
-		      if (n < 10)
-			wcdigits[n] = __towctrans (L'0' + n, map);
-		      else if (n == 10)
-			{
-			  wcdigits[10] = __towctrans (L',', map);
-			  have_locthousands &= wcdigits[10] != L'\0';
-			}
-
-#ifndef COMPILE_WSCANF
-		      memset (&state, '\0', sizeof (state));
-
-		      size_t mblen = __wcrtomb (mbdigits[n], wcdigits[n],
-						&state);
-		      if (mblen == (size_t) -1)
-			{
-			  if (n == 10)
-			    {
-			      if (have_locthousands)
-				{
-				  size_t thousands_len = strlen (thousands);
-				  if (thousands_len <= MB_LEN_MAX)
-				    memcpy (mbdigits[10], thousands,
-					    thousands_len + 1);
-				  else
-				    have_locthousands = false;
-				}
-			    }
-			  else
-			    /* Ignore checking against localized digits.  */
-			    goto no_i18nflt;
-			}
-		      else
-			mbdigits[n][mblen] = '\0';
-#endif
-		    }
-
-		  /* Start checking against localized digits, if
-		     conversion is done correctly. */
-		  while (1)
-		    {
-		      if (char_buffer_error (&charbuf))
-			{
-			  __set_errno (ENOMEM);
-			  done = EOF;
-			  goto errout;
-			}
-		      if (got_e && charbuf.current[-1] == exp_char
-			  && (c == L_('-') || c == L_('+')))
-			char_buffer_add (&charbuf, c);
-		      else if (char_buffer_size (&charbuf) > got_sign && !got_e
-			       && (CHAR_T) TOLOWER (c) == exp_char)
-			{
-			  char_buffer_add (&charbuf, exp_char);
-			  got_e = got_dot = 1;
-			}
-		      else
-			{
-			  /* Check against localized digits, decimal point,
-			     and thousands separator.  */
-			  int n;
-			  for (n = 0; n < 12; ++n)
-			    {
-#ifdef COMPILE_WSCANF
-			      if (c == wcdigits[n])
-				{
-				  if (n < 10)
-				    char_buffer_add (&charbuf, L_('0') + n);
-				  else if (n == 11 && !got_dot)
-				    {
-				      char_buffer_add (&charbuf, decimal);
-				      got_dot = 1;
-				    }
-				  else if (n == 10 && have_locthousands
-					   && ! got_dot)
-				    char_buffer_add (&charbuf, thousands);
-				  else
-				    /* The last read character is not part
-				       of the number anymore.  */
-				    n = 12;
-
-				  break;
-				}
-#else
-			      const char *cmpp = mbdigits[n];
-			      int avail = width > 0 ? width : INT_MAX;
-
-			      while ((unsigned char) *cmpp == c && avail >= 0)
-				if (*++cmpp == '\0')
-				  break;
-				else
-				  {
-				    if (avail == 0 || inchar () == EOF)
-				      break;
-				    --avail;
-				  }
-			      if (*cmpp == '\0')
-				{
-				  if (width > 0)
-				    width = avail;
-
-				  if (n < 10)
-				    char_buffer_add (&charbuf, L_('0') + n);
-				  else if (n == 11 && !got_dot)
-				    {
-				      /* Add all the characters.  */
-				      for (cmpp = decimal; *cmpp != '\0';
-					   ++cmpp)
-					char_buffer_add (&charbuf,
-							 (unsigned char) *cmpp);
-
-				      got_dot = 1;
-				    }
-				  else if (n == 10 && (flags & GROUP) != 0
-					   && ! got_dot)
-				    {
-				      /* Add all the characters.  */
-				      for (cmpp = thousands; *cmpp != '\0';
-					   ++cmpp)
-					char_buffer_add (&charbuf,
-							 (unsigned char) *cmpp);
-				    }
-				  else
-				    /* The last read character is not part
-				       of the number anymore.  */
-				      n = 12;
-
-				  break;
-				}
-
-			      /* We are pushing all read characters back.  */
-			      if (cmpp > mbdigits[n])
-				{
-				  ungetc (c, s);
-				  while (--cmpp > mbdigits[n])
-				    ungetc_not_eof ((unsigned char) *cmpp, s);
-				  c = (unsigned char) *cmpp;
-				}
-#endif
-			    }
-
-			  if (n >= 12)
-			    {
-			      /* The last read character is not part
-				 of the number anymore.  */
-			      ungetc (c, s);
-			      break;
-			    }
-			}
-
-		      if (width == 0 || inchar () == EOF)
-			break;
-
-		      if (width > 0)
-			--width;
-		    }
-		}
-
-#ifndef COMPILE_WSCANF
-	    no_i18nflt:
-	      ;
-#endif
-	    }
-
-	  if (char_buffer_error (&charbuf))
-	    {
-	      __set_errno (ENOMEM);
-	      done = EOF;
-	      goto errout;
-	    }
-
-	  /* Have we read any character?  If we try to read a number
-	     in hexadecimal notation and we have read only the `0x'
-	     prefix this is an error.  */
-	  if (__glibc_unlikely (char_buffer_size (&charbuf) == got_sign
-				|| ((flags & HEXA_FLOAT)
-				    && (char_buffer_size (&charbuf)
-					== 2 + got_sign))))
-	    conv_error ();
-
-	scan_float:
-	  /* Convert the number.  */
-	  char_buffer_add (&charbuf, L_('\0'));
-	  if (char_buffer_error (&charbuf))
-	    {
-	      __set_errno (ENOMEM);
-	      done = EOF;
-	      goto errout;
-	    }
-	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
-	    {
-	      long double d = __strtold_internal
-		(char_buffer_start (&charbuf), &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (long double *) = d;
-	    }
-	  else if (flags & (LONG | LONGDBL))
-	    {
-	      double d = __strtod_internal
-		(char_buffer_start (&charbuf), &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (double *) = d;
-	    }
-	  else
-	    {
-	      float d = __strtof_internal
-		(char_buffer_start (&charbuf), &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
-		*ARG (float *) = d;
-	    }
-
-	  if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))
-	    conv_error ();
-
-	  if (!(flags & SUPPRESS))
-	    ++done;
-	  break;
-
-	case L_('['):	/* Character class.  */
-	  if (flags & LONG)
-	    STRING_ARG (wstr, wchar_t, 100);
-	  else
-	    STRING_ARG (str, char, 100);
-
-	  if (*f == L_('^'))
-	    {
-	      ++f;
-	      not_in = 1;
-	    }
-	  else
-	    not_in = 0;
-
-	  if (width < 0)
-	    /* There is no width given so there is also no limit on the
-	       number of characters we read.  Therefore we set width to
-	       a very high value to make the algorithm easier.  */
-	    width = INT_MAX;
-
-#ifdef COMPILE_WSCANF
-	  /* Find the beginning and the end of the scanlist.  We are not
-	     creating a lookup table since it would have to be too large.
-	     Instead we search each time through the string.  This is not
-	     a constant lookup time but who uses this feature deserves to
-	     be punished.  */
-	  tw = (wchar_t *) f;	/* Marks the beginning.  */
-
-	  if (*f == L']')
-	    ++f;
-
-	  while ((fc = *f++) != L'\0' && fc != L']');
-
-	  if (__glibc_unlikely (fc == L'\0'))
-	    conv_error ();
-	  wchar_t *twend = (wchar_t *) f - 1;
-#else
-	  /* Fill WP with byte flags indexed by character.
-	     We will use this flag map for matching input characters.  */
-	  if (!scratch_buffer_set_array_size
-	      (&charbuf.scratch, UCHAR_MAX + 1, 1))
-	    {
-	      done = EOF;
-	      goto errout;
-	    }
-	  memset (charbuf.scratch.data, '\0', UCHAR_MAX + 1);
-
-	  fc = *f;
-	  if (fc == ']' || fc == '-')
-	    {
-	      /* If ] or - appears before any char in the set, it is not
-		 the terminator or separator, but the first char in the
-		 set.  */
-	      ((char *)charbuf.scratch.data)[fc] = 1;
-	      ++f;
-	    }
-
-	  while ((fc = *f++) != '\0' && fc != ']')
-	    if (fc == '-' && *f != '\0' && *f != ']'
-		&& (unsigned char) f[-2] <= (unsigned char) *f)
-	      {
-		/* Add all characters from the one before the '-'
-		   up to (but not including) the next format char.  */
-		for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
-		  ((char *)charbuf.scratch.data)[fc] = 1;
-	      }
-	    else
-	      /* Add the character to the flag map.  */
-	      ((char *)charbuf.scratch.data)[fc] = 1;
-
-	  if (__glibc_unlikely (fc == '\0'))
-	    conv_error();
-#endif
-
-	  if (flags & LONG)
-	    {
-	      size_t now = read_in;
-#ifdef COMPILE_WSCANF
-	      if (__glibc_unlikely (inchar () == WEOF))
-		input_error ();
-
-	      do
-		{
-		  wchar_t *runp;
-
-		  /* Test whether it's in the scanlist.  */
-		  runp = tw;
-		  while (runp < twend)
-		    {
-		      if (runp[0] == L'-' && runp[1] != '\0'
-			  && runp + 1 != twend
-			  && runp != tw
-			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
-			{
-			  /* Match against all characters in between the
-			     first and last character of the sequence.  */
-			  wchar_t wc;
-
-			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
-			    if ((wint_t) wc == c)
-			      break;
-
-			  if (wc <= runp[1] && !not_in)
-			    break;
-			  if (wc <= runp[1] && not_in)
-			    {
-			      /* The current character is not in the
-				 scanset.  */
-			      ungetc (c, s);
-			      goto out;
-			    }
-
-			  runp += 2;
-			}
-		      else
-			{
-			  if ((wint_t) *runp == c && !not_in)
-			    break;
-			  if ((wint_t) *runp == c && not_in)
-			    {
-			      ungetc (c, s);
-			      goto out;
-			    }
-
-			  ++runp;
-			}
-		    }
-
-		  if (runp == twend && !not_in)
-		    {
-		      ungetc (c, s);
-		      goto out;
-		    }
-
-		  if (!(flags & SUPPRESS))
-		    {
-		      *wstr++ = c;
-
-		      if ((flags & MALLOC)
-			  && wstr == (wchar_t *) *strptr + strsize)
-			{
-			  /* Enlarge the buffer.  */
-			  wstr = (wchar_t *) realloc (*strptr,
-						      (2 * strsize)
-						      * sizeof (wchar_t));
-			  if (wstr == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      wstr = (wchar_t *)
-				realloc (*strptr, (strsize + 1)
-						  * sizeof (wchar_t));
-			      if (wstr == NULL)
-				{
-				  if (flags & POSIX_MALLOC)
-				    {
-				      done = EOF;
-				      goto errout;
-				    }
-				  /* We lose.  Oh well.  Terminate the string
-				     and stop converting, so at least we don't
-				     skip any input.  */
-				  ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
-				  strptr = NULL;
-				  ++done;
-				  conv_error ();
-				}
-			      else
-				{
-				  *strptr = (char *) wstr;
-				  wstr += strsize;
-				  ++strsize;
-				}
-			    }
-			  else
-			    {
-			      *strptr = (char *) wstr;
-			      wstr += strsize;
-			      strsize *= 2;
-			    }
-			}
-		    }
-		}
-	      while (--width > 0 && inchar () != WEOF);
-	    out:
-#else
-	      char buf[MB_LEN_MAX];
-	      size_t cnt = 0;
-	      mbstate_t cstate;
-
-	      if (__glibc_unlikely (inchar () == EOF))
-		input_error ();
-
-	      memset (&cstate, '\0', sizeof (cstate));
-
-	      do
-		{
-		  if (((char *) charbuf.scratch.data)[c] == not_in)
-		    {
-		      ungetc_not_eof (c, s);
-		      break;
-		    }
-
-		  /* This is easy.  */
-		  if (!(flags & SUPPRESS))
-		    {
-		      size_t n;
-
-		      /* Convert it into a wide character.  */
-		      buf[0] = c;
-		      n = __mbrtowc (wstr, buf, 1, &cstate);
-
-		      if (n == (size_t) -2)
-			{
-			  /* Possibly correct character, just not enough
-			     input.  */
-			  ++cnt;
-			  assert (cnt < MB_LEN_MAX);
-			  continue;
-			}
-		      cnt = 0;
-
-		      ++wstr;
-		      if ((flags & MALLOC)
-			  && wstr == (wchar_t *) *strptr + strsize)
-			{
-			  /* Enlarge the buffer.  */
-			  wstr = (wchar_t *) realloc (*strptr,
-						      (2 * strsize
-						       * sizeof (wchar_t)));
-			  if (wstr == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      wstr = (wchar_t *)
-				realloc (*strptr, ((strsize + 1)
-						   * sizeof (wchar_t)));
-			      if (wstr == NULL)
-				{
-				  if (flags & POSIX_MALLOC)
-				    {
-				      done = EOF;
-				      goto errout;
-				    }
-				  /* We lose.  Oh well.  Terminate the
-				     string and stop converting,
-				     so at least we don't skip any input.  */
-				  ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
-				  strptr = NULL;
-				  ++done;
-				  conv_error ();
-				}
-			      else
-				{
-				  *strptr = (char *) wstr;
-				  wstr += strsize;
-				  ++strsize;
-				}
-			    }
-			  else
-			    {
-			      *strptr = (char *) wstr;
-			      wstr += strsize;
-			      strsize *= 2;
-			    }
-			}
-		    }
-
-		  if (--width <= 0)
-		    break;
-		}
-	      while (inchar () != EOF);
-
-	      if (__glibc_unlikely (cnt != 0))
-		/* We stopped in the middle of recognizing another
-		   character.  That's a problem.  */
-		encode_error ();
-#endif
-
-	      if (__glibc_unlikely (now == read_in))
-		/* We haven't succesfully read any character.  */
-		conv_error ();
-
-	      if (!(flags & SUPPRESS))
-		{
-		  *wstr++ = L'\0';
-
-		  if ((flags & MALLOC)
-		      && wstr - (wchar_t *) *strptr != strsize)
-		    {
-		      wchar_t *cp = (wchar_t *)
-			realloc (*strptr, ((wstr - (wchar_t *) *strptr)
-					   * sizeof(wchar_t)));
-		      if (cp != NULL)
-			*strptr = (char *) cp;
-		    }
-		  strptr = NULL;
-
-		  ++done;
-		}
-	    }
-	  else
-	    {
-	      size_t now = read_in;
-
-	      if (__glibc_unlikely (inchar () == EOF))
-		input_error ();
-
-#ifdef COMPILE_WSCANF
-
-	      memset (&state, '\0', sizeof (state));
-
-	      do
-		{
-		  wchar_t *runp;
-		  size_t n;
-
-		  /* Test whether it's in the scanlist.  */
-		  runp = tw;
-		  while (runp < twend)
-		    {
-		      if (runp[0] == L'-' && runp[1] != '\0'
-			  && runp + 1 != twend
-			  && runp != tw
-			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
-			{
-			  /* Match against all characters in between the
-			     first and last character of the sequence.  */
-			  wchar_t wc;
-
-			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
-			    if ((wint_t) wc == c)
-			      break;
-
-			  if (wc <= runp[1] && !not_in)
-			    break;
-			  if (wc <= runp[1] && not_in)
-			    {
-			      /* The current character is not in the
-				 scanset.  */
-			      ungetc (c, s);
-			      goto out2;
-			    }
-
-			  runp += 2;
-			}
-		      else
-			{
-			  if ((wint_t) *runp == c && !not_in)
-			    break;
-			  if ((wint_t) *runp == c && not_in)
-			    {
-			      ungetc (c, s);
-			      goto out2;
-			    }
-
-			  ++runp;
-			}
-		    }
-
-		  if (runp == twend && !not_in)
-		    {
-		      ungetc (c, s);
-		      goto out2;
-		    }
-
-		  if (!(flags & SUPPRESS))
-		    {
-		      if ((flags & MALLOC)
-			  && *strptr + strsize - str <= MB_LEN_MAX)
-			{
-			  /* Enlarge the buffer.  */
-			  size_t strleng = str - *strptr;
-			  char *newstr;
-
-			  newstr = (char *) realloc (*strptr, 2 * strsize);
-			  if (newstr == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      newstr = (char *) realloc (*strptr,
-							 strleng + MB_LEN_MAX);
-			      if (newstr == NULL)
-				{
-				  if (flags & POSIX_MALLOC)
-				    {
-				      done = EOF;
-				      goto errout;
-				    }
-				  /* We lose.  Oh well.  Terminate the string
-				     and stop converting, so at least we don't
-				     skip any input.  */
-				  ((char *) (*strptr))[strleng] = '\0';
-				  strptr = NULL;
-				  ++done;
-				  conv_error ();
-				}
-			      else
-				{
-				  *strptr = newstr;
-				  str = newstr + strleng;
-				  strsize = strleng + MB_LEN_MAX;
-				}
-			    }
-			  else
-			    {
-			      *strptr = newstr;
-			      str = newstr + strleng;
-			      strsize *= 2;
-			    }
-			}
-		    }
-
-		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
-		  if (__glibc_unlikely (n == (size_t) -1))
-		    encode_error ();
-
-		  assert (n <= MB_LEN_MAX);
-		  str += n;
-		}
-	      while (--width > 0 && inchar () != WEOF);
-	    out2:
-#else
-	      do
-		{
-		  if (((char *) charbuf.scratch.data)[c] == not_in)
-		    {
-		      ungetc_not_eof (c, s);
-		      break;
-		    }
-
-		  /* This is easy.  */
-		  if (!(flags & SUPPRESS))
-		    {
-		      *str++ = c;
-		      if ((flags & MALLOC)
-			  && (char *) str == *strptr + strsize)
-			{
-			  /* Enlarge the buffer.  */
-			  size_t newsize = 2 * strsize;
-
-			allocagain:
-			  str = (char *) realloc (*strptr, newsize);
-			  if (str == NULL)
-			    {
-			      /* Can't allocate that much.  Last-ditch
-				 effort.  */
-			      if (newsize > strsize + 1)
-				{
-				  newsize = strsize + 1;
-				  goto allocagain;
-				}
-			      if (flags & POSIX_MALLOC)
-				{
-				  done = EOF;
-				  goto errout;
-				}
-			      /* We lose.  Oh well.  Terminate the
-				 string and stop converting,
-				 so at least we don't skip any input.  */
-			      ((char *) (*strptr))[strsize - 1] = '\0';
-			      strptr = NULL;
-			      ++done;
-			      conv_error ();
-			    }
-			  else
-			    {
-			      *strptr = (char *) str;
-			      str += strsize;
-			      strsize = newsize;
-			    }
-			}
-		    }
-		}
-	      while (--width > 0 && inchar () != EOF);
-#endif
-
-	      if (__glibc_unlikely (now == read_in))
-		/* We haven't succesfully read any character.  */
-		conv_error ();
-
-	      if (!(flags & SUPPRESS))
-		{
-#ifdef COMPILE_WSCANF
-		  /* We have to emit the code to get into the initial
-		     state.  */
-		  char buf[MB_LEN_MAX];
-		  size_t n = __wcrtomb (buf, L'\0', &state);
-		  if (n > 0 && (flags & MALLOC)
-		      && str + n >= *strptr + strsize)
-		    {
-		      /* Enlarge the buffer.  */
-		      size_t strleng = str - *strptr;
-		      char *newstr;
-
-		      newstr = (char *) realloc (*strptr, strleng + n + 1);
-		      if (newstr == NULL)
-			{
-			  if (flags & POSIX_MALLOC)
-			    {
-			      done = EOF;
-			      goto errout;
-			    }
-			  /* We lose.  Oh well.  Terminate the string
-			     and stop converting, so at least we don't
-			     skip any input.  */
-			  ((char *) (*strptr))[strleng] = '\0';
-			  strptr = NULL;
-			  ++done;
-			  conv_error ();
-			}
-		      else
-			{
-			  *strptr = newstr;
-			  str = newstr + strleng;
-			  strsize = strleng + n + 1;
-			}
-		    }
-
-		  str = __mempcpy (str, buf, n);
-#endif
-		  *str++ = '\0';
-
-		  if ((flags & MALLOC) && str - *strptr != strsize)
-		    {
-		      char *cp = (char *) realloc (*strptr, str - *strptr);
-		      if (cp != NULL)
-			*strptr = cp;
-		    }
-		  strptr = NULL;
-
-		  ++done;
-		}
-	    }
-	  break;
-
-	case L_('p'):	/* Generic pointer.  */
-	  base = 16;
-	  /* A PTR must be the same size as a `long int'.  */
-	  flags &= ~(SHORT|LONGDBL);
-	  if (need_long)
-	    flags |= LONG;
-	  flags |= READ_POINTER;
-	  goto number;
-
-	default:
-	  /* If this is an unknown format character punt.  */
-	  conv_error ();
-	}
-    }
-
-  /* The last thing we saw int the format string was a white space.
-     Consume the last white spaces.  */
-  if (skip_space)
-    {
-      do
-	c = inchar ();
-      while (ISSPACE (c));
-      ungetc (c, s);
-    }
-
- errout:
-  /* Unlock stream.  */
-  UNLOCK_STREAM (s);
-
-  scratch_buffer_free (&charbuf.scratch);
-  if (errp != NULL)
-    *errp |= errval;
-
-  if (__glibc_unlikely (done == EOF))
-    {
-      if (__glibc_unlikely (ptrs_to_free != NULL))
-	{
-	  struct ptrs_to_free *p = ptrs_to_free;
-	  while (p != NULL)
-	    {
-	      for (size_t cnt = 0; cnt < p->count; ++cnt)
-		{
-		  free (*p->ptrs[cnt]);
-		  *p->ptrs[cnt] = NULL;
-		}
-	      p = p->next;
-	      ptrs_to_free = p;
-	    }
-	}
-    }
-  else if (__glibc_unlikely (strptr != NULL))
-    {
-      free (*strptr);
-      *strptr = NULL;
-    }
-  return done;
-}
-
-#ifdef COMPILE_WSCANF
-int
-__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
-{
-  return _IO_vfwscanf (s, format, argptr, NULL);
-}
-ldbl_weak_alias (__vfwscanf, vfwscanf)
-#else
 int
 ___vfscanf (FILE *s, const char *format, va_list argptr)
 {
-  return _IO_vfscanf_internal (s, format, argptr, NULL);
+  return __vfscanf_internal (s, format, argptr, 0);
 }
-ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
 ldbl_strong_alias (___vfscanf, __vfscanf)
 ldbl_hidden_def (___vfscanf, __vfscanf)
 ldbl_weak_alias (___vfscanf, vfscanf)
-#endif
diff --git a/stdio-common/vfwscanf-internal.c b/stdio-common/vfwscanf-internal.c
new file mode 100644
index 0000000000..26c89270b7
--- /dev/null
+++ b/stdio-common/vfwscanf-internal.c
@@ -0,0 +1,2 @@
+#define COMPILE_WSCANF	1
+#include "vfscanf-internal.c"
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
index 26b1a66608..86980464c2 100644
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf.c
@@ -1,2 +1,26 @@
-#define COMPILE_WSCANF	1
-#include "vfscanf.c"
+/* Implementation and symbols for vfwscanf.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+
+int
+__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
+{
+  return __vfwscanf_internal (s, format, argptr, 0);
+}
+ldbl_weak_alias (__vfwscanf, vfwscanf)
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 8a5d8ba107..92f670dff7 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -6,9 +6,13 @@
    for platforms where compatibility symbols are required for a previous
    ABI that defined long double functions as aliases for the double code.  */
 
+#include <shlib-compat.h>
+
 #define LONG_DOUBLE_COMPAT(lib, introduced) 0
 #define long_double_symbol(lib, local, symbol)
 #define ldbl_hidden_def(local, name) libc_hidden_def (name)
 #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+#define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 #define __ldbl_is_dbl 0
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index 61ba784f86..1c49036f7b 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -20,10 +20,16 @@
   long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
 # define long_double_symbol_1(lib, local, symbol, version) \
   versioned_symbol (lib, local, symbol, version)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
 #else
 # define ldbl_hidden_def(local, name) libc_hidden_def (name)
 # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+/* Same as compat_symbol, ldbl_compat_symbol is not to be used outside
+   '#if SHLIB_COMPAT' statement and should fail if it is.  */
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  _Static_assert (0, "ldbl_compat_symbol should be used inside SHLIB_COMPAT");
 # ifndef __ASSEMBLER__
 /* Note that weak_alias cannot be used - it is defined to nothing
    in most of the C files.  */
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 7a1e89c1a3..91ea27a423 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -330,16 +330,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
   return done;
 }
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
 int
 attribute_compat_text_section
 __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, errp);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
+  if (__glibc_unlikely (errp != 0))
+    *errp = (res == -1);
   return res;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -347,7 +351,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, NULL);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -423,7 +427,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfwscanf (s, fmt, ap, NULL);
+  res = __vfwscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -1027,7 +1031,6 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
-compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
@@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
 compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
 compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
+/* This function is not in public headers, but was exported until
+   version 2.29.  For platforms that are newer than that, there's no
+   need to expose the symbol.  */
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
+compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+# endif
 #endif
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
 compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 0c6a2c47ac..00b07dd48e 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stream, format, arg, NULL);
+  done = __vfwscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index ff523db706..40401d0aa1 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -16,20 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#include <wchar.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index 7beb45b4d3..f70c6b596d 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stream, format, args, NULL);
+  done = __vfwscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index 130769154d..b91eb651a3 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
 #include <wchar.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index 049521b964..eb22c8acae 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stdin, format, args, NULL);
+  done = __vfwscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index abfbd50c11..59f80d78fb 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stdin);
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
                   ` (4 preceding siblings ...)
  2018-11-15 21:46 ` [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319) Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-22 17:39   ` Adhemerval Zanella
  2018-11-15 21:53 ` [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL " Gabriel F. T. Gomes
  2018-12-02 11:53 ` [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Florian Weimer
  7 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changes since v2

  - None, but dependent on previous patch in the set, thus resending.

Changed since v1:

  - In __nldbl___isoc99_vwscanf, called __vfwscanf_internal directly
    (missing (accidentally?) from the previous version).
  - Broke long lines.
  - Changed name of variable (from rv to ret), since the rationale for
    making these changes to variables names is consistency.
  - Added signed-off-by statements.

-- 8< --
Change the callers of __vfscanf_internal and __vfwscanf_internal that
want to treat 'long double' as another name for 'double' (all of which
happen to be in sysdeps/ieee754/ldbl-opt/nldbl-compat.c) to communicate
this via the new flags argument, instead of the per-thread variable
__no_long_double and its __ldbl_is_dbl wrapper macro.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* stdio-common/vfscanf-internal.c: Don't look at __ldbl_is_dbl.
	* sysdeps/ieee754/ldbl-opt/ndlbl-compat.c:
	Include libio/strfile.h instead of libioP.h.
	(__nldbl_IO_vfscanf, __ndlbl___vfscanf, __nldbl_sscanf)
	(__nldbl___vsscanf, __nldbl_vscanf, __nldbl_fscanf)
	(__nldbl_scanf, __nldbl_vfwscanf, __nldbl_swscanf)
	(__nldbl_vswscanf, __nldbl_vwscanf, __nldbl_fwscanf)
	(__nldbl_wscanf): Call __vfscanf_internal / __vfwscanf_internal
	directly, passing SCANF_LDBL_IS_DBL.  Set up a strfile if
	necessary.  Do not set __no_long_double.  Normalize variable names.
	(__nldbl___isoc99_vfscanf, __nldbl___isoc99_sscanf)
	(__nldbl___isoc99_vsscanf, __nldbl___isoc99_vscanf)
	(__nldbl___isoc99_fscanf, __nldbl___isoc99_scanf)
	(__nldbl___isoc99_vfwscanf, __nldbl___isoc99_swscanf)
	(__nldbl___isoc99_vswscanf, __nldbl___isoc99_vwscanf)
	(__nldbl___isoc99_fwscanf, __nldbl___isoc99_wscanf):
	Call __vfscanf_internal / __vfwscanf_internal directly, passing
	SCANF_LDBL_IS_DBL | SCANF_ISOC99_A.  Set up a strfile if necessary.
	Do not set __no_long_double.  Normalize variable names.
---
 stdio-common/vfscanf-internal.c         |   4 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 251 +++++++++++++++-----------------
 2 files changed, 121 insertions(+), 134 deletions(-)

diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index f0072d8682..818b558140 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -332,10 +332,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
   struct char_buffer charbuf;
   scratch_buffer_init (&charbuf.scratch);
 
-  /* Temporarily honor the environmental mode bits.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= SCANF_LDBL_IS_DBL;
-
 #ifdef __va_copy
   __va_copy (arg, argptr);
 #else
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 91ea27a423..468e23dec4 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -19,7 +19,7 @@
 
 #include <stdarg.h>
 #include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
 #include <math.h>
 #include <wchar.h>
 #include <printf.h>
@@ -335,13 +335,10 @@ int
 attribute_compat_text_section
 __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
+  int ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
   if (__glibc_unlikely (errp != 0))
-    *errp = (res == -1);
-  return res;
+    *errp = (ret == -1);
+  return ret;
 }
 #endif
 
@@ -349,11 +346,7 @@ int
 attribute_compat_text_section
 __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 weak_alias (__nldbl___vfscanf, __nldbl_vfscanf)
 libc_hidden_def (__nldbl_vfscanf)
@@ -362,26 +355,26 @@ int
 attribute_compat_text_section
 __nldbl_sscanf (const char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_sscanf, __nldbl__IO_sscanf)
 
 int
 attribute_compat_text_section
-__nldbl___vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___vsscanf (const char *s, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = _IO_vsscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 weak_alias (__nldbl___vsscanf, __nldbl_vsscanf)
 libc_hidden_def (__nldbl_vsscanf)
@@ -390,46 +383,42 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vscanf (const char *fmt, va_list ap)
 {
-  return __nldbl_vfscanf (stdin, fmt, ap);
+  return __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_fscanf (FILE *stream, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_scanf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwscanf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfwscanf)
 
@@ -437,25 +426,28 @@ int
 attribute_compat_text_section
 __nldbl_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vswscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl_vswscanf (const wchar_t *string, const wchar_t *fmt, va_list ap)
+__nldbl_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = vswscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vswscanf)
 
@@ -463,35 +455,35 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vwscanf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl_vfwscanf (stdin, fmt, ap);
+  return __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_fwscanf (FILE *stream, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_wscanf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
@@ -866,11 +858,7 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vfscanf (FILE *s, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __isoc99_vfscanf (s, fmt, ap);
-  clear_no_long_double ();
-  return res;
+  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vfscanf)
 
@@ -878,25 +866,26 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_sscanf (const char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vsscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___isoc99_vsscanf (const char *s, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __isoc99_vsscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+
+  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vsscanf)
 
@@ -904,46 +893,44 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vscanf (const char *fmt, va_list ap)
 {
-  return __nldbl___isoc99_vfscanf (stdin, fmt, ap);
+  return __vfscanf_internal (stdin, fmt, ap,
+			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_fscanf (FILE *stream, const char *fmt, ...)
+__nldbl___isoc99_fscanf (FILE *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_scanf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfscanf_internal (stdin, fmt, ap,
+			    SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __isoc99_vfwscanf (s, fmt, ap);
-  clear_no_long_double ();
-  return res;
+  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vfwscanf)
 
@@ -951,26 +938,28 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vswscanf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_vswscanf (const wchar_t *string, const wchar_t *fmt,
-			   va_list ap)
+__nldbl___isoc99_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __isoc99_vswscanf (string, fmt, ap);
-  __no_long_double = 0;
-  return res;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 libc_hidden_def (__nldbl___isoc99_vswscanf)
 
@@ -978,35 +967,37 @@ int
 attribute_compat_text_section
 __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl___isoc99_vfwscanf (stdin, fmt, ap);
+  return __vfwscanf_internal (stdin, fmt, ap,
+			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
 }
 
 int
 attribute_compat_text_section
-__nldbl___isoc99_fwscanf (FILE *stream, const wchar_t *fmt, ...)
+__nldbl___isoc99_fwscanf (FILE *s, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfwscanf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___isoc99_wscanf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfwscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwscanf_internal (stdin, fmt, ap,
+			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 4/7] Add __v*printf_internal with flags arguments
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-22 17:46   ` Adhemerval Zanella
  2018-11-22 17:55   ` Adhemerval Zanella
  2018-11-15 21:46 ` [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal " Gabriel F. T. Gomes
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changes since v2:

  - Expanded the comments about PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
  - Removed the parameter-less macros LDBL_IS_DBL and DO_FORTIFY.
    Explicitly compare the flags.

Changes since v1:

  - Fixed white-space errors.
  - In argp_fmtstream_printf, do not call __vsnprintf, instead call
    __vsnprintf_internal passing 0 to mode_flags.  With this change,
    there's no need to use libc_hidden_{proto,def} for __vsnprintf
    (because it doesn't have other internal callers).  Also, it is no
    longer necessary to '#undef __vsnprintf' and '#define __vsnprintf
    vsnprintf' in argp-namefrob.h.
  - In __argp_error and __argp_failure call __vasprintf_internal
    directly, passing 0 (zero) to mode_flags, since these functions do
    not currently have support for long double with the same format as
    double (a subsequent patch in my personal branch provides that and
    adjusts the call accordingly).
    With this change, there's no need to use libc_hidden_{proto,def} for
    __vasprintf.  It is also no longer required to '#undef __vasprintf'
    and '#define __vasprintf vasprintf' in argp-namefrob.h.
  - Declarations of _IO_vfprintf, _IO_vsprintf, __vfwprintf, and
    __vswprintf removed from the internal headers: libio.h, iolibio.h,
    and include/wchar.h, since they are no longer called from within
    glibc.
  - Added attribute_hidden to all new internal functions, since they are
    all called from within libc.
    Here are the objdumps of one such calls, before and after this
    change, on a 32-bits powerpc machine:
    Without attribute_hidden:
      $ objdump -d --reloc INTERNAL-VISIBLE-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 21
      000523a0 <vprintf@@GLIBC_2.4>:
         523a0:       94 21 ff f0     stwu    r1,-16(r1)
         523a4:       7c 85 23 78     mr      r5,r4
         523a8:       7c 08 02 a6     mflr    r0
         523ac:       42 9f 00 05     bcl     20,4*cr7+so,523b0 <vprintf@@GLIBC_2.4+0x10>
         523b0:       7c 64 1b 78     mr      r4,r3
         523b4:       38 c0 00 00     li      r6,0
         523b8:       93 c1 00 08     stw     r30,8(r1)
         523bc:       90 01 00 14     stw     r0,20(r1)
         523c0:       7f c8 02 a6     mflr    r30
         523c4:       3f de 00 15     addis   r30,r30,21
         523c8:       3b de dc 44     addi    r30,r30,-9148
         523cc:       81 3e fe 80     lwz     r9,-384(r30)
         523d0:       80 69 00 00     lwz     r3,0(r9)
         523d4:       48 01 52 bd     bl      67690 <__vfprintf_internal>
         523d8:       80 01 00 14     lwz     r0,20(r1)
         523dc:       83 c1 00 08     lwz     r30,8(r1)
         523e0:       38 21 00 10     addi    r1,r1,16
         523e4:       7c 08 03 a6     mtlr    r0
         523e8:       4e 80 00 20     blr
    With attribute_hidden:
      $ objdump -d --reloc INTERNAL-HIDDEN-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 18
      00052370 <vprintf@@GLIBC_2.4>:
         52370:       94 21 ff f0     stwu    r1,-16(r1)
         52374:       7c 85 23 78     mr      r5,r4
         52378:       7d 88 02 a6     mflr    r12
         5237c:       42 9f 00 05     bcl     20,4*cr7+so,52380 <vprintf@@GLIBC_2.4+0x10>
         52380:       7c 64 1b 78     mr      r4,r3
         52384:       38 c0 00 00     li      r6,0
         52388:       93 c1 00 08     stw     r30,8(r1)
         5238c:       7f c8 02 a6     mflr    r30
         52390:       7d 88 03 a6     mtlr    r12
         52394:       3f de 00 15     addis   r30,r30,21
         52398:       3b de dc 74     addi    r30,r30,-9100
         5239c:       81 3e fe 80     lwz     r9,-384(r30)
         523a0:       83 c1 00 08     lwz     r30,8(r1)
         523a4:       80 69 00 00     lwz     r3,0(r9)
         523a8:       38 21 00 10     addi    r1,r1,16
         523ac:       48 01 52 24     b       675d0 <__vfprintf_internal>
    The branch-and-link instruction is gone.

Additional note for review:

  - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
    original patch would be vey hard, because git doesn't detect the
    filename change.  To make review a little easier, I did as Zack did
    and manually edited the diff.  I'll reply to this thread and attach
    the original patch if someone wants to apply it.
    (ping me if I forget it)

-- 8< --
There are a lot more printf variants than there are scanf variants,
and the code for setting up and tearing down their custom FILE
variants around the call to __vf(w)printf is more complicated and
variable.  Therefore, I have added _internal versions of all the
v*printf variants, rather than introducing helper routines so that
they can all directly call __vf(w)printf_internal, as was done with
scanf.

As with the scanf changes, in this patch the _internal functions still
look at the environmental mode bits and all callers pass 0 for the
flags parameter.

Several of the affected public functions had _IO_ name aliases that
were not exported (but, in one case, appeared in libio.h anyway);
I was originally planning to leave them as aliases to avoid having
to touch internal callers, but it turns out ldbl_*_alias only work
for exported symbols, so they've all been removed instead.  It also
turns out there were hardly any internal callers.  _IO_vsprintf and
_IO_vfprintf *are* exported, so those two stick around.

Summary for the changes to each of the affected symbols:

  _IO_vfprintf, _IO_vsprintf:
    All internal calls removed, thus the internal declarations, as well
    as uses of libc_hidden_proto and libc_hidden_def, were also removed.
    The external symbol is now exposed via uses of ldbl_strong_alias
    to __vfprintf_internal and __vsprintf_internal, respectively.

  _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf,
  _IO_vfwprintf, _IO_vswprintf,
  _IO_obstack_vprintf, _IO_obstack_printf:
    All internal calls removed, thus declaration in internal headers
    were also removed.  They were never exported, so there are no
    aliases tying them to the internal functions.  I.e.: entirely gone.

  __vsnprintf:
    Internal calls were always preceded by macros such as
      #define __vsnprintf _IO_vsnprintf, and
      #define __vsnprintf vsnprintf
    The macros were removed and their uses replaced with calls to the
    new internal function __vsnprintf_internal.  Since there were no
    internal calls, the internal declaration was also removed.  The
    external symbol is preserved with ldbl_weak_alias to ___vsnprintf.

  __vfwprintf:
    All internal calls converted into calls to __vfwprintf_internal,
    thus the internal declaration was removed.  The function is now a
    wrapper that calls __vfwprintf_internal.  The external symbol is
    preserved.

  __vswprintf:
    Similarly, but no external symbol.

  __vasprintf, __vdprintf, __vfprintf, __vsprintf:
    New internal wrappers.  Not exported.

  vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf,
  vfwprintf, vswprintf,
  obstack_vprintf, obstack_printf:
    These functions used to be aliases to the respective _IO_* function,
    they are now aliases to their respective __* functions.

Tested for powerpc and powerpc64le.

2018-10-16  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* libio/libioP.h (__vfprintf_internal, __vfwprintf_internal)
	(__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal)
	(__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal):
	New functions.
	(PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants.
	(_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes.

	* stdio-common/vfprintf-internal.c: Rename from vfprintf.c.
	Include wctype.h here if COMPILE_WPRINTF is defined.
	Define __vfprintf_internal or __vfwprintf_internal, depending
	on COMPILE_WPRINTF.
	Temporarily, on entry to this function, update mode_flags
	according to the environmental settings corresponding to
	PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
	Throughout, check mode_flags instead of __ldbl_is_dbl and
	_IO_FLAGS2_FORTIFY on the destination FILE.
	* stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c.
	Include vfprintf-internal.c.  Don't include wctype.h.
	* stdio-common/vfprintf.c: New file.  Just define __vfprintf
	as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf
	and vfprintf.
	* stdio-common/vfwprintf.c: New file.  Just define __vfwprintf
	as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf
	and vfwprintf.
	* stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal.

	* libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal
	and add mode_flags argument; use __vfprintf_internal.
	(__vdprintf): New function.  Alias vdprintf to this.
	* libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly.
	* libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly.
	* libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly.
	(__obstack_printf): Use __obstack_printf_internal.
	* libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with
	public aliases __vsnprintf and vsnprintf.
	Remove use of ldbl_hidden_def, since __vsnprintf is no longer
	called internally.
	* libio/vswprintf (_IO_vswprintf, __vswprintf): Similarly, with
	public aliases _IO_vsprintf and vsprintf.
	* libio/swprintf.c (__swprintf): Use __vswprintf_internal.
	* stdio-common/asprintf.c (__asprintf): Use __vasprintf_internal.
	* stdio-common/dprintf.c (__dprintf): Use __vdprintf_internal.
	* stdio-common/snprintf.c (__snprintf): Use __vsprintf_internal.
	* stdio-common/sprintf.c (__sprintf): Use __vsprintf_internal.

	* debug/obprintf_chk.c, debug/vasprintf_chk.c, debug/vdprintf_chk.c
	* debug/vsnprintf_chk.c, debug/vsprintf_chk.c, hurd/vpprintf.c
	* stdio-common/fprintf.c, stdio-common/fxprintf.c
	* stdio-common/printf.c: Use __vfprintf_internal.

	* debug/fwprintf_chk.c, debug/vfwprintf_chk.c, debug/vswprintf_chk.c
	* debug/vwprintf_chk.c, debug/wprintf_chk.c, libio/fwprintf.c
	* libio/vwprintf.c, libio/wprintf.c: Use __vfwprintf_internal.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Use __vsprintf_internal,
	__obstack_vprintf_internal, __vasprintf_internal, __vdprintf_internal,
	__vsnprintf_internal, __vswprintf_internal, __vfprintf_internal, and
	__vfwprintf_internal.

	* libio/libio.h: Remove libc_hidden_proto and declaration for
	_IO_vfprintf.
	Remove declaration of _IO_vfwprintf.
	* libio/iolibio.h: Remove libc_hidden_proto and declaration for
	_IO_vsprintf.
	Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
	_IO_obstack_printf.
	* include/stdio.h: Add prototype for __vasprintf.
	(__vsnprintf): Remove declaration, because there are no more
	internal calls.
	* include/wchar.h (__vfwprintf, __vswprintf): Remove
	declaration, because there are no more internal calls.

	* argp/argp-fmtstream.c (__argp_fmtstream_printf): Use
	__vsnprintf_internal, instead of _IO_vsnprintf.
	* argp/argp-help.c (__argp_error, __argp_failure): Use
	__vasprintf_internal, instead of _IO_vasprintf.
	* argp/argp-namefrob.h (__vsnprintf): Do not undefined then
	redefine, because there are no more internal calls.
---
 argp/argp-fmtstream.c                            |    3 +-
 argp/argp-help.c                                 |    4 +-
 argp/argp-namefrob.h                             |    2 -
 debug/fwprintf_chk.c                             |    2 +-
 debug/obprintf_chk.c                             |    2 +-
 debug/vasprintf_chk.c                            |    2 +-
 debug/vdprintf_chk.c                             |    2 +-
 debug/vfwprintf_chk.c                            |    2 +-
 debug/vsnprintf_chk.c                            |    2 +-
 debug/vsprintf_chk.c                             |    2 +-
 debug/vswprintf_chk.c                            |    2 +-
 debug/vwprintf_chk.c                             |    2 +-
 debug/wprintf_chk.c                              |    2 +-
 hurd/vpprintf.c                                  |    2 +-
 include/stdio.h                                  |    3 -
 include/wchar.h                                  |   10 -
 libio/fwprintf.c                                 |    2 +-
 libio/iolibio.h                                  |    8 -
 libio/iovdprintf.c                               |   13 +-
 libio/iovsprintf.c                               |   16 +-
 libio/libio.h                                    |    5 -
 libio/libioP.h                                   |   47 +-
 libio/obprintf.c                                 |   19 +-
 libio/swprintf.c                                 |    2 +-
 libio/vasprintf.c                                |   20 +-
 libio/vsnprintf.c                                |   16 +-
 libio/vswprintf.c                                |   16 +-
 libio/vwprintf.c                                 |    2 +-
 libio/wprintf.c                                  |    2 +-
 stdio-common/Makefile                            |    3 +-
 stdio-common/asprintf.c                          |    6 +-
 stdio-common/dprintf.c                           |    5 +-
 stdio-common/fprintf.c                           |    2 +-
 stdio-common/fxprintf.c                          |    4 +-
 stdio-common/printf.c                            |    3 +-
 stdio-common/snprintf.c                          |    4 +-
 stdio-common/sprintf.c                           |    4 +-
 stdio-common/{vfprintf.c => vfprintf-internal.c} |   66 +-
 stdio-common/vfprintf.c                          | 2351 +---------------------
 stdio-common/vfwprintf-internal.c                |    2 +
 stdio-common/vfwprintf.c                         |   28 +-
 stdio-common/vprintf.c                           |    4 +-
 stdlib/strfrom-skeleton.c                        |    2 +-
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |   21 +-
 44 files changed, 219 insertions(+), 2498 deletions(-)
 copy stdio-common/{vfprintf.c => vfprintf-internal.c} (98%)
 create mode 100644 stdio-common/vfwprintf-internal.c

diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
index e43a0c7cf1..b9dcb2c9c7 100644
--- a/argp/argp-fmtstream.c
+++ b/argp/argp-fmtstream.c
@@ -42,7 +42,6 @@
 #ifdef _LIBC
 # include <wchar.h>
 # include <libio/libioP.h>
-# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 #endif
 
 #define INIT_BUF_SIZE 200
@@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
 
       va_start (args, fmt);
       avail = fs->end - fs->p;
-      out = __vsnprintf (fs->p, avail, fmt, args);
+      out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
       va_end (args);
       if ((size_t) out >= avail)
 	size_guess = out + 1;
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 2b6b0775d6..6857391ce2 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
 #ifdef _LIBC
 	  char *buf;
 
-	  if (_IO_vasprintf (&buf, fmt, ap) < 0)
+	  if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
 	    buf = NULL;
 
 	  __fxprintf (stream, "%s: %s\n",
@@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 #ifdef _LIBC
 	      char *buf;
 
-	      if (_IO_vasprintf (&buf, fmt, ap) < 0)
+	      if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
 		buf = NULL;
 
 	      __fxprintf (stream, ": %s", buf);
diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
index 5588fe172a..5e48b5940d 100644
--- a/argp/argp-namefrob.h
+++ b/argp/argp-namefrob.h
@@ -98,8 +98,6 @@
 #define __strerror_r strerror_r
 #undef __strndup
 #define __strndup strndup
-#undef __vsnprintf
-#define __vsnprintf vsnprintf
 
 #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
 # define clearerr_unlocked(x) clearerr (x)
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index aeb83077da..63167c1839 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
     fp->_flags2 |= _IO_FLAGS2_FORTIFY;
 
   va_start (ap, format);
-  done = _IO_vfwprintf (fp, format, ap);
+  done = __vfwprintf_internal (fp, format, ap, 0);
   va_end (ap);
 
   if (flag > 0)
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 3ac5a3cd4f..41dd481c34 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
   if (flags > 0)
     new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
 
   /* Shrink the buffer to the space we really currently need.  */
   obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index 48b4741651..dbfebff83f 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
   if (flags > 0)
     sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
   if (ret < 0)
     {
       free (sf._sbf._f._IO_buf_base);
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index bc713b4962..4386127cfe 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -55,7 +55,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg)
   if (flags > 0)
     tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfprintf (&tmpfil.file, format, arg);
+  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
 
   _IO_FINISH (&tmpfil.file);
 
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index 1ffd18cbd2..abf2bd6517 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -30,7 +30,7 @@ __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
   if (flag > 0)
     fp->_flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfwprintf (fp, format, ap);
+  done = __vfwprintf_internal (fp, format, ap, 0);
 
   if (flag > 0)
     fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index d20d0fbd93..95d286f416 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
     sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
   _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
-  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
 
   if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
     *sf.f._sbf._f._IO_write_ptr = '\0';
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 9a443bb699..53f07236ae 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -80,7 +80,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
   if (flags > 0)
     f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
-  ret = _IO_vfprintf (&f._sbf._f, format, args);
+  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
 
   *f._sbf._f._IO_write_ptr = '\0';
   return ret;
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index c6a7edcacd..4d616f8835 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
     sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
 
   _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
-  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
 
   if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
     /* ISO C99 requires swprintf/vswprintf to return an error if the
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index 51b67c159d..fedc7a46bf 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
   if (flag > 0)
     stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
 
-  done = _IO_vfwprintf (stdout, format, ap);
+  done = __vfwprintf_internal (stdout, format, ap, 0);
 
   if (flag > 0)
     stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 17023b6bb4..819050e5af 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -33,7 +33,7 @@ __wprintf_chk (int flag, const wchar_t *format, ...)
     stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
 
   va_start (ap, format);
-  done = _IO_vfwprintf (stdout, format, ap);
+  done = __vfwprintf_internal (stdout, format, ap, 0);
   va_end (ap);
 
   if (flag > 0)
diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c
index 76cd31f922..b9634afc2b 100644
--- a/hurd/vpprintf.c
+++ b/hurd/vpprintf.c
@@ -53,7 +53,7 @@ vpprintf (io_t port, const char *format, va_list arg)
   _IO_cookie_init (&temp_f.cfile, _IO_NO_READS,
 		   (void *) port, (cookie_io_functions_t) { write: do_write });
 
-  done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
+  done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0);
 
   return done;
 }
diff --git a/include/stdio.h b/include/stdio.h
index 51ada4a4c4..0856d729d9 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen,
 		       const char *__restrict __format, ...)
      __attribute__ ((__format__ (__printf__, 3, 4)));
 libc_hidden_proto (__snprintf)
-extern int __vsnprintf (char *__restrict __s, size_t __maxlen,
-			const char *__restrict __format, __gnuc_va_list __arg)
-     __attribute__ ((__format__ (__printf__, 3, 0)));
 extern int __vfscanf (FILE *__restrict __s,
 		      const char *__restrict __format,
 		      __gnuc_va_list __arg)
diff --git a/include/wchar.h b/include/wchar.h
index 1db0ac8278..d0fe45c3a6 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s,
 		       __gnuc_va_list __arg)
      attribute_hidden
      /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */;
-extern int __vswprintf (wchar_t *__restrict __s, size_t __n,
-			const wchar_t *__restrict __format,
-			__gnuc_va_list __arg)
-     attribute_hidden
-     /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
 extern int __fwprintf (__FILE *__restrict __s,
 		       const wchar_t *__restrict __format, ...)
      attribute_hidden
      /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
-extern int __vfwprintf (__FILE *__restrict __s,
-			const wchar_t *__restrict __format,
-			__gnuc_va_list __arg)
-     attribute_hidden
-     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
 extern int __vfwprintf_chk (FILE *__restrict __s, int __flag,
 			    const wchar_t *__restrict __format,
 			    __gnuc_va_list __arg)
diff --git a/libio/fwprintf.c b/libio/fwprintf.c
index fab63a8716..9903f1f342 100644
--- a/libio/fwprintf.c
+++ b/libio/fwprintf.c
@@ -30,7 +30,7 @@ __fwprintf (FILE *stream, const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vfwprintf (stream, format, arg);
+  done = __vfwprintf_internal (stream, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/iolibio.h b/libio/iolibio.h
index 6c94fe6d62..2642d71e4f 100644
--- a/libio/iolibio.h
+++ b/libio/iolibio.h
@@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
 extern int _IO_sprintf (char *, const char*, ...) __THROW;
 extern int _IO_ungetc (int, FILE*) __THROW;
 extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW;
-extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW;
-libc_hidden_proto (_IO_vsprintf)
-extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list)
-       __THROW;
 
-struct obstack;
-extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list)
-       __THROW;
-extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW;
 #define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN))
 #define _IO_fseek(__fp, __offset, __whence) \
   (_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \
diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
index 78a3a2bd15..1d2ed0f9e7 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -28,7 +28,8 @@
 #include <stdio_ext.h>
 
 int
-_IO_vdprintf (int d, const char *format, va_list arg)
+__vdprintf_internal (int d, const char *format, va_list arg,
+		     unsigned int mode_flags)
 {
   struct _IO_FILE_plus tmpfil;
   struct _IO_wide_data wd;
@@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg)
   _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
 		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
 
-  done = _IO_vfprintf (&tmpfil.file, format, arg);
+  done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags);
 
   if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
     done = EOF;
@@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg)
 
   return done;
 }
-ldbl_weak_alias (_IO_vdprintf, vdprintf)
+
+int
+__vdprintf (int d, const char *format, va_list arg)
+{
+  return __vdprintf_internal (d, format, arg, 0);
+}
+ldbl_weak_alias (__vdprintf, vdprintf)
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 4def251701..3b1e8292b5 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -28,7 +28,8 @@
 #include "strfile.h"
 
 int
-__IO_vsprintf (char *string, const char *format, va_list args)
+__vsprintf_internal (char *string, const char *format, va_list args,
+		     unsigned int mode_flags)
 {
   _IO_strfile sf;
   int ret;
@@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args)
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
   _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
   _IO_str_init_static_internal (&sf, string, -1, string);
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
   _IO_putc_unlocked ('\0', &sf._sbf._f);
   return ret;
 }
-ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)
 
-ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
-ldbl_weak_alias (__IO_vsprintf, vsprintf)
+int
+__vsprintf (char *string, const char *format, va_list args)
+{
+  return __vsprintf_internal (string, format, args, 0);
+}
+
+ldbl_strong_alias (__vsprintf, _IO_vsprintf)
+ldbl_weak_alias (__vsprintf, vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index 30cb7d784f..c188814ccc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;
 
 extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
 			__gnuc_va_list, int *__restrict);
-extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
-			 __gnuc_va_list);
 extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
 extern size_t _IO_sgetn (FILE *, void *, size_t);
 
@@ -298,8 +296,6 @@ weak_extern (_IO_stdin_used);
 
 extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
 			 __gnuc_va_list, int *__restrict);
-extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
-			  __gnuc_va_list);
 extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t);
 extern void _IO_free_wbackup_area (FILE *) __THROW;
 
@@ -319,7 +315,6 @@ libc_hidden_proto (_IO_free_wbackup_area)
 libc_hidden_proto (_IO_padn)
 libc_hidden_proto (_IO_putc)
 libc_hidden_proto (_IO_sgetn)
-libc_hidden_proto (_IO_vfprintf)
 
 #ifdef _IO_MTSAFE_IO
 # undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index 9e971cb96b..fe52ef1752 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,49 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
 extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
 extern void _IO_wstr_finish (FILE *, int) __THROW;
 
-extern int _IO_vasprintf (char **result_ptr, const char *format,
-			  va_list args) __THROW;
-extern int _IO_vdprintf (int d, const char *format, va_list arg);
-extern int _IO_vsnprintf (char *string, size_t maxlen,
-			  const char *format, va_list args) __THROW;
+/* Internal versions of v*printf that take an additional flags
+   parameter.  */
+extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
+				unsigned int mode_flags)
+    attribute_hidden;
+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
+				 unsigned int mode_flags)
+    attribute_hidden;
+
+extern int __vasprintf_internal (char **result_ptr, const char *format,
+				 va_list ap, unsigned int mode_flags)
+    attribute_hidden;
+extern int __vdprintf_internal (int d, const char *format, va_list ap,
+				unsigned int mode_flags)
+    attribute_hidden;
+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
+				       va_list ap, unsigned int mode_flags)
+    attribute_hidden;
+
+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+				unsigned int mode_flags)
+    attribute_hidden;
+extern int __vsnprintf_internal (char *string, size_t maxlen,
+				 const char *format, va_list ap,
+				 unsigned int mode_flags)
+    attribute_hidden;
+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
+				 const wchar_t *format, va_list ap,
+				 unsigned int mode_flags)
+    attribute_hidden;
+
+/* Flags for __v*printf_internal.
+
+   PRINTF_LDBL_IS_DBL indicates whether long double values are to be
+   handled as having the same format as double, in which case the flag
+   should be set to one, or as another format, otherwise.
 
+   PRINTF_FORTIFY, when set to one, indicates that fortification checks
+   are to be performed in input parameters.  This is used by the
+   __*printf_chk functions, which are used when _FORTIFY_SOURCE is
+   defined to 1 or 2.  Otherwise, such checks are ignored.  */
+#define PRINTF_LDBL_IS_DBL 0x0001
+#define PRINTF_FORTIFY     0x0002
 
 extern size_t _IO_getline (FILE *,char *, size_t, int, int);
 libc_hidden_proto (_IO_getline)
diff --git a/libio/obprintf.c b/libio/obprintf.c
index a74f9467a2..10a4b5c10c 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
+__obstack_vprintf_internal (struct obstack *obstack, const char *format,
+			    va_list args, unsigned int mode_flags)
 {
   struct obstack_FILE
     {
@@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 
   new_f.ofile.obstack = obstack;
 
-  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+  result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
+				mode_flags);
 
   /* Shrink the buffer to the space we really currently need.  */
   obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
@@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 
   return result;
 }
-ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf)
 
+int
+__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap)
+{
+  return __obstack_vprintf_internal (obstack, format, ap, 0);
+}
+ldbl_weak_alias (__obstack_vprintf, obstack_vprintf)
 
 int
-_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
+__obstack_printf (struct obstack *obstack, const char *format, ...)
 {
   int result;
   va_list ap;
   va_start (ap, format);
-  result = _IO_obstack_vprintf (obstack, format, ap);
+  result = __obstack_vprintf_internal (obstack, format, ap, 0);
   va_end (ap);
   return result;
 }
-ldbl_weak_alias (_IO_obstack_printf, obstack_printf)
+ldbl_weak_alias (__obstack_printf, obstack_printf)
diff --git a/libio/swprintf.c b/libio/swprintf.c
index 10f722d035..19b3f33198 100644
--- a/libio/swprintf.c
+++ b/libio/swprintf.c
@@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vswprintf (s, n, format, arg);
+  done = __vswprintf_internal (s, n, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
index 6c35d2b108..fabd84f403 100644
--- a/libio/vasprintf.c
+++ b/libio/vasprintf.c
@@ -24,15 +24,13 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <malloc.h>
 #include <string.h>
-#include "libioP.h"
-#include "stdio.h"
-#include <stdio_ext.h>
-#include "strfile.h"
+#include <stdlib.h>
+#include <strfile.h>
 
 int
-_IO_vasprintf (char **result_ptr, const char *format, va_list args)
+__vasprintf_internal (char **result_ptr, const char *format, va_list args,
+		      unsigned int mode_flags)
 {
   /* Initial size of the buffer to be used.  Will be doubled each time an
      overflow occurs.  */
@@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
   sf._s._free_buffer_unused = (_IO_free_type) free;
-  ret = _IO_vfprintf (&sf._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
   if (ret < 0)
     {
       free (sf._sbf._f._IO_buf_base);
@@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
   (*result_ptr)[needed - 1] = '\0';
   return ret;
 }
-ldbl_weak_alias (_IO_vasprintf, vasprintf)
+
+int
+__vasprintf (char **result_ptr, const char *format, va_list args)
+{
+  return __vasprintf_internal (result_ptr, format, args, 0);
+}
+ldbl_weak_alias (__vasprintf, vasprintf)
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index 39b5500528..35b267abf8 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_vsnprintf (char *string, size_t maxlen, const char *format,
-	       va_list args)
+__vsnprintf_internal (char *string, size_t maxlen, const char *format,
+		      va_list args, unsigned int mode_flags)
 {
   _IO_strnfile sf;
   int ret;
@@ -111,11 +111,17 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format,
   _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
   string[0] = '\0';
   _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
-  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);
 
   if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
     *sf.f._sbf._f._IO_write_ptr = '\0';
   return ret;
 }
-ldbl_weak_alias (_IO_vsnprintf, __vsnprintf)
-ldbl_weak_alias (_IO_vsnprintf, vsnprintf)
+
+int
+___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
+{
+  return __vsnprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (___vsnprintf, __vsnprintf)
+ldbl_weak_alias (___vsnprintf, vsnprintf)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index bcc473d115..e415e39fc9 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
 
 
 int
-_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
-	       va_list args)
+__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
+		      va_list args, unsigned int mode_flags)
 {
   _IO_wstrnfile sf;
   int ret;
@@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
   _IO_fwide (&sf.f._sbf._f, 1);
   string[0] = L'\0';
   _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
-  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);
 
   if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
     /* ISO C99 requires swprintf/vswprintf to return an error if the
@@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
 
   return ret;
 }
-weak_alias (_IO_vswprintf, __vswprintf)
-ldbl_weak_alias (_IO_vswprintf, vswprintf)
+
+int
+__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
+	     va_list args)
+{
+  return __vswprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (__vswprintf, vswprintf)
diff --git a/libio/vwprintf.c b/libio/vwprintf.c
index 72ebfec92d..e8a529afff 100644
--- a/libio/vwprintf.c
+++ b/libio/vwprintf.c
@@ -25,6 +25,6 @@
 int
 __vwprintf (const wchar_t *format, __gnuc_va_list arg)
 {
-  return __vfwprintf (stdout, format, arg);
+  return __vfwprintf_internal (stdout, format, arg, 0);
 }
 ldbl_strong_alias (__vwprintf, vwprintf)
diff --git a/libio/wprintf.c b/libio/wprintf.c
index 5945f651fc..361cd40a1b 100644
--- a/libio/wprintf.c
+++ b/libio/wprintf.c
@@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vfwprintf (stdout, format, arg);
+  done = __vfwprintf_internal (stdout, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index f3b3ceddbd..84bad1fafe 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -40,7 +40,8 @@ routines	:=							      \
 	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
 	isoc99_vsscanf							      \
 	psiginfo gentempfd						      \
-	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
+	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf		      \
+	vfprintf-internal vfwprintf-internal
 
 aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
 
diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
index bff858e657..8943ffcae1 100644
--- a/stdio-common/asprintf.c
+++ b/stdio-common/asprintf.c
@@ -16,11 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-
 #include <libioP.h>
-#define vasprintf(s, f, a) _IO_vasprintf (s, f, a)
-#undef __asprintf
 
 /* Write formatted output from FORMAT to a string which is
    allocated with malloc and stored in *STRING_PTR.  */
@@ -32,7 +28,7 @@ ___asprintf (char **string_ptr, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vasprintf (string_ptr, format, arg);
+  done = __vasprintf_internal (string_ptr, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
index 11bd12b838..9adc8ae4c7 100644
--- a/stdio-common/dprintf.c
+++ b/stdio-common/dprintf.c
@@ -16,10 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-
 #include <libioP.h>
-#define vdprintf(d, f, a) _IO_vdprintf (d, f, a)
 
 /* Write formatted output to D, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vdprintf (d, format, arg);
+  done = __vdprintf_internal (d, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c
index 2bbf14bf5d..c8f8ac4faf 100644
--- a/stdio-common/fprintf.c
+++ b/stdio-common/fprintf.c
@@ -29,7 +29,7 @@ __fprintf (FILE *stream, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vfprintf (stream, format, arg);
+  done = __vfprintf_internal (stream, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
index 8d02b71f91..a028e8edd5 100644
--- a/stdio-common/fxprintf.c
+++ b/stdio-common/fxprintf.c
@@ -27,7 +27,7 @@ static int
 locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
 {
   if (_IO_fwide (fp, 0) <= 0)
-    return _IO_vfprintf (fp, fmt, ap);
+    return __vfprintf_internal (fp, fmt, ap, 0);
 
   /* We must convert the narrow format string to a wide one.
      Each byte can produce at most one wide character.  */
@@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
   res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
 
   if (res != -1)
-    res = _IO_vfwprintf (fp, wfmt, ap);
+    res = __vfwprintf_internal (fp, wfmt, ap, 0);
 
   if (used_malloc)
     free (wfmt);
diff --git a/stdio-common/printf.c b/stdio-common/printf.c
index 205b5e42df..ea41dd557c 100644
--- a/stdio-common/printf.c
+++ b/stdio-common/printf.c
@@ -30,7 +30,7 @@ __printf (const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vfprintf (stdout, format, arg);
+  done = __vfprintf_internal (stdout, format, arg, 0);
   va_end (arg);
 
   return done;
@@ -38,5 +38,4 @@ __printf (const char *format, ...)
 
 #undef _IO_printf
 ldbl_strong_alias (__printf, printf);
-/* This is for libg++.  */
 ldbl_strong_alias (__printf, _IO_printf);
diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
index 29a169b08b..b75e160ea3 100644
--- a/stdio-common/snprintf.c
+++ b/stdio-common/snprintf.c
@@ -16,9 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
-#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
@@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vsnprintf (s, maxlen, format, arg);
+  done = __vsnprintf_internal (s, maxlen, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index bf5671dde9..77423b292f 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -16,9 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
 #include <libioP.h>
-#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
 
 /* Write formatted output into S, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = vsprintf (s, format, arg);
+  done = __vsprintf_internal (s, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf-internal.c
similarity index 98%
copy from stdio-common/vfprintf.c
copy to stdio-common/vfprintf-internal.c
index ae412e4b84..b0c86e99bd 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf-internal.c
@@ -41,6 +41,10 @@
 
 #include <libioP.h>
 
+#ifdef COMPILE_WPRINTF
+#include <wctype.h>
+#endif
+
 /* In some cases we need extra space for all the output which is not
    counted in the width of the string. We assume 32 characters is
    enough.  */
@@ -78,7 +82,7 @@
   } while (0)
 
 #ifndef COMPILE_WPRINTF
-# define vfprintf	_IO_vfprintf_internal
+# define vfprintf	__vfprintf_internal
 # define CHAR_T		char
 # define UCHAR_T	unsigned char
 # define INT_T		int
@@ -105,7 +109,7 @@ typedef const char *THOUSANDS_SEP_T;
 # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
 			  return -1
 #else
-# define vfprintf	_IO_vfwprintf
+# define vfprintf	__vfwprintf_internal
 # define CHAR_T		wchar_t
 /* This is a hack!!!  There should be a type uwchar_t.  */
 # define UCHAR_T	unsigned int /* uwchar_t */
@@ -747,7 +751,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -778,7 +782,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
 	      {								      \
 		fspec->data_arg_type = PA_DOUBLE;			      \
 		fspec->info.is_long_double = 0;				      \
@@ -808,7 +812,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -838,7 +842,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
 	      fspec->info.is_long_double = 0;				      \
 	    /* Not supported by *printf functions.  */			      \
 	    fspec->info.is_binary128 = 0;				      \
@@ -891,7 +895,7 @@ static const uint8_t jump_table[] =
       /* NOTREACHED */							      \
 									      \
     LABEL (form_number):						      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
+      if ((mode_flags & PRINTF_FORTIFY) != 0)				      \
 	{								      \
 	  if (! readonly_format)					      \
 	    {								      \
@@ -1214,7 +1218,8 @@ static const uint8_t jump_table[] =
 #endif
 
 /* Helper function to provide temporary buffering for unbuffered streams.  */
-static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
+static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
+			      unsigned int)
      __THROW __attribute__ ((noinline));
 
 /* Handle positional format specifiers.  */
@@ -1223,7 +1228,9 @@ static int printf_positional (FILE *s,
 			      va_list ap, va_list *ap_savep, int done,
 			      int nspecs_done, const UCHAR_T *lead_str_end,
 			      CHAR_T *work_buffer, int save_errno,
-			      const char *grouping, THOUSANDS_SEP_T);
+			      const char *grouping,
+			      THOUSANDS_SEP_T thousands_sep,
+			      unsigned int mode_flags);
 
 /* Handle unknown format specifier.  */
 static int printf_unknown (FILE *, const struct printf_info *,
@@ -1235,7 +1242,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
 
 /* The function itself.  */
 int
-vfprintf (FILE *s, const CHAR_T *format, va_list ap)
+vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
 {
   /* The character used as thousands separator.  */
   THOUSANDS_SEP_T thousands_sep = 0;
@@ -1273,6 +1280,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
      0 if unknown.  */
   int readonly_format = 0;
 
+  /* Temporarily honor environmental settings.  */
+  if (__ldbl_is_dbl)
+    mode_flags |= PRINTF_LDBL_IS_DBL;
+  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
+    mode_flags |= PRINTF_FORTIFY;
+
   /* Orient the stream.  */
 #ifdef ORIENT
   ORIENT;
@@ -1293,7 +1306,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   if (UNBUFFERED_P (s))
     /* Use a helper function which will allocate a local temporary buffer
        for the stream and then call us again.  */
-    return buffered_vfprintf (s, format, ap);
+    return buffered_vfprintf (s, format, ap, mode_flags);
 
   /* Initialize local variables.  */
   done = 0;
@@ -1682,7 +1695,7 @@ do_positional:
     }
   done = printf_positional (s, format, readonly_format, ap, &ap_save,
 			    done, nspecs_done, lead_str_end, work_buffer,
-			    save_errno, grouping, thousands_sep);
+			    save_errno, grouping, thousands_sep, mode_flags);
 
  all_done:
   if (__glibc_unlikely (workstart != NULL))
@@ -1699,7 +1712,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
 		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
 		   const UCHAR_T *lead_str_end,
 		   CHAR_T *work_buffer, int save_errno,
-		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
+		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
+		   unsigned int mode_flags)
 {
   /* For positional argument handling.  */
   struct scratch_buffer specsbuf;
@@ -1789,7 +1803,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
        now.  */
     args_size = &args_value[nargs].pa_int;
     args_type = &args_size[nargs];
-    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
+    memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
 	    nargs * sizeof (*args_type));
   }
 
@@ -1856,7 +1870,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
       case PA_FLOAT:				/* Promoted.  */
 	T (PA_DOUBLE, pa_double, double);
       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
-	if (__ldbl_is_dbl)
+	if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
 	  {
 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
@@ -1884,7 +1898,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
       case -1:
 	/* Error case.  Not all parameters appear in N$ format
 	   strings.  We have no way to determine their type.  */
-	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
+	assert ((mode_flags & PRINTF_FORTIFY) != 0);
 	__libc_fatal ("*** invalid %N$ use detected ***\n");
       }
 
@@ -2285,7 +2299,8 @@ static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
 #endif
 
 static int
-buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
+buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
+		   unsigned int mode_flags)
 {
   CHAR_T buf[BUFSIZ];
   struct helper_file helper;
@@ -2318,11 +2333,7 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
 
   /* Now print to helper instead.  */
-#ifndef COMPILE_WPRINTF
-  result = _IO_vfprintf (hp, format, args);
-#else
-  result = vfprintf (hp, format, args);
-#endif
+  result = vfprintf (hp, format, args, mode_flags);
 
   /* Lock stream.  */
   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
@@ -2351,14 +2362,3 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
 
   return result;
 }
-
-#undef vfprintf
-#ifdef COMPILE_WPRINTF
-strong_alias (_IO_vfwprintf, __vfwprintf);
-ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
-#else
-ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
-ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
-#endif
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index ae412e4b84..13a10db99b 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -15,2350 +15,13 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <array_length.h>
-#include <ctype.h>
-#include <limits.h>
-#include <printf.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <wchar.h>
-#include <libc-lock.h>
-#include <sys/param.h>
-#include <_itoa.h>
-#include <locale/localeinfo.h>
-#include <stdio.h>
-#include <scratch_buffer.h>
+#include <libio/libioP.h>
 
-/* This code is shared between the standard stdio implementation found
-   in GNU C library and the libio implementation originally found in
-   GNU libg++.
-
-   Beside this it is also shared between the normal and wide character
-   implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
-
-#include <libioP.h>
-
-/* In some cases we need extra space for all the output which is not
-   counted in the width of the string. We assume 32 characters is
-   enough.  */
-#define EXTSIZ		32
-#define ARGCHECK(S, Format) \
-  do									      \
-    {									      \
-      /* Check file argument for consistence.  */			      \
-      CHECK_FILE (S, -1);						      \
-      if (S->_flags & _IO_NO_WRITES)					      \
-	{								      \
-	  S->_flags |= _IO_ERR_SEEN;					      \
-	  __set_errno (EBADF);						      \
-	  return -1;							      \
-	}								      \
-      if (Format == NULL)						      \
-	{								      \
-	  __set_errno (EINVAL);						      \
-	  return -1;							      \
-	}								      \
-    } while (0)
-#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
-
-#define done_add(val) \
-  do {									      \
-    unsigned int _val = val;						      \
-    assert ((unsigned int) done < (unsigned int) INT_MAX);		      \
-    if (__glibc_unlikely (INT_MAX - done < _val))			      \
-      {									      \
-	done = -1;							      \
-	 __set_errno (EOVERFLOW);					      \
-	goto all_done;							      \
-      }									      \
-    done += _val;							      \
-  } while (0)
-
-#ifndef COMPILE_WPRINTF
-# define vfprintf	_IO_vfprintf_internal
-# define CHAR_T		char
-# define UCHAR_T	unsigned char
-# define INT_T		int
-typedef const char *THOUSANDS_SEP_T;
-# define L_(Str)	Str
-# define ISDIGIT(Ch)	((unsigned int) ((Ch) - '0') < 10)
-# define STR_LEN(Str)	strlen (Str)
-
-# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
-# define PAD(Padchar) \
-  do {									      \
-    if (width > 0)							      \
-      {									      \
-	ssize_t written = _IO_padn (s, (Padchar), width);		      \
-	if (__glibc_unlikely (written != width))			      \
-	  {								      \
-	    done = -1;							      \
-	    goto all_done;						      \
-	  }								      \
-	done_add (written);						      \
-      }									      \
-  } while (0)
-# define PUTC(C, F)	_IO_putc_unlocked (C, F)
-# define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
-			  return -1
-#else
-# define vfprintf	_IO_vfwprintf
-# define CHAR_T		wchar_t
-/* This is a hack!!!  There should be a type uwchar_t.  */
-# define UCHAR_T	unsigned int /* uwchar_t */
-# define INT_T		wint_t
-typedef wchar_t THOUSANDS_SEP_T;
-# define L_(Str)	L##Str
-# define ISDIGIT(Ch)	((unsigned int) ((Ch) - L'0') < 10)
-# define STR_LEN(Str)	__wcslen (Str)
-
-# include <_itowa.h>
-
-# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
-# define PAD(Padchar) \
-  do {									      \
-    if (width > 0)							      \
-      {									      \
-	ssize_t written = _IO_wpadn (s, (Padchar), width);		      \
-	if (__glibc_unlikely (written != width))			      \
-	  {								      \
-	    done = -1;							      \
-	    goto all_done;						      \
-	  }								      \
-	done_add (written);						      \
-      }									      \
-  } while (0)
-# define PUTC(C, F)	_IO_putwc_unlocked (C, F)
-# define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
-
-# undef _itoa
-# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
-# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
-# undef EOF
-# define EOF WEOF
-#endif
-
-#include "_i18n_number.h"
-
-/* Include the shared code for parsing the format string.  */
-#include "printf-parse.h"
-
-
-#define	outchar(Ch)							      \
-  do									      \
-    {									      \
-      const INT_T outc = (Ch);						      \
-      if (PUTC (outc, s) == EOF || done == INT_MAX)			      \
-	{								      \
-	  done = -1;							      \
-	  goto all_done;						      \
-	}								      \
-      ++done;								      \
-    }									      \
-  while (0)
-
-#define outstring(String, Len)						      \
-  do									      \
-    {									      \
-      assert ((size_t) done <= (size_t) INT_MAX);			      \
-      if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))		      \
-	{								      \
-	  done = -1;							      \
-	  goto all_done;						      \
-	}								      \
-      if (__glibc_unlikely (INT_MAX - done < (Len)))			      \
-      {									      \
-	done = -1;							      \
-	 __set_errno (EOVERFLOW);					      \
-	goto all_done;							      \
-      }									      \
-      done += (Len);							      \
-    }									      \
-  while (0)
-
-/* For handling long_double and longlong we use the same flag.  If
-   `long' and `long long' are effectively the same type define it to
-   zero.  */
-#if LONG_MAX == LONG_LONG_MAX
-# define is_longlong 0
-#else
-# define is_longlong is_long_double
-#endif
-
-/* If `long' and `int' is effectively the same type we don't have to
-   handle `long separately.  */
-#if INT_MAX == LONG_MAX
-# define is_long_num	0
-#else
-# define is_long_num	is_long
-#endif
-
-
-/* Global constants.  */
-static const CHAR_T null[] = L_("(null)");
-
-/* Size of the work_buffer variable (in characters, not bytes.  */
-enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
-
-/* This table maps a character into a number representing a class.  In
-   each step there is a destination label for each class.  */
-static const uint8_t jump_table[] =
-  {
-    /* ' ' */  1,            0,            0, /* '#' */  4,
-	       0, /* '%' */ 14,            0, /* '\''*/  6,
-	       0,            0, /* '*' */  7, /* '+' */  2,
-	       0, /* '-' */  3, /* '.' */  9,            0,
-    /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
-    /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
-    /* '8' */  8, /* '9' */  8,            0,            0,
-	       0,            0,            0,            0,
-	       0, /* 'A' */ 26,            0, /* 'C' */ 25,
-	       0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
-	       0, /* 'I' */ 29,            0,            0,
-    /* 'L' */ 12,            0,            0,            0,
-	       0,            0,            0, /* 'S' */ 21,
-	       0,            0,            0,            0,
-    /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
-	       0,            0,            0,            0,
-	       0, /* 'a' */ 26,            0, /* 'c' */ 20,
-    /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
-    /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
-    /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
-    /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
-    /* 't' */ 27, /* 'u' */ 16,            0,            0,
-    /* 'x' */ 18,            0, /* 'z' */ 13
-  };
-
-#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
-#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
-#define LABEL(Name) do_##Name
-#ifdef SHARED
-  /* 'int' is enough and it saves some space on 64 bit systems.  */
-# define JUMP_TABLE_TYPE const int
-# define JUMP_TABLE_BASE_LABEL do_form_unknown
-# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
-# define JUMP(ChExpr, table)						      \
-      do								      \
-	{								      \
-	  int offset;							      \
-	  void *ptr;							      \
-	  spec = (ChExpr);						      \
-	  offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)	      \
-	    : table[CHAR_CLASS (spec)];					      \
-	  ptr = &&JUMP_TABLE_BASE_LABEL + offset;			      \
-	  goto *ptr;							      \
-	}								      \
-      while (0)
-#else
-# define JUMP_TABLE_TYPE const void *const
-# define REF(Name) &&do_##Name
-# define JUMP(ChExpr, table)						      \
-      do								      \
-	{								      \
-	  const void *ptr;						      \
-	  spec = (ChExpr);						      \
-	  ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)		      \
-	    : table[CHAR_CLASS (spec)];					      \
-	  goto *ptr;							      \
-	}								      \
-      while (0)
-#endif
-
-#define STEP0_3_TABLE							      \
-    /* Step 0: at the beginning.  */					      \
-    static JUMP_TABLE_TYPE step0_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (flag_space),		/* for ' ' */				      \
-      REF (flag_plus),		/* for '+' */				      \
-      REF (flag_minus),		/* for '-' */				      \
-      REF (flag_hash),		/* for '<hash>' */			      \
-      REF (flag_zero),		/* for '0' */				      \
-      REF (flag_quote),		/* for '\'' */				      \
-      REF (width_asterics),	/* for '*' */				      \
-      REF (width),		/* for '1'...'9' */			      \
-      REF (precision),		/* for '.' */				      \
-      REF (mod_half),		/* for 'h' */				      \
-      REF (mod_long),		/* for 'l' */				      \
-      REF (mod_longlong),	/* for 'L', 'q' */			      \
-      REF (mod_size_t),		/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_character),	/* for 'c' */				      \
-      REF (form_string),	/* for 's', 'S' */			      \
-      REF (form_pointer),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_strerror),	/* for 'm' */				      \
-      REF (form_wcharacter),	/* for 'C' */				      \
-      REF (form_floathex),	/* for 'A', 'a' */			      \
-      REF (mod_ptrdiff_t),      /* for 't' */				      \
-      REF (mod_intmax_t),       /* for 'j' */				      \
-      REF (flag_i18n),		/* for 'I' */				      \
-    };									      \
-    /* Step 1: after processing width.  */				      \
-    static JUMP_TABLE_TYPE step1_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (form_unknown),	/* for ' ' */				      \
-      REF (form_unknown),	/* for '+' */				      \
-      REF (form_unknown),	/* for '-' */				      \
-      REF (form_unknown),	/* for '<hash>' */			      \
-      REF (form_unknown),	/* for '0' */				      \
-      REF (form_unknown),	/* for '\'' */				      \
-      REF (form_unknown),	/* for '*' */				      \
-      REF (form_unknown),	/* for '1'...'9' */			      \
-      REF (precision),		/* for '.' */				      \
-      REF (mod_half),		/* for 'h' */				      \
-      REF (mod_long),		/* for 'l' */				      \
-      REF (mod_longlong),	/* for 'L', 'q' */			      \
-      REF (mod_size_t),		/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_character),	/* for 'c' */				      \
-      REF (form_string),	/* for 's', 'S' */			      \
-      REF (form_pointer),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_strerror),	/* for 'm' */				      \
-      REF (form_wcharacter),	/* for 'C' */				      \
-      REF (form_floathex),	/* for 'A', 'a' */			      \
-      REF (mod_ptrdiff_t),      /* for 't' */				      \
-      REF (mod_intmax_t),       /* for 'j' */				      \
-      REF (form_unknown)        /* for 'I' */				      \
-    };									      \
-    /* Step 2: after processing precision.  */				      \
-    static JUMP_TABLE_TYPE step2_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (form_unknown),	/* for ' ' */				      \
-      REF (form_unknown),	/* for '+' */				      \
-      REF (form_unknown),	/* for '-' */				      \
-      REF (form_unknown),	/* for '<hash>' */			      \
-      REF (form_unknown),	/* for '0' */				      \
-      REF (form_unknown),	/* for '\'' */				      \
-      REF (form_unknown),	/* for '*' */				      \
-      REF (form_unknown),	/* for '1'...'9' */			      \
-      REF (form_unknown),	/* for '.' */				      \
-      REF (mod_half),		/* for 'h' */				      \
-      REF (mod_long),		/* for 'l' */				      \
-      REF (mod_longlong),	/* for 'L', 'q' */			      \
-      REF (mod_size_t),		/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_character),	/* for 'c' */				      \
-      REF (form_string),	/* for 's', 'S' */			      \
-      REF (form_pointer),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_strerror),	/* for 'm' */				      \
-      REF (form_wcharacter),	/* for 'C' */				      \
-      REF (form_floathex),	/* for 'A', 'a' */			      \
-      REF (mod_ptrdiff_t),      /* for 't' */				      \
-      REF (mod_intmax_t),       /* for 'j' */				      \
-      REF (form_unknown)        /* for 'I' */				      \
-    };									      \
-    /* Step 3a: after processing first 'h' modifier.  */		      \
-    static JUMP_TABLE_TYPE step3a_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (form_unknown),	/* for ' ' */				      \
-      REF (form_unknown),	/* for '+' */				      \
-      REF (form_unknown),	/* for '-' */				      \
-      REF (form_unknown),	/* for '<hash>' */			      \
-      REF (form_unknown),	/* for '0' */				      \
-      REF (form_unknown),	/* for '\'' */				      \
-      REF (form_unknown),	/* for '*' */				      \
-      REF (form_unknown),	/* for '1'...'9' */			      \
-      REF (form_unknown),	/* for '.' */				      \
-      REF (mod_halfhalf),	/* for 'h' */				      \
-      REF (form_unknown),	/* for 'l' */				      \
-      REF (form_unknown),	/* for 'L', 'q' */			      \
-      REF (form_unknown),	/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_unknown),	/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_unknown),	/* for 'c' */				      \
-      REF (form_unknown),	/* for 's', 'S' */			      \
-      REF (form_unknown),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_unknown),	/* for 'm' */				      \
-      REF (form_unknown),	/* for 'C' */				      \
-      REF (form_unknown),	/* for 'A', 'a' */			      \
-      REF (form_unknown),       /* for 't' */				      \
-      REF (form_unknown),       /* for 'j' */				      \
-      REF (form_unknown)        /* for 'I' */				      \
-    };									      \
-    /* Step 3b: after processing first 'l' modifier.  */		      \
-    static JUMP_TABLE_TYPE step3b_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (form_unknown),	/* for ' ' */				      \
-      REF (form_unknown),	/* for '+' */				      \
-      REF (form_unknown),	/* for '-' */				      \
-      REF (form_unknown),	/* for '<hash>' */			      \
-      REF (form_unknown),	/* for '0' */				      \
-      REF (form_unknown),	/* for '\'' */				      \
-      REF (form_unknown),	/* for '*' */				      \
-      REF (form_unknown),	/* for '1'...'9' */			      \
-      REF (form_unknown),	/* for '.' */				      \
-      REF (form_unknown),	/* for 'h' */				      \
-      REF (mod_longlong),	/* for 'l' */				      \
-      REF (form_unknown),	/* for 'L', 'q' */			      \
-      REF (form_unknown),	/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_character),	/* for 'c' */				      \
-      REF (form_string),	/* for 's', 'S' */			      \
-      REF (form_pointer),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_strerror),	/* for 'm' */				      \
-      REF (form_wcharacter),	/* for 'C' */				      \
-      REF (form_floathex),	/* for 'A', 'a' */			      \
-      REF (form_unknown),       /* for 't' */				      \
-      REF (form_unknown),       /* for 'j' */				      \
-      REF (form_unknown)        /* for 'I' */				      \
-    }
-
-#define STEP4_TABLE							      \
-    /* Step 4: processing format specifier.  */				      \
-    static JUMP_TABLE_TYPE step4_jumps[30] =				      \
-    {									      \
-      REF (form_unknown),						      \
-      REF (form_unknown),	/* for ' ' */				      \
-      REF (form_unknown),	/* for '+' */				      \
-      REF (form_unknown),	/* for '-' */				      \
-      REF (form_unknown),	/* for '<hash>' */			      \
-      REF (form_unknown),	/* for '0' */				      \
-      REF (form_unknown),	/* for '\'' */				      \
-      REF (form_unknown),	/* for '*' */				      \
-      REF (form_unknown),	/* for '1'...'9' */			      \
-      REF (form_unknown),	/* for '.' */				      \
-      REF (form_unknown),	/* for 'h' */				      \
-      REF (form_unknown),	/* for 'l' */				      \
-      REF (form_unknown),	/* for 'L', 'q' */			      \
-      REF (form_unknown),	/* for 'z', 'Z' */			      \
-      REF (form_percent),	/* for '%' */				      \
-      REF (form_integer),	/* for 'd', 'i' */			      \
-      REF (form_unsigned),	/* for 'u' */				      \
-      REF (form_octal),		/* for 'o' */				      \
-      REF (form_hexa),		/* for 'X', 'x' */			      \
-      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
-      REF (form_character),	/* for 'c' */				      \
-      REF (form_string),	/* for 's', 'S' */			      \
-      REF (form_pointer),	/* for 'p' */				      \
-      REF (form_number),	/* for 'n' */				      \
-      REF (form_strerror),	/* for 'm' */				      \
-      REF (form_wcharacter),	/* for 'C' */				      \
-      REF (form_floathex),	/* for 'A', 'a' */			      \
-      REF (form_unknown),       /* for 't' */				      \
-      REF (form_unknown),       /* for 'j' */				      \
-      REF (form_unknown)        /* for 'I' */				      \
-    }
-
-
-#define process_arg(fspec)						      \
-      /* Start real work.  We know about all flags and modifiers and	      \
-	 now process the wanted format specifier.  */			      \
-    LABEL (form_percent):						      \
-      /* Write a literal "%".  */					      \
-      outchar (L_('%'));						      \
-      break;								      \
-									      \
-    LABEL (form_integer):						      \
-      /* Signed decimal integer.  */					      \
-      base = 10;							      \
-									      \
-      if (is_longlong)							      \
-	{								      \
-	  long long int signed_number;					      \
-									      \
-	  if (fspec == NULL)						      \
-	    signed_number = va_arg (ap, long long int);			      \
-	  else								      \
-	    signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
-									      \
-	  is_negative = signed_number < 0;				      \
-	  number.longlong = is_negative ? (- signed_number) : signed_number;  \
-									      \
-	  goto LABEL (longlong_number);					      \
-	}								      \
-      else								      \
-	{								      \
-	  long int signed_number;					      \
-									      \
-	  if (fspec == NULL)						      \
-	    {								      \
-	      if (is_long_num)						      \
-		signed_number = va_arg (ap, long int);			      \
-	      else if (is_char)						      \
-		signed_number = (signed char) va_arg (ap, unsigned int);      \
-	      else if (!is_short)					      \
-		signed_number = va_arg (ap, int);			      \
-	      else							      \
-		signed_number = (short int) va_arg (ap, unsigned int);	      \
-	    }								      \
-	  else								      \
-	    if (is_long_num)						      \
-	      signed_number = args_value[fspec->data_arg].pa_long_int;	      \
-	    else if (is_char)						      \
-	      signed_number = (signed char)				      \
-		args_value[fspec->data_arg].pa_u_int;			      \
-	    else if (!is_short)						      \
-	      signed_number = args_value[fspec->data_arg].pa_int;	      \
-	    else							      \
-	      signed_number = (short int)				      \
-		args_value[fspec->data_arg].pa_u_int;			      \
-									      \
-	  is_negative = signed_number < 0;				      \
-	  number.word = is_negative ? (- signed_number) : signed_number;      \
-									      \
-	  goto LABEL (number);						      \
-	}								      \
-      /* NOTREACHED */							      \
-									      \
-    LABEL (form_unsigned):						      \
-      /* Unsigned decimal integer.  */					      \
-      base = 10;							      \
-      goto LABEL (unsigned_number);					      \
-      /* NOTREACHED */							      \
-									      \
-    LABEL (form_octal):							      \
-      /* Unsigned octal integer.  */					      \
-      base = 8;								      \
-      goto LABEL (unsigned_number);					      \
-      /* NOTREACHED */							      \
-									      \
-    LABEL (form_hexa):							      \
-      /* Unsigned hexadecimal integer.  */				      \
-      base = 16;							      \
-									      \
-    LABEL (unsigned_number):	  /* Unsigned number of base BASE.  */	      \
-									      \
-      /* ISO specifies the `+' and ` ' flags only for signed		      \
-	 conversions.  */						      \
-      is_negative = 0;							      \
-      showsign = 0;							      \
-      space = 0;							      \
-									      \
-      if (is_longlong)							      \
-	{								      \
-	  if (fspec == NULL)						      \
-	    number.longlong = va_arg (ap, unsigned long long int);	      \
-	  else								      \
-	    number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
-									      \
-	LABEL (longlong_number):					      \
-	  if (prec < 0)							      \
-	    /* Supply a default precision if none was given.  */	      \
-	    prec = 1;							      \
-	  else								      \
-	    /* We have to take care for the '0' flag.  If a precision	      \
-	       is given it must be ignored.  */				      \
-	    pad = L_(' ');						      \
-									      \
-	  /* If the precision is 0 and the number is 0 nothing has to	      \
-	     be written for the number, except for the 'o' format in	      \
-	     alternate form.  */					      \
-	  if (prec == 0 && number.longlong == 0)			      \
-	    {								      \
-	      string = workend;						      \
-	      if (base == 8 && alt)					      \
-		*--string = L_('0');					      \
-	    }								      \
-	  else								      \
-	    {								      \
-	      /* Put the number in WORK.  */				      \
-	      string = _itoa (number.longlong, workend, base,		      \
-			      spec == L_('X'));				      \
-	      if (group && grouping)					      \
-		string = group_number (work_buffer, string, workend,	      \
-				       grouping, thousands_sep);	      \
-	      if (use_outdigits && base == 10)				      \
-		string = _i18n_number_rewrite (string, workend, workend);     \
-	    }								      \
-	  /* Simplify further test for num != 0.  */			      \
-	  number.word = number.longlong != 0;				      \
-	}								      \
-      else								      \
-	{								      \
-	  if (fspec == NULL)						      \
-	    {								      \
-	      if (is_long_num)						      \
-		number.word = va_arg (ap, unsigned long int);		      \
-	      else if (is_char)						      \
-		number.word = (unsigned char) va_arg (ap, unsigned int);      \
-	      else if (!is_short)					      \
-		number.word = va_arg (ap, unsigned int);		      \
-	      else							      \
-		number.word = (unsigned short int) va_arg (ap, unsigned int); \
-	    }								      \
-	  else								      \
-	    if (is_long_num)						      \
-	      number.word = args_value[fspec->data_arg].pa_u_long_int;	      \
-	    else if (is_char)						      \
-	      number.word = (unsigned char)				      \
-		args_value[fspec->data_arg].pa_u_int;			      \
-	    else if (!is_short)						      \
-	      number.word = args_value[fspec->data_arg].pa_u_int;	      \
-	    else							      \
-	      number.word = (unsigned short int)			      \
-		args_value[fspec->data_arg].pa_u_int;			      \
-									      \
-	LABEL (number):							      \
-	  if (prec < 0)							      \
-	    /* Supply a default precision if none was given.  */	      \
-	    prec = 1;							      \
-	  else								      \
-	    /* We have to take care for the '0' flag.  If a precision	      \
-	       is given it must be ignored.  */				      \
-	    pad = L_(' ');						      \
-									      \
-	  /* If the precision is 0 and the number is 0 nothing has to	      \
-	     be written for the number, except for the 'o' format in	      \
-	     alternate form.  */					      \
-	  if (prec == 0 && number.word == 0)				      \
-	    {								      \
-	      string = workend;						      \
-	      if (base == 8 && alt)					      \
-		*--string = L_('0');					      \
-	    }								      \
-	  else								      \
-	    {								      \
-	      /* Put the number in WORK.  */				      \
-	      string = _itoa_word (number.word, workend, base,		      \
-				   spec == L_('X'));			      \
-	      if (group && grouping)					      \
-		string = group_number (work_buffer, string, workend,	      \
-				       grouping, thousands_sep);	      \
-	      if (use_outdigits && base == 10)				      \
-		string = _i18n_number_rewrite (string, workend, workend);     \
-	    }								      \
-	}								      \
-									      \
-      if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
-	/* Add octal marker.  */					      \
-	*--string = L_('0');						      \
-									      \
-      prec = MAX (0, prec - (workend - string));			      \
-									      \
-      if (!left)							      \
-	{								      \
-	  width -= workend - string + prec;				      \
-									      \
-	  if (number.word != 0 && alt && base == 16)			      \
-	    /* Account for 0X hex marker.  */				      \
-	    width -= 2;							      \
-									      \
-	  if (is_negative || showsign || space)				      \
-	    --width;							      \
-									      \
-	  if (pad == L_(' '))						      \
-	    {								      \
-	      PAD (L_(' '));						      \
-	      width = 0;						      \
-	    }								      \
-									      \
-	  if (is_negative)						      \
-	    outchar (L_('-'));						      \
-	  else if (showsign)						      \
-	    outchar (L_('+'));						      \
-	  else if (space)						      \
-	    outchar (L_(' '));						      \
-									      \
-	  if (number.word != 0 && alt && base == 16)			      \
-	    {								      \
-	      outchar (L_('0'));					      \
-	      outchar (spec);						      \
-	    }								      \
-									      \
-	  width += prec;						      \
-	  PAD (L_('0'));						      \
-									      \
-	  outstring (string, workend - string);				      \
-									      \
-	  break;							      \
-	}								      \
-      else								      \
-	{								      \
-	  if (is_negative)						      \
-	    {								      \
-	      outchar (L_('-'));					      \
-	      --width;							      \
-	    }								      \
-	  else if (showsign)						      \
-	    {								      \
-	      outchar (L_('+'));					      \
-	      --width;							      \
-	    }								      \
-	  else if (space)						      \
-	    {								      \
-	      outchar (L_(' '));					      \
-	      --width;							      \
-	    }								      \
-									      \
-	  if (number.word != 0 && alt && base == 16)			      \
-	    {								      \
-	      outchar (L_('0'));					      \
-	      outchar (spec);						      \
-	      width -= 2;						      \
-	    }								      \
-									      \
-	  width -= workend - string + prec;				      \
-									      \
-	  if (prec > 0)							      \
-	    {								      \
-	      int temp = width;						      \
-	      width = prec;						      \
-	      PAD (L_('0'));						      \
-	      width = temp;						      \
-	    }								      \
-									      \
-	  outstring (string, workend - string);				      \
-									      \
-	  PAD (L_(' '));						      \
-	  break;							      \
-	}								      \
-									      \
-    LABEL (form_float):							      \
-      {									      \
-	/* Floating-point number.  This is handled by printf_fp.c.  */	      \
-	const void *ptr;						      \
-	int function_done;						      \
-									      \
-	if (fspec == NULL)						      \
-	  {								      \
-	    if (__ldbl_is_dbl)						      \
-	      is_long_double = 0;					      \
-									      \
-	    struct printf_info info = { .prec = prec,			      \
-					.width = width,			      \
-					.spec = spec,			      \
-					.is_long_double = is_long_double,     \
-					.is_short = is_short,		      \
-					.is_long = is_long,		      \
-					.alt = alt,			      \
-					.space = space,			      \
-					.left = left,			      \
-					.showsign = showsign,		      \
-					.group = group,			      \
-					.pad = pad,			      \
-					.extra = 0,			      \
-					.i18n = use_outdigits,		      \
-					.wide = sizeof (CHAR_T) != 1,	      \
-					.is_binary128 = 0};		      \
-									      \
-	    if (is_long_double)						      \
-	      the_arg.pa_long_double = va_arg (ap, long double);	      \
-	    else							      \
-	      the_arg.pa_double = va_arg (ap, double);			      \
-	    ptr = (const void *) &the_arg;				      \
-									      \
-	    function_done = __printf_fp (s, &info, &ptr);		      \
-	  }								      \
-	else								      \
-	  {								      \
-	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
-	      {								      \
-		fspec->data_arg_type = PA_DOUBLE;			      \
-		fspec->info.is_long_double = 0;				      \
-	      }								      \
-	    /* Not supported by *printf functions.  */			      \
-	    fspec->info.is_binary128 = 0;				      \
-									      \
-	    function_done = __printf_fp (s, &fspec->info, &ptr);	      \
-	  }								      \
-									      \
-	if (function_done < 0)						      \
-	  {								      \
-	    /* Error in print handler; up to handler to set errno.  */	      \
-	    done = -1;							      \
-	    goto all_done;						      \
-	  }								      \
-									      \
-	done_add (function_done);					      \
-      }									      \
-      break;								      \
-									      \
-    LABEL (form_floathex):						      \
-      {									      \
-	/* Floating point number printed as hexadecimal number.  */	      \
-	const void *ptr;						      \
-	int function_done;						      \
-									      \
-	if (fspec == NULL)						      \
-	  {								      \
-	    if (__ldbl_is_dbl)						      \
-	      is_long_double = 0;					      \
-									      \
-	    struct printf_info info = { .prec = prec,			      \
-					.width = width,			      \
-					.spec = spec,			      \
-					.is_long_double = is_long_double,     \
-					.is_short = is_short,		      \
-					.is_long = is_long,		      \
-					.alt = alt,			      \
-					.space = space,			      \
-					.left = left,			      \
-					.showsign = showsign,		      \
-					.group = group,			      \
-					.pad = pad,			      \
-					.extra = 0,			      \
-					.wide = sizeof (CHAR_T) != 1,	      \
-					.is_binary128 = 0};		      \
-									      \
-	    if (is_long_double)						      \
-	      the_arg.pa_long_double = va_arg (ap, long double);	      \
-	    else							      \
-	      the_arg.pa_double = va_arg (ap, double);			      \
-	    ptr = (const void *) &the_arg;				      \
-									      \
-	    function_done = __printf_fphex (s, &info, &ptr);		      \
-	  }								      \
-	else								      \
-	  {								      \
-	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
-	      fspec->info.is_long_double = 0;				      \
-	    /* Not supported by *printf functions.  */			      \
-	    fspec->info.is_binary128 = 0;				      \
-									      \
-	    function_done = __printf_fphex (s, &fspec->info, &ptr);	      \
-	  }								      \
-									      \
-	if (function_done < 0)						      \
-	  {								      \
-	    /* Error in print handler; up to handler to set errno.  */	      \
-	    done = -1;							      \
-	    goto all_done;						      \
-	  }								      \
-									      \
-	done_add (function_done);					      \
-      }									      \
-      break;								      \
-									      \
-    LABEL (form_pointer):						      \
-      /* Generic pointer.  */						      \
-      {									      \
-	const void *ptr;						      \
-	if (fspec == NULL)						      \
-	  ptr = va_arg (ap, void *);					      \
-	else								      \
-	  ptr = args_value[fspec->data_arg].pa_pointer;			      \
-	if (ptr != NULL)						      \
-	  {								      \
-	    /* If the pointer is not NULL, write it as a %#x spec.  */	      \
-	    base = 16;							      \
-	    number.word = (unsigned long int) ptr;			      \
-	    is_negative = 0;						      \
-	    alt = 1;							      \
-	    group = 0;							      \
-	    spec = L_('x');						      \
-	    goto LABEL (number);					      \
-	  }								      \
-	else								      \
-	  {								      \
-	    /* Write "(nil)" for a nil pointer.  */			      \
-	    string = (CHAR_T *) L_("(nil)");				      \
-	    /* Make sure the full string "(nil)" is printed.  */	      \
-	    if (prec < 5)						      \
-	      prec = 5;							      \
-	    /* This is a wide string iff compiling wprintf.  */		      \
-	    is_long = sizeof (CHAR_T) > 1;				      \
-	    goto LABEL (print_string);					      \
-	  }								      \
-      }									      \
-      /* NOTREACHED */							      \
-									      \
-    LABEL (form_number):						      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
-	{								      \
-	  if (! readonly_format)					      \
-	    {								      \
-	      extern int __readonly_area (const void *, size_t)		      \
-		attribute_hidden;					      \
-	      readonly_format						      \
-		= __readonly_area (format, ((STR_LEN (format) + 1)	      \
-					    * sizeof (CHAR_T)));	      \
-	    }								      \
-	  if (readonly_format < 0)					      \
-	    __libc_fatal ("*** %n in writable segment detected ***\n");	      \
-	}								      \
-      /* Answer the count of characters written.  */			      \
-      if (fspec == NULL)						      \
-	{								      \
-	  if (is_longlong)						      \
-	    *(long long int *) va_arg (ap, void *) = done;		      \
-	  else if (is_long_num)						      \
-	    *(long int *) va_arg (ap, void *) = done;			      \
-	  else if (is_char)						      \
-	    *(char *) va_arg (ap, void *) = done;			      \
-	  else if (!is_short)						      \
-	    *(int *) va_arg (ap, void *) = done;			      \
-	  else								      \
-	    *(short int *) va_arg (ap, void *) = done;			      \
-	}								      \
-      else								      \
-	if (is_longlong)						      \
-	  *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
-	else if (is_long_num)						      \
-	  *(long int *) args_value[fspec->data_arg].pa_pointer = done;	      \
-	else if (is_char)						      \
-	  *(char *) args_value[fspec->data_arg].pa_pointer = done;	      \
-	else if (!is_short)						      \
-	  *(int *) args_value[fspec->data_arg].pa_pointer = done;	      \
-	else								      \
-	  *(short int *) args_value[fspec->data_arg].pa_pointer = done;	      \
-      break;								      \
-									      \
-    LABEL (form_strerror):						      \
-      /* Print description of error ERRNO.  */				      \
-      string =								      \
-	(CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,	      \
-				 WORK_BUFFER_SIZE * sizeof (CHAR_T));	      \
-      is_long = 0;		/* This is no wide-char string.  */	      \
-      goto LABEL (print_string)
-
-#ifdef COMPILE_WPRINTF
-# define process_string_arg(fspec) \
-    LABEL (form_character):						      \
-      /* Character.  */							      \
-      if (is_long)							      \
-	goto LABEL (form_wcharacter);					      \
-      --width;	/* Account for the character itself.  */		      \
-      if (!left)							      \
-	PAD (L' ');							      \
-      if (fspec == NULL)						      \
-	outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
-      else								      \
-	outchar (__btowc ((unsigned char)				      \
-			  args_value[fspec->data_arg].pa_int));		      \
-      if (left)								      \
-	PAD (L' ');							      \
-      break;								      \
-									      \
-    LABEL (form_wcharacter):						      \
-      {									      \
-	/* Wide character.  */						      \
-	--width;							      \
-	if (!left)							      \
-	  PAD (L' ');							      \
-	if (fspec == NULL)						      \
-	  outchar (va_arg (ap, wchar_t));				      \
-	else								      \
-	  outchar (args_value[fspec->data_arg].pa_wchar);		      \
-	if (left)							      \
-	  PAD (L' ');							      \
-      }									      \
-      break;								      \
-									      \
-    LABEL (form_string):						      \
-      {									      \
-	size_t len;							      \
-	int string_malloced;						      \
-									      \
-	/* The string argument could in fact be `char *' or `wchar_t *'.      \
-	   But this should not make a difference here.  */		      \
-	if (fspec == NULL)						      \
-	  string = (CHAR_T *) va_arg (ap, const wchar_t *);		      \
-	else								      \
-	  string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring;	      \
-									      \
-	/* Entry point for printing other strings.  */			      \
-      LABEL (print_string):						      \
-									      \
-	string_malloced = 0;						      \
-	if (string == NULL)						      \
-	  {								      \
-	    /* Write "(null)" if there's space.  */			      \
-	    if (prec == -1 || prec >= (int) array_length (null) - 1)          \
-	      {								      \
-		string = (CHAR_T *) null;				      \
-		len = array_length (null) - 1;				      \
-	      }								      \
-	    else							      \
-	      {								      \
-		string = (CHAR_T *) L"";				      \
-		len = 0;						      \
-	      }								      \
-	  }								      \
-	else if (!is_long && spec != L_('S'))				      \
-	  {								      \
-	    /* This is complicated.  We have to transform the multibyte	      \
-	       string into a wide character string.  */			      \
-	    const char *mbs = (const char *) string;			      \
-	    mbstate_t mbstate;						      \
-									      \
-	    len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
-									      \
-	    /* Allocate dynamically an array which definitely is long	      \
-	       enough for the wide character version.  Each byte in the	      \
-	       multi-byte string can produce at most one wide character.  */  \
-	    if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))	      \
-	      {								      \
-		__set_errno (EOVERFLOW);				      \
-		done = -1;						      \
-		goto all_done;						      \
-	      }								      \
-	    else if (__libc_use_alloca (len * sizeof (wchar_t)))	      \
-	      string = (CHAR_T *) alloca (len * sizeof (wchar_t));	      \
-	    else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
-		     == NULL)						      \
-	      {								      \
-		done = -1;						      \
-		goto all_done;						      \
-	      }								      \
-	    else							      \
-	      string_malloced = 1;					      \
-									      \
-	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
-	    len = __mbsrtowcs (string, &mbs, len, &mbstate);		      \
-	    if (len == (size_t) -1)					      \
-	      {								      \
-		/* Illegal multibyte character.  */			      \
-		done = -1;						      \
-		goto all_done;						      \
-	      }								      \
-	  }								      \
-	else								      \
-	  {								      \
-	    if (prec != -1)						      \
-	      /* Search for the end of the string, but don't search past      \
-		 the length specified by the precision.  */		      \
-	      len = __wcsnlen (string, prec);				      \
-	    else							      \
-	      len = __wcslen (string);					      \
-	  }								      \
-									      \
-	if ((width -= len) < 0)						      \
-	  {								      \
-	    outstring (string, len);					      \
-	    break;							      \
-	  }								      \
-									      \
-	if (!left)							      \
-	  PAD (L' ');							      \
-	outstring (string, len);					      \
-	if (left)							      \
-	  PAD (L' ');							      \
-	if (__glibc_unlikely (string_malloced))				      \
-	  free (string);						      \
-      }									      \
-      break;
-#else
-# define process_string_arg(fspec) \
-    LABEL (form_character):						      \
-      /* Character.  */							      \
-      if (is_long)							      \
-	goto LABEL (form_wcharacter);					      \
-      --width;	/* Account for the character itself.  */		      \
-      if (!left)							      \
-	PAD (' ');							      \
-      if (fspec == NULL)						      \
-	outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */	      \
-      else								      \
-	outchar ((unsigned char) args_value[fspec->data_arg].pa_int);	      \
-      if (left)								      \
-	PAD (' ');							      \
-      break;								      \
-									      \
-    LABEL (form_wcharacter):						      \
-      {									      \
-	/* Wide character.  */						      \
-	char buf[MB_LEN_MAX];						      \
-	mbstate_t mbstate;						      \
-	size_t len;							      \
-									      \
-	memset (&mbstate, '\0', sizeof (mbstate_t));			      \
-	len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t)	      \
-			       : args_value[fspec->data_arg].pa_wchar),	      \
-			 &mbstate);					      \
-	if (len == (size_t) -1)						      \
-	  {								      \
-	    /* Something went wrong during the conversion.  Bail out.  */     \
-	    done = -1;							      \
-	    goto all_done;						      \
-	  }								      \
-	width -= len;							      \
-	if (!left)							      \
-	  PAD (' ');							      \
-	outstring (buf, len);						      \
-	if (left)							      \
-	  PAD (' ');							      \
-      }									      \
-      break;								      \
-									      \
-    LABEL (form_string):						      \
-      {									      \
-	size_t len;							      \
-	int string_malloced;						      \
-									      \
-	/* The string argument could in fact be `char *' or `wchar_t *'.      \
-	   But this should not make a difference here.  */		      \
-	if (fspec == NULL)						      \
-	  string = (char *) va_arg (ap, const char *);			      \
-	else								      \
-	  string = (char *) args_value[fspec->data_arg].pa_string;	      \
-									      \
-	/* Entry point for printing other strings.  */			      \
-      LABEL (print_string):						      \
-									      \
-	string_malloced = 0;						      \
-	if (string == NULL)						      \
-	  {								      \
-	    /* Write "(null)" if there's space.  */			      \
-	    if (prec == -1 || prec >= (int) sizeof (null) - 1)		      \
-	      {								      \
-		string = (char *) null;					      \
-		len = sizeof (null) - 1;				      \
-	      }								      \
-	    else							      \
-	      {								      \
-		string = (char *) "";					      \
-		len = 0;						      \
-	      }								      \
-	  }								      \
-	else if (!is_long && spec != L_('S'))				      \
-	  {								      \
-	    if (prec != -1)						      \
-	      /* Search for the end of the string, but don't search past      \
-		 the length (in bytes) specified by the precision.  */	      \
-	      len = __strnlen (string, prec);				      \
-	    else							      \
-	      len = strlen (string);					      \
-	  }								      \
-	else								      \
-	  {								      \
-	    const wchar_t *s2 = (const wchar_t *) string;		      \
-	    mbstate_t mbstate;						      \
-									      \
-	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
-									      \
-	    if (prec >= 0)						      \
-	      {								      \
-		/* The string `s2' might not be NUL terminated.  */	      \
-		if (__libc_use_alloca (prec))				      \
-		  string = (char *) alloca (prec);			      \
-		else if ((string = (char *) malloc (prec)) == NULL)	      \
-		  {							      \
-		    done = -1;						      \
-		    goto all_done;					      \
-		  }							      \
-		else							      \
-		  string_malloced = 1;					      \
-		len = __wcsrtombs (string, &s2, prec, &mbstate);	      \
-	      }								      \
-	    else							      \
-	      {								      \
-		len = __wcsrtombs (NULL, &s2, 0, &mbstate);		      \
-		if (len != (size_t) -1)					      \
-		  {							      \
-		    assert (__mbsinit (&mbstate));			      \
-		    s2 = (const wchar_t *) string;			      \
-		    if (__libc_use_alloca (len + 1))			      \
-		      string = (char *) alloca (len + 1);		      \
-		    else if ((string = (char *) malloc (len + 1)) == NULL)    \
-		      {							      \
-			done = -1;					      \
-			goto all_done;					      \
-		      }							      \
-		    else						      \
-		      string_malloced = 1;				      \
-		    (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
-		  }							      \
-	      }								      \
-									      \
-	    if (len == (size_t) -1)					      \
-	      {								      \
-		/* Illegal wide-character string.  */			      \
-		done = -1;						      \
-		goto all_done;						      \
-	      }								      \
-	  }								      \
-									      \
-	if ((width -= len) < 0)						      \
-	  {								      \
-	    outstring (string, len);					      \
-	    break;							      \
-	  }								      \
-									      \
-	if (!left)							      \
-	  PAD (' ');							      \
-	outstring (string, len);					      \
-	if (left)							      \
-	  PAD (' ');							      \
-	if (__glibc_unlikely (string_malloced))			              \
-	  free (string);						      \
-      }									      \
-      break;
-#endif
-
-/* Helper function to provide temporary buffering for unbuffered streams.  */
-static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
-     __THROW __attribute__ ((noinline));
-
-/* Handle positional format specifiers.  */
-static int printf_positional (FILE *s,
-			      const CHAR_T *format, int readonly_format,
-			      va_list ap, va_list *ap_savep, int done,
-			      int nspecs_done, const UCHAR_T *lead_str_end,
-			      CHAR_T *work_buffer, int save_errno,
-			      const char *grouping, THOUSANDS_SEP_T);
-
-/* Handle unknown format specifier.  */
-static int printf_unknown (FILE *, const struct printf_info *,
-			   const void *const *) __THROW;
-
-/* Group digits of number string.  */
-static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
-			     THOUSANDS_SEP_T);
-
-/* The function itself.  */
-int
-vfprintf (FILE *s, const CHAR_T *format, va_list ap)
+extern int
+__vfprintf (FILE *fp, const char *format, va_list ap)
 {
-  /* The character used as thousands separator.  */
-  THOUSANDS_SEP_T thousands_sep = 0;
-
-  /* The string describing the size of groups of digits.  */
-  const char *grouping;
-
-  /* Place to accumulate the result.  */
-  int done;
-
-  /* Current character in format string.  */
-  const UCHAR_T *f;
-
-  /* End of leading constant string.  */
-  const UCHAR_T *lead_str_end;
-
-  /* Points to next format specifier.  */
-  const UCHAR_T *end_of_spec;
-
-  /* Buffer intermediate results.  */
-  CHAR_T work_buffer[WORK_BUFFER_SIZE];
-  CHAR_T *workstart = NULL;
-  CHAR_T *workend;
-
-  /* We have to save the original argument pointer.  */
-  va_list ap_save;
-
-  /* Count number of specifiers we already processed.  */
-  int nspecs_done;
-
-  /* For the %m format we may need the current `errno' value.  */
-  int save_errno = errno;
-
-  /* 1 if format is in read-only memory, -1 if it is in writable memory,
-     0 if unknown.  */
-  int readonly_format = 0;
-
-  /* Orient the stream.  */
-#ifdef ORIENT
-  ORIENT;
-#endif
-
-  /* Sanity check of arguments.  */
-  ARGCHECK (s, format);
-
-#ifdef ORIENT
-  /* Check for correct orientation.  */
-  if (_IO_vtable_offset (s) == 0 &&
-      _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
-      != (sizeof (CHAR_T) == 1 ? -1 : 1))
-    /* The stream is already oriented otherwise.  */
-    return EOF;
-#endif
-
-  if (UNBUFFERED_P (s))
-    /* Use a helper function which will allocate a local temporary buffer
-       for the stream and then call us again.  */
-    return buffered_vfprintf (s, format, ap);
-
-  /* Initialize local variables.  */
-  done = 0;
-  grouping = (const char *) -1;
-#ifdef __va_copy
-  /* This macro will be available soon in gcc's <stdarg.h>.  We need it
-     since on some systems `va_list' is not an integral type.  */
-  __va_copy (ap_save, ap);
-#else
-  ap_save = ap;
-#endif
-  nspecs_done = 0;
-
-#ifdef COMPILE_WPRINTF
-  /* Find the first format specifier.  */
-  f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
-#else
-  /* Find the first format specifier.  */
-  f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
-#endif
-
-  /* Lock stream.  */
-  _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
-  _IO_flockfile (s);
-
-  /* Write the literal text before the first format.  */
-  outstring ((const UCHAR_T *) format,
-	     lead_str_end - (const UCHAR_T *) format);
-
-  /* If we only have to print a simple string, return now.  */
-  if (*f == L_('\0'))
-    goto all_done;
-
-  /* Use the slow path in case any printf handler is registered.  */
-  if (__glibc_unlikely (__printf_function_table != NULL
-			|| __printf_modifier_table != NULL
-			|| __printf_va_arg_table != NULL))
-    goto do_positional;
-
-  /* Process whole format string.  */
-  do
-    {
-      STEP0_3_TABLE;
-      STEP4_TABLE;
-
-      union printf_arg *args_value;	/* This is not used here but ... */
-      int is_negative;	/* Flag for negative number.  */
-      union
-      {
-	unsigned long long int longlong;
-	unsigned long int word;
-      } number;
-      int base;
-      union printf_arg the_arg;
-      CHAR_T *string;	/* Pointer to argument string.  */
-      int alt = 0;	/* Alternate format.  */
-      int space = 0;	/* Use space prefix if no sign is needed.  */
-      int left = 0;	/* Left-justify output.  */
-      int showsign = 0;	/* Always begin with plus or minus sign.  */
-      int group = 0;	/* Print numbers according grouping rules.  */
-      int is_long_double = 0; /* Argument is long double/ long long int.  */
-      int is_short = 0;	/* Argument is short int.  */
-      int is_long = 0;	/* Argument is long int.  */
-      int is_char = 0;	/* Argument is promoted (unsigned) char.  */
-      int width = 0;	/* Width of output; 0 means none specified.  */
-      int prec = -1;	/* Precision of output; -1 means none specified.  */
-      /* This flag is set by the 'I' modifier and selects the use of the
-	 `outdigits' as determined by the current locale.  */
-      int use_outdigits = 0;
-      UCHAR_T pad = L_(' ');/* Padding character.  */
-      CHAR_T spec;
-
-      workstart = NULL;
-      workend = work_buffer + WORK_BUFFER_SIZE;
-
-      /* Get current character in format string.  */
-      JUMP (*++f, step0_jumps);
-
-      /* ' ' flag.  */
-    LABEL (flag_space):
-      space = 1;
-      JUMP (*++f, step0_jumps);
-
-      /* '+' flag.  */
-    LABEL (flag_plus):
-      showsign = 1;
-      JUMP (*++f, step0_jumps);
-
-      /* The '-' flag.  */
-    LABEL (flag_minus):
-      left = 1;
-      pad = L_(' ');
-      JUMP (*++f, step0_jumps);
-
-      /* The '#' flag.  */
-    LABEL (flag_hash):
-      alt = 1;
-      JUMP (*++f, step0_jumps);
-
-      /* The '0' flag.  */
-    LABEL (flag_zero):
-      if (!left)
-	pad = L_('0');
-      JUMP (*++f, step0_jumps);
-
-      /* The '\'' flag.  */
-    LABEL (flag_quote):
-      group = 1;
-
-      if (grouping == (const char *) -1)
-	{
-#ifdef COMPILE_WPRINTF
-	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
-					    _NL_NUMERIC_THOUSANDS_SEP_WC);
-#else
-	  thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
-#endif
-
-	  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
-	  if (*grouping == '\0' || *grouping == CHAR_MAX
-#ifdef COMPILE_WPRINTF
-	      || thousands_sep == L'\0'
-#else
-	      || *thousands_sep == '\0'
-#endif
-	      )
-	    grouping = NULL;
-	}
-      JUMP (*++f, step0_jumps);
-
-    LABEL (flag_i18n):
-      use_outdigits = 1;
-      JUMP (*++f, step0_jumps);
-
-      /* Get width from argument.  */
-    LABEL (width_asterics):
-      {
-	const UCHAR_T *tmp;	/* Temporary value.  */
-
-	tmp = ++f;
-	if (ISDIGIT (*tmp))
-	  {
-	    int pos = read_int (&tmp);
-
-	    if (pos == -1)
-	      {
-		__set_errno (EOVERFLOW);
-		done = -1;
-		goto all_done;
-	      }
-
-	    if (pos && *tmp == L_('$'))
-	      /* The width comes from a positional parameter.  */
-	      goto do_positional;
-	  }
-	width = va_arg (ap, int);
-
-	/* Negative width means left justified.  */
-	if (width < 0)
-	  {
-	    width = -width;
-	    pad = L_(' ');
-	    left = 1;
-	  }
-
-	if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
-	  {
-	    __set_errno (EOVERFLOW);
-	    done = -1;
-	    goto all_done;
-	  }
-
-	if (width >= WORK_BUFFER_SIZE - EXTSIZ)
-	  {
-	    /* We have to use a special buffer.  */
-	    size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
-	    if (__libc_use_alloca (needed))
-	      workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
-	    else
-	      {
-		workstart = (CHAR_T *) malloc (needed);
-		if (workstart == NULL)
-		  {
-		    done = -1;
-		    goto all_done;
-		  }
-		workend = workstart + width + EXTSIZ;
-	      }
-	  }
-      }
-      JUMP (*f, step1_jumps);
-
-      /* Given width in format string.  */
-    LABEL (width):
-      width = read_int (&f);
-
-      if (__glibc_unlikely (width == -1
-			    || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
-	{
-	  __set_errno (EOVERFLOW);
-	  done = -1;
-	  goto all_done;
-	}
-
-      if (width >= WORK_BUFFER_SIZE - EXTSIZ)
-	{
-	  /* We have to use a special buffer.  */
-	  size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
-	  if (__libc_use_alloca (needed))
-	    workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
-	  else
-	    {
-	      workstart = (CHAR_T *) malloc (needed);
-	      if (workstart == NULL)
-		{
-		  done = -1;
-		  goto all_done;
-		}
-	      workend = workstart + width + EXTSIZ;
-	    }
-	}
-      if (*f == L_('$'))
-	/* Oh, oh.  The argument comes from a positional parameter.  */
-	goto do_positional;
-      JUMP (*f, step1_jumps);
-
-    LABEL (precision):
-      ++f;
-      if (*f == L_('*'))
-	{
-	  const UCHAR_T *tmp;	/* Temporary value.  */
-
-	  tmp = ++f;
-	  if (ISDIGIT (*tmp))
-	    {
-	      int pos = read_int (&tmp);
-
-	      if (pos == -1)
-		{
-		  __set_errno (EOVERFLOW);
-		  done = -1;
-		  goto all_done;
-		}
-
-	      if (pos && *tmp == L_('$'))
-		/* The precision comes from a positional parameter.  */
-		goto do_positional;
-	    }
-	  prec = va_arg (ap, int);
-
-	  /* If the precision is negative the precision is omitted.  */
-	  if (prec < 0)
-	    prec = -1;
-	}
-      else if (ISDIGIT (*f))
-	{
-	  prec = read_int (&f);
-
-	  /* The precision was specified in this case as an extremely
-	     large positive value.  */
-	  if (prec == -1)
-	    {
-	      __set_errno (EOVERFLOW);
-	      done = -1;
-	      goto all_done;
-	    }
-	}
-      else
-	prec = 0;
-      if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
-	{
-	  /* Deallocate any previously allocated buffer because it is
-	     too small.  */
-	  if (__glibc_unlikely (workstart != NULL))
-	    free (workstart);
-	  workstart = NULL;
-	  if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
-	    {
-	      __set_errno (EOVERFLOW);
-	      done = -1;
-	      goto all_done;
-	    }
-	  size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
-
-	  if (__libc_use_alloca (needed))
-	    workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
-	  else
-	    {
-	      workstart = (CHAR_T *) malloc (needed);
-	      if (workstart == NULL)
-		{
-		  done = -1;
-		  goto all_done;
-		}
-	      workend = workstart + prec + EXTSIZ;
-	    }
-	}
-      JUMP (*f, step2_jumps);
-
-      /* Process 'h' modifier.  There might another 'h' following.  */
-    LABEL (mod_half):
-      is_short = 1;
-      JUMP (*++f, step3a_jumps);
-
-      /* Process 'hh' modifier.  */
-    LABEL (mod_halfhalf):
-      is_short = 0;
-      is_char = 1;
-      JUMP (*++f, step4_jumps);
-
-      /* Process 'l' modifier.  There might another 'l' following.  */
-    LABEL (mod_long):
-      is_long = 1;
-      JUMP (*++f, step3b_jumps);
-
-      /* Process 'L', 'q', or 'll' modifier.  No other modifier is
-	 allowed to follow.  */
-    LABEL (mod_longlong):
-      is_long_double = 1;
-      is_long = 1;
-      JUMP (*++f, step4_jumps);
-
-    LABEL (mod_size_t):
-      is_long_double = sizeof (size_t) > sizeof (unsigned long int);
-      is_long = sizeof (size_t) > sizeof (unsigned int);
-      JUMP (*++f, step4_jumps);
-
-    LABEL (mod_ptrdiff_t):
-      is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
-      is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
-      JUMP (*++f, step4_jumps);
-
-    LABEL (mod_intmax_t):
-      is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
-      is_long = sizeof (intmax_t) > sizeof (unsigned int);
-      JUMP (*++f, step4_jumps);
-
-      /* Process current format.  */
-      while (1)
-	{
-	  process_arg (((struct printf_spec *) NULL));
-	  process_string_arg (((struct printf_spec *) NULL));
-
-	LABEL (form_unknown):
-	  if (spec == L_('\0'))
-	    {
-	      /* The format string ended before the specifier is complete.  */
-	      __set_errno (EINVAL);
-	      done = -1;
-	      goto all_done;
-	    }
-
-	  /* If we are in the fast loop force entering the complicated
-	     one.  */
-	  goto do_positional;
-	}
-
-      /* The format is correctly handled.  */
-      ++nspecs_done;
-
-      if (__glibc_unlikely (workstart != NULL))
-	free (workstart);
-      workstart = NULL;
-
-      /* Look for next format specifier.  */
-#ifdef COMPILE_WPRINTF
-      f = __find_specwc ((end_of_spec = ++f));
-#else
-      f = __find_specmb ((end_of_spec = ++f));
-#endif
-
-      /* Write the following constant string.  */
-      outstring (end_of_spec, f - end_of_spec);
-    }
-  while (*f != L_('\0'));
-
-  /* Unlock stream and return.  */
-  goto all_done;
-
-  /* Hand off processing for positional parameters.  */
-do_positional:
-  if (__glibc_unlikely (workstart != NULL))
-    {
-      free (workstart);
-      workstart = NULL;
-    }
-  done = printf_positional (s, format, readonly_format, ap, &ap_save,
-			    done, nspecs_done, lead_str_end, work_buffer,
-			    save_errno, grouping, thousands_sep);
-
- all_done:
-  if (__glibc_unlikely (workstart != NULL))
-    free (workstart);
-  /* Unlock the stream.  */
-  _IO_funlockfile (s);
-  _IO_cleanup_region_end (0);
-
-  return done;
-}
-\f
-static int
-printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
-		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
-		   const UCHAR_T *lead_str_end,
-		   CHAR_T *work_buffer, int save_errno,
-		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
-{
-  /* For positional argument handling.  */
-  struct scratch_buffer specsbuf;
-  scratch_buffer_init (&specsbuf);
-  struct printf_spec *specs = specsbuf.data;
-  size_t specs_limit = specsbuf.length / sizeof (specs[0]);
-
-  /* Used as a backing store for args_value, args_size, args_type
-     below.  */
-  struct scratch_buffer argsbuf;
-  scratch_buffer_init (&argsbuf);
-
-  /* Array with information about the needed arguments.  This has to
-     be dynamically extensible.  */
-  size_t nspecs = 0;
-
-  /* The number of arguments the format string requests.  This will
-     determine the size of the array needed to store the argument
-     attributes.  */
-  size_t nargs = 0;
-
-  /* Positional parameters refer to arguments directly.  This could
-     also determine the maximum number of arguments.  Track the
-     maximum number.  */
-  size_t max_ref_arg = 0;
-
-  /* Just a counter.  */
-  size_t cnt;
-
-  CHAR_T *workstart = NULL;
-
-  if (grouping == (const char *) -1)
-    {
-#ifdef COMPILE_WPRINTF
-      thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
-					_NL_NUMERIC_THOUSANDS_SEP_WC);
-#else
-      thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
-#endif
-
-      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
-      if (*grouping == '\0' || *grouping == CHAR_MAX)
-	grouping = NULL;
-    }
-
-  for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
-       f = specs[nspecs++].next_fmt)
-    {
-      if (nspecs == specs_limit)
-	{
-	  if (!scratch_buffer_grow_preserve (&specsbuf))
-	    {
-	      done = -1;
-	      goto all_done;
-	    }
-	  specs = specsbuf.data;
-	  specs_limit = specsbuf.length / sizeof (specs[0]);
-	}
-
-      /* Parse the format specifier.  */
-#ifdef COMPILE_WPRINTF
-      nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
-#else
-      nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
-#endif
-    }
-
-  /* Determine the number of arguments the format string consumes.  */
-  nargs = MAX (nargs, max_ref_arg);
-
-  union printf_arg *args_value;
-  int *args_size;
-  int *args_type;
-  {
-    /* Calculate total size needed to represent a single argument
-       across all three argument-related arrays.  */
-    size_t bytes_per_arg
-      = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
-    if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
-      {
-	done = -1;
-	goto all_done;
-      }
-    args_value = argsbuf.data;
-    /* Set up the remaining two arrays to each point past the end of
-       the prior array, since space for all three has been allocated
-       now.  */
-    args_size = &args_value[nargs].pa_int;
-    args_type = &args_size[nargs];
-    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
-	    nargs * sizeof (*args_type));
-  }
-
-  /* XXX Could do sanity check here: If any element in ARGS_TYPE is
-     still zero after this loop, format is invalid.  For now we
-     simply use 0 as the value.  */
-
-  /* Fill in the types of all the arguments.  */
-  for (cnt = 0; cnt < nspecs; ++cnt)
-    {
-      /* If the width is determined by an argument this is an int.  */
-      if (specs[cnt].width_arg != -1)
-	args_type[specs[cnt].width_arg] = PA_INT;
-
-      /* If the precision is determined by an argument this is an int.  */
-      if (specs[cnt].prec_arg != -1)
-	args_type[specs[cnt].prec_arg] = PA_INT;
-
-      switch (specs[cnt].ndata_args)
-	{
-	case 0:		/* No arguments.  */
-	  break;
-	case 1:		/* One argument; we already have the
-			   type and size.  */
-	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
-	  args_size[specs[cnt].data_arg] = specs[cnt].size;
-	  break;
-	default:
-	  /* We have more than one argument for this format spec.
-	     We must call the arginfo function again to determine
-	     all the types.  */
-	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
-	    (&specs[cnt].info,
-	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
-	     &args_size[specs[cnt].data_arg]);
-	  break;
-	}
-    }
-
-  /* Now we know all the types and the order.  Fill in the argument
-     values.  */
-  for (cnt = 0; cnt < nargs; ++cnt)
-    switch (args_type[cnt])
-      {
-#define T(tag, mem, type)				\
-	case tag:					\
-	  args_value[cnt].mem = va_arg (*ap_savep, type); \
-	  break
-
-	T (PA_WCHAR, pa_wchar, wint_t);
-      case PA_CHAR:				/* Promoted.  */
-      case PA_INT|PA_FLAG_SHORT:		/* Promoted.  */
-#if LONG_MAX == INT_MAX
-      case PA_INT|PA_FLAG_LONG:
-#endif
-	T (PA_INT, pa_int, int);
-#if LONG_MAX == LONG_LONG_MAX
-      case PA_INT|PA_FLAG_LONG:
-#endif
-	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
-#if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
-# error "he?"
-#endif
-      case PA_FLOAT:				/* Promoted.  */
-	T (PA_DOUBLE, pa_double, double);
-      case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
-	if (__ldbl_is_dbl)
-	  {
-	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
-	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
-	  }
-	else
-	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
-	break;
-      case PA_STRING:				/* All pointers are the same */
-      case PA_WSTRING:			/* All pointers are the same */
-	T (PA_POINTER, pa_pointer, void *);
-#undef T
-      default:
-	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
-	  args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
-	else if (__glibc_unlikely (__printf_va_arg_table != NULL)
-		 && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
-	  {
-	    args_value[cnt].pa_user = alloca (args_size[cnt]);
-	    (*__printf_va_arg_table[args_type[cnt] - PA_LAST])
-	      (args_value[cnt].pa_user, ap_savep);
-	  }
-	else
-	  args_value[cnt].pa_long_double = 0.0;
-	break;
-      case -1:
-	/* Error case.  Not all parameters appear in N$ format
-	   strings.  We have no way to determine their type.  */
-	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
-	__libc_fatal ("*** invalid %N$ use detected ***\n");
-      }
-
-  /* Now walk through all format specifiers and process them.  */
-  for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
-    {
-      STEP4_TABLE;
-
-      int is_negative;
-      union
-      {
-	unsigned long long int longlong;
-	unsigned long int word;
-      } number;
-      int base;
-      union printf_arg the_arg;
-      CHAR_T *string;		/* Pointer to argument string.  */
-
-      /* Fill variables from values in struct.  */
-      int alt = specs[nspecs_done].info.alt;
-      int space = specs[nspecs_done].info.space;
-      int left = specs[nspecs_done].info.left;
-      int showsign = specs[nspecs_done].info.showsign;
-      int group = specs[nspecs_done].info.group;
-      int is_long_double = specs[nspecs_done].info.is_long_double;
-      int is_short = specs[nspecs_done].info.is_short;
-      int is_char = specs[nspecs_done].info.is_char;
-      int is_long = specs[nspecs_done].info.is_long;
-      int width = specs[nspecs_done].info.width;
-      int prec = specs[nspecs_done].info.prec;
-      int use_outdigits = specs[nspecs_done].info.i18n;
-      char pad = specs[nspecs_done].info.pad;
-      CHAR_T spec = specs[nspecs_done].info.spec;
-
-      workstart = NULL;
-      CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
-
-      /* Fill in last information.  */
-      if (specs[nspecs_done].width_arg != -1)
-	{
-	  /* Extract the field width from an argument.  */
-	  specs[nspecs_done].info.width =
-	    args_value[specs[nspecs_done].width_arg].pa_int;
-
-	  if (specs[nspecs_done].info.width < 0)
-	    /* If the width value is negative left justification is
-	       selected and the value is taken as being positive.  */
-	    {
-	      specs[nspecs_done].info.width *= -1;
-	      left = specs[nspecs_done].info.left = 1;
-	    }
-	  width = specs[nspecs_done].info.width;
-	}
-
-      if (specs[nspecs_done].prec_arg != -1)
-	{
-	  /* Extract the precision from an argument.  */
-	  specs[nspecs_done].info.prec =
-	    args_value[specs[nspecs_done].prec_arg].pa_int;
-
-	  if (specs[nspecs_done].info.prec < 0)
-	    /* If the precision is negative the precision is
-	       omitted.  */
-	    specs[nspecs_done].info.prec = -1;
-
-	  prec = specs[nspecs_done].info.prec;
-	}
-
-      /* Maybe the buffer is too small.  */
-      if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
-	{
-	  if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
-				 * sizeof (CHAR_T)))
-	    workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
-					  * sizeof (CHAR_T))
-		       + (MAX (prec, width) + EXTSIZ));
-	  else
-	    {
-	      workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
-					     * sizeof (CHAR_T));
-	      if (workstart == NULL)
-		{
-		  done = -1;
-		  goto all_done;
-		}
-	      workend = workstart + (MAX (prec, width) + EXTSIZ);
-	    }
-	}
-
-      /* Process format specifiers.  */
-      while (1)
-	{
-	  extern printf_function **__printf_function_table;
-	  int function_done;
-
-	  if (spec <= UCHAR_MAX
-	      && __printf_function_table != NULL
-	      && __printf_function_table[(size_t) spec] != NULL)
-	    {
-	      const void **ptr = alloca (specs[nspecs_done].ndata_args
-					 * sizeof (const void *));
-
-	      /* Fill in an array of pointers to the argument values.  */
-	      for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
-		   ++i)
-		ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
-
-	      /* Call the function.  */
-	      function_done = __printf_function_table[(size_t) spec]
-		(s, &specs[nspecs_done].info, ptr);
-
-	      if (function_done != -2)
-		{
-		  /* If an error occurred we don't have information
-		     about # of chars.  */
-		  if (function_done < 0)
-		    {
-		      /* Function has set errno.  */
-		      done = -1;
-		      goto all_done;
-		    }
-
-		  done_add (function_done);
-		  break;
-		}
-	    }
-
-	  JUMP (spec, step4_jumps);
-
-	  process_arg ((&specs[nspecs_done]));
-	  process_string_arg ((&specs[nspecs_done]));
-
-	  LABEL (form_unknown):
-	  {
-	    unsigned int i;
-	    const void **ptr;
-
-	    ptr = alloca (specs[nspecs_done].ndata_args
-			  * sizeof (const void *));
-
-	    /* Fill in an array of pointers to the argument values.  */
-	    for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
-	      ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
-
-	    /* Call the function.  */
-	    function_done = printf_unknown (s, &specs[nspecs_done].info,
-					    ptr);
-
-	    /* If an error occurred we don't have information about #
-	       of chars.  */
-	    if (function_done < 0)
-	      {
-		/* Function has set errno.  */
-		done = -1;
-		goto all_done;
-	      }
-
-	    done_add (function_done);
-	  }
-	  break;
-	}
-
-      if (__glibc_unlikely (workstart != NULL))
-	free (workstart);
-      workstart = NULL;
-
-      /* Write the following constant string.  */
-      outstring (specs[nspecs_done].end_of_fmt,
-		 specs[nspecs_done].next_fmt
-		 - specs[nspecs_done].end_of_fmt);
-    }
- all_done:
-  if (__glibc_unlikely (workstart != NULL))
-    free (workstart);
-  scratch_buffer_free (&argsbuf);
-  scratch_buffer_free (&specsbuf);
-  return done;
+  return __vfprintf_internal (fp, format, ap, 0);
 }
-\f
-/* Handle an unknown format specifier.  This prints out a canonicalized
-   representation of the format spec itself.  */
-static int
-printf_unknown (FILE *s, const struct printf_info *info,
-		const void *const *args)
-
-{
-  int done = 0;
-  CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
-  CHAR_T *const workend
-    = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
-  CHAR_T *w;
-
-  outchar (L_('%'));
-
-  if (info->alt)
-    outchar (L_('#'));
-  if (info->group)
-    outchar (L_('\''));
-  if (info->showsign)
-    outchar (L_('+'));
-  else if (info->space)
-    outchar (L_(' '));
-  if (info->left)
-    outchar (L_('-'));
-  if (info->pad == L_('0'))
-    outchar (L_('0'));
-  if (info->i18n)
-    outchar (L_('I'));
-
-  if (info->width != 0)
-    {
-      w = _itoa_word (info->width, workend, 10, 0);
-      while (w < workend)
-	outchar (*w++);
-    }
-
-  if (info->prec != -1)
-    {
-      outchar (L_('.'));
-      w = _itoa_word (info->prec, workend, 10, 0);
-      while (w < workend)
-	outchar (*w++);
-    }
-
-  if (info->spec != L_('\0'))
-    outchar (info->spec);
-
- all_done:
-  return done;
-}
-\f
-/* Group the digits from W to REAR_PTR according to the grouping rules
-   of the current locale.  The interpretation of GROUPING is as in
-   `struct lconv' from <locale.h>.  The grouped number extends from
-   the returned pointer until REAR_PTR.  FRONT_PTR to W is used as a
-   scratch area.  */
-static CHAR_T *
-group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
-	      const char *grouping, THOUSANDS_SEP_T thousands_sep)
-{
-  /* Length of the current group.  */
-  int len;
-#ifndef COMPILE_WPRINTF
-  /* Length of the separator (in wide mode, the separator is always a
-     single wide character).  */
-  int tlen = strlen (thousands_sep);
-#endif
-
-  /* We treat all negative values like CHAR_MAX.  */
-
-  if (*grouping == CHAR_MAX || *grouping <= 0)
-    /* No grouping should be done.  */
-    return w;
-
-  len = *grouping++;
-
-  /* Copy existing string so that nothing gets overwritten.  */
-  memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T));
-  CHAR_T *s = front_ptr + (rear_ptr - w);
-
-  w = rear_ptr;
-
-  /* Process all characters in the string.  */
-  while (s > front_ptr)
-    {
-      *--w = *--s;
-
-      if (--len == 0 && s > front_ptr)
-	{
-	  /* A new group begins.  */
-#ifdef COMPILE_WPRINTF
-	  if (w != s)
-	    *--w = thousands_sep;
-	  else
-	    /* Not enough room for the separator.  */
-	    goto copy_rest;
-#else
-	  int cnt = tlen;
-	  if (tlen < w - s)
-	    do
-	      *--w = thousands_sep[--cnt];
-	    while (cnt > 0);
-	  else
-	    /* Not enough room for the separator.  */
-	    goto copy_rest;
-#endif
-
-	  if (*grouping == CHAR_MAX
-#if CHAR_MIN < 0
-		   || *grouping < 0
-#endif
-		   )
-	    {
-	    copy_rest:
-	      /* No further grouping to be done.  Copy the rest of the
-		 number.  */
-	      memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
-	      break;
-	    }
-	  else if (*grouping != '\0')
-	    len = *grouping++;
-	  else
-	    /* The previous grouping repeats ad infinitum.  */
-	    len = grouping[-1];
-	}
-    }
-  return w;
-}
-\f
-/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
-struct helper_file
-  {
-    struct _IO_FILE_plus _f;
-#ifdef COMPILE_WPRINTF
-    struct _IO_wide_data _wide_data;
-#endif
-    FILE *_put_stream;
-#ifdef _IO_MTSAFE_IO
-    _IO_lock_t lock;
-#endif
-  };
-
-static int
-_IO_helper_overflow (FILE *s, int c)
-{
-  FILE *target = ((struct helper_file*) s)->_put_stream;
-#ifdef COMPILE_WPRINTF
-  int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
-  if (used)
-    {
-      size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
-      if (written == 0 || written == WEOF)
-	return WEOF;
-      __wmemmove (s->_wide_data->_IO_write_base,
-		  s->_wide_data->_IO_write_base + written,
-		  used - written);
-      s->_wide_data->_IO_write_ptr -= written;
-    }
-#else
-  int used = s->_IO_write_ptr - s->_IO_write_base;
-  if (used)
-    {
-      size_t written = _IO_sputn (target, s->_IO_write_base, used);
-      if (written == 0 || written == EOF)
-	return EOF;
-      memmove (s->_IO_write_base, s->_IO_write_base + written,
-	       used - written);
-      s->_IO_write_ptr -= written;
-    }
-#endif
-  return PUTC (c, s);
-}
-
-#ifdef COMPILE_WPRINTF
-static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_wdefault_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
-#else
-static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_default_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, _IO_default_pbackfail),
-  JUMP_INIT (xsputn, _IO_default_xsputn),
-  JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_default_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
-#endif
-
-static int
-buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
-{
-  CHAR_T buf[BUFSIZ];
-  struct helper_file helper;
-  FILE *hp = (FILE *) &helper._f;
-  int result, to_flush;
-
-  /* Orient the stream.  */
-#ifdef ORIENT
-  ORIENT;
-#endif
-
-  /* Initialize helper.  */
-  helper._put_stream = s;
-#ifdef COMPILE_WPRINTF
-  hp->_wide_data = &helper._wide_data;
-  _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
-  hp->_mode = 1;
-#else
-  _IO_setp (hp, buf, buf + sizeof buf);
-  hp->_mode = -1;
-#endif
-  hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
-#if _IO_JUMPS_OFFSET
-  hp->_vtable_offset = 0;
-#endif
-#ifdef _IO_MTSAFE_IO
-  hp->_lock = NULL;
-#endif
-  hp->_flags2 = s->_flags2;
-  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
-
-  /* Now print to helper instead.  */
-#ifndef COMPILE_WPRINTF
-  result = _IO_vfprintf (hp, format, args);
-#else
-  result = vfprintf (hp, format, args);
-#endif
-
-  /* Lock stream.  */
-  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
-  _IO_flockfile (s);
-
-  /* Now flush anything from the helper to the S. */
-#ifdef COMPILE_WPRINTF
-  if ((to_flush = (hp->_wide_data->_IO_write_ptr
-		   - hp->_wide_data->_IO_write_base)) > 0)
-    {
-      if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
-	  != to_flush)
-	result = -1;
-    }
-#else
-  if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
-    {
-      if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
-	result = -1;
-    }
-#endif
-
-  /* Unlock the stream.  */
-  _IO_funlockfile (s);
-  __libc_cleanup_region_end (0);
-
-  return result;
-}
-
-#undef vfprintf
-#ifdef COMPILE_WPRINTF
-strong_alias (_IO_vfwprintf, __vfwprintf);
-ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
-#else
-ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
-ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
-#endif
+ldbl_strong_alias (__vfprintf, _IO_vfprintf);
+ldbl_strong_alias (__vfprintf, vfprintf);
+ldbl_hidden_def (__vfprintf, vfprintf)
diff --git a/stdio-common/vfwprintf-internal.c b/stdio-common/vfwprintf-internal.c
new file mode 100644
index 0000000000..cefaf2fafe
--- /dev/null
+++ b/stdio-common/vfwprintf-internal.c
@@ -0,0 +1,2 @@
+#define COMPILE_WPRINTF	1
+#include "vfprintf-internal.c"
diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
index 2c3cd06fad..5d65eb7697 100644
--- a/stdio-common/vfwprintf.c
+++ b/stdio-common/vfwprintf.c
@@ -1,3 +1,25 @@
-#include <wctype.h>
-#define COMPILE_WPRINTF	1
-#include "vfprintf.c"
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libio/libioP.h>
+
+extern int
+__vfwprintf (FILE *fp, const wchar_t *format, va_list ap)
+{
+  return __vfwprintf_internal (fp, format, ap, 0);
+}
+ldbl_weak_alias (__vfwprintf, vfwprintf);
diff --git a/stdio-common/vprintf.c b/stdio-common/vprintf.c
index d459642dc8..0da8ba761e 100644
--- a/stdio-common/vprintf.c
+++ b/stdio-common/vprintf.c
@@ -25,9 +25,9 @@
 /* Write formatted output to stdout according to the
    format string FORMAT, using the argument list in ARG.  */
 int
-__vprintf (const char *format, __gnuc_va_list arg)
+__vprintf (const char *format, va_list ap)
 {
-  return vfprintf (stdout, format, arg);
+  return __vfprintf_internal (stdout, format, ap, 0);
 }
 
 ldbl_strong_alias (__vprintf, vprintf)
diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
index 2840512cae..5b33604427 100644
--- a/stdlib/strfrom-skeleton.c
+++ b/stdlib/strfrom-skeleton.c
@@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
     }
 
   /* The following code to prepare the virtual file has been adapted from the
-     function _IO_vsnprintf from libio.  */
+     function __vsnprintf_internal from libio.  */
 
   if (size == 0)
     {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 468e23dec4..bda84af0bb 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -166,7 +166,7 @@ __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
 {
   int done;
   set_no_long_double ();
-  done = _IO_vfprintf (s, fmt, ap);
+  done = __vfprintf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return done;
 }
@@ -175,15 +175,16 @@ strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
 
 int
 attribute_compat_text_section
-__nldbl__IO_vsprintf (char *string, const char *fmt, va_list ap)
+__nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
   int done;
   __no_long_double = 1;
-  done = _IO_vsprintf (string, fmt, ap);
+  done = __vsprintf_internal (string, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
-weak_alias (__nldbl__IO_vsprintf, __nldbl_vsprintf)
+strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
+weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
 libc_hidden_def (__nldbl_vsprintf)
 
 int
@@ -193,7 +194,7 @@ __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
 {
   int done;
   __no_long_double = 1;
-  done = _IO_obstack_vprintf (obstack, fmt, ap);
+  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
@@ -245,7 +246,7 @@ __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vasprintf (result_ptr, fmt, ap);
+  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
@@ -257,7 +258,7 @@ __nldbl_vdprintf (int d, const char *fmt, va_list arg)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vdprintf (d, fmt, arg);
+  res = __vdprintf_internal (d, fmt, arg, 0);
   clear_no_long_double ();
   return res;
 }
@@ -269,7 +270,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfwprintf (s, fmt, ap);
+  res = __vfwprintf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -289,7 +290,7 @@ __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vsnprintf (string, maxlen, fmt, ap);
+  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
@@ -303,7 +304,7 @@ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
 {
   int res;
   __no_long_double = 1;
-  res = _IO_vswprintf (string, maxlen, fmt, ap);
+  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
   __no_long_double = 0;
   return res;
 }
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
                   ` (3 preceding siblings ...)
  2018-11-15 21:46 ` [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Gabriel F. T. Gomes
@ 2018-11-15 21:46 ` Gabriel F. T. Gomes
  2018-11-22 18:11   ` Adhemerval Zanella
  2018-12-18 13:03   ` Szabolcs Nagy
  2018-11-15 21:46 ` [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Gabriel F. T. Gomes
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:46 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changes since v2:

  - Fix copyright statements.
  - Add note about the fix for bug 11319.

Changes since v1:

  - Fixed white-space errors.
  - Updated commit message.
  - In the declaration of __vsnprintf_internal, in libio/libioP.h,
    mention that passing -1 to the maxlen argument is the behavior of
    ordinary (v)sprintf function (this was already described in the
    commit message, but seems relevant to the code itself).

-- 8< --
The _chk variants of all of the printf functions become much simpler.
This is the last thing that we needed _IO_acquire_lock_clear_flags2
for, so it can go as well.  I took the opportunity to make the headers
included and the names of all local variables consistent across all the
affected files.

Since we ultimately want to get rid of __no_long_double as well, it
must be possible to get all of the nontrivial effects of the _chk
functions by calling the _internal functions with appropriate flags.
For most of the __(v)xprintf_chk functions, this is covered by
PRINTF_FORTIFY plus some up-front argument checks that can be
duplicated.  However, __(v)sprintf_chk installs a custom jump table so
that it can crash instead of overflowing the output buffer.  This
functionality is moved to __vsprintf_internal, which now has a
'maxlen' argument like __vsnprintf_internal; to get the unsafe
behavior of ordinary (v)sprintf, pass -1 for that argument.

obstack_printf_chk and obstack_vprintf_chk are no longer in the same
file.

As a side-effect of the unification of both fortified and non-fortified
vdprintf initialization, this patch fixes bug 11319.

Tested for powerpc and powerpc64le.

2018-10-24  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	[BZ #11319]
	* libio/iovsprintf.c (_IO_str_chk_overflow, libio_vtable):
	Moved here from debug/vsprintf_chk.c.
	(__vsprintf_internal): Add 'maxlen' argument.  Change the setup
	and completion logic for the strfile to match exactly what
	__vsprintf_chk used to do, except, when maxlen is -1, pass -1 to
	_IO_str_init_static_internal instead of maxlen-1.
	(__vsprintf): Pass -1 as maxlen to __vsprintf_internal.
	* stdio-common/sprintf.c (__sprintf): Pass -1 as maxlen to
	__vsprintf_internal.

	* debug/vsprintf_chk.c (__vsprintf_chk)
	* debug/sprintf_chk.c (__sprintf_chk):
	Directly call __vsprintf_internal, passing PRINTF_FORTIFY if
	'flags' argument is positive, and slen as maxlen.  No need to lock
	the FILE and/or construct a temporary FILE.  Minimize and normalize
	header inclusions and variable names.  Do not libc_hidden_def anything.

	* debug/asprintf_chk.c (__asprintf_chk)
	* debug/dprintf_chk.c (__dprintf_chk)
	* debug/fprintf_chk.c (__fprintf_chk)
	* debug/fwprintf_chk.c (__fwprintf_chk)
	* debug/printf_chk.c (__printf_chk)
	* debug/snprintf_chk.c (__snprintf_chk)
	* debug/swprintf_chk.c (__swprintf_chk)
	* debug/vasprintf_chk.c (__vasprintf_chk)
	* debug/vdprintf_chk.c (__vdprintf_chk)
	* debug/vfprintf_chk.c (__vfprintf_chk)
	* debug/vfwprintf_chk.c (__vfwprintf_chk)
	* debug/vprintf_chk.c (__vprintf_chk)
	* debug/vsnprintf_chk.c (__vsnprintf_chk)
	* debug/vswprintf_chk.c (__vswprintf_chk)
	* debug/vwprintf_chk.c (__vwprintf_chk)
	* debug/wprintf_chk.c (__wprintf_chk):
	Directly call the corresponding vxxprintf_internal function, passing
	PRINTF_FORTIFY if 'flag' argument is positive.	No need to lock
	the FILE and/or construct a temporary FILE.  Minimize and normalize
	header inclusions and variable names.  Do not libc_hidden_def anything.

	* debug/obprintf_chk.c (__obstack_printf_chk): Directly call
	__obstack_vprintf_internal.
	(__obstack_vprintf_chk): Convert into a wrapper that calls
	__obstack_vprintf_internal (these two functions already had the
	same code) and move to new file...
	* debug/vobprintf_chk.c (__obstack_vprintf_chk): ... here.  New
	file.
	* debug/obprintf.c (__obstack_vprintf_internal): Remove the checking of
	the flags argument and the setting of _IO_FLAGS2_FORTIFY.
	* debug/Makefile (routines): Add vobprintf_chk.

	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	(__nldbl___vsprintf): Pass -1 as maxlen to __vsprintf_internal.
	(__nldbl___vfprintf_chk, __nldbl___vsnprintf_chk)
	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
	(__nldbl___vasprintf_chk, __nldbl___vdprintf_chk)
	(__nldbl___obstack_vfprintf_chk):
	Directly call the corresponding vxxprintf_internal function,
	passing PRINTF_FORTIFY if 'flag' argument is positive.  If necessary,
	duplicate comparison of slen with 0 or maxlen from the corresponding
	non-__nldbl function.

	* include/stdio.h (__vsnprintf_chk, __vfprintf_chk, __vasprintf_chk)
	(__vdprintf_chk, __obstack_vfprintf_chk): Remove libc_hidden_proto.
	* include/wchar.h (__vfwprintf_chk, __vswprintf_chk):
	Remove libc_hidden_proto.

	* stdio-common/vfprintf-internal.c
	(__vfprintf_internal, __vfwprintf_internal):
	Do not check _IO_FLAGS2_FORTIFY.
	* libio/libio.h (_IO_FLAGS2_FORTIFY): Remove.
	* libio/libioP.h: Update prototype of __vsprintf_internal and add
	a comment explaining why it has the maxlen argument.
	(_IO_acquire_lock_clear_flags2_fct): Remove.
	(_IO_acquire_lock_clear_flags2): Remove.
	(_IO_release_lock): Remove conditional statement which will
	now never execute.
	(_IO_acquire_lock): Remove variable which is now unused.
	* sysdeps/generic/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
	* sysdeps/nptl/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
---
 debug/Makefile                            |  2 +-
 debug/asprintf_chk.c                      | 20 ++++---
 debug/dprintf_chk.c                       | 20 ++++---
 debug/fprintf_chk.c                       | 20 +++----
 debug/fwprintf_chk.c                      | 20 +++----
 debug/obprintf_chk.c                      | 96 ++++---------------------------
 debug/printf_chk.c                        | 20 +++----
 debug/snprintf_chk.c                      | 24 ++++----
 debug/sprintf_chk.c                       | 25 ++++----
 debug/swprintf_chk.c                      | 27 +++++----
 debug/vasprintf_chk.c                     | 68 ++--------------------
 debug/vdprintf_chk.c                      | 37 ++----------
 debug/vfprintf_chk.c                      | 21 ++-----
 debug/vfwprintf_chk.c                     | 21 ++-----
 debug/{asprintf_chk.c => vobprintf_chk.c} | 23 +++-----
 debug/vprintf_chk.c                       | 20 ++-----
 debug/vsnprintf_chk.c                     | 46 ++-------------
 debug/vsprintf_chk.c                      | 69 +++-------------------
 debug/vswprintf_chk.c                     | 51 ++--------------
 debug/vwprintf_chk.c                      | 21 ++-----
 debug/wprintf_chk.c                       | 21 +++----
 include/stdio.h                           |  5 --
 include/wchar.h                           |  2 -
 libio/iovsprintf.c                        | 54 +++++++++++++++--
 libio/libio.h                             |  1 -
 libio/libioP.h                            | 27 +++------
 stdio-common/sprintf.c                    |  2 +-
 stdio-common/vfprintf-internal.c          |  2 -
 sysdeps/generic/stdio-lock.h              |  7 ---
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c   | 32 ++++++++---
 sysdeps/nptl/stdio-lock.h                 |  7 ---
 31 files changed, 247 insertions(+), 564 deletions(-)
 copy debug/{asprintf_chk.c => vobprintf_chk.c} (61%)

diff --git a/debug/Makefile b/debug/Makefile
index 506cebc3c4..2ef08cf23b 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -45,7 +45,7 @@ routines  = backtrace backtracesyms backtracesymsfd noophooks \
 	    gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
 	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
 	    wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
-	    vdprintf_chk obprintf_chk \
+	    vdprintf_chk obprintf_chk vobprintf_chk \
 	    longjmp_chk ____longjmp_chk \
 	    fdelt_chk poll_chk ppoll_chk \
 	    explicit_bzero_chk \
diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c
index 9cd4143f2e..eb885c35ca 100644
--- a/debug/asprintf_chk.c
+++ b/debug/asprintf_chk.c
@@ -15,22 +15,24 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output from FORMAT to a string which is
    allocated with malloc and stored in *STRING_PTR.  */
 int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__asprintf_chk (char **result_ptr, int flag, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vasprintf_chk (result_ptr, flags, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vasprintf_internal (result_ptr, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c
index df3867c61c..b5c62827c0 100644
--- a/debug/dprintf_chk.c
+++ b/debug/dprintf_chk.c
@@ -15,21 +15,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output to D, according to the format string FORMAT.  */
 int
-__dprintf_chk (int d, int flags, const char *format, ...)
+__dprintf_chk (int d, int flag, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vdprintf_chk (d, flags, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vdprintf_internal (d, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
index cff4438afb..14afc073b2 100644
--- a/debug/fprintf_chk.c
+++ b/debug/fprintf_chk.c
@@ -16,29 +16,23 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 ___fprintf_chk (FILE *fp, int flag, const char *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = vfprintf (fp, format, ap);
+  ret = __vfprintf_internal (fp, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___fprintf_chk, __fprintf_chk)
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index 63167c1839..10d84ce98b 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -16,28 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = __vfwprintf_internal (fp, format, ap, 0);
+  ret = __vfwprintf_internal (fp, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return ret;
 }
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 41dd481c34..c1a8f9e9a9 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -17,99 +17,23 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-
-#include <stdlib.h>
-#include <libioP.h>
-#include "../libio/strfile.h"
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <obstack.h>
+#include <libio/libioP.h>
 #include <stdarg.h>
-#include <stdio_ext.h>
-
-
-struct _IO_obstack_file
-{
-  struct _IO_FILE_plus file;
-  struct obstack *obstack;
-};
-
-extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
-
-int
-__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
-		       va_list args)
-{
-  struct obstack_FILE
-    {
-      struct _IO_obstack_file ofile;
-    } new_f;
-  int result;
-  int size;
-  int room;
-
-#ifdef _IO_MTSAFE_IO
-  new_f.ofile.file.file._lock = NULL;
-#endif
-
-  _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
-  room = obstack_room (obstack);
-  size = obstack_object_size (obstack) + room;
-  if (size == 0)
-    {
-      /* We have to handle the allocation a bit different since the
-	 `_IO_str_init_static' function would handle a size of zero
-	 different from what we expect.  */
-
-      /* Get more memory.  */
-      obstack_make_room (obstack, 64);
-
-      /* Recompute how much room we have.  */
-      room = obstack_room (obstack);
-      size = room;
-
-      assert (size != 0);
-    }
-
-  _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile,
-				obstack_base (obstack),
-				size, obstack_next_free (obstack));
-  /* Now allocate the rest of the current chunk.  */
-  assert (size == (new_f.ofile.file.file._IO_write_end
-		   - new_f.ofile.file.file._IO_write_base));
-  assert (new_f.ofile.file.file._IO_write_ptr
-	  == (new_f.ofile.file.file._IO_write_base
-	      + obstack_object_size (obstack)));
-  obstack_blank_fast (obstack, room);
-
-  new_f.ofile.obstack = obstack;
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
-     can only come from read-only format strings.  */
-  if (flags > 0)
-    new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
-
-  /* Shrink the buffer to the space we really currently need.  */
-  obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
-				- new_f.ofile.file.file._IO_write_end));
-
-  return result;
-}
-libc_hidden_def (__obstack_vprintf_chk)
 
 
 int
-__obstack_printf_chk (struct obstack *obstack, int flags, const char *format,
+__obstack_printf_chk (struct obstack *obstack, int flag, const char *format,
 		      ...)
 {
-  int result;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
+  int ret;
+
   va_start (ap, format);
-  result = __obstack_vprintf_chk (obstack, flags, format, ap);
+  ret = __obstack_vprintf_internal (obstack, format, ap, mode);
   va_end (ap);
-  return result;
+
+  return ret;
 }
diff --git a/debug/printf_chk.c b/debug/printf_chk.c
index 426dc78386..e035b42590 100644
--- a/debug/printf_chk.c
+++ b/debug/printf_chk.c
@@ -16,29 +16,23 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 ___printf_chk (int flag, const char *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = vfprintf (stdout, format, ap);
+  ret = __vfprintf_internal (stdout, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___printf_chk, __printf_chk)
diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
index cddba37109..984b5e8932 100644
--- a/debug/snprintf_chk.c
+++ b/debug/snprintf_chk.c
@@ -15,25 +15,29 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-___snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
 		 const char *format, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
 
-  va_start (arg, format);
-  done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
-  va_end (arg);
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  return done;
+  va_start (ap, format);
+  ret = __vsnprintf_internal (s, maxlen, format, ap, mode);
+  va_end (ap);
+
+  return ret;
 }
 ldbl_strong_alias (___snprintf_chk, __snprintf_chk)
diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
index 78214563dd..649e8ab4d5 100644
--- a/debug/sprintf_chk.c
+++ b/debug/sprintf_chk.c
@@ -15,22 +15,27 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
+
 
 /* Write formatted output into S, according to the format string FORMAT.  */
-/* VARARGS4 */
 int
-___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
+___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
+
+  if (slen == 0)
+    __chk_fail ();
 
-  va_start (arg, format);
-  done = __vsprintf_chk (s, flags, slen, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vsprintf_internal (s, slen, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 ldbl_strong_alias (___sprintf_chk, __sprintf_chk)
diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c
index 35887e48e2..186c17751c 100644
--- a/debug/swprintf_chk.c
+++ b/debug/swprintf_chk.c
@@ -16,20 +16,27 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <wchar.h>
+#include <libio/libioP.h>
 
-/* Write formatted output into S, according to the format string FORMAT.  */
-/* VARARGS5 */
+
+/* Write formatted output into S, according to the format string FORMAT,
+   writing no more than MAXLEN characters.  */
 int
-__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len,
+__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
 		const wchar_t *format, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  int ret;
 
-  va_start (arg, format);
-  done = __vswprintf_chk (s, n, flag, s_len, format, arg);
-  va_end (arg);
+  va_start (ap, format);
+  ret = __vswprintf_internal (s, maxlen, format, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index dbfebff83f..f5975ea02a 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -24,72 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <malloc.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
 int
-__vasprintf_chk (char **result_ptr, int flags, const char *format,
-		 va_list args)
+__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap)
 {
-  /* Initial size of the buffer to be used.  Will be doubled each time an
-     overflow occurs.  */
-  const size_t init_string_size = 100;
-  char *string;
-  _IO_strfile sf;
-  int ret;
-  size_t needed;
-  size_t allocated;
-  /* No need to clear the memory here (unlike for open_memstream) since
-     we know we will never seek on the stream.  */
-  string = (char *) malloc (init_string_size);
-  if (string == NULL)
-    return -1;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, string, init_string_size, string);
-  sf._sbf._f._flags &= ~_IO_USER_BUF;
-  sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
-  sf._s._free_buffer_unused = (_IO_free_type) free;
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
-  if (ret < 0)
-    {
-      free (sf._sbf._f._IO_buf_base);
-      return ret;
-    }
-  /* Only use realloc if the size we need is of the same (binary)
-     order of magnitude then the memory we allocated.  */
-  needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1;
-  allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base;
-  if ((allocated >> 1) <= needed)
-    *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
-  else
-    {
-      *result_ptr = (char *) malloc (needed);
-      if (*result_ptr != NULL)
-	{
-	  memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1);
-	  free (sf._sbf._f._IO_buf_base);
-	}
-      else
-	/* We have no choice, use the buffer we already have.  */
-	*result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
-    }
-  if (*result_ptr == NULL)
-    *result_ptr = sf._sbf._f._IO_buf_base;
-  (*result_ptr)[needed - 1] = '\0';
-  return ret;
+  return __vasprintf_internal (result_ptr, format, ap, mode);
 }
-libc_hidden_def (__vasprintf_chk)
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index 4386127cfe..e04514e355 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -24,41 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
-#include <stdio_ext.h>
+#include <libio/libioP.h>
 
 int
-__vdprintf_chk (int d, int flags, const char *format, va_list arg)
+__vdprintf_chk (int d, int flag, const char *format, va_list ap)
 {
-  struct _IO_FILE_plus tmpfil;
-  struct _IO_wide_data wd;
-  int done;
-
-#ifdef _IO_MTSAFE_IO
-  tmpfil.file._lock = NULL;
-#endif
-  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
-  _IO_new_file_init_internal (&tmpfil);
-  if (_IO_file_attach (&tmpfil.file, d) == NULL)
-    {
-      _IO_un_link (&tmpfil);
-      return EOF;
-    }
-  tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
-
-  _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
-		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
-
-  _IO_FINISH (&tmpfil.file);
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  return done;
+  return __vdprintf_internal (d, format, ap, mode);
 }
-libc_hidden_def (__vdprintf_chk)
diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
index 5babbf611e..44426e14fd 100644
--- a/debug/vfprintf_chk.c
+++ b/debug/vfprintf_chk.c
@@ -15,28 +15,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 ___vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = vfprintf (fp, format, ap);
-
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return __vfprintf_internal (fp, format, ap, mode);
 }
-ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk)
 ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk)
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index abf2bd6517..3aed308156 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -15,27 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to FP from the format string FORMAT.  */
 int
 __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (fp);
-  if (flag > 0)
-    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfwprintf_internal (fp, format, ap, 0);
-
-  if (flag > 0)
-    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (fp);
-
-  return done;
+  return __vfwprintf_internal (fp, format, ap, mode);
 }
-libc_hidden_def (__vfwprintf_chk)
diff --git a/debug/asprintf_chk.c b/debug/vobprintf_chk.c
similarity index 61%
copy from debug/asprintf_chk.c
copy to debug/vobprintf_chk.c
index 9cd4143f2e..bed2c98eac 100644
--- a/debug/asprintf_chk.c
+++ b/debug/vobprintf_chk.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Print output of stream to given obstack.
+   Copyright (C) 2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,22 +16,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
-#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
 
 
-/* Write formatted output from FORMAT to a string which is
-   allocated with malloc and stored in *STRING_PTR.  */
 int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+		       va_list ap)
 {
-  va_list arg;
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  va_start (arg, format);
-  done = __vasprintf_chk (result_ptr, flags, format, arg);
-  va_end (arg);
-
-  return done;
+  return __obstack_vprintf_internal (obstack, format, ap, mode);
 }
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
index b3b2c53df2..69fcb721ac 100644
--- a/debug/vprintf_chk.c
+++ b/debug/vprintf_chk.c
@@ -15,27 +15,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 ___vprintf_chk (int flag, const char *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = vfprintf (stdout, format, ap);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfprintf_internal (stdout, format, ap, mode);
 }
 ldbl_strong_alias (___vprintf_chk, __vprintf_chk)
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index 95d286f416..666a83b701 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -15,56 +15,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
-extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
-		  const char *format, va_list args)
+___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+		  const char *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_strnfile sf;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (maxlen == 0)
-    {
-      s = sf.overflow_buf;
-      maxlen = sizeof (sf.overflow_buf);
-    }
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
-  s[0] = '\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
-  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
-    *sf.f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsnprintf_internal (s, maxlen, format, ap, mode);
 }
-ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
 ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 53f07236ae..c1b1a8da4f 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -15,75 +15,20 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
-
-
-static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
-
-static int
-_IO_str_chk_overflow (FILE *fp, int c)
-{
-  /* When we come to here this means the user supplied buffer is
-     filled.  */
-  __chk_fail ();
-}
-
-
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_chk_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
+#include <libio/libioP.h>
 
 int
-___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
-		 va_list args)
+___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+		 va_list ap)
 {
-  _IO_strfile f;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  f._sbf._f._lock = NULL;
-#endif
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
   if (slen == 0)
     __chk_fail ();
 
-  _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
-  s[0] = '\0';
-  _IO_str_init_static_internal (&f, s, slen - 1, s);
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
-     can only come from read-only format strings.  */
-  if (flags > 0)
-    f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
-
-  *f._sbf._f._IO_write_ptr = '\0';
-  return ret;
+  return __vsprintf_internal (s, slen, format, ap, mode);
 }
 ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
 ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 4d616f8835..2c6fadd463 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -15,60 +15,21 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
-/* VARARGS5 */
 int
-__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
-		 const wchar_t *format, va_list args)
+__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
+		 const wchar_t *format, va_list ap)
 {
-  /* XXX Maybe for less strict version do not fail immediately.
-     Though, maxlen is supposed to be the size of buffer pointed
-     to by s, so a conforming program can't pass such maxlen
-     to *snprintf.  */
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  _IO_wstrnfile sf;
-  struct _IO_wide_data wd;
-  int ret;
-#ifdef _IO_MTSAFE_IO
-  sf.f._sbf._f._lock = NULL;
-#endif
-
-  /* We need to handle the special case where MAXLEN is 0.  Use the
-     overflow buffer right from the start.  */
-  if (__glibc_unlikely (maxlen == 0))
-    /* Since we have to write at least the terminating L'\0' a buffer
-       length of zero always makes the function fail.  */
-    return -1;
-
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
-  _IO_fwide (&sf.f._sbf._f, 1);
-  s[0] = L'\0';
-
-  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
      can only come from read-only format strings.  */
-  if (flags > 0)
-    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
-  _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
-  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
-
-  if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
-    /* ISO C99 requires swprintf/vswprintf to return an error if the
-       output does not fit int he provided buffer.  */
-    return -1;
-
-  /* Terminate the string.  */
-  *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  return ret;
+  return __vswprintf_internal (s, maxlen, format, ap, mode);
 }
-libc_hidden_def (__vswprintf_chk)
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index fedc7a46bf..f1e8878a54 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -15,27 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
 {
-  int done;
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
 
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
-  done = __vfwprintf_internal (stdout, format, ap, 0);
-
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return __vfwprintf_internal (stdout, format, ap, mode);
 }
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 819050e5af..9f406e95f8 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -16,29 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
 
 
 /* Write formatted output to stdout from the format string FORMAT.  */
 int
 __wprintf_chk (int flag, const wchar_t *format, ...)
 {
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
   va_list ap;
-  int done;
-
-  _IO_acquire_lock_clear_flags2 (stdout);
-  if (flag > 0)
-    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+  int ret;
 
   va_start (ap, format);
-  done = __vfwprintf_internal (stdout, format, ap, 0);
+  ret = __vfwprintf_internal (stdout, format, ap, mode);
   va_end (ap);
 
-  if (flag > 0)
-    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
-  _IO_release_lock (stdout);
-
-  return done;
+  return ret;
 }
diff --git a/include/stdio.h b/include/stdio.h
index 0856d729d9..1b7da0f74d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -216,11 +216,6 @@ libc_hidden_proto (__open_memstream)
 libc_hidden_proto (__libc_fatal)
 rtld_hidden_proto (__libc_fatal)
 libc_hidden_proto (__vsprintf_chk)
-libc_hidden_proto (__vsnprintf_chk)
-libc_hidden_proto (__vfprintf_chk)
-libc_hidden_proto (__vasprintf_chk)
-libc_hidden_proto (__vdprintf_chk)
-libc_hidden_proto (__obstack_vprintf_chk)
 
 extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
 libc_hidden_proto (__fmemopen)
diff --git a/include/wchar.h b/include/wchar.h
index d0fe45c3a6..86506d28e9 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -216,8 +216,6 @@ extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
 			    const wchar_t *__restrict __format,
 			    __gnuc_va_list __arg)
      /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
-libc_hidden_proto (__vfwprintf_chk)
-libc_hidden_proto (__vswprintf_chk)
 
 extern int __isoc99_fwscanf (__FILE *__restrict __stream,
 			     const wchar_t *__restrict __format, ...);
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 3b1e8292b5..08e4002625 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -27,8 +27,47 @@
 #include "libioP.h"
 #include "strfile.h"
 
+static int __THROW
+_IO_str_chk_overflow (FILE *fp, int c)
+{
+  /* If we get here, the user-supplied buffer would be overrun by
+     further output.  */
+  __chk_fail ();
+}
+
+static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_str_finish),
+  JUMP_INIT(overflow, _IO_str_chk_overflow),
+  JUMP_INIT(underflow, _IO_str_underflow),
+  JUMP_INIT(uflow, _IO_default_uflow),
+  JUMP_INIT(pbackfail, _IO_str_pbackfail),
+  JUMP_INIT(xsputn, _IO_default_xsputn),
+  JUMP_INIT(xsgetn, _IO_default_xsgetn),
+  JUMP_INIT(seekoff, _IO_str_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_default_setbuf),
+  JUMP_INIT(sync, _IO_default_sync),
+  JUMP_INIT(doallocate, _IO_default_doallocate),
+  JUMP_INIT(read, _IO_default_read),
+  JUMP_INIT(write, _IO_default_write),
+  JUMP_INIT(seek, _IO_default_seek),
+  JUMP_INIT(close, _IO_default_close),
+  JUMP_INIT(stat, _IO_default_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+/* This function is called by regular vsprintf with maxlen set to -1,
+   and by vsprintf_chk with maxlen set to the size of the output
+   string.  In the former case, _IO_str_chk_overflow will never be
+   called; in the latter case it will crash the program if the buffer
+   overflows.  */
+
 int
-__vsprintf_internal (char *string, const char *format, va_list args,
+__vsprintf_internal (char *string, size_t maxlen,
+		     const char *format, va_list args,
 		     unsigned int mode_flags)
 {
   _IO_strfile sf;
@@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, string, -1, string);
+  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
+  string[0] = '\0';
+  _IO_str_init_static_internal (&sf, string,
+				(maxlen == -1) ? -1 : maxlen - 1,
+				string);
+
   ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
-  _IO_putc_unlocked ('\0', &sf._sbf._f);
+
+  *sf._sbf._f._IO_write_ptr = '\0';
   return ret;
 }
 
 int
 __vsprintf (char *string, const char *format, va_list args)
 {
-  return __vsprintf_internal (string, format, args, 0);
+  return __vsprintf_internal (string, -1, format, args, 0);
 }
 
 ldbl_strong_alias (__vsprintf, _IO_vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index c188814ccc..3a93807efc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -90,7 +90,6 @@ typedef union
 /* Bits for the _flags2 field.  */
 #define _IO_FLAGS2_MMAP 1
 #define _IO_FLAGS2_NOTCANCEL 2
-#define _IO_FLAGS2_FORTIFY 4
 #define _IO_FLAGS2_USER_WBUF 8
 #define _IO_FLAGS2_NOCLOSE 32
 #define _IO_FLAGS2_CLOEXEC 64
diff --git a/libio/libioP.h b/libio/libioP.h
index fe52ef1752..ce5228e382 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
 				       va_list ap, unsigned int mode_flags)
     attribute_hidden;
 
-extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument,
+   because it's called by both vsprintf and vsprintf_chk.  If maxlen is
+   not set to -1, overrunning the buffer will cause a prompt crash.
+   This is the behavior of ordinary (v)sprintf functions, thus they call
+   __vsprintf_internal with that argument set to -1.  */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+				const char *format, va_list ap,
 				unsigned int mode_flags)
     attribute_hidden;
+
 extern int __vsnprintf_internal (char *string, size_t maxlen,
 				 const char *format, va_list ap,
 				 unsigned int mode_flags)
@@ -818,26 +825,10 @@ _IO_acquire_lock_fct (FILE **p)
     _IO_funlockfile (fp);
 }
 
-static inline void
-__attribute__ ((__always_inline__))
-_IO_acquire_lock_clear_flags2_fct (FILE **p)
-{
-  FILE *fp = *p;
-  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
-  if ((fp->_flags & _IO_USER_LOCK) == 0)
-    _IO_funlockfile (fp);
-}
-
 #if !defined _IO_MTSAFE_IO && IS_IN (libc)
 # define _IO_acquire_lock(_fp)						      \
-  do {									      \
-    FILE *_IO_acquire_lock_file = NULL
-# define _IO_acquire_lock_clear_flags2(_fp)				      \
-  do {									      \
-    FILE *_IO_acquire_lock_file = (_fp)
+  do {
 # define _IO_release_lock(_fp)						      \
-    if (_IO_acquire_lock_file != NULL)					      \
-      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
   } while (0)
 #endif
 
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index 77423b292f..447faa4e25 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = __vsprintf_internal (s, format, arg, 0);
+  done = __vsprintf_internal (s, -1, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index b0c86e99bd..4cc4261ead 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1283,8 +1283,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
   /* Temporarily honor environmental settings.  */
   if (__ldbl_is_dbl)
     mode_flags |= PRINTF_LDBL_IS_DBL;
-  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
-    mode_flags |= PRINTF_FORTIFY;
 
   /* Orient the stream.  */
 #ifdef ORIENT
diff --git a/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h
index 4a40618545..25ccd07f29 100644
--- a/sysdeps/generic/stdio-lock.h
+++ b/sysdeps/generic/stdio-lock.h
@@ -54,15 +54,8 @@ __libc_lock_define_recursive (typedef, _IO_lock_t)
 	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
 	= (_fp);							      \
     _IO_flockfile (_IO_acquire_lock_file);
-#  define _IO_acquire_lock_clear_flags2(_fp) \
-  do {									      \
-    FILE *_IO_acquire_lock_file						      \
-	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
-	= (_fp);							      \
-    _IO_flockfile (_IO_acquire_lock_file);
 # else
 #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
 # endif
 # define _IO_release_lock(_fp) ; } while (0)
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 958bbc1834..59b2c9fcdd 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -179,7 +179,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
   int done;
   __no_long_double = 1;
-  done = __vsprintf_internal (string, fmt, ap, 0);
+  done = __vsprintf_internal (string, -1, fmt, ap, 0);
   __no_long_double = 0;
   return done;
 }
@@ -579,7 +579,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = __vfprintf_chk (s, flag, fmt, ap);
+  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -591,7 +591,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = __vfwprintf_chk (s, flag, fmt, ap);
+  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -609,9 +609,13 @@ attribute_compat_text_section
 __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
 			 const char *fmt, va_list ap)
 {
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap);
+  res = __vsnprintf_internal (string, maxlen, fmt, ap,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -622,9 +626,13 @@ attribute_compat_text_section
 __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
 			va_list ap)
 {
+  if (slen == 0)
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vsprintf_chk (string, flag, slen, fmt, ap);
+  res = __vsprintf_internal (string, slen, fmt, ap,
+			     (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -635,9 +643,13 @@ attribute_compat_text_section
 __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
 			 const wchar_t *fmt, va_list ap)
 {
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
   int res;
   __no_long_double = 1;
-  res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap);
+  res = __vswprintf_internal (string, maxlen, fmt, ap,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -670,7 +682,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
 {
   int res;
   __no_long_double = 1;
-  res = __vasprintf_chk (ptr, flag, fmt, arg);
+  res = __vasprintf_internal (ptr, fmt, arg,
+			      (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
@@ -696,7 +709,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
 {
   int res;
   set_no_long_double ();
-  res = __vdprintf_chk (d, flag, fmt, arg);
+  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
   clear_no_long_double ();
   return res;
 }
@@ -723,7 +736,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
 {
   int res;
   __no_long_double = 1;
-  res = __obstack_vprintf_chk (obstack, flag, fmt, arg);
+  res = __obstack_vprintf_internal (obstack, fmt, arg,
+				    (flag > 0) ? PRINTF_FORTIFY : 0);
   __no_long_double = 0;
   return res;
 }
diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
index 5b9782452f..1d6a81c5bf 100644
--- a/sysdeps/nptl/stdio-lock.h
+++ b/sysdeps/nptl/stdio-lock.h
@@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
 	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
 	= (_fp);							      \
     _IO_flockfile (_IO_acquire_lock_file);
-#  define _IO_acquire_lock_clear_flags2(_fp) \
-  do {									      \
-    FILE *_IO_acquire_lock_file						      \
-	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
-	= (_fp);							      \
-    _IO_flockfile (_IO_acquire_lock_file);
 # else
 #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
 # endif
 # define _IO_release_lock(_fp) ; } while (0)
 
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
                   ` (5 preceding siblings ...)
  2018-11-15 21:46 ` [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Gabriel F. T. Gomes
@ 2018-11-15 21:53 ` Gabriel F. T. Gomes
  2018-11-22 18:13   ` Adhemerval Zanella
  2018-12-02 11:53 ` [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Florian Weimer
  7 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-15 21:53 UTC (permalink / raw)
  To: libc-alpha

From: Zack Weinberg <zackw@panix.com>

Changed since v2:

  - Removed #ifdef ASSEMBLER since no longer used.

Changed since v1:

  - Removed libc_hidden_def and libc_hidden_proto from all of the
    __nldbl_*printf* function, since they are no longer called from
    within glibc, only from nldbl-*printf*.c files (libnldbl_nonshared.a)

-- 8< --
After all that prep work, nldbl-compat.c can now use PRINTF_LDBL_IS_DBL
instead of __no_long_double to control the behavior of printf-like
functions; this is the last thing we needed __no_long_double for, so it
can go away entirely.

Tested for powerpc and powerpc64le.

2018-10-25  Zack Weinberg  <zackw@panix.com>
	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>

	* stdio-common/vfprintf-internal.c
	(__vfprintf_internal, __vfwprintf_internal): Don't use __ldbl_is_dbl.
	* sysdeps/generic/math_ldbl_opt.h: Remove __ldbl_is_dbl.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h: Remove __ldbl_is_dbl
	and __no_long_double.
	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.c: Remove file.
	* sysdeps/ieee754/ldbl-opt/Makefile (routines): Remove math_ldbl_opt.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Remove
	libc_hidden_proto and libc_hidden_def from all __nldbl_*printf*
	and __nldbl_*syslog* functions.
	(__nldbl_cleanup, set_no_long_double, clear_no_long_double): Remove.
	(__nldbl___asprintf, __nldbl_dprintf, __nldbl_fprintf)
	(__nldbl_fwprintf, __nldbl_printf, __nldbl_sprintf)
	(__nldbl_vfprintf, __nldbl___vsprintf, __nldbl_obstack_vprintf)
	(__ndlbl_obstack_printf, __nldbl_snprintf, __nldbl_swprintf)
	(__nldbl_vasprintf, __nldbl_vdprintf, __nldbl_vfwprintf)
	(__nldbl_vprintf, __nldbl_vsnprintf, __ndlbl_vswprintf)
	(__nldbl_vwprintf, __nldbl_wprintf):
	Directly call the appropriate __v*printf_internal routine, passing
	PRINTF_LDBL_IS_DBL.  Do not mess with __no_long_double. Normalize
	variable names.
	(__nldbl___fprintf_chk, __nldbl___fwprintf_chk)
	(__nldbl___printf_chk, __nldbl___snprintf_chk)
	(__nldbl___sprintf_chk, __nldbl___swprintf_chk)
	(__nldbl___vfprintf_chk, __nldbl___vfwprintf_chk)
	(__nldbl___vprintf_chk, __nldbl___vsnprintf_chk)
	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
	(__nldbl___vwprintf_chk, __nldbl___wprintf_chk)
	(__nldbl___vasprintf_chk, __nldbl___asprintf_chk)
	(__nldbl___vdprintf_chk, __nldbl___dprintf_chk)
	(__nldbl___obstack_vprintf_chk, __nldbl___obstack_printf_chk):
	Likewise, and also pass PRINTF_FORTIFY when appropriate.
	(__nldbl_syslog, __nldbl_vsyslog):
	Directly call __vsyslog_internal, passing PRINTF_LDBL_IS_DBL.
	(__nldbl_syslog_chk): Likewise, and also pass PRINTF_FORTIFY when
	appropriate.
	(__nldbl_vsyslog_chk): Likewise, and also pass PRINTF_FORTIFY when
	appropriate.
---
 stdio-common/vfprintf-internal.c         |   4 -
 sysdeps/generic/math_ldbl_opt.h          |   1 -
 sysdeps/ieee754/ldbl-opt/Makefile        |   2 +-
 sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |   7 -
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c  | 504 +++++++++++++++----------------
 5 files changed, 238 insertions(+), 280 deletions(-)

diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index 4cc4261ead..61769e0ce1 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1280,10 +1280,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
      0 if unknown.  */
   int readonly_format = 0;
 
-  /* Temporarily honor environmental settings.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= PRINTF_LDBL_IS_DBL;
-
   /* Orient the stream.  */
 #ifdef ORIENT
   ORIENT;
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 92f670dff7..fbd2c82e2f 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -15,4 +15,3 @@
 #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
 #define ldbl_compat_symbol(lib, local, symbol, version) \
   compat_symbol (lib, local, symbol, version)
-#define __ldbl_is_dbl 0
diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index 6854413fa3..64fdb8cb9e 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -8,7 +8,7 @@ endif
 
 ifeq ($(subdir),math)
 libm-routines += s_nexttowardfd
-routines += math_ldbl_opt nldbl-compat
+routines += nldbl-compat
 
 extra-libs += libnldbl
 libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index 1c49036f7b..cbe8156e39 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -40,10 +40,3 @@
   weak_alias (local, symbol)
 # endif
 #endif
-
-#ifndef __ASSEMBLER__
-/* Set temporarily to non-zero if long double should be considered
-   the same as double.  */
-extern __thread int __no_long_double attribute_tls_model_ie attribute_hidden;
-# define __ldbl_is_dbl __builtin_expect (__no_long_double, 0)
-#endif
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 59b2c9fcdd..f6dd81759d 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -30,43 +30,15 @@
 
 #include "nldbl-compat.h"
 
-libc_hidden_proto (__nldbl_vfprintf)
 libc_hidden_proto (__nldbl_vsscanf)
-libc_hidden_proto (__nldbl_vsprintf)
 libc_hidden_proto (__nldbl_vfscanf)
 libc_hidden_proto (__nldbl_vfwscanf)
-libc_hidden_proto (__nldbl_vdprintf)
 libc_hidden_proto (__nldbl_vswscanf)
-libc_hidden_proto (__nldbl_vfwprintf)
-libc_hidden_proto (__nldbl_vswprintf)
-libc_hidden_proto (__nldbl_vsnprintf)
-libc_hidden_proto (__nldbl_vasprintf)
-libc_hidden_proto (__nldbl_obstack_vprintf)
-libc_hidden_proto (__nldbl___vfwprintf_chk)
-libc_hidden_proto (__nldbl___vsnprintf_chk)
-libc_hidden_proto (__nldbl___vfprintf_chk)
-libc_hidden_proto (__nldbl___vsyslog_chk)
-libc_hidden_proto (__nldbl___vsprintf_chk)
-libc_hidden_proto (__nldbl___vswprintf_chk)
-libc_hidden_proto (__nldbl___vasprintf_chk)
-libc_hidden_proto (__nldbl___vdprintf_chk)
-libc_hidden_proto (__nldbl___obstack_vprintf_chk)
 libc_hidden_proto (__nldbl___isoc99_vsscanf)
 libc_hidden_proto (__nldbl___isoc99_vfscanf)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
 libc_hidden_proto (__nldbl___isoc99_vfwscanf)
 
-static void
-__nldbl_cleanup (void *arg)
-{
-  __no_long_double = 0;
-}
-
-#define set_no_long_double() \
-  __libc_cleanup_push (__nldbl_cleanup, NULL); __no_long_double = 1
-#define clear_no_long_double() \
-  __no_long_double = 0; __libc_cleanup_pop (0)
-
 /* Compatibility with IEEE double as long double.
    IEEE quad long double is used by default for most programs, so
    we don't need to split this into one file per function for the
@@ -76,14 +48,14 @@ int
 attribute_compat_text_section
 __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vasprintf (string_ptr, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (string_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl___asprintf, __nldbl_asprintf)
 
@@ -91,28 +63,28 @@ int
 attribute_compat_text_section
 __nldbl_dprintf (int d, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vdprintf (d, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_fprintf (FILE *stream, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
 
@@ -120,28 +92,28 @@ int
 attribute_compat_text_section weak_function
 __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_printf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_printf, __nldbl__IO_printf)
 
@@ -149,14 +121,14 @@ int
 attribute_compat_text_section
 __nldbl_sprintf (char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsprintf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_sprintf, __nldbl__IO_sprintf)
 
@@ -164,123 +136,93 @@ int
 attribute_compat_text_section
 __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
 {
-  int done;
-  set_no_long_double ();
-  done = __vfprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return done;
+  return __vfprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vfprintf)
 strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
 
 int
 attribute_compat_text_section
 __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __vsprintf_internal (string, -1, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __vsprintf_internal (string, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
 weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
-libc_hidden_def (__nldbl_vsprintf)
 
 int
 attribute_compat_text_section
 __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
 			 va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_obstack_vprintf)
 
 int
 attribute_compat_text_section
 __nldbl_obstack_printf (struct obstack *obstack, const char *fmt, ...)
 {
-  int result;
+  int ret;
   va_list ap;
   va_start (ap, fmt);
-  result = __nldbl_obstack_vprintf (obstack, fmt, ap);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
-  return result;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_snprintf (char *s, size_t maxlen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsnprintf (s, maxlen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vswprintf (s, n, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, n, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vasprintf_internal (result_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vasprintf)
 
 int
 attribute_compat_text_section
-__nldbl_vdprintf (int d, const char *fmt, va_list arg)
+__nldbl_vdprintf (int d, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, 0);
-  clear_no_long_double ();
-  return res;
+  return __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vdprintf)
 
 int
 attribute_compat_text_section weak_function
 __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfwprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vfwprintf)
 
 int
 attribute_compat_text_section
 __nldbl_vprintf (const char *fmt, va_list ap)
 {
-  return __nldbl_vfprintf (stdout, fmt, ap);
+  return __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
@@ -288,13 +230,8 @@ attribute_compat_text_section
 __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vsnprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vsnprintf)
 weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
 
 int
@@ -302,33 +239,28 @@ attribute_compat_text_section weak_function
 __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vswprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl_vswprintf)
 
 int
 attribute_compat_text_section
 __nldbl_vwprintf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl_vfwprintf (stdout, fmt, ap);
+  return __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_wprintf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
@@ -491,42 +423,51 @@ int
 attribute_compat_text_section
 __nldbl___fprintf_chk (FILE *stream, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___printf_chk (int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
@@ -534,74 +475,94 @@ attribute_compat_text_section
 __nldbl___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
 			const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
 
-  va_start (arg, fmt);
-  done = __nldbl___vsnprintf_chk (s, maxlen, flag, slen, fmt, arg);
-  va_end (arg);
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  return done;
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
+
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___sprintf_chk (char *s, int flag, size_t slen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (slen == 0)
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vsprintf_chk (s, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, slen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
+__nldbl___swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
 			const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vswprintf_chk (s, n, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (s, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vfprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (s, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vfwprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___vprintf_chk (int flag, const char *fmt, va_list ap)
 {
-  return __nldbl___vfprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
@@ -612,14 +573,12 @@ __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsnprintf_internal (string, maxlen, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vsnprintf_chk)
 
 int
 attribute_compat_text_section
@@ -629,14 +588,12 @@ __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
   if (slen == 0)
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsprintf_internal (string, slen, fmt, ap,
-			     (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsprintf_internal (string, slen, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vsprintf_chk)
 
 int
 attribute_compat_text_section
@@ -646,116 +603,125 @@ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vswprintf_internal (string, maxlen, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vswprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___vwprintf_chk (int flag, const wchar_t *fmt, va_list ap)
 {
-  return __nldbl___vfwprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
 attribute_compat_text_section
 __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
+__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (ptr, fmt, arg,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (ptr, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vasprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___asprintf_chk (char **ptr, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vasprintf_chk (ptr, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (ptr, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
+__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vdprintf_internal (d, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___vdprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___dprintf_chk (int d, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vdprintf_chk (d, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
-			       const char *fmt, va_list arg)
+			       const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __obstack_vprintf_internal (obstack, fmt, arg,
-				    (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __obstack_vprintf_internal (obstack, fmt, ap, mode);
 }
-libc_hidden_def (__nldbl___obstack_vprintf_chk)
 
 int
 attribute_compat_text_section
 __nldbl___obstack_printf_chk (struct obstack *obstack, int flag,
 			      const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___obstack_vprintf_chk (obstack, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 extern __typeof (printf_size) __printf_size;
@@ -837,18 +803,28 @@ __nldbl_syslog (int pri, const char *fmt, ...)
 {
   va_list ap;
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
 }
 
+void
+attribute_compat_text_section
+__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
+{
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
+}
+
 void
 attribute_compat_text_section
 __nldbl___syslog_chk (int pri, int flag, const char *fmt, ...)
 {
   va_list ap;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, flag, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
   va_end(ap);
 }
 
@@ -856,17 +832,11 @@ void
 attribute_compat_text_section
 __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
 {
-  set_no_long_double ();
-  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-}
-libc_hidden_def (__nldbl___vsyslog_chk)
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-void
-attribute_compat_text_section
-__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
-{
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
 }
 
 int
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-11-15 21:46 ` [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal " Gabriel F. T. Gomes
@ 2018-11-16 18:34   ` Gabriel F. T. Gomes
  2018-11-22 17:35   ` Adhemerval Zanella
  1 sibling, 0 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-11-16 18:34 UTC (permalink / raw)
  To: libc-alpha

On Thu, 15 Nov 2018, Gabriel F. T. Gomes wrote:

>-	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
>+	  if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))

This should have been:

  if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) != 0))

Fixed locally.  Sorry about that.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-11-15 21:46 ` [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal " Gabriel F. T. Gomes
  2018-11-16 18:34   ` Gabriel F. T. Gomes
@ 2018-11-22 17:35   ` Adhemerval Zanella
  2018-12-04 15:15     ` Gabriel F. T. Gomes
  1 sibling, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:35 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changed since v2:
> 
>   - Expand comments about SCANF_LDBL_IS_DBL and SCANF_ISOC99_A.
>   - Remove parameter-less macros LDBL_DISTINCT and USE_ISOC99_A.  Paste
>     their code directly where it is used.
>   - Use Static_assert rather than `...' in ldbl_compat_symbol.
>   - Fix copyright statements.

The patch looks ok with the exception of the part where it adapts some symbol
to set _IO_FLAGS2_SCANF_STD on _flags2 *without* acquiring the lock previously.
I also see the idea of second patch is also to get rid of such mechanism, so
maybe one option is to combine both patches.

> 
> Changed since v1:
> 
>   - Added one line comment to new files.
>   - In nldbl-compat.c, added explanation for the need to use
>     '#if SHLIB_COMPAT' within 'if LONG_DOUBLE_COMPAT'.  Also moved the
>     block further down, for stylistic reasons [1].
>   - Added attribute_hidden to the internal (libioP.h) declarations of
>     __vfscanf_internal and __vfwscanf_internal [2].
>   - Added comment explaining the reason for the use of SHLIB_COMPAT on
>     stdio-common/iovfscanf.c and stdio-common/iovfwscanf.c.
>   - Converted the definition of ldbl_compat_symbol from an expansion of
>     compat_symbol to '...', because ldbl_compat_symbol is also not
>     supposed to be used outside of '#if SHLIB_COMPAT' statements.  In my
>     opinion, it's better to make this clear in the definition of
>     ldbl_compat_symbol itself, rather than having to go to the
>     definition of compat_symbol to learn this (if people think that this
>     is not the best option, I can revert this change (In that case, the
>     definition of ldbl_compat_symbol could be moved outside the '#if
>     SHARED' block).  Added a comment with this explanation.
>   - Added signed-off-by statements.
>   - Replaced 2.28 with 2.29 to adjust for the next release.
> 
> Not changed since v1:
> 
>   - Florian suggested that the need for ldbl_compat_symbol is
>     questionable, because we could define LONG_DOUBLE_COMPAT_VERSION to
>     GLIBC_2_0 by default (pretending that the long double transition
>     happened for all other platforms), then use it in compat_symbol
>     calls, which would create the compat symbols for _IO_vfscanf and
>     _IO_vfwscanf with that version.
>     That would work, because all the functions that will use
>     ldbl_compat_symbol after this patch set were actually introduced
>     before GLIBC_2_0.  However, for newer functions, such as swscanf,
>     that wouldn't work, if we ever need to do something similar.
> 
> Additional note for review:
> 
>   - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
>     original patch would be vey hard, because git doesn't detect the
>     filename change.  To make review a little easier, I did as Zack did
>     and manually edited the diff.  I'll reply to this thread and attach
>     the original patch if someone wants to apply it.
>     (ping me if I forget it)
> 
> [1] https://sourceware.org/ml/libc-alpha/2018-03/msg00309.html
> 
> [2] As a result, internal calls to __vfscanf_internal, on powerpc, do
>     not use the PLT, the following blocks show the difference:
> 
>     Without __attribute__ (hidden):
>       $ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
>       0014ea00 <__nldbl___vfscanf>:
>         14ea00:       94 21 ff f0     stwu    r1,-16(r1)
>         14ea04:       38 c0 00 01     li      r6,1
>         14ea08:       7c 08 02 a6     mflr    r0
>         14ea0c:       42 9f 00 05     bcl     20,4*cr7+so,14ea10 <__nldbl___vfscanf+0x10>
>         14ea10:       93 c1 00 08     stw     r30,8(r1)
>         14ea14:       90 01 00 14     stw     r0,20(r1)
>         14ea18:       7f c8 02 a6     mflr    r30
>         14ea1c:       3f de 00 05     addis   r30,r30,5
>         14ea20:       3b de 15 e4     addi    r30,r30,5604
>         14ea24:       4b f0 b8 0d     bl      5a230 <__vfscanf_internal>
>         14ea28:       80 01 00 14     lwz     r0,20(r1)
>         14ea2c:       83 c1 00 08     lwz     r30,8(r1)
>         14ea30:       38 21 00 10     addi    r1,r1,16
>         14ea34:       7c 08 03 a6     mtlr    r0
>         14ea38:       4e 80 00 20     blr
>         14ea3c:       60 00 00 00     nop
> 
>     With __attribute__ (hidden):
>       $ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
>       0014e8b0 <__nldbl___vfscanf>:
>         14e8b0:       38 c0 00 01     li      r6,1
>         14e8b4:       4b f0 b8 bc     b       5a170 <__vfscanf_internal>
>         14e8b8:       60 00 00 00     nop
>         14e8bc:       60 00 00 00     nop
> 
> -- 8< --
> There are two flags currently defined: SCANF_LDBL_IS_DBL is the mode
> used by __nldbl_ scanf variants, and SCANF_ISOC99_A is the mode used
> by __isoc99_ scanf variants.  In this patch, the new functions honor
> these flag bits if they're set, but they still also look at the
> corresponding bits of environmental state, and callers all pass zero.
> 
> The new functions do *not* have the "errp" argument possessed by
> _IO_vfscanf and _IO_vfwscanf.  All internal callers passed NULL for
> that argument.  External callers could theoretically exist, so I
> preserved wrappers, but they are flagged as compat symbols and they
> don't preserve the three-way distinction among types of errors that
> was formerly exposed.  These functions probably should have been in
> the list of deprecated _IO_ symbols in 2.27 NEWS -- they're not just
> aliases for vfscanf and vfwscanf.
> 
> (It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
> Please check that part of the patch very carefully, I am still not
> confident I understand all of the details of ldbl-opt.)
> 
> This patch also introduces helper inlines in libio/strfile.h that
> encapsulate the process of initializing an _IO_strfile object for
> reading.  This allows us to call __vfscanf_internal directly from
> sscanf, and __vfwscanf_internal directly from swscanf, without
> duplicating the initialization code.  (Previously, they called their
> v-counterparts, but that won't work if we want to control *both* C99
> mode and ldbl-is-dbl mode using the flags argument to__vfscanf_internal.)
> It's still a little awkward, especially for wide strfiles, but it's
> much better than what we had.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
> 	(__vfscanf_internal, __vfwscanf_internal): New function prototypes.
> 	* libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
> 	* libio/strfile.h: Add multiple inclusion guard.
> 	(_IO_strfile_read, _IO_strfile_readw): New inline functions.
> 
> 	* sysdeps/generic/math_ldbl_opt.h: Include shlib-compat.h, for
> 	consistency with the other version of this file.
> 	(ldbl_compat_symbol): New macro.
> 	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h (ldbl_compat_symbol):
> 	New macro.
> 
> 	* stdio-common/vfscanf-internal.c: Rename from vfscanf.c.
> 	Define __vfscanf_internal or __vfwscanf_internal, depending on
> 	COMPILE_WSCANF; don't define any other public symbols.
> 	Remove errval and code to set errp.
> 	Temporarily check __ldbl_is_dbl and _IO_FLAGS2_SCANF_STD as well
> 	as the mode_flags argument.
> 	(encode_error, conv_error, input_error): Don't set errval.
> 	* stdio-common/vfwscanf-internal.c: Rename from vfwscanf.c.
> 	Include vfscanf-internal.c.
> 	* stdio-common/vfscanf.c: New file defining the public entry
> 	point vfscanf, which calls __vfscanf_internal.
> 	* stdio-common/vfwscanf.c: New file defining the public entry
> 	point vfwscanf, which calls __vfwscanf_internal.
> 
> 	* stdio-common/iovfscanf.c: New file.
> 	* stdio-common/iovfwscanf.c: Likewise.
> 
> 	* stdio-common/Makefile (routines): Add vfscanf-internal,
> 	vfwscanf-internal, iovfscanf, iovfwscanf.
> 	* stdio-common/Versions: Mention GLIBC_2.29, so that
> 	it can be used in SHLIB_COMPAT expressions.
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl__IO_vfscanf):
> 	Wrap definition and compat_symbol line in #if SHLIB_COMPAT.
> 	Call __vfscanf_internal, instead of _IO_vfscanf.
> 	(__nldbl___vfscanf): Call __vfscanf_internal, instead of
> 	_IO_vfscanf.
> 	(__nldbl_vfwscanf): Call __vfwscanf_internal, instead of
> 	_IO_vfwscanf.
> 
> 	* libio/iovsscanf.c: Clean up includes, when possible.  Use
> 	_IO_strfile_read or _IO_strfile_readw, when needed.  Call
> 	__vfscanf_internal or __vfwscanf_internal directly.
> 	* libio/iovswscanf.c: Likewise.
> 	* libio/swscanf.c: Likewise.
> 	* libio/vscanf.c: Likewise.
> 	* libio/vwscanf.c: Likewise.
> 	* libio/wscanf.c: Likewise.
> 	* stdio-common/isoc99_fscanf.c: Likewise.
> 	* stdio-common/isoc99_scanf.c: Likewise.
> 	* stdio-common/isoc99_sscanf.c: Likewise.
> 	* stdio-common/isoc99_vfscanf.c: Likewise.
> 	* stdio-common/isoc99_vscanf.c: Likewise.
> 	* stdio-common/isoc99_vsscanf.c: Likewise.
> 	* stdio-common/scanf.c: Likewise.
> 	* stdio-common/sscanf.c: Likewise.
> 	* wcsmbs/isoc99_fwscanf.c: Likewise.
> 	* wcsmbs/isoc99_swscanf.c: Likewise.
> 	* wcsmbs/isoc99_vfwscanf.c: Likewise.
> 	* wcsmbs/isoc99_vswscanf.c: Likewise.
> 	* wcsmbs/isoc99_vwscanf.c: Likewise.
> 	* wcsmbs/isoc99_wscanf.c: Likewise.
> ---
>  libio/iovsscanf.c                              |   12 +-
>  libio/iovswscanf.c                             |   14 +-
>  libio/libio.h                                  |    1 -
>  libio/libioP.h                                 |   22 +
>  libio/strfile.h                                |   33 +-
>  libio/swscanf.c                                |   10 +-
>  libio/vscanf.c                                 |    2 +-
>  libio/vwscanf.c                                |    2 +-
>  libio/wscanf.c                                 |    2 +-
>  stdio-common/Makefile                          |    3 +-
>  stdio-common/Versions                          |    3 +
>  stdio-common/{isoc99_scanf.c => iovfscanf.c}   |   36 +-
>  stdio-common/{isoc99_scanf.c => iovfwscanf.c}  |   36 +-
>  stdio-common/isoc99_fscanf.c                   |    2 +-
>  stdio-common/isoc99_scanf.c                    |    2 +-
>  stdio-common/isoc99_sscanf.c                   |    9 +-
>  stdio-common/isoc99_vfscanf.c                  |    2 +-
>  stdio-common/isoc99_vscanf.c                   |    2 +-
>  stdio-common/isoc99_vsscanf.c                  |   17 +-
>  stdio-common/scanf.c                           |    2 +-
>  stdio-common/sscanf.c                          |   12 +-
>  stdio-common/{vfscanf.c => vfscanf-internal.c} |   48 +-
>  stdio-common/vfscanf.c                         | 3042 +-----------------------
>  stdio-common/vfwscanf-internal.c               |    2 +
>  stdio-common/vfwscanf.c                        |   28 +-
>  sysdeps/generic/math_ldbl_opt.h                |    4 +
>  sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h       |    6 +
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c        |   17 +-
>  wcsmbs/isoc99_fwscanf.c                        |    2 +-
>  wcsmbs/isoc99_swscanf.c                        |   12 +-
>  wcsmbs/isoc99_vfwscanf.c                       |    2 +-
>  wcsmbs/isoc99_vswscanf.c                       |   16 +-
>  wcsmbs/isoc99_vwscanf.c                        |    2 +-
>  wcsmbs/isoc99_wscanf.c                         |    2 +-
>  34 files changed, 204 insertions(+), 3203 deletions(-)
>  copy stdio-common/{isoc99_scanf.c => iovfscanf.c} (54%)
>  copy stdio-common/{isoc99_scanf.c => iovfwscanf.c} (54%)
>  copy stdio-common/{vfscanf.c => vfscanf-internal.c} (98%)
>  create mode 100644 stdio-common/vfwscanf-internal.c
> 
> diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
> index e56ab8bd7d..ee6a99ec6a 100644
> --- a/libio/iovsscanf.c
> +++ b/libio/iovsscanf.c
> @@ -24,22 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include "libioP.h"
>  #include "strfile.h"
>  
>  int
>  _IO_vsscanf (const char *string, const char *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_read (&sf, string);
> +  return __vfscanf_internal (f, format, args, 0);
>  }
>  ldbl_weak_alias (_IO_vsscanf, __vsscanf)
>  ldbl_weak_alias (_IO_vsscanf, vsscanf)

Ok.

> diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
> index 5bd1c88412..cb9cbe15cc 100644
> --- a/libio/iovswscanf.c
> +++ b/libio/iovswscanf.c
> @@ -24,24 +24,16 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include "libioP.h"
> -#include "strfile.h"
>  #include <wchar.h>
> +#include "strfile.h"
>  
>  int
>  __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> -  _IO_fwide (&sf._sbf._f, 1);
> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
> +  return __vfwscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__vswscanf)
>  ldbl_hidden_def (__vswscanf, vswscanf)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index 00f9169613..d4eba2df54 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
>  libc_hidden_proto (_IO_putc)
>  libc_hidden_proto (_IO_sgetn)
>  libc_hidden_proto (_IO_vfprintf)
> -libc_hidden_proto (_IO_vfscanf)
>  
>  #ifdef _IO_MTSAFE_IO
>  # undef _IO_peekc

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index df2633d858..525dce19ee 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -704,6 +704,28 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
>  
>  #endif /* _G_HAVE_MMAP */
>  
> +/* Flags for __vfscanf_internal and __vfwscanf_internal.
> +
> +   SCANF_LDBL_IS_DBL indicates whether long double values are to be
> +   handled as having the same format as double, in which case the flag
> +   should be set to one, or as another format, otherwise.
> +
> +   SCANF_ISOC99_A, when set to one, indicates that the ISO C99 or POSIX
> +   behavior of the scanf functions is to be used, i.e. automatic
> +   allocation for input strings with %as, %aS and %a[, a GNU extension,
> +   is disabled. This is the behavior that the __isoc99_scanf family of
> +   functions use.  When the flag is set to zero, automatic allocation is
> +   enabled.  */
> +#define SCANF_LDBL_IS_DBL 0x0001
> +#define SCANF_ISOC99_A    0x0002
> +
> +extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
> +			       unsigned int flags)
> +  attribute_hidden;
> +extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
> +				unsigned int flags)
> +  attribute_hidden;
> +
>  extern int _IO_vscanf (const char *, va_list) __THROW;
>  
>  #ifdef _IO_MTSAFE_IO

Ok.

> diff --git a/libio/strfile.h b/libio/strfile.h
> index 75caac2af5..62900a7128 100644
> --- a/libio/strfile.h
> +++ b/libio/strfile.h
> @@ -24,7 +24,9 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <stdio.h>
> +#ifndef STRFILE_H_
> +#define STRFILE_H_
> +
>  #include "libioP.h"
>  
>  typedef void *(*_IO_alloc_type) (size_t);
> @@ -80,3 +82,32 @@ typedef struct
>  } _IO_wstrnfile;
>  
>  extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
> +
> +/* Initialize an _IO_strfile SF to read from narrow string STRING, and
> +   return the corresponding FILE object.  It is not necessary to fclose
> +   the FILE when it is no longer needed.  */
> +static inline FILE *
> +_IO_strfile_read (_IO_strfile *sf, const char *string)
> +{
> +  sf->_sbf._f._lock = NULL;
> +  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> +  _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
> +  _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
> +  return &sf->_sbf._f;
> +}
> +
> +/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
> +   string STRING, and return the corresponding FILE object.  It is not
> +   necessary to fclose the FILE when it is no longer needed.  */
> +static inline FILE *
> +_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
> +                   const wchar_t *string)
> +{
> +  sf->_sbf._f._lock = NULL;
> +  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
> +  _IO_fwide (&sf->_sbf._f, 1);
> +  _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
> +  return &sf->_sbf._f;
> +}
> +
> +#endif /* strfile.h.  */

Ok.

> diff --git a/libio/swscanf.c b/libio/swscanf.c
> index c8686bcbaf..90f721cc51 100644
> --- a/libio/swscanf.c
> +++ b/libio/swscanf.c
> @@ -15,20 +15,22 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <wchar.h>
> +#include "strfile.h"
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __swscanf (const wchar_t *s, const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
>  
>    va_start (arg, format);
> -  done = __vswscanf (s, format, arg);
> +  done = __vfwscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/vscanf.c b/libio/vscanf.c
> index 9c27122c27..a3e2dd43f2 100644
> --- a/libio/vscanf.c
> +++ b/libio/vscanf.c
> @@ -32,6 +32,6 @@
>  int
>  _IO_vscanf (const char *format, va_list args)
>  {
> -  return _IO_vfscanf (_IO_stdin, format, args, NULL);
> +  return __vfscanf_internal (_IO_stdin, format, args, 0);
>  }
>  ldbl_weak_alias (_IO_vscanf, vscanf)

Ok.

> diff --git a/libio/vwscanf.c b/libio/vwscanf.c
> index 0d5f558758..7af770c8c3 100644
> --- a/libio/vwscanf.c
> +++ b/libio/vwscanf.c
> @@ -30,6 +30,6 @@
>  int
>  __vwscanf (const wchar_t *format, va_list args)
>  {
> -  return _IO_vfwscanf (_IO_stdin, format, args, NULL);
> +  return __vfwscanf_internal (_IO_stdin, format, args, 0);
>  }
>  ldbl_strong_alias (__vwscanf, vwscanf)

Ok.

> diff --git a/libio/wscanf.c b/libio/wscanf.c
> index c8cdad0acd..fe27ff6fa6 100644
> --- a/libio/wscanf.c
> +++ b/libio/wscanf.c
> @@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stdin, format, arg, NULL);
> +  done = __vfwscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index a10f12ab3c..f3b3ceddbd 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -39,7 +39,8 @@ routines	:=							      \
>  	flockfile ftrylockfile funlockfile				      \
>  	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
>  	isoc99_vsscanf							      \
> -	psiginfo gentempfd
> +	psiginfo gentempfd						      \
> +	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
>  
>  aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
>  

Ok.

> diff --git a/stdio-common/Versions b/stdio-common/Versions
> index b8217578c8..522f302198 100644
> --- a/stdio-common/Versions
> +++ b/stdio-common/Versions
> @@ -60,6 +60,9 @@ libc {
>    GLIBC_2.28 {
>      renameat2;
>    }
> +  GLIBC_2.29 {
> +    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) used in iovfscanf.c etc.
> +  }
>    GLIBC_PRIVATE {
>      # global variables
>      _itoa_lower_digits;

Ok.

> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfscanf.c
> similarity index 54%
> copy from stdio-common/isoc99_scanf.c
> copy to stdio-common/iovfscanf.c
> index bf7dbe86bb..77e698f665 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/iovfscanf.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Implementation and symbols for _IO_vfscanf.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
>  
>     The GNU C Library is free software; you can redistribute it and/or
> @@ -15,30 +16,23 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> +#include <shlib-compat.h>
>  
> +/* This function is provided for ports older than GLIBC 2.29 because
> +   external callers could theoretically exist.  Newer ports do not need,
> +   since it is not part of the API.  */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>  
> -/* Read formatted input from stdin according to the format string FORMAT.  */
> -/* VARARGS1 */
>  int
> -__isoc99_scanf (const char *format, ...)
> +attribute_compat_text_section
> +__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
>  {
> -  va_list arg;
> -  int done;
> -
> -#ifdef _IO_MTSAFE_IO
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -#endif
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
> -  va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> -  va_end (arg);
> +  int rv = __vfscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
>  
> -#ifdef _IO_MTSAFE_IO
> -  _IO_release_lock (stdin);
>  #endif
> -  return done;
> -}

Ok.

> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfwscanf.c
> similarity index 54%
> copy from stdio-common/isoc99_scanf.c
> copy to stdio-common/iovfwscanf.c
> index bf7dbe86bb..26a57788cb 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/iovfwscanf.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Implementation and symbols for _IO_vfwscanf.
> +   Copyright (C) 1991-2018 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
>  
>     The GNU C Library is free software; you can redistribute it and/or
> @@ -15,30 +16,23 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> +#include <shlib-compat.h>
>  
> +/* This function is provided for ports older than GLIBC 2.29 because
> +   external callers could theoretically exist.  Newer ports do not need,
> +   since it is not part of the API.  */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>  
> -/* Read formatted input from stdin according to the format string FORMAT.  */
> -/* VARARGS1 */
>  int
> -__isoc99_scanf (const char *format, ...)
> +attribute_compat_text_section
> +__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
>  {
> -  va_list arg;
> -  int done;
> -
> -#ifdef _IO_MTSAFE_IO
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -#endif
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
> -  va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> -  va_end (arg);
> +  int rv = __vfwscanf_internal (fp, format, ap, 0);
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (rv == -1);
> +  return rv;
> +}
> +compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
>  
> -#ifdef _IO_MTSAFE_IO
> -  _IO_release_lock (stdin);
>  #endif
> -  return done;
> -}

Ok.

> diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
> index 9cdf85e679..4210d11f2b 100644
> --- a/stdio-common/isoc99_fscanf.c
> +++ b/stdio-common/isoc99_fscanf.c
> @@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stream, format, arg, NULL);
> +  done = __vfscanf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stream);

Ok.

> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
> index bf7dbe86bb..64c873eed9 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/isoc99_scanf.c
> @@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> +  done = __vfscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>  #ifdef _IO_MTSAFE_IO

Ok.

> diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
> index 56a60a2c05..2c89a03fe9 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -16,19 +16,20 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_sscanf (const char *s, const char *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __isoc99_vsscanf (s, format, arg);
> +  done = __vfscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
Wouldn't be more consistent to fold the second patch in this set, which replace
_IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
removed in a subsequent patch?

> diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
> index b80e05f8db..c96ca831ae 100644
> --- a/stdio-common/isoc99_vfscanf.c
> +++ b/stdio-common/isoc99_vfscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stream);
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfscanf (stream, format, args, NULL);
> +  done = __vfscanf_internal (stream, format, args, 0);
>    _IO_release_lock (stream);
>    return done;
>  }

Ok.

> diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
> index 0b747f85ba..72ae72ddee 100644
> --- a/stdio-common/isoc99_vscanf.c
> +++ b/stdio-common/isoc99_vscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stdin);
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfscanf (stdin, format, args, NULL);
> +  done = __vfscanf_internal (stdin, format, args, 0);
>    _IO_release_lock (stdin);
>    return done;
>  }

Ok.

> diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
> index ac85ef2d0d..02bc0f50e6 100644
> --- a/stdio-common/isoc99_vsscanf.c
> +++ b/stdio-common/isoc99_vsscanf.c
> @@ -24,23 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <libioP.h>
> -#include <stdio.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>  
>  int
>  __isoc99_vsscanf (const char *string, const char *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_read (&sf, string);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> +  return __vfscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__isoc99_vsscanf)

As before I think it requires to acquire the file lock before setting
_flags2.

> diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
> index e61b5f1ad3..de38d70353 100644
> --- a/stdio-common/scanf.c
> +++ b/stdio-common/scanf.c
> @@ -30,7 +30,7 @@ __scanf (const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = _IO_vfscanf (stdin, format, arg, NULL);
> +  done = __vfscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
> index 88cd641798..e25e9c27a5 100644
> --- a/stdio-common/sscanf.c
> +++ b/stdio-common/sscanf.c
> @@ -16,26 +16,24 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __sscanf (const char *s, const char *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
>  
>    va_start (arg, format);
> -  done = __vsscanf (s, format, arg);
> +  done = __vfscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;
>  }
>  ldbl_hidden_def (__sscanf, sscanf)
>  ldbl_strong_alias (__sscanf, sscanf)
> -#undef _IO_sscanf
> -/* This is for libg++.  */
>  ldbl_strong_alias (__sscanf, _IO_sscanf)

Ok.

> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
> similarity index 98%
> copy from stdio-common/vfscanf.c
> copy to stdio-common/vfscanf-internal.c

Ok.

> index 1ce836a324..13a7a300b7 100644
> --- a/stdio-common/vfscanf.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Internal functions for the *scanf* implementation.
> +   Copyright (C) 1991-2018 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
>  
>     The GNU C Library is free software; you can redistribute it and/or
> @@ -132,16 +133,13 @@
>  #include "printf-parse.h" /* Use read_int.  */
>  
>  #define encode_error() do {						      \
> -			  errval = 4;					      \
>  			  __set_errno (EILSEQ);				      \
>  			  goto errout;					      \
>  			} while (0)
>  #define conv_error()	do {						      \
> -			  errval = 2;					      \
>  			  goto errout;					      \
>  			} while (0)
>  #define input_error()	do {						      \
> -			  errval = 1;					      \
>  			  if (done == 0) done = EOF;			      \
>  			  goto errout;					      \
>  			} while (0)
> @@ -267,12 +265,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
>     Return the number of assignments made, or -1 for an input error.  */
>  #ifdef COMPILE_WSCANF
>  int
> -_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
> -	      int *errp)
> +__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
> +                     unsigned int mode_flags)
>  #else
>  int
> -_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> -		      int *errp)
> +__vfscanf_internal (FILE *s, const char *format, va_list argptr,
> +                    unsigned int mode_flags)
>  #endif
>  {
>    va_list arg;
> @@ -283,7 +281,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    WINT_T c = 0;	/* Last char read.  */
>    int width;		/* Maximum field width.  */
>    int flags;		/* Modifiers for current format element.  */
> -  int errval = 0;
>  #ifndef COMPILE_WSCANF
>    locale_t loc = _NL_CURRENT_LOCALE;
>    struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
> @@ -335,6 +332,12 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    struct char_buffer charbuf;
>    scratch_buffer_init (&charbuf.scratch);
>  
> +  /* Temporarily honor the environmental mode bits.  */
> +  if (__ldbl_is_dbl)
> +    mode_flags |= SCANF_LDBL_IS_DBL;
> +  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> +    mode_flags |= SCANF_ISOC99_A;
> +>  #ifdef __va_copy
>    __va_copy (arg, argptr);
>  #else
> @@ -566,7 +569,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>  	    }
>  	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
>  	     supported at all.  */
> -	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> +	  if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))
>  	    {
>  	      --f;
>  	      break;
> @@ -2423,7 +2426,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>  	      done = EOF;
>  	      goto errout;
>  	    }
> -	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
> +	  if ((flags & LONGDBL) \
> +	      && __glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
>  	    {
>  	      long double d = __strtold_internal
>  		(char_buffer_start (&charbuf), &tw, flags & GROUP);
> @@ -3018,8 +3022,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    UNLOCK_STREAM (s);
>  
>    scratch_buffer_free (&charbuf.scratch);
> -  if (errp != NULL)
> -    *errp |= errval;
>  
>    if (__glibc_unlikely (done == EOF))
>      {
> @@ -3045,23 +3047,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
>      }
>    return done;
>  }
> -
> -#ifdef COMPILE_WSCANF
> -int
> -__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> -{
> -  return _IO_vfwscanf (s, format, argptr, NULL);
> -}
> -ldbl_weak_alias (__vfwscanf, vfwscanf)
> -#else
> -int
> -___vfscanf (FILE *s, const char *format, va_list argptr)
> -{
> -  return _IO_vfscanf_internal (s, format, argptr, NULL);
> -}
> -ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_strong_alias (___vfscanf, __vfscanf)
> -ldbl_hidden_def (___vfscanf, __vfscanf)
> -ldbl_weak_alias (___vfscanf, vfscanf)
> -#endif

Ok.

> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
> index 1ce836a324..5eedca8340 100644
> --- a/stdio-common/vfscanf.c
> +++ b/stdio-common/vfscanf.c

Another option instead of -M which might generate more consise patches in
case of rename plus small rewrites is the -B option. In this case, -B/90% 
avoid sending the full file removal and detect is has moved to another one
with some modifications.

> @@ -15,3053 +15,13 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <assert.h>
> -#include <errno.h>
> -#include <limits.h>
> -#include <ctype.h>
> -#include <stdarg.h>
> -#include <stdbool.h>
> -#include <stdio.h>
> -#include <stdint.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <wchar.h>
> -#include <wctype.h>
> -#include <libc-diag.h>
> -#include <libc-lock.h>
> -#include <locale/localeinfo.h>
> -#include <scratch_buffer.h>
> -
> -#ifdef	__GNUC__
> -# define HAVE_LONGLONG
> -# define LONGLONG	long long
> -#else
> -# define LONGLONG	long
> -#endif
> -
> -/* Determine whether we have to handle `long long' at all.  */
> -#if LONG_MAX == LONG_LONG_MAX
> -# define need_longlong	0
> -#else
> -# define need_longlong	1
> -#endif
> -
> -/* Determine whether we have to handle `long'.  */
> -#if INT_MAX == LONG_MAX
> -# define need_long	0
> -#else
> -# define need_long	1
> -#endif
> -
> -/* Those are flags in the conversion format. */
> -#define LONG		0x0001	/* l: long or double */
> -#define LONGDBL		0x0002	/* L: long long or long double */
> -#define SHORT		0x0004	/* h: short */
> -#define SUPPRESS	0x0008	/* *: suppress assignment */
> -#define POINTER		0x0010	/* weird %p pointer (`fake hex') */
> -#define NOSKIP		0x0020	/* do not skip blanks */
> -#define NUMBER_SIGNED	0x0040	/* signed integer */
> -#define GROUP		0x0080	/* ': group numbers */
> -#define GNU_MALLOC	0x0100	/* a: malloc strings */
> -#define CHAR		0x0200	/* hh: char */
> -#define I18N		0x0400	/* I: use locale's digits */
> -#define HEXA_FLOAT	0x0800	/* hexadecimal float */
> -#define READ_POINTER	0x1000	/* this is a pointer value */
> -#define POSIX_MALLOC	0x2000	/* m: malloc strings */
> -#define MALLOC		(GNU_MALLOC | POSIX_MALLOC)
> -
> -#include <locale/localeinfo.h>
>  #include <libioP.h>
>  
> -#ifdef COMPILE_WSCANF
> -# define ungetc(c, s)	((void) (c == WEOF				      \
> -				 || (--read_in,				      \
> -				     _IO_sputbackwc (s, c))))
> -# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
> -					 _IO_sputbackwc (s, c)))
> -# define inchar()	(c == WEOF ? ((errno = inchar_errno), WEOF)	      \
> -			 : ((c = _IO_getwc_unlocked (s)),		      \
> -			    (void) (c != WEOF				      \
> -				    ? ++read_in				      \
> -				    : (size_t) (inchar_errno = errno)), c))
> -
> -# define ISSPACE(Ch)	  iswspace (Ch)
> -# define ISDIGIT(Ch)	  iswdigit (Ch)
> -# define ISXDIGIT(Ch)	  iswxdigit (Ch)
> -# define TOLOWER(Ch)	  towlower (Ch)
> -# define ORIENT	  if (_IO_fwide (s, 1) != 1) return WEOF
> -# define __strtoll_internal	__wcstoll_internal
> -# define __strtoull_internal	__wcstoull_internal
> -# define __strtol_internal	__wcstol_internal
> -# define __strtoul_internal	__wcstoul_internal
> -# define __strtold_internal	__wcstold_internal
> -# define __strtod_internal	__wcstod_internal
> -# define __strtof_internal	__wcstof_internal
> -
> -# define L_(Str)	L##Str
> -# define CHAR_T		wchar_t
> -# define UCHAR_T	unsigned int
> -# define WINT_T		wint_t
> -# undef EOF
> -# define EOF		WEOF
> -#else
> -# define ungetc(c, s)	((void) ((int) c == EOF				      \
> -				 || (--read_in,				      \
> -				     _IO_sputbackc (s, (unsigned char) c))))
> -# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
> -					 _IO_sputbackc (s, (unsigned char) c)))
> -# define inchar()	(c == EOF ? ((errno = inchar_errno), EOF)	      \
> -			 : ((c = _IO_getc_unlocked (s)),		      \
> -			    (void) (c != EOF				      \
> -				    ? ++read_in				      \
> -				    : (size_t) (inchar_errno = errno)), c))
> -# define ISSPACE(Ch)	  __isspace_l (Ch, loc)
> -# define ISDIGIT(Ch)	  __isdigit_l (Ch, loc)
> -# define ISXDIGIT(Ch)	  __isxdigit_l (Ch, loc)
> -# define TOLOWER(Ch)	  __tolower_l ((unsigned char) (Ch), loc)
> -# define ORIENT	  if (_IO_vtable_offset (s) == 0			      \
> -			      && _IO_fwide (s, -1) != -1)		      \
> -			    return EOF
> -
> -# define L_(Str)	Str
> -# define CHAR_T		char
> -# define UCHAR_T	unsigned char
> -# define WINT_T		int
> -#endif
> -
> -#include "printf-parse.h" /* Use read_int.  */
> -
> -#define encode_error() do {						      \
> -			  errval = 4;					      \
> -			  __set_errno (EILSEQ);				      \
> -			  goto errout;					      \
> -			} while (0)
> -#define conv_error()	do {						      \
> -			  errval = 2;					      \
> -			  goto errout;					      \
> -			} while (0)
> -#define input_error()	do {						      \
> -			  errval = 1;					      \
> -			  if (done == 0) done = EOF;			      \
> -			  goto errout;					      \
> -			} while (0)
> -#define add_ptr_to_free(ptr)						      \
> -  do									      \
> -    {									      \
> -      if (ptrs_to_free == NULL						      \
> -	  || ptrs_to_free->count == (sizeof (ptrs_to_free->ptrs)	      \
> -				     / sizeof (ptrs_to_free->ptrs[0])))	      \
> -	{								      \
> -	  struct ptrs_to_free *new_ptrs = alloca (sizeof (*ptrs_to_free));    \
> -	  new_ptrs->count = 0;						      \
> -	  new_ptrs->next = ptrs_to_free;				      \
> -	  ptrs_to_free = new_ptrs;					      \
> -	}								      \
> -      ptrs_to_free->ptrs[ptrs_to_free->count++] = (ptr);		      \
> -    }									      \
> -  while (0)
> -#define ARGCHECK(s, format)						      \
> -  do									      \
> -    {									      \
> -      /* Check file argument for consistence.  */			      \
> -      CHECK_FILE (s, EOF);						      \
> -      if (s->_flags & _IO_NO_READS)					      \
> -	{								      \
> -	  __set_errno (EBADF);						      \
> -	  return EOF;							      \
> -	}								      \
> -      else if (format == NULL)						      \
> -	{								      \
> -	  __set_errno (EINVAL);						      \
> -	  return EOF;							      \
> -	}								      \
> -    } while (0)
> -#define LOCK_STREAM(S)							      \
> -  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, (S)); \
> -  _IO_flockfile (S)
> -#define UNLOCK_STREAM(S)						      \
> -  _IO_funlockfile (S);							      \
> -  __libc_cleanup_region_end (0)
> -
> -struct ptrs_to_free
> -{
> -  size_t count;
> -  struct ptrs_to_free *next;
> -  char **ptrs[32];
> -};
> -
> -struct char_buffer {
> -  CHAR_T *current;
> -  CHAR_T *end;
> -  struct scratch_buffer scratch;
> -};
> -
> -/* Returns a pointer to the first CHAR_T object in the buffer.  Only
> -   valid if char_buffer_add (BUFFER, CH) has been called and
> -   char_buffer_error (BUFFER) is false.  */
> -static inline CHAR_T *
> -char_buffer_start (const struct char_buffer *buffer)
> -{
> -  return (CHAR_T *) buffer->scratch.data;
> -}
> -
> -/* Returns the number of CHAR_T objects in the buffer.  Only valid if
> -   char_buffer_error (BUFFER) is false.  */
> -static inline size_t
> -char_buffer_size (const struct char_buffer *buffer)
> -{
> -  return buffer->current - char_buffer_start (buffer);
> -}
> -
> -/* Reinitializes BUFFER->current and BUFFER->end to cover the entire
> -   scratch buffer.  */
> -static inline void
> -char_buffer_rewind (struct char_buffer *buffer)
> -{
> -  buffer->current = char_buffer_start (buffer);
> -  buffer->end = buffer->current + buffer->scratch.length / sizeof (CHAR_T);
> -}
> -
> -/* Returns true if a previous call to char_buffer_add (BUFFER, CH)
> -   failed.  */
> -static inline bool
> -char_buffer_error (const struct char_buffer *buffer)
> -{
> -  return __glibc_unlikely (buffer->current == NULL);
> -}
> -
> -/* Slow path for char_buffer_add.  */
> -static void
> -char_buffer_add_slow (struct char_buffer *buffer, CHAR_T ch)
> -{
> -  if (char_buffer_error (buffer))
> -    return;
> -  size_t offset = buffer->end - (CHAR_T *) buffer->scratch.data;
> -  if (!scratch_buffer_grow_preserve (&buffer->scratch))
> -    {
> -      buffer->current = NULL;
> -      buffer->end = NULL;
> -      return;
> -    }
> -  char_buffer_rewind (buffer);
> -  buffer->current += offset;
> -  *buffer->current++ = ch;
> -}
> -
> -/* Adds CH to BUFFER.  This function does not report any errors, check
> -   for them with char_buffer_error.  */
> -static inline void
> -char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
> -  __attribute__ ((always_inline));
> -static inline void
> -char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
> -{
> -  if (__glibc_unlikely (buffer->current == buffer->end))
> -    char_buffer_add_slow (buffer, ch);
> -  else
> -    *buffer->current++ = ch;
> -}
> -
> -/* Read formatted input from S according to the format string
> -   FORMAT, using the argument list in ARG.
> -   Return the number of assignments made, or -1 for an input error.  */
> -#ifdef COMPILE_WSCANF
> -int
> -_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
> -	      int *errp)
> -#else
> -int
> -_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> -		      int *errp)
> -#endif
> -{
> -  va_list arg;
> -  const CHAR_T *f = format;
> -  UCHAR_T fc;	/* Current character of the format.  */
> -  WINT_T done = 0;	/* Assignments done.  */
> -  size_t read_in = 0;	/* Chars read in.  */
> -  WINT_T c = 0;	/* Last char read.  */
> -  int width;		/* Maximum field width.  */
> -  int flags;		/* Modifiers for current format element.  */
> -  int errval = 0;
> -#ifndef COMPILE_WSCANF
> -  locale_t loc = _NL_CURRENT_LOCALE;
> -  struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
> -#endif
> -
> -  /* Errno of last failed inchar call.  */
> -  int inchar_errno = 0;
> -  /* Status for reading F-P nums.  */
> -  char got_digit, got_dot, got_e, got_sign;
> -  /* If a [...] is a [^...].  */
> -  CHAR_T not_in;
> -#define exp_char not_in
> -  /* Base for integral numbers.  */
> -  int base;
> -  /* Decimal point character.  */
> -#ifdef COMPILE_WSCANF
> -  wint_t decimal;
> -#else
> -  const char *decimal;
> -#endif
> -  /* The thousands character of the current locale.  */
> -#ifdef COMPILE_WSCANF
> -  wint_t thousands;
> -#else
> -  const char *thousands;
> -#endif
> -  struct ptrs_to_free *ptrs_to_free = NULL;
> -  /* State for the conversions.  */
> -  mbstate_t state;
> -  /* Integral holding variables.  */
> -  union
> -    {
> -      long long int q;
> -      unsigned long long int uq;
> -      long int l;
> -      unsigned long int ul;
> -    } num;
> -  /* Character-buffer pointer.  */
> -  char *str = NULL;
> -  wchar_t *wstr = NULL;
> -  char **strptr = NULL;
> -  ssize_t strsize = 0;
> -  /* We must not react on white spaces immediately because they can
> -     possibly be matched even if in the input stream no character is
> -     available anymore.  */
> -  int skip_space = 0;
> -  /* Workspace.  */
> -  CHAR_T *tw;			/* Temporary pointer.  */
> -  struct char_buffer charbuf;
> -  scratch_buffer_init (&charbuf.scratch);
> -
> -#ifdef __va_copy
> -  __va_copy (arg, argptr);
> -#else
> -  arg = (va_list) argptr;
> -#endif
> -
> -#ifdef ORIENT
> -  ORIENT;
> -#endif
> -
> -  ARGCHECK (s, format);
> -
> - {
> -#ifndef COMPILE_WSCANF
> -   struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
> -#endif
> -
> -   /* Figure out the decimal point character.  */
> -#ifdef COMPILE_WSCANF
> -   decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
> -#else
> -   decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
> -#endif
> -   /* Figure out the thousands separator character.  */
> -#ifdef COMPILE_WSCANF
> -   thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> -   thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
> -   if (*thousands == '\0')
> -     thousands = NULL;
> -#endif
> - }
> -
> -  /* Lock the stream.  */
> -  LOCK_STREAM (s);
> -
> -
> -#ifndef COMPILE_WSCANF
> -  /* From now on we use `state' to convert the format string.  */
> -  memset (&state, '\0', sizeof (state));
> -#endif
> -
> -  /* Run through the format string.  */
> -  while (*f != '\0')
> -    {
> -      unsigned int argpos;
> -      /* Extract the next argument, which is of type TYPE.
> -	 For a %N$... spec, this is the Nth argument from the beginning;
> -	 otherwise it is the next argument after the state now in ARG.  */
> -#ifdef __va_copy
> -# define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
> -			 ({ unsigned int pos = argpos;			      \
> -			    va_list arg;				      \
> -			    __va_copy (arg, argptr);			      \
> -			    while (--pos > 0)				      \
> -			      (void) va_arg (arg, void *);		      \
> -			    va_arg (arg, type);				      \
> -			  }))
> -#else
> -# if 0
> -      /* XXX Possible optimization.  */
> -#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
> -			 ({ va_list arg = (va_list) argptr;		      \
> -			    arg = (va_list) ((char *) arg		      \
> -					     + (argpos - 1)		      \
> -					     * __va_rounded_size (void *));   \
> -			    va_arg (arg, type);				      \
> -			 }))
> -# else
> -#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
> -			 ({ unsigned int pos = argpos;			      \
> -			    va_list arg = (va_list) argptr;		      \
> -			    while (--pos > 0)				      \
> -			      (void) va_arg (arg, void *);		      \
> -			    va_arg (arg, type);				      \
> -			  }))
> -# endif
> -#endif
> -
> -#ifndef COMPILE_WSCANF
> -      if (!isascii ((unsigned char) *f))
> -	{
> -	  /* Non-ASCII, may be a multibyte.  */
> -	  int len = __mbrlen (f, strlen (f), &state);
> -	  if (len > 0)
> -	    {
> -	      do
> -		{
> -		  c = inchar ();
> -		  if (__glibc_unlikely (c == EOF))
> -		    input_error ();
> -		  else if (c != (unsigned char) *f++)
> -		    {
> -		      ungetc_not_eof (c, s);
> -		      conv_error ();
> -		    }
> -		}
> -	      while (--len > 0);
> -	      continue;
> -	    }
> -	}
> -#endif
> -
> -      fc = *f++;
> -      if (fc != '%')
> -	{
> -	  /* Remember to skip spaces.  */
> -	  if (ISSPACE (fc))
> -	    {
> -	      skip_space = 1;
> -	      continue;
> -	    }
> -
> -	  /* Read a character.  */
> -	  c = inchar ();
> -
> -	  /* Characters other than format specs must just match.  */
> -	  if (__glibc_unlikely (c == EOF))
> -	    input_error ();
> -
> -	  /* We saw white space char as the last character in the format
> -	     string.  Now it's time to skip all leading white space.  */
> -	  if (skip_space)
> -	    {
> -	      while (ISSPACE (c))
> -		if (__glibc_unlikely (inchar () == EOF))
> -		  input_error ();
> -	      skip_space = 0;
> -	    }
> -
> -	  if (__glibc_unlikely (c != fc))
> -	    {
> -	      ungetc (c, s);
> -	      conv_error ();
> -	    }
> -
> -	  continue;
> -	}
> -
> -      /* This is the start of the conversion string. */
> -      flags = 0;
> -
> -      /* Initialize state of modifiers.  */
> -      argpos = 0;
> -
> -      /* Prepare temporary buffer.  */
> -      char_buffer_rewind (&charbuf);
> -
> -      /* Check for a positional parameter specification.  */
> -      if (ISDIGIT ((UCHAR_T) *f))
> -	{
> -	  argpos = read_int ((const UCHAR_T **) &f);
> -	  if (*f == L_('$'))
> -	    ++f;
> -	  else
> -	    {
> -	      /* Oops; that was actually the field width.  */
> -	      width = argpos;
> -	      argpos = 0;
> -	      goto got_width;
> -	    }
> -	}
> -
> -      /* Check for the assignment-suppressing, the number grouping flag,
> -	 and the signal to use the locale's digit representation.  */
> -      while (*f == L_('*') || *f == L_('\'') || *f == L_('I'))
> -	switch (*f++)
> -	  {
> -	  case L_('*'):
> -	    flags |= SUPPRESS;
> -	    break;
> -	  case L_('\''):
> -#ifdef COMPILE_WSCANF
> -	    if (thousands != L'\0')
> -#else
> -	    if (thousands != NULL)
> -#endif
> -	      flags |= GROUP;
> -	    break;
> -	  case L_('I'):
> -	    flags |= I18N;
> -	    break;
> -	  }
> -
> -      /* Find the maximum field width.  */
> -      width = 0;
> -      if (ISDIGIT ((UCHAR_T) *f))
> -	width = read_int ((const UCHAR_T **) &f);
> -    got_width:
> -      if (width == 0)
> -	width = -1;
> -
> -      /* Check for type modifiers.  */
> -      switch (*f++)
> -	{
> -	case L_('h'):
> -	  /* ints are short ints or chars.  */
> -	  if (*f == L_('h'))
> -	    {
> -	      ++f;
> -	      flags |= CHAR;
> -	    }
> -	  else
> -	    flags |= SHORT;
> -	  break;
> -	case L_('l'):
> -	  if (*f == L_('l'))
> -	    {
> -	      /* A double `l' is equivalent to an `L'.  */
> -	      ++f;
> -	      flags |= LONGDBL | LONG;
> -	    }
> -	  else
> -	    /* ints are long ints.  */
> -	    flags |= LONG;
> -	  break;
> -	case L_('q'):
> -	case L_('L'):
> -	  /* doubles are long doubles, and ints are long long ints.  */
> -	  flags |= LONGDBL | LONG;
> -	  break;
> -	case L_('a'):
> -	  /* The `a' is used as a flag only if followed by `s', `S' or
> -	     `['.  */
> -	  if (*f != L_('s') && *f != L_('S') && *f != L_('['))
> -	    {
> -	      --f;
> -	      break;
> -	    }
> -	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
> -	     supported at all.  */
> -	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> -	    {
> -	      --f;
> -	      break;
> -	    }
> -	  /* String conversions (%s, %[) take a `char **'
> -	     arg and fill it in with a malloc'd pointer.  */
> -	  flags |= GNU_MALLOC;
> -	  break;
> -	case L_('m'):
> -	  flags |= POSIX_MALLOC;
> -	  if (*f == L_('l'))
> -	    {
> -	      ++f;
> -	      flags |= LONG;
> -	    }
> -	  break;
> -	case L_('z'):
> -	  if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
> -	    flags |= LONGDBL;
> -	  else if (sizeof (size_t) > sizeof (unsigned int))
> -	    flags |= LONG;
> -	  break;
> -	case L_('j'):
> -	  if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))
> -	    flags |= LONGDBL;
> -	  else if (sizeof (uintmax_t) > sizeof (unsigned int))
> -	    flags |= LONG;
> -	  break;
> -	case L_('t'):
> -	  if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))
> -	    flags |= LONGDBL;
> -	  else if (sizeof (ptrdiff_t) > sizeof (int))
> -	    flags |= LONG;
> -	  break;
> -	default:
> -	  /* Not a recognized modifier.  Backup.  */
> -	  --f;
> -	  break;
> -	}
> -
> -      /* End of the format string?  */
> -      if (__glibc_unlikely (*f == L_('\0')))
> -	conv_error ();
> -
> -      /* Find the conversion specifier.  */
> -      fc = *f++;
> -      if (skip_space || (fc != L_('[') && fc != L_('c')
> -			 && fc != L_('C') && fc != L_('n')))
> -	{
> -	  /* Eat whitespace.  */
> -	  int save_errno = errno;
> -	  __set_errno (0);
> -	  do
> -	    /* We add the additional test for EOF here since otherwise
> -	       inchar will restore the old errno value which might be
> -	       EINTR but does not indicate an interrupt since nothing
> -	       was read at this time.  */
> -	    if (__builtin_expect ((c == EOF || inchar () == EOF)
> -				  && errno == EINTR, 0))
> -	      input_error ();
> -	  while (ISSPACE (c));
> -	  __set_errno (save_errno);
> -	  ungetc (c, s);
> -	  skip_space = 0;
> -	}
> -
> -      switch (fc)
> -	{
> -	case L_('%'):	/* Must match a literal '%'.  */
> -	  c = inchar ();
> -	  if (__glibc_unlikely (c == EOF))
> -	    input_error ();
> -	  if (__glibc_unlikely (c != fc))
> -	    {
> -	      ungetc_not_eof (c, s);
> -	      conv_error ();
> -	    }
> -	  break;
> -
> -	case L_('n'):	/* Answer number of assignments done.  */
> -	  /* Corrigendum 1 to ISO C 1990 describes the allowed flags
> -	     with the 'n' conversion specifier.  */
> -	  if (!(flags & SUPPRESS))
> -	    {
> -	      /* Don't count the read-ahead.  */
> -	      if (need_longlong && (flags & LONGDBL))
> -		*ARG (long long int *) = read_in;
> -	      else if (need_long && (flags & LONG))
> -		*ARG (long int *) = read_in;
> -	      else if (flags & SHORT)
> -		*ARG (short int *) = read_in;
> -	      else if (!(flags & CHAR))
> -		*ARG (int *) = read_in;
> -	      else
> -		*ARG (char *) = read_in;
> -
> -#ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1
> -	      /* We have a severe problem here.  The ISO C standard
> -		 contradicts itself in explaining the effect of the %n
> -		 format in `scanf'.  While in ISO C:1990 and the ISO C
> -		 Amendement 1:1995 the result is described as
> -
> -		   Execution of a %n directive does not effect the
> -		   assignment count returned at the completion of
> -		   execution of the f(w)scanf function.
> -
> -		 in ISO C Corrigendum 1:1994 the following was added:
> -
> -		   Subclause 7.9.6.2
> -		   Add the following fourth example:
> -		     In:
> -		       #include <stdio.h>
> -		       int d1, d2, n1, n2, i;
> -		       i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
> -		     the value 123 is assigned to d1 and the value3 to n1.
> -		     Because %n can never get an input failure the value
> -		     of 3 is also assigned to n2.  The value of d2 is not
> -		     affected.  The value 3 is assigned to i.
> -
> -		 We go for now with the historically correct code from ISO C,
> -		 i.e., we don't count the %n assignments.  When it ever
> -		 should proof to be wrong just remove the #ifdef above.  */
> -	      ++done;
> -#endif
> -	    }
> -	  break;
> -
> -	case L_('c'):	/* Match characters.  */
> -	  if ((flags & LONG) == 0)
> -	    {
> -	      if (width == -1)
> -		width = 1;
> -
> -#define STRING_ARG(Str, Type, Width)					      \
> -	      do if (!(flags & SUPPRESS))				      \
> -		{							      \
> -		  if (flags & MALLOC)					      \
> -		    {							      \
> -		      /* The string is to be stored in a malloc'd buffer.  */ \
> -		      /* For %mS using char ** is actually wrong, but	      \
> -			 shouldn't make a difference on any arch glibc	      \
> -			 supports and would unnecessarily complicate	      \
> -			 things. */					      \
> -		      strptr = ARG (char **);				      \
> -		      if (strptr == NULL)				      \
> -			conv_error ();					      \
> -		      /* Allocate an initial buffer.  */		      \
> -		      strsize = Width;					      \
> -		      *strptr = (char *) malloc (strsize * sizeof (Type));    \
> -		      Str = (Type *) *strptr;				      \
> -		      if (Str != NULL)					      \
> -			add_ptr_to_free (strptr);			      \
> -		      else if (flags & POSIX_MALLOC)			      \
> -			{						      \
> -			  done = EOF;					      \
> -			  goto errout;					      \
> -			}						      \
> -		    }							      \
> -		  else							      \
> -		    Str = ARG (Type *);					      \
> -		  if (Str == NULL)					      \
> -		    conv_error ();					      \
> -		} while (0)
> -#ifdef COMPILE_WSCANF
> -	      STRING_ARG (str, char, 100);
> -#else
> -	      STRING_ARG (str, char, (width > 1024 ? 1024 : width));
> -#endif
> -
> -	      c = inchar ();
> -	      if (__glibc_unlikely (c == EOF))
> -		input_error ();
> -
> -#ifdef COMPILE_WSCANF
> -	      /* We have to convert the wide character(s) into multibyte
> -		 characters and store the result.  */
> -	      memset (&state, '\0', sizeof (state));
> -
> -	      do
> -		{
> -		  size_t n;
> -
> -		  if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
> -		      && *strptr + strsize - str <= MB_LEN_MAX)
> -		    {
> -		      /* We have to enlarge the buffer if the `m' flag
> -			 was given.  */
> -		      size_t strleng = str - *strptr;
> -		      char *newstr;
> -
> -		      newstr = (char *) realloc (*strptr, strsize * 2);
> -		      if (newstr == NULL)
> -			{
> -			  /* Can't allocate that much.  Last-ditch effort.  */
> -			  newstr = (char *) realloc (*strptr,
> -						     strleng + MB_LEN_MAX);
> -			  if (newstr == NULL)
> -			    {
> -			      /* c can't have `a' flag, only `m'.  */
> -			      done = EOF;
> -			      goto errout;
> -			    }
> -			  else
> -			    {
> -			      *strptr = newstr;
> -			      str = newstr + strleng;
> -			      strsize = strleng + MB_LEN_MAX;
> -			    }
> -			}
> -		      else
> -			{
> -			  *strptr = newstr;
> -			  str = newstr + strleng;
> -			  strsize *= 2;
> -			}
> -		    }
> -
> -		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
> -		  if (__glibc_unlikely (n == (size_t) -1))
> -		    /* No valid wide character.  */
> -		    input_error ();
> -
> -		  /* Increment the output pointer.  Even if we don't
> -		     write anything.  */
> -		  str += n;
> -		}
> -	      while (--width > 0 && inchar () != EOF);
> -#else
> -	      if (!(flags & SUPPRESS))
> -		{
> -		  do
> -		    {
> -		      if ((flags & MALLOC)
> -			  && (char *) str == *strptr + strsize)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  size_t newsize
> -			    = strsize
> -			      + (strsize >= width ? width - 1 : strsize);
> -
> -			  str = (char *) realloc (*strptr, newsize);
> -			  if (str == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      str = (char *) realloc (*strptr, strsize + 1);
> -			      if (str == NULL)
> -				{
> -				  /* c can't have `a' flag, only `m'.  */
> -				  done = EOF;
> -				  goto errout;
> -				}
> -			      else
> -				{
> -				  *strptr = (char *) str;
> -				  str += strsize;
> -				  ++strsize;
> -				}
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) str;
> -			      str += strsize;
> -			      strsize = newsize;
> -			    }
> -			}
> -		      *str++ = c;
> -		    }
> -		  while (--width > 0 && inchar () != EOF);
> -		}
> -	      else
> -		while (--width > 0 && inchar () != EOF);
> -#endif
> -
> -	      if (!(flags & SUPPRESS))
> -		{
> -		  if ((flags & MALLOC) && str - *strptr != strsize)
> -		    {
> -		      char *cp = (char *) realloc (*strptr, str - *strptr);
> -		      if (cp != NULL)
> -			*strptr = cp;
> -		    }
> -		  strptr = NULL;
> -		  ++done;
> -		}
> -
> -	      break;
> -	    }
> -	  /* FALLTHROUGH */
> -	case L_('C'):
> -	  if (width == -1)
> -	    width = 1;
> -
> -	  STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
> -
> -	  c = inchar ();
> -	  if (__glibc_unlikely (c == EOF))
> -	    input_error ();
> -
> -#ifdef COMPILE_WSCANF
> -	  /* Just store the incoming wide characters.  */
> -	  if (!(flags & SUPPRESS))
> -	    {
> -	      do
> -		{
> -		  if ((flags & MALLOC)
> -		      && wstr == (wchar_t *) *strptr + strsize)
> -		    {
> -		      size_t newsize
> -			= strsize + (strsize > width ? width - 1 : strsize);
> -		      /* Enlarge the buffer.  */
> -		      wstr = (wchar_t *) realloc (*strptr,
> -						  newsize * sizeof (wchar_t));
> -		      if (wstr == NULL)
> -			{
> -			  /* Can't allocate that much.  Last-ditch effort.  */
> -			  wstr = (wchar_t *) realloc (*strptr,
> -						      (strsize + 1)
> -						      * sizeof (wchar_t));
> -			  if (wstr == NULL)
> -			    {
> -			      /* C or lc can't have `a' flag, only `m'
> -				 flag.  */
> -			      done = EOF;
> -			      goto errout;
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) wstr;
> -			      wstr += strsize;
> -			      ++strsize;
> -			    }
> -			}
> -		      else
> -			{
> -			  *strptr = (char *) wstr;
> -			  wstr += strsize;
> -			  strsize = newsize;
> -			}
> -		    }
> -		  *wstr++ = c;
> -		}
> -	      while (--width > 0 && inchar () != EOF);
> -	    }
> -	  else
> -	    while (--width > 0 && inchar () != EOF);
> -#else
> -	  {
> -	    /* We have to convert the multibyte input sequence to wide
> -	       characters.  */
> -	    char buf[1];
> -	    mbstate_t cstate;
> -
> -	    memset (&cstate, '\0', sizeof (cstate));
> -
> -	    do
> -	      {
> -		/* This is what we present the mbrtowc function first.  */
> -		buf[0] = c;
> -
> -		if (!(flags & SUPPRESS) && (flags & MALLOC)
> -		    && wstr == (wchar_t *) *strptr + strsize)
> -		  {
> -		    size_t newsize
> -		      = strsize + (strsize > width ? width - 1 : strsize);
> -		    /* Enlarge the buffer.  */
> -		    wstr = (wchar_t *) realloc (*strptr,
> -						newsize * sizeof (wchar_t));
> -		    if (wstr == NULL)
> -		      {
> -			/* Can't allocate that much.  Last-ditch effort.  */
> -			wstr = (wchar_t *) realloc (*strptr,
> -						    ((strsize + 1)
> -						     * sizeof (wchar_t)));
> -			if (wstr == NULL)
> -			  {
> -			    /* C or lc can't have `a' flag, only `m' flag.  */
> -			    done = EOF;
> -			    goto errout;
> -			  }
> -			else
> -			  {
> -			    *strptr = (char *) wstr;
> -			    wstr += strsize;
> -			    ++strsize;
> -			  }
> -		      }
> -		    else
> -		      {
> -			*strptr = (char *) wstr;
> -			wstr += strsize;
> -			strsize = newsize;
> -		      }
> -		  }
> -
> -		while (1)
> -		  {
> -		    size_t n;
> -
> -		    n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
> -				   buf, 1, &cstate);
> -
> -		    if (n == (size_t) -2)
> -		      {
> -			/* Possibly correct character, just not enough
> -			   input.  */
> -			if (__glibc_unlikely (inchar () == EOF))
> -			  encode_error ();
> -
> -			buf[0] = c;
> -			continue;
> -		      }
> -
> -		    if (__glibc_unlikely (n != 1))
> -		      encode_error ();
> -
> -		    /* We have a match.  */
> -		    break;
> -		  }
> -
> -		/* Advance the result pointer.  */
> -		++wstr;
> -	      }
> -	    while (--width > 0 && inchar () != EOF);
> -	  }
> -#endif
> -
> -	  if (!(flags & SUPPRESS))
> -	    {
> -	      if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
> -		{
> -		  wchar_t *cp = (wchar_t *) realloc (*strptr,
> -						     ((wstr
> -						       - (wchar_t *) *strptr)
> -						      * sizeof (wchar_t)));
> -		  if (cp != NULL)
> -		    *strptr = (char *) cp;
> -		}
> -	      strptr = NULL;
> -
> -	      ++done;
> -	    }
> -
> -	  break;
> -
> -	case L_('s'):		/* Read a string.  */
> -	  if (!(flags & LONG))
> -	    {
> -	      STRING_ARG (str, char, 100);
> -
> -	      c = inchar ();
> -	      if (__glibc_unlikely (c == EOF))
> -		input_error ();
> -
> -#ifdef COMPILE_WSCANF
> -	      memset (&state, '\0', sizeof (state));
> -#endif
> -
> -	      do
> -		{
> -		  if (ISSPACE (c))
> -		    {
> -		      ungetc_not_eof (c, s);
> -		      break;
> -		    }
> -
> -#ifdef COMPILE_WSCANF
> -		  /* This is quite complicated.  We have to convert the
> -		     wide characters into multibyte characters and then
> -		     store them.  */
> -		  {
> -		    size_t n;
> -
> -		    if (!(flags & SUPPRESS) && (flags & MALLOC)
> -			&& *strptr + strsize - str <= MB_LEN_MAX)
> -		      {
> -			/* We have to enlarge the buffer if the `a' or `m'
> -			   flag was given.  */
> -			size_t strleng = str - *strptr;
> -			char *newstr;
> -
> -			newstr = (char *) realloc (*strptr, strsize * 2);
> -			if (newstr == NULL)
> -			  {
> -			    /* Can't allocate that much.  Last-ditch
> -			       effort.  */
> -			    newstr = (char *) realloc (*strptr,
> -						       strleng + MB_LEN_MAX);
> -			    if (newstr == NULL)
> -			      {
> -				if (flags & POSIX_MALLOC)
> -				  {
> -				    done = EOF;
> -				    goto errout;
> -				  }
> -				/* We lose.  Oh well.  Terminate the
> -				   string and stop converting,
> -				   so at least we don't skip any input.  */
> -				((char *) (*strptr))[strleng] = '\0';
> -				strptr = NULL;
> -				++done;
> -				conv_error ();
> -			      }
> -			    else
> -			      {
> -				*strptr = newstr;
> -				str = newstr + strleng;
> -				strsize = strleng + MB_LEN_MAX;
> -			      }
> -			  }
> -			else
> -			  {
> -			    *strptr = newstr;
> -			    str = newstr + strleng;
> -			    strsize *= 2;
> -			  }
> -		      }
> -
> -		    n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c,
> -				   &state);
> -		    if (__glibc_unlikely (n == (size_t) -1))
> -		      encode_error ();
> -
> -		    assert (n <= MB_LEN_MAX);
> -		    str += n;
> -		  }
> -#else
> -		  /* This is easy.  */
> -		  if (!(flags & SUPPRESS))
> -		    {
> -		      *str++ = c;
> -		      if ((flags & MALLOC)
> -			  && (char *) str == *strptr + strsize)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  str = (char *) realloc (*strptr, 2 * strsize);
> -			  if (str == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      str = (char *) realloc (*strptr, strsize + 1);
> -			      if (str == NULL)
> -				{
> -				  if (flags & POSIX_MALLOC)
> -				    {
> -				      done = EOF;
> -				      goto errout;
> -				    }
> -				  /* We lose.  Oh well.  Terminate the
> -				     string and stop converting,
> -				     so at least we don't skip any input.  */
> -				  ((char *) (*strptr))[strsize - 1] = '\0';
> -				  strptr = NULL;
> -				  ++done;
> -				  conv_error ();
> -				}
> -			      else
> -				{
> -				  *strptr = (char *) str;
> -				  str += strsize;
> -				  ++strsize;
> -				}
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) str;
> -			      str += strsize;
> -			      strsize *= 2;
> -			    }
> -			}
> -		    }
> -#endif
> -		}
> -	      while ((width <= 0 || --width > 0) && inchar () != EOF);
> -
> -	      if (!(flags & SUPPRESS))
> -		{
> -#ifdef COMPILE_WSCANF
> -		  /* We have to emit the code to get into the initial
> -		     state.  */
> -		  char buf[MB_LEN_MAX];
> -		  size_t n = __wcrtomb (buf, L'\0', &state);
> -		  if (n > 0 && (flags & MALLOC)
> -		      && str + n >= *strptr + strsize)
> -		    {
> -		      /* Enlarge the buffer.  */
> -		      size_t strleng = str - *strptr;
> -		      char *newstr;
> -
> -		      newstr = (char *) realloc (*strptr, strleng + n + 1);
> -		      if (newstr == NULL)
> -			{
> -			  if (flags & POSIX_MALLOC)
> -			    {
> -			      done = EOF;
> -			      goto errout;
> -			    }
> -			  /* We lose.  Oh well.  Terminate the string
> -			     and stop converting, so at least we don't
> -			     skip any input.  */
> -			  ((char *) (*strptr))[strleng] = '\0';
> -			  strptr = NULL;
> -			  ++done;
> -			  conv_error ();
> -			}
> -		      else
> -			{
> -			  *strptr = newstr;
> -			  str = newstr + strleng;
> -			  strsize = strleng + n + 1;
> -			}
> -		    }
> -
> -		  str = __mempcpy (str, buf, n);
> -#endif
> -		  *str++ = '\0';
> -
> -		  if ((flags & MALLOC) && str - *strptr != strsize)
> -		    {
> -		      char *cp = (char *) realloc (*strptr, str - *strptr);
> -		      if (cp != NULL)
> -			*strptr = cp;
> -		    }
> -		  strptr = NULL;
> -
> -		  ++done;
> -		}
> -	      break;
> -	    }
> -	  /* FALLTHROUGH */
> -
> -	case L_('S'):
> -	  {
> -#ifndef COMPILE_WSCANF
> -	    mbstate_t cstate;
> -#endif
> -
> -	    /* Wide character string.  */
> -	    STRING_ARG (wstr, wchar_t, 100);
> -
> -	    c = inchar ();
> -	    if (__builtin_expect (c == EOF,  0))
> -	      input_error ();
> -
> -#ifndef COMPILE_WSCANF
> -	    memset (&cstate, '\0', sizeof (cstate));
> -#endif
> -
> -	    do
> -	      {
> -		if (ISSPACE (c))
> -		  {
> -		    ungetc_not_eof (c, s);
> -		    break;
> -		  }
> -
> -#ifdef COMPILE_WSCANF
> -		/* This is easy.  */
> -		if (!(flags & SUPPRESS))
> -		  {
> -		    *wstr++ = c;
> -		    if ((flags & MALLOC)
> -			&& wstr == (wchar_t *) *strptr + strsize)
> -		      {
> -			/* Enlarge the buffer.  */
> -			wstr = (wchar_t *) realloc (*strptr,
> -						    (2 * strsize)
> -						    * sizeof (wchar_t));
> -			if (wstr == NULL)
> -			  {
> -			    /* Can't allocate that much.  Last-ditch
> -			       effort.  */
> -			    wstr = (wchar_t *) realloc (*strptr,
> -							(strsize + 1)
> -							* sizeof (wchar_t));
> -			    if (wstr == NULL)
> -			      {
> -				if (flags & POSIX_MALLOC)
> -				  {
> -				    done = EOF;
> -				    goto errout;
> -				  }
> -				/* We lose.  Oh well.  Terminate the string
> -				   and stop converting, so at least we don't
> -				   skip any input.  */
> -				((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> -				strptr = NULL;
> -				++done;
> -				conv_error ();
> -			      }
> -			    else
> -			      {
> -				*strptr = (char *) wstr;
> -				wstr += strsize;
> -				++strsize;
> -			      }
> -			  }
> -			else
> -			  {
> -			    *strptr = (char *) wstr;
> -			    wstr += strsize;
> -			    strsize *= 2;
> -			  }
> -		      }
> -		  }
> -#else
> -		{
> -		  char buf[1];
> -
> -		  buf[0] = c;
> -
> -		  while (1)
> -		    {
> -		      size_t n;
> -
> -		      n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
> -				     buf, 1, &cstate);
> -
> -		      if (n == (size_t) -2)
> -			{
> -			  /* Possibly correct character, just not enough
> -			     input.  */
> -			  if (__glibc_unlikely (inchar () == EOF))
> -			    encode_error ();
> -
> -			  buf[0] = c;
> -			  continue;
> -			}
> -
> -		      if (__glibc_unlikely (n != 1))
> -			encode_error ();
> -
> -		      /* We have a match.  */
> -		      ++wstr;
> -		      break;
> -		    }
> -
> -		  if (!(flags & SUPPRESS) && (flags & MALLOC)
> -		      && wstr == (wchar_t *) *strptr + strsize)
> -		    {
> -		      /* Enlarge the buffer.  */
> -		      wstr = (wchar_t *) realloc (*strptr,
> -						  (2 * strsize
> -						   * sizeof (wchar_t)));
> -		      if (wstr == NULL)
> -			{
> -			  /* Can't allocate that much.  Last-ditch effort.  */
> -			  wstr = (wchar_t *) realloc (*strptr,
> -						      ((strsize + 1)
> -						       * sizeof (wchar_t)));
> -			  if (wstr == NULL)
> -			    {
> -			      if (flags & POSIX_MALLOC)
> -				{
> -				  done = EOF;
> -				  goto errout;
> -				}
> -			      /* We lose.  Oh well.  Terminate the
> -				 string and stop converting, so at
> -				 least we don't skip any input.  */
> -			      ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> -			      strptr = NULL;
> -			      ++done;
> -			      conv_error ();
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) wstr;
> -			      wstr += strsize;
> -			      ++strsize;
> -			    }
> -			}
> -		      else
> -			{
> -			  *strptr = (char *) wstr;
> -			  wstr += strsize;
> -			  strsize *= 2;
> -			}
> -		    }
> -		}
> -#endif
> -	      }
> -	    while ((width <= 0 || --width > 0) && inchar () != EOF);
> -
> -	    if (!(flags & SUPPRESS))
> -	      {
> -		*wstr++ = L'\0';
> -
> -		if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
> -		  {
> -		    wchar_t *cp = (wchar_t *) realloc (*strptr,
> -						       ((wstr
> -							 - (wchar_t *) *strptr)
> -							* sizeof(wchar_t)));
> -		    if (cp != NULL)
> -		      *strptr = (char *) cp;
> -		  }
> -		strptr = NULL;
> -
> -		++done;
> -	      }
> -	  }
> -	  break;
> -
> -	case L_('x'):	/* Hexadecimal integer.  */
> -	case L_('X'):	/* Ditto.  */
> -	  base = 16;
> -	  goto number;
> -
> -	case L_('o'):	/* Octal integer.  */
> -	  base = 8;
> -	  goto number;
> -
> -	case L_('u'):	/* Unsigned decimal integer.  */
> -	  base = 10;
> -	  goto number;
> -
> -	case L_('d'):	/* Signed decimal integer.  */
> -	  base = 10;
> -	  flags |= NUMBER_SIGNED;
> -	  goto number;
> -
> -	case L_('i'):	/* Generic number.  */
> -	  base = 0;
> -	  flags |= NUMBER_SIGNED;
> -
> -	number:
> -	  c = inchar ();
> -	  if (__glibc_unlikely (c == EOF))
> -	    input_error ();
> -
> -	  /* Check for a sign.  */
> -	  if (c == L_('-') || c == L_('+'))
> -	    {
> -	      char_buffer_add (&charbuf, c);
> -	      if (width > 0)
> -		--width;
> -	      c = inchar ();
> -	    }
> -
> -	  /* Look for a leading indication of base.  */
> -	  if (width != 0 && c == L_('0'))
> -	    {
> -	      if (width > 0)
> -		--width;
> -
> -	      char_buffer_add (&charbuf, c);
> -	      c = inchar ();
> -
> -	      if (width != 0 && TOLOWER (c) == L_('x'))
> -		{
> -		  if (base == 0)
> -		    base = 16;
> -		  if (base == 16)
> -		    {
> -		      if (width > 0)
> -			--width;
> -		      c = inchar ();
> -		    }
> -		}
> -	      else if (base == 0)
> -		base = 8;
> -	    }
> -
> -	  if (base == 0)
> -	    base = 10;
> -
> -	  if (base == 10 && __builtin_expect ((flags & I18N) != 0, 0))
> -	    {
> -	      int from_level;
> -	      int to_level;
> -	      int level;
> -#ifdef COMPILE_WSCANF
> -	      const wchar_t *wcdigits[10];
> -	      const wchar_t *wcdigits_extended[10];
> -#else
> -	      const char *mbdigits[10];
> -	      const char *mbdigits_extended[10];
> -#endif
> -	      /*  "to_inpunct" is a map from ASCII digits to their
> -		  equivalent in locale. This is defined for locales
> -		  which use an extra digits set.  */
> -	      wctrans_t map = __wctrans ("to_inpunct");
> -	      int n;
> -
> -	      from_level = 0;
> -#ifdef COMPILE_WSCANF
> -	      to_level = _NL_CURRENT_WORD (LC_CTYPE,
> -					   _NL_CTYPE_INDIGITS_WC_LEN) - 1;
> -#else
> -	      to_level = (uint32_t) curctype->values[_NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_MB_LEN)].word - 1;
> -#endif
> -
> -	      /* Get the alternative digit forms if there are any.  */
> -	      if (__glibc_unlikely (map != NULL))
> -		{
> -		  /*  Adding new level for extra digits set in locale file.  */
> -		  ++to_level;
> -
> -		  for (n = 0; n < 10; ++n)
> -		    {
> -#ifdef COMPILE_WSCANF
> -		      wcdigits[n] = (const wchar_t *)
> -			_NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
> -
> -		      wchar_t *wc_extended = (wchar_t *)
> -			alloca ((to_level + 2) * sizeof (wchar_t));
> -		      __wmemcpy (wc_extended, wcdigits[n], to_level);
> -		      wc_extended[to_level] = __towctrans (L'0' + n, map);
> -		      wc_extended[to_level + 1] = '\0';
> -		      wcdigits_extended[n] = wc_extended;
> -#else
> -		      mbdigits[n]
> -			= curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
> -
> -		      /*  Get the equivalent wide char in map.  */
> -		      wint_t extra_wcdigit = __towctrans (L'0' + n, map);
> -
> -		      /*  Convert it to multibyte representation.  */
> -		      mbstate_t state;
> -		      memset (&state, '\0', sizeof (state));
> -
> -		      char extra_mbdigit[MB_LEN_MAX];
> -		      size_t mblen
> -			= __wcrtomb (extra_mbdigit, extra_wcdigit, &state);
> -
> -		      if (mblen == (size_t) -1)
> -			{
> -			  /*  Ignore this new level.  */
> -			  map = NULL;
> -			  break;
> -			}
> -
> -		      /*  Calculate the length of mbdigits[n].  */
> -		      const char *last_char = mbdigits[n];
> -		      for (level = 0; level < to_level; ++level)
> -			last_char = strchr (last_char, '\0') + 1;
> -
> -		      size_t mbdigits_len = last_char - mbdigits[n];
> -
> -		      /*  Allocate memory for extended multibyte digit.  */
> -		      char *mb_extended;
> -		      mb_extended = (char *) alloca (mbdigits_len + mblen + 1);
> -
> -		      /*  And get the mbdigits + extra_digit string.  */
> -		      *(char *) __mempcpy (__mempcpy (mb_extended, mbdigits[n],
> -						      mbdigits_len),
> -					   extra_mbdigit, mblen) = '\0';
> -		      mbdigits_extended[n] = mb_extended;
> -#endif
> -		    }
> -		}
> -
> -	      /* Read the number into workspace.  */
> -	      while (c != EOF && width != 0)
> -		{
> -		  /* In this round we get the pointer to the digit strings
> -		     and also perform the first round of comparisons.  */
> -		  for (n = 0; n < 10; ++n)
> -		    {
> -		      /* Get the string for the digits with value N.  */
> -#ifdef COMPILE_WSCANF
> -
> -		      /* wcdigits_extended[] is fully set in the loop
> -			 above, but the test for "map != NULL" is done
> -			 inside the loop here and outside the loop there.  */
> -		      DIAG_PUSH_NEEDS_COMMENT;
> -		      DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized");
> -
> -		      if (__glibc_unlikely (map != NULL))
> -			wcdigits[n] = wcdigits_extended[n];
> -		      else
> -			wcdigits[n] = (const wchar_t *)
> -			  _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
> -		      wcdigits[n] += from_level;
> -
> -		      DIAG_POP_NEEDS_COMMENT;
> -
> -		      if (c == (wint_t) *wcdigits[n])
> -			{
> -			  to_level = from_level;
> -			  break;
> -			}
> -
> -		      /* Advance the pointer to the next string.  */
> -		      ++wcdigits[n];
> -#else
> -		      const char *cmpp;
> -		      int avail = width > 0 ? width : INT_MAX;
> -
> -		      if (__glibc_unlikely (map != NULL))
> -			mbdigits[n] = mbdigits_extended[n];
> -		      else
> -			mbdigits[n]
> -			  = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
> -
> -		      for (level = 0; level < from_level; level++)
> -			mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -
> -		      cmpp = mbdigits[n];
> -		      while ((unsigned char) *cmpp == c && avail >= 0)
> -			{
> -			  if (*++cmpp == '\0')
> -			    break;
> -			  else
> -			    {
> -			      if (avail == 0 || inchar () == EOF)
> -				break;
> -			      --avail;
> -			    }
> -			}
> -
> -		      if (*cmpp == '\0')
> -			{
> -			  if (width > 0)
> -			    width = avail;
> -			  to_level = from_level;
> -			  break;
> -			}
> -
> -		      /* We are pushing all read characters back.  */
> -		      if (cmpp > mbdigits[n])
> -			{
> -			  ungetc (c, s);
> -			  while (--cmpp > mbdigits[n])
> -			    ungetc_not_eof ((unsigned char) *cmpp, s);
> -			  c = (unsigned char) *cmpp;
> -			}
> -
> -		      /* Advance the pointer to the next string.  */
> -		      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -#endif
> -		    }
> -
> -		  if (n == 10)
> -		    {
> -		      /* Have not yet found the digit.  */
> -		      for (level = from_level + 1; level <= to_level; ++level)
> -			{
> -			  /* Search all ten digits of this level.  */
> -			  for (n = 0; n < 10; ++n)
> -			    {
> -#ifdef COMPILE_WSCANF
> -			      if (c == (wint_t) *wcdigits[n])
> -				break;
> -
> -			      /* Advance the pointer to the next string.  */
> -			      ++wcdigits[n];
> -#else
> -			      const char *cmpp;
> -			      int avail = width > 0 ? width : INT_MAX;
> -
> -			      cmpp = mbdigits[n];
> -			      while ((unsigned char) *cmpp == c && avail >= 0)
> -				{
> -				  if (*++cmpp == '\0')
> -				    break;
> -				  else
> -				    {
> -				      if (avail == 0 || inchar () == EOF)
> -					break;
> -				      --avail;
> -				    }
> -				}
> -
> -			      if (*cmpp == '\0')
> -				{
> -				  if (width > 0)
> -				    width = avail;
> -				  break;
> -				}
> -
> -			      /* We are pushing all read characters back.  */
> -			      if (cmpp > mbdigits[n])
> -				{
> -				  ungetc (c, s);
> -				  while (--cmpp > mbdigits[n])
> -				    ungetc_not_eof ((unsigned char) *cmpp, s);
> -				  c = (unsigned char) *cmpp;
> -				}
> -
> -			      /* Advance the pointer to the next string.  */
> -			      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -#endif
> -			    }
> -
> -			  if (n < 10)
> -			    {
> -			      /* Found it.  */
> -			      from_level = level;
> -			      to_level = level;
> -			      break;
> -			    }
> -			}
> -		    }
> -
> -		  if (n < 10)
> -		    c = L_('0') + n;
> -		  else if (flags & GROUP)
> -		    {
> -		      /* Try matching against the thousands separator.  */
> -#ifdef COMPILE_WSCANF
> -		      if (c != thousands)
> -			  break;
> -#else
> -		      const char *cmpp = thousands;
> -		      int avail = width > 0 ? width : INT_MAX;
> -
> -		      while ((unsigned char) *cmpp == c && avail >= 0)
> -			{
> -			  char_buffer_add (&charbuf, c);
> -			  if (*++cmpp == '\0')
> -			    break;
> -			  else
> -			    {
> -			      if (avail == 0 || inchar () == EOF)
> -				break;
> -			      --avail;
> -			    }
> -			}
> -
> -		      if (char_buffer_error (&charbuf))
> -			{
> -			  __set_errno (ENOMEM);
> -			  done = EOF;
> -			  goto errout;
> -			}
> -
> -		      if (*cmpp != '\0')
> -			{
> -			  /* We are pushing all read characters back.  */
> -			  if (cmpp > thousands)
> -			    {
> -			      charbuf.current -= cmpp - thousands;
> -			      ungetc (c, s);
> -			      while (--cmpp > thousands)
> -				ungetc_not_eof ((unsigned char) *cmpp, s);
> -			      c = (unsigned char) *cmpp;
> -			    }
> -			  break;
> -			}
> -
> -		      if (width > 0)
> -			width = avail;
> -
> -		      /* The last thousands character will be added back by
> -			 the char_buffer_add below.  */
> -		      --charbuf.current;
> -#endif
> -		    }
> -		  else
> -		    break;
> -
> -		  char_buffer_add (&charbuf, c);
> -		  if (width > 0)
> -		    --width;
> -
> -		  c = inchar ();
> -		}
> -	    }
> -	  else
> -	    /* Read the number into workspace.  */
> -	    while (c != EOF && width != 0)
> -	      {
> -		if (base == 16)
> -		  {
> -		    if (!ISXDIGIT (c))
> -		      break;
> -		  }
> -		else if (!ISDIGIT (c) || (int) (c - L_('0')) >= base)
> -		  {
> -		    if (base == 10 && (flags & GROUP))
> -		      {
> -			/* Try matching against the thousands separator.  */
> -#ifdef COMPILE_WSCANF
> -			if (c != thousands)
> -			  break;
> -#else
> -			const char *cmpp = thousands;
> -			int avail = width > 0 ? width : INT_MAX;
> -
> -			while ((unsigned char) *cmpp == c && avail >= 0)
> -			  {
> -			    char_buffer_add (&charbuf, c);
> -			    if (*++cmpp == '\0')
> -			      break;
> -			    else
> -			      {
> -				if (avail == 0 || inchar () == EOF)
> -				  break;
> -				--avail;
> -			      }
> -			  }
> -
> -			if (char_buffer_error (&charbuf))
> -			  {
> -			    __set_errno (ENOMEM);
> -			    done = EOF;
> -			    goto errout;
> -			  }
> -
> -			if (*cmpp != '\0')
> -			  {
> -			    /* We are pushing all read characters back.  */
> -			    if (cmpp > thousands)
> -			      {
> -				charbuf.current -= cmpp - thousands;
> -				ungetc (c, s);
> -				while (--cmpp > thousands)
> -				  ungetc_not_eof ((unsigned char) *cmpp, s);
> -				c = (unsigned char) *cmpp;
> -			      }
> -			    break;
> -			  }
> -
> -			if (width > 0)
> -			  width = avail;
> -
> -			/* The last thousands character will be added back by
> -			   the char_buffer_add below.  */
> -			--charbuf.current;
> -#endif
> -		      }
> -		    else
> -		      break;
> -		  }
> -		char_buffer_add (&charbuf, c);
> -		if (width > 0)
> -		  --width;
> -
> -		c = inchar ();
> -	      }
> -
> -	  if (char_buffer_error (&charbuf))
> -	    {
> -	      __set_errno (ENOMEM);
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -
> -	  if (char_buffer_size (&charbuf) == 0
> -	      || (char_buffer_size (&charbuf) == 1
> -		  && (char_buffer_start (&charbuf)[0] == L_('+')
> -		      || char_buffer_start (&charbuf)[0] == L_('-'))))
> -	    {
> -	      /* There was no number.  If we are supposed to read a pointer
> -		 we must recognize "(nil)" as well.  */
> -	      if (__builtin_expect (char_buffer_size (&charbuf) == 0
> -				    && (flags & READ_POINTER)
> -				    && (width < 0 || width >= 5)
> -				    && c == '('
> -				    && TOLOWER (inchar ()) == L_('n')
> -				    && TOLOWER (inchar ()) == L_('i')
> -				    && TOLOWER (inchar ()) == L_('l')
> -				    && inchar () == L_(')'), 1))
> -		/* We must produce the value of a NULL pointer.  A single
> -		   '0' digit is enough.  */
> -		  char_buffer_add (&charbuf, L_('0'));
> -	      else
> -		{
> -		  /* The last read character is not part of the number
> -		     anymore.  */
> -		  ungetc (c, s);
> -
> -		  conv_error ();
> -		}
> -	    }
> -	  else
> -	    /* The just read character is not part of the number anymore.  */
> -	    ungetc (c, s);
> -
> -	  /* Convert the number.  */
> -	  char_buffer_add (&charbuf, L_('\0'));
> -	  if (char_buffer_error (&charbuf))
> -	    {
> -	      __set_errno (ENOMEM);
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -	  if (need_longlong && (flags & LONGDBL))
> -	    {
> -	      if (flags & NUMBER_SIGNED)
> -		num.q = __strtoll_internal
> -		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> -	      else
> -		num.uq = __strtoull_internal
> -		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> -	    }
> -	  else
> -	    {
> -	      if (flags & NUMBER_SIGNED)
> -		num.l = __strtol_internal
> -		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> -	      else
> -		num.ul = __strtoul_internal
> -		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> -	    }
> -	  if (__glibc_unlikely (char_buffer_start (&charbuf) == tw))
> -	    conv_error ();
> -
> -	  if (!(flags & SUPPRESS))
> -	    {
> -	      if (flags & NUMBER_SIGNED)
> -		{
> -		  if (need_longlong && (flags & LONGDBL))
> -		    *ARG (LONGLONG int *) = num.q;
> -		  else if (need_long && (flags & LONG))
> -		    *ARG (long int *) = num.l;
> -		  else if (flags & SHORT)
> -		    *ARG (short int *) = (short int) num.l;
> -		  else if (!(flags & CHAR))
> -		    *ARG (int *) = (int) num.l;
> -		  else
> -		    *ARG (signed char *) = (signed char) num.ul;
> -		}
> -	      else
> -		{
> -		  if (need_longlong && (flags & LONGDBL))
> -		    *ARG (unsigned LONGLONG int *) = num.uq;
> -		  else if (need_long && (flags & LONG))
> -		    *ARG (unsigned long int *) = num.ul;
> -		  else if (flags & SHORT)
> -		    *ARG (unsigned short int *)
> -		      = (unsigned short int) num.ul;
> -		  else if (!(flags & CHAR))
> -		    *ARG (unsigned int *) = (unsigned int) num.ul;
> -		  else
> -		    *ARG (unsigned char *) = (unsigned char) num.ul;
> -		}
> -	      ++done;
> -	    }
> -	  break;
> -
> -	case L_('e'):	/* Floating-point numbers.  */
> -	case L_('E'):
> -	case L_('f'):
> -	case L_('F'):
> -	case L_('g'):
> -	case L_('G'):
> -	case L_('a'):
> -	case L_('A'):
> -	  c = inchar ();
> -	  if (width > 0)
> -	    --width;
> -	  if (__glibc_unlikely (c == EOF))
> -	    input_error ();
> -
> -	  got_digit = got_dot = got_e = got_sign = 0;
> -
> -	  /* Check for a sign.  */
> -	  if (c == L_('-') || c == L_('+'))
> -	    {
> -	      got_sign = 1;
> -	      char_buffer_add (&charbuf, c);
> -	      if (__glibc_unlikely (width == 0 || inchar () == EOF))
> -		/* EOF is only an input error before we read any chars.  */
> -		conv_error ();
> -	      if (width > 0)
> -		--width;
> -	    }
> -
> -	  /* Take care for the special arguments "nan" and "inf".  */
> -	  if (TOLOWER (c) == L_('n'))
> -	    {
> -	      /* Maybe "nan".  */
> -	      char_buffer_add (&charbuf, c);
> -	      if (__builtin_expect (width == 0
> -				    || inchar () == EOF
> -				    || TOLOWER (c) != L_('a'), 0))
> -		conv_error ();
> -	      if (width > 0)
> -		--width;
> -	      char_buffer_add (&charbuf, c);
> -	      if (__builtin_expect (width == 0
> -				    || inchar () == EOF
> -				    || TOLOWER (c) != L_('n'), 0))
> -		conv_error ();
> -	      if (width > 0)
> -		--width;
> -	      char_buffer_add (&charbuf, c);
> -	      /* It is "nan".  */
> -	      goto scan_float;
> -	    }
> -	  else if (TOLOWER (c) == L_('i'))
> -	    {
> -	      /* Maybe "inf" or "infinity".  */
> -	      char_buffer_add (&charbuf, c);
> -	      if (__builtin_expect (width == 0
> -				    || inchar () == EOF
> -				    || TOLOWER (c) != L_('n'), 0))
> -		conv_error ();
> -	      if (width > 0)
> -		--width;
> -	      char_buffer_add (&charbuf, c);
> -	      if (__builtin_expect (width == 0
> -				    || inchar () == EOF
> -				    || TOLOWER (c) != L_('f'), 0))
> -		conv_error ();
> -	      if (width > 0)
> -		--width;
> -	      char_buffer_add (&charbuf, c);
> -	      /* It is as least "inf".  */
> -	      if (width != 0 && inchar () != EOF)
> -		{
> -		  if (TOLOWER (c) == L_('i'))
> -		    {
> -		      if (width > 0)
> -			--width;
> -		      /* Now we have to read the rest as well.  */
> -		      char_buffer_add (&charbuf, c);
> -		      if (__builtin_expect (width == 0
> -					    || inchar () == EOF
> -					    || TOLOWER (c) != L_('n'), 0))
> -			conv_error ();
> -		      if (width > 0)
> -			--width;
> -		      char_buffer_add (&charbuf, c);
> -		      if (__builtin_expect (width == 0
> -					    || inchar () == EOF
> -					    || TOLOWER (c) != L_('i'), 0))
> -			conv_error ();
> -		      if (width > 0)
> -			--width;
> -		      char_buffer_add (&charbuf, c);
> -		      if (__builtin_expect (width == 0
> -					    || inchar () == EOF
> -					    || TOLOWER (c) != L_('t'), 0))
> -			conv_error ();
> -		      if (width > 0)
> -			--width;
> -		      char_buffer_add (&charbuf, c);
> -		      if (__builtin_expect (width == 0
> -					    || inchar () == EOF
> -					    || TOLOWER (c) != L_('y'), 0))
> -			conv_error ();
> -		      if (width > 0)
> -			--width;
> -		      char_buffer_add (&charbuf, c);
> -		    }
> -		  else
> -		    /* Never mind.  */
> -		    ungetc (c, s);
> -		}
> -	      goto scan_float;
> -	    }
> -
> -	  exp_char = L_('e');
> -	  if (width != 0 && c == L_('0'))
> -	    {
> -	      char_buffer_add (&charbuf, c);
> -	      c = inchar ();
> -	      if (width > 0)
> -		--width;
> -	      if (width != 0 && TOLOWER (c) == L_('x'))
> -		{
> -		  /* It is a number in hexadecimal format.  */
> -		  char_buffer_add (&charbuf, c);
> -
> -		  flags |= HEXA_FLOAT;
> -		  exp_char = L_('p');
> -
> -		  /* Grouping is not allowed.  */
> -		  flags &= ~GROUP;
> -		  c = inchar ();
> -		  if (width > 0)
> -		    --width;
> -		}
> -	      else
> -		got_digit = 1;
> -	    }
> -
> -	  while (1)
> -	    {
> -	      if (char_buffer_error (&charbuf))
> -		{
> -		  __set_errno (ENOMEM);
> -		  done = EOF;
> -		  goto errout;
> -		}
> -	      if (ISDIGIT (c))
> -		{
> -		  char_buffer_add (&charbuf, c);
> -		  got_digit = 1;
> -		}
> -	      else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c))
> -		{
> -		  char_buffer_add (&charbuf, c);
> -		  got_digit = 1;
> -		}
> -	      else if (got_e && charbuf.current[-1] == exp_char
> -		       && (c == L_('-') || c == L_('+')))
> -		char_buffer_add (&charbuf, c);
> -	      else if (got_digit && !got_e
> -		       && (CHAR_T) TOLOWER (c) == exp_char)
> -		{
> -		  char_buffer_add (&charbuf, exp_char);
> -		  got_e = got_dot = 1;
> -		}
> -	      else
> -		{
> -#ifdef COMPILE_WSCANF
> -		  if (! got_dot && c == decimal)
> -		    {
> -		      char_buffer_add (&charbuf, c);
> -		      got_dot = 1;
> -		    }
> -		  else if ((flags & GROUP) != 0 && ! got_dot && c == thousands)
> -		    char_buffer_add (&charbuf, c);
> -		  else
> -		    {
> -		      /* The last read character is not part of the number
> -			 anymore.  */
> -		      ungetc (c, s);
> -		      break;
> -		    }
> -#else
> -		  const char *cmpp = decimal;
> -		  int avail = width > 0 ? width : INT_MAX;
> -
> -		  if (! got_dot)
> -		    {
> -		      while ((unsigned char) *cmpp == c && avail >= 0)
> -			if (*++cmpp == '\0')
> -			  break;
> -			else
> -			  {
> -			    if (avail == 0 || inchar () == EOF)
> -			      break;
> -			    --avail;
> -			  }
> -		    }
> -
> -		  if (*cmpp == '\0')
> -		    {
> -		      /* Add all the characters.  */
> -		      for (cmpp = decimal; *cmpp != '\0'; ++cmpp)
> -			char_buffer_add (&charbuf, (unsigned char) *cmpp);
> -		      if (width > 0)
> -			width = avail;
> -		      got_dot = 1;
> -		    }
> -		  else
> -		    {
> -		      /* Figure out whether it is a thousands separator.
> -			 There is one problem: we possibly read more than
> -			 one character.  We cannot push them back but since
> -			 we know that parts of the `decimal' string matched,
> -			 we can compare against it.  */
> -		      const char *cmp2p = thousands;
> -
> -		      if ((flags & GROUP) != 0 && ! got_dot)
> -			{
> -			  while (cmp2p - thousands < cmpp - decimal
> -				 && *cmp2p == decimal[cmp2p - thousands])
> -			    ++cmp2p;
> -			  if (cmp2p - thousands == cmpp - decimal)
> -			    {
> -			      while ((unsigned char) *cmp2p == c && avail >= 0)
> -				if (*++cmp2p == '\0')
> -				  break;
> -				else
> -				  {
> -				    if (avail == 0 || inchar () == EOF)
> -				      break;
> -				    --avail;
> -				  }
> -			    }
> -			}
> -
> -		      if (cmp2p != NULL && *cmp2p == '\0')
> -			{
> -			  /* Add all the characters.  */
> -			  for (cmpp = thousands; *cmpp != '\0'; ++cmpp)
> -			    char_buffer_add (&charbuf, (unsigned char) *cmpp);
> -			  if (width > 0)
> -			    width = avail;
> -			}
> -		      else
> -			{
> -			  /* The last read character is not part of the number
> -			     anymore.  */
> -			  ungetc (c, s);
> -			  break;
> -			}
> -		    }
> -#endif
> -		}
> -
> -	      if (width == 0 || inchar () == EOF)
> -		break;
> -
> -	      if (width > 0)
> -		--width;
> -	    }
> -
> -	  if (char_buffer_error (&charbuf))
> -	    {
> -	      __set_errno (ENOMEM);
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -
> -	  wctrans_t map;
> -	  if (__builtin_expect ((flags & I18N) != 0, 0)
> -	      /* Hexadecimal floats make no sense, fixing localized
> -		 digits with ASCII letters.  */
> -	      && !(flags & HEXA_FLOAT)
> -	      /* Minimum requirement.  */
> -	      && (char_buffer_size (&charbuf) == got_sign || got_dot)
> -	      && (map = __wctrans ("to_inpunct")) != NULL)
> -	    {
> -	      /* Reget the first character.  */
> -	      inchar ();
> -
> -	      /* Localized digits, decimal points, and thousands
> -		 separator.  */
> -	      wint_t wcdigits[12];
> -
> -	      /* First get decimal equivalent to check if we read it
> -		 or not.  */
> -	      wcdigits[11] = __towctrans (L'.', map);
> -
> -	      /* If we have not read any character or have just read
> -		 locale decimal point which matches the decimal point
> -		 for localized FP numbers, then we may have localized
> -		 digits.  Note, we test GOT_DOT above.  */
> -#ifdef COMPILE_WSCANF
> -	      if (char_buffer_size (&charbuf) == got_sign
> -		  || (char_buffer_size (&charbuf) == got_sign + 1
> -		      && wcdigits[11] == decimal))
> -#else
> -	      char mbdigits[12][MB_LEN_MAX + 1];
> -
> -	      mbstate_t state;
> -	      memset (&state, '\0', sizeof (state));
> -
> -	      bool match_so_far = char_buffer_size (&charbuf) == got_sign;
> -	      size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
> -	      if (mblen != (size_t) -1)
> -		{
> -		  mbdigits[11][mblen] = '\0';
> -		  match_so_far |=
> -		    (char_buffer_size (&charbuf) == strlen (decimal) + got_sign
> -		     && strcmp (decimal, mbdigits[11]) == 0);
> -		}
> -	      else
> -		{
> -		  size_t decimal_len = strlen (decimal);
> -		  /* This should always be the case but the data comes
> -		     from a file.  */
> -		  if (decimal_len <= MB_LEN_MAX)
> -		    {
> -		      match_so_far |= (char_buffer_size (&charbuf)
> -				       == decimal_len + got_sign);
> -		      memcpy (mbdigits[11], decimal, decimal_len + 1);
> -		    }
> -		  else
> -		    match_so_far = false;
> -		}
> -
> -	      if (match_so_far)
> -#endif
> -		{
> -		  bool have_locthousands = (flags & GROUP) != 0;
> -
> -		  /* Now get the digits and the thousands-sep equivalents.  */
> -		  for (int n = 0; n < 11; ++n)
> -		    {
> -		      if (n < 10)
> -			wcdigits[n] = __towctrans (L'0' + n, map);
> -		      else if (n == 10)
> -			{
> -			  wcdigits[10] = __towctrans (L',', map);
> -			  have_locthousands &= wcdigits[10] != L'\0';
> -			}
> -
> -#ifndef COMPILE_WSCANF
> -		      memset (&state, '\0', sizeof (state));
> -
> -		      size_t mblen = __wcrtomb (mbdigits[n], wcdigits[n],
> -						&state);
> -		      if (mblen == (size_t) -1)
> -			{
> -			  if (n == 10)
> -			    {
> -			      if (have_locthousands)
> -				{
> -				  size_t thousands_len = strlen (thousands);
> -				  if (thousands_len <= MB_LEN_MAX)
> -				    memcpy (mbdigits[10], thousands,
> -					    thousands_len + 1);
> -				  else
> -				    have_locthousands = false;
> -				}
> -			    }
> -			  else
> -			    /* Ignore checking against localized digits.  */
> -			    goto no_i18nflt;
> -			}
> -		      else
> -			mbdigits[n][mblen] = '\0';
> -#endif
> -		    }
> -
> -		  /* Start checking against localized digits, if
> -		     conversion is done correctly. */
> -		  while (1)
> -		    {
> -		      if (char_buffer_error (&charbuf))
> -			{
> -			  __set_errno (ENOMEM);
> -			  done = EOF;
> -			  goto errout;
> -			}
> -		      if (got_e && charbuf.current[-1] == exp_char
> -			  && (c == L_('-') || c == L_('+')))
> -			char_buffer_add (&charbuf, c);
> -		      else if (char_buffer_size (&charbuf) > got_sign && !got_e
> -			       && (CHAR_T) TOLOWER (c) == exp_char)
> -			{
> -			  char_buffer_add (&charbuf, exp_char);
> -			  got_e = got_dot = 1;
> -			}
> -		      else
> -			{
> -			  /* Check against localized digits, decimal point,
> -			     and thousands separator.  */
> -			  int n;
> -			  for (n = 0; n < 12; ++n)
> -			    {
> -#ifdef COMPILE_WSCANF
> -			      if (c == wcdigits[n])
> -				{
> -				  if (n < 10)
> -				    char_buffer_add (&charbuf, L_('0') + n);
> -				  else if (n == 11 && !got_dot)
> -				    {
> -				      char_buffer_add (&charbuf, decimal);
> -				      got_dot = 1;
> -				    }
> -				  else if (n == 10 && have_locthousands
> -					   && ! got_dot)
> -				    char_buffer_add (&charbuf, thousands);
> -				  else
> -				    /* The last read character is not part
> -				       of the number anymore.  */
> -				    n = 12;
> -
> -				  break;
> -				}
> -#else
> -			      const char *cmpp = mbdigits[n];
> -			      int avail = width > 0 ? width : INT_MAX;
> -
> -			      while ((unsigned char) *cmpp == c && avail >= 0)
> -				if (*++cmpp == '\0')
> -				  break;
> -				else
> -				  {
> -				    if (avail == 0 || inchar () == EOF)
> -				      break;
> -				    --avail;
> -				  }
> -			      if (*cmpp == '\0')
> -				{
> -				  if (width > 0)
> -				    width = avail;
> -
> -				  if (n < 10)
> -				    char_buffer_add (&charbuf, L_('0') + n);
> -				  else if (n == 11 && !got_dot)
> -				    {
> -				      /* Add all the characters.  */
> -				      for (cmpp = decimal; *cmpp != '\0';
> -					   ++cmpp)
> -					char_buffer_add (&charbuf,
> -							 (unsigned char) *cmpp);
> -
> -				      got_dot = 1;
> -				    }
> -				  else if (n == 10 && (flags & GROUP) != 0
> -					   && ! got_dot)
> -				    {
> -				      /* Add all the characters.  */
> -				      for (cmpp = thousands; *cmpp != '\0';
> -					   ++cmpp)
> -					char_buffer_add (&charbuf,
> -							 (unsigned char) *cmpp);
> -				    }
> -				  else
> -				    /* The last read character is not part
> -				       of the number anymore.  */
> -				      n = 12;
> -
> -				  break;
> -				}
> -
> -			      /* We are pushing all read characters back.  */
> -			      if (cmpp > mbdigits[n])
> -				{
> -				  ungetc (c, s);
> -				  while (--cmpp > mbdigits[n])
> -				    ungetc_not_eof ((unsigned char) *cmpp, s);
> -				  c = (unsigned char) *cmpp;
> -				}
> -#endif
> -			    }
> -
> -			  if (n >= 12)
> -			    {
> -			      /* The last read character is not part
> -				 of the number anymore.  */
> -			      ungetc (c, s);
> -			      break;
> -			    }
> -			}
> -
> -		      if (width == 0 || inchar () == EOF)
> -			break;
> -
> -		      if (width > 0)
> -			--width;
> -		    }
> -		}
> -
> -#ifndef COMPILE_WSCANF
> -	    no_i18nflt:
> -	      ;
> -#endif
> -	    }
> -
> -	  if (char_buffer_error (&charbuf))
> -	    {
> -	      __set_errno (ENOMEM);
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -
> -	  /* Have we read any character?  If we try to read a number
> -	     in hexadecimal notation and we have read only the `0x'
> -	     prefix this is an error.  */
> -	  if (__glibc_unlikely (char_buffer_size (&charbuf) == got_sign
> -				|| ((flags & HEXA_FLOAT)
> -				    && (char_buffer_size (&charbuf)
> -					== 2 + got_sign))))
> -	    conv_error ();
> -
> -	scan_float:
> -	  /* Convert the number.  */
> -	  char_buffer_add (&charbuf, L_('\0'));
> -	  if (char_buffer_error (&charbuf))
> -	    {
> -	      __set_errno (ENOMEM);
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
> -	    {
> -	      long double d = __strtold_internal
> -		(char_buffer_start (&charbuf), &tw, flags & GROUP);
> -	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> -		*ARG (long double *) = d;
> -	    }
> -	  else if (flags & (LONG | LONGDBL))
> -	    {
> -	      double d = __strtod_internal
> -		(char_buffer_start (&charbuf), &tw, flags & GROUP);
> -	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> -		*ARG (double *) = d;
> -	    }
> -	  else
> -	    {
> -	      float d = __strtof_internal
> -		(char_buffer_start (&charbuf), &tw, flags & GROUP);
> -	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> -		*ARG (float *) = d;
> -	    }
> -
> -	  if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))
> -	    conv_error ();
> -
> -	  if (!(flags & SUPPRESS))
> -	    ++done;
> -	  break;
> -
> -	case L_('['):	/* Character class.  */
> -	  if (flags & LONG)
> -	    STRING_ARG (wstr, wchar_t, 100);
> -	  else
> -	    STRING_ARG (str, char, 100);
> -
> -	  if (*f == L_('^'))
> -	    {
> -	      ++f;
> -	      not_in = 1;
> -	    }
> -	  else
> -	    not_in = 0;
> -
> -	  if (width < 0)
> -	    /* There is no width given so there is also no limit on the
> -	       number of characters we read.  Therefore we set width to
> -	       a very high value to make the algorithm easier.  */
> -	    width = INT_MAX;
> -
> -#ifdef COMPILE_WSCANF
> -	  /* Find the beginning and the end of the scanlist.  We are not
> -	     creating a lookup table since it would have to be too large.
> -	     Instead we search each time through the string.  This is not
> -	     a constant lookup time but who uses this feature deserves to
> -	     be punished.  */
> -	  tw = (wchar_t *) f;	/* Marks the beginning.  */
> -
> -	  if (*f == L']')
> -	    ++f;
> -
> -	  while ((fc = *f++) != L'\0' && fc != L']');
> -
> -	  if (__glibc_unlikely (fc == L'\0'))
> -	    conv_error ();
> -	  wchar_t *twend = (wchar_t *) f - 1;
> -#else
> -	  /* Fill WP with byte flags indexed by character.
> -	     We will use this flag map for matching input characters.  */
> -	  if (!scratch_buffer_set_array_size
> -	      (&charbuf.scratch, UCHAR_MAX + 1, 1))
> -	    {
> -	      done = EOF;
> -	      goto errout;
> -	    }
> -	  memset (charbuf.scratch.data, '\0', UCHAR_MAX + 1);
> -
> -	  fc = *f;
> -	  if (fc == ']' || fc == '-')
> -	    {
> -	      /* If ] or - appears before any char in the set, it is not
> -		 the terminator or separator, but the first char in the
> -		 set.  */
> -	      ((char *)charbuf.scratch.data)[fc] = 1;
> -	      ++f;
> -	    }
> -
> -	  while ((fc = *f++) != '\0' && fc != ']')
> -	    if (fc == '-' && *f != '\0' && *f != ']'
> -		&& (unsigned char) f[-2] <= (unsigned char) *f)
> -	      {
> -		/* Add all characters from the one before the '-'
> -		   up to (but not including) the next format char.  */
> -		for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
> -		  ((char *)charbuf.scratch.data)[fc] = 1;
> -	      }
> -	    else
> -	      /* Add the character to the flag map.  */
> -	      ((char *)charbuf.scratch.data)[fc] = 1;
> -
> -	  if (__glibc_unlikely (fc == '\0'))
> -	    conv_error();
> -#endif
> -
> -	  if (flags & LONG)
> -	    {
> -	      size_t now = read_in;
> -#ifdef COMPILE_WSCANF
> -	      if (__glibc_unlikely (inchar () == WEOF))
> -		input_error ();
> -
> -	      do
> -		{
> -		  wchar_t *runp;
> -
> -		  /* Test whether it's in the scanlist.  */
> -		  runp = tw;
> -		  while (runp < twend)
> -		    {
> -		      if (runp[0] == L'-' && runp[1] != '\0'
> -			  && runp + 1 != twend
> -			  && runp != tw
> -			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
> -			{
> -			  /* Match against all characters in between the
> -			     first and last character of the sequence.  */
> -			  wchar_t wc;
> -
> -			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
> -			    if ((wint_t) wc == c)
> -			      break;
> -
> -			  if (wc <= runp[1] && !not_in)
> -			    break;
> -			  if (wc <= runp[1] && not_in)
> -			    {
> -			      /* The current character is not in the
> -				 scanset.  */
> -			      ungetc (c, s);
> -			      goto out;
> -			    }
> -
> -			  runp += 2;
> -			}
> -		      else
> -			{
> -			  if ((wint_t) *runp == c && !not_in)
> -			    break;
> -			  if ((wint_t) *runp == c && not_in)
> -			    {
> -			      ungetc (c, s);
> -			      goto out;
> -			    }
> -
> -			  ++runp;
> -			}
> -		    }
> -
> -		  if (runp == twend && !not_in)
> -		    {
> -		      ungetc (c, s);
> -		      goto out;
> -		    }
> -
> -		  if (!(flags & SUPPRESS))
> -		    {
> -		      *wstr++ = c;
> -
> -		      if ((flags & MALLOC)
> -			  && wstr == (wchar_t *) *strptr + strsize)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  wstr = (wchar_t *) realloc (*strptr,
> -						      (2 * strsize)
> -						      * sizeof (wchar_t));
> -			  if (wstr == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      wstr = (wchar_t *)
> -				realloc (*strptr, (strsize + 1)
> -						  * sizeof (wchar_t));
> -			      if (wstr == NULL)
> -				{
> -				  if (flags & POSIX_MALLOC)
> -				    {
> -				      done = EOF;
> -				      goto errout;
> -				    }
> -				  /* We lose.  Oh well.  Terminate the string
> -				     and stop converting, so at least we don't
> -				     skip any input.  */
> -				  ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> -				  strptr = NULL;
> -				  ++done;
> -				  conv_error ();
> -				}
> -			      else
> -				{
> -				  *strptr = (char *) wstr;
> -				  wstr += strsize;
> -				  ++strsize;
> -				}
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) wstr;
> -			      wstr += strsize;
> -			      strsize *= 2;
> -			    }
> -			}
> -		    }
> -		}
> -	      while (--width > 0 && inchar () != WEOF);
> -	    out:
> -#else
> -	      char buf[MB_LEN_MAX];
> -	      size_t cnt = 0;
> -	      mbstate_t cstate;
> -
> -	      if (__glibc_unlikely (inchar () == EOF))
> -		input_error ();
> -
> -	      memset (&cstate, '\0', sizeof (cstate));
> -
> -	      do
> -		{
> -		  if (((char *) charbuf.scratch.data)[c] == not_in)
> -		    {
> -		      ungetc_not_eof (c, s);
> -		      break;
> -		    }
> -
> -		  /* This is easy.  */
> -		  if (!(flags & SUPPRESS))
> -		    {
> -		      size_t n;
> -
> -		      /* Convert it into a wide character.  */
> -		      buf[0] = c;
> -		      n = __mbrtowc (wstr, buf, 1, &cstate);
> -
> -		      if (n == (size_t) -2)
> -			{
> -			  /* Possibly correct character, just not enough
> -			     input.  */
> -			  ++cnt;
> -			  assert (cnt < MB_LEN_MAX);
> -			  continue;
> -			}
> -		      cnt = 0;
> -
> -		      ++wstr;
> -		      if ((flags & MALLOC)
> -			  && wstr == (wchar_t *) *strptr + strsize)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  wstr = (wchar_t *) realloc (*strptr,
> -						      (2 * strsize
> -						       * sizeof (wchar_t)));
> -			  if (wstr == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      wstr = (wchar_t *)
> -				realloc (*strptr, ((strsize + 1)
> -						   * sizeof (wchar_t)));
> -			      if (wstr == NULL)
> -				{
> -				  if (flags & POSIX_MALLOC)
> -				    {
> -				      done = EOF;
> -				      goto errout;
> -				    }
> -				  /* We lose.  Oh well.  Terminate the
> -				     string and stop converting,
> -				     so at least we don't skip any input.  */
> -				  ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> -				  strptr = NULL;
> -				  ++done;
> -				  conv_error ();
> -				}
> -			      else
> -				{
> -				  *strptr = (char *) wstr;
> -				  wstr += strsize;
> -				  ++strsize;
> -				}
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) wstr;
> -			      wstr += strsize;
> -			      strsize *= 2;
> -			    }
> -			}
> -		    }
> -
> -		  if (--width <= 0)
> -		    break;
> -		}
> -	      while (inchar () != EOF);
> -
> -	      if (__glibc_unlikely (cnt != 0))
> -		/* We stopped in the middle of recognizing another
> -		   character.  That's a problem.  */
> -		encode_error ();
> -#endif
> -
> -	      if (__glibc_unlikely (now == read_in))
> -		/* We haven't succesfully read any character.  */
> -		conv_error ();
> -
> -	      if (!(flags & SUPPRESS))
> -		{
> -		  *wstr++ = L'\0';
> -
> -		  if ((flags & MALLOC)
> -		      && wstr - (wchar_t *) *strptr != strsize)
> -		    {
> -		      wchar_t *cp = (wchar_t *)
> -			realloc (*strptr, ((wstr - (wchar_t *) *strptr)
> -					   * sizeof(wchar_t)));
> -		      if (cp != NULL)
> -			*strptr = (char *) cp;
> -		    }
> -		  strptr = NULL;
> -
> -		  ++done;
> -		}
> -	    }
> -	  else
> -	    {
> -	      size_t now = read_in;
> -
> -	      if (__glibc_unlikely (inchar () == EOF))
> -		input_error ();
> -
> -#ifdef COMPILE_WSCANF
> -
> -	      memset (&state, '\0', sizeof (state));
> -
> -	      do
> -		{
> -		  wchar_t *runp;
> -		  size_t n;
> -
> -		  /* Test whether it's in the scanlist.  */
> -		  runp = tw;
> -		  while (runp < twend)
> -		    {
> -		      if (runp[0] == L'-' && runp[1] != '\0'
> -			  && runp + 1 != twend
> -			  && runp != tw
> -			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
> -			{
> -			  /* Match against all characters in between the
> -			     first and last character of the sequence.  */
> -			  wchar_t wc;
> -
> -			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
> -			    if ((wint_t) wc == c)
> -			      break;
> -
> -			  if (wc <= runp[1] && !not_in)
> -			    break;
> -			  if (wc <= runp[1] && not_in)
> -			    {
> -			      /* The current character is not in the
> -				 scanset.  */
> -			      ungetc (c, s);
> -			      goto out2;
> -			    }
> -
> -			  runp += 2;
> -			}
> -		      else
> -			{
> -			  if ((wint_t) *runp == c && !not_in)
> -			    break;
> -			  if ((wint_t) *runp == c && not_in)
> -			    {
> -			      ungetc (c, s);
> -			      goto out2;
> -			    }
> -
> -			  ++runp;
> -			}
> -		    }
> -
> -		  if (runp == twend && !not_in)
> -		    {
> -		      ungetc (c, s);
> -		      goto out2;
> -		    }
> -
> -		  if (!(flags & SUPPRESS))
> -		    {
> -		      if ((flags & MALLOC)
> -			  && *strptr + strsize - str <= MB_LEN_MAX)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  size_t strleng = str - *strptr;
> -			  char *newstr;
> -
> -			  newstr = (char *) realloc (*strptr, 2 * strsize);
> -			  if (newstr == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      newstr = (char *) realloc (*strptr,
> -							 strleng + MB_LEN_MAX);
> -			      if (newstr == NULL)
> -				{
> -				  if (flags & POSIX_MALLOC)
> -				    {
> -				      done = EOF;
> -				      goto errout;
> -				    }
> -				  /* We lose.  Oh well.  Terminate the string
> -				     and stop converting, so at least we don't
> -				     skip any input.  */
> -				  ((char *) (*strptr))[strleng] = '\0';
> -				  strptr = NULL;
> -				  ++done;
> -				  conv_error ();
> -				}
> -			      else
> -				{
> -				  *strptr = newstr;
> -				  str = newstr + strleng;
> -				  strsize = strleng + MB_LEN_MAX;
> -				}
> -			    }
> -			  else
> -			    {
> -			      *strptr = newstr;
> -			      str = newstr + strleng;
> -			      strsize *= 2;
> -			    }
> -			}
> -		    }
> -
> -		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
> -		  if (__glibc_unlikely (n == (size_t) -1))
> -		    encode_error ();
> -
> -		  assert (n <= MB_LEN_MAX);
> -		  str += n;
> -		}
> -	      while (--width > 0 && inchar () != WEOF);
> -	    out2:
> -#else
> -	      do
> -		{
> -		  if (((char *) charbuf.scratch.data)[c] == not_in)
> -		    {
> -		      ungetc_not_eof (c, s);
> -		      break;
> -		    }
> -
> -		  /* This is easy.  */
> -		  if (!(flags & SUPPRESS))
> -		    {
> -		      *str++ = c;
> -		      if ((flags & MALLOC)
> -			  && (char *) str == *strptr + strsize)
> -			{
> -			  /* Enlarge the buffer.  */
> -			  size_t newsize = 2 * strsize;
> -
> -			allocagain:
> -			  str = (char *) realloc (*strptr, newsize);
> -			  if (str == NULL)
> -			    {
> -			      /* Can't allocate that much.  Last-ditch
> -				 effort.  */
> -			      if (newsize > strsize + 1)
> -				{
> -				  newsize = strsize + 1;
> -				  goto allocagain;
> -				}
> -			      if (flags & POSIX_MALLOC)
> -				{
> -				  done = EOF;
> -				  goto errout;
> -				}
> -			      /* We lose.  Oh well.  Terminate the
> -				 string and stop converting,
> -				 so at least we don't skip any input.  */
> -			      ((char *) (*strptr))[strsize - 1] = '\0';
> -			      strptr = NULL;
> -			      ++done;
> -			      conv_error ();
> -			    }
> -			  else
> -			    {
> -			      *strptr = (char *) str;
> -			      str += strsize;
> -			      strsize = newsize;
> -			    }
> -			}
> -		    }
> -		}
> -	      while (--width > 0 && inchar () != EOF);
> -#endif
> -
> -	      if (__glibc_unlikely (now == read_in))
> -		/* We haven't succesfully read any character.  */
> -		conv_error ();
> -
> -	      if (!(flags & SUPPRESS))
> -		{
> -#ifdef COMPILE_WSCANF
> -		  /* We have to emit the code to get into the initial
> -		     state.  */
> -		  char buf[MB_LEN_MAX];
> -		  size_t n = __wcrtomb (buf, L'\0', &state);
> -		  if (n > 0 && (flags & MALLOC)
> -		      && str + n >= *strptr + strsize)
> -		    {
> -		      /* Enlarge the buffer.  */
> -		      size_t strleng = str - *strptr;
> -		      char *newstr;
> -
> -		      newstr = (char *) realloc (*strptr, strleng + n + 1);
> -		      if (newstr == NULL)
> -			{
> -			  if (flags & POSIX_MALLOC)
> -			    {
> -			      done = EOF;
> -			      goto errout;
> -			    }
> -			  /* We lose.  Oh well.  Terminate the string
> -			     and stop converting, so at least we don't
> -			     skip any input.  */
> -			  ((char *) (*strptr))[strleng] = '\0';
> -			  strptr = NULL;
> -			  ++done;
> -			  conv_error ();
> -			}
> -		      else
> -			{
> -			  *strptr = newstr;
> -			  str = newstr + strleng;
> -			  strsize = strleng + n + 1;
> -			}
> -		    }
> -
> -		  str = __mempcpy (str, buf, n);
> -#endif
> -		  *str++ = '\0';
> -
> -		  if ((flags & MALLOC) && str - *strptr != strsize)
> -		    {
> -		      char *cp = (char *) realloc (*strptr, str - *strptr);
> -		      if (cp != NULL)
> -			*strptr = cp;
> -		    }
> -		  strptr = NULL;
> -
> -		  ++done;
> -		}
> -	    }
> -	  break;
> -
> -	case L_('p'):	/* Generic pointer.  */
> -	  base = 16;
> -	  /* A PTR must be the same size as a `long int'.  */
> -	  flags &= ~(SHORT|LONGDBL);
> -	  if (need_long)
> -	    flags |= LONG;
> -	  flags |= READ_POINTER;
> -	  goto number;
> -
> -	default:
> -	  /* If this is an unknown format character punt.  */
> -	  conv_error ();
> -	}
> -    }
> -
> -  /* The last thing we saw int the format string was a white space.
> -     Consume the last white spaces.  */
> -  if (skip_space)
> -    {
> -      do
> -	c = inchar ();
> -      while (ISSPACE (c));
> -      ungetc (c, s);
> -    }
> -
> - errout:
> -  /* Unlock stream.  */
> -  UNLOCK_STREAM (s);
> -
> -  scratch_buffer_free (&charbuf.scratch);
> -  if (errp != NULL)
> -    *errp |= errval;
> -
> -  if (__glibc_unlikely (done == EOF))
> -    {
> -      if (__glibc_unlikely (ptrs_to_free != NULL))
> -	{
> -	  struct ptrs_to_free *p = ptrs_to_free;
> -	  while (p != NULL)
> -	    {
> -	      for (size_t cnt = 0; cnt < p->count; ++cnt)
> -		{
> -		  free (*p->ptrs[cnt]);
> -		  *p->ptrs[cnt] = NULL;
> -		}
> -	      p = p->next;
> -	      ptrs_to_free = p;
> -	    }
> -	}
> -    }
> -  else if (__glibc_unlikely (strptr != NULL))
> -    {
> -      free (*strptr);
> -      *strptr = NULL;
> -    }
> -  return done;
> -}
> -
> -#ifdef COMPILE_WSCANF
> -int
> -__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> -{
> -  return _IO_vfwscanf (s, format, argptr, NULL);
> -}
> -ldbl_weak_alias (__vfwscanf, vfwscanf)
> -#else
>  int
>  ___vfscanf (FILE *s, const char *format, va_list argptr)
>  {
> -  return _IO_vfscanf_internal (s, format, argptr, NULL);
> +  return __vfscanf_internal (s, format, argptr, 0);
>  }
> -ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
>  ldbl_strong_alias (___vfscanf, __vfscanf)
>  ldbl_hidden_def (___vfscanf, __vfscanf)
>  ldbl_weak_alias (___vfscanf, vfscanf)
> -#endif

Ok.

> diff --git a/stdio-common/vfwscanf-internal.c b/stdio-common/vfwscanf-internal.c
> new file mode 100644
> index 0000000000..26c89270b7
> --- /dev/null
> +++ b/stdio-common/vfwscanf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WSCANF	1
> +#include "vfscanf-internal.c"
> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
> index 26b1a66608..86980464c2 100644
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf.c
> @@ -1,2 +1,26 @@
> -#define COMPILE_WSCANF	1
> -#include "vfscanf.c"
> +/* Implementation and symbols for vfwscanf.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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 the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <libioP.h>
> +
> +int
> +__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> +{
> +  return __vfwscanf_internal (s, format, argptr, 0);
> +}
> +ldbl_weak_alias (__vfwscanf, vfwscanf)

Ok.

> diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
> index 8a5d8ba107..92f670dff7 100644
> --- a/sysdeps/generic/math_ldbl_opt.h
> +++ b/sysdeps/generic/math_ldbl_opt.h
> @@ -6,9 +6,13 @@
>     for platforms where compatibility symbols are required for a previous
>     ABI that defined long double functions as aliases for the double code.  */
>  
> +#include <shlib-compat.h>
> +
>  #define LONG_DOUBLE_COMPAT(lib, introduced) 0
>  #define long_double_symbol(lib, local, symbol)
>  #define ldbl_hidden_def(local, name) libc_hidden_def (name)
>  #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
>  #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +#define ldbl_compat_symbol(lib, local, symbol, version) \
> +  compat_symbol (lib, local, symbol, version)
>  #define __ldbl_is_dbl 0

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> index 61ba784f86..1c49036f7b 100644
> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> @@ -20,10 +20,16 @@
>    long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
>  # define long_double_symbol_1(lib, local, symbol, version) \
>    versioned_symbol (lib, local, symbol, version)
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> +  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
>  #else
>  # define ldbl_hidden_def(local, name) libc_hidden_def (name)
>  # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
>  # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +/* Same as compat_symbol, ldbl_compat_symbol is not to be used outside
> +   '#if SHLIB_COMPAT' statement and should fail if it is.  */
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> +  _Static_assert (0, "ldbl_compat_symbol should be used inside SHLIB_COMPAT");
>  # ifndef __ASSEMBLER__
>  /* Note that weak_alias cannot be used - it is defined to nothing
>     in most of the C files.  */

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 7a1e89c1a3..91ea27a423 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -330,16 +330,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
>    return done;
>  }
>  
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>  int
>  attribute_compat_text_section
>  __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfscanf (s, fmt, ap, errp);
> +  res = __vfscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
> +  if (__glibc_unlikely (errp != 0))
> +    *errp = (res == -1);
>    return res;
>  }
> +#endif
>  
>  int
>  attribute_compat_text_section
> @@ -347,7 +351,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfscanf (s, fmt, ap, NULL);
> +  res = __vfscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -423,7 +427,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfwscanf (s, fmt, ap, NULL);
> +  res = __vfwscanf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -1027,7 +1031,6 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
> -compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
> @@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
>  compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
> +/* This function is not in public headers, but was exported until
> +   version 2.29.  For platforms that are newer than that, there's no
> +   need to expose the symbol.  */
> +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> +compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +# endif
>  #endif
>  #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
>  compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);

Ok.

> diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
> index 0c6a2c47ac..00b07dd48e 100644
> --- a/wcsmbs/isoc99_fwscanf.c
> +++ b/wcsmbs/isoc99_fwscanf.c
> @@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stream, format, arg, NULL);
> +  done = __vfwscanf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stream);

Ok.

> diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
> index ff523db706..40401d0aa1 100644
> --- a/wcsmbs/isoc99_swscanf.c
> +++ b/wcsmbs/isoc99_swscanf.c
> @@ -16,20 +16,22 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#include <wchar.h>
> +#include <libio/strfile.h>
>  
>  /* Read formatted input from S, according to the format string FORMAT.  */
> -/* VARARGS2 */
> +
>  int
>  __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __isoc99_vswscanf (s, format, arg);
> +  done = __vfwscanf_internal (f, format, arg, 0);
>    va_end (arg);
>  
>    return done;

As before I think it requires to acquire the file lock before setting
_flags2.

> diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
> index 7beb45b4d3..f70c6b596d 100644
> --- a/wcsmbs/isoc99_vfwscanf.c
> +++ b/wcsmbs/isoc99_vfwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stream);
>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfwscanf (stream, format, args, NULL);
> +  done = __vfwscanf_internal (stream, format, args, 0);
>    _IO_release_lock (stream);
>    return done;
>  }

Ok.

> diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
> index 130769154d..b91eb651a3 100644
> --- a/wcsmbs/isoc99_vswscanf.c
> +++ b/wcsmbs/isoc99_vswscanf.c
> @@ -24,24 +24,16 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <libioP.h>
>  #include <wchar.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>  
>  int
>  __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
>  {
> -  int ret;
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> -  _IO_fwide (&sf._sbf._f, 1);
> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> -  return ret;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> +  return __vfwscanf_internal (f, format, args, 0);
>  }
>  libc_hidden_def (__isoc99_vswscanf)

As before I think it requires to acquire the file lock before setting
_flags2.

> diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
> index 049521b964..eb22c8acae 100644
> --- a/wcsmbs/isoc99_vwscanf.c
> +++ b/wcsmbs/isoc99_vwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
>  
>    _IO_acquire_lock_clear_flags2 (stdin);
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = _IO_vfwscanf (stdin, format, args, NULL);
> +  done = __vfwscanf_internal (stdin, format, args, 0);
>    _IO_release_lock (stdin);
>    return done;
>  }

Ok.

> diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
> index abfbd50c11..59f80d78fb 100644
> --- a/wcsmbs/isoc99_wscanf.c
> +++ b/wcsmbs/isoc99_wscanf.c
> @@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
>    stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = _IO_vfwscanf (stdin, format, arg, NULL);
> +  done = __vfwscanf_internal (stdin, format, arg, 0);
>    va_end (arg);
>  
>    _IO_release_lock (stdin);
> 

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
  2018-11-15 21:46 ` [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Gabriel F. T. Gomes
@ 2018-11-22 17:38   ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:38 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2
> 
>   - None, but dependent on previous patch in the set, thus resending.

LGTM.

> 
> Changes since v1:
> 
>   - Cleared VARGARSn comments.
>   - Added signed-off-by statements.
> 
> -- 8< --
> Change the callers of __vfscanf_internal and __vfwscanf_internal that
> want C99-compliant behavior to communicate this via the new flags
> argument, rather than setting bits on the FILE object.  This also
> means these functions do not need to do their own locking.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* stdio-common/isoc99_scanf.c
> 	* stdio-common/isoc99_fscanf.c
> 	* stdio-common/isoc99_sscanf.c
> 	* stdio-common/isoc99_vscanf.c
> 	* stdio-common/isoc99_vfscanf.c
> 	* stdio-common/isoc99_vsscanf.c
> 	* wcsmbs/isoc99_wscanf.c
> 	* wcsmbs/isoc99_fwscanf.c
> 	* wcsmbs/isoc99_swscanf.c
> 	* wcsmbs/isoc99_vwscanf.c
> 	* wcsmbs/isoc99_vfwscanf.c
> 	* wcsmbs/isoc99_vswscanf.c:
> 	Pass SCANF_ISOC99_A to __vfscanf_internal and/or __vfwscanf_internal.
> 	Do not set _IO_FLAGS2_SCANF_STD on the FILE passed to that function.
> 	No need to lock and unlock the FILE passed to that function.
> 
> 	* stdio-common/vfscanf-internal.c
> 	(__vfscanf_internal, __vfwscanf_internal):
> 	Don't look at _IO_FLAGS2_SCANF_STD.
> 	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct)
> 	(_IO_release_lock): Don't clear _IO_FLAGS2_SCANF_STD.
> 	* libio/libio.h (_IO_FLAGS2_SCANF_STD): Delete.
> ---
>  libio/libio.h                   |  1 -
>  libio/libioP.h                  |  5 ++---
>  stdio-common/isoc99_fscanf.c    |  7 +------
>  stdio-common/isoc99_scanf.c     | 12 +-----------
>  stdio-common/isoc99_sscanf.c    |  3 +--
>  stdio-common/isoc99_vfscanf.c   |  9 +--------
>  stdio-common/isoc99_vscanf.c    |  9 +--------
>  stdio-common/isoc99_vsscanf.c   |  3 +--
>  stdio-common/vfscanf-internal.c |  2 --
>  wcsmbs/isoc99_fwscanf.c         |  7 +------
>  wcsmbs/isoc99_swscanf.c         |  3 +--
>  wcsmbs/isoc99_vfwscanf.c        |  9 +--------
>  wcsmbs/isoc99_vswscanf.c        |  3 +--
>  wcsmbs/isoc99_vwscanf.c         |  9 +--------
>  wcsmbs/isoc99_wscanf.c          |  7 +------
>  15 files changed, 14 insertions(+), 75 deletions(-)
> 
> diff --git a/libio/libio.h b/libio/libio.h
> index d4eba2df54..30cb7d784f 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -92,7 +92,6 @@ typedef union
>  #define _IO_FLAGS2_NOTCANCEL 2
>  #define _IO_FLAGS2_FORTIFY 4
>  #define _IO_FLAGS2_USER_WBUF 8
> -#define _IO_FLAGS2_SCANF_STD 16
>  #define _IO_FLAGS2_NOCLOSE 32
>  #define _IO_FLAGS2_CLOEXEC 64
>  #define _IO_FLAGS2_NEED_LOCK 128
> diff --git a/libio/libioP.h b/libio/libioP.h
> index 525dce19ee..9e971cb96b 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -786,7 +786,7 @@ __attribute__ ((__always_inline__))
>  _IO_acquire_lock_clear_flags2_fct (FILE **p)
>  {
>    FILE *fp = *p;
> -  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY | _IO_FLAGS2_SCANF_STD);
> +  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
>    if ((fp->_flags & _IO_USER_LOCK) == 0)
>      _IO_funlockfile (fp);
>  }
> @@ -800,8 +800,7 @@ _IO_acquire_lock_clear_flags2_fct (FILE **p)
>      FILE *_IO_acquire_lock_file = (_fp)
>  # define _IO_release_lock(_fp)						      \
>      if (_IO_acquire_lock_file != NULL)					      \
> -      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY		      \
> -                                          | _IO_FLAGS2_SCANF_STD);	      \
> +      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
>    } while (0)
>  #endif
>  
> diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
> index 4210d11f2b..d7b5993f3e 100644
> --- a/stdio-common/isoc99_fscanf.c
> +++ b/stdio-common/isoc99_fscanf.c
> @@ -20,20 +20,15 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_fscanf (FILE *stream, const char *format, ...)
>  {
>    va_list arg;
>    int done;
>  
> -  _IO_acquire_lock_clear_flags2 (stream);
> -  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
>    va_start (arg, format);
> -  done = __vfscanf_internal (stream, format, arg, 0);
> +  done = __vfscanf_internal (stream, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
> -  _IO_release_lock (stream);
>    return done;
>  }
> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
> index 64c873eed9..3998322ea1 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/isoc99_scanf.c
> @@ -19,26 +19,16 @@
>  #include <stdio.h>
>  #include <libioP.h>
>  
> -
>  /* Read formatted input from stdin according to the format string FORMAT.  */
> -/* VARARGS1 */
>  int
>  __isoc99_scanf (const char *format, ...)
>  {
>    va_list arg;
>    int done;
>  
> -#ifdef _IO_MTSAFE_IO
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -#endif
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
>    va_start (arg, format);
> -  done = __vfscanf_internal (stdin, format, arg, 0);
> +  done = __vfscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
> -#ifdef _IO_MTSAFE_IO
> -  _IO_release_lock (stdin);
> -#endif
>    return done;
>  }
> diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
> index 2c89a03fe9..c9e5103b81 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -26,10 +26,9 @@ __isoc99_sscanf (const char *s, const char *format, ...)
>    int done;
>    _IO_strfile sf;
>    FILE *f = _IO_strfile_read (&sf, s);
> -  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __vfscanf_internal (f, format, arg, 0);
> +  done = __vfscanf_internal (f, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
>    return done;
> diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
> index c96ca831ae..3c59c60b3e 100644
> --- a/stdio-common/isoc99_vfscanf.c
> +++ b/stdio-common/isoc99_vfscanf.c
> @@ -19,16 +19,9 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
>  {
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stream);
> -  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = __vfscanf_internal (stream, format, args, 0);
> -  _IO_release_lock (stream);
> -  return done;
> +  return __vfscanf_internal (stream, format, args, SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__isoc99_vfscanf)
> diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
> index 72ae72ddee..fc5d609ae7 100644
> --- a/stdio-common/isoc99_vscanf.c
> +++ b/stdio-common/isoc99_vscanf.c
> @@ -19,15 +19,8 @@
>  #include <stdio.h>
>  
>  /* Read formatted input from STDIN according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_vscanf (const char *format, va_list args)
>  {
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = __vfscanf_internal (stdin, format, args, 0);
> -  _IO_release_lock (stdin);
> -  return done;
> +  return __vfscanf_internal (stdin, format, args, SCANF_ISOC99_A);
>  }
> diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
> index 02bc0f50e6..dfc394bb51 100644
> --- a/stdio-common/isoc99_vsscanf.c
> +++ b/stdio-common/isoc99_vsscanf.c
> @@ -31,7 +31,6 @@ __isoc99_vsscanf (const char *string, const char *format, va_list args)
>  {
>    _IO_strfile sf;
>    FILE *f = _IO_strfile_read (&sf, string);
> -  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  return __vfscanf_internal (f, format, args, 0);
> +  return __vfscanf_internal (f, format, args, SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__isoc99_vsscanf)
> diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
> index 13a7a300b7..f0072d8682 100644
> --- a/stdio-common/vfscanf-internal.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -335,8 +335,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    /* Temporarily honor the environmental mode bits.  */
>    if (__ldbl_is_dbl)
>      mode_flags |= SCANF_LDBL_IS_DBL;
> -  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> -    mode_flags |= SCANF_ISOC99_A;
>  
>  #ifdef __va_copy
>    __va_copy (arg, argptr);
> diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
> index 00b07dd48e..5829607916 100644
> --- a/wcsmbs/isoc99_fwscanf.c
> +++ b/wcsmbs/isoc99_fwscanf.c
> @@ -21,20 +21,15 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
>  
> -  _IO_acquire_lock_clear_flags2 (stream);
> -  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
>    va_start (arg, format);
> -  done = __vfwscanf_internal (stream, format, arg, 0);
> +  done = __vfwscanf_internal (stream, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
> -  _IO_release_lock (stream);
>    return done;
>  }
> diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
> index 40401d0aa1..f90e56d97f 100644
> --- a/wcsmbs/isoc99_swscanf.c
> +++ b/wcsmbs/isoc99_swscanf.c
> @@ -28,10 +28,9 @@ __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
>    FILE *f = _IO_strfile_readw (&sf, &wd, s);
> -  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>  
>    va_start (arg, format);
> -  done = __vfwscanf_internal (f, format, arg, 0);
> +  done = __vfwscanf_internal (f, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
>    return done;
> diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
> index f70c6b596d..715d354b5a 100644
> --- a/wcsmbs/isoc99_vfwscanf.c
> +++ b/wcsmbs/isoc99_vfwscanf.c
> @@ -20,16 +20,9 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STREAM according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
>  {
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stream);
> -  stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = __vfwscanf_internal (stream, format, args, 0);
> -  _IO_release_lock (stream);
> -  return done;
> +  return __vfwscanf_internal (stream, format, args, SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__isoc99_vfwscanf)
> diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
> index b91eb651a3..0d8ef7611a 100644
> --- a/wcsmbs/isoc99_vswscanf.c
> +++ b/wcsmbs/isoc99_vswscanf.c
> @@ -33,7 +33,6 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
>    _IO_strfile sf;
>    struct _IO_wide_data wd;
>    FILE *f = _IO_strfile_readw (&sf, &wd, string);
> -  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  return __vfwscanf_internal (f, format, args, 0);
> +  return __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__isoc99_vswscanf)
> diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
> index eb22c8acae..3ac3182608 100644
> --- a/wcsmbs/isoc99_vwscanf.c
> +++ b/wcsmbs/isoc99_vwscanf.c
> @@ -20,15 +20,8 @@
>  #include <wchar.h>
>  
>  /* Read formatted input from STDIN according to the format string FORMAT.  */
> -/* VARARGS2 */
>  int
>  __isoc99_vwscanf (const wchar_t *format, va_list args)
>  {
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -  done = __vfwscanf_internal (stdin, format, args, 0);
> -  _IO_release_lock (stdin);
> -  return done;
> +  return __vfwscanf_internal (stdin, format, args, SCANF_ISOC99_A);
>  }
> diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
> index 59f80d78fb..b9418f7912 100644
> --- a/wcsmbs/isoc99_wscanf.c
> +++ b/wcsmbs/isoc99_wscanf.c
> @@ -22,20 +22,15 @@
>  
>  
>  /* Read formatted input from stdin according to the format string FORMAT.  */
> -/* VARARGS1 */
>  int
>  __isoc99_wscanf (const wchar_t *format, ...)
>  {
>    va_list arg;
>    int done;
>  
> -  _IO_acquire_lock_clear_flags2 (stdin);
> -  stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
>    va_start (arg, format);
> -  done = __vfwscanf_internal (stdin, format, arg, 0);
> +  done = __vfwscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
>    va_end (arg);
>  
> -  _IO_release_lock (stdin);
>    return done;
>  }
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-11-15 21:46 ` [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Gabriel F. T. Gomes
@ 2018-11-22 17:39   ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:39 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2
> 
>   - None, but dependent on previous patch in the set, thus resending.

LGTM.

> 
> Changed since v1:
> 
>   - In __nldbl___isoc99_vwscanf, called __vfwscanf_internal directly
>     (missing (accidentally?) from the previous version).
>   - Broke long lines.
>   - Changed name of variable (from rv to ret), since the rationale for
>     making these changes to variables names is consistency.
>   - Added signed-off-by statements.
> 
> -- 8< --
> Change the callers of __vfscanf_internal and __vfwscanf_internal that
> want to treat 'long double' as another name for 'double' (all of which
> happen to be in sysdeps/ieee754/ldbl-opt/nldbl-compat.c) to communicate
> this via the new flags argument, instead of the per-thread variable
> __no_long_double and its __ldbl_is_dbl wrapper macro.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* stdio-common/vfscanf-internal.c: Don't look at __ldbl_is_dbl.
> 	* sysdeps/ieee754/ldbl-opt/ndlbl-compat.c:
> 	Include libio/strfile.h instead of libioP.h.
> 	(__nldbl_IO_vfscanf, __ndlbl___vfscanf, __nldbl_sscanf)
> 	(__nldbl___vsscanf, __nldbl_vscanf, __nldbl_fscanf)
> 	(__nldbl_scanf, __nldbl_vfwscanf, __nldbl_swscanf)
> 	(__nldbl_vswscanf, __nldbl_vwscanf, __nldbl_fwscanf)
> 	(__nldbl_wscanf): Call __vfscanf_internal / __vfwscanf_internal
> 	directly, passing SCANF_LDBL_IS_DBL.  Set up a strfile if
> 	necessary.  Do not set __no_long_double.  Normalize variable names.
> 	(__nldbl___isoc99_vfscanf, __nldbl___isoc99_sscanf)
> 	(__nldbl___isoc99_vsscanf, __nldbl___isoc99_vscanf)
> 	(__nldbl___isoc99_fscanf, __nldbl___isoc99_scanf)
> 	(__nldbl___isoc99_vfwscanf, __nldbl___isoc99_swscanf)
> 	(__nldbl___isoc99_vswscanf, __nldbl___isoc99_vwscanf)
> 	(__nldbl___isoc99_fwscanf, __nldbl___isoc99_wscanf):
> 	Call __vfscanf_internal / __vfwscanf_internal directly, passing
> 	SCANF_LDBL_IS_DBL | SCANF_ISOC99_A.  Set up a strfile if necessary.
> 	Do not set __no_long_double.  Normalize variable names.
> ---
>  stdio-common/vfscanf-internal.c         |   4 -
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 251 +++++++++++++++-----------------
>  2 files changed, 121 insertions(+), 134 deletions(-)
> 
> diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
> index f0072d8682..818b558140 100644
> --- a/stdio-common/vfscanf-internal.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -332,10 +332,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
>    struct char_buffer charbuf;
>    scratch_buffer_init (&charbuf.scratch);
>  
> -  /* Temporarily honor the environmental mode bits.  */
> -  if (__ldbl_is_dbl)
> -    mode_flags |= SCANF_LDBL_IS_DBL;
> -
>  #ifdef __va_copy
>    __va_copy (arg, argptr);
>  #else
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 91ea27a423..468e23dec4 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -19,7 +19,7 @@
>  
>  #include <stdarg.h>
>  #include <stdio.h>
> -#include <libioP.h>
> +#include <libio/strfile.h>
>  #include <math.h>
>  #include <wchar.h>
>  #include <printf.h>
> @@ -335,13 +335,10 @@ int
>  attribute_compat_text_section
>  __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfscanf_internal (s, fmt, ap, 0);
> -  clear_no_long_double ();
> +  int ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
>    if (__glibc_unlikely (errp != 0))
> -    *errp = (res == -1);
> -  return res;
> +    *errp = (ret == -1);
> +  return ret;
>  }
>  #endif
>  
> @@ -349,11 +346,7 @@ int
>  attribute_compat_text_section
>  __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfscanf_internal (s, fmt, ap, 0);
> -  clear_no_long_double ();
> -  return res;
> +  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  weak_alias (__nldbl___vfscanf, __nldbl_vfscanf)
>  libc_hidden_def (__nldbl_vfscanf)
> @@ -362,26 +355,26 @@ int
>  attribute_compat_text_section
>  __nldbl_sscanf (const char *s, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vsscanf (s, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  strong_alias (__nldbl_sscanf, __nldbl__IO_sscanf)
>  
>  int
>  attribute_compat_text_section
> -__nldbl___vsscanf (const char *string, const char *fmt, va_list ap)
> +__nldbl___vsscanf (const char *s, const char *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = _IO_vsscanf (string, fmt, ap);
> -  __no_long_double = 0;
> -  return res;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  weak_alias (__nldbl___vsscanf, __nldbl_vsscanf)
>  libc_hidden_def (__nldbl_vsscanf)
> @@ -390,46 +383,42 @@ int
>  attribute_compat_text_section weak_function
>  __nldbl_vscanf (const char *fmt, va_list ap)
>  {
> -  return __nldbl_vfscanf (stdin, fmt, ap);
> +  return __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_fscanf (FILE *stream, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfscanf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_scanf (const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfscanf (stdin, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfwscanf_internal (s, fmt, ap, 0);
> -  clear_no_long_double ();
> -  return res;
> +  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  libc_hidden_def (__nldbl_vfwscanf)
>  
> @@ -437,25 +426,28 @@ int
>  attribute_compat_text_section
>  __nldbl_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vswscanf (s, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl_vswscanf (const wchar_t *string, const wchar_t *fmt, va_list ap)
> +__nldbl_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = vswscanf (string, fmt, ap);
> -  __no_long_double = 0;
> -  return res;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +
> +  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  libc_hidden_def (__nldbl_vswscanf)
>  
> @@ -463,35 +455,35 @@ int
>  attribute_compat_text_section weak_function
>  __nldbl_vwscanf (const wchar_t *fmt, va_list ap)
>  {
> -  return __nldbl_vfwscanf (stdin, fmt, ap);
> +  return __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_fwscanf (FILE *stream, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfwscanf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_wscanf (const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfwscanf (stdin, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
> @@ -866,11 +858,7 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_vfscanf (FILE *s, const char *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __isoc99_vfscanf (s, fmt, ap);
> -  clear_no_long_double ();
> -  return res;
> +  return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__nldbl___isoc99_vfscanf)
>  
> @@ -878,25 +866,26 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_sscanf (const char *s, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vsscanf (s, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___isoc99_vsscanf (const char *string, const char *fmt, va_list ap)
> +__nldbl___isoc99_vsscanf (const char *s, const char *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __isoc99_vsscanf (string, fmt, ap);
> -  __no_long_double = 0;
> -  return res;
> +  _IO_strfile sf;
> +  FILE *f = _IO_strfile_read (&sf, s);
> +
> +  return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__nldbl___isoc99_vsscanf)
>  
> @@ -904,46 +893,44 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_vscanf (const char *fmt, va_list ap)
>  {
> -  return __nldbl___isoc99_vfscanf (stdin, fmt, ap);
> +  return __vfscanf_internal (stdin, fmt, ap,
> +			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___isoc99_fscanf (FILE *stream, const char *fmt, ...)
> +__nldbl___isoc99_fscanf (FILE *s, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vfscanf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___isoc99_scanf (const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfscanf_internal (stdin, fmt, ap,
> +			    SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __isoc99_vfwscanf (s, fmt, ap);
> -  clear_no_long_double ();
> -  return res;
> +  return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__nldbl___isoc99_vfwscanf)
>  
> @@ -951,26 +938,28 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vswscanf (s, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___isoc99_vswscanf (const wchar_t *string, const wchar_t *fmt,
> -			   va_list ap)
> +__nldbl___isoc99_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __isoc99_vswscanf (string, fmt, ap);
> -  __no_long_double = 0;
> -  return res;
> +  _IO_strfile sf;
> +  struct _IO_wide_data wd;
> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
> +
> +  return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  libc_hidden_def (__nldbl___isoc99_vswscanf)
>  
> @@ -978,35 +967,37 @@ int
>  attribute_compat_text_section
>  __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
>  {
> -  return __nldbl___isoc99_vfwscanf (stdin, fmt, ap);
> +  return __vfwscanf_internal (stdin, fmt, ap,
> +			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___isoc99_fwscanf (FILE *stream, const wchar_t *fmt, ...)
> +__nldbl___isoc99_fwscanf (FILE *s, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vfwscanf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___isoc99_wscanf (const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___isoc99_vfwscanf (stdin, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwscanf_internal (stdin, fmt, ap,
> +			     SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 4/7] Add __v*printf_internal with flags arguments
  2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
@ 2018-11-22 17:46   ` Adhemerval Zanella
  2018-11-22 17:55   ` Adhemerval Zanella
  1 sibling, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:46 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2:
> 
>   - Expanded the comments about PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
>   - Removed the parameter-less macros LDBL_IS_DBL and DO_FORTIFY.
>     Explicitly compare the flags.

LGTM, thanks.

> 
> Changes since v1:
> 
>   - Fixed white-space errors.
>   - In argp_fmtstream_printf, do not call __vsnprintf, instead call
>     __vsnprintf_internal passing 0 to mode_flags.  With this change,
>     there's no need to use libc_hidden_{proto,def} for __vsnprintf
>     (because it doesn't have other internal callers).  Also, it is no
>     longer necessary to '#undef __vsnprintf' and '#define __vsnprintf
>     vsnprintf' in argp-namefrob.h.
>   - In __argp_error and __argp_failure call __vasprintf_internal
>     directly, passing 0 (zero) to mode_flags, since these functions do
>     not currently have support for long double with the same format as
>     double (a subsequent patch in my personal branch provides that and
>     adjusts the call accordingly).
>     With this change, there's no need to use libc_hidden_{proto,def} for
>     __vasprintf.  It is also no longer required to '#undef __vasprintf'
>     and '#define __vasprintf vasprintf' in argp-namefrob.h.
>   - Declarations of _IO_vfprintf, _IO_vsprintf, __vfwprintf, and
>     __vswprintf removed from the internal headers: libio.h, iolibio.h,
>     and include/wchar.h, since they are no longer called from within
>     glibc.
>   - Added attribute_hidden to all new internal functions, since they are
>     all called from within libc.
>     Here are the objdumps of one such calls, before and after this
>     change, on a 32-bits powerpc machine:
>     Without attribute_hidden:
>       $ objdump -d --reloc INTERNAL-VISIBLE-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 21
>       000523a0 <vprintf@@GLIBC_2.4>:
>          523a0:       94 21 ff f0     stwu    r1,-16(r1)
>          523a4:       7c 85 23 78     mr      r5,r4
>          523a8:       7c 08 02 a6     mflr    r0
>          523ac:       42 9f 00 05     bcl     20,4*cr7+so,523b0 <vprintf@@GLIBC_2.4+0x10>
>          523b0:       7c 64 1b 78     mr      r4,r3
>          523b4:       38 c0 00 00     li      r6,0
>          523b8:       93 c1 00 08     stw     r30,8(r1)
>          523bc:       90 01 00 14     stw     r0,20(r1)
>          523c0:       7f c8 02 a6     mflr    r30
>          523c4:       3f de 00 15     addis   r30,r30,21
>          523c8:       3b de dc 44     addi    r30,r30,-9148
>          523cc:       81 3e fe 80     lwz     r9,-384(r30)
>          523d0:       80 69 00 00     lwz     r3,0(r9)
>          523d4:       48 01 52 bd     bl      67690 <__vfprintf_internal>
>          523d8:       80 01 00 14     lwz     r0,20(r1)
>          523dc:       83 c1 00 08     lwz     r30,8(r1)
>          523e0:       38 21 00 10     addi    r1,r1,16
>          523e4:       7c 08 03 a6     mtlr    r0
>          523e8:       4e 80 00 20     blr
>     With attribute_hidden:
>       $ objdump -d --reloc INTERNAL-HIDDEN-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 18
>       00052370 <vprintf@@GLIBC_2.4>:
>          52370:       94 21 ff f0     stwu    r1,-16(r1)
>          52374:       7c 85 23 78     mr      r5,r4
>          52378:       7d 88 02 a6     mflr    r12
>          5237c:       42 9f 00 05     bcl     20,4*cr7+so,52380 <vprintf@@GLIBC_2.4+0x10>
>          52380:       7c 64 1b 78     mr      r4,r3
>          52384:       38 c0 00 00     li      r6,0
>          52388:       93 c1 00 08     stw     r30,8(r1)
>          5238c:       7f c8 02 a6     mflr    r30
>          52390:       7d 88 03 a6     mtlr    r12
>          52394:       3f de 00 15     addis   r30,r30,21
>          52398:       3b de dc 74     addi    r30,r30,-9100
>          5239c:       81 3e fe 80     lwz     r9,-384(r30)
>          523a0:       83 c1 00 08     lwz     r30,8(r1)
>          523a4:       80 69 00 00     lwz     r3,0(r9)
>          523a8:       38 21 00 10     addi    r1,r1,16
>          523ac:       48 01 52 24     b       675d0 <__vfprintf_internal>
>     The branch-and-link instruction is gone.
> 
> Additional note for review:
> 
>   - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
>     original patch would be vey hard, because git doesn't detect the
>     filename change.  To make review a little easier, I did as Zack did
>     and manually edited the diff.  I'll reply to this thread and attach
>     the original patch if someone wants to apply it.
>     (ping me if I forget it)
> 
> -- 8< --
> There are a lot more printf variants than there are scanf variants,
> and the code for setting up and tearing down their custom FILE
> variants around the call to __vf(w)printf is more complicated and
> variable.  Therefore, I have added _internal versions of all the
> v*printf variants, rather than introducing helper routines so that
> they can all directly call __vf(w)printf_internal, as was done with
> scanf.
> 
> As with the scanf changes, in this patch the _internal functions still
> look at the environmental mode bits and all callers pass 0 for the
> flags parameter.
> 
> Several of the affected public functions had _IO_ name aliases that
> were not exported (but, in one case, appeared in libio.h anyway);
> I was originally planning to leave them as aliases to avoid having
> to touch internal callers, but it turns out ldbl_*_alias only work
> for exported symbols, so they've all been removed instead.  It also
> turns out there were hardly any internal callers.  _IO_vsprintf and
> _IO_vfprintf *are* exported, so those two stick around.
> 
> Summary for the changes to each of the affected symbols:
> 
>   _IO_vfprintf, _IO_vsprintf:
>     All internal calls removed, thus the internal declarations, as well
>     as uses of libc_hidden_proto and libc_hidden_def, were also removed.
>     The external symbol is now exposed via uses of ldbl_strong_alias
>     to __vfprintf_internal and __vsprintf_internal, respectively.
> 
>   _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf,
>   _IO_vfwprintf, _IO_vswprintf,
>   _IO_obstack_vprintf, _IO_obstack_printf:
>     All internal calls removed, thus declaration in internal headers
>     were also removed.  They were never exported, so there are no
>     aliases tying them to the internal functions.  I.e.: entirely gone.
> 
>   __vsnprintf:
>     Internal calls were always preceded by macros such as
>       #define __vsnprintf _IO_vsnprintf, and
>       #define __vsnprintf vsnprintf
>     The macros were removed and their uses replaced with calls to the
>     new internal function __vsnprintf_internal.  Since there were no
>     internal calls, the internal declaration was also removed.  The
>     external symbol is preserved with ldbl_weak_alias to ___vsnprintf.
> 
>   __vfwprintf:
>     All internal calls converted into calls to __vfwprintf_internal,
>     thus the internal declaration was removed.  The function is now a
>     wrapper that calls __vfwprintf_internal.  The external symbol is
>     preserved.
> 
>   __vswprintf:
>     Similarly, but no external symbol.
> 
>   __vasprintf, __vdprintf, __vfprintf, __vsprintf:
>     New internal wrappers.  Not exported.
> 
>   vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf,
>   vfwprintf, vswprintf,
>   obstack_vprintf, obstack_printf:
>     These functions used to be aliases to the respective _IO_* function,
>     they are now aliases to their respective __* functions.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* libio/libioP.h (__vfprintf_internal, __vfwprintf_internal)
> 	(__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal)
> 	(__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal):
> 	New functions.
> 	(PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants.
> 	(_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes.
> 
> 	* stdio-common/vfprintf-internal.c: Rename from vfprintf.c.
> 	Include wctype.h here if COMPILE_WPRINTF is defined.
> 	Define __vfprintf_internal or __vfwprintf_internal, depending
> 	on COMPILE_WPRINTF.
> 	Temporarily, on entry to this function, update mode_flags
> 	according to the environmental settings corresponding to
> 	PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
> 	Throughout, check mode_flags instead of __ldbl_is_dbl and
> 	_IO_FLAGS2_FORTIFY on the destination FILE.
> 	* stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c.
> 	Include vfprintf-internal.c.  Don't include wctype.h.
> 	* stdio-common/vfprintf.c: New file.  Just define __vfprintf
> 	as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf
> 	and vfprintf.
> 	* stdio-common/vfwprintf.c: New file.  Just define __vfwprintf
> 	as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf
> 	and vfwprintf.
> 	* stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal.
> 
> 	* libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal
> 	and add mode_flags argument; use __vfprintf_internal.
> 	(__vdprintf): New function.  Alias vdprintf to this.
> 	* libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly.
> 	* libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly.
> 	* libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly.
> 	(__obstack_printf): Use __obstack_printf_internal.
> 	* libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with
> 	public aliases __vsnprintf and vsnprintf.
> 	Remove use of ldbl_hidden_def, since __vsnprintf is no longer
> 	called internally.
> 	* libio/vswprintf (_IO_vswprintf, __vswprintf): Similarly, with
> 	public aliases _IO_vsprintf and vsprintf.
> 	* libio/swprintf.c (__swprintf): Use __vswprintf_internal.
> 	* stdio-common/asprintf.c (__asprintf): Use __vasprintf_internal.
> 	* stdio-common/dprintf.c (__dprintf): Use __vdprintf_internal.
> 	* stdio-common/snprintf.c (__snprintf): Use __vsprintf_internal.
> 	* stdio-common/sprintf.c (__sprintf): Use __vsprintf_internal.
> 
> 	* debug/obprintf_chk.c, debug/vasprintf_chk.c, debug/vdprintf_chk.c
> 	* debug/vsnprintf_chk.c, debug/vsprintf_chk.c, hurd/vpprintf.c
> 	* stdio-common/fprintf.c, stdio-common/fxprintf.c
> 	* stdio-common/printf.c: Use __vfprintf_internal.
> 
> 	* debug/fwprintf_chk.c, debug/vfwprintf_chk.c, debug/vswprintf_chk.c
> 	* debug/vwprintf_chk.c, debug/wprintf_chk.c, libio/fwprintf.c
> 	* libio/vwprintf.c, libio/wprintf.c: Use __vfwprintf_internal.
> 
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Use __vsprintf_internal,
> 	__obstack_vprintf_internal, __vasprintf_internal, __vdprintf_internal,
> 	__vsnprintf_internal, __vswprintf_internal, __vfprintf_internal, and
> 	__vfwprintf_internal.
> 
> 	* libio/libio.h: Remove libc_hidden_proto and declaration for
> 	_IO_vfprintf.
> 	Remove declaration of _IO_vfwprintf.
> 	* libio/iolibio.h: Remove libc_hidden_proto and declaration for
> 	_IO_vsprintf.
> 	Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
> 	_IO_obstack_printf.
> 	* include/stdio.h: Add prototype for __vasprintf.
> 	(__vsnprintf): Remove declaration, because there are no more
> 	internal calls.
> 	* include/wchar.h (__vfwprintf, __vswprintf): Remove
> 	declaration, because there are no more internal calls.
> 
> 	* argp/argp-fmtstream.c (__argp_fmtstream_printf): Use
> 	__vsnprintf_internal, instead of _IO_vsnprintf.
> 	* argp/argp-help.c (__argp_error, __argp_failure): Use
> 	__vasprintf_internal, instead of _IO_vasprintf.
> 	* argp/argp-namefrob.h (__vsnprintf): Do not undefined then
> 	redefine, because there are no more internal calls.
> ---
>  argp/argp-fmtstream.c                            |    3 +-
>  argp/argp-help.c                                 |    4 +-
>  argp/argp-namefrob.h                             |    2 -
>  debug/fwprintf_chk.c                             |    2 +-
>  debug/obprintf_chk.c                             |    2 +-
>  debug/vasprintf_chk.c                            |    2 +-
>  debug/vdprintf_chk.c                             |    2 +-
>  debug/vfwprintf_chk.c                            |    2 +-
>  debug/vsnprintf_chk.c                            |    2 +-
>  debug/vsprintf_chk.c                             |    2 +-
>  debug/vswprintf_chk.c                            |    2 +-
>  debug/vwprintf_chk.c                             |    2 +-
>  debug/wprintf_chk.c                              |    2 +-
>  hurd/vpprintf.c                                  |    2 +-
>  include/stdio.h                                  |    3 -
>  include/wchar.h                                  |   10 -
>  libio/fwprintf.c                                 |    2 +-
>  libio/iolibio.h                                  |    8 -
>  libio/iovdprintf.c                               |   13 +-
>  libio/iovsprintf.c                               |   16 +-
>  libio/libio.h                                    |    5 -
>  libio/libioP.h                                   |   47 +-
>  libio/obprintf.c                                 |   19 +-
>  libio/swprintf.c                                 |    2 +-
>  libio/vasprintf.c                                |   20 +-
>  libio/vsnprintf.c                                |   16 +-
>  libio/vswprintf.c                                |   16 +-
>  libio/vwprintf.c                                 |    2 +-
>  libio/wprintf.c                                  |    2 +-
>  stdio-common/Makefile                            |    3 +-
>  stdio-common/asprintf.c                          |    6 +-
>  stdio-common/dprintf.c                           |    5 +-
>  stdio-common/fprintf.c                           |    2 +-
>  stdio-common/fxprintf.c                          |    4 +-
>  stdio-common/printf.c                            |    3 +-
>  stdio-common/snprintf.c                          |    4 +-
>  stdio-common/sprintf.c                           |    4 +-
>  stdio-common/{vfprintf.c => vfprintf-internal.c} |   66 +-
>  stdio-common/vfprintf.c                          | 2351 +---------------------
>  stdio-common/vfwprintf-internal.c                |    2 +
>  stdio-common/vfwprintf.c                         |   28 +-
>  stdio-common/vprintf.c                           |    4 +-
>  stdlib/strfrom-skeleton.c                        |    2 +-
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |   21 +-
>  44 files changed, 219 insertions(+), 2498 deletions(-)
>  copy stdio-common/{vfprintf.c => vfprintf-internal.c} (98%)
>  create mode 100644 stdio-common/vfwprintf-internal.c
> 
> diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
> index e43a0c7cf1..b9dcb2c9c7 100644
> --- a/argp/argp-fmtstream.c
> +++ b/argp/argp-fmtstream.c
> @@ -42,7 +42,6 @@
>  #ifdef _LIBC
>  # include <wchar.h>
>  # include <libio/libioP.h>
> -# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
>  #endif
>  
>  #define INIT_BUF_SIZE 200
> @@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
>  
>        va_start (args, fmt);
>        avail = fs->end - fs->p;
> -      out = __vsnprintf (fs->p, avail, fmt, args);
> +      out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
>        va_end (args);
>        if ((size_t) out >= avail)
>  	size_guess = out + 1;

Ok.

> diff --git a/argp/argp-help.c b/argp/argp-help.c
> index 2b6b0775d6..6857391ce2 100644
> --- a/argp/argp-help.c
> +++ b/argp/argp-help.c
> @@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
>  #ifdef _LIBC
>  	  char *buf;
>  
> -	  if (_IO_vasprintf (&buf, fmt, ap) < 0)
> +	  if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
>  	    buf = NULL;
>  
>  	  __fxprintf (stream, "%s: %s\n",
> @@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
>  #ifdef _LIBC
>  	      char *buf;
>  
> -	      if (_IO_vasprintf (&buf, fmt, ap) < 0)
> +	      if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
>  		buf = NULL;
>  
>  	      __fxprintf (stream, ": %s", buf);

Ok.

> diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
> index 5588fe172a..5e48b5940d 100644
> --- a/argp/argp-namefrob.h
> +++ b/argp/argp-namefrob.h
> @@ -98,8 +98,6 @@
>  #define __strerror_r strerror_r
>  #undef __strndup
>  #define __strndup strndup
> -#undef __vsnprintf
> -#define __vsnprintf vsnprintf
>  
>  #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
>  # define clearerr_unlocked(x) clearerr (x)
> diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
> index aeb83077da..63167c1839 100644
> --- a/debug/fwprintf_chk.c
> +++ b/debug/fwprintf_chk.c
> @@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
>      fp->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    va_start (ap, format);
> -  done = _IO_vfwprintf (fp, format, ap);
> +  done = __vfwprintf_internal (fp, format, ap, 0);
>    va_end (ap);
>  
>    if (flag > 0)

Ok.

> diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
> index 3ac5a3cd4f..41dd481c34 100644
> --- a/debug/obprintf_chk.c
> +++ b/debug/obprintf_chk.c
> @@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
>    if (flags > 0)
>      new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
> +  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
>  
>    /* Shrink the buffer to the space we really currently need.  */
>    obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr

Ok.

> diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
> index 48b4741651..dbfebff83f 100644
> --- a/debug/vasprintf_chk.c
> +++ b/debug/vasprintf_chk.c
> @@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
>    if (flags > 0)
>      sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
>    if (ret < 0)
>      {
>        free (sf._sbf._f._IO_buf_base);

Ok.

> diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
> index bc713b4962..4386127cfe 100644
> --- a/debug/vdprintf_chk.c
> +++ b/debug/vdprintf_chk.c
> @@ -55,7 +55,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg)
>    if (flags > 0)
>      tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfprintf (&tmpfil.file, format, arg);
> +  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
>  
>    _IO_FINISH (&tmpfil.file);
>  

Ok.

> diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
> index 1ffd18cbd2..abf2bd6517 100644
> --- a/debug/vfwprintf_chk.c
> +++ b/debug/vfwprintf_chk.c
> @@ -30,7 +30,7 @@ __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
>    if (flag > 0)
>      fp->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfwprintf (fp, format, ap);
> +  done = __vfwprintf_internal (fp, format, ap, 0);
>  
>    if (flag > 0)
>      fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;

Ok.

> diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
> index d20d0fbd93..95d286f416 100644
> --- a/debug/vsnprintf_chk.c
> +++ b/debug/vsnprintf_chk.c
> @@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
>      sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
> -  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
>  
>    if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
>      *sf.f._sbf._f._IO_write_ptr = '\0';

Ok.

> diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
> index 9a443bb699..53f07236ae 100644
> --- a/debug/vsprintf_chk.c
> +++ b/debug/vsprintf_chk.c
> @@ -80,7 +80,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
>    if (flags > 0)
>      f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  ret = _IO_vfprintf (&f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
>  
>    *f._sbf._f._IO_write_ptr = '\0';
>    return ret;

Ok.

> diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
> index c6a7edcacd..4d616f8835 100644
> --- a/debug/vswprintf_chk.c
> +++ b/debug/vswprintf_chk.c
> @@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
>      sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
> -  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
> +  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
>  
>    if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
>      /* ISO C99 requires swprintf/vswprintf to return an error if the

Ok.

> diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
> index 51b67c159d..fedc7a46bf 100644
> --- a/debug/vwprintf_chk.c
> +++ b/debug/vwprintf_chk.c
> @@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
>    if (flag > 0)
>      stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfwprintf (stdout, format, ap);
> +  done = __vfwprintf_internal (stdout, format, ap, 0);
>  
>    if (flag > 0)
>      stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;

Ok.

> diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
> index 17023b6bb4..819050e5af 100644
> --- a/debug/wprintf_chk.c
> +++ b/debug/wprintf_chk.c
> @@ -33,7 +33,7 @@ __wprintf_chk (int flag, const wchar_t *format, ...)
>      stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    va_start (ap, format);
> -  done = _IO_vfwprintf (stdout, format, ap);
> +  done = __vfwprintf_internal (stdout, format, ap, 0);
>    va_end (ap);
>  
>    if (flag > 0)

Ok.

> diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c
> index 76cd31f922..b9634afc2b 100644
> --- a/hurd/vpprintf.c
> +++ b/hurd/vpprintf.c
> @@ -53,7 +53,7 @@ vpprintf (io_t port, const char *format, va_list arg)
>    _IO_cookie_init (&temp_f.cfile, _IO_NO_READS,
>  		   (void *) port, (cookie_io_functions_t) { write: do_write });
>  
> -  done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
> +  done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0);
>  
>    return done;
>  }



> diff --git a/include/stdio.h b/include/stdio.h
> index 51ada4a4c4..0856d729d9 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen,
>  		       const char *__restrict __format, ...)
>       __attribute__ ((__format__ (__printf__, 3, 4)));
>  libc_hidden_proto (__snprintf)
> -extern int __vsnprintf (char *__restrict __s, size_t __maxlen,
> -			const char *__restrict __format, __gnuc_va_list __arg)
> -     __attribute__ ((__format__ (__printf__, 3, 0)));
>  extern int __vfscanf (FILE *__restrict __s,
>  		      const char *__restrict __format,
>  		      __gnuc_va_list __arg)
> diff --git a/include/wchar.h b/include/wchar.h
> index 1db0ac8278..d0fe45c3a6 100644
> --- a/include/wchar.h
> +++ b/include/wchar.h
> @@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s,
>  		       __gnuc_va_list __arg)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */;
> -extern int __vswprintf (wchar_t *__restrict __s, size_t __n,
> -			const wchar_t *__restrict __format,
> -			__gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
>  extern int __fwprintf (__FILE *__restrict __s,
>  		       const wchar_t *__restrict __format, ...)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
> -extern int __vfwprintf (__FILE *__restrict __s,
> -			const wchar_t *__restrict __format,
> -			__gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
>  extern int __vfwprintf_chk (FILE *__restrict __s, int __flag,
>  			    const wchar_t *__restrict __format,
>  			    __gnuc_va_list __arg)

Ok.

> diff --git a/libio/fwprintf.c b/libio/fwprintf.c
> index fab63a8716..9903f1f342 100644
> --- a/libio/fwprintf.c
> +++ b/libio/fwprintf.c
> @@ -30,7 +30,7 @@ __fwprintf (FILE *stream, const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vfwprintf (stream, format, arg);
> +  done = __vfwprintf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/iolibio.h b/libio/iolibio.h
> index 6c94fe6d62..2642d71e4f 100644
> --- a/libio/iolibio.h
> +++ b/libio/iolibio.h
> @@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
>  extern int _IO_sprintf (char *, const char*, ...) __THROW;
>  extern int _IO_ungetc (int, FILE*) __THROW;
>  extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW;
> -extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW;
> -libc_hidden_proto (_IO_vsprintf)
> -extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list)
> -       __THROW;
>  
> -struct obstack;
> -extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list)
> -       __THROW;
> -extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW;
>  #define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN))
>  #define _IO_fseek(__fp, __offset, __whence) \
>    (_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \

Ok.

> diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
> index 78a3a2bd15..1d2ed0f9e7 100644
> --- a/libio/iovdprintf.c
> +++ b/libio/iovdprintf.c
> @@ -28,7 +28,8 @@
>  #include <stdio_ext.h>
>  
>  int
> -_IO_vdprintf (int d, const char *format, va_list arg)
> +__vdprintf_internal (int d, const char *format, va_list arg,
> +		     unsigned int mode_flags)
>  {
>    struct _IO_FILE_plus tmpfil;
>    struct _IO_wide_data wd;
> @@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg)
>    _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
>  		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
>  
> -  done = _IO_vfprintf (&tmpfil.file, format, arg);
> +  done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags);
>  
>    if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
>      done = EOF;
> @@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg)
>  
>    return done;
>  }
> -ldbl_weak_alias (_IO_vdprintf, vdprintf)
> +
> +int
> +__vdprintf (int d, const char *format, va_list arg)
> +{
> +  return __vdprintf_internal (d, format, arg, 0);
> +}
> +ldbl_weak_alias (__vdprintf, vdprintf)

Ok.

> diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
> index 4def251701..3b1e8292b5 100644
> --- a/libio/iovsprintf.c
> +++ b/libio/iovsprintf.c
> @@ -28,7 +28,8 @@
>  #include "strfile.h"
>  
>  int
> -__IO_vsprintf (char *string, const char *format, va_list args)
> +__vsprintf_internal (char *string, const char *format, va_list args,
> +		     unsigned int mode_flags)
>  {
>    _IO_strfile sf;
>    int ret;
> @@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args)
>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>    _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>    _IO_str_init_static_internal (&sf, string, -1, string);
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
>    _IO_putc_unlocked ('\0', &sf._sbf._f);
>    return ret;
>  }
> -ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)
>  
> -ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
> -ldbl_weak_alias (__IO_vsprintf, vsprintf)
> +int
> +__vsprintf (char *string, const char *format, va_list args)
> +{
> +  return __vsprintf_internal (string, format, args, 0);
> +}
> +
> +ldbl_strong_alias (__vsprintf, _IO_vsprintf)
> +ldbl_weak_alias (__vsprintf, vsprintf)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index 30cb7d784f..c188814ccc 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;
>  
>  extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
>  			__gnuc_va_list, int *__restrict);
> -extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
> -			 __gnuc_va_list);
>  extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
>  extern size_t _IO_sgetn (FILE *, void *, size_t);
>  
> @@ -298,8 +296,6 @@ weak_extern (_IO_stdin_used);
>  
>  extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
>  			 __gnuc_va_list, int *__restrict);
> -extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
> -			  __gnuc_va_list);
>  extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t);
>  extern void _IO_free_wbackup_area (FILE *) __THROW;
>  
> @@ -319,7 +315,6 @@ libc_hidden_proto (_IO_free_wbackup_area)
>  libc_hidden_proto (_IO_padn)
>  libc_hidden_proto (_IO_putc)
>  libc_hidden_proto (_IO_sgetn)
> -libc_hidden_proto (_IO_vfprintf)
>  
>  #ifdef _IO_MTSAFE_IO
>  # undef _IO_peekc

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index 9e971cb96b..fe52ef1752 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -658,12 +658,49 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
>  extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
>  extern void _IO_wstr_finish (FILE *, int) __THROW;
>  
> -extern int _IO_vasprintf (char **result_ptr, const char *format,
> -			  va_list args) __THROW;
> -extern int _IO_vdprintf (int d, const char *format, va_list arg);
> -extern int _IO_vsnprintf (char *string, size_t maxlen,
> -			  const char *format, va_list args) __THROW;
> +/* Internal versions of v*printf that take an additional flags
> +   parameter.  */
> +extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vasprintf_internal (char **result_ptr, const char *format,
> +				 va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vdprintf_internal (int d, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
> +				       va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vsprintf_internal (char *string, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vsnprintf_internal (char *string, size_t maxlen,
> +				 const char *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
> +				 const wchar_t *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +
> +/* Flags for __v*printf_internal.
> +
> +   PRINTF_LDBL_IS_DBL indicates whether long double values are to be
> +   handled as having the same format as double, in which case the flag
> +   should be set to one, or as another format, otherwise.
>  
> +   PRINTF_FORTIFY, when set to one, indicates that fortification checks
> +   are to be performed in input parameters.  This is used by the
> +   __*printf_chk functions, which are used when _FORTIFY_SOURCE is
> +   defined to 1 or 2.  Otherwise, such checks are ignored.  */
> +#define PRINTF_LDBL_IS_DBL 0x0001
> +#define PRINTF_FORTIFY     0x0002
>  
>  extern size_t _IO_getline (FILE *,char *, size_t, int, int);
>  libc_hidden_proto (_IO_getline)

Ok.

> diff --git a/libio/obprintf.c b/libio/obprintf.c
> index a74f9467a2..10a4b5c10c 100644
> --- a/libio/obprintf.c
> +++ b/libio/obprintf.c
> @@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
> +__obstack_vprintf_internal (struct obstack *obstack, const char *format,
> +			    va_list args, unsigned int mode_flags)
>  {
>    struct obstack_FILE
>      {
> @@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
>  
>    new_f.ofile.obstack = obstack;
>  
> -  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
> +  result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
> +				mode_flags);
>  
>    /* Shrink the buffer to the space we really currently need.  */
>    obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
> @@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
>  
>    return result;
>  }
> -ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf)
>  
> +int
> +__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap)
> +{
> +  return __obstack_vprintf_internal (obstack, format, ap, 0);
> +}
> +ldbl_weak_alias (__obstack_vprintf, obstack_vprintf)
>  
>  int
> -_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
> +__obstack_printf (struct obstack *obstack, const char *format, ...)
>  {
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -  result = _IO_obstack_vprintf (obstack, format, ap);
> +  result = __obstack_vprintf_internal (obstack, format, ap, 0);
>    va_end (ap);
>    return result;
>  }
> -ldbl_weak_alias (_IO_obstack_printf, obstack_printf)
> +ldbl_weak_alias (__obstack_printf, obstack_printf)

Ok.

> diff --git a/libio/swprintf.c b/libio/swprintf.c
> index 10f722d035..19b3f33198 100644
> --- a/libio/swprintf.c
> +++ b/libio/swprintf.c
> @@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vswprintf (s, n, format, arg);
> +  done = __vswprintf_internal (s, n, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/vasprintf.c b/libio/vasprintf.c
> index 6c35d2b108..fabd84f403 100644
> --- a/libio/vasprintf.c
> +++ b/libio/vasprintf.c
> @@ -24,15 +24,13 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <malloc.h>
>  #include <string.h>
> -#include "libioP.h"
> -#include "stdio.h"
> -#include <stdio_ext.h>
> -#include "strfile.h"
> +#include <stdlib.h>
> +#include <strfile.h>
>  
>  int
> -_IO_vasprintf (char **result_ptr, const char *format, va_list args)
> +__vasprintf_internal (char **result_ptr, const char *format, va_list args,
> +		      unsigned int mode_flags)
>  {
>    /* Initial size of the buffer to be used.  Will be doubled each time an
>       overflow occurs.  */
> @@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
>    sf._sbf._f._flags &= ~_IO_USER_BUF;
>    sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
>    sf._s._free_buffer_unused = (_IO_free_type) free;
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
>    if (ret < 0)
>      {
>        free (sf._sbf._f._IO_buf_base);
> @@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
>    (*result_ptr)[needed - 1] = '\0';
>    return ret;
>  }
> -ldbl_weak_alias (_IO_vasprintf, vasprintf)
> +
> +int
> +__vasprintf (char **result_ptr, const char *format, va_list args)
> +{
> +  return __vasprintf_internal (result_ptr, format, args, 0);
> +}
> +ldbl_weak_alias (__vasprintf, vasprintf)

Ok.

> diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
> index 39b5500528..35b267abf8 100644
> --- a/libio/vsnprintf.c
> +++ b/libio/vsnprintf.c
> @@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_vsnprintf (char *string, size_t maxlen, const char *format,
> -	       va_list args)
> +__vsnprintf_internal (char *string, size_t maxlen, const char *format,
> +		      va_list args, unsigned int mode_flags)
>  {
>    _IO_strnfile sf;
>    int ret;
> @@ -111,11 +111,17 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format,
>    _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
>    string[0] = '\0';
>    _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
> -  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);
>  
>    if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
>      *sf.f._sbf._f._IO_write_ptr = '\0';
>    return ret;
>  }
> -ldbl_weak_alias (_IO_vsnprintf, __vsnprintf)
> -ldbl_weak_alias (_IO_vsnprintf, vsnprintf)
> +
> +int
> +___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
> +{
> +  return __vsnprintf_internal (string, maxlen, format, args, 0);
> +}
> +ldbl_weak_alias (___vsnprintf, __vsnprintf)
> +ldbl_weak_alias (___vsnprintf, vsnprintf)

Ok.

> diff --git a/libio/vswprintf.c b/libio/vswprintf.c
> index bcc473d115..e415e39fc9 100644
> --- a/libio/vswprintf.c
> +++ b/libio/vswprintf.c
> @@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
> -	       va_list args)
> +__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
> +		      va_list args, unsigned int mode_flags)
>  {
>    _IO_wstrnfile sf;
>    int ret;
> @@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
>    _IO_fwide (&sf.f._sbf._f, 1);
>    string[0] = L'\0';
>    _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
> -  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
> +  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);
>  
>    if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
>      /* ISO C99 requires swprintf/vswprintf to return an error if the
> @@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
>  
>    return ret;
>  }
> -weak_alias (_IO_vswprintf, __vswprintf)
> -ldbl_weak_alias (_IO_vswprintf, vswprintf)
> +
> +int
> +__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
> +	     va_list args)
> +{
> +  return __vswprintf_internal (string, maxlen, format, args, 0);
> +}
> +ldbl_weak_alias (__vswprintf, vswprintf)

Ok.

> diff --git a/libio/vwprintf.c b/libio/vwprintf.c
> index 72ebfec92d..e8a529afff 100644
> --- a/libio/vwprintf.c
> +++ b/libio/vwprintf.c
> @@ -25,6 +25,6 @@
>  int
>  __vwprintf (const wchar_t *format, __gnuc_va_list arg)
>  {
> -  return __vfwprintf (stdout, format, arg);
> +  return __vfwprintf_internal (stdout, format, arg, 0);
>  }
>  ldbl_strong_alias (__vwprintf, vwprintf)

Ok.

> diff --git a/libio/wprintf.c b/libio/wprintf.c
> index 5945f651fc..361cd40a1b 100644
> --- a/libio/wprintf.c
> +++ b/libio/wprintf.c
> @@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vfwprintf (stdout, format, arg);
> +  done = __vfwprintf_internal (stdout, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index f3b3ceddbd..84bad1fafe 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -40,7 +40,8 @@ routines	:=							      \
>  	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
>  	isoc99_vsscanf							      \
>  	psiginfo gentempfd						      \
> -	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
> +	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf		      \
> +	vfprintf-internal vfwprintf-internal
>  
>  aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
>  

Ok.

> diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
> index bff858e657..8943ffcae1 100644
> --- a/stdio-common/asprintf.c
> +++ b/stdio-common/asprintf.c
> @@ -16,11 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -
>  #include <libioP.h>
> -#define vasprintf(s, f, a) _IO_vasprintf (s, f, a)
> -#undef __asprintf
>  
>  /* Write formatted output from FORMAT to a string which is
>     allocated with malloc and stored in *STRING_PTR.  */
> @@ -32,7 +28,7 @@ ___asprintf (char **string_ptr, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vasprintf (string_ptr, format, arg);
> +  done = __vasprintf_internal (string_ptr, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
> index 11bd12b838..9adc8ae4c7 100644
> --- a/stdio-common/dprintf.c
> +++ b/stdio-common/dprintf.c
> @@ -16,10 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -
>  #include <libioP.h>
> -#define vdprintf(d, f, a) _IO_vdprintf (d, f, a)
>  
>  /* Write formatted output to D, according to the format string FORMAT.  */
>  /* VARARGS2 */
> @@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vdprintf (d, format, arg);
> +  done = __vdprintf_internal (d, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c
> index 2bbf14bf5d..c8f8ac4faf 100644
> --- a/stdio-common/fprintf.c
> +++ b/stdio-common/fprintf.c
> @@ -29,7 +29,7 @@ __fprintf (FILE *stream, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vfprintf (stream, format, arg);
> +  done = __vfprintf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
> index 8d02b71f91..a028e8edd5 100644
> --- a/stdio-common/fxprintf.c
> +++ b/stdio-common/fxprintf.c
> @@ -27,7 +27,7 @@ static int
>  locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
>  {
>    if (_IO_fwide (fp, 0) <= 0)
> -    return _IO_vfprintf (fp, fmt, ap);
> +    return __vfprintf_internal (fp, fmt, ap, 0);
>  
>    /* We must convert the narrow format string to a wide one.
>       Each byte can produce at most one wide character.  */
> @@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
>    res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
>  
>    if (res != -1)
> -    res = _IO_vfwprintf (fp, wfmt, ap);
> +    res = __vfwprintf_internal (fp, wfmt, ap, 0);
>  
>    if (used_malloc)
>      free (wfmt);

Ok.

> diff --git a/stdio-common/printf.c b/stdio-common/printf.c
> index 205b5e42df..ea41dd557c 100644
> --- a/stdio-common/printf.c
> +++ b/stdio-common/printf.c
> @@ -30,7 +30,7 @@ __printf (const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vfprintf (stdout, format, arg);
> +  done = __vfprintf_internal (stdout, format, arg, 0);
>    va_end (arg);
>  
>    return done;
> @@ -38,5 +38,4 @@ __printf (const char *format, ...)
>  
>  #undef _IO_printf
>  ldbl_strong_alias (__printf, printf);
> -/* This is for libg++.  */
>  ldbl_strong_alias (__printf, _IO_printf);

Ok.

> diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
> index 29a169b08b..b75e160ea3 100644
> --- a/stdio-common/snprintf.c
> +++ b/stdio-common/snprintf.c
> @@ -16,9 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> -#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
>  
>  /* Write formatted output into S, according to the format
>     string FORMAT, writing no more than MAXLEN characters.  */
> @@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vsnprintf (s, maxlen, format, arg);
> +  done = __vsnprintf_internal (s, maxlen, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
> index bf5671dde9..77423b292f 100644
> --- a/stdio-common/sprintf.c
> +++ b/stdio-common/sprintf.c
> @@ -16,9 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> -#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
>  
>  /* Write formatted output into S, according to the format string FORMAT.  */
>  /* VARARGS2 */
> @@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vsprintf (s, format, arg);
> +  done = __vsprintf_internal (s, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf-internal.c
> similarity index 98%
> copy from stdio-common/vfprintf.c
> copy to stdio-common/vfprintf-internal.c
> index ae412e4b84..b0c86e99bd 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf-internal.c
> @@ -41,6 +41,10 @@
>  
>  #include <libioP.h>
>  
> +#ifdef COMPILE_WPRINTF
> +#include <wctype.h>
> +#endif
> +
>  /* In some cases we need extra space for all the output which is not
>     counted in the width of the string. We assume 32 characters is
>     enough.  */
> @@ -78,7 +82,7 @@
>    } while (0)
>  
>  #ifndef COMPILE_WPRINTF
> -# define vfprintf	_IO_vfprintf_internal
> +# define vfprintf	__vfprintf_internal
>  # define CHAR_T		char
>  # define UCHAR_T	unsigned char
>  # define INT_T		int
> @@ -105,7 +109,7 @@ typedef const char *THOUSANDS_SEP_T;
>  # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
>  			  return -1
>  #else
> -# define vfprintf	_IO_vfwprintf
> +# define vfprintf	__vfwprintf_internal
>  # define CHAR_T		wchar_t
>  /* This is a hack!!!  There should be a type uwchar_t.  */
>  # define UCHAR_T	unsigned int /* uwchar_t */
> @@ -747,7 +751,7 @@ static const uint8_t jump_table[] =
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -778,7 +782,7 @@ static const uint8_t jump_table[] =
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      {								      \
>  		fspec->data_arg_type = PA_DOUBLE;			      \
>  		fspec->info.is_long_double = 0;				      \
> @@ -808,7 +812,7 @@ static const uint8_t jump_table[] =
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -838,7 +842,7 @@ static const uint8_t jump_table[] =
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      fspec->info.is_long_double = 0;				      \
>  	    /* Not supported by *printf functions.  */			      \
>  	    fspec->info.is_binary128 = 0;				      \
> @@ -891,7 +895,7 @@ static const uint8_t jump_table[] =
>        /* NOTREACHED */							      \
>  									      \
>      LABEL (form_number):						      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
> +      if ((mode_flags & PRINTF_FORTIFY) != 0)				      \
>  	{								      \
>  	  if (! readonly_format)					      \
>  	    {								      \
> @@ -1214,7 +1218,8 @@ static const uint8_t jump_table[] =
>  #endif
>  
>  /* Helper function to provide temporary buffering for unbuffered streams.  */
> -static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
> +static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
> +			      unsigned int)
>       __THROW __attribute__ ((noinline));
>  
>  /* Handle positional format specifiers.  */
> @@ -1223,7 +1228,9 @@ static int printf_positional (FILE *s,
>  			      va_list ap, va_list *ap_savep, int done,
>  			      int nspecs_done, const UCHAR_T *lead_str_end,
>  			      CHAR_T *work_buffer, int save_errno,
> -			      const char *grouping, THOUSANDS_SEP_T);
> +			      const char *grouping,
> +			      THOUSANDS_SEP_T thousands_sep,
> +			      unsigned int mode_flags);
>  
>  /* Handle unknown format specifier.  */
>  static int printf_unknown (FILE *, const struct printf_info *,
> @@ -1235,7 +1242,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
>  
>  /* The function itself.  */
>  int
> -vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> +vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
>  {
>    /* The character used as thousands separator.  */
>    THOUSANDS_SEP_T thousands_sep = 0;
> @@ -1273,6 +1280,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
>       0 if unknown.  */
>    int readonly_format = 0;
>  
> +  /* Temporarily honor environmental settings.  */
> +  if (__ldbl_is_dbl)
> +    mode_flags |= PRINTF_LDBL_IS_DBL;
> +  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
> +    mode_flags |= PRINTF_FORTIFY;
> +
>    /* Orient the stream.  */
>  #ifdef ORIENT
>    ORIENT;
> @@ -1293,7 +1306,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
>    if (UNBUFFERED_P (s))
>      /* Use a helper function which will allocate a local temporary buffer
>         for the stream and then call us again.  */
> -    return buffered_vfprintf (s, format, ap);
> +    return buffered_vfprintf (s, format, ap, mode_flags);
>  
>    /* Initialize local variables.  */
>    done = 0;
> @@ -1682,7 +1695,7 @@ do_positional:
>      }
>    done = printf_positional (s, format, readonly_format, ap, &ap_save,
>  			    done, nspecs_done, lead_str_end, work_buffer,
> -			    save_errno, grouping, thousands_sep);
> +			    save_errno, grouping, thousands_sep, mode_flags);
>  
>   all_done:
>    if (__glibc_unlikely (workstart != NULL))
> @@ -1699,7 +1712,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>  		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
>  		   const UCHAR_T *lead_str_end,
>  		   CHAR_T *work_buffer, int save_errno,
> -		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
> +		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
> +		   unsigned int mode_flags)
>  {
>    /* For positional argument handling.  */
>    struct scratch_buffer specsbuf;
> @@ -1789,7 +1803,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>         now.  */
>      args_size = &args_value[nargs].pa_int;
>      args_type = &args_size[nargs];
> -    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> +    memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
>  	    nargs * sizeof (*args_type));
>    }
>  
> @@ -1856,7 +1870,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>        case PA_FLOAT:				/* Promoted.  */
>  	T (PA_DOUBLE, pa_double, double);
>        case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> -	if (__ldbl_is_dbl)
> +	if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
>  	  {
>  	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
>  	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> @@ -1884,7 +1898,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>        case -1:
>  	/* Error case.  Not all parameters appear in N$ format
>  	   strings.  We have no way to determine their type.  */
> -	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> +	assert ((mode_flags & PRINTF_FORTIFY) != 0);
>  	__libc_fatal ("*** invalid %N$ use detected ***\n");
>        }
>  
> @@ -2285,7 +2299,8 @@ static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
>  #endif
>  
>  static int
> -buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
> +buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
> +		   unsigned int mode_flags)
>  {
>    CHAR_T buf[BUFSIZ];
>    struct helper_file helper;
> @@ -2318,11 +2333,7 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
>    _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
>  
>    /* Now print to helper instead.  */
> -#ifndef COMPILE_WPRINTF
> -  result = _IO_vfprintf (hp, format, args);
> -#else
> -  result = vfprintf (hp, format, args);
> -#endif
> +  result = vfprintf (hp, format, args, mode_flags);
>  
>    /* Lock stream.  */
>    __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
> @@ -2351,14 +2362,3 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
>  
>    return result;
>  }
> -
> -#undef vfprintf
> -#ifdef COMPILE_WPRINTF
> -strong_alias (_IO_vfwprintf, __vfwprintf);
> -ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
> -#else
> -ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
> -ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
> -#endif

Ok.

> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
> index ae412e4b84..13a10db99b 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf.c
> @@ -15,2350 +15,13 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <array_length.h>
> -#include <ctype.h>
> -#include <limits.h>
> -#include <printf.h>
> -#include <stdarg.h>
> -#include <stdint.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <wchar.h>
> -#include <libc-lock.h>
> -#include <sys/param.h>
> -#include <_itoa.h>
> -#include <locale/localeinfo.h>
> -#include <stdio.h>
> -#include <scratch_buffer.h>
> +#include <libio/libioP.h>
>  
> -/* This code is shared between the standard stdio implementation found
> -   in GNU C library and the libio implementation originally found in
> -   GNU libg++.
> -
> -   Beside this it is also shared between the normal and wide character
> -   implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
> -
> -#include <libioP.h>
> -
> -/* In some cases we need extra space for all the output which is not
> -   counted in the width of the string. We assume 32 characters is
> -   enough.  */
> -#define EXTSIZ		32
> -#define ARGCHECK(S, Format) \
> -  do									      \
> -    {									      \
> -      /* Check file argument for consistence.  */			      \
> -      CHECK_FILE (S, -1);						      \
> -      if (S->_flags & _IO_NO_WRITES)					      \
> -	{								      \
> -	  S->_flags |= _IO_ERR_SEEN;					      \
> -	  __set_errno (EBADF);						      \
> -	  return -1;							      \
> -	}								      \
> -      if (Format == NULL)						      \
> -	{								      \
> -	  __set_errno (EINVAL);						      \
> -	  return -1;							      \
> -	}								      \
> -    } while (0)
> -#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
> -
> -#define done_add(val) \
> -  do {									      \
> -    unsigned int _val = val;						      \
> -    assert ((unsigned int) done < (unsigned int) INT_MAX);		      \
> -    if (__glibc_unlikely (INT_MAX - done < _val))			      \
> -      {									      \
> -	done = -1;							      \
> -	 __set_errno (EOVERFLOW);					      \
> -	goto all_done;							      \
> -      }									      \
> -    done += _val;							      \
> -  } while (0)
> -
> -#ifndef COMPILE_WPRINTF
> -# define vfprintf	_IO_vfprintf_internal
> -# define CHAR_T		char
> -# define UCHAR_T	unsigned char
> -# define INT_T		int
> -typedef const char *THOUSANDS_SEP_T;
> -# define L_(Str)	Str
> -# define ISDIGIT(Ch)	((unsigned int) ((Ch) - '0') < 10)
> -# define STR_LEN(Str)	strlen (Str)
> -
> -# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
> -# define PAD(Padchar) \
> -  do {									      \
> -    if (width > 0)							      \
> -      {									      \
> -	ssize_t written = _IO_padn (s, (Padchar), width);		      \
> -	if (__glibc_unlikely (written != width))			      \
> -	  {								      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	done_add (written);						      \
> -      }									      \
> -  } while (0)
> -# define PUTC(C, F)	_IO_putc_unlocked (C, F)
> -# define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
> -			  return -1
> -#else
> -# define vfprintf	_IO_vfwprintf
> -# define CHAR_T		wchar_t
> -/* This is a hack!!!  There should be a type uwchar_t.  */
> -# define UCHAR_T	unsigned int /* uwchar_t */
> -# define INT_T		wint_t
> -typedef wchar_t THOUSANDS_SEP_T;
> -# define L_(Str)	L##Str
> -# define ISDIGIT(Ch)	((unsigned int) ((Ch) - L'0') < 10)
> -# define STR_LEN(Str)	__wcslen (Str)
> -
> -# include <_itowa.h>
> -
> -# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
> -# define PAD(Padchar) \
> -  do {									      \
> -    if (width > 0)							      \
> -      {									      \
> -	ssize_t written = _IO_wpadn (s, (Padchar), width);		      \
> -	if (__glibc_unlikely (written != width))			      \
> -	  {								      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	done_add (written);						      \
> -      }									      \
> -  } while (0)
> -# define PUTC(C, F)	_IO_putwc_unlocked (C, F)
> -# define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
> -
> -# undef _itoa
> -# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
> -# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
> -# undef EOF
> -# define EOF WEOF
> -#endif
> -
> -#include "_i18n_number.h"
> -
> -/* Include the shared code for parsing the format string.  */
> -#include "printf-parse.h"
> -
> -
> -#define	outchar(Ch)							      \
> -  do									      \
> -    {									      \
> -      const INT_T outc = (Ch);						      \
> -      if (PUTC (outc, s) == EOF || done == INT_MAX)			      \
> -	{								      \
> -	  done = -1;							      \
> -	  goto all_done;						      \
> -	}								      \
> -      ++done;								      \
> -    }									      \
> -  while (0)
> -
> -#define outstring(String, Len)						      \
> -  do									      \
> -    {									      \
> -      assert ((size_t) done <= (size_t) INT_MAX);			      \
> -      if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))		      \
> -	{								      \
> -	  done = -1;							      \
> -	  goto all_done;						      \
> -	}								      \
> -      if (__glibc_unlikely (INT_MAX - done < (Len)))			      \
> -      {									      \
> -	done = -1;							      \
> -	 __set_errno (EOVERFLOW);					      \
> -	goto all_done;							      \
> -      }									      \
> -      done += (Len);							      \
> -    }									      \
> -  while (0)
> -
> -/* For handling long_double and longlong we use the same flag.  If
> -   `long' and `long long' are effectively the same type define it to
> -   zero.  */
> -#if LONG_MAX == LONG_LONG_MAX
> -# define is_longlong 0
> -#else
> -# define is_longlong is_long_double
> -#endif
> -
> -/* If `long' and `int' is effectively the same type we don't have to
> -   handle `long separately.  */
> -#if INT_MAX == LONG_MAX
> -# define is_long_num	0
> -#else
> -# define is_long_num	is_long
> -#endif
> -
> -
> -/* Global constants.  */
> -static const CHAR_T null[] = L_("(null)");
> -
> -/* Size of the work_buffer variable (in characters, not bytes.  */
> -enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
> -
> -/* This table maps a character into a number representing a class.  In
> -   each step there is a destination label for each class.  */
> -static const uint8_t jump_table[] =
> -  {
> -    /* ' ' */  1,            0,            0, /* '#' */  4,
> -	       0, /* '%' */ 14,            0, /* '\''*/  6,
> -	       0,            0, /* '*' */  7, /* '+' */  2,
> -	       0, /* '-' */  3, /* '.' */  9,            0,
> -    /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
> -    /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
> -    /* '8' */  8, /* '9' */  8,            0,            0,
> -	       0,            0,            0,            0,
> -	       0, /* 'A' */ 26,            0, /* 'C' */ 25,
> -	       0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
> -	       0, /* 'I' */ 29,            0,            0,
> -    /* 'L' */ 12,            0,            0,            0,
> -	       0,            0,            0, /* 'S' */ 21,
> -	       0,            0,            0,            0,
> -    /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
> -	       0,            0,            0,            0,
> -	       0, /* 'a' */ 26,            0, /* 'c' */ 20,
> -    /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
> -    /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
> -    /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
> -    /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
> -    /* 't' */ 27, /* 'u' */ 16,            0,            0,
> -    /* 'x' */ 18,            0, /* 'z' */ 13
> -  };
> -
> -#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
> -#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
> -#define LABEL(Name) do_##Name
> -#ifdef SHARED
> -  /* 'int' is enough and it saves some space on 64 bit systems.  */
> -# define JUMP_TABLE_TYPE const int
> -# define JUMP_TABLE_BASE_LABEL do_form_unknown
> -# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
> -# define JUMP(ChExpr, table)						      \
> -      do								      \
> -	{								      \
> -	  int offset;							      \
> -	  void *ptr;							      \
> -	  spec = (ChExpr);						      \
> -	  offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)	      \
> -	    : table[CHAR_CLASS (spec)];					      \
> -	  ptr = &&JUMP_TABLE_BASE_LABEL + offset;			      \
> -	  goto *ptr;							      \
> -	}								      \
> -      while (0)
> -#else
> -# define JUMP_TABLE_TYPE const void *const
> -# define REF(Name) &&do_##Name
> -# define JUMP(ChExpr, table)						      \
> -      do								      \
> -	{								      \
> -	  const void *ptr;						      \
> -	  spec = (ChExpr);						      \
> -	  ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)		      \
> -	    : table[CHAR_CLASS (spec)];					      \
> -	  goto *ptr;							      \
> -	}								      \
> -      while (0)
> -#endif
> -
> -#define STEP0_3_TABLE							      \
> -    /* Step 0: at the beginning.  */					      \
> -    static JUMP_TABLE_TYPE step0_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (flag_space),		/* for ' ' */				      \
> -      REF (flag_plus),		/* for '+' */				      \
> -      REF (flag_minus),		/* for '-' */				      \
> -      REF (flag_hash),		/* for '<hash>' */			      \
> -      REF (flag_zero),		/* for '0' */				      \
> -      REF (flag_quote),		/* for '\'' */				      \
> -      REF (width_asterics),	/* for '*' */				      \
> -      REF (width),		/* for '1'...'9' */			      \
> -      REF (precision),		/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (flag_i18n),		/* for 'I' */				      \
> -    };									      \
> -    /* Step 1: after processing width.  */				      \
> -    static JUMP_TABLE_TYPE step1_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (precision),		/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 2: after processing precision.  */				      \
> -    static JUMP_TABLE_TYPE step2_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 3a: after processing first 'h' modifier.  */		      \
> -    static JUMP_TABLE_TYPE step3a_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (mod_halfhalf),	/* for 'h' */				      \
> -      REF (form_unknown),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_unknown),	/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_unknown),	/* for 'c' */				      \
> -      REF (form_unknown),	/* for 's', 'S' */			      \
> -      REF (form_unknown),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_unknown),	/* for 'm' */				      \
> -      REF (form_unknown),	/* for 'C' */				      \
> -      REF (form_unknown),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 3b: after processing first 'l' modifier.  */		      \
> -    static JUMP_TABLE_TYPE step3b_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (form_unknown),	/* for 'h' */				      \
> -      REF (mod_longlong),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    }
> -
> -#define STEP4_TABLE							      \
> -    /* Step 4: processing format specifier.  */				      \
> -    static JUMP_TABLE_TYPE step4_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (form_unknown),	/* for 'h' */				      \
> -      REF (form_unknown),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    }
> -
> -
> -#define process_arg(fspec)						      \
> -      /* Start real work.  We know about all flags and modifiers and	      \
> -	 now process the wanted format specifier.  */			      \
> -    LABEL (form_percent):						      \
> -      /* Write a literal "%".  */					      \
> -      outchar (L_('%'));						      \
> -      break;								      \
> -									      \
> -    LABEL (form_integer):						      \
> -      /* Signed decimal integer.  */					      \
> -      base = 10;							      \
> -									      \
> -      if (is_longlong)							      \
> -	{								      \
> -	  long long int signed_number;					      \
> -									      \
> -	  if (fspec == NULL)						      \
> -	    signed_number = va_arg (ap, long long int);			      \
> -	  else								      \
> -	    signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
> -									      \
> -	  is_negative = signed_number < 0;				      \
> -	  number.longlong = is_negative ? (- signed_number) : signed_number;  \
> -									      \
> -	  goto LABEL (longlong_number);					      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  long int signed_number;					      \
> -									      \
> -	  if (fspec == NULL)						      \
> -	    {								      \
> -	      if (is_long_num)						      \
> -		signed_number = va_arg (ap, long int);			      \
> -	      else if (is_char)						      \
> -		signed_number = (signed char) va_arg (ap, unsigned int);      \
> -	      else if (!is_short)					      \
> -		signed_number = va_arg (ap, int);			      \
> -	      else							      \
> -		signed_number = (short int) va_arg (ap, unsigned int);	      \
> -	    }								      \
> -	  else								      \
> -	    if (is_long_num)						      \
> -	      signed_number = args_value[fspec->data_arg].pa_long_int;	      \
> -	    else if (is_char)						      \
> -	      signed_number = (signed char)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -	    else if (!is_short)						      \
> -	      signed_number = args_value[fspec->data_arg].pa_int;	      \
> -	    else							      \
> -	      signed_number = (short int)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -									      \
> -	  is_negative = signed_number < 0;				      \
> -	  number.word = is_negative ? (- signed_number) : signed_number;      \
> -									      \
> -	  goto LABEL (number);						      \
> -	}								      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_unsigned):						      \
> -      /* Unsigned decimal integer.  */					      \
> -      base = 10;							      \
> -      goto LABEL (unsigned_number);					      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_octal):							      \
> -      /* Unsigned octal integer.  */					      \
> -      base = 8;								      \
> -      goto LABEL (unsigned_number);					      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_hexa):							      \
> -      /* Unsigned hexadecimal integer.  */				      \
> -      base = 16;							      \
> -									      \
> -    LABEL (unsigned_number):	  /* Unsigned number of base BASE.  */	      \
> -									      \
> -      /* ISO specifies the `+' and ` ' flags only for signed		      \
> -	 conversions.  */						      \
> -      is_negative = 0;							      \
> -      showsign = 0;							      \
> -      space = 0;							      \
> -									      \
> -      if (is_longlong)							      \
> -	{								      \
> -	  if (fspec == NULL)						      \
> -	    number.longlong = va_arg (ap, unsigned long long int);	      \
> -	  else								      \
> -	    number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
> -									      \
> -	LABEL (longlong_number):					      \
> -	  if (prec < 0)							      \
> -	    /* Supply a default precision if none was given.  */	      \
> -	    prec = 1;							      \
> -	  else								      \
> -	    /* We have to take care for the '0' flag.  If a precision	      \
> -	       is given it must be ignored.  */				      \
> -	    pad = L_(' ');						      \
> -									      \
> -	  /* If the precision is 0 and the number is 0 nothing has to	      \
> -	     be written for the number, except for the 'o' format in	      \
> -	     alternate form.  */					      \
> -	  if (prec == 0 && number.longlong == 0)			      \
> -	    {								      \
> -	      string = workend;						      \
> -	      if (base == 8 && alt)					      \
> -		*--string = L_('0');					      \
> -	    }								      \
> -	  else								      \
> -	    {								      \
> -	      /* Put the number in WORK.  */				      \
> -	      string = _itoa (number.longlong, workend, base,		      \
> -			      spec == L_('X'));				      \
> -	      if (group && grouping)					      \
> -		string = group_number (work_buffer, string, workend,	      \
> -				       grouping, thousands_sep);	      \
> -	      if (use_outdigits && base == 10)				      \
> -		string = _i18n_number_rewrite (string, workend, workend);     \
> -	    }								      \
> -	  /* Simplify further test for num != 0.  */			      \
> -	  number.word = number.longlong != 0;				      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  if (fspec == NULL)						      \
> -	    {								      \
> -	      if (is_long_num)						      \
> -		number.word = va_arg (ap, unsigned long int);		      \
> -	      else if (is_char)						      \
> -		number.word = (unsigned char) va_arg (ap, unsigned int);      \
> -	      else if (!is_short)					      \
> -		number.word = va_arg (ap, unsigned int);		      \
> -	      else							      \
> -		number.word = (unsigned short int) va_arg (ap, unsigned int); \
> -	    }								      \
> -	  else								      \
> -	    if (is_long_num)						      \
> -	      number.word = args_value[fspec->data_arg].pa_u_long_int;	      \
> -	    else if (is_char)						      \
> -	      number.word = (unsigned char)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -	    else if (!is_short)						      \
> -	      number.word = args_value[fspec->data_arg].pa_u_int;	      \
> -	    else							      \
> -	      number.word = (unsigned short int)			      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -									      \
> -	LABEL (number):							      \
> -	  if (prec < 0)							      \
> -	    /* Supply a default precision if none was given.  */	      \
> -	    prec = 1;							      \
> -	  else								      \
> -	    /* We have to take care for the '0' flag.  If a precision	      \
> -	       is given it must be ignored.  */				      \
> -	    pad = L_(' ');						      \
> -									      \
> -	  /* If the precision is 0 and the number is 0 nothing has to	      \
> -	     be written for the number, except for the 'o' format in	      \
> -	     alternate form.  */					      \
> -	  if (prec == 0 && number.word == 0)				      \
> -	    {								      \
> -	      string = workend;						      \
> -	      if (base == 8 && alt)					      \
> -		*--string = L_('0');					      \
> -	    }								      \
> -	  else								      \
> -	    {								      \
> -	      /* Put the number in WORK.  */				      \
> -	      string = _itoa_word (number.word, workend, base,		      \
> -				   spec == L_('X'));			      \
> -	      if (group && grouping)					      \
> -		string = group_number (work_buffer, string, workend,	      \
> -				       grouping, thousands_sep);	      \
> -	      if (use_outdigits && base == 10)				      \
> -		string = _i18n_number_rewrite (string, workend, workend);     \
> -	    }								      \
> -	}								      \
> -									      \
> -      if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
> -	/* Add octal marker.  */					      \
> -	*--string = L_('0');						      \
> -									      \
> -      prec = MAX (0, prec - (workend - string));			      \
> -									      \
> -      if (!left)							      \
> -	{								      \
> -	  width -= workend - string + prec;				      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    /* Account for 0X hex marker.  */				      \
> -	    width -= 2;							      \
> -									      \
> -	  if (is_negative || showsign || space)				      \
> -	    --width;							      \
> -									      \
> -	  if (pad == L_(' '))						      \
> -	    {								      \
> -	      PAD (L_(' '));						      \
> -	      width = 0;						      \
> -	    }								      \
> -									      \
> -	  if (is_negative)						      \
> -	    outchar (L_('-'));						      \
> -	  else if (showsign)						      \
> -	    outchar (L_('+'));						      \
> -	  else if (space)						      \
> -	    outchar (L_(' '));						      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    {								      \
> -	      outchar (L_('0'));					      \
> -	      outchar (spec);						      \
> -	    }								      \
> -									      \
> -	  width += prec;						      \
> -	  PAD (L_('0'));						      \
> -									      \
> -	  outstring (string, workend - string);				      \
> -									      \
> -	  break;							      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  if (is_negative)						      \
> -	    {								      \
> -	      outchar (L_('-'));					      \
> -	      --width;							      \
> -	    }								      \
> -	  else if (showsign)						      \
> -	    {								      \
> -	      outchar (L_('+'));					      \
> -	      --width;							      \
> -	    }								      \
> -	  else if (space)						      \
> -	    {								      \
> -	      outchar (L_(' '));					      \
> -	      --width;							      \
> -	    }								      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    {								      \
> -	      outchar (L_('0'));					      \
> -	      outchar (spec);						      \
> -	      width -= 2;						      \
> -	    }								      \
> -									      \
> -	  width -= workend - string + prec;				      \
> -									      \
> -	  if (prec > 0)							      \
> -	    {								      \
> -	      int temp = width;						      \
> -	      width = prec;						      \
> -	      PAD (L_('0'));						      \
> -	      width = temp;						      \
> -	    }								      \
> -									      \
> -	  outstring (string, workend - string);				      \
> -									      \
> -	  PAD (L_(' '));						      \
> -	  break;							      \
> -	}								      \
> -									      \
> -    LABEL (form_float):							      \
> -      {									      \
> -	/* Floating-point number.  This is handled by printf_fp.c.  */	      \
> -	const void *ptr;						      \
> -	int function_done;						      \
> -									      \
> -	if (fspec == NULL)						      \
> -	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> -	      is_long_double = 0;					      \
> -									      \
> -	    struct printf_info info = { .prec = prec,			      \
> -					.width = width,			      \
> -					.spec = spec,			      \
> -					.is_long_double = is_long_double,     \
> -					.is_short = is_short,		      \
> -					.is_long = is_long,		      \
> -					.alt = alt,			      \
> -					.space = space,			      \
> -					.left = left,			      \
> -					.showsign = showsign,		      \
> -					.group = group,			      \
> -					.pad = pad,			      \
> -					.extra = 0,			      \
> -					.i18n = use_outdigits,		      \
> -					.wide = sizeof (CHAR_T) != 1,	      \
> -					.is_binary128 = 0};		      \
> -									      \
> -	    if (is_long_double)						      \
> -	      the_arg.pa_long_double = va_arg (ap, long double);	      \
> -	    else							      \
> -	      the_arg.pa_double = va_arg (ap, double);			      \
> -	    ptr = (const void *) &the_arg;				      \
> -									      \
> -	    function_done = __printf_fp (s, &info, &ptr);		      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> -	      {								      \
> -		fspec->data_arg_type = PA_DOUBLE;			      \
> -		fspec->info.is_long_double = 0;				      \
> -	      }								      \
> -	    /* Not supported by *printf functions.  */			      \
> -	    fspec->info.is_binary128 = 0;				      \
> -									      \
> -	    function_done = __printf_fp (s, &fspec->info, &ptr);	      \
> -	  }								      \
> -									      \
> -	if (function_done < 0)						      \
> -	  {								      \
> -	    /* Error in print handler; up to handler to set errno.  */	      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -									      \
> -	done_add (function_done);					      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_floathex):						      \
> -      {									      \
> -	/* Floating point number printed as hexadecimal number.  */	      \
> -	const void *ptr;						      \
> -	int function_done;						      \
> -									      \
> -	if (fspec == NULL)						      \
> -	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> -	      is_long_double = 0;					      \
> -									      \
> -	    struct printf_info info = { .prec = prec,			      \
> -					.width = width,			      \
> -					.spec = spec,			      \
> -					.is_long_double = is_long_double,     \
> -					.is_short = is_short,		      \
> -					.is_long = is_long,		      \
> -					.alt = alt,			      \
> -					.space = space,			      \
> -					.left = left,			      \
> -					.showsign = showsign,		      \
> -					.group = group,			      \
> -					.pad = pad,			      \
> -					.extra = 0,			      \
> -					.wide = sizeof (CHAR_T) != 1,	      \
> -					.is_binary128 = 0};		      \
> -									      \
> -	    if (is_long_double)						      \
> -	      the_arg.pa_long_double = va_arg (ap, long double);	      \
> -	    else							      \
> -	      the_arg.pa_double = va_arg (ap, double);			      \
> -	    ptr = (const void *) &the_arg;				      \
> -									      \
> -	    function_done = __printf_fphex (s, &info, &ptr);		      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> -	      fspec->info.is_long_double = 0;				      \
> -	    /* Not supported by *printf functions.  */			      \
> -	    fspec->info.is_binary128 = 0;				      \
> -									      \
> -	    function_done = __printf_fphex (s, &fspec->info, &ptr);	      \
> -	  }								      \
> -									      \
> -	if (function_done < 0)						      \
> -	  {								      \
> -	    /* Error in print handler; up to handler to set errno.  */	      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -									      \
> -	done_add (function_done);					      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_pointer):						      \
> -      /* Generic pointer.  */						      \
> -      {									      \
> -	const void *ptr;						      \
> -	if (fspec == NULL)						      \
> -	  ptr = va_arg (ap, void *);					      \
> -	else								      \
> -	  ptr = args_value[fspec->data_arg].pa_pointer;			      \
> -	if (ptr != NULL)						      \
> -	  {								      \
> -	    /* If the pointer is not NULL, write it as a %#x spec.  */	      \
> -	    base = 16;							      \
> -	    number.word = (unsigned long int) ptr;			      \
> -	    is_negative = 0;						      \
> -	    alt = 1;							      \
> -	    group = 0;							      \
> -	    spec = L_('x');						      \
> -	    goto LABEL (number);					      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    /* Write "(nil)" for a nil pointer.  */			      \
> -	    string = (CHAR_T *) L_("(nil)");				      \
> -	    /* Make sure the full string "(nil)" is printed.  */	      \
> -	    if (prec < 5)						      \
> -	      prec = 5;							      \
> -	    /* This is a wide string iff compiling wprintf.  */		      \
> -	    is_long = sizeof (CHAR_T) > 1;				      \
> -	    goto LABEL (print_string);					      \
> -	  }								      \
> -      }									      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_number):						      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
> -	{								      \
> -	  if (! readonly_format)					      \
> -	    {								      \
> -	      extern int __readonly_area (const void *, size_t)		      \
> -		attribute_hidden;					      \
> -	      readonly_format						      \
> -		= __readonly_area (format, ((STR_LEN (format) + 1)	      \
> -					    * sizeof (CHAR_T)));	      \
> -	    }								      \
> -	  if (readonly_format < 0)					      \
> -	    __libc_fatal ("*** %n in writable segment detected ***\n");	      \
> -	}								      \
> -      /* Answer the count of characters written.  */			      \
> -      if (fspec == NULL)						      \
> -	{								      \
> -	  if (is_longlong)						      \
> -	    *(long long int *) va_arg (ap, void *) = done;		      \
> -	  else if (is_long_num)						      \
> -	    *(long int *) va_arg (ap, void *) = done;			      \
> -	  else if (is_char)						      \
> -	    *(char *) va_arg (ap, void *) = done;			      \
> -	  else if (!is_short)						      \
> -	    *(int *) va_arg (ap, void *) = done;			      \
> -	  else								      \
> -	    *(short int *) va_arg (ap, void *) = done;			      \
> -	}								      \
> -      else								      \
> -	if (is_longlong)						      \
> -	  *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
> -	else if (is_long_num)						      \
> -	  *(long int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else if (is_char)						      \
> -	  *(char *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else if (!is_short)						      \
> -	  *(int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else								      \
> -	  *(short int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -      break;								      \
> -									      \
> -    LABEL (form_strerror):						      \
> -      /* Print description of error ERRNO.  */				      \
> -      string =								      \
> -	(CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,	      \
> -				 WORK_BUFFER_SIZE * sizeof (CHAR_T));	      \
> -      is_long = 0;		/* This is no wide-char string.  */	      \
> -      goto LABEL (print_string)
> -
> -#ifdef COMPILE_WPRINTF
> -# define process_string_arg(fspec) \
> -    LABEL (form_character):						      \
> -      /* Character.  */							      \
> -      if (is_long)							      \
> -	goto LABEL (form_wcharacter);					      \
> -      --width;	/* Account for the character itself.  */		      \
> -      if (!left)							      \
> -	PAD (L' ');							      \
> -      if (fspec == NULL)						      \
> -	outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
> -      else								      \
> -	outchar (__btowc ((unsigned char)				      \
> -			  args_value[fspec->data_arg].pa_int));		      \
> -      if (left)								      \
> -	PAD (L' ');							      \
> -      break;								      \
> -									      \
> -    LABEL (form_wcharacter):						      \
> -      {									      \
> -	/* Wide character.  */						      \
> -	--width;							      \
> -	if (!left)							      \
> -	  PAD (L' ');							      \
> -	if (fspec == NULL)						      \
> -	  outchar (va_arg (ap, wchar_t));				      \
> -	else								      \
> -	  outchar (args_value[fspec->data_arg].pa_wchar);		      \
> -	if (left)							      \
> -	  PAD (L' ');							      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_string):						      \
> -      {									      \
> -	size_t len;							      \
> -	int string_malloced;						      \
> -									      \
> -	/* The string argument could in fact be `char *' or `wchar_t *'.      \
> -	   But this should not make a difference here.  */		      \
> -	if (fspec == NULL)						      \
> -	  string = (CHAR_T *) va_arg (ap, const wchar_t *);		      \
> -	else								      \
> -	  string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring;	      \
> -									      \
> -	/* Entry point for printing other strings.  */			      \
> -      LABEL (print_string):						      \
> -									      \
> -	string_malloced = 0;						      \
> -	if (string == NULL)						      \
> -	  {								      \
> -	    /* Write "(null)" if there's space.  */			      \
> -	    if (prec == -1 || prec >= (int) array_length (null) - 1)          \
> -	      {								      \
> -		string = (CHAR_T *) null;				      \
> -		len = array_length (null) - 1;				      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		string = (CHAR_T *) L"";				      \
> -		len = 0;						      \
> -	      }								      \
> -	  }								      \
> -	else if (!is_long && spec != L_('S'))				      \
> -	  {								      \
> -	    /* This is complicated.  We have to transform the multibyte	      \
> -	       string into a wide character string.  */			      \
> -	    const char *mbs = (const char *) string;			      \
> -	    mbstate_t mbstate;						      \
> -									      \
> -	    len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
> -									      \
> -	    /* Allocate dynamically an array which definitely is long	      \
> -	       enough for the wide character version.  Each byte in the	      \
> -	       multi-byte string can produce at most one wide character.  */  \
> -	    if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))	      \
> -	      {								      \
> -		__set_errno (EOVERFLOW);				      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	    else if (__libc_use_alloca (len * sizeof (wchar_t)))	      \
> -	      string = (CHAR_T *) alloca (len * sizeof (wchar_t));	      \
> -	    else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
> -		     == NULL)						      \
> -	      {								      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	    else							      \
> -	      string_malloced = 1;					      \
> -									      \
> -	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
> -	    len = __mbsrtowcs (string, &mbs, len, &mbstate);		      \
> -	    if (len == (size_t) -1)					      \
> -	      {								      \
> -		/* Illegal multibyte character.  */			      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    if (prec != -1)						      \
> -	      /* Search for the end of the string, but don't search past      \
> -		 the length specified by the precision.  */		      \
> -	      len = __wcsnlen (string, prec);				      \
> -	    else							      \
> -	      len = __wcslen (string);					      \
> -	  }								      \
> -									      \
> -	if ((width -= len) < 0)						      \
> -	  {								      \
> -	    outstring (string, len);					      \
> -	    break;							      \
> -	  }								      \
> -									      \
> -	if (!left)							      \
> -	  PAD (L' ');							      \
> -	outstring (string, len);					      \
> -	if (left)							      \
> -	  PAD (L' ');							      \
> -	if (__glibc_unlikely (string_malloced))				      \
> -	  free (string);						      \
> -      }									      \
> -      break;
> -#else
> -# define process_string_arg(fspec) \
> -    LABEL (form_character):						      \
> -      /* Character.  */							      \
> -      if (is_long)							      \
> -	goto LABEL (form_wcharacter);					      \
> -      --width;	/* Account for the character itself.  */		      \
> -      if (!left)							      \
> -	PAD (' ');							      \
> -      if (fspec == NULL)						      \
> -	outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */	      \
> -      else								      \
> -	outchar ((unsigned char) args_value[fspec->data_arg].pa_int);	      \
> -      if (left)								      \
> -	PAD (' ');							      \
> -      break;								      \
> -									      \
> -    LABEL (form_wcharacter):						      \
> -      {									      \
> -	/* Wide character.  */						      \
> -	char buf[MB_LEN_MAX];						      \
> -	mbstate_t mbstate;						      \
> -	size_t len;							      \
> -									      \
> -	memset (&mbstate, '\0', sizeof (mbstate_t));			      \
> -	len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t)	      \
> -			       : args_value[fspec->data_arg].pa_wchar),	      \
> -			 &mbstate);					      \
> -	if (len == (size_t) -1)						      \
> -	  {								      \
> -	    /* Something went wrong during the conversion.  Bail out.  */     \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	width -= len;							      \
> -	if (!left)							      \
> -	  PAD (' ');							      \
> -	outstring (buf, len);						      \
> -	if (left)							      \
> -	  PAD (' ');							      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_string):						      \
> -      {									      \
> -	size_t len;							      \
> -	int string_malloced;						      \
> -									      \
> -	/* The string argument could in fact be `char *' or `wchar_t *'.      \
> -	   But this should not make a difference here.  */		      \
> -	if (fspec == NULL)						      \
> -	  string = (char *) va_arg (ap, const char *);			      \
> -	else								      \
> -	  string = (char *) args_value[fspec->data_arg].pa_string;	      \
> -									      \
> -	/* Entry point for printing other strings.  */			      \
> -      LABEL (print_string):						      \
> -									      \
> -	string_malloced = 0;						      \
> -	if (string == NULL)						      \
> -	  {								      \
> -	    /* Write "(null)" if there's space.  */			      \
> -	    if (prec == -1 || prec >= (int) sizeof (null) - 1)		      \
> -	      {								      \
> -		string = (char *) null;					      \
> -		len = sizeof (null) - 1;				      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		string = (char *) "";					      \
> -		len = 0;						      \
> -	      }								      \
> -	  }								      \
> -	else if (!is_long && spec != L_('S'))				      \
> -	  {								      \
> -	    if (prec != -1)						      \
> -	      /* Search for the end of the string, but don't search past      \
> -		 the length (in bytes) specified by the precision.  */	      \
> -	      len = __strnlen (string, prec);				      \
> -	    else							      \
> -	      len = strlen (string);					      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    const wchar_t *s2 = (const wchar_t *) string;		      \
> -	    mbstate_t mbstate;						      \
> -									      \
> -	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
> -									      \
> -	    if (prec >= 0)						      \
> -	      {								      \
> -		/* The string `s2' might not be NUL terminated.  */	      \
> -		if (__libc_use_alloca (prec))				      \
> -		  string = (char *) alloca (prec);			      \
> -		else if ((string = (char *) malloc (prec)) == NULL)	      \
> -		  {							      \
> -		    done = -1;						      \
> -		    goto all_done;					      \
> -		  }							      \
> -		else							      \
> -		  string_malloced = 1;					      \
> -		len = __wcsrtombs (string, &s2, prec, &mbstate);	      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		len = __wcsrtombs (NULL, &s2, 0, &mbstate);		      \
> -		if (len != (size_t) -1)					      \
> -		  {							      \
> -		    assert (__mbsinit (&mbstate));			      \
> -		    s2 = (const wchar_t *) string;			      \
> -		    if (__libc_use_alloca (len + 1))			      \
> -		      string = (char *) alloca (len + 1);		      \
> -		    else if ((string = (char *) malloc (len + 1)) == NULL)    \
> -		      {							      \
> -			done = -1;					      \
> -			goto all_done;					      \
> -		      }							      \
> -		    else						      \
> -		      string_malloced = 1;				      \
> -		    (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
> -		  }							      \
> -	      }								      \
> -									      \
> -	    if (len == (size_t) -1)					      \
> -	      {								      \
> -		/* Illegal wide-character string.  */			      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	  }								      \
> -									      \
> -	if ((width -= len) < 0)						      \
> -	  {								      \
> -	    outstring (string, len);					      \
> -	    break;							      \
> -	  }								      \
> -									      \
> -	if (!left)							      \
> -	  PAD (' ');							      \
> -	outstring (string, len);					      \
> -	if (left)							      \
> -	  PAD (' ');							      \
> -	if (__glibc_unlikely (string_malloced))			              \
> -	  free (string);						      \
> -      }									      \
> -      break;
> -#endif
> -
> -/* Helper function to provide temporary buffering for unbuffered streams.  */
> -static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
> -     __THROW __attribute__ ((noinline));
> -
> -/* Handle positional format specifiers.  */
> -static int printf_positional (FILE *s,
> -			      const CHAR_T *format, int readonly_format,
> -			      va_list ap, va_list *ap_savep, int done,
> -			      int nspecs_done, const UCHAR_T *lead_str_end,
> -			      CHAR_T *work_buffer, int save_errno,
> -			      const char *grouping, THOUSANDS_SEP_T);
> -
> -/* Handle unknown format specifier.  */
> -static int printf_unknown (FILE *, const struct printf_info *,
> -			   const void *const *) __THROW;
> -
> -/* Group digits of number string.  */
> -static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
> -			     THOUSANDS_SEP_T);
> -
> -/* The function itself.  */
> -int
> -vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> +extern int
> +__vfprintf (FILE *fp, const char *format, va_list ap)
>  {
> -  /* The character used as thousands separator.  */
> -  THOUSANDS_SEP_T thousands_sep = 0;
> -
> -  /* The string describing the size of groups of digits.  */
> -  const char *grouping;
> -
> -  /* Place to accumulate the result.  */
> -  int done;
> -
> -  /* Current character in format string.  */
> -  const UCHAR_T *f;
> -
> -  /* End of leading constant string.  */
> -  const UCHAR_T *lead_str_end;
> -
> -  /* Points to next format specifier.  */
> -  const UCHAR_T *end_of_spec;
> -
> -  /* Buffer intermediate results.  */
> -  CHAR_T work_buffer[WORK_BUFFER_SIZE];
> -  CHAR_T *workstart = NULL;
> -  CHAR_T *workend;
> -
> -  /* We have to save the original argument pointer.  */
> -  va_list ap_save;
> -
> -  /* Count number of specifiers we already processed.  */
> -  int nspecs_done;
> -
> -  /* For the %m format we may need the current `errno' value.  */
> -  int save_errno = errno;
> -
> -  /* 1 if format is in read-only memory, -1 if it is in writable memory,
> -     0 if unknown.  */
> -  int readonly_format = 0;
> -
> -  /* Orient the stream.  */
> -#ifdef ORIENT
> -  ORIENT;
> -#endif
> -
> -  /* Sanity check of arguments.  */
> -  ARGCHECK (s, format);
> -
> -#ifdef ORIENT
> -  /* Check for correct orientation.  */
> -  if (_IO_vtable_offset (s) == 0 &&
> -      _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
> -      != (sizeof (CHAR_T) == 1 ? -1 : 1))
> -    /* The stream is already oriented otherwise.  */
> -    return EOF;
> -#endif
> -
> -  if (UNBUFFERED_P (s))
> -    /* Use a helper function which will allocate a local temporary buffer
> -       for the stream and then call us again.  */
> -    return buffered_vfprintf (s, format, ap);
> -
> -  /* Initialize local variables.  */
> -  done = 0;
> -  grouping = (const char *) -1;
> -#ifdef __va_copy
> -  /* This macro will be available soon in gcc's <stdarg.h>.  We need it
> -     since on some systems `va_list' is not an integral type.  */
> -  __va_copy (ap_save, ap);
> -#else
> -  ap_save = ap;
> -#endif
> -  nspecs_done = 0;
> -
> -#ifdef COMPILE_WPRINTF
> -  /* Find the first format specifier.  */
> -  f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
> -#else
> -  /* Find the first format specifier.  */
> -  f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
> -#endif
> -
> -  /* Lock stream.  */
> -  _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
> -  _IO_flockfile (s);
> -
> -  /* Write the literal text before the first format.  */
> -  outstring ((const UCHAR_T *) format,
> -	     lead_str_end - (const UCHAR_T *) format);
> -
> -  /* If we only have to print a simple string, return now.  */
> -  if (*f == L_('\0'))
> -    goto all_done;
> -
> -  /* Use the slow path in case any printf handler is registered.  */
> -  if (__glibc_unlikely (__printf_function_table != NULL
> -			|| __printf_modifier_table != NULL
> -			|| __printf_va_arg_table != NULL))
> -    goto do_positional;
> -
> -  /* Process whole format string.  */
> -  do
> -    {
> -      STEP0_3_TABLE;
> -      STEP4_TABLE;
> -
> -      union printf_arg *args_value;	/* This is not used here but ... */
> -      int is_negative;	/* Flag for negative number.  */
> -      union
> -      {
> -	unsigned long long int longlong;
> -	unsigned long int word;
> -      } number;
> -      int base;
> -      union printf_arg the_arg;
> -      CHAR_T *string;	/* Pointer to argument string.  */
> -      int alt = 0;	/* Alternate format.  */
> -      int space = 0;	/* Use space prefix if no sign is needed.  */
> -      int left = 0;	/* Left-justify output.  */
> -      int showsign = 0;	/* Always begin with plus or minus sign.  */
> -      int group = 0;	/* Print numbers according grouping rules.  */
> -      int is_long_double = 0; /* Argument is long double/ long long int.  */
> -      int is_short = 0;	/* Argument is short int.  */
> -      int is_long = 0;	/* Argument is long int.  */
> -      int is_char = 0;	/* Argument is promoted (unsigned) char.  */
> -      int width = 0;	/* Width of output; 0 means none specified.  */
> -      int prec = -1;	/* Precision of output; -1 means none specified.  */
> -      /* This flag is set by the 'I' modifier and selects the use of the
> -	 `outdigits' as determined by the current locale.  */
> -      int use_outdigits = 0;
> -      UCHAR_T pad = L_(' ');/* Padding character.  */
> -      CHAR_T spec;
> -
> -      workstart = NULL;
> -      workend = work_buffer + WORK_BUFFER_SIZE;
> -
> -      /* Get current character in format string.  */
> -      JUMP (*++f, step0_jumps);
> -
> -      /* ' ' flag.  */
> -    LABEL (flag_space):
> -      space = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* '+' flag.  */
> -    LABEL (flag_plus):
> -      showsign = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '-' flag.  */
> -    LABEL (flag_minus):
> -      left = 1;
> -      pad = L_(' ');
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '#' flag.  */
> -    LABEL (flag_hash):
> -      alt = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '0' flag.  */
> -    LABEL (flag_zero):
> -      if (!left)
> -	pad = L_('0');
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '\'' flag.  */
> -    LABEL (flag_quote):
> -      group = 1;
> -
> -      if (grouping == (const char *) -1)
> -	{
> -#ifdef COMPILE_WPRINTF
> -	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> -					    _NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> -	  thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> -#endif
> -
> -	  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> -	  if (*grouping == '\0' || *grouping == CHAR_MAX
> -#ifdef COMPILE_WPRINTF
> -	      || thousands_sep == L'\0'
> -#else
> -	      || *thousands_sep == '\0'
> -#endif
> -	      )
> -	    grouping = NULL;
> -	}
> -      JUMP (*++f, step0_jumps);
> -
> -    LABEL (flag_i18n):
> -      use_outdigits = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* Get width from argument.  */
> -    LABEL (width_asterics):
> -      {
> -	const UCHAR_T *tmp;	/* Temporary value.  */
> -
> -	tmp = ++f;
> -	if (ISDIGIT (*tmp))
> -	  {
> -	    int pos = read_int (&tmp);
> -
> -	    if (pos == -1)
> -	      {
> -		__set_errno (EOVERFLOW);
> -		done = -1;
> -		goto all_done;
> -	      }
> -
> -	    if (pos && *tmp == L_('$'))
> -	      /* The width comes from a positional parameter.  */
> -	      goto do_positional;
> -	  }
> -	width = va_arg (ap, int);
> -
> -	/* Negative width means left justified.  */
> -	if (width < 0)
> -	  {
> -	    width = -width;
> -	    pad = L_(' ');
> -	    left = 1;
> -	  }
> -
> -	if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	  {
> -	    __set_errno (EOVERFLOW);
> -	    done = -1;
> -	    goto all_done;
> -	  }
> -
> -	if (width >= WORK_BUFFER_SIZE - EXTSIZ)
> -	  {
> -	    /* We have to use a special buffer.  */
> -	    size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
> -	    if (__libc_use_alloca (needed))
> -	      workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
> -	    else
> -	      {
> -		workstart = (CHAR_T *) malloc (needed);
> -		if (workstart == NULL)
> -		  {
> -		    done = -1;
> -		    goto all_done;
> -		  }
> -		workend = workstart + width + EXTSIZ;
> -	      }
> -	  }
> -      }
> -      JUMP (*f, step1_jumps);
> -
> -      /* Given width in format string.  */
> -    LABEL (width):
> -      width = read_int (&f);
> -
> -      if (__glibc_unlikely (width == -1
> -			    || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	{
> -	  __set_errno (EOVERFLOW);
> -	  done = -1;
> -	  goto all_done;
> -	}
> -
> -      if (width >= WORK_BUFFER_SIZE - EXTSIZ)
> -	{
> -	  /* We have to use a special buffer.  */
> -	  size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
> -	  if (__libc_use_alloca (needed))
> -	    workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc (needed);
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + width + EXTSIZ;
> -	    }
> -	}
> -      if (*f == L_('$'))
> -	/* Oh, oh.  The argument comes from a positional parameter.  */
> -	goto do_positional;
> -      JUMP (*f, step1_jumps);
> -
> -    LABEL (precision):
> -      ++f;
> -      if (*f == L_('*'))
> -	{
> -	  const UCHAR_T *tmp;	/* Temporary value.  */
> -
> -	  tmp = ++f;
> -	  if (ISDIGIT (*tmp))
> -	    {
> -	      int pos = read_int (&tmp);
> -
> -	      if (pos == -1)
> -		{
> -		  __set_errno (EOVERFLOW);
> -		  done = -1;
> -		  goto all_done;
> -		}
> -
> -	      if (pos && *tmp == L_('$'))
> -		/* The precision comes from a positional parameter.  */
> -		goto do_positional;
> -	    }
> -	  prec = va_arg (ap, int);
> -
> -	  /* If the precision is negative the precision is omitted.  */
> -	  if (prec < 0)
> -	    prec = -1;
> -	}
> -      else if (ISDIGIT (*f))
> -	{
> -	  prec = read_int (&f);
> -
> -	  /* The precision was specified in this case as an extremely
> -	     large positive value.  */
> -	  if (prec == -1)
> -	    {
> -	      __set_errno (EOVERFLOW);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	}
> -      else
> -	prec = 0;
> -      if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
> -	{
> -	  /* Deallocate any previously allocated buffer because it is
> -	     too small.  */
> -	  if (__glibc_unlikely (workstart != NULL))
> -	    free (workstart);
> -	  workstart = NULL;
> -	  if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	    {
> -	      __set_errno (EOVERFLOW);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	  size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
> -
> -	  if (__libc_use_alloca (needed))
> -	    workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc (needed);
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + prec + EXTSIZ;
> -	    }
> -	}
> -      JUMP (*f, step2_jumps);
> -
> -      /* Process 'h' modifier.  There might another 'h' following.  */
> -    LABEL (mod_half):
> -      is_short = 1;
> -      JUMP (*++f, step3a_jumps);
> -
> -      /* Process 'hh' modifier.  */
> -    LABEL (mod_halfhalf):
> -      is_short = 0;
> -      is_char = 1;
> -      JUMP (*++f, step4_jumps);
> -
> -      /* Process 'l' modifier.  There might another 'l' following.  */
> -    LABEL (mod_long):
> -      is_long = 1;
> -      JUMP (*++f, step3b_jumps);
> -
> -      /* Process 'L', 'q', or 'll' modifier.  No other modifier is
> -	 allowed to follow.  */
> -    LABEL (mod_longlong):
> -      is_long_double = 1;
> -      is_long = 1;
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_size_t):
> -      is_long_double = sizeof (size_t) > sizeof (unsigned long int);
> -      is_long = sizeof (size_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_ptrdiff_t):
> -      is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
> -      is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_intmax_t):
> -      is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
> -      is_long = sizeof (intmax_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -      /* Process current format.  */
> -      while (1)
> -	{
> -	  process_arg (((struct printf_spec *) NULL));
> -	  process_string_arg (((struct printf_spec *) NULL));
> -
> -	LABEL (form_unknown):
> -	  if (spec == L_('\0'))
> -	    {
> -	      /* The format string ended before the specifier is complete.  */
> -	      __set_errno (EINVAL);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -
> -	  /* If we are in the fast loop force entering the complicated
> -	     one.  */
> -	  goto do_positional;
> -	}
> -
> -      /* The format is correctly handled.  */
> -      ++nspecs_done;
> -
> -      if (__glibc_unlikely (workstart != NULL))
> -	free (workstart);
> -      workstart = NULL;
> -
> -      /* Look for next format specifier.  */
> -#ifdef COMPILE_WPRINTF
> -      f = __find_specwc ((end_of_spec = ++f));
> -#else
> -      f = __find_specmb ((end_of_spec = ++f));
> -#endif
> -
> -      /* Write the following constant string.  */
> -      outstring (end_of_spec, f - end_of_spec);
> -    }
> -  while (*f != L_('\0'));
> -
> -  /* Unlock stream and return.  */
> -  goto all_done;
> -
> -  /* Hand off processing for positional parameters.  */
> -do_positional:
> -  if (__glibc_unlikely (workstart != NULL))
> -    {
> -      free (workstart);
> -      workstart = NULL;
> -    }
> -  done = printf_positional (s, format, readonly_format, ap, &ap_save,
> -			    done, nspecs_done, lead_str_end, work_buffer,
> -			    save_errno, grouping, thousands_sep);
> -
> - all_done:
> -  if (__glibc_unlikely (workstart != NULL))
> -    free (workstart);
> -  /* Unlock the stream.  */
> -  _IO_funlockfile (s);
> -  _IO_cleanup_region_end (0);
> -
> -  return done;
> -}
> -\f
> -static int
> -printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
> -		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
> -		   const UCHAR_T *lead_str_end,
> -		   CHAR_T *work_buffer, int save_errno,
> -		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
> -{
> -  /* For positional argument handling.  */
> -  struct scratch_buffer specsbuf;
> -  scratch_buffer_init (&specsbuf);
> -  struct printf_spec *specs = specsbuf.data;
> -  size_t specs_limit = specsbuf.length / sizeof (specs[0]);
> -
> -  /* Used as a backing store for args_value, args_size, args_type
> -     below.  */
> -  struct scratch_buffer argsbuf;
> -  scratch_buffer_init (&argsbuf);
> -
> -  /* Array with information about the needed arguments.  This has to
> -     be dynamically extensible.  */
> -  size_t nspecs = 0;
> -
> -  /* The number of arguments the format string requests.  This will
> -     determine the size of the array needed to store the argument
> -     attributes.  */
> -  size_t nargs = 0;
> -
> -  /* Positional parameters refer to arguments directly.  This could
> -     also determine the maximum number of arguments.  Track the
> -     maximum number.  */
> -  size_t max_ref_arg = 0;
> -
> -  /* Just a counter.  */
> -  size_t cnt;
> -
> -  CHAR_T *workstart = NULL;
> -
> -  if (grouping == (const char *) -1)
> -    {
> -#ifdef COMPILE_WPRINTF
> -      thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> -					_NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> -      thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> -#endif
> -
> -      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> -      if (*grouping == '\0' || *grouping == CHAR_MAX)
> -	grouping = NULL;
> -    }
> -
> -  for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
> -       f = specs[nspecs++].next_fmt)
> -    {
> -      if (nspecs == specs_limit)
> -	{
> -	  if (!scratch_buffer_grow_preserve (&specsbuf))
> -	    {
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	  specs = specsbuf.data;
> -	  specs_limit = specsbuf.length / sizeof (specs[0]);
> -	}
> -
> -      /* Parse the format specifier.  */
> -#ifdef COMPILE_WPRINTF
> -      nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
> -#else
> -      nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
> -#endif
> -    }
> -
> -  /* Determine the number of arguments the format string consumes.  */
> -  nargs = MAX (nargs, max_ref_arg);
> -
> -  union printf_arg *args_value;
> -  int *args_size;
> -  int *args_type;
> -  {
> -    /* Calculate total size needed to represent a single argument
> -       across all three argument-related arrays.  */
> -    size_t bytes_per_arg
> -      = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
> -    if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
> -      {
> -	done = -1;
> -	goto all_done;
> -      }
> -    args_value = argsbuf.data;
> -    /* Set up the remaining two arrays to each point past the end of
> -       the prior array, since space for all three has been allocated
> -       now.  */
> -    args_size = &args_value[nargs].pa_int;
> -    args_type = &args_size[nargs];
> -    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> -	    nargs * sizeof (*args_type));
> -  }
> -
> -  /* XXX Could do sanity check here: If any element in ARGS_TYPE is
> -     still zero after this loop, format is invalid.  For now we
> -     simply use 0 as the value.  */
> -
> -  /* Fill in the types of all the arguments.  */
> -  for (cnt = 0; cnt < nspecs; ++cnt)
> -    {
> -      /* If the width is determined by an argument this is an int.  */
> -      if (specs[cnt].width_arg != -1)
> -	args_type[specs[cnt].width_arg] = PA_INT;
> -
> -      /* If the precision is determined by an argument this is an int.  */
> -      if (specs[cnt].prec_arg != -1)
> -	args_type[specs[cnt].prec_arg] = PA_INT;
> -
> -      switch (specs[cnt].ndata_args)
> -	{
> -	case 0:		/* No arguments.  */
> -	  break;
> -	case 1:		/* One argument; we already have the
> -			   type and size.  */
> -	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
> -	  args_size[specs[cnt].data_arg] = specs[cnt].size;
> -	  break;
> -	default:
> -	  /* We have more than one argument for this format spec.
> -	     We must call the arginfo function again to determine
> -	     all the types.  */
> -	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
> -	    (&specs[cnt].info,
> -	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
> -	     &args_size[specs[cnt].data_arg]);
> -	  break;
> -	}
> -    }
> -
> -  /* Now we know all the types and the order.  Fill in the argument
> -     values.  */
> -  for (cnt = 0; cnt < nargs; ++cnt)
> -    switch (args_type[cnt])
> -      {
> -#define T(tag, mem, type)				\
> -	case tag:					\
> -	  args_value[cnt].mem = va_arg (*ap_savep, type); \
> -	  break
> -
> -	T (PA_WCHAR, pa_wchar, wint_t);
> -      case PA_CHAR:				/* Promoted.  */
> -      case PA_INT|PA_FLAG_SHORT:		/* Promoted.  */
> -#if LONG_MAX == INT_MAX
> -      case PA_INT|PA_FLAG_LONG:
> -#endif
> -	T (PA_INT, pa_int, int);
> -#if LONG_MAX == LONG_LONG_MAX
> -      case PA_INT|PA_FLAG_LONG:
> -#endif
> -	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
> -#if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
> -# error "he?"
> -#endif
> -      case PA_FLOAT:				/* Promoted.  */
> -	T (PA_DOUBLE, pa_double, double);
> -      case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> -	if (__ldbl_is_dbl)
> -	  {
> -	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
> -	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> -	  }
> -	else
> -	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
> -	break;
> -      case PA_STRING:				/* All pointers are the same */
> -      case PA_WSTRING:			/* All pointers are the same */
> -	T (PA_POINTER, pa_pointer, void *);
> -#undef T
> -      default:
> -	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
> -	  args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
> -	else if (__glibc_unlikely (__printf_va_arg_table != NULL)
> -		 && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
> -	  {
> -	    args_value[cnt].pa_user = alloca (args_size[cnt]);
> -	    (*__printf_va_arg_table[args_type[cnt] - PA_LAST])
> -	      (args_value[cnt].pa_user, ap_savep);
> -	  }
> -	else
> -	  args_value[cnt].pa_long_double = 0.0;
> -	break;
> -      case -1:
> -	/* Error case.  Not all parameters appear in N$ format
> -	   strings.  We have no way to determine their type.  */
> -	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> -	__libc_fatal ("*** invalid %N$ use detected ***\n");
> -      }
> -
> -  /* Now walk through all format specifiers and process them.  */
> -  for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
> -    {
> -      STEP4_TABLE;
> -
> -      int is_negative;
> -      union
> -      {
> -	unsigned long long int longlong;
> -	unsigned long int word;
> -      } number;
> -      int base;
> -      union printf_arg the_arg;
> -      CHAR_T *string;		/* Pointer to argument string.  */
> -
> -      /* Fill variables from values in struct.  */
> -      int alt = specs[nspecs_done].info.alt;
> -      int space = specs[nspecs_done].info.space;
> -      int left = specs[nspecs_done].info.left;
> -      int showsign = specs[nspecs_done].info.showsign;
> -      int group = specs[nspecs_done].info.group;
> -      int is_long_double = specs[nspecs_done].info.is_long_double;
> -      int is_short = specs[nspecs_done].info.is_short;
> -      int is_char = specs[nspecs_done].info.is_char;
> -      int is_long = specs[nspecs_done].info.is_long;
> -      int width = specs[nspecs_done].info.width;
> -      int prec = specs[nspecs_done].info.prec;
> -      int use_outdigits = specs[nspecs_done].info.i18n;
> -      char pad = specs[nspecs_done].info.pad;
> -      CHAR_T spec = specs[nspecs_done].info.spec;
> -
> -      workstart = NULL;
> -      CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
> -
> -      /* Fill in last information.  */
> -      if (specs[nspecs_done].width_arg != -1)
> -	{
> -	  /* Extract the field width from an argument.  */
> -	  specs[nspecs_done].info.width =
> -	    args_value[specs[nspecs_done].width_arg].pa_int;
> -
> -	  if (specs[nspecs_done].info.width < 0)
> -	    /* If the width value is negative left justification is
> -	       selected and the value is taken as being positive.  */
> -	    {
> -	      specs[nspecs_done].info.width *= -1;
> -	      left = specs[nspecs_done].info.left = 1;
> -	    }
> -	  width = specs[nspecs_done].info.width;
> -	}
> -
> -      if (specs[nspecs_done].prec_arg != -1)
> -	{
> -	  /* Extract the precision from an argument.  */
> -	  specs[nspecs_done].info.prec =
> -	    args_value[specs[nspecs_done].prec_arg].pa_int;
> -
> -	  if (specs[nspecs_done].info.prec < 0)
> -	    /* If the precision is negative the precision is
> -	       omitted.  */
> -	    specs[nspecs_done].info.prec = -1;
> -
> -	  prec = specs[nspecs_done].info.prec;
> -	}
> -
> -      /* Maybe the buffer is too small.  */
> -      if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
> -	{
> -	  if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
> -				 * sizeof (CHAR_T)))
> -	    workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
> -					  * sizeof (CHAR_T))
> -		       + (MAX (prec, width) + EXTSIZ));
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
> -					     * sizeof (CHAR_T));
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + (MAX (prec, width) + EXTSIZ);
> -	    }
> -	}
> -
> -      /* Process format specifiers.  */
> -      while (1)
> -	{
> -	  extern printf_function **__printf_function_table;
> -	  int function_done;
> -
> -	  if (spec <= UCHAR_MAX
> -	      && __printf_function_table != NULL
> -	      && __printf_function_table[(size_t) spec] != NULL)
> -	    {
> -	      const void **ptr = alloca (specs[nspecs_done].ndata_args
> -					 * sizeof (const void *));
> -
> -	      /* Fill in an array of pointers to the argument values.  */
> -	      for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
> -		   ++i)
> -		ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
> -
> -	      /* Call the function.  */
> -	      function_done = __printf_function_table[(size_t) spec]
> -		(s, &specs[nspecs_done].info, ptr);
> -
> -	      if (function_done != -2)
> -		{
> -		  /* If an error occurred we don't have information
> -		     about # of chars.  */
> -		  if (function_done < 0)
> -		    {
> -		      /* Function has set errno.  */
> -		      done = -1;
> -		      goto all_done;
> -		    }
> -
> -		  done_add (function_done);
> -		  break;
> -		}
> -	    }
> -
> -	  JUMP (spec, step4_jumps);
> -
> -	  process_arg ((&specs[nspecs_done]));
> -	  process_string_arg ((&specs[nspecs_done]));
> -
> -	  LABEL (form_unknown):
> -	  {
> -	    unsigned int i;
> -	    const void **ptr;
> -
> -	    ptr = alloca (specs[nspecs_done].ndata_args
> -			  * sizeof (const void *));
> -
> -	    /* Fill in an array of pointers to the argument values.  */
> -	    for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
> -	      ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
> -
> -	    /* Call the function.  */
> -	    function_done = printf_unknown (s, &specs[nspecs_done].info,
> -					    ptr);
> -
> -	    /* If an error occurred we don't have information about #
> -	       of chars.  */
> -	    if (function_done < 0)
> -	      {
> -		/* Function has set errno.  */
> -		done = -1;
> -		goto all_done;
> -	      }
> -
> -	    done_add (function_done);
> -	  }
> -	  break;
> -	}
> -
> -      if (__glibc_unlikely (workstart != NULL))
> -	free (workstart);
> -      workstart = NULL;
> -
> -      /* Write the following constant string.  */
> -      outstring (specs[nspecs_done].end_of_fmt,
> -		 specs[nspecs_done].next_fmt
> -		 - specs[nspecs_done].end_of_fmt);
> -    }
> - all_done:
> -  if (__glibc_unlikely (workstart != NULL))
> -    free (workstart);
> -  scratch_buffer_free (&argsbuf);
> -  scratch_buffer_free (&specsbuf);
> -  return done;
> +  return __vfprintf_internal (fp, format, ap, 0);
>  }
> -\f
> -/* Handle an unknown format specifier.  This prints out a canonicalized
> -   representation of the format spec itself.  */
> -static int
> -printf_unknown (FILE *s, const struct printf_info *info,
> -		const void *const *args)
> -
> -{
> -  int done = 0;
> -  CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
> -  CHAR_T *const workend
> -    = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
> -  CHAR_T *w;
> -
> -  outchar (L_('%'));
> -
> -  if (info->alt)
> -    outchar (L_('#'));
> -  if (info->group)
> -    outchar (L_('\''));
> -  if (info->showsign)
> -    outchar (L_('+'));
> -  else if (info->space)
> -    outchar (L_(' '));
> -  if (info->left)
> -    outchar (L_('-'));
> -  if (info->pad == L_('0'))
> -    outchar (L_('0'));
> -  if (info->i18n)
> -    outchar (L_('I'));
> -
> -  if (info->width != 0)
> -    {
> -      w = _itoa_word (info->width, workend, 10, 0);
> -      while (w < workend)
> -	outchar (*w++);
> -    }
> -
> -  if (info->prec != -1)
> -    {
> -      outchar (L_('.'));
> -      w = _itoa_word (info->prec, workend, 10, 0);
> -      while (w < workend)
> -	outchar (*w++);
> -    }
> -
> -  if (info->spec != L_('\0'))
> -    outchar (info->spec);
> -
> - all_done:
> -  return done;
> -}
> -\f
> -/* Group the digits from W to REAR_PTR according to the grouping rules
> -   of the current locale.  The interpretation of GROUPING is as in
> -   `struct lconv' from <locale.h>.  The grouped number extends from
> -   the returned pointer until REAR_PTR.  FRONT_PTR to W is used as a
> -   scratch area.  */
> -static CHAR_T *
> -group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
> -	      const char *grouping, THOUSANDS_SEP_T thousands_sep)
> -{
> -  /* Length of the current group.  */
> -  int len;
> -#ifndef COMPILE_WPRINTF
> -  /* Length of the separator (in wide mode, the separator is always a
> -     single wide character).  */
> -  int tlen = strlen (thousands_sep);
> -#endif
> -
> -  /* We treat all negative values like CHAR_MAX.  */
> -
> -  if (*grouping == CHAR_MAX || *grouping <= 0)
> -    /* No grouping should be done.  */
> -    return w;
> -
> -  len = *grouping++;
> -
> -  /* Copy existing string so that nothing gets overwritten.  */
> -  memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T));
> -  CHAR_T *s = front_ptr + (rear_ptr - w);
> -
> -  w = rear_ptr;
> -
> -  /* Process all characters in the string.  */
> -  while (s > front_ptr)
> -    {
> -      *--w = *--s;
> -
> -      if (--len == 0 && s > front_ptr)
> -	{
> -	  /* A new group begins.  */
> -#ifdef COMPILE_WPRINTF
> -	  if (w != s)
> -	    *--w = thousands_sep;
> -	  else
> -	    /* Not enough room for the separator.  */
> -	    goto copy_rest;
> -#else
> -	  int cnt = tlen;
> -	  if (tlen < w - s)
> -	    do
> -	      *--w = thousands_sep[--cnt];
> -	    while (cnt > 0);
> -	  else
> -	    /* Not enough room for the separator.  */
> -	    goto copy_rest;
> -#endif
> -
> -	  if (*grouping == CHAR_MAX
> -#if CHAR_MIN < 0
> -		   || *grouping < 0
> -#endif
> -		   )
> -	    {
> -	    copy_rest:
> -	      /* No further grouping to be done.  Copy the rest of the
> -		 number.  */
> -	      memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
> -	      break;
> -	    }
> -	  else if (*grouping != '\0')
> -	    len = *grouping++;
> -	  else
> -	    /* The previous grouping repeats ad infinitum.  */
> -	    len = grouping[-1];
> -	}
> -    }
> -  return w;
> -}
> -\f
> -/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
> -struct helper_file
> -  {
> -    struct _IO_FILE_plus _f;
> -#ifdef COMPILE_WPRINTF
> -    struct _IO_wide_data _wide_data;
> -#endif
> -    FILE *_put_stream;
> -#ifdef _IO_MTSAFE_IO
> -    _IO_lock_t lock;
> -#endif
> -  };
> -
> -static int
> -_IO_helper_overflow (FILE *s, int c)
> -{
> -  FILE *target = ((struct helper_file*) s)->_put_stream;
> -#ifdef COMPILE_WPRINTF
> -  int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
> -  if (used)
> -    {
> -      size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
> -      if (written == 0 || written == WEOF)
> -	return WEOF;
> -      __wmemmove (s->_wide_data->_IO_write_base,
> -		  s->_wide_data->_IO_write_base + written,
> -		  used - written);
> -      s->_wide_data->_IO_write_ptr -= written;
> -    }
> -#else
> -  int used = s->_IO_write_ptr - s->_IO_write_base;
> -  if (used)
> -    {
> -      size_t written = _IO_sputn (target, s->_IO_write_base, used);
> -      if (written == 0 || written == EOF)
> -	return EOF;
> -      memmove (s->_IO_write_base, s->_IO_write_base + written,
> -	       used - written);
> -      s->_IO_write_ptr -= written;
> -    }
> -#endif
> -  return PUTC (c, s);
> -}
> -
> -#ifdef COMPILE_WPRINTF
> -static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
> -{
> -  JUMP_INIT_DUMMY,
> -  JUMP_INIT (finish, _IO_wdefault_finish),
> -  JUMP_INIT (overflow, _IO_helper_overflow),
> -  JUMP_INIT (underflow, _IO_default_underflow),
> -  JUMP_INIT (uflow, _IO_default_uflow),
> -  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
> -  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
> -  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
> -  JUMP_INIT (seekoff, _IO_default_seekoff),
> -  JUMP_INIT (seekpos, _IO_default_seekpos),
> -  JUMP_INIT (setbuf, _IO_default_setbuf),
> -  JUMP_INIT (sync, _IO_default_sync),
> -  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
> -  JUMP_INIT (read, _IO_default_read),
> -  JUMP_INIT (write, _IO_default_write),
> -  JUMP_INIT (seek, _IO_default_seek),
> -  JUMP_INIT (close, _IO_default_close),
> -  JUMP_INIT (stat, _IO_default_stat)
> -};
> -#else
> -static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
> -{
> -  JUMP_INIT_DUMMY,
> -  JUMP_INIT (finish, _IO_default_finish),
> -  JUMP_INIT (overflow, _IO_helper_overflow),
> -  JUMP_INIT (underflow, _IO_default_underflow),
> -  JUMP_INIT (uflow, _IO_default_uflow),
> -  JUMP_INIT (pbackfail, _IO_default_pbackfail),
> -  JUMP_INIT (xsputn, _IO_default_xsputn),
> -  JUMP_INIT (xsgetn, _IO_default_xsgetn),
> -  JUMP_INIT (seekoff, _IO_default_seekoff),
> -  JUMP_INIT (seekpos, _IO_default_seekpos),
> -  JUMP_INIT (setbuf, _IO_default_setbuf),
> -  JUMP_INIT (sync, _IO_default_sync),
> -  JUMP_INIT (doallocate, _IO_default_doallocate),
> -  JUMP_INIT (read, _IO_default_read),
> -  JUMP_INIT (write, _IO_default_write),
> -  JUMP_INIT (seek, _IO_default_seek),
> -  JUMP_INIT (close, _IO_default_close),
> -  JUMP_INIT (stat, _IO_default_stat)
> -};
> -#endif
> -
> -static int
> -buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
> -{
> -  CHAR_T buf[BUFSIZ];
> -  struct helper_file helper;
> -  FILE *hp = (FILE *) &helper._f;
> -  int result, to_flush;
> -
> -  /* Orient the stream.  */
> -#ifdef ORIENT
> -  ORIENT;
> -#endif
> -
> -  /* Initialize helper.  */
> -  helper._put_stream = s;
> -#ifdef COMPILE_WPRINTF
> -  hp->_wide_data = &helper._wide_data;
> -  _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
> -  hp->_mode = 1;
> -#else
> -  _IO_setp (hp, buf, buf + sizeof buf);
> -  hp->_mode = -1;
> -#endif
> -  hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
> -#if _IO_JUMPS_OFFSET
> -  hp->_vtable_offset = 0;
> -#endif
> -#ifdef _IO_MTSAFE_IO
> -  hp->_lock = NULL;
> -#endif
> -  hp->_flags2 = s->_flags2;
> -  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
> -
> -  /* Now print to helper instead.  */
> -#ifndef COMPILE_WPRINTF
> -  result = _IO_vfprintf (hp, format, args);
> -#else
> -  result = vfprintf (hp, format, args);
> -#endif
> -
> -  /* Lock stream.  */
> -  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
> -  _IO_flockfile (s);
> -
> -  /* Now flush anything from the helper to the S. */
> -#ifdef COMPILE_WPRINTF
> -  if ((to_flush = (hp->_wide_data->_IO_write_ptr
> -		   - hp->_wide_data->_IO_write_base)) > 0)
> -    {
> -      if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
> -	  != to_flush)
> -	result = -1;
> -    }
> -#else
> -  if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
> -    {
> -      if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
> -	result = -1;
> -    }
> -#endif
> -
> -  /* Unlock the stream.  */
> -  _IO_funlockfile (s);
> -  __libc_cleanup_region_end (0);
> -
> -  return result;
> -}
> -
> -#undef vfprintf
> -#ifdef COMPILE_WPRINTF
> -strong_alias (_IO_vfwprintf, __vfwprintf);
> -ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
> -#else
> -ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
> -ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
> -#endif
> +ldbl_strong_alias (__vfprintf, _IO_vfprintf);
> +ldbl_strong_alias (__vfprintf, vfprintf);
> +ldbl_hidden_def (__vfprintf, vfprintf)

Ok.

> diff --git a/stdio-common/vfwprintf-internal.c b/stdio-common/vfwprintf-internal.c
> new file mode 100644
> index 0000000000..cefaf2fafe
> --- /dev/null
> +++ b/stdio-common/vfwprintf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WPRINTF	1
> +#include "vfprintf-internal.c"

Ok.

> diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
> index 2c3cd06fad..5d65eb7697 100644
> --- a/stdio-common/vfwprintf.c
> +++ b/stdio-common/vfwprintf.c
> @@ -1,3 +1,25 @@
> -#include <wctype.h>
> -#define COMPILE_WPRINTF	1
> -#include "vfprintf.c"
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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 the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <libio/libioP.h>
> +
> +extern int
> +__vfwprintf (FILE *fp, const wchar_t *format, va_list ap)
> +{
> +  return __vfwprintf_internal (fp, format, ap, 0);
> +}
> +ldbl_weak_alias (__vfwprintf, vfwprintf);

Ok.

> diff --git a/stdio-common/vprintf.c b/stdio-common/vprintf.c
> index d459642dc8..0da8ba761e 100644
> --- a/stdio-common/vprintf.c
> +++ b/stdio-common/vprintf.c
> @@ -25,9 +25,9 @@
>  /* Write formatted output to stdout according to the
>     format string FORMAT, using the argument list in ARG.  */
>  int
> -__vprintf (const char *format, __gnuc_va_list arg)
> +__vprintf (const char *format, va_list ap)
>  {
> -  return vfprintf (stdout, format, arg);
> +  return __vfprintf_internal (stdout, format, ap, 0);
>  }
>  
>  ldbl_strong_alias (__vprintf, vprintf)

Ok.

> diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
> index 2840512cae..5b33604427 100644
> --- a/stdlib/strfrom-skeleton.c
> +++ b/stdlib/strfrom-skeleton.c
> @@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
>      }
>  
>    /* The following code to prepare the virtual file has been adapted from the
> -     function _IO_vsnprintf from libio.  */
> +     function __vsnprintf_internal from libio.  */
>  
>    if (size == 0)
>      {

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 468e23dec4..bda84af0bb 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -166,7 +166,7 @@ __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
>  {
>    int done;
>    set_no_long_double ();
> -  done = _IO_vfprintf (s, fmt, ap);
> +  done = __vfprintf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return done;
>  }
> @@ -175,15 +175,16 @@ strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
>  
>  int
>  attribute_compat_text_section
> -__nldbl__IO_vsprintf (char *string, const char *fmt, va_list ap)
> +__nldbl___vsprintf (char *string, const char *fmt, va_list ap)
>  {
>    int done;
>    __no_long_double = 1;
> -  done = _IO_vsprintf (string, fmt, ap);
> +  done = __vsprintf_internal (string, fmt, ap, 0);
>    __no_long_double = 0;
>    return done;
>  }
> -weak_alias (__nldbl__IO_vsprintf, __nldbl_vsprintf)
> +strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
> +weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
>  libc_hidden_def (__nldbl_vsprintf)
>  
>  int
> @@ -193,7 +194,7 @@ __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
>  {
>    int done;
>    __no_long_double = 1;
> -  done = _IO_obstack_vprintf (obstack, fmt, ap);
> +  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
>    __no_long_double = 0;
>    return done;
>  }
> @@ -245,7 +246,7 @@ __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vasprintf (result_ptr, fmt, ap);
> +  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -257,7 +258,7 @@ __nldbl_vdprintf (int d, const char *fmt, va_list arg)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vdprintf (d, fmt, arg);
> +  res = __vdprintf_internal (d, fmt, arg, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -269,7 +270,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfwprintf (s, fmt, ap);
> +  res = __vfwprintf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -289,7 +290,7 @@ __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vsnprintf (string, maxlen, fmt, ap);
> +  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -303,7 +304,7 @@ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vswprintf (string, maxlen, fmt, ap);
> +  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> 

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 4/7] Add __v*printf_internal with flags arguments
  2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
  2018-11-22 17:46   ` Adhemerval Zanella
@ 2018-11-22 17:55   ` Adhemerval Zanella
  2018-11-22 17:59     ` Adhemerval Zanella
  1 sibling, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:55 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2:
> 
>   - Expanded the comments about PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
>   - Removed the parameter-less macros LDBL_IS_DBL and DO_FORTIFY.
>     Explicitly compare the flags.

LGTM, thanks.

> 
> Changes since v1:
> 
>   - Fixed white-space errors.
>   - In argp_fmtstream_printf, do not call __vsnprintf, instead call
>     __vsnprintf_internal passing 0 to mode_flags.  With this change,
>     there's no need to use libc_hidden_{proto,def} for __vsnprintf
>     (because it doesn't have other internal callers).  Also, it is no
>     longer necessary to '#undef __vsnprintf' and '#define __vsnprintf
>     vsnprintf' in argp-namefrob.h.
>   - In __argp_error and __argp_failure call __vasprintf_internal
>     directly, passing 0 (zero) to mode_flags, since these functions do
>     not currently have support for long double with the same format as
>     double (a subsequent patch in my personal branch provides that and
>     adjusts the call accordingly).
>     With this change, there's no need to use libc_hidden_{proto,def} for
>     __vasprintf.  It is also no longer required to '#undef __vasprintf'
>     and '#define __vasprintf vasprintf' in argp-namefrob.h.
>   - Declarations of _IO_vfprintf, _IO_vsprintf, __vfwprintf, and
>     __vswprintf removed from the internal headers: libio.h, iolibio.h,
>     and include/wchar.h, since they are no longer called from within
>     glibc.
>   - Added attribute_hidden to all new internal functions, since they are
>     all called from within libc.
>     Here are the objdumps of one such calls, before and after this
>     change, on a 32-bits powerpc machine:
>     Without attribute_hidden:
>       $ objdump -d --reloc INTERNAL-VISIBLE-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 21
>       000523a0 <vprintf@@GLIBC_2.4>:
>          523a0:       94 21 ff f0     stwu    r1,-16(r1)
>          523a4:       7c 85 23 78     mr      r5,r4
>          523a8:       7c 08 02 a6     mflr    r0
>          523ac:       42 9f 00 05     bcl     20,4*cr7+so,523b0 <vprintf@@GLIBC_2.4+0x10>
>          523b0:       7c 64 1b 78     mr      r4,r3
>          523b4:       38 c0 00 00     li      r6,0
>          523b8:       93 c1 00 08     stw     r30,8(r1)
>          523bc:       90 01 00 14     stw     r0,20(r1)
>          523c0:       7f c8 02 a6     mflr    r30
>          523c4:       3f de 00 15     addis   r30,r30,21
>          523c8:       3b de dc 44     addi    r30,r30,-9148
>          523cc:       81 3e fe 80     lwz     r9,-384(r30)
>          523d0:       80 69 00 00     lwz     r3,0(r9)
>          523d4:       48 01 52 bd     bl      67690 <__vfprintf_internal>
>          523d8:       80 01 00 14     lwz     r0,20(r1)
>          523dc:       83 c1 00 08     lwz     r30,8(r1)
>          523e0:       38 21 00 10     addi    r1,r1,16
>          523e4:       7c 08 03 a6     mtlr    r0
>          523e8:       4e 80 00 20     blr
>     With attribute_hidden:
>       $ objdump -d --reloc INTERNAL-HIDDEN-glibc/libc.so | grep "<vprintf@@GLIBC_2.4>:" -A 18
>       00052370 <vprintf@@GLIBC_2.4>:
>          52370:       94 21 ff f0     stwu    r1,-16(r1)
>          52374:       7c 85 23 78     mr      r5,r4
>          52378:       7d 88 02 a6     mflr    r12
>          5237c:       42 9f 00 05     bcl     20,4*cr7+so,52380 <vprintf@@GLIBC_2.4+0x10>
>          52380:       7c 64 1b 78     mr      r4,r3
>          52384:       38 c0 00 00     li      r6,0
>          52388:       93 c1 00 08     stw     r30,8(r1)
>          5238c:       7f c8 02 a6     mflr    r30
>          52390:       7d 88 03 a6     mtlr    r12
>          52394:       3f de 00 15     addis   r30,r30,21
>          52398:       3b de dc 74     addi    r30,r30,-9100
>          5239c:       81 3e fe 80     lwz     r9,-384(r30)
>          523a0:       83 c1 00 08     lwz     r30,8(r1)
>          523a4:       80 69 00 00     lwz     r3,0(r9)
>          523a8:       38 21 00 10     addi    r1,r1,16
>          523ac:       48 01 52 24     b       675d0 <__vfprintf_internal>
>     The branch-and-link instruction is gone.
> 
> Additional note for review:
> 
>   - Reviewing the changes from vfprintf.c to vfprintf-internal.c in the
>     original patch would be vey hard, because git doesn't detect the
>     filename change.  To make review a little easier, I did as Zack did
>     and manually edited the diff.  I'll reply to this thread and attach
>     the original patch if someone wants to apply it.
>     (ping me if I forget it)
> 
> -- 8< --
> There are a lot more printf variants than there are scanf variants,
> and the code for setting up and tearing down their custom FILE
> variants around the call to __vf(w)printf is more complicated and
> variable.  Therefore, I have added _internal versions of all the
> v*printf variants, rather than introducing helper routines so that
> they can all directly call __vf(w)printf_internal, as was done with
> scanf.
> 
> As with the scanf changes, in this patch the _internal functions still
> look at the environmental mode bits and all callers pass 0 for the
> flags parameter.
> 
> Several of the affected public functions had _IO_ name aliases that
> were not exported (but, in one case, appeared in libio.h anyway);
> I was originally planning to leave them as aliases to avoid having
> to touch internal callers, but it turns out ldbl_*_alias only work
> for exported symbols, so they've all been removed instead.  It also
> turns out there were hardly any internal callers.  _IO_vsprintf and
> _IO_vfprintf *are* exported, so those two stick around.
> 
> Summary for the changes to each of the affected symbols:
> 
>   _IO_vfprintf, _IO_vsprintf:
>     All internal calls removed, thus the internal declarations, as well
>     as uses of libc_hidden_proto and libc_hidden_def, were also removed.
>     The external symbol is now exposed via uses of ldbl_strong_alias
>     to __vfprintf_internal and __vsprintf_internal, respectively.
> 
>   _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf,
>   _IO_vfwprintf, _IO_vswprintf,
>   _IO_obstack_vprintf, _IO_obstack_printf:
>     All internal calls removed, thus declaration in internal headers
>     were also removed.  They were never exported, so there are no
>     aliases tying them to the internal functions.  I.e.: entirely gone.
> 
>   __vsnprintf:
>     Internal calls were always preceded by macros such as
>       #define __vsnprintf _IO_vsnprintf, and
>       #define __vsnprintf vsnprintf
>     The macros were removed and their uses replaced with calls to the
>     new internal function __vsnprintf_internal.  Since there were no
>     internal calls, the internal declaration was also removed.  The
>     external symbol is preserved with ldbl_weak_alias to ___vsnprintf.
> 
>   __vfwprintf:
>     All internal calls converted into calls to __vfwprintf_internal,
>     thus the internal declaration was removed.  The function is now a
>     wrapper that calls __vfwprintf_internal.  The external symbol is
>     preserved.
> 
>   __vswprintf:
>     Similarly, but no external symbol.
> 
>   __vasprintf, __vdprintf, __vfprintf, __vsprintf:
>     New internal wrappers.  Not exported.
> 
>   vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf,
>   vfwprintf, vswprintf,
>   obstack_vprintf, obstack_printf:
>     These functions used to be aliases to the respective _IO_* function,
>     they are now aliases to their respective __* functions.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* libio/libioP.h (__vfprintf_internal, __vfwprintf_internal)
> 	(__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal)
> 	(__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal):
> 	New functions.
> 	(PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants.
> 	(_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes.
> 
> 	* stdio-common/vfprintf-internal.c: Rename from vfprintf.c.
> 	Include wctype.h here if COMPILE_WPRINTF is defined.
> 	Define __vfprintf_internal or __vfwprintf_internal, depending
> 	on COMPILE_WPRINTF.
> 	Temporarily, on entry to this function, update mode_flags
> 	according to the environmental settings corresponding to
> 	PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
> 	Throughout, check mode_flags instead of __ldbl_is_dbl and
> 	_IO_FLAGS2_FORTIFY on the destination FILE.
> 	* stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c.
> 	Include vfprintf-internal.c.  Don't include wctype.h.
> 	* stdio-common/vfprintf.c: New file.  Just define __vfprintf
> 	as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf
> 	and vfprintf.
> 	* stdio-common/vfwprintf.c: New file.  Just define __vfwprintf
> 	as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf
> 	and vfwprintf.
> 	* stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal.
> 
> 	* libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal
> 	and add mode_flags argument; use __vfprintf_internal.
> 	(__vdprintf): New function.  Alias vdprintf to this.
> 	* libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly.
> 	* libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly.
> 	* libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly.
> 	(__obstack_printf): Use __obstack_printf_internal.
> 	* libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with
> 	public aliases __vsnprintf and vsnprintf.
> 	Remove use of ldbl_hidden_def, since __vsnprintf is no longer
> 	called internally.
> 	* libio/vswprintf (_IO_vswprintf, __vswprintf): Similarly, with
> 	public aliases _IO_vsprintf and vsprintf.
> 	* libio/swprintf.c (__swprintf): Use __vswprintf_internal.
> 	* stdio-common/asprintf.c (__asprintf): Use __vasprintf_internal.
> 	* stdio-common/dprintf.c (__dprintf): Use __vdprintf_internal.
> 	* stdio-common/snprintf.c (__snprintf): Use __vsprintf_internal.
> 	* stdio-common/sprintf.c (__sprintf): Use __vsprintf_internal.
> 
> 	* debug/obprintf_chk.c, debug/vasprintf_chk.c, debug/vdprintf_chk.c
> 	* debug/vsnprintf_chk.c, debug/vsprintf_chk.c, hurd/vpprintf.c
> 	* stdio-common/fprintf.c, stdio-common/fxprintf.c
> 	* stdio-common/printf.c: Use __vfprintf_internal.
> 
> 	* debug/fwprintf_chk.c, debug/vfwprintf_chk.c, debug/vswprintf_chk.c
> 	* debug/vwprintf_chk.c, debug/wprintf_chk.c, libio/fwprintf.c
> 	* libio/vwprintf.c, libio/wprintf.c: Use __vfwprintf_internal.
> 
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Use __vsprintf_internal,
> 	__obstack_vprintf_internal, __vasprintf_internal, __vdprintf_internal,
> 	__vsnprintf_internal, __vswprintf_internal, __vfprintf_internal, and
> 	__vfwprintf_internal.
> 
> 	* libio/libio.h: Remove libc_hidden_proto and declaration for
> 	_IO_vfprintf.
> 	Remove declaration of _IO_vfwprintf.
> 	* libio/iolibio.h: Remove libc_hidden_proto and declaration for
> 	_IO_vsprintf.
> 	Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
> 	_IO_obstack_printf.
> 	* include/stdio.h: Add prototype for __vasprintf.
> 	(__vsnprintf): Remove declaration, because there are no more
> 	internal calls.
> 	* include/wchar.h (__vfwprintf, __vswprintf): Remove
> 	declaration, because there are no more internal calls.
> 
> 	* argp/argp-fmtstream.c (__argp_fmtstream_printf): Use
> 	__vsnprintf_internal, instead of _IO_vsnprintf.
> 	* argp/argp-help.c (__argp_error, __argp_failure): Use
> 	__vasprintf_internal, instead of _IO_vasprintf.
> 	* argp/argp-namefrob.h (__vsnprintf): Do not undefined then
> 	redefine, because there are no more internal calls.
> ---
>  argp/argp-fmtstream.c                            |    3 +-
>  argp/argp-help.c                                 |    4 +-
>  argp/argp-namefrob.h                             |    2 -
>  debug/fwprintf_chk.c                             |    2 +-
>  debug/obprintf_chk.c                             |    2 +-
>  debug/vasprintf_chk.c                            |    2 +-
>  debug/vdprintf_chk.c                             |    2 +-
>  debug/vfwprintf_chk.c                            |    2 +-
>  debug/vsnprintf_chk.c                            |    2 +-
>  debug/vsprintf_chk.c                             |    2 +-
>  debug/vswprintf_chk.c                            |    2 +-
>  debug/vwprintf_chk.c                             |    2 +-
>  debug/wprintf_chk.c                              |    2 +-
>  hurd/vpprintf.c                                  |    2 +-
>  include/stdio.h                                  |    3 -
>  include/wchar.h                                  |   10 -
>  libio/fwprintf.c                                 |    2 +-
>  libio/iolibio.h                                  |    8 -
>  libio/iovdprintf.c                               |   13 +-
>  libio/iovsprintf.c                               |   16 +-
>  libio/libio.h                                    |    5 -
>  libio/libioP.h                                   |   47 +-
>  libio/obprintf.c                                 |   19 +-
>  libio/swprintf.c                                 |    2 +-
>  libio/vasprintf.c                                |   20 +-
>  libio/vsnprintf.c                                |   16 +-
>  libio/vswprintf.c                                |   16 +-
>  libio/vwprintf.c                                 |    2 +-
>  libio/wprintf.c                                  |    2 +-
>  stdio-common/Makefile                            |    3 +-
>  stdio-common/asprintf.c                          |    6 +-
>  stdio-common/dprintf.c                           |    5 +-
>  stdio-common/fprintf.c                           |    2 +-
>  stdio-common/fxprintf.c                          |    4 +-
>  stdio-common/printf.c                            |    3 +-
>  stdio-common/snprintf.c                          |    4 +-
>  stdio-common/sprintf.c                           |    4 +-
>  stdio-common/{vfprintf.c => vfprintf-internal.c} |   66 +-
>  stdio-common/vfprintf.c                          | 2351 +---------------------
>  stdio-common/vfwprintf-internal.c                |    2 +
>  stdio-common/vfwprintf.c                         |   28 +-
>  stdio-common/vprintf.c                           |    4 +-
>  stdlib/strfrom-skeleton.c                        |    2 +-
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c          |   21 +-
>  44 files changed, 219 insertions(+), 2498 deletions(-)
>  copy stdio-common/{vfprintf.c => vfprintf-internal.c} (98%)
>  create mode 100644 stdio-common/vfwprintf-internal.c
> 
> diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
> index e43a0c7cf1..b9dcb2c9c7 100644
> --- a/argp/argp-fmtstream.c
> +++ b/argp/argp-fmtstream.c
> @@ -42,7 +42,6 @@
>  #ifdef _LIBC
>  # include <wchar.h>
>  # include <libio/libioP.h>
> -# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
>  #endif
>  
>  #define INIT_BUF_SIZE 200
> @@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
>  
>        va_start (args, fmt);
>        avail = fs->end - fs->p;
> -      out = __vsnprintf (fs->p, avail, fmt, args);
> +      out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
>        va_end (args);
>        if ((size_t) out >= avail)
>  	size_guess = out + 1;

Ok.

> diff --git a/argp/argp-help.c b/argp/argp-help.c
> index 2b6b0775d6..6857391ce2 100644
> --- a/argp/argp-help.c
> +++ b/argp/argp-help.c
> @@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
>  #ifdef _LIBC
>  	  char *buf;
>  
> -	  if (_IO_vasprintf (&buf, fmt, ap) < 0)
> +	  if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
>  	    buf = NULL;
>  
>  	  __fxprintf (stream, "%s: %s\n",
> @@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
>  #ifdef _LIBC
>  	      char *buf;
>  
> -	      if (_IO_vasprintf (&buf, fmt, ap) < 0)
> +	      if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
>  		buf = NULL;
>  
>  	      __fxprintf (stream, ": %s", buf);

Ok.

> diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
> index 5588fe172a..5e48b5940d 100644
> --- a/argp/argp-namefrob.h
> +++ b/argp/argp-namefrob.h
> @@ -98,8 +98,6 @@
>  #define __strerror_r strerror_r
>  #undef __strndup
>  #define __strndup strndup
> -#undef __vsnprintf
> -#define __vsnprintf vsnprintf
>  
>  #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
>  # define clearerr_unlocked(x) clearerr (x)

Ok.

> diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
> index aeb83077da..63167c1839 100644
> --- a/debug/fwprintf_chk.c
> +++ b/debug/fwprintf_chk.c
> @@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
>      fp->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    va_start (ap, format);
> -  done = _IO_vfwprintf (fp, format, ap);
> +  done = __vfwprintf_internal (fp, format, ap, 0);
>    va_end (ap);
>  
>    if (flag > 0)

Ok.

> diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
> index 3ac5a3cd4f..41dd481c34 100644
> --- a/debug/obprintf_chk.c
> +++ b/debug/obprintf_chk.c
> @@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
>    if (flags > 0)
>      new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
> +  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
>  
>    /* Shrink the buffer to the space we really currently need.  */
>    obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr

Ok.

> diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
> index 48b4741651..dbfebff83f 100644
> --- a/debug/vasprintf_chk.c
> +++ b/debug/vasprintf_chk.c
> @@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
>    if (flags > 0)
>      sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
>    if (ret < 0)
>      {
>        free (sf._sbf._f._IO_buf_base);

Ok.

> diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
> index bc713b4962..4386127cfe 100644
> --- a/debug/vdprintf_chk.c
> +++ b/debug/vdprintf_chk.c
> @@ -55,7 +55,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg)
>    if (flags > 0)
>      tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfprintf (&tmpfil.file, format, arg);
> +  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
>  
>    _IO_FINISH (&tmpfil.file);
>  

Ok.

> diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
> index 1ffd18cbd2..abf2bd6517 100644
> --- a/debug/vfwprintf_chk.c
> +++ b/debug/vfwprintf_chk.c
> @@ -30,7 +30,7 @@ __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
>    if (flag > 0)
>      fp->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfwprintf (fp, format, ap);
> +  done = __vfwprintf_internal (fp, format, ap, 0);
>  
>    if (flag > 0)
>      fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;

Ok.

> diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
> index d20d0fbd93..95d286f416 100644
> --- a/debug/vsnprintf_chk.c
> +++ b/debug/vsnprintf_chk.c
> @@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
>      sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
> -  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
>  
>    if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
>      *sf.f._sbf._f._IO_write_ptr = '\0';

Ok.

> diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
> index 9a443bb699..53f07236ae 100644
> --- a/debug/vsprintf_chk.c
> +++ b/debug/vsprintf_chk.c
> @@ -80,7 +80,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
>    if (flags > 0)
>      f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  ret = _IO_vfprintf (&f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
>  
>    *f._sbf._f._IO_write_ptr = '\0';
>    return ret;

Ok.

> diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
> index c6a7edcacd..4d616f8835 100644
> --- a/debug/vswprintf_chk.c
> +++ b/debug/vswprintf_chk.c
> @@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
>      sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
> -  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
> +  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
>  
>    if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
>      /* ISO C99 requires swprintf/vswprintf to return an error if the

Ok.

> diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
> index 51b67c159d..fedc7a46bf 100644
> --- a/debug/vwprintf_chk.c
> +++ b/debug/vwprintf_chk.c
> @@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
>    if (flag > 0)
>      stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
> -  done = _IO_vfwprintf (stdout, format, ap);
> +  done = __vfwprintf_internal (stdout, format, ap, 0);
>  
>    if (flag > 0)
>      stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;

Ok.

> diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
> index 17023b6bb4..819050e5af 100644
> --- a/debug/wprintf_chk.c
> +++ b/debug/wprintf_chk.c
> @@ -33,7 +33,7 @@ __wprintf_chk (int flag, const wchar_t *format, ...)
>      stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
>  
>    va_start (ap, format);
> -  done = _IO_vfwprintf (stdout, format, ap);
> +  done = __vfwprintf_internal (stdout, format, ap, 0);
>    va_end (ap);
>  
>    if (flag > 0)

Ok.

> diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c
> index 76cd31f922..b9634afc2b 100644
> --- a/hurd/vpprintf.c
> +++ b/hurd/vpprintf.c
> @@ -53,7 +53,7 @@ vpprintf (io_t port, const char *format, va_list arg)
>    _IO_cookie_init (&temp_f.cfile, _IO_NO_READS,
>  		   (void *) port, (cookie_io_functions_t) { write: do_write });
>  
> -  done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
> +  done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0);
>  
>    return done;
>  }

Ok.

> diff --git a/include/stdio.h b/include/stdio.h
> index 51ada4a4c4..0856d729d9 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen,
>  		       const char *__restrict __format, ...)
>       __attribute__ ((__format__ (__printf__, 3, 4)));
>  libc_hidden_proto (__snprintf)
> -extern int __vsnprintf (char *__restrict __s, size_t __maxlen,
> -			const char *__restrict __format, __gnuc_va_list __arg)
> -     __attribute__ ((__format__ (__printf__, 3, 0)));
>  extern int __vfscanf (FILE *__restrict __s,
>  		      const char *__restrict __format,
>  		      __gnuc_va_list __arg)

Ok.

> diff --git a/include/wchar.h b/include/wchar.h
> index 1db0ac8278..d0fe45c3a6 100644
> --- a/include/wchar.h
> +++ b/include/wchar.h
> @@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s,
>  		       __gnuc_va_list __arg)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */;
> -extern int __vswprintf (wchar_t *__restrict __s, size_t __n,
> -			const wchar_t *__restrict __format,
> -			__gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
>  extern int __fwprintf (__FILE *__restrict __s,
>  		       const wchar_t *__restrict __format, ...)
>       attribute_hidden
>       /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
> -extern int __vfwprintf (__FILE *__restrict __s,
> -			const wchar_t *__restrict __format,
> -			__gnuc_va_list __arg)
> -     attribute_hidden
> -     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
>  extern int __vfwprintf_chk (FILE *__restrict __s, int __flag,
>  			    const wchar_t *__restrict __format,
>  			    __gnuc_va_list __arg)

Ok.

> diff --git a/libio/fwprintf.c b/libio/fwprintf.c
> index fab63a8716..9903f1f342 100644
> --- a/libio/fwprintf.c
> +++ b/libio/fwprintf.c
> @@ -30,7 +30,7 @@ __fwprintf (FILE *stream, const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vfwprintf (stream, format, arg);
> +  done = __vfwprintf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/iolibio.h b/libio/iolibio.h
> index 6c94fe6d62..2642d71e4f 100644
> --- a/libio/iolibio.h
> +++ b/libio/iolibio.h
> @@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
>  extern int _IO_sprintf (char *, const char*, ...) __THROW;
>  extern int _IO_ungetc (int, FILE*) __THROW;
>  extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW;
> -extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW;
> -libc_hidden_proto (_IO_vsprintf)
> -extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list)
> -       __THROW;
>  
> -struct obstack;
> -extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list)
> -       __THROW;
> -extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW;
>  #define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN))
>  #define _IO_fseek(__fp, __offset, __whence) \
>    (_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \

Ok.

> diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
> index 78a3a2bd15..1d2ed0f9e7 100644
> --- a/libio/iovdprintf.c
> +++ b/libio/iovdprintf.c
> @@ -28,7 +28,8 @@
>  #include <stdio_ext.h>
>  
>  int
> -_IO_vdprintf (int d, const char *format, va_list arg)
> +__vdprintf_internal (int d, const char *format, va_list arg,
> +		     unsigned int mode_flags)
>  {
>    struct _IO_FILE_plus tmpfil;
>    struct _IO_wide_data wd;
> @@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg)
>    _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
>  		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
>  
> -  done = _IO_vfprintf (&tmpfil.file, format, arg);
> +  done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags);
>  
>    if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
>      done = EOF;
> @@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg)
>  
>    return done;
>  }
> -ldbl_weak_alias (_IO_vdprintf, vdprintf)
> +
> +int
> +__vdprintf (int d, const char *format, va_list arg)
> +{
> +  return __vdprintf_internal (d, format, arg, 0);
> +}
> +ldbl_weak_alias (__vdprintf, vdprintf)

Ok.

> diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
> index 4def251701..3b1e8292b5 100644
> --- a/libio/iovsprintf.c
> +++ b/libio/iovsprintf.c
> @@ -28,7 +28,8 @@
>  #include "strfile.h"
>  
>  int
> -__IO_vsprintf (char *string, const char *format, va_list args)
> +__vsprintf_internal (char *string, const char *format, va_list args,
> +		     unsigned int mode_flags)
>  {
>    _IO_strfile sf;
>    int ret;
> @@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args)
>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>    _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>    _IO_str_init_static_internal (&sf, string, -1, string);
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
>    _IO_putc_unlocked ('\0', &sf._sbf._f);
>    return ret;
>  }
> -ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)
>  
> -ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
> -ldbl_weak_alias (__IO_vsprintf, vsprintf)
> +int
> +__vsprintf (char *string, const char *format, va_list args)
> +{
> +  return __vsprintf_internal (string, format, args, 0);
> +}
> +
> +ldbl_strong_alias (__vsprintf, _IO_vsprintf)
> +ldbl_weak_alias (__vsprintf, vsprintf)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index 30cb7d784f..c188814ccc 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;
>  
>  extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
>  			__gnuc_va_list, int *__restrict);
> -extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
> -			 __gnuc_va_list);
>  extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
>  extern size_t _IO_sgetn (FILE *, void *, size_t);
>  
> @@ -298,8 +296,6 @@ weak_extern (_IO_stdin_used);
>  
>  extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
>  			 __gnuc_va_list, int *__restrict);
> -extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
> -			  __gnuc_va_list);
>  extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t);
>  extern void _IO_free_wbackup_area (FILE *) __THROW;
>  
> @@ -319,7 +315,6 @@ libc_hidden_proto (_IO_free_wbackup_area)
>  libc_hidden_proto (_IO_padn)
>  libc_hidden_proto (_IO_putc)
>  libc_hidden_proto (_IO_sgetn)
> -libc_hidden_proto (_IO_vfprintf)
>  
>  #ifdef _IO_MTSAFE_IO
>  # undef _IO_peekc

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index 9e971cb96b..fe52ef1752 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -658,12 +658,49 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
>  extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
>  extern void _IO_wstr_finish (FILE *, int) __THROW;
>  
> -extern int _IO_vasprintf (char **result_ptr, const char *format,
> -			  va_list args) __THROW;
> -extern int _IO_vdprintf (int d, const char *format, va_list arg);
> -extern int _IO_vsnprintf (char *string, size_t maxlen,
> -			  const char *format, va_list args) __THROW;
> +/* Internal versions of v*printf that take an additional flags
> +   parameter.  */
> +extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vasprintf_internal (char **result_ptr, const char *format,
> +				 va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vdprintf_internal (int d, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
> +				       va_list ap, unsigned int mode_flags)
> +    attribute_hidden;
> +
> +extern int __vsprintf_internal (char *string, const char *format, va_list ap,
> +				unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vsnprintf_internal (char *string, size_t maxlen,
> +				 const char *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
> +				 const wchar_t *format, va_list ap,
> +				 unsigned int mode_flags)
> +    attribute_hidden;
> +
> +/* Flags for __v*printf_internal.
> +
> +   PRINTF_LDBL_IS_DBL indicates whether long double values are to be
> +   handled as having the same format as double, in which case the flag
> +   should be set to one, or as another format, otherwise.
>  
> +   PRINTF_FORTIFY, when set to one, indicates that fortification checks
> +   are to be performed in input parameters.  This is used by the
> +   __*printf_chk functions, which are used when _FORTIFY_SOURCE is
> +   defined to 1 or 2.  Otherwise, such checks are ignored.  */
> +#define PRINTF_LDBL_IS_DBL 0x0001
> +#define PRINTF_FORTIFY     0x0002
>  
>  extern size_t _IO_getline (FILE *,char *, size_t, int, int);
>  libc_hidden_proto (_IO_getline)

Ok.

> diff --git a/libio/obprintf.c b/libio/obprintf.c
> index a74f9467a2..10a4b5c10c 100644
> --- a/libio/obprintf.c
> +++ b/libio/obprintf.c
> @@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
> +__obstack_vprintf_internal (struct obstack *obstack, const char *format,
> +			    va_list args, unsigned int mode_flags)
>  {
>    struct obstack_FILE
>      {
> @@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
>  
>    new_f.ofile.obstack = obstack;
>  
> -  result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
> +  result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
> +				mode_flags);
>  
>    /* Shrink the buffer to the space we really currently need.  */
>    obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
> @@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
>  
>    return result;
>  }
> -ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf)
>  
> +int
> +__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap)
> +{
> +  return __obstack_vprintf_internal (obstack, format, ap, 0);
> +}
> +ldbl_weak_alias (__obstack_vprintf, obstack_vprintf)
>  
>  int
> -_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
> +__obstack_printf (struct obstack *obstack, const char *format, ...)
>  {
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -  result = _IO_obstack_vprintf (obstack, format, ap);
> +  result = __obstack_vprintf_internal (obstack, format, ap, 0);
>    va_end (ap);
>    return result;
>  }
> -ldbl_weak_alias (_IO_obstack_printf, obstack_printf)
> +ldbl_weak_alias (__obstack_printf, obstack_printf)

Ok.

> diff --git a/libio/swprintf.c b/libio/swprintf.c
> index 10f722d035..19b3f33198 100644
> --- a/libio/swprintf.c
> +++ b/libio/swprintf.c
> @@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vswprintf (s, n, format, arg);
> +  done = __vswprintf_internal (s, n, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/libio/vasprintf.c b/libio/vasprintf.c
> index 6c35d2b108..fabd84f403 100644
> --- a/libio/vasprintf.c
> +++ b/libio/vasprintf.c
> @@ -24,15 +24,13 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <malloc.h>
>  #include <string.h>
> -#include "libioP.h"
> -#include "stdio.h"
> -#include <stdio_ext.h>
> -#include "strfile.h"
> +#include <stdlib.h>
> +#include <strfile.h>
>  
>  int
> -_IO_vasprintf (char **result_ptr, const char *format, va_list args)
> +__vasprintf_internal (char **result_ptr, const char *format, va_list args,
> +		      unsigned int mode_flags)
>  {
>    /* Initial size of the buffer to be used.  Will be doubled each time an
>       overflow occurs.  */
> @@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
>    sf._sbf._f._flags &= ~_IO_USER_BUF;
>    sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
>    sf._s._free_buffer_unused = (_IO_free_type) free;
> -  ret = _IO_vfprintf (&sf._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
>    if (ret < 0)
>      {
>        free (sf._sbf._f._IO_buf_base);
> @@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
>    (*result_ptr)[needed - 1] = '\0';
>    return ret;
>  }
> -ldbl_weak_alias (_IO_vasprintf, vasprintf)
> +
> +int
> +__vasprintf (char **result_ptr, const char *format, va_list args)
> +{
> +  return __vasprintf_internal (result_ptr, format, args, 0);
> +}
> +ldbl_weak_alias (__vasprintf, vasprintf)

Ok.

> diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
> index 39b5500528..35b267abf8 100644
> --- a/libio/vsnprintf.c
> +++ b/libio/vsnprintf.c
> @@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_vsnprintf (char *string, size_t maxlen, const char *format,
> -	       va_list args)
> +__vsnprintf_internal (char *string, size_t maxlen, const char *format,
> +		      va_list args, unsigned int mode_flags)
>  {
>    _IO_strnfile sf;
>    int ret;
> @@ -111,11 +111,17 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format,
>    _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
>    string[0] = '\0';
>    _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
> -  ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
> +  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);
>  
>    if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
>      *sf.f._sbf._f._IO_write_ptr = '\0';
>    return ret;
>  }
> -ldbl_weak_alias (_IO_vsnprintf, __vsnprintf)
> -ldbl_weak_alias (_IO_vsnprintf, vsnprintf)
> +
> +int
> +___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
> +{
> +  return __vsnprintf_internal (string, maxlen, format, args, 0);
> +}
> +ldbl_weak_alias (___vsnprintf, __vsnprintf)
> +ldbl_weak_alias (___vsnprintf, vsnprintf)

Ok.

> diff --git a/libio/vswprintf.c b/libio/vswprintf.c
> index bcc473d115..e415e39fc9 100644
> --- a/libio/vswprintf.c
> +++ b/libio/vswprintf.c
> @@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
>  
>  
>  int
> -_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
> -	       va_list args)
> +__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
> +		      va_list args, unsigned int mode_flags)
>  {
>    _IO_wstrnfile sf;
>    int ret;
> @@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
>    _IO_fwide (&sf.f._sbf._f, 1);
>    string[0] = L'\0';
>    _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
> -  ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
> +  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);
>  
>    if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
>      /* ISO C99 requires swprintf/vswprintf to return an error if the
> @@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
>  
>    return ret;
>  }
> -weak_alias (_IO_vswprintf, __vswprintf)
> -ldbl_weak_alias (_IO_vswprintf, vswprintf)
> +
> +int
> +__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
> +	     va_list args)
> +{
> +  return __vswprintf_internal (string, maxlen, format, args, 0);
> +}
> +ldbl_weak_alias (__vswprintf, vswprintf)

Ok.

> diff --git a/libio/vwprintf.c b/libio/vwprintf.c
> index 72ebfec92d..e8a529afff 100644
> --- a/libio/vwprintf.c
> +++ b/libio/vwprintf.c
> @@ -25,6 +25,6 @@
>  int
>  __vwprintf (const wchar_t *format, __gnuc_va_list arg)
>  {
> -  return __vfwprintf (stdout, format, arg);
> +  return __vfwprintf_internal (stdout, format, arg, 0);
>  }
>  ldbl_strong_alias (__vwprintf, vwprintf)

Ok.

> diff --git a/libio/wprintf.c b/libio/wprintf.c
> index 5945f651fc..361cd40a1b 100644
> --- a/libio/wprintf.c
> +++ b/libio/wprintf.c
> @@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vfwprintf (stdout, format, arg);
> +  done = __vfwprintf_internal (stdout, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index f3b3ceddbd..84bad1fafe 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -40,7 +40,8 @@ routines	:=							      \
>  	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
>  	isoc99_vsscanf							      \
>  	psiginfo gentempfd						      \
> -	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
> +	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf		      \
> +	vfprintf-internal vfwprintf-internal
>  
>  aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
>  

Ok.

> diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
> index bff858e657..8943ffcae1 100644
> --- a/stdio-common/asprintf.c
> +++ b/stdio-common/asprintf.c
> @@ -16,11 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -
>  #include <libioP.h>
> -#define vasprintf(s, f, a) _IO_vasprintf (s, f, a)
> -#undef __asprintf
>  
>  /* Write formatted output from FORMAT to a string which is
>     allocated with malloc and stored in *STRING_PTR.  */
> @@ -32,7 +28,7 @@ ___asprintf (char **string_ptr, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vasprintf (string_ptr, format, arg);
> +  done = __vasprintf_internal (string_ptr, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
> index 11bd12b838..9adc8ae4c7 100644
> --- a/stdio-common/dprintf.c
> +++ b/stdio-common/dprintf.c
> @@ -16,10 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -
>  #include <libioP.h>
> -#define vdprintf(d, f, a) _IO_vdprintf (d, f, a)
>  
>  /* Write formatted output to D, according to the format string FORMAT.  */
>  /* VARARGS2 */
> @@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vdprintf (d, format, arg);
> +  done = __vdprintf_internal (d, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c
> index 2bbf14bf5d..c8f8ac4faf 100644
> --- a/stdio-common/fprintf.c
> +++ b/stdio-common/fprintf.c
> @@ -29,7 +29,7 @@ __fprintf (FILE *stream, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vfprintf (stream, format, arg);
> +  done = __vfprintf_internal (stream, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
> index 8d02b71f91..a028e8edd5 100644
> --- a/stdio-common/fxprintf.c
> +++ b/stdio-common/fxprintf.c
> @@ -27,7 +27,7 @@ static int
>  locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
>  {
>    if (_IO_fwide (fp, 0) <= 0)
> -    return _IO_vfprintf (fp, fmt, ap);
> +    return __vfprintf_internal (fp, fmt, ap, 0);
>  
>    /* We must convert the narrow format string to a wide one.
>       Each byte can produce at most one wide character.  */
> @@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
>    res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
>  
>    if (res != -1)
> -    res = _IO_vfwprintf (fp, wfmt, ap);
> +    res = __vfwprintf_internal (fp, wfmt, ap, 0);
>  
>    if (used_malloc)
>      free (wfmt);

Ok.

> diff --git a/stdio-common/printf.c b/stdio-common/printf.c
> index 205b5e42df..ea41dd557c 100644
> --- a/stdio-common/printf.c
> +++ b/stdio-common/printf.c
> @@ -30,7 +30,7 @@ __printf (const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vfprintf (stdout, format, arg);
> +  done = __vfprintf_internal (stdout, format, arg, 0);
>    va_end (arg);
>  
>    return done;
> @@ -38,5 +38,4 @@ __printf (const char *format, ...)
>  
>  #undef _IO_printf
>  ldbl_strong_alias (__printf, printf);
> -/* This is for libg++.  */
>  ldbl_strong_alias (__printf, _IO_printf);

Ok.

> diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
> index 29a169b08b..b75e160ea3 100644
> --- a/stdio-common/snprintf.c
> +++ b/stdio-common/snprintf.c
> @@ -16,9 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> -#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
>  
>  /* Write formatted output into S, according to the format
>     string FORMAT, writing no more than MAXLEN characters.  */
> @@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vsnprintf (s, maxlen, format, arg);
> +  done = __vsnprintf_internal (s, maxlen, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
> index bf5671dde9..77423b292f 100644
> --- a/stdio-common/sprintf.c
> +++ b/stdio-common/sprintf.c
> @@ -16,9 +16,7 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
>  #include <libioP.h>
> -#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)
>  
>  /* Write formatted output into S, according to the format string FORMAT.  */
>  /* VARARGS2 */
> @@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = vsprintf (s, format, arg);
> +  done = __vsprintf_internal (s, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf-internal.c
> similarity index 98%
> copy from stdio-common/vfprintf.c
> copy to stdio-common/vfprintf-internal.c
> index ae412e4b84..b0c86e99bd 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf-internal.c
> @@ -41,6 +41,10 @@
>  
>  #include <libioP.h>
>  
> +#ifdef COMPILE_WPRINTF
> +#include <wctype.h>
> +#endif
> +
>  /* In some cases we need extra space for all the output which is not
>     counted in the width of the string. We assume 32 characters is
>     enough.  */
> @@ -78,7 +82,7 @@
>    } while (0)
>  
>  #ifndef COMPILE_WPRINTF
> -# define vfprintf	_IO_vfprintf_internal
> +# define vfprintf	__vfprintf_internal
>  # define CHAR_T		char
>  # define UCHAR_T	unsigned char
>  # define INT_T		int
> @@ -105,7 +109,7 @@ typedef const char *THOUSANDS_SEP_T;
>  # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
>  			  return -1
>  #else
> -# define vfprintf	_IO_vfwprintf
> +# define vfprintf	__vfwprintf_internal
>  # define CHAR_T		wchar_t
>  /* This is a hack!!!  There should be a type uwchar_t.  */
>  # define UCHAR_T	unsigned int /* uwchar_t */
> @@ -747,7 +751,7 @@ static const uint8_t jump_table[] =
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -778,7 +782,7 @@ static const uint8_t jump_table[] =
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      {								      \
>  		fspec->data_arg_type = PA_DOUBLE;			      \
>  		fspec->info.is_long_double = 0;				      \
> @@ -808,7 +812,7 @@ static const uint8_t jump_table[] =
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -838,7 +842,7 @@ static const uint8_t jump_table[] =
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))    \
>  	      fspec->info.is_long_double = 0;				      \
>  	    /* Not supported by *printf functions.  */			      \
>  	    fspec->info.is_binary128 = 0;				      \
> @@ -891,7 +895,7 @@ static const uint8_t jump_table[] =
>        /* NOTREACHED */							      \
>  									      \
>      LABEL (form_number):						      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
> +      if ((mode_flags & PRINTF_FORTIFY) != 0)				      \
>  	{								      \
>  	  if (! readonly_format)					      \
>  	    {								      \
> @@ -1214,7 +1218,8 @@ static const uint8_t jump_table[] =
>  #endif
>  
>  /* Helper function to provide temporary buffering for unbuffered streams.  */
> -static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
> +static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
> +			      unsigned int)
>       __THROW __attribute__ ((noinline));
>  
>  /* Handle positional format specifiers.  */
> @@ -1223,7 +1228,9 @@ static int printf_positional (FILE *s,
>  			      va_list ap, va_list *ap_savep, int done,
>  			      int nspecs_done, const UCHAR_T *lead_str_end,
>  			      CHAR_T *work_buffer, int save_errno,
> -			      const char *grouping, THOUSANDS_SEP_T);
> +			      const char *grouping,
> +			      THOUSANDS_SEP_T thousands_sep,
> +			      unsigned int mode_flags);
>  
>  /* Handle unknown format specifier.  */
>  static int printf_unknown (FILE *, const struct printf_info *,
> @@ -1235,7 +1242,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
>  
>  /* The function itself.  */
>  int
> -vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> +vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
>  {
>    /* The character used as thousands separator.  */
>    THOUSANDS_SEP_T thousands_sep = 0;
> @@ -1273,6 +1280,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
>       0 if unknown.  */
>    int readonly_format = 0;
>  
> +  /* Temporarily honor environmental settings.  */
> +  if (__ldbl_is_dbl)
> +    mode_flags |= PRINTF_LDBL_IS_DBL;
> +  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
> +    mode_flags |= PRINTF_FORTIFY;
> +
>    /* Orient the stream.  */
>  #ifdef ORIENT
>    ORIENT;
> @@ -1293,7 +1306,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
>    if (UNBUFFERED_P (s))
>      /* Use a helper function which will allocate a local temporary buffer
>         for the stream and then call us again.  */
> -    return buffered_vfprintf (s, format, ap);
> +    return buffered_vfprintf (s, format, ap, mode_flags);
>  
>    /* Initialize local variables.  */
>    done = 0;
> @@ -1682,7 +1695,7 @@ do_positional:
>      }
>    done = printf_positional (s, format, readonly_format, ap, &ap_save,
>  			    done, nspecs_done, lead_str_end, work_buffer,
> -			    save_errno, grouping, thousands_sep);
> +			    save_errno, grouping, thousands_sep, mode_flags);
>  
>   all_done:
>    if (__glibc_unlikely (workstart != NULL))
> @@ -1699,7 +1712,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>  		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
>  		   const UCHAR_T *lead_str_end,
>  		   CHAR_T *work_buffer, int save_errno,
> -		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
> +		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
> +		   unsigned int mode_flags)
>  {
>    /* For positional argument handling.  */
>    struct scratch_buffer specsbuf;
> @@ -1789,7 +1803,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>         now.  */
>      args_size = &args_value[nargs].pa_int;
>      args_type = &args_size[nargs];
> -    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> +    memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
>  	    nargs * sizeof (*args_type));
>    }
>  
> @@ -1856,7 +1870,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>        case PA_FLOAT:				/* Promoted.  */
>  	T (PA_DOUBLE, pa_double, double);
>        case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> -	if (__ldbl_is_dbl)
> +	if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
>  	  {
>  	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
>  	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> @@ -1884,7 +1898,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
>        case -1:
>  	/* Error case.  Not all parameters appear in N$ format
>  	   strings.  We have no way to determine their type.  */
> -	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> +	assert ((mode_flags & PRINTF_FORTIFY) != 0);
>  	__libc_fatal ("*** invalid %N$ use detected ***\n");
>        }
>  
> @@ -2285,7 +2299,8 @@ static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
>  #endif
>  
>  static int
> -buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
> +buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
> +		   unsigned int mode_flags)
>  {
>    CHAR_T buf[BUFSIZ];
>    struct helper_file helper;
> @@ -2318,11 +2333,7 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
>    _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
>  
>    /* Now print to helper instead.  */
> -#ifndef COMPILE_WPRINTF
> -  result = _IO_vfprintf (hp, format, args);
> -#else
> -  result = vfprintf (hp, format, args);
> -#endif
> +  result = vfprintf (hp, format, args, mode_flags);
>  
>    /* Lock stream.  */
>    __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
> @@ -2351,14 +2362,3 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
>  
>    return result;
>  }
> -
> -#undef vfprintf
> -#ifdef COMPILE_WPRINTF
> -strong_alias (_IO_vfwprintf, __vfwprintf);
> -ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
> -#else
> -ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
> -ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
> -#endif

Ok.

> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
> index ae412e4b84..13a10db99b 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf.c
> @@ -15,2350 +15,13 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <array_length.h>
> -#include <ctype.h>
> -#include <limits.h>
> -#include <printf.h>
> -#include <stdarg.h>
> -#include <stdint.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <wchar.h>
> -#include <libc-lock.h>
> -#include <sys/param.h>
> -#include <_itoa.h>
> -#include <locale/localeinfo.h>
> -#include <stdio.h>
> -#include <scratch_buffer.h>
> +#include <libio/libioP.h>
>  
> -/* This code is shared between the standard stdio implementation found
> -   in GNU C library and the libio implementation originally found in
> -   GNU libg++.
> -
> -   Beside this it is also shared between the normal and wide character
> -   implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
> -
> -#include <libioP.h>
> -
> -/* In some cases we need extra space for all the output which is not
> -   counted in the width of the string. We assume 32 characters is
> -   enough.  */
> -#define EXTSIZ		32
> -#define ARGCHECK(S, Format) \
> -  do									      \
> -    {									      \
> -      /* Check file argument for consistence.  */			      \
> -      CHECK_FILE (S, -1);						      \
> -      if (S->_flags & _IO_NO_WRITES)					      \
> -	{								      \
> -	  S->_flags |= _IO_ERR_SEEN;					      \
> -	  __set_errno (EBADF);						      \
> -	  return -1;							      \
> -	}								      \
> -      if (Format == NULL)						      \
> -	{								      \
> -	  __set_errno (EINVAL);						      \
> -	  return -1;							      \
> -	}								      \
> -    } while (0)
> -#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
> -
> -#define done_add(val) \
> -  do {									      \
> -    unsigned int _val = val;						      \
> -    assert ((unsigned int) done < (unsigned int) INT_MAX);		      \
> -    if (__glibc_unlikely (INT_MAX - done < _val))			      \
> -      {									      \
> -	done = -1;							      \
> -	 __set_errno (EOVERFLOW);					      \
> -	goto all_done;							      \
> -      }									      \
> -    done += _val;							      \
> -  } while (0)
> -
> -#ifndef COMPILE_WPRINTF
> -# define vfprintf	_IO_vfprintf_internal
> -# define CHAR_T		char
> -# define UCHAR_T	unsigned char
> -# define INT_T		int
> -typedef const char *THOUSANDS_SEP_T;
> -# define L_(Str)	Str
> -# define ISDIGIT(Ch)	((unsigned int) ((Ch) - '0') < 10)
> -# define STR_LEN(Str)	strlen (Str)
> -
> -# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
> -# define PAD(Padchar) \
> -  do {									      \
> -    if (width > 0)							      \
> -      {									      \
> -	ssize_t written = _IO_padn (s, (Padchar), width);		      \
> -	if (__glibc_unlikely (written != width))			      \
> -	  {								      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	done_add (written);						      \
> -      }									      \
> -  } while (0)
> -# define PUTC(C, F)	_IO_putc_unlocked (C, F)
> -# define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
> -			  return -1
> -#else
> -# define vfprintf	_IO_vfwprintf
> -# define CHAR_T		wchar_t
> -/* This is a hack!!!  There should be a type uwchar_t.  */
> -# define UCHAR_T	unsigned int /* uwchar_t */
> -# define INT_T		wint_t
> -typedef wchar_t THOUSANDS_SEP_T;
> -# define L_(Str)	L##Str
> -# define ISDIGIT(Ch)	((unsigned int) ((Ch) - L'0') < 10)
> -# define STR_LEN(Str)	__wcslen (Str)
> -
> -# include <_itowa.h>
> -
> -# define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
> -# define PAD(Padchar) \
> -  do {									      \
> -    if (width > 0)							      \
> -      {									      \
> -	ssize_t written = _IO_wpadn (s, (Padchar), width);		      \
> -	if (__glibc_unlikely (written != width))			      \
> -	  {								      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	done_add (written);						      \
> -      }									      \
> -  } while (0)
> -# define PUTC(C, F)	_IO_putwc_unlocked (C, F)
> -# define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
> -
> -# undef _itoa
> -# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
> -# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
> -# undef EOF
> -# define EOF WEOF
> -#endif
> -
> -#include "_i18n_number.h"
> -
> -/* Include the shared code for parsing the format string.  */
> -#include "printf-parse.h"
> -
> -
> -#define	outchar(Ch)							      \
> -  do									      \
> -    {									      \
> -      const INT_T outc = (Ch);						      \
> -      if (PUTC (outc, s) == EOF || done == INT_MAX)			      \
> -	{								      \
> -	  done = -1;							      \
> -	  goto all_done;						      \
> -	}								      \
> -      ++done;								      \
> -    }									      \
> -  while (0)
> -
> -#define outstring(String, Len)						      \
> -  do									      \
> -    {									      \
> -      assert ((size_t) done <= (size_t) INT_MAX);			      \
> -      if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))		      \
> -	{								      \
> -	  done = -1;							      \
> -	  goto all_done;						      \
> -	}								      \
> -      if (__glibc_unlikely (INT_MAX - done < (Len)))			      \
> -      {									      \
> -	done = -1;							      \
> -	 __set_errno (EOVERFLOW);					      \
> -	goto all_done;							      \
> -      }									      \
> -      done += (Len);							      \
> -    }									      \
> -  while (0)
> -
> -/* For handling long_double and longlong we use the same flag.  If
> -   `long' and `long long' are effectively the same type define it to
> -   zero.  */
> -#if LONG_MAX == LONG_LONG_MAX
> -# define is_longlong 0
> -#else
> -# define is_longlong is_long_double
> -#endif
> -
> -/* If `long' and `int' is effectively the same type we don't have to
> -   handle `long separately.  */
> -#if INT_MAX == LONG_MAX
> -# define is_long_num	0
> -#else
> -# define is_long_num	is_long
> -#endif
> -
> -
> -/* Global constants.  */
> -static const CHAR_T null[] = L_("(null)");
> -
> -/* Size of the work_buffer variable (in characters, not bytes.  */
> -enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
> -
> -/* This table maps a character into a number representing a class.  In
> -   each step there is a destination label for each class.  */
> -static const uint8_t jump_table[] =
> -  {
> -    /* ' ' */  1,            0,            0, /* '#' */  4,
> -	       0, /* '%' */ 14,            0, /* '\''*/  6,
> -	       0,            0, /* '*' */  7, /* '+' */  2,
> -	       0, /* '-' */  3, /* '.' */  9,            0,
> -    /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
> -    /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
> -    /* '8' */  8, /* '9' */  8,            0,            0,
> -	       0,            0,            0,            0,
> -	       0, /* 'A' */ 26,            0, /* 'C' */ 25,
> -	       0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
> -	       0, /* 'I' */ 29,            0,            0,
> -    /* 'L' */ 12,            0,            0,            0,
> -	       0,            0,            0, /* 'S' */ 21,
> -	       0,            0,            0,            0,
> -    /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
> -	       0,            0,            0,            0,
> -	       0, /* 'a' */ 26,            0, /* 'c' */ 20,
> -    /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
> -    /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
> -    /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
> -    /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
> -    /* 't' */ 27, /* 'u' */ 16,            0,            0,
> -    /* 'x' */ 18,            0, /* 'z' */ 13
> -  };
> -
> -#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
> -#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
> -#define LABEL(Name) do_##Name
> -#ifdef SHARED
> -  /* 'int' is enough and it saves some space on 64 bit systems.  */
> -# define JUMP_TABLE_TYPE const int
> -# define JUMP_TABLE_BASE_LABEL do_form_unknown
> -# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
> -# define JUMP(ChExpr, table)						      \
> -      do								      \
> -	{								      \
> -	  int offset;							      \
> -	  void *ptr;							      \
> -	  spec = (ChExpr);						      \
> -	  offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)	      \
> -	    : table[CHAR_CLASS (spec)];					      \
> -	  ptr = &&JUMP_TABLE_BASE_LABEL + offset;			      \
> -	  goto *ptr;							      \
> -	}								      \
> -      while (0)
> -#else
> -# define JUMP_TABLE_TYPE const void *const
> -# define REF(Name) &&do_##Name
> -# define JUMP(ChExpr, table)						      \
> -      do								      \
> -	{								      \
> -	  const void *ptr;						      \
> -	  spec = (ChExpr);						      \
> -	  ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)		      \
> -	    : table[CHAR_CLASS (spec)];					      \
> -	  goto *ptr;							      \
> -	}								      \
> -      while (0)
> -#endif
> -
> -#define STEP0_3_TABLE							      \
> -    /* Step 0: at the beginning.  */					      \
> -    static JUMP_TABLE_TYPE step0_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (flag_space),		/* for ' ' */				      \
> -      REF (flag_plus),		/* for '+' */				      \
> -      REF (flag_minus),		/* for '-' */				      \
> -      REF (flag_hash),		/* for '<hash>' */			      \
> -      REF (flag_zero),		/* for '0' */				      \
> -      REF (flag_quote),		/* for '\'' */				      \
> -      REF (width_asterics),	/* for '*' */				      \
> -      REF (width),		/* for '1'...'9' */			      \
> -      REF (precision),		/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (flag_i18n),		/* for 'I' */				      \
> -    };									      \
> -    /* Step 1: after processing width.  */				      \
> -    static JUMP_TABLE_TYPE step1_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (precision),		/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 2: after processing precision.  */				      \
> -    static JUMP_TABLE_TYPE step2_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (mod_half),		/* for 'h' */				      \
> -      REF (mod_long),		/* for 'l' */				      \
> -      REF (mod_longlong),	/* for 'L', 'q' */			      \
> -      REF (mod_size_t),		/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (mod_ptrdiff_t),      /* for 't' */				      \
> -      REF (mod_intmax_t),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 3a: after processing first 'h' modifier.  */		      \
> -    static JUMP_TABLE_TYPE step3a_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (mod_halfhalf),	/* for 'h' */				      \
> -      REF (form_unknown),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_unknown),	/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_unknown),	/* for 'c' */				      \
> -      REF (form_unknown),	/* for 's', 'S' */			      \
> -      REF (form_unknown),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_unknown),	/* for 'm' */				      \
> -      REF (form_unknown),	/* for 'C' */				      \
> -      REF (form_unknown),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    };									      \
> -    /* Step 3b: after processing first 'l' modifier.  */		      \
> -    static JUMP_TABLE_TYPE step3b_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (form_unknown),	/* for 'h' */				      \
> -      REF (mod_longlong),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    }
> -
> -#define STEP4_TABLE							      \
> -    /* Step 4: processing format specifier.  */				      \
> -    static JUMP_TABLE_TYPE step4_jumps[30] =				      \
> -    {									      \
> -      REF (form_unknown),						      \
> -      REF (form_unknown),	/* for ' ' */				      \
> -      REF (form_unknown),	/* for '+' */				      \
> -      REF (form_unknown),	/* for '-' */				      \
> -      REF (form_unknown),	/* for '<hash>' */			      \
> -      REF (form_unknown),	/* for '0' */				      \
> -      REF (form_unknown),	/* for '\'' */				      \
> -      REF (form_unknown),	/* for '*' */				      \
> -      REF (form_unknown),	/* for '1'...'9' */			      \
> -      REF (form_unknown),	/* for '.' */				      \
> -      REF (form_unknown),	/* for 'h' */				      \
> -      REF (form_unknown),	/* for 'l' */				      \
> -      REF (form_unknown),	/* for 'L', 'q' */			      \
> -      REF (form_unknown),	/* for 'z', 'Z' */			      \
> -      REF (form_percent),	/* for '%' */				      \
> -      REF (form_integer),	/* for 'd', 'i' */			      \
> -      REF (form_unsigned),	/* for 'u' */				      \
> -      REF (form_octal),		/* for 'o' */				      \
> -      REF (form_hexa),		/* for 'X', 'x' */			      \
> -      REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
> -      REF (form_character),	/* for 'c' */				      \
> -      REF (form_string),	/* for 's', 'S' */			      \
> -      REF (form_pointer),	/* for 'p' */				      \
> -      REF (form_number),	/* for 'n' */				      \
> -      REF (form_strerror),	/* for 'm' */				      \
> -      REF (form_wcharacter),	/* for 'C' */				      \
> -      REF (form_floathex),	/* for 'A', 'a' */			      \
> -      REF (form_unknown),       /* for 't' */				      \
> -      REF (form_unknown),       /* for 'j' */				      \
> -      REF (form_unknown)        /* for 'I' */				      \
> -    }
> -
> -
> -#define process_arg(fspec)						      \
> -      /* Start real work.  We know about all flags and modifiers and	      \
> -	 now process the wanted format specifier.  */			      \
> -    LABEL (form_percent):						      \
> -      /* Write a literal "%".  */					      \
> -      outchar (L_('%'));						      \
> -      break;								      \
> -									      \
> -    LABEL (form_integer):						      \
> -      /* Signed decimal integer.  */					      \
> -      base = 10;							      \
> -									      \
> -      if (is_longlong)							      \
> -	{								      \
> -	  long long int signed_number;					      \
> -									      \
> -	  if (fspec == NULL)						      \
> -	    signed_number = va_arg (ap, long long int);			      \
> -	  else								      \
> -	    signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
> -									      \
> -	  is_negative = signed_number < 0;				      \
> -	  number.longlong = is_negative ? (- signed_number) : signed_number;  \
> -									      \
> -	  goto LABEL (longlong_number);					      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  long int signed_number;					      \
> -									      \
> -	  if (fspec == NULL)						      \
> -	    {								      \
> -	      if (is_long_num)						      \
> -		signed_number = va_arg (ap, long int);			      \
> -	      else if (is_char)						      \
> -		signed_number = (signed char) va_arg (ap, unsigned int);      \
> -	      else if (!is_short)					      \
> -		signed_number = va_arg (ap, int);			      \
> -	      else							      \
> -		signed_number = (short int) va_arg (ap, unsigned int);	      \
> -	    }								      \
> -	  else								      \
> -	    if (is_long_num)						      \
> -	      signed_number = args_value[fspec->data_arg].pa_long_int;	      \
> -	    else if (is_char)						      \
> -	      signed_number = (signed char)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -	    else if (!is_short)						      \
> -	      signed_number = args_value[fspec->data_arg].pa_int;	      \
> -	    else							      \
> -	      signed_number = (short int)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -									      \
> -	  is_negative = signed_number < 0;				      \
> -	  number.word = is_negative ? (- signed_number) : signed_number;      \
> -									      \
> -	  goto LABEL (number);						      \
> -	}								      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_unsigned):						      \
> -      /* Unsigned decimal integer.  */					      \
> -      base = 10;							      \
> -      goto LABEL (unsigned_number);					      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_octal):							      \
> -      /* Unsigned octal integer.  */					      \
> -      base = 8;								      \
> -      goto LABEL (unsigned_number);					      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_hexa):							      \
> -      /* Unsigned hexadecimal integer.  */				      \
> -      base = 16;							      \
> -									      \
> -    LABEL (unsigned_number):	  /* Unsigned number of base BASE.  */	      \
> -									      \
> -      /* ISO specifies the `+' and ` ' flags only for signed		      \
> -	 conversions.  */						      \
> -      is_negative = 0;							      \
> -      showsign = 0;							      \
> -      space = 0;							      \
> -									      \
> -      if (is_longlong)							      \
> -	{								      \
> -	  if (fspec == NULL)						      \
> -	    number.longlong = va_arg (ap, unsigned long long int);	      \
> -	  else								      \
> -	    number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
> -									      \
> -	LABEL (longlong_number):					      \
> -	  if (prec < 0)							      \
> -	    /* Supply a default precision if none was given.  */	      \
> -	    prec = 1;							      \
> -	  else								      \
> -	    /* We have to take care for the '0' flag.  If a precision	      \
> -	       is given it must be ignored.  */				      \
> -	    pad = L_(' ');						      \
> -									      \
> -	  /* If the precision is 0 and the number is 0 nothing has to	      \
> -	     be written for the number, except for the 'o' format in	      \
> -	     alternate form.  */					      \
> -	  if (prec == 0 && number.longlong == 0)			      \
> -	    {								      \
> -	      string = workend;						      \
> -	      if (base == 8 && alt)					      \
> -		*--string = L_('0');					      \
> -	    }								      \
> -	  else								      \
> -	    {								      \
> -	      /* Put the number in WORK.  */				      \
> -	      string = _itoa (number.longlong, workend, base,		      \
> -			      spec == L_('X'));				      \
> -	      if (group && grouping)					      \
> -		string = group_number (work_buffer, string, workend,	      \
> -				       grouping, thousands_sep);	      \
> -	      if (use_outdigits && base == 10)				      \
> -		string = _i18n_number_rewrite (string, workend, workend);     \
> -	    }								      \
> -	  /* Simplify further test for num != 0.  */			      \
> -	  number.word = number.longlong != 0;				      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  if (fspec == NULL)						      \
> -	    {								      \
> -	      if (is_long_num)						      \
> -		number.word = va_arg (ap, unsigned long int);		      \
> -	      else if (is_char)						      \
> -		number.word = (unsigned char) va_arg (ap, unsigned int);      \
> -	      else if (!is_short)					      \
> -		number.word = va_arg (ap, unsigned int);		      \
> -	      else							      \
> -		number.word = (unsigned short int) va_arg (ap, unsigned int); \
> -	    }								      \
> -	  else								      \
> -	    if (is_long_num)						      \
> -	      number.word = args_value[fspec->data_arg].pa_u_long_int;	      \
> -	    else if (is_char)						      \
> -	      number.word = (unsigned char)				      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -	    else if (!is_short)						      \
> -	      number.word = args_value[fspec->data_arg].pa_u_int;	      \
> -	    else							      \
> -	      number.word = (unsigned short int)			      \
> -		args_value[fspec->data_arg].pa_u_int;			      \
> -									      \
> -	LABEL (number):							      \
> -	  if (prec < 0)							      \
> -	    /* Supply a default precision if none was given.  */	      \
> -	    prec = 1;							      \
> -	  else								      \
> -	    /* We have to take care for the '0' flag.  If a precision	      \
> -	       is given it must be ignored.  */				      \
> -	    pad = L_(' ');						      \
> -									      \
> -	  /* If the precision is 0 and the number is 0 nothing has to	      \
> -	     be written for the number, except for the 'o' format in	      \
> -	     alternate form.  */					      \
> -	  if (prec == 0 && number.word == 0)				      \
> -	    {								      \
> -	      string = workend;						      \
> -	      if (base == 8 && alt)					      \
> -		*--string = L_('0');					      \
> -	    }								      \
> -	  else								      \
> -	    {								      \
> -	      /* Put the number in WORK.  */				      \
> -	      string = _itoa_word (number.word, workend, base,		      \
> -				   spec == L_('X'));			      \
> -	      if (group && grouping)					      \
> -		string = group_number (work_buffer, string, workend,	      \
> -				       grouping, thousands_sep);	      \
> -	      if (use_outdigits && base == 10)				      \
> -		string = _i18n_number_rewrite (string, workend, workend);     \
> -	    }								      \
> -	}								      \
> -									      \
> -      if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
> -	/* Add octal marker.  */					      \
> -	*--string = L_('0');						      \
> -									      \
> -      prec = MAX (0, prec - (workend - string));			      \
> -									      \
> -      if (!left)							      \
> -	{								      \
> -	  width -= workend - string + prec;				      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    /* Account for 0X hex marker.  */				      \
> -	    width -= 2;							      \
> -									      \
> -	  if (is_negative || showsign || space)				      \
> -	    --width;							      \
> -									      \
> -	  if (pad == L_(' '))						      \
> -	    {								      \
> -	      PAD (L_(' '));						      \
> -	      width = 0;						      \
> -	    }								      \
> -									      \
> -	  if (is_negative)						      \
> -	    outchar (L_('-'));						      \
> -	  else if (showsign)						      \
> -	    outchar (L_('+'));						      \
> -	  else if (space)						      \
> -	    outchar (L_(' '));						      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    {								      \
> -	      outchar (L_('0'));					      \
> -	      outchar (spec);						      \
> -	    }								      \
> -									      \
> -	  width += prec;						      \
> -	  PAD (L_('0'));						      \
> -									      \
> -	  outstring (string, workend - string);				      \
> -									      \
> -	  break;							      \
> -	}								      \
> -      else								      \
> -	{								      \
> -	  if (is_negative)						      \
> -	    {								      \
> -	      outchar (L_('-'));					      \
> -	      --width;							      \
> -	    }								      \
> -	  else if (showsign)						      \
> -	    {								      \
> -	      outchar (L_('+'));					      \
> -	      --width;							      \
> -	    }								      \
> -	  else if (space)						      \
> -	    {								      \
> -	      outchar (L_(' '));					      \
> -	      --width;							      \
> -	    }								      \
> -									      \
> -	  if (number.word != 0 && alt && base == 16)			      \
> -	    {								      \
> -	      outchar (L_('0'));					      \
> -	      outchar (spec);						      \
> -	      width -= 2;						      \
> -	    }								      \
> -									      \
> -	  width -= workend - string + prec;				      \
> -									      \
> -	  if (prec > 0)							      \
> -	    {								      \
> -	      int temp = width;						      \
> -	      width = prec;						      \
> -	      PAD (L_('0'));						      \
> -	      width = temp;						      \
> -	    }								      \
> -									      \
> -	  outstring (string, workend - string);				      \
> -									      \
> -	  PAD (L_(' '));						      \
> -	  break;							      \
> -	}								      \
> -									      \
> -    LABEL (form_float):							      \
> -      {									      \
> -	/* Floating-point number.  This is handled by printf_fp.c.  */	      \
> -	const void *ptr;						      \
> -	int function_done;						      \
> -									      \
> -	if (fspec == NULL)						      \
> -	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> -	      is_long_double = 0;					      \
> -									      \
> -	    struct printf_info info = { .prec = prec,			      \
> -					.width = width,			      \
> -					.spec = spec,			      \
> -					.is_long_double = is_long_double,     \
> -					.is_short = is_short,		      \
> -					.is_long = is_long,		      \
> -					.alt = alt,			      \
> -					.space = space,			      \
> -					.left = left,			      \
> -					.showsign = showsign,		      \
> -					.group = group,			      \
> -					.pad = pad,			      \
> -					.extra = 0,			      \
> -					.i18n = use_outdigits,		      \
> -					.wide = sizeof (CHAR_T) != 1,	      \
> -					.is_binary128 = 0};		      \
> -									      \
> -	    if (is_long_double)						      \
> -	      the_arg.pa_long_double = va_arg (ap, long double);	      \
> -	    else							      \
> -	      the_arg.pa_double = va_arg (ap, double);			      \
> -	    ptr = (const void *) &the_arg;				      \
> -									      \
> -	    function_done = __printf_fp (s, &info, &ptr);		      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> -	      {								      \
> -		fspec->data_arg_type = PA_DOUBLE;			      \
> -		fspec->info.is_long_double = 0;				      \
> -	      }								      \
> -	    /* Not supported by *printf functions.  */			      \
> -	    fspec->info.is_binary128 = 0;				      \
> -									      \
> -	    function_done = __printf_fp (s, &fspec->info, &ptr);	      \
> -	  }								      \
> -									      \
> -	if (function_done < 0)						      \
> -	  {								      \
> -	    /* Error in print handler; up to handler to set errno.  */	      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -									      \
> -	done_add (function_done);					      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_floathex):						      \
> -      {									      \
> -	/* Floating point number printed as hexadecimal number.  */	      \
> -	const void *ptr;						      \
> -	int function_done;						      \
> -									      \
> -	if (fspec == NULL)						      \
> -	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> -	      is_long_double = 0;					      \
> -									      \
> -	    struct printf_info info = { .prec = prec,			      \
> -					.width = width,			      \
> -					.spec = spec,			      \
> -					.is_long_double = is_long_double,     \
> -					.is_short = is_short,		      \
> -					.is_long = is_long,		      \
> -					.alt = alt,			      \
> -					.space = space,			      \
> -					.left = left,			      \
> -					.showsign = showsign,		      \
> -					.group = group,			      \
> -					.pad = pad,			      \
> -					.extra = 0,			      \
> -					.wide = sizeof (CHAR_T) != 1,	      \
> -					.is_binary128 = 0};		      \
> -									      \
> -	    if (is_long_double)						      \
> -	      the_arg.pa_long_double = va_arg (ap, long double);	      \
> -	    else							      \
> -	      the_arg.pa_double = va_arg (ap, double);			      \
> -	    ptr = (const void *) &the_arg;				      \
> -									      \
> -	    function_done = __printf_fphex (s, &info, &ptr);		      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> -	      fspec->info.is_long_double = 0;				      \
> -	    /* Not supported by *printf functions.  */			      \
> -	    fspec->info.is_binary128 = 0;				      \
> -									      \
> -	    function_done = __printf_fphex (s, &fspec->info, &ptr);	      \
> -	  }								      \
> -									      \
> -	if (function_done < 0)						      \
> -	  {								      \
> -	    /* Error in print handler; up to handler to set errno.  */	      \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -									      \
> -	done_add (function_done);					      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_pointer):						      \
> -      /* Generic pointer.  */						      \
> -      {									      \
> -	const void *ptr;						      \
> -	if (fspec == NULL)						      \
> -	  ptr = va_arg (ap, void *);					      \
> -	else								      \
> -	  ptr = args_value[fspec->data_arg].pa_pointer;			      \
> -	if (ptr != NULL)						      \
> -	  {								      \
> -	    /* If the pointer is not NULL, write it as a %#x spec.  */	      \
> -	    base = 16;							      \
> -	    number.word = (unsigned long int) ptr;			      \
> -	    is_negative = 0;						      \
> -	    alt = 1;							      \
> -	    group = 0;							      \
> -	    spec = L_('x');						      \
> -	    goto LABEL (number);					      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    /* Write "(nil)" for a nil pointer.  */			      \
> -	    string = (CHAR_T *) L_("(nil)");				      \
> -	    /* Make sure the full string "(nil)" is printed.  */	      \
> -	    if (prec < 5)						      \
> -	      prec = 5;							      \
> -	    /* This is a wide string iff compiling wprintf.  */		      \
> -	    is_long = sizeof (CHAR_T) > 1;				      \
> -	    goto LABEL (print_string);					      \
> -	  }								      \
> -      }									      \
> -      /* NOTREACHED */							      \
> -									      \
> -    LABEL (form_number):						      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
> -	{								      \
> -	  if (! readonly_format)					      \
> -	    {								      \
> -	      extern int __readonly_area (const void *, size_t)		      \
> -		attribute_hidden;					      \
> -	      readonly_format						      \
> -		= __readonly_area (format, ((STR_LEN (format) + 1)	      \
> -					    * sizeof (CHAR_T)));	      \
> -	    }								      \
> -	  if (readonly_format < 0)					      \
> -	    __libc_fatal ("*** %n in writable segment detected ***\n");	      \
> -	}								      \
> -      /* Answer the count of characters written.  */			      \
> -      if (fspec == NULL)						      \
> -	{								      \
> -	  if (is_longlong)						      \
> -	    *(long long int *) va_arg (ap, void *) = done;		      \
> -	  else if (is_long_num)						      \
> -	    *(long int *) va_arg (ap, void *) = done;			      \
> -	  else if (is_char)						      \
> -	    *(char *) va_arg (ap, void *) = done;			      \
> -	  else if (!is_short)						      \
> -	    *(int *) va_arg (ap, void *) = done;			      \
> -	  else								      \
> -	    *(short int *) va_arg (ap, void *) = done;			      \
> -	}								      \
> -      else								      \
> -	if (is_longlong)						      \
> -	  *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
> -	else if (is_long_num)						      \
> -	  *(long int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else if (is_char)						      \
> -	  *(char *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else if (!is_short)						      \
> -	  *(int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -	else								      \
> -	  *(short int *) args_value[fspec->data_arg].pa_pointer = done;	      \
> -      break;								      \
> -									      \
> -    LABEL (form_strerror):						      \
> -      /* Print description of error ERRNO.  */				      \
> -      string =								      \
> -	(CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,	      \
> -				 WORK_BUFFER_SIZE * sizeof (CHAR_T));	      \
> -      is_long = 0;		/* This is no wide-char string.  */	      \
> -      goto LABEL (print_string)
> -
> -#ifdef COMPILE_WPRINTF
> -# define process_string_arg(fspec) \
> -    LABEL (form_character):						      \
> -      /* Character.  */							      \
> -      if (is_long)							      \
> -	goto LABEL (form_wcharacter);					      \
> -      --width;	/* Account for the character itself.  */		      \
> -      if (!left)							      \
> -	PAD (L' ');							      \
> -      if (fspec == NULL)						      \
> -	outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
> -      else								      \
> -	outchar (__btowc ((unsigned char)				      \
> -			  args_value[fspec->data_arg].pa_int));		      \
> -      if (left)								      \
> -	PAD (L' ');							      \
> -      break;								      \
> -									      \
> -    LABEL (form_wcharacter):						      \
> -      {									      \
> -	/* Wide character.  */						      \
> -	--width;							      \
> -	if (!left)							      \
> -	  PAD (L' ');							      \
> -	if (fspec == NULL)						      \
> -	  outchar (va_arg (ap, wchar_t));				      \
> -	else								      \
> -	  outchar (args_value[fspec->data_arg].pa_wchar);		      \
> -	if (left)							      \
> -	  PAD (L' ');							      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_string):						      \
> -      {									      \
> -	size_t len;							      \
> -	int string_malloced;						      \
> -									      \
> -	/* The string argument could in fact be `char *' or `wchar_t *'.      \
> -	   But this should not make a difference here.  */		      \
> -	if (fspec == NULL)						      \
> -	  string = (CHAR_T *) va_arg (ap, const wchar_t *);		      \
> -	else								      \
> -	  string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring;	      \
> -									      \
> -	/* Entry point for printing other strings.  */			      \
> -      LABEL (print_string):						      \
> -									      \
> -	string_malloced = 0;						      \
> -	if (string == NULL)						      \
> -	  {								      \
> -	    /* Write "(null)" if there's space.  */			      \
> -	    if (prec == -1 || prec >= (int) array_length (null) - 1)          \
> -	      {								      \
> -		string = (CHAR_T *) null;				      \
> -		len = array_length (null) - 1;				      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		string = (CHAR_T *) L"";				      \
> -		len = 0;						      \
> -	      }								      \
> -	  }								      \
> -	else if (!is_long && spec != L_('S'))				      \
> -	  {								      \
> -	    /* This is complicated.  We have to transform the multibyte	      \
> -	       string into a wide character string.  */			      \
> -	    const char *mbs = (const char *) string;			      \
> -	    mbstate_t mbstate;						      \
> -									      \
> -	    len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
> -									      \
> -	    /* Allocate dynamically an array which definitely is long	      \
> -	       enough for the wide character version.  Each byte in the	      \
> -	       multi-byte string can produce at most one wide character.  */  \
> -	    if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))	      \
> -	      {								      \
> -		__set_errno (EOVERFLOW);				      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	    else if (__libc_use_alloca (len * sizeof (wchar_t)))	      \
> -	      string = (CHAR_T *) alloca (len * sizeof (wchar_t));	      \
> -	    else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
> -		     == NULL)						      \
> -	      {								      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	    else							      \
> -	      string_malloced = 1;					      \
> -									      \
> -	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
> -	    len = __mbsrtowcs (string, &mbs, len, &mbstate);		      \
> -	    if (len == (size_t) -1)					      \
> -	      {								      \
> -		/* Illegal multibyte character.  */			      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    if (prec != -1)						      \
> -	      /* Search for the end of the string, but don't search past      \
> -		 the length specified by the precision.  */		      \
> -	      len = __wcsnlen (string, prec);				      \
> -	    else							      \
> -	      len = __wcslen (string);					      \
> -	  }								      \
> -									      \
> -	if ((width -= len) < 0)						      \
> -	  {								      \
> -	    outstring (string, len);					      \
> -	    break;							      \
> -	  }								      \
> -									      \
> -	if (!left)							      \
> -	  PAD (L' ');							      \
> -	outstring (string, len);					      \
> -	if (left)							      \
> -	  PAD (L' ');							      \
> -	if (__glibc_unlikely (string_malloced))				      \
> -	  free (string);						      \
> -      }									      \
> -      break;
> -#else
> -# define process_string_arg(fspec) \
> -    LABEL (form_character):						      \
> -      /* Character.  */							      \
> -      if (is_long)							      \
> -	goto LABEL (form_wcharacter);					      \
> -      --width;	/* Account for the character itself.  */		      \
> -      if (!left)							      \
> -	PAD (' ');							      \
> -      if (fspec == NULL)						      \
> -	outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */	      \
> -      else								      \
> -	outchar ((unsigned char) args_value[fspec->data_arg].pa_int);	      \
> -      if (left)								      \
> -	PAD (' ');							      \
> -      break;								      \
> -									      \
> -    LABEL (form_wcharacter):						      \
> -      {									      \
> -	/* Wide character.  */						      \
> -	char buf[MB_LEN_MAX];						      \
> -	mbstate_t mbstate;						      \
> -	size_t len;							      \
> -									      \
> -	memset (&mbstate, '\0', sizeof (mbstate_t));			      \
> -	len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t)	      \
> -			       : args_value[fspec->data_arg].pa_wchar),	      \
> -			 &mbstate);					      \
> -	if (len == (size_t) -1)						      \
> -	  {								      \
> -	    /* Something went wrong during the conversion.  Bail out.  */     \
> -	    done = -1;							      \
> -	    goto all_done;						      \
> -	  }								      \
> -	width -= len;							      \
> -	if (!left)							      \
> -	  PAD (' ');							      \
> -	outstring (buf, len);						      \
> -	if (left)							      \
> -	  PAD (' ');							      \
> -      }									      \
> -      break;								      \
> -									      \
> -    LABEL (form_string):						      \
> -      {									      \
> -	size_t len;							      \
> -	int string_malloced;						      \
> -									      \
> -	/* The string argument could in fact be `char *' or `wchar_t *'.      \
> -	   But this should not make a difference here.  */		      \
> -	if (fspec == NULL)						      \
> -	  string = (char *) va_arg (ap, const char *);			      \
> -	else								      \
> -	  string = (char *) args_value[fspec->data_arg].pa_string;	      \
> -									      \
> -	/* Entry point for printing other strings.  */			      \
> -      LABEL (print_string):						      \
> -									      \
> -	string_malloced = 0;						      \
> -	if (string == NULL)						      \
> -	  {								      \
> -	    /* Write "(null)" if there's space.  */			      \
> -	    if (prec == -1 || prec >= (int) sizeof (null) - 1)		      \
> -	      {								      \
> -		string = (char *) null;					      \
> -		len = sizeof (null) - 1;				      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		string = (char *) "";					      \
> -		len = 0;						      \
> -	      }								      \
> -	  }								      \
> -	else if (!is_long && spec != L_('S'))				      \
> -	  {								      \
> -	    if (prec != -1)						      \
> -	      /* Search for the end of the string, but don't search past      \
> -		 the length (in bytes) specified by the precision.  */	      \
> -	      len = __strnlen (string, prec);				      \
> -	    else							      \
> -	      len = strlen (string);					      \
> -	  }								      \
> -	else								      \
> -	  {								      \
> -	    const wchar_t *s2 = (const wchar_t *) string;		      \
> -	    mbstate_t mbstate;						      \
> -									      \
> -	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
> -									      \
> -	    if (prec >= 0)						      \
> -	      {								      \
> -		/* The string `s2' might not be NUL terminated.  */	      \
> -		if (__libc_use_alloca (prec))				      \
> -		  string = (char *) alloca (prec);			      \
> -		else if ((string = (char *) malloc (prec)) == NULL)	      \
> -		  {							      \
> -		    done = -1;						      \
> -		    goto all_done;					      \
> -		  }							      \
> -		else							      \
> -		  string_malloced = 1;					      \
> -		len = __wcsrtombs (string, &s2, prec, &mbstate);	      \
> -	      }								      \
> -	    else							      \
> -	      {								      \
> -		len = __wcsrtombs (NULL, &s2, 0, &mbstate);		      \
> -		if (len != (size_t) -1)					      \
> -		  {							      \
> -		    assert (__mbsinit (&mbstate));			      \
> -		    s2 = (const wchar_t *) string;			      \
> -		    if (__libc_use_alloca (len + 1))			      \
> -		      string = (char *) alloca (len + 1);		      \
> -		    else if ((string = (char *) malloc (len + 1)) == NULL)    \
> -		      {							      \
> -			done = -1;					      \
> -			goto all_done;					      \
> -		      }							      \
> -		    else						      \
> -		      string_malloced = 1;				      \
> -		    (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
> -		  }							      \
> -	      }								      \
> -									      \
> -	    if (len == (size_t) -1)					      \
> -	      {								      \
> -		/* Illegal wide-character string.  */			      \
> -		done = -1;						      \
> -		goto all_done;						      \
> -	      }								      \
> -	  }								      \
> -									      \
> -	if ((width -= len) < 0)						      \
> -	  {								      \
> -	    outstring (string, len);					      \
> -	    break;							      \
> -	  }								      \
> -									      \
> -	if (!left)							      \
> -	  PAD (' ');							      \
> -	outstring (string, len);					      \
> -	if (left)							      \
> -	  PAD (' ');							      \
> -	if (__glibc_unlikely (string_malloced))			              \
> -	  free (string);						      \
> -      }									      \
> -      break;
> -#endif
> -
> -/* Helper function to provide temporary buffering for unbuffered streams.  */
> -static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
> -     __THROW __attribute__ ((noinline));
> -
> -/* Handle positional format specifiers.  */
> -static int printf_positional (FILE *s,
> -			      const CHAR_T *format, int readonly_format,
> -			      va_list ap, va_list *ap_savep, int done,
> -			      int nspecs_done, const UCHAR_T *lead_str_end,
> -			      CHAR_T *work_buffer, int save_errno,
> -			      const char *grouping, THOUSANDS_SEP_T);
> -
> -/* Handle unknown format specifier.  */
> -static int printf_unknown (FILE *, const struct printf_info *,
> -			   const void *const *) __THROW;
> -
> -/* Group digits of number string.  */
> -static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
> -			     THOUSANDS_SEP_T);
> -
> -/* The function itself.  */
> -int
> -vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> +extern int
> +__vfprintf (FILE *fp, const char *format, va_list ap)
>  {
> -  /* The character used as thousands separator.  */
> -  THOUSANDS_SEP_T thousands_sep = 0;
> -
> -  /* The string describing the size of groups of digits.  */
> -  const char *grouping;
> -
> -  /* Place to accumulate the result.  */
> -  int done;
> -
> -  /* Current character in format string.  */
> -  const UCHAR_T *f;
> -
> -  /* End of leading constant string.  */
> -  const UCHAR_T *lead_str_end;
> -
> -  /* Points to next format specifier.  */
> -  const UCHAR_T *end_of_spec;
> -
> -  /* Buffer intermediate results.  */
> -  CHAR_T work_buffer[WORK_BUFFER_SIZE];
> -  CHAR_T *workstart = NULL;
> -  CHAR_T *workend;
> -
> -  /* We have to save the original argument pointer.  */
> -  va_list ap_save;
> -
> -  /* Count number of specifiers we already processed.  */
> -  int nspecs_done;
> -
> -  /* For the %m format we may need the current `errno' value.  */
> -  int save_errno = errno;
> -
> -  /* 1 if format is in read-only memory, -1 if it is in writable memory,
> -     0 if unknown.  */
> -  int readonly_format = 0;
> -
> -  /* Orient the stream.  */
> -#ifdef ORIENT
> -  ORIENT;
> -#endif
> -
> -  /* Sanity check of arguments.  */
> -  ARGCHECK (s, format);
> -
> -#ifdef ORIENT
> -  /* Check for correct orientation.  */
> -  if (_IO_vtable_offset (s) == 0 &&
> -      _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
> -      != (sizeof (CHAR_T) == 1 ? -1 : 1))
> -    /* The stream is already oriented otherwise.  */
> -    return EOF;
> -#endif
> -
> -  if (UNBUFFERED_P (s))
> -    /* Use a helper function which will allocate a local temporary buffer
> -       for the stream and then call us again.  */
> -    return buffered_vfprintf (s, format, ap);
> -
> -  /* Initialize local variables.  */
> -  done = 0;
> -  grouping = (const char *) -1;
> -#ifdef __va_copy
> -  /* This macro will be available soon in gcc's <stdarg.h>.  We need it
> -     since on some systems `va_list' is not an integral type.  */
> -  __va_copy (ap_save, ap);
> -#else
> -  ap_save = ap;
> -#endif
> -  nspecs_done = 0;
> -
> -#ifdef COMPILE_WPRINTF
> -  /* Find the first format specifier.  */
> -  f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
> -#else
> -  /* Find the first format specifier.  */
> -  f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
> -#endif
> -
> -  /* Lock stream.  */
> -  _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
> -  _IO_flockfile (s);
> -
> -  /* Write the literal text before the first format.  */
> -  outstring ((const UCHAR_T *) format,
> -	     lead_str_end - (const UCHAR_T *) format);
> -
> -  /* If we only have to print a simple string, return now.  */
> -  if (*f == L_('\0'))
> -    goto all_done;
> -
> -  /* Use the slow path in case any printf handler is registered.  */
> -  if (__glibc_unlikely (__printf_function_table != NULL
> -			|| __printf_modifier_table != NULL
> -			|| __printf_va_arg_table != NULL))
> -    goto do_positional;
> -
> -  /* Process whole format string.  */
> -  do
> -    {
> -      STEP0_3_TABLE;
> -      STEP4_TABLE;
> -
> -      union printf_arg *args_value;	/* This is not used here but ... */
> -      int is_negative;	/* Flag for negative number.  */
> -      union
> -      {
> -	unsigned long long int longlong;
> -	unsigned long int word;
> -      } number;
> -      int base;
> -      union printf_arg the_arg;
> -      CHAR_T *string;	/* Pointer to argument string.  */
> -      int alt = 0;	/* Alternate format.  */
> -      int space = 0;	/* Use space prefix if no sign is needed.  */
> -      int left = 0;	/* Left-justify output.  */
> -      int showsign = 0;	/* Always begin with plus or minus sign.  */
> -      int group = 0;	/* Print numbers according grouping rules.  */
> -      int is_long_double = 0; /* Argument is long double/ long long int.  */
> -      int is_short = 0;	/* Argument is short int.  */
> -      int is_long = 0;	/* Argument is long int.  */
> -      int is_char = 0;	/* Argument is promoted (unsigned) char.  */
> -      int width = 0;	/* Width of output; 0 means none specified.  */
> -      int prec = -1;	/* Precision of output; -1 means none specified.  */
> -      /* This flag is set by the 'I' modifier and selects the use of the
> -	 `outdigits' as determined by the current locale.  */
> -      int use_outdigits = 0;
> -      UCHAR_T pad = L_(' ');/* Padding character.  */
> -      CHAR_T spec;
> -
> -      workstart = NULL;
> -      workend = work_buffer + WORK_BUFFER_SIZE;
> -
> -      /* Get current character in format string.  */
> -      JUMP (*++f, step0_jumps);
> -
> -      /* ' ' flag.  */
> -    LABEL (flag_space):
> -      space = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* '+' flag.  */
> -    LABEL (flag_plus):
> -      showsign = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '-' flag.  */
> -    LABEL (flag_minus):
> -      left = 1;
> -      pad = L_(' ');
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '#' flag.  */
> -    LABEL (flag_hash):
> -      alt = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '0' flag.  */
> -    LABEL (flag_zero):
> -      if (!left)
> -	pad = L_('0');
> -      JUMP (*++f, step0_jumps);
> -
> -      /* The '\'' flag.  */
> -    LABEL (flag_quote):
> -      group = 1;
> -
> -      if (grouping == (const char *) -1)
> -	{
> -#ifdef COMPILE_WPRINTF
> -	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> -					    _NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> -	  thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> -#endif
> -
> -	  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> -	  if (*grouping == '\0' || *grouping == CHAR_MAX
> -#ifdef COMPILE_WPRINTF
> -	      || thousands_sep == L'\0'
> -#else
> -	      || *thousands_sep == '\0'
> -#endif
> -	      )
> -	    grouping = NULL;
> -	}
> -      JUMP (*++f, step0_jumps);
> -
> -    LABEL (flag_i18n):
> -      use_outdigits = 1;
> -      JUMP (*++f, step0_jumps);
> -
> -      /* Get width from argument.  */
> -    LABEL (width_asterics):
> -      {
> -	const UCHAR_T *tmp;	/* Temporary value.  */
> -
> -	tmp = ++f;
> -	if (ISDIGIT (*tmp))
> -	  {
> -	    int pos = read_int (&tmp);
> -
> -	    if (pos == -1)
> -	      {
> -		__set_errno (EOVERFLOW);
> -		done = -1;
> -		goto all_done;
> -	      }
> -
> -	    if (pos && *tmp == L_('$'))
> -	      /* The width comes from a positional parameter.  */
> -	      goto do_positional;
> -	  }
> -	width = va_arg (ap, int);
> -
> -	/* Negative width means left justified.  */
> -	if (width < 0)
> -	  {
> -	    width = -width;
> -	    pad = L_(' ');
> -	    left = 1;
> -	  }
> -
> -	if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	  {
> -	    __set_errno (EOVERFLOW);
> -	    done = -1;
> -	    goto all_done;
> -	  }
> -
> -	if (width >= WORK_BUFFER_SIZE - EXTSIZ)
> -	  {
> -	    /* We have to use a special buffer.  */
> -	    size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
> -	    if (__libc_use_alloca (needed))
> -	      workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
> -	    else
> -	      {
> -		workstart = (CHAR_T *) malloc (needed);
> -		if (workstart == NULL)
> -		  {
> -		    done = -1;
> -		    goto all_done;
> -		  }
> -		workend = workstart + width + EXTSIZ;
> -	      }
> -	  }
> -      }
> -      JUMP (*f, step1_jumps);
> -
> -      /* Given width in format string.  */
> -    LABEL (width):
> -      width = read_int (&f);
> -
> -      if (__glibc_unlikely (width == -1
> -			    || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	{
> -	  __set_errno (EOVERFLOW);
> -	  done = -1;
> -	  goto all_done;
> -	}
> -
> -      if (width >= WORK_BUFFER_SIZE - EXTSIZ)
> -	{
> -	  /* We have to use a special buffer.  */
> -	  size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
> -	  if (__libc_use_alloca (needed))
> -	    workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc (needed);
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + width + EXTSIZ;
> -	    }
> -	}
> -      if (*f == L_('$'))
> -	/* Oh, oh.  The argument comes from a positional parameter.  */
> -	goto do_positional;
> -      JUMP (*f, step1_jumps);
> -
> -    LABEL (precision):
> -      ++f;
> -      if (*f == L_('*'))
> -	{
> -	  const UCHAR_T *tmp;	/* Temporary value.  */
> -
> -	  tmp = ++f;
> -	  if (ISDIGIT (*tmp))
> -	    {
> -	      int pos = read_int (&tmp);
> -
> -	      if (pos == -1)
> -		{
> -		  __set_errno (EOVERFLOW);
> -		  done = -1;
> -		  goto all_done;
> -		}
> -
> -	      if (pos && *tmp == L_('$'))
> -		/* The precision comes from a positional parameter.  */
> -		goto do_positional;
> -	    }
> -	  prec = va_arg (ap, int);
> -
> -	  /* If the precision is negative the precision is omitted.  */
> -	  if (prec < 0)
> -	    prec = -1;
> -	}
> -      else if (ISDIGIT (*f))
> -	{
> -	  prec = read_int (&f);
> -
> -	  /* The precision was specified in this case as an extremely
> -	     large positive value.  */
> -	  if (prec == -1)
> -	    {
> -	      __set_errno (EOVERFLOW);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	}
> -      else
> -	prec = 0;
> -      if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
> -	{
> -	  /* Deallocate any previously allocated buffer because it is
> -	     too small.  */
> -	  if (__glibc_unlikely (workstart != NULL))
> -	    free (workstart);
> -	  workstart = NULL;
> -	  if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
> -	    {
> -	      __set_errno (EOVERFLOW);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	  size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
> -
> -	  if (__libc_use_alloca (needed))
> -	    workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc (needed);
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + prec + EXTSIZ;
> -	    }
> -	}
> -      JUMP (*f, step2_jumps);
> -
> -      /* Process 'h' modifier.  There might another 'h' following.  */
> -    LABEL (mod_half):
> -      is_short = 1;
> -      JUMP (*++f, step3a_jumps);
> -
> -      /* Process 'hh' modifier.  */
> -    LABEL (mod_halfhalf):
> -      is_short = 0;
> -      is_char = 1;
> -      JUMP (*++f, step4_jumps);
> -
> -      /* Process 'l' modifier.  There might another 'l' following.  */
> -    LABEL (mod_long):
> -      is_long = 1;
> -      JUMP (*++f, step3b_jumps);
> -
> -      /* Process 'L', 'q', or 'll' modifier.  No other modifier is
> -	 allowed to follow.  */
> -    LABEL (mod_longlong):
> -      is_long_double = 1;
> -      is_long = 1;
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_size_t):
> -      is_long_double = sizeof (size_t) > sizeof (unsigned long int);
> -      is_long = sizeof (size_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_ptrdiff_t):
> -      is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
> -      is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -    LABEL (mod_intmax_t):
> -      is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
> -      is_long = sizeof (intmax_t) > sizeof (unsigned int);
> -      JUMP (*++f, step4_jumps);
> -
> -      /* Process current format.  */
> -      while (1)
> -	{
> -	  process_arg (((struct printf_spec *) NULL));
> -	  process_string_arg (((struct printf_spec *) NULL));
> -
> -	LABEL (form_unknown):
> -	  if (spec == L_('\0'))
> -	    {
> -	      /* The format string ended before the specifier is complete.  */
> -	      __set_errno (EINVAL);
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -
> -	  /* If we are in the fast loop force entering the complicated
> -	     one.  */
> -	  goto do_positional;
> -	}
> -
> -      /* The format is correctly handled.  */
> -      ++nspecs_done;
> -
> -      if (__glibc_unlikely (workstart != NULL))
> -	free (workstart);
> -      workstart = NULL;
> -
> -      /* Look for next format specifier.  */
> -#ifdef COMPILE_WPRINTF
> -      f = __find_specwc ((end_of_spec = ++f));
> -#else
> -      f = __find_specmb ((end_of_spec = ++f));
> -#endif
> -
> -      /* Write the following constant string.  */
> -      outstring (end_of_spec, f - end_of_spec);
> -    }
> -  while (*f != L_('\0'));
> -
> -  /* Unlock stream and return.  */
> -  goto all_done;
> -
> -  /* Hand off processing for positional parameters.  */
> -do_positional:
> -  if (__glibc_unlikely (workstart != NULL))
> -    {
> -      free (workstart);
> -      workstart = NULL;
> -    }
> -  done = printf_positional (s, format, readonly_format, ap, &ap_save,
> -			    done, nspecs_done, lead_str_end, work_buffer,
> -			    save_errno, grouping, thousands_sep);
> -
> - all_done:
> -  if (__glibc_unlikely (workstart != NULL))
> -    free (workstart);
> -  /* Unlock the stream.  */
> -  _IO_funlockfile (s);
> -  _IO_cleanup_region_end (0);
> -
> -  return done;
> -}
> -\f
> -static int
> -printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
> -		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
> -		   const UCHAR_T *lead_str_end,
> -		   CHAR_T *work_buffer, int save_errno,
> -		   const char *grouping, THOUSANDS_SEP_T thousands_sep)
> -{
> -  /* For positional argument handling.  */
> -  struct scratch_buffer specsbuf;
> -  scratch_buffer_init (&specsbuf);
> -  struct printf_spec *specs = specsbuf.data;
> -  size_t specs_limit = specsbuf.length / sizeof (specs[0]);
> -
> -  /* Used as a backing store for args_value, args_size, args_type
> -     below.  */
> -  struct scratch_buffer argsbuf;
> -  scratch_buffer_init (&argsbuf);
> -
> -  /* Array with information about the needed arguments.  This has to
> -     be dynamically extensible.  */
> -  size_t nspecs = 0;
> -
> -  /* The number of arguments the format string requests.  This will
> -     determine the size of the array needed to store the argument
> -     attributes.  */
> -  size_t nargs = 0;
> -
> -  /* Positional parameters refer to arguments directly.  This could
> -     also determine the maximum number of arguments.  Track the
> -     maximum number.  */
> -  size_t max_ref_arg = 0;
> -
> -  /* Just a counter.  */
> -  size_t cnt;
> -
> -  CHAR_T *workstart = NULL;
> -
> -  if (grouping == (const char *) -1)
> -    {
> -#ifdef COMPILE_WPRINTF
> -      thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> -					_NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> -      thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> -#endif
> -
> -      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> -      if (*grouping == '\0' || *grouping == CHAR_MAX)
> -	grouping = NULL;
> -    }
> -
> -  for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
> -       f = specs[nspecs++].next_fmt)
> -    {
> -      if (nspecs == specs_limit)
> -	{
> -	  if (!scratch_buffer_grow_preserve (&specsbuf))
> -	    {
> -	      done = -1;
> -	      goto all_done;
> -	    }
> -	  specs = specsbuf.data;
> -	  specs_limit = specsbuf.length / sizeof (specs[0]);
> -	}
> -
> -      /* Parse the format specifier.  */
> -#ifdef COMPILE_WPRINTF
> -      nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
> -#else
> -      nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
> -#endif
> -    }
> -
> -  /* Determine the number of arguments the format string consumes.  */
> -  nargs = MAX (nargs, max_ref_arg);
> -
> -  union printf_arg *args_value;
> -  int *args_size;
> -  int *args_type;
> -  {
> -    /* Calculate total size needed to represent a single argument
> -       across all three argument-related arrays.  */
> -    size_t bytes_per_arg
> -      = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
> -    if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
> -      {
> -	done = -1;
> -	goto all_done;
> -      }
> -    args_value = argsbuf.data;
> -    /* Set up the remaining two arrays to each point past the end of
> -       the prior array, since space for all three has been allocated
> -       now.  */
> -    args_size = &args_value[nargs].pa_int;
> -    args_type = &args_size[nargs];
> -    memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> -	    nargs * sizeof (*args_type));
> -  }
> -
> -  /* XXX Could do sanity check here: If any element in ARGS_TYPE is
> -     still zero after this loop, format is invalid.  For now we
> -     simply use 0 as the value.  */
> -
> -  /* Fill in the types of all the arguments.  */
> -  for (cnt = 0; cnt < nspecs; ++cnt)
> -    {
> -      /* If the width is determined by an argument this is an int.  */
> -      if (specs[cnt].width_arg != -1)
> -	args_type[specs[cnt].width_arg] = PA_INT;
> -
> -      /* If the precision is determined by an argument this is an int.  */
> -      if (specs[cnt].prec_arg != -1)
> -	args_type[specs[cnt].prec_arg] = PA_INT;
> -
> -      switch (specs[cnt].ndata_args)
> -	{
> -	case 0:		/* No arguments.  */
> -	  break;
> -	case 1:		/* One argument; we already have the
> -			   type and size.  */
> -	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
> -	  args_size[specs[cnt].data_arg] = specs[cnt].size;
> -	  break;
> -	default:
> -	  /* We have more than one argument for this format spec.
> -	     We must call the arginfo function again to determine
> -	     all the types.  */
> -	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
> -	    (&specs[cnt].info,
> -	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
> -	     &args_size[specs[cnt].data_arg]);
> -	  break;
> -	}
> -    }
> -
> -  /* Now we know all the types and the order.  Fill in the argument
> -     values.  */
> -  for (cnt = 0; cnt < nargs; ++cnt)
> -    switch (args_type[cnt])
> -      {
> -#define T(tag, mem, type)				\
> -	case tag:					\
> -	  args_value[cnt].mem = va_arg (*ap_savep, type); \
> -	  break
> -
> -	T (PA_WCHAR, pa_wchar, wint_t);
> -      case PA_CHAR:				/* Promoted.  */
> -      case PA_INT|PA_FLAG_SHORT:		/* Promoted.  */
> -#if LONG_MAX == INT_MAX
> -      case PA_INT|PA_FLAG_LONG:
> -#endif
> -	T (PA_INT, pa_int, int);
> -#if LONG_MAX == LONG_LONG_MAX
> -      case PA_INT|PA_FLAG_LONG:
> -#endif
> -	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
> -#if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
> -# error "he?"
> -#endif
> -      case PA_FLOAT:				/* Promoted.  */
> -	T (PA_DOUBLE, pa_double, double);
> -      case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> -	if (__ldbl_is_dbl)
> -	  {
> -	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
> -	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> -	  }
> -	else
> -	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
> -	break;
> -      case PA_STRING:				/* All pointers are the same */
> -      case PA_WSTRING:			/* All pointers are the same */
> -	T (PA_POINTER, pa_pointer, void *);
> -#undef T
> -      default:
> -	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
> -	  args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
> -	else if (__glibc_unlikely (__printf_va_arg_table != NULL)
> -		 && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
> -	  {
> -	    args_value[cnt].pa_user = alloca (args_size[cnt]);
> -	    (*__printf_va_arg_table[args_type[cnt] - PA_LAST])
> -	      (args_value[cnt].pa_user, ap_savep);
> -	  }
> -	else
> -	  args_value[cnt].pa_long_double = 0.0;
> -	break;
> -      case -1:
> -	/* Error case.  Not all parameters appear in N$ format
> -	   strings.  We have no way to determine their type.  */
> -	assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> -	__libc_fatal ("*** invalid %N$ use detected ***\n");
> -      }
> -
> -  /* Now walk through all format specifiers and process them.  */
> -  for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
> -    {
> -      STEP4_TABLE;
> -
> -      int is_negative;
> -      union
> -      {
> -	unsigned long long int longlong;
> -	unsigned long int word;
> -      } number;
> -      int base;
> -      union printf_arg the_arg;
> -      CHAR_T *string;		/* Pointer to argument string.  */
> -
> -      /* Fill variables from values in struct.  */
> -      int alt = specs[nspecs_done].info.alt;
> -      int space = specs[nspecs_done].info.space;
> -      int left = specs[nspecs_done].info.left;
> -      int showsign = specs[nspecs_done].info.showsign;
> -      int group = specs[nspecs_done].info.group;
> -      int is_long_double = specs[nspecs_done].info.is_long_double;
> -      int is_short = specs[nspecs_done].info.is_short;
> -      int is_char = specs[nspecs_done].info.is_char;
> -      int is_long = specs[nspecs_done].info.is_long;
> -      int width = specs[nspecs_done].info.width;
> -      int prec = specs[nspecs_done].info.prec;
> -      int use_outdigits = specs[nspecs_done].info.i18n;
> -      char pad = specs[nspecs_done].info.pad;
> -      CHAR_T spec = specs[nspecs_done].info.spec;
> -
> -      workstart = NULL;
> -      CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
> -
> -      /* Fill in last information.  */
> -      if (specs[nspecs_done].width_arg != -1)
> -	{
> -	  /* Extract the field width from an argument.  */
> -	  specs[nspecs_done].info.width =
> -	    args_value[specs[nspecs_done].width_arg].pa_int;
> -
> -	  if (specs[nspecs_done].info.width < 0)
> -	    /* If the width value is negative left justification is
> -	       selected and the value is taken as being positive.  */
> -	    {
> -	      specs[nspecs_done].info.width *= -1;
> -	      left = specs[nspecs_done].info.left = 1;
> -	    }
> -	  width = specs[nspecs_done].info.width;
> -	}
> -
> -      if (specs[nspecs_done].prec_arg != -1)
> -	{
> -	  /* Extract the precision from an argument.  */
> -	  specs[nspecs_done].info.prec =
> -	    args_value[specs[nspecs_done].prec_arg].pa_int;
> -
> -	  if (specs[nspecs_done].info.prec < 0)
> -	    /* If the precision is negative the precision is
> -	       omitted.  */
> -	    specs[nspecs_done].info.prec = -1;
> -
> -	  prec = specs[nspecs_done].info.prec;
> -	}
> -
> -      /* Maybe the buffer is too small.  */
> -      if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
> -	{
> -	  if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
> -				 * sizeof (CHAR_T)))
> -	    workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
> -					  * sizeof (CHAR_T))
> -		       + (MAX (prec, width) + EXTSIZ));
> -	  else
> -	    {
> -	      workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
> -					     * sizeof (CHAR_T));
> -	      if (workstart == NULL)
> -		{
> -		  done = -1;
> -		  goto all_done;
> -		}
> -	      workend = workstart + (MAX (prec, width) + EXTSIZ);
> -	    }
> -	}
> -
> -      /* Process format specifiers.  */
> -      while (1)
> -	{
> -	  extern printf_function **__printf_function_table;
> -	  int function_done;
> -
> -	  if (spec <= UCHAR_MAX
> -	      && __printf_function_table != NULL
> -	      && __printf_function_table[(size_t) spec] != NULL)
> -	    {
> -	      const void **ptr = alloca (specs[nspecs_done].ndata_args
> -					 * sizeof (const void *));
> -
> -	      /* Fill in an array of pointers to the argument values.  */
> -	      for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
> -		   ++i)
> -		ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
> -
> -	      /* Call the function.  */
> -	      function_done = __printf_function_table[(size_t) spec]
> -		(s, &specs[nspecs_done].info, ptr);
> -
> -	      if (function_done != -2)
> -		{
> -		  /* If an error occurred we don't have information
> -		     about # of chars.  */
> -		  if (function_done < 0)
> -		    {
> -		      /* Function has set errno.  */
> -		      done = -1;
> -		      goto all_done;
> -		    }
> -
> -		  done_add (function_done);
> -		  break;
> -		}
> -	    }
> -
> -	  JUMP (spec, step4_jumps);
> -
> -	  process_arg ((&specs[nspecs_done]));
> -	  process_string_arg ((&specs[nspecs_done]));
> -
> -	  LABEL (form_unknown):
> -	  {
> -	    unsigned int i;
> -	    const void **ptr;
> -
> -	    ptr = alloca (specs[nspecs_done].ndata_args
> -			  * sizeof (const void *));
> -
> -	    /* Fill in an array of pointers to the argument values.  */
> -	    for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
> -	      ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
> -
> -	    /* Call the function.  */
> -	    function_done = printf_unknown (s, &specs[nspecs_done].info,
> -					    ptr);
> -
> -	    /* If an error occurred we don't have information about #
> -	       of chars.  */
> -	    if (function_done < 0)
> -	      {
> -		/* Function has set errno.  */
> -		done = -1;
> -		goto all_done;
> -	      }
> -
> -	    done_add (function_done);
> -	  }
> -	  break;
> -	}
> -
> -      if (__glibc_unlikely (workstart != NULL))
> -	free (workstart);
> -      workstart = NULL;
> -
> -      /* Write the following constant string.  */
> -      outstring (specs[nspecs_done].end_of_fmt,
> -		 specs[nspecs_done].next_fmt
> -		 - specs[nspecs_done].end_of_fmt);
> -    }
> - all_done:
> -  if (__glibc_unlikely (workstart != NULL))
> -    free (workstart);
> -  scratch_buffer_free (&argsbuf);
> -  scratch_buffer_free (&specsbuf);
> -  return done;
> +  return __vfprintf_internal (fp, format, ap, 0);
>  }
> -\f
> -/* Handle an unknown format specifier.  This prints out a canonicalized
> -   representation of the format spec itself.  */
> -static int
> -printf_unknown (FILE *s, const struct printf_info *info,
> -		const void *const *args)
> -
> -{
> -  int done = 0;
> -  CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
> -  CHAR_T *const workend
> -    = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
> -  CHAR_T *w;
> -
> -  outchar (L_('%'));
> -
> -  if (info->alt)
> -    outchar (L_('#'));
> -  if (info->group)
> -    outchar (L_('\''));
> -  if (info->showsign)
> -    outchar (L_('+'));
> -  else if (info->space)
> -    outchar (L_(' '));
> -  if (info->left)
> -    outchar (L_('-'));
> -  if (info->pad == L_('0'))
> -    outchar (L_('0'));
> -  if (info->i18n)
> -    outchar (L_('I'));
> -
> -  if (info->width != 0)
> -    {
> -      w = _itoa_word (info->width, workend, 10, 0);
> -      while (w < workend)
> -	outchar (*w++);
> -    }
> -
> -  if (info->prec != -1)
> -    {
> -      outchar (L_('.'));
> -      w = _itoa_word (info->prec, workend, 10, 0);
> -      while (w < workend)
> -	outchar (*w++);
> -    }
> -
> -  if (info->spec != L_('\0'))
> -    outchar (info->spec);
> -
> - all_done:
> -  return done;
> -}
> -\f
> -/* Group the digits from W to REAR_PTR according to the grouping rules
> -   of the current locale.  The interpretation of GROUPING is as in
> -   `struct lconv' from <locale.h>.  The grouped number extends from
> -   the returned pointer until REAR_PTR.  FRONT_PTR to W is used as a
> -   scratch area.  */
> -static CHAR_T *
> -group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
> -	      const char *grouping, THOUSANDS_SEP_T thousands_sep)
> -{
> -  /* Length of the current group.  */
> -  int len;
> -#ifndef COMPILE_WPRINTF
> -  /* Length of the separator (in wide mode, the separator is always a
> -     single wide character).  */
> -  int tlen = strlen (thousands_sep);
> -#endif
> -
> -  /* We treat all negative values like CHAR_MAX.  */
> -
> -  if (*grouping == CHAR_MAX || *grouping <= 0)
> -    /* No grouping should be done.  */
> -    return w;
> -
> -  len = *grouping++;
> -
> -  /* Copy existing string so that nothing gets overwritten.  */
> -  memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T));
> -  CHAR_T *s = front_ptr + (rear_ptr - w);
> -
> -  w = rear_ptr;
> -
> -  /* Process all characters in the string.  */
> -  while (s > front_ptr)
> -    {
> -      *--w = *--s;
> -
> -      if (--len == 0 && s > front_ptr)
> -	{
> -	  /* A new group begins.  */
> -#ifdef COMPILE_WPRINTF
> -	  if (w != s)
> -	    *--w = thousands_sep;
> -	  else
> -	    /* Not enough room for the separator.  */
> -	    goto copy_rest;
> -#else
> -	  int cnt = tlen;
> -	  if (tlen < w - s)
> -	    do
> -	      *--w = thousands_sep[--cnt];
> -	    while (cnt > 0);
> -	  else
> -	    /* Not enough room for the separator.  */
> -	    goto copy_rest;
> -#endif
> -
> -	  if (*grouping == CHAR_MAX
> -#if CHAR_MIN < 0
> -		   || *grouping < 0
> -#endif
> -		   )
> -	    {
> -	    copy_rest:
> -	      /* No further grouping to be done.  Copy the rest of the
> -		 number.  */
> -	      memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
> -	      break;
> -	    }
> -	  else if (*grouping != '\0')
> -	    len = *grouping++;
> -	  else
> -	    /* The previous grouping repeats ad infinitum.  */
> -	    len = grouping[-1];
> -	}
> -    }
> -  return w;
> -}
> -\f
> -/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
> -struct helper_file
> -  {
> -    struct _IO_FILE_plus _f;
> -#ifdef COMPILE_WPRINTF
> -    struct _IO_wide_data _wide_data;
> -#endif
> -    FILE *_put_stream;
> -#ifdef _IO_MTSAFE_IO
> -    _IO_lock_t lock;
> -#endif
> -  };
> -
> -static int
> -_IO_helper_overflow (FILE *s, int c)
> -{
> -  FILE *target = ((struct helper_file*) s)->_put_stream;
> -#ifdef COMPILE_WPRINTF
> -  int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
> -  if (used)
> -    {
> -      size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
> -      if (written == 0 || written == WEOF)
> -	return WEOF;
> -      __wmemmove (s->_wide_data->_IO_write_base,
> -		  s->_wide_data->_IO_write_base + written,
> -		  used - written);
> -      s->_wide_data->_IO_write_ptr -= written;
> -    }
> -#else
> -  int used = s->_IO_write_ptr - s->_IO_write_base;
> -  if (used)
> -    {
> -      size_t written = _IO_sputn (target, s->_IO_write_base, used);
> -      if (written == 0 || written == EOF)
> -	return EOF;
> -      memmove (s->_IO_write_base, s->_IO_write_base + written,
> -	       used - written);
> -      s->_IO_write_ptr -= written;
> -    }
> -#endif
> -  return PUTC (c, s);
> -}
> -
> -#ifdef COMPILE_WPRINTF
> -static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
> -{
> -  JUMP_INIT_DUMMY,
> -  JUMP_INIT (finish, _IO_wdefault_finish),
> -  JUMP_INIT (overflow, _IO_helper_overflow),
> -  JUMP_INIT (underflow, _IO_default_underflow),
> -  JUMP_INIT (uflow, _IO_default_uflow),
> -  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
> -  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
> -  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
> -  JUMP_INIT (seekoff, _IO_default_seekoff),
> -  JUMP_INIT (seekpos, _IO_default_seekpos),
> -  JUMP_INIT (setbuf, _IO_default_setbuf),
> -  JUMP_INIT (sync, _IO_default_sync),
> -  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
> -  JUMP_INIT (read, _IO_default_read),
> -  JUMP_INIT (write, _IO_default_write),
> -  JUMP_INIT (seek, _IO_default_seek),
> -  JUMP_INIT (close, _IO_default_close),
> -  JUMP_INIT (stat, _IO_default_stat)
> -};
> -#else
> -static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
> -{
> -  JUMP_INIT_DUMMY,
> -  JUMP_INIT (finish, _IO_default_finish),
> -  JUMP_INIT (overflow, _IO_helper_overflow),
> -  JUMP_INIT (underflow, _IO_default_underflow),
> -  JUMP_INIT (uflow, _IO_default_uflow),
> -  JUMP_INIT (pbackfail, _IO_default_pbackfail),
> -  JUMP_INIT (xsputn, _IO_default_xsputn),
> -  JUMP_INIT (xsgetn, _IO_default_xsgetn),
> -  JUMP_INIT (seekoff, _IO_default_seekoff),
> -  JUMP_INIT (seekpos, _IO_default_seekpos),
> -  JUMP_INIT (setbuf, _IO_default_setbuf),
> -  JUMP_INIT (sync, _IO_default_sync),
> -  JUMP_INIT (doallocate, _IO_default_doallocate),
> -  JUMP_INIT (read, _IO_default_read),
> -  JUMP_INIT (write, _IO_default_write),
> -  JUMP_INIT (seek, _IO_default_seek),
> -  JUMP_INIT (close, _IO_default_close),
> -  JUMP_INIT (stat, _IO_default_stat)
> -};
> -#endif
> -
> -static int
> -buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
> -{
> -  CHAR_T buf[BUFSIZ];
> -  struct helper_file helper;
> -  FILE *hp = (FILE *) &helper._f;
> -  int result, to_flush;
> -
> -  /* Orient the stream.  */
> -#ifdef ORIENT
> -  ORIENT;
> -#endif
> -
> -  /* Initialize helper.  */
> -  helper._put_stream = s;
> -#ifdef COMPILE_WPRINTF
> -  hp->_wide_data = &helper._wide_data;
> -  _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
> -  hp->_mode = 1;
> -#else
> -  _IO_setp (hp, buf, buf + sizeof buf);
> -  hp->_mode = -1;
> -#endif
> -  hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
> -#if _IO_JUMPS_OFFSET
> -  hp->_vtable_offset = 0;
> -#endif
> -#ifdef _IO_MTSAFE_IO
> -  hp->_lock = NULL;
> -#endif
> -  hp->_flags2 = s->_flags2;
> -  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
> -
> -  /* Now print to helper instead.  */
> -#ifndef COMPILE_WPRINTF
> -  result = _IO_vfprintf (hp, format, args);
> -#else
> -  result = vfprintf (hp, format, args);
> -#endif
> -
> -  /* Lock stream.  */
> -  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
> -  _IO_flockfile (s);
> -
> -  /* Now flush anything from the helper to the S. */
> -#ifdef COMPILE_WPRINTF
> -  if ((to_flush = (hp->_wide_data->_IO_write_ptr
> -		   - hp->_wide_data->_IO_write_base)) > 0)
> -    {
> -      if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
> -	  != to_flush)
> -	result = -1;
> -    }
> -#else
> -  if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
> -    {
> -      if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
> -	result = -1;
> -    }
> -#endif
> -
> -  /* Unlock the stream.  */
> -  _IO_funlockfile (s);
> -  __libc_cleanup_region_end (0);
> -
> -  return result;
> -}
> -
> -#undef vfprintf
> -#ifdef COMPILE_WPRINTF
> -strong_alias (_IO_vfwprintf, __vfwprintf);
> -ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
> -#else
> -ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
> -ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
> -ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
> -#endif
> +ldbl_strong_alias (__vfprintf, _IO_vfprintf);
> +ldbl_strong_alias (__vfprintf, vfprintf);
> +ldbl_hidden_def (__vfprintf, vfprintf)

Ok.

> diff --git a/stdio-common/vfwprintf-internal.c b/stdio-common/vfwprintf-internal.c
> new file mode 100644
> index 0000000000..cefaf2fafe
> --- /dev/null
> +++ b/stdio-common/vfwprintf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WPRINTF	1
> +#include "vfprintf-internal.c"

Ok.

> diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
> index 2c3cd06fad..5d65eb7697 100644
> --- a/stdio-common/vfwprintf.c
> +++ b/stdio-common/vfwprintf.c
> @@ -1,3 +1,25 @@
> -#include <wctype.h>
> -#define COMPILE_WPRINTF	1
> -#include "vfprintf.c"
> +/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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 the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <libio/libioP.h>
> +
> +extern int
> +__vfwprintf (FILE *fp, const wchar_t *format, va_list ap)
> +{
> +  return __vfwprintf_internal (fp, format, ap, 0);
> +}
> +ldbl_weak_alias (__vfwprintf, vfwprintf);

Ok.

> diff --git a/stdio-common/vprintf.c b/stdio-common/vprintf.c
> index d459642dc8..0da8ba761e 100644
> --- a/stdio-common/vprintf.c
> +++ b/stdio-common/vprintf.c
> @@ -25,9 +25,9 @@
>  /* Write formatted output to stdout according to the
>     format string FORMAT, using the argument list in ARG.  */
>  int
> -__vprintf (const char *format, __gnuc_va_list arg)
> +__vprintf (const char *format, va_list ap)
>  {
> -  return vfprintf (stdout, format, arg);
> +  return __vfprintf_internal (stdout, format, ap, 0);
>  }
>  
>  ldbl_strong_alias (__vprintf, vprintf)

Ok.

> diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
> index 2840512cae..5b33604427 100644
> --- a/stdlib/strfrom-skeleton.c
> +++ b/stdlib/strfrom-skeleton.c
> @@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
>      }
>  
>    /* The following code to prepare the virtual file has been adapted from the
> -     function _IO_vsnprintf from libio.  */
> +     function __vsnprintf_internal from libio.  */
>  
>    if (size == 0)
>      {

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 468e23dec4..bda84af0bb 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -166,7 +166,7 @@ __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
>  {
>    int done;
>    set_no_long_double ();
> -  done = _IO_vfprintf (s, fmt, ap);
> +  done = __vfprintf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return done;
>  }
> @@ -175,15 +175,16 @@ strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
>  
>  int
>  attribute_compat_text_section
> -__nldbl__IO_vsprintf (char *string, const char *fmt, va_list ap)
> +__nldbl___vsprintf (char *string, const char *fmt, va_list ap)
>  {
>    int done;
>    __no_long_double = 1;
> -  done = _IO_vsprintf (string, fmt, ap);
> +  done = __vsprintf_internal (string, fmt, ap, 0);
>    __no_long_double = 0;
>    return done;
>  }
> -weak_alias (__nldbl__IO_vsprintf, __nldbl_vsprintf)
> +strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
> +weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
>  libc_hidden_def (__nldbl_vsprintf)
>  
>  int
> @@ -193,7 +194,7 @@ __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
>  {
>    int done;
>    __no_long_double = 1;
> -  done = _IO_obstack_vprintf (obstack, fmt, ap);
> +  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
>    __no_long_double = 0;
>    return done;
>  }
> @@ -245,7 +246,7 @@ __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vasprintf (result_ptr, fmt, ap);
> +  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -257,7 +258,7 @@ __nldbl_vdprintf (int d, const char *fmt, va_list arg)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vdprintf (d, fmt, arg);
> +  res = __vdprintf_internal (d, fmt, arg, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -269,7 +270,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = _IO_vfwprintf (s, fmt, ap);
> +  res = __vfwprintf_internal (s, fmt, ap, 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -289,7 +290,7 @@ __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vsnprintf (string, maxlen, fmt, ap);
> +  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -303,7 +304,7 @@ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
>  {
>    int res;
>    __no_long_double = 1;
> -  res = _IO_vswprintf (string, maxlen, fmt, ap);
> +  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
>    __no_long_double = 0;
>    return res;
>  }
> 

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 4/7] Add __v*printf_internal with flags arguments
  2018-11-22 17:55   ` Adhemerval Zanella
@ 2018-11-22 17:59     ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 17:59 UTC (permalink / raw)
  To: libc-alpha



On 22/11/2018 15:55, Adhemerval Zanella wrote:
> 
> 
> On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
>> From: Zack Weinberg <zackw@panix.com>
>>
>> Changes since v2:
>>
>>   - Expanded the comments about PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
>>   - Removed the parameter-less macros LDBL_IS_DBL and DO_FORTIFY.
>>     Explicitly compare the flags.
> 
> LGTM, thanks.
And, as before please add a note on CL that it fixes BZ#11319 by unifying both 
fortified and non-fortified vdprintf initialization.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal.
  2018-11-15 21:46 ` [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal Gabriel F. T. Gomes
@ 2018-11-22 18:00   ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 18:00 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2
> 
>   - None, but dependent on previous patch in the set, thus resending.

LGTM.

> 
> Changed since v1:
> 
>   - Fixed white-space errors.
>   - Removed internal declaration of __vsyslog_chk, because it's no
>     longer called from within libc.  There's a call to it in the inline
>     definition of vsyslog in bits/syslog.h, but that definition is only
>     inlined in user code with:
>       #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
>   - Removed libc_hidden_def and libc_hidden_proto for vsyslog, as it is
>     never called internally (it never was).
>   - Added attribute_hidden to the internal declaration of
>     __vsyslog_internal.  Here are the objdumps of one internal call,
>     before and after this change, on a 32-bits powerpc machine:
>     Without attribute_hidden:
>       $ objdump -d --reloc SYSLOG-PRISTINE-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 17
>       000fc790 <vsyslog@@GLIBC_2.4>:
>          fc790:       94 21 ff f0     stwu    r1,-16(r1)
>          fc794:       38 c0 00 00     li      r6,0
>          fc798:       7c 08 02 a6     mflr    r0
>          fc79c:       42 9f 00 05     bcl     20,4*cr7+so,fc7a0 <vsyslog@@GLIBC_2.4+0x10>
>          fc7a0:       93 c1 00 08     stw     r30,8(r1)
>          fc7a4:       90 01 00 14     stw     r0,20(r1)
>          fc7a8:       7f c8 02 a6     mflr    r30
>          fc7ac:       3f de 00 0a     addis   r30,r30,10
>          fc7b0:       3b de 38 54     addi    r30,r30,14420
>          fc7b4:       4b ff f9 9d     bl      fc150 <__vsyslog_internal>
>          fc7b8:       80 01 00 14     lwz     r0,20(r1)
>          fc7bc:       83 c1 00 08     lwz     r30,8(r1)
>          fc7c0:       38 21 00 10     addi    r1,r1,16
>          fc7c4:       7c 08 03 a6     mtlr    r0
>          fc7c8:       4e 80 00 20     blr
>          fc7cc:       60 00 00 00     nop
>     With attribute_hidden:
>       $ objdump -d --reloc SYSLOG-PATCHED-glibc/libc.so | grep "<vsyslog@@GLIBC_2.4>:" -A 5
>       000fc780 <vsyslog@@GLIBC_2.4>:
>          fc780:       38 c0 00 00     li      r6,0
>          fc784:       4b ff f9 cc     b       fc150 <__vsyslog_internal>
>          fc788:       60 00 00 00     nop
>          fc78c:       60 00 00 00     nop
> 
> -- 8< --
> __nldbl___vsyslog_chk will ultimately want to pass PRINTF_LDBL_IS_DBL
> down to __vfprintf_internal *as well as* possibly setting PRINTF_FORTIFY.
> To make that possible, we need a __vsyslog_internal that takes the
> same flags as printf.  The code in misc/syslog.c does also get a
> little simpler.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-16  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* misc/syslog.c: Include libioP.h, not iolibio.h.
> 	(__vsyslog_internal): New function with the former body of
> 	__vsyslog_chk; takes mode_flags argument same as
> 	__v*printf_internal.  Call __vfprintf_internal directly.
> 
> 	(__vsyslog_chk): Now a wrapper around __vsyslog_internal.
> 	Remove libc_hidden_def.
> 	(__syslog, __syslog_chk): Use __vsyslog_internal.
> 	(__vsyslog): Move to just below __syslog.  Use __vsyslog_internal.
> 
> 	* include/sys/syslog.h: Add multiple inclusion guard.
> 	Add prototype for __vsyslog_internal.
> 	Remove declaration and libc_hidden_proto for __vsyslog_chk.
> 
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl___vsyslog_chk):
> 	Use __vsyslog_internal.
> ---
>  include/sys/syslog.h                    | 19 ++++++++++-------
>  misc/syslog.c                           | 36 +++++++++++++++++----------------
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c |  2 +-
>  3 files changed, 32 insertions(+), 25 deletions(-)
> 
> diff --git a/include/sys/syslog.h b/include/sys/syslog.h
> index 3be3189ed1..89d3479ebc 100644
> --- a/include/sys/syslog.h
> +++ b/include/sys/syslog.h
> @@ -1,11 +1,16 @@
> +#ifndef _LIBC_SYS_SYSLOG_H
> +#define _LIBC_SYS_SYSLOG_H 1
>  #include <misc/sys/syslog.h>
> -
>  #ifndef _ISOMAC
> +
>  libc_hidden_proto (syslog)
> -libc_hidden_proto (vsyslog)
>  
> -extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
> -			   __gnuc_va_list __ap)
> -     __attribute__ ((__format__ (__printf__, 3, 0)));
> -libc_hidden_proto (__vsyslog_chk)
> -#endif
> +/* __vsyslog_internal uses the same mode_flags bits as
> +   __v*printf_internal; see libio/libioP.h.  */
> +extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list ap,
> +				unsigned int mode_flags)
> +     attribute_hidden
> +     __attribute__ ((__format__ (__printf__, 2, 0)));
> +
> +#endif /* _ISOMAC */
> +#endif /* syslog.h */

Ok.

> diff --git a/misc/syslog.c b/misc/syslog.c
> index 644dbe80ec..3a15da41ce 100644
> --- a/misc/syslog.c
> +++ b/misc/syslog.c
> @@ -53,7 +53,7 @@ static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
>  
>  #include <stdarg.h>
>  
> -#include <libio/iolibio.h>
> +#include <libio/libioP.h>
>  #include <math_ldbl_opt.h>
>  
>  #include <kernel-features.h>
> @@ -114,24 +114,38 @@ __syslog(int pri, const char *fmt, ...)
>  	va_list ap;
>  
>  	va_start(ap, fmt);
> -	__vsyslog_chk(pri, -1, fmt, ap);
> +	__vsyslog_internal(pri, fmt, ap, 0);
>  	va_end(ap);
>  }
>  ldbl_hidden_def (__syslog, syslog)
>  ldbl_strong_alias (__syslog, syslog)
>  
> +void
> +__vsyslog(int pri, const char *fmt, va_list ap)
> +{
> +	__vsyslog_internal(pri, fmt, ap, 0);
> +}
> +ldbl_weak_alias (__vsyslog, vsyslog)
> +
>  void
>  __syslog_chk(int pri, int flag, const char *fmt, ...)
>  {
>  	va_list ap;
>  
>  	va_start(ap, fmt);
> -	__vsyslog_chk(pri, flag, fmt, ap);
> +	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
>  	va_end(ap);
>  }
>  
>  void
>  __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
> +{
> +	__vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
> +}
> +
> +void
> +__vsyslog_internal(int pri, const char *fmt, va_list ap,
> +		   unsigned int mode_flags)
>  {
>  	struct tm now_tm;
>  	time_t now;
> @@ -215,11 +229,8 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
>  	    __set_errno (saved_errno);
>  
>  	    /* We have the header.  Print the user's format into the
> -               buffer.  */
> -	    if (flag == -1)
> -	      vfprintf (f, fmt, ap);
> -	    else
> -	      __vfprintf_chk (f, flag, fmt, ap);
> +	       buffer.  */
> +	    __vfprintf_internal (f, fmt, ap, mode_flags);
>  
>  	    /* Close the memory stream; this will finalize the data
>  	       into a malloc'd buffer in BUF.  */
> @@ -316,15 +327,6 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
>  	if (buf != failbuf)
>  		free (buf);
>  }
> -libc_hidden_def (__vsyslog_chk)
> -
> -void
> -__vsyslog(int pri, const char *fmt, va_list ap)
> -{
> -  __vsyslog_chk (pri, -1, fmt, ap);
> -}
> -ldbl_hidden_def (__vsyslog, vsyslog)
> -ldbl_weak_alias (__vsyslog, vsyslog)
>  
>  static struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
>  

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index bda84af0bb..958bbc1834 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -843,7 +843,7 @@ attribute_compat_text_section
>  __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
>  {
>    set_no_long_double ();
> -  __vsyslog_chk (pri, flag, fmt, ap);
> +  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
>    clear_no_long_double ();
>  }
>  libc_hidden_def (__nldbl___vsyslog_chk)
> 

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-11-15 21:46 ` [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319) Gabriel F. T. Gomes
@ 2018-11-22 18:11   ` Adhemerval Zanella
  2018-12-04 16:20     ` Gabriel F. T. Gomes
  2018-12-18 13:03   ` Szabolcs Nagy
  1 sibling, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 18:11 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changes since v2:
> 
>   - Fix copyright statements.
>   - Add note about the fix for bug 11319.

I don't recall exactly which patch was the one that actually fixes BZ#11319,
my previous indication was 'Add __v*printf_internal with flags arguments.'.
Could you recheck it please?

Besides it the patch LGTM, thanks.

> 
> Changes since v1:
> 
>   - Fixed white-space errors.
>   - Updated commit message.
>   - In the declaration of __vsnprintf_internal, in libio/libioP.h,
>     mention that passing -1 to the maxlen argument is the behavior of
>     ordinary (v)sprintf function (this was already described in the
>     commit message, but seems relevant to the code itself).
> 
> -- 8< --
> The _chk variants of all of the printf functions become much simpler.
> This is the last thing that we needed _IO_acquire_lock_clear_flags2
> for, so it can go as well.  I took the opportunity to make the headers
> included and the names of all local variables consistent across all the
> affected files.
> 
> Since we ultimately want to get rid of __no_long_double as well, it
> must be possible to get all of the nontrivial effects of the _chk
> functions by calling the _internal functions with appropriate flags.
> For most of the __(v)xprintf_chk functions, this is covered by
> PRINTF_FORTIFY plus some up-front argument checks that can be
> duplicated.  However, __(v)sprintf_chk installs a custom jump table so
> that it can crash instead of overflowing the output buffer.  This
> functionality is moved to __vsprintf_internal, which now has a
> 'maxlen' argument like __vsnprintf_internal; to get the unsafe
> behavior of ordinary (v)sprintf, pass -1 for that argument.
> 
> obstack_printf_chk and obstack_vprintf_chk are no longer in the same
> file.
> 
> As a side-effect of the unification of both fortified and non-fortified
> vdprintf initialization, this patch fixes bug 11319.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-24  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	[BZ #11319]
> 	* libio/iovsprintf.c (_IO_str_chk_overflow, libio_vtable):
> 	Moved here from debug/vsprintf_chk.c.
> 	(__vsprintf_internal): Add 'maxlen' argument.  Change the setup
> 	and completion logic for the strfile to match exactly what
> 	__vsprintf_chk used to do, except, when maxlen is -1, pass -1 to
> 	_IO_str_init_static_internal instead of maxlen-1.
> 	(__vsprintf): Pass -1 as maxlen to __vsprintf_internal.
> 	* stdio-common/sprintf.c (__sprintf): Pass -1 as maxlen to
> 	__vsprintf_internal.
> 
> 	* debug/vsprintf_chk.c (__vsprintf_chk)
> 	* debug/sprintf_chk.c (__sprintf_chk):
> 	Directly call __vsprintf_internal, passing PRINTF_FORTIFY if
> 	'flags' argument is positive, and slen as maxlen.  No need to lock
> 	the FILE and/or construct a temporary FILE.  Minimize and normalize
> 	header inclusions and variable names.  Do not libc_hidden_def anything.
> 
> 	* debug/asprintf_chk.c (__asprintf_chk)
> 	* debug/dprintf_chk.c (__dprintf_chk)
> 	* debug/fprintf_chk.c (__fprintf_chk)
> 	* debug/fwprintf_chk.c (__fwprintf_chk)
> 	* debug/printf_chk.c (__printf_chk)
> 	* debug/snprintf_chk.c (__snprintf_chk)
> 	* debug/swprintf_chk.c (__swprintf_chk)
> 	* debug/vasprintf_chk.c (__vasprintf_chk)
> 	* debug/vdprintf_chk.c (__vdprintf_chk)
> 	* debug/vfprintf_chk.c (__vfprintf_chk)
> 	* debug/vfwprintf_chk.c (__vfwprintf_chk)
> 	* debug/vprintf_chk.c (__vprintf_chk)
> 	* debug/vsnprintf_chk.c (__vsnprintf_chk)
> 	* debug/vswprintf_chk.c (__vswprintf_chk)
> 	* debug/vwprintf_chk.c (__vwprintf_chk)
> 	* debug/wprintf_chk.c (__wprintf_chk):
> 	Directly call the corresponding vxxprintf_internal function, passing
> 	PRINTF_FORTIFY if 'flag' argument is positive.	No need to lock
> 	the FILE and/or construct a temporary FILE.  Minimize and normalize
> 	header inclusions and variable names.  Do not libc_hidden_def anything.
> 
> 	* debug/obprintf_chk.c (__obstack_printf_chk): Directly call
> 	__obstack_vprintf_internal.
> 	(__obstack_vprintf_chk): Convert into a wrapper that calls
> 	__obstack_vprintf_internal (these two functions already had the
> 	same code) and move to new file...
> 	* debug/vobprintf_chk.c (__obstack_vprintf_chk): ... here.  New
> 	file.
> 	* debug/obprintf.c (__obstack_vprintf_internal): Remove the checking of
> 	the flags argument and the setting of _IO_FLAGS2_FORTIFY.
> 	* debug/Makefile (routines): Add vobprintf_chk.
> 
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	(__nldbl___vsprintf): Pass -1 as maxlen to __vsprintf_internal.
> 	(__nldbl___vfprintf_chk, __nldbl___vsnprintf_chk)
> 	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
> 	(__nldbl___vasprintf_chk, __nldbl___vdprintf_chk)
> 	(__nldbl___obstack_vfprintf_chk):
> 	Directly call the corresponding vxxprintf_internal function,
> 	passing PRINTF_FORTIFY if 'flag' argument is positive.  If necessary,
> 	duplicate comparison of slen with 0 or maxlen from the corresponding
> 	non-__nldbl function.
> 
> 	* include/stdio.h (__vsnprintf_chk, __vfprintf_chk, __vasprintf_chk)
> 	(__vdprintf_chk, __obstack_vfprintf_chk): Remove libc_hidden_proto.
> 	* include/wchar.h (__vfwprintf_chk, __vswprintf_chk):
> 	Remove libc_hidden_proto.
> 
> 	* stdio-common/vfprintf-internal.c
> 	(__vfprintf_internal, __vfwprintf_internal):
> 	Do not check _IO_FLAGS2_FORTIFY.
> 	* libio/libio.h (_IO_FLAGS2_FORTIFY): Remove.
> 	* libio/libioP.h: Update prototype of __vsprintf_internal and add
> 	a comment explaining why it has the maxlen argument.
> 	(_IO_acquire_lock_clear_flags2_fct): Remove.
> 	(_IO_acquire_lock_clear_flags2): Remove.
> 	(_IO_release_lock): Remove conditional statement which will
> 	now never execute.
> 	(_IO_acquire_lock): Remove variable which is now unused.
> 	* sysdeps/generic/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
> 	* sysdeps/nptl/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
> ---
>  debug/Makefile                            |  2 +-
>  debug/asprintf_chk.c                      | 20 ++++---
>  debug/dprintf_chk.c                       | 20 ++++---
>  debug/fprintf_chk.c                       | 20 +++----
>  debug/fwprintf_chk.c                      | 20 +++----
>  debug/obprintf_chk.c                      | 96 ++++---------------------------
>  debug/printf_chk.c                        | 20 +++----
>  debug/snprintf_chk.c                      | 24 ++++----
>  debug/sprintf_chk.c                       | 25 ++++----
>  debug/swprintf_chk.c                      | 27 +++++----
>  debug/vasprintf_chk.c                     | 68 ++--------------------
>  debug/vdprintf_chk.c                      | 37 ++----------
>  debug/vfprintf_chk.c                      | 21 ++-----
>  debug/vfwprintf_chk.c                     | 21 ++-----
>  debug/{asprintf_chk.c => vobprintf_chk.c} | 23 +++-----
>  debug/vprintf_chk.c                       | 20 ++-----
>  debug/vsnprintf_chk.c                     | 46 ++-------------
>  debug/vsprintf_chk.c                      | 69 +++-------------------
>  debug/vswprintf_chk.c                     | 51 ++--------------
>  debug/vwprintf_chk.c                      | 21 ++-----
>  debug/wprintf_chk.c                       | 21 +++----
>  include/stdio.h                           |  5 --
>  include/wchar.h                           |  2 -
>  libio/iovsprintf.c                        | 54 +++++++++++++++--
>  libio/libio.h                             |  1 -
>  libio/libioP.h                            | 27 +++------
>  stdio-common/sprintf.c                    |  2 +-
>  stdio-common/vfprintf-internal.c          |  2 -
>  sysdeps/generic/stdio-lock.h              |  7 ---
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c   | 32 ++++++++---
>  sysdeps/nptl/stdio-lock.h                 |  7 ---
>  31 files changed, 247 insertions(+), 564 deletions(-)
>  copy debug/{asprintf_chk.c => vobprintf_chk.c} (61%)
> 
> diff --git a/debug/Makefile b/debug/Makefile
> index 506cebc3c4..2ef08cf23b 100644
> --- a/debug/Makefile
> +++ b/debug/Makefile
> @@ -45,7 +45,7 @@ routines  = backtrace backtracesyms backtracesymsfd noophooks \
>  	    gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
>  	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
>  	    wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
> -	    vdprintf_chk obprintf_chk \
> +	    vdprintf_chk obprintf_chk vobprintf_chk \
>  	    longjmp_chk ____longjmp_chk \
>  	    fdelt_chk poll_chk ppoll_chk \
>  	    explicit_bzero_chk \

Ok.

> diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c
> index 9cd4143f2e..eb885c35ca 100644
> --- a/debug/asprintf_chk.c
> +++ b/debug/asprintf_chk.c
> @@ -15,22 +15,24 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <stdio.h>
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output from FORMAT to a string which is
>     allocated with malloc and stored in *STRING_PTR.  */
>  int
> -__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
> +__asprintf_chk (char **result_ptr, int flag, const char *format, ...)
>  {
> -  va_list arg;
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, format);
> -  done = __vasprintf_chk (result_ptr, flags, format, arg);
> -  va_end (arg);
> +  va_start (ap, format);
> +  ret = __vasprintf_internal (result_ptr, format, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }

Ok.

> diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c
> index df3867c61c..b5c62827c0 100644
> --- a/debug/dprintf_chk.c
> +++ b/debug/dprintf_chk.c
> @@ -15,21 +15,23 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <stdio.h>
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to D, according to the format string FORMAT.  */
>  int
> -__dprintf_chk (int d, int flags, const char *format, ...)
> +__dprintf_chk (int d, int flag, const char *format, ...)
>  {
> -  va_list arg;
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, format);
> -  done = __vdprintf_chk (d, flags, format, arg);
> -  va_end (arg);
> +  va_start (ap, format);
> +  ret = __vdprintf_internal (d, format, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }

Ok.

> diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
> index cff4438afb..14afc073b2 100644
> --- a/debug/fprintf_chk.c
> +++ b/debug/fprintf_chk.c
> @@ -16,29 +16,23 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to FP from the format string FORMAT.  */
>  int
>  ___fprintf_chk (FILE *fp, int flag, const char *format, ...)
>  {
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>    va_list ap;
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (fp);
> -  if (flag > 0)
> -    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
> +  int ret;
>  
>    va_start (ap, format);
> -  done = vfprintf (fp, format, ap);
> +  ret = __vfprintf_internal (fp, format, ap, mode);
>    va_end (ap);
>  
> -  if (flag > 0)
> -    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (fp);
> -
> -  return done;
> +  return ret;
>  }
>  ldbl_strong_alias (___fprintf_chk, __fprintf_chk)

Ok.

> diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
> index 63167c1839..10d84ce98b 100644
> --- a/debug/fwprintf_chk.c
> +++ b/debug/fwprintf_chk.c
> @@ -16,28 +16,22 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <wchar.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to FP from the format string FORMAT.  */
>  int
>  __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
>  {
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>    va_list ap;
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (fp);
> -  if (flag > 0)
> -    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
> +  int ret;
>  
>    va_start (ap, format);
> -  done = __vfwprintf_internal (fp, format, ap, 0);
> +  ret = __vfwprintf_internal (fp, format, ap, mode);
>    va_end (ap);
>  
> -  if (flag > 0)
> -    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (fp);
> -
> -  return done;
> +  return ret;
>  }

Ok.

> diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
> index 41dd481c34..c1a8f9e9a9 100644
> --- a/debug/obprintf_chk.c
> +++ b/debug/obprintf_chk.c
> @@ -17,99 +17,23 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -
> -#include <stdlib.h>
> -#include <libioP.h>
> -#include "../libio/strfile.h"
> -#include <assert.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <obstack.h>
> +#include <libio/libioP.h>
>  #include <stdarg.h>
> -#include <stdio_ext.h>
> -
> -
> -struct _IO_obstack_file
> -{
> -  struct _IO_FILE_plus file;
> -  struct obstack *obstack;
> -};
> -
> -extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
> -
> -int
> -__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
> -		       va_list args)
> -{
> -  struct obstack_FILE
> -    {
> -      struct _IO_obstack_file ofile;
> -    } new_f;
> -  int result;
> -  int size;
> -  int room;
> -
> -#ifdef _IO_MTSAFE_IO
> -  new_f.ofile.file.file._lock = NULL;
> -#endif
> -
> -  _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
> -  room = obstack_room (obstack);
> -  size = obstack_object_size (obstack) + room;
> -  if (size == 0)
> -    {
> -      /* We have to handle the allocation a bit different since the
> -	 `_IO_str_init_static' function would handle a size of zero
> -	 different from what we expect.  */
> -
> -      /* Get more memory.  */
> -      obstack_make_room (obstack, 64);
> -
> -      /* Recompute how much room we have.  */
> -      room = obstack_room (obstack);
> -      size = room;
> -
> -      assert (size != 0);
> -    }
> -
> -  _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile,
> -				obstack_base (obstack),
> -				size, obstack_next_free (obstack));
> -  /* Now allocate the rest of the current chunk.  */
> -  assert (size == (new_f.ofile.file.file._IO_write_end
> -		   - new_f.ofile.file.file._IO_write_base));
> -  assert (new_f.ofile.file.file._IO_write_ptr
> -	  == (new_f.ofile.file.file._IO_write_base
> -	      + obstack_object_size (obstack)));
> -  obstack_blank_fast (obstack, room);
> -
> -  new_f.ofile.obstack = obstack;
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> -     can only come from read-only format strings.  */
> -  if (flags > 0)
> -    new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
> -
> -  /* Shrink the buffer to the space we really currently need.  */
> -  obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
> -				- new_f.ofile.file.file._IO_write_end));
> -
> -  return result;
> -}
> -libc_hidden_def (__obstack_vprintf_chk)
>  
>  
>  int
> -__obstack_printf_chk (struct obstack *obstack, int flags, const char *format,
> +__obstack_printf_chk (struct obstack *obstack, int flag, const char *format,
>  		      ...)
>  {
> -  int result;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>    va_list ap;
> +  int ret;
> +
>    va_start (ap, format);
> -  result = __obstack_vprintf_chk (obstack, flags, format, ap);
> +  ret = __obstack_vprintf_internal (obstack, format, ap, mode);
>    va_end (ap);
> -  return result;
> +
> +  return ret;
>  }

Ok.

> diff --git a/debug/printf_chk.c b/debug/printf_chk.c
> index 426dc78386..e035b42590 100644
> --- a/debug/printf_chk.c
> +++ b/debug/printf_chk.c
> @@ -16,29 +16,23 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to stdout from the format string FORMAT.  */
>  int
>  ___printf_chk (int flag, const char *format, ...)
>  {
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>    va_list ap;
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stdout);
> -  if (flag > 0)
> -    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
> +  int ret;
>  
>    va_start (ap, format);
> -  done = vfprintf (stdout, format, ap);
> +  ret = __vfprintf_internal (stdout, format, ap, mode);
>    va_end (ap);
>  
> -  if (flag > 0)
> -    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (stdout);
> -
> -  return done;
> +  return ret;
>  }
>  ldbl_strong_alias (___printf_chk, __printf_chk)

Ok.

> diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
> index cddba37109..984b5e8932 100644
> --- a/debug/snprintf_chk.c
> +++ b/debug/snprintf_chk.c
> @@ -15,25 +15,29 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <stdio.h>
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output into S, according to the format
>     string FORMAT, writing no more than MAXLEN characters.  */
> -/* VARARGS5 */
>  int
> -___snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
> +___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
>  		 const char *format, ...)
>  {
> -  va_list arg;
> -  int done;
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
>  
> -  va_start (arg, format);
> -  done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
> -  va_end (arg);
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  int ret;
>  
> -  return done;
> +  va_start (ap, format);
> +  ret = __vsnprintf_internal (s, maxlen, format, ap, mode);
> +  va_end (ap);
> +
> +  return ret;
>  }
>  ldbl_strong_alias (___snprintf_chk, __snprintf_chk)

Ok.

> diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
> index 78214563dd..649e8ab4d5 100644
> --- a/debug/sprintf_chk.c
> +++ b/debug/sprintf_chk.c
> @@ -15,22 +15,27 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
>  #include <stdarg.h>
> -#include <stdio.h>
> +#include <libio/libioP.h>
> +
>  
>  /* Write formatted output into S, according to the format string FORMAT.  */
> -/* VARARGS4 */
>  int
> -___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
> +___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
>  {
> -  va_list arg;
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  int ret;
> +
> +  if (slen == 0)
> +    __chk_fail ();
>  
> -  va_start (arg, format);
> -  done = __vsprintf_chk (s, flags, slen, format, arg);
> -  va_end (arg);
> +  va_start (ap, format);
> +  ret = __vsprintf_internal (s, slen, format, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  ldbl_strong_alias (___sprintf_chk, __sprintf_chk)

Ok.

> diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c
> index 35887e48e2..186c17751c 100644
> --- a/debug/swprintf_chk.c
> +++ b/debug/swprintf_chk.c
> @@ -16,20 +16,27 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <wchar.h>
> +#include <libio/libioP.h>
>  
> -/* Write formatted output into S, according to the format string FORMAT.  */
> -/* VARARGS5 */
> +
> +/* Write formatted output into S, according to the format string FORMAT,
> +   writing no more than MAXLEN characters.  */
>  int
> -__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len,
> +__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
>  		const wchar_t *format, ...)
>  {
> -  va_list arg;
> -  int done;
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
> +
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, format);
> -  done = __vswprintf_chk (s, n, flag, s_len, format, arg);
> -  va_end (arg);
> +  va_start (ap, format);
> +  ret = __vswprintf_internal (s, maxlen, format, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }

Ok.

> diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
> index dbfebff83f..f5975ea02a 100644
> --- a/debug/vasprintf_chk.c
> +++ b/debug/vasprintf_chk.c
> @@ -24,72 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <malloc.h>
> -#include <string.h>
> -#include <stdio.h>
> -#include <stdio_ext.h>
> -#include "../libio/libioP.h"
> -#include "../libio/strfile.h"
> +#include <libio/libioP.h>
>  
>  int
> -__vasprintf_chk (char **result_ptr, int flags, const char *format,
> -		 va_list args)
> +__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap)
>  {
> -  /* Initial size of the buffer to be used.  Will be doubled each time an
> -     overflow occurs.  */
> -  const size_t init_string_size = 100;
> -  char *string;
> -  _IO_strfile sf;
> -  int ret;
> -  size_t needed;
> -  size_t allocated;
> -  /* No need to clear the memory here (unlike for open_memstream) since
> -     we know we will never seek on the stream.  */
> -  string = (char *) malloc (init_string_size);
> -  if (string == NULL)
> -    return -1;
> -#ifdef _IO_MTSAFE_IO
> -  sf._sbf._f._lock = NULL;
> -#endif
> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, string, init_string_size, string);
> -  sf._sbf._f._flags &= ~_IO_USER_BUF;
> -  sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
> -  sf._s._free_buffer_unused = (_IO_free_type) free;
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>       can only come from read-only format strings.  */
> -  if (flags > 0)
> -    sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
> -  if (ret < 0)
> -    {
> -      free (sf._sbf._f._IO_buf_base);
> -      return ret;
> -    }
> -  /* Only use realloc if the size we need is of the same (binary)
> -     order of magnitude then the memory we allocated.  */
> -  needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1;
> -  allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base;
> -  if ((allocated >> 1) <= needed)
> -    *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
> -  else
> -    {
> -      *result_ptr = (char *) malloc (needed);
> -      if (*result_ptr != NULL)
> -	{
> -	  memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1);
> -	  free (sf._sbf._f._IO_buf_base);
> -	}
> -      else
> -	/* We have no choice, use the buffer we already have.  */
> -	*result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
> -    }
> -  if (*result_ptr == NULL)
> -    *result_ptr = sf._sbf._f._IO_buf_base;
> -  (*result_ptr)[needed - 1] = '\0';
> -  return ret;
> +  return __vasprintf_internal (result_ptr, format, ap, mode);
>  }
> -libc_hidden_def (__vasprintf_chk)

Ok.

> diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
> index 4386127cfe..e04514e355 100644
> --- a/debug/vdprintf_chk.c
> +++ b/debug/vdprintf_chk.c
> @@ -24,41 +24,14 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> -#include <libioP.h>
> -#include <stdio_ext.h>
> +#include <libio/libioP.h>
>  
>  int
> -__vdprintf_chk (int d, int flags, const char *format, va_list arg)
> +__vdprintf_chk (int d, int flag, const char *format, va_list ap)
>  {
> -  struct _IO_FILE_plus tmpfil;
> -  struct _IO_wide_data wd;
> -  int done;
> -
> -#ifdef _IO_MTSAFE_IO
> -  tmpfil.file._lock = NULL;
> -#endif
> -  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
> -  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
> -  _IO_new_file_init_internal (&tmpfil);
> -  if (_IO_file_attach (&tmpfil.file, d) == NULL)
> -    {
> -      _IO_un_link (&tmpfil);
> -      return EOF;
> -    }
> -  tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
> -
> -  _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
> -		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>       can only come from read-only format strings.  */
> -  if (flags > 0)
> -    tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
> -
> -  _IO_FINISH (&tmpfil.file);
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  return done;
> +  return __vdprintf_internal (d, format, ap, mode);
>  }
> -libc_hidden_def (__vdprintf_chk)

Ok.

> diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
> index 5babbf611e..44426e14fd 100644
> --- a/debug/vfprintf_chk.c
> +++ b/debug/vfprintf_chk.c
> @@ -15,28 +15,17 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to FP from the format string FORMAT.  */
>  int
>  ___vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
>  {
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  _IO_acquire_lock_clear_flags2 (fp);
> -  if (flag > 0)
> -    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  done = vfprintf (fp, format, ap);
> -
> -  if (flag > 0)
> -    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (fp);
> -
> -  return done;
> +  return __vfprintf_internal (fp, format, ap, mode);
>  }
> -ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk)
>  ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk)

Ok.

> diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
> index abf2bd6517..3aed308156 100644
> --- a/debug/vfwprintf_chk.c
> +++ b/debug/vfwprintf_chk.c
> @@ -15,27 +15,16 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <wchar.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to FP from the format string FORMAT.  */
>  int
>  __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
>  {
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  _IO_acquire_lock_clear_flags2 (fp);
> -  if (flag > 0)
> -    fp->_flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  done = __vfwprintf_internal (fp, format, ap, 0);
> -
> -  if (flag > 0)
> -    fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (fp);
> -
> -  return done;
> +  return __vfwprintf_internal (fp, format, ap, mode);
>  }
> -libc_hidden_def (__vfwprintf_chk)

Ok.

> diff --git a/debug/asprintf_chk.c b/debug/vobprintf_chk.c
> similarity index 61%
> copy from debug/asprintf_chk.c
> copy to debug/vobprintf_chk.c
> index 9cd4143f2e..bed2c98eac 100644
> --- a/debug/asprintf_chk.c
> +++ b/debug/vobprintf_chk.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Print output of stream to given obstack.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
>  
>     The GNU C Library is free software; you can redistribute it and/or
> @@ -15,22 +16,16 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <libioP.h>
> -#include <stdarg.h>
> -#include <stdio.h>
> +#include <libio/libioP.h>
>  
>  
> -/* Write formatted output from FORMAT to a string which is
> -   allocated with malloc and stored in *STRING_PTR.  */
>  int
> -__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
> +__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
> +		       va_list ap)
>  {
> -  va_list arg;
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  va_start (arg, format);
> -  done = __vasprintf_chk (result_ptr, flags, format, arg);
> -  va_end (arg);
> -
> -  return done;
> +  return __obstack_vprintf_internal (obstack, format, ap, mode);
>  }

Ok.

> diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
> index b3b2c53df2..69fcb721ac 100644
> --- a/debug/vprintf_chk.c
> +++ b/debug/vprintf_chk.c
> @@ -15,27 +15,17 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to stdout from the format string FORMAT.  */
>  int
>  ___vprintf_chk (int flag, const char *format, va_list ap)
>  {
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  _IO_acquire_lock_clear_flags2 (stdout);
> -  if (flag > 0)
> -    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  done = vfprintf (stdout, format, ap);
> -
> -  if (flag > 0)
> -    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (stdout);
> -
> -  return done;
> +  return __vfprintf_internal (stdout, format, ap, mode);
>  }
>  ldbl_strong_alias (___vprintf_chk, __vprintf_chk)

Ok.

> diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
> index 95d286f416..666a83b701 100644
> --- a/debug/vsnprintf_chk.c
> +++ b/debug/vsnprintf_chk.c
> @@ -15,56 +15,22 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> -#include "../libio/strfile.h"
> +#include <libio/libioP.h>
>  
> -extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
>  
>  /* Write formatted output into S, according to the format
>     string FORMAT, writing no more than MAXLEN characters.  */
> -/* VARARGS5 */
>  int
> -___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
> -		  const char *format, va_list args)
> +___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
> +		  const char *format, va_list ap)
>  {
> -  /* XXX Maybe for less strict version do not fail immediately.
> -     Though, maxlen is supposed to be the size of buffer pointed
> -     to by s, so a conforming program can't pass such maxlen
> -     to *snprintf.  */
>    if (__glibc_unlikely (slen < maxlen))
>      __chk_fail ();
>  
> -  _IO_strnfile sf;
> -  int ret;
> -#ifdef _IO_MTSAFE_IO
> -  sf.f._sbf._f._lock = NULL;
> -#endif
> -
> -  /* We need to handle the special case where MAXLEN is 0.  Use the
> -     overflow buffer right from the start.  */
> -  if (maxlen == 0)
> -    {
> -      s = sf.overflow_buf;
> -      maxlen = sizeof (sf.overflow_buf);
> -    }
> -
> -  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
> -  s[0] = '\0';
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>       can only come from read-only format strings.  */
> -  if (flags > 0)
> -    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
> -  ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
> -    *sf.f._sbf._f._IO_write_ptr = '\0';
> -  return ret;
> +  return __vsnprintf_internal (s, maxlen, format, ap, mode);
>  }
> -ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
>  ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)

Ok.

> diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
> index 53f07236ae..c1b1a8da4f 100644
> --- a/debug/vsprintf_chk.c
> +++ b/debug/vsprintf_chk.c
> @@ -15,75 +15,20 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
> -#include "../libio/libioP.h"
> -#include "../libio/strfile.h"
> -
> -
> -static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
> -
> -static int
> -_IO_str_chk_overflow (FILE *fp, int c)
> -{
> -  /* When we come to here this means the user supplied buffer is
> -     filled.  */
> -  __chk_fail ();
> -}
> -
> -
> -static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
> -{
> -  JUMP_INIT_DUMMY,
> -  JUMP_INIT(finish, _IO_str_finish),
> -  JUMP_INIT(overflow, _IO_str_chk_overflow),
> -  JUMP_INIT(underflow, _IO_str_underflow),
> -  JUMP_INIT(uflow, _IO_default_uflow),
> -  JUMP_INIT(pbackfail, _IO_str_pbackfail),
> -  JUMP_INIT(xsputn, _IO_default_xsputn),
> -  JUMP_INIT(xsgetn, _IO_default_xsgetn),
> -  JUMP_INIT(seekoff, _IO_str_seekoff),
> -  JUMP_INIT(seekpos, _IO_default_seekpos),
> -  JUMP_INIT(setbuf, _IO_default_setbuf),
> -  JUMP_INIT(sync, _IO_default_sync),
> -  JUMP_INIT(doallocate, _IO_default_doallocate),
> -  JUMP_INIT(read, _IO_default_read),
> -  JUMP_INIT(write, _IO_default_write),
> -  JUMP_INIT(seek, _IO_default_seek),
> -  JUMP_INIT(close, _IO_default_close),
> -  JUMP_INIT(stat, _IO_default_stat),
> -  JUMP_INIT(showmanyc, _IO_default_showmanyc),
> -  JUMP_INIT(imbue, _IO_default_imbue)
> -};
> -
> +#include <libio/libioP.h>
>  
>  int
> -___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
> -		 va_list args)
> +___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
> +		 va_list ap)
>  {
> -  _IO_strfile f;
> -  int ret;
> -#ifdef _IO_MTSAFE_IO
> -  f._sbf._f._lock = NULL;
> -#endif
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
>    if (slen == 0)
>      __chk_fail ();
>  
> -  _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
> -  s[0] = '\0';
> -  _IO_str_init_static_internal (&f, s, slen - 1, s);
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> -     can only come from read-only format strings.  */
> -  if (flags > 0)
> -    f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
> -
> -  *f._sbf._f._IO_write_ptr = '\0';
> -  return ret;
> +  return __vsprintf_internal (s, slen, format, ap, mode);
>  }
>  ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
>  ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)

Ok.

> diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
> index 4d616f8835..2c6fadd463 100644
> --- a/debug/vswprintf_chk.c
> +++ b/debug/vswprintf_chk.c
> @@ -15,60 +15,21 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <wchar.h>
> -#include "../libio/libioP.h"
> -#include "../libio/strfile.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output into S, according to the format
>     string FORMAT, writing no more than MAXLEN characters.  */
> -/* VARARGS5 */
>  int
> -__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
> -		 const wchar_t *format, va_list args)
> +__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
> +		 const wchar_t *format, va_list ap)
>  {
> -  /* XXX Maybe for less strict version do not fail immediately.
> -     Though, maxlen is supposed to be the size of buffer pointed
> -     to by s, so a conforming program can't pass such maxlen
> -     to *snprintf.  */
>    if (__glibc_unlikely (slen < maxlen))
>      __chk_fail ();
>  
> -  _IO_wstrnfile sf;
> -  struct _IO_wide_data wd;
> -  int ret;
> -#ifdef _IO_MTSAFE_IO
> -  sf.f._sbf._f._lock = NULL;
> -#endif
> -
> -  /* We need to handle the special case where MAXLEN is 0.  Use the
> -     overflow buffer right from the start.  */
> -  if (__glibc_unlikely (maxlen == 0))
> -    /* Since we have to write at least the terminating L'\0' a buffer
> -       length of zero always makes the function fail.  */
> -    return -1;
> -
> -  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
> -  _IO_fwide (&sf.f._sbf._f, 1);
> -  s[0] = L'\0';
> -
> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>       can only come from read-only format strings.  */
> -  if (flags > 0)
> -    sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
> -  ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
> -
> -  if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
> -    /* ISO C99 requires swprintf/vswprintf to return an error if the
> -       output does not fit int he provided buffer.  */
> -    return -1;
> -
> -  /* Terminate the string.  */
> -  *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  return ret;
> +  return __vswprintf_internal (s, maxlen, format, ap, mode);
>  }
> -libc_hidden_def (__vswprintf_chk)

Ok.

> diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
> index fedc7a46bf..f1e8878a54 100644
> --- a/debug/vwprintf_chk.c
> +++ b/debug/vwprintf_chk.c
> @@ -15,27 +15,16 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> -#include <stdarg.h>
> -#include <stdio.h>
> -#include <wchar.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to stdout from the format string FORMAT.  */
>  int
>  __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
>  {
> -  int done;
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>  
> -  _IO_acquire_lock_clear_flags2 (stdout);
> -  if (flag > 0)
> -    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
> -
> -  done = __vfwprintf_internal (stdout, format, ap, 0);
> -
> -  if (flag > 0)
> -    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (stdout);
> -
> -  return done;
> +  return __vfwprintf_internal (stdout, format, ap, mode);
>  }

Ok.

> diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
> index 819050e5af..9f406e95f8 100644
> --- a/debug/wprintf_chk.c
> +++ b/debug/wprintf_chk.c
> @@ -16,29 +16,22 @@
>     <http://www.gnu.org/licenses/>.  */
>  
>  #include <stdarg.h>
> -#include <stdio.h>
> -#include <wchar.h>
> -#include "../libio/libioP.h"
> +#include <libio/libioP.h>
>  
>  
>  /* Write formatted output to stdout from the format string FORMAT.  */
>  int
>  __wprintf_chk (int flag, const wchar_t *format, ...)
>  {
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>    va_list ap;
> -  int done;
> -
> -  _IO_acquire_lock_clear_flags2 (stdout);
> -  if (flag > 0)
> -    stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
> +  int ret;
>  
>    va_start (ap, format);
> -  done = __vfwprintf_internal (stdout, format, ap, 0);
> +  ret = __vfwprintf_internal (stdout, format, ap, mode);
>    va_end (ap);
>  
> -  if (flag > 0)
> -    stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
> -  _IO_release_lock (stdout);
> -
> -  return done;
> +  return ret;
>  }

Ok.

> diff --git a/include/stdio.h b/include/stdio.h
> index 0856d729d9..1b7da0f74d 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -216,11 +216,6 @@ libc_hidden_proto (__open_memstream)
>  libc_hidden_proto (__libc_fatal)
>  rtld_hidden_proto (__libc_fatal)
>  libc_hidden_proto (__vsprintf_chk)
> -libc_hidden_proto (__vsnprintf_chk)
> -libc_hidden_proto (__vfprintf_chk)
> -libc_hidden_proto (__vasprintf_chk)
> -libc_hidden_proto (__vdprintf_chk)
> -libc_hidden_proto (__obstack_vprintf_chk)
>  
>  extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
>  libc_hidden_proto (__fmemopen)

Ok.

> diff --git a/include/wchar.h b/include/wchar.h
> index d0fe45c3a6..86506d28e9 100644
> --- a/include/wchar.h
> +++ b/include/wchar.h
> @@ -216,8 +216,6 @@ extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
>  			    const wchar_t *__restrict __format,
>  			    __gnuc_va_list __arg)
>       /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
> -libc_hidden_proto (__vfwprintf_chk)
> -libc_hidden_proto (__vswprintf_chk)
>  
>  extern int __isoc99_fwscanf (__FILE *__restrict __stream,
>  			     const wchar_t *__restrict __format, ...);

Ok.

> diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
> index 3b1e8292b5..08e4002625 100644
> --- a/libio/iovsprintf.c
> +++ b/libio/iovsprintf.c
> @@ -27,8 +27,47 @@
>  #include "libioP.h"
>  #include "strfile.h"
>  
> +static int __THROW
> +_IO_str_chk_overflow (FILE *fp, int c)
> +{
> +  /* If we get here, the user-supplied buffer would be overrun by
> +     further output.  */
> +  __chk_fail ();
> +}
> +
> +static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
> +{
> +  JUMP_INIT_DUMMY,
> +  JUMP_INIT(finish, _IO_str_finish),
> +  JUMP_INIT(overflow, _IO_str_chk_overflow),
> +  JUMP_INIT(underflow, _IO_str_underflow),
> +  JUMP_INIT(uflow, _IO_default_uflow),
> +  JUMP_INIT(pbackfail, _IO_str_pbackfail),
> +  JUMP_INIT(xsputn, _IO_default_xsputn),
> +  JUMP_INIT(xsgetn, _IO_default_xsgetn),
> +  JUMP_INIT(seekoff, _IO_str_seekoff),
> +  JUMP_INIT(seekpos, _IO_default_seekpos),
> +  JUMP_INIT(setbuf, _IO_default_setbuf),
> +  JUMP_INIT(sync, _IO_default_sync),
> +  JUMP_INIT(doallocate, _IO_default_doallocate),
> +  JUMP_INIT(read, _IO_default_read),
> +  JUMP_INIT(write, _IO_default_write),
> +  JUMP_INIT(seek, _IO_default_seek),
> +  JUMP_INIT(close, _IO_default_close),
> +  JUMP_INIT(stat, _IO_default_stat),
> +  JUMP_INIT(showmanyc, _IO_default_showmanyc),
> +  JUMP_INIT(imbue, _IO_default_imbue)
> +};
> +
> +/* This function is called by regular vsprintf with maxlen set to -1,
> +   and by vsprintf_chk with maxlen set to the size of the output
> +   string.  In the former case, _IO_str_chk_overflow will never be
> +   called; in the latter case it will crash the program if the buffer
> +   overflows.  */
> +
>  int
> -__vsprintf_internal (char *string, const char *format, va_list args,
> +__vsprintf_internal (char *string, size_t maxlen,
> +		     const char *format, va_list args,
>  		     unsigned int mode_flags)
>  {
>    _IO_strfile sf;
> @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
>    sf._sbf._f._lock = NULL;
>  #endif
>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, string, -1, string);
> +  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
> +  string[0] = '\0';
> +  _IO_str_init_static_internal (&sf, string,
> +				(maxlen == -1) ? -1 : maxlen - 1,
> +				string);
> +
>    ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
> -  _IO_putc_unlocked ('\0', &sf._sbf._f);
> +
> +  *sf._sbf._f._IO_write_ptr = '\0';
>    return ret;
>  }
>  
>  int
>  __vsprintf (char *string, const char *format, va_list args)
>  {
> -  return __vsprintf_internal (string, format, args, 0);
> +  return __vsprintf_internal (string, -1, format, args, 0);
>  }
>  
>  ldbl_strong_alias (__vsprintf, _IO_vsprintf)

Ok.

> diff --git a/libio/libio.h b/libio/libio.h
> index c188814ccc..3a93807efc 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -90,7 +90,6 @@ typedef union
>  /* Bits for the _flags2 field.  */
>  #define _IO_FLAGS2_MMAP 1
>  #define _IO_FLAGS2_NOTCANCEL 2
> -#define _IO_FLAGS2_FORTIFY 4
>  #define _IO_FLAGS2_USER_WBUF 8
>  #define _IO_FLAGS2_NOCLOSE 32
>  #define _IO_FLAGS2_CLOEXEC 64

Ok.

> diff --git a/libio/libioP.h b/libio/libioP.h
> index fe52ef1752..ce5228e382 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
>  				       va_list ap, unsigned int mode_flags)
>      attribute_hidden;
>  
> -extern int __vsprintf_internal (char *string, const char *format, va_list ap,
> +/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument,
> +   because it's called by both vsprintf and vsprintf_chk.  If maxlen is
> +   not set to -1, overrunning the buffer will cause a prompt crash.
> +   This is the behavior of ordinary (v)sprintf functions, thus they call
> +   __vsprintf_internal with that argument set to -1.  */
> +extern int __vsprintf_internal (char *string, size_t maxlen,
> +				const char *format, va_list ap,
>  				unsigned int mode_flags)
>      attribute_hidden;
> +
>  extern int __vsnprintf_internal (char *string, size_t maxlen,
>  				 const char *format, va_list ap,
>  				 unsigned int mode_flags)
> @@ -818,26 +825,10 @@ _IO_acquire_lock_fct (FILE **p)
>      _IO_funlockfile (fp);
>  }
>  
> -static inline void
> -__attribute__ ((__always_inline__))
> -_IO_acquire_lock_clear_flags2_fct (FILE **p)
> -{
> -  FILE *fp = *p;
> -  fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
> -  if ((fp->_flags & _IO_USER_LOCK) == 0)
> -    _IO_funlockfile (fp);
> -}
> -
>  #if !defined _IO_MTSAFE_IO && IS_IN (libc)
>  # define _IO_acquire_lock(_fp)						      \
> -  do {									      \
> -    FILE *_IO_acquire_lock_file = NULL
> -# define _IO_acquire_lock_clear_flags2(_fp)				      \
> -  do {									      \
> -    FILE *_IO_acquire_lock_file = (_fp)
> +  do {
>  # define _IO_release_lock(_fp)						      \
> -    if (_IO_acquire_lock_file != NULL)					      \
> -      _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY);		      \
>    } while (0)
>  #endif
>  

Ok.

> diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
> index 77423b292f..447faa4e25 100644
> --- a/stdio-common/sprintf.c
> +++ b/stdio-common/sprintf.c
> @@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
>    int done;
>  
>    va_start (arg, format);
> -  done = __vsprintf_internal (s, format, arg, 0);
> +  done = __vsprintf_internal (s, -1, format, arg, 0);
>    va_end (arg);
>  
>    return done;

Ok.

> diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
> index b0c86e99bd..4cc4261ead 100644
> --- a/stdio-common/vfprintf-internal.c
> +++ b/stdio-common/vfprintf-internal.c
> @@ -1283,8 +1283,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
>    /* Temporarily honor environmental settings.  */
>    if (__ldbl_is_dbl)
>      mode_flags |= PRINTF_LDBL_IS_DBL;
> -  if (s->_flags2 & _IO_FLAGS2_FORTIFY)
> -    mode_flags |= PRINTF_FORTIFY;
>  
>    /* Orient the stream.  */
>  #ifdef ORIENT

Ok.

> diff --git a/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h
> index 4a40618545..25ccd07f29 100644
> --- a/sysdeps/generic/stdio-lock.h
> +++ b/sysdeps/generic/stdio-lock.h
> @@ -54,15 +54,8 @@ __libc_lock_define_recursive (typedef, _IO_lock_t)
>  	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
>  	= (_fp);							      \
>      _IO_flockfile (_IO_acquire_lock_file);
> -#  define _IO_acquire_lock_clear_flags2(_fp) \
> -  do {									      \
> -    FILE *_IO_acquire_lock_file						      \
> -	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
> -	= (_fp);							      \
> -    _IO_flockfile (_IO_acquire_lock_file);
>  # else
>  #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
> -#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
>  # endif
>  # define _IO_release_lock(_fp) ; } while (0)
>  

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 958bbc1834..59b2c9fcdd 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -179,7 +179,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
>  {
>    int done;
>    __no_long_double = 1;
> -  done = __vsprintf_internal (string, fmt, ap, 0);
> +  done = __vsprintf_internal (string, -1, fmt, ap, 0);
>    __no_long_double = 0;
>    return done;
>  }
> @@ -579,7 +579,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = __vfprintf_chk (s, flag, fmt, ap);
> +  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -591,7 +591,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
>  {
>    int res;
>    set_no_long_double ();
> -  res = __vfwprintf_chk (s, flag, fmt, ap);
> +  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -609,9 +609,13 @@ attribute_compat_text_section
>  __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
>  			 const char *fmt, va_list ap)
>  {
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
> +
>    int res;
>    __no_long_double = 1;
> -  res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap);
> +  res = __vsnprintf_internal (string, maxlen, fmt, ap,
> +			      (flag > 0) ? PRINTF_FORTIFY : 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -622,9 +626,13 @@ attribute_compat_text_section
>  __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
>  			va_list ap)
>  {
> +  if (slen == 0)
> +    __chk_fail ();
> +
>    int res;
>    __no_long_double = 1;
> -  res = __vsprintf_chk (string, flag, slen, fmt, ap);
> +  res = __vsprintf_internal (string, slen, fmt, ap,
> +			     (flag > 0) ? PRINTF_FORTIFY : 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -635,9 +643,13 @@ attribute_compat_text_section
>  __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
>  			 const wchar_t *fmt, va_list ap)
>  {
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
> +
>    int res;
>    __no_long_double = 1;
> -  res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap);
> +  res = __vswprintf_internal (string, maxlen, fmt, ap,
> +			      (flag > 0) ? PRINTF_FORTIFY : 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -670,7 +682,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
>  {
>    int res;
>    __no_long_double = 1;
> -  res = __vasprintf_chk (ptr, flag, fmt, arg);
> +  res = __vasprintf_internal (ptr, fmt, arg,
> +			      (flag > 0) ? PRINTF_FORTIFY : 0);
>    __no_long_double = 0;
>    return res;
>  }
> @@ -696,7 +709,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
>  {
>    int res;
>    set_no_long_double ();
> -  res = __vdprintf_chk (d, flag, fmt, arg);
> +  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
>    clear_no_long_double ();
>    return res;
>  }
> @@ -723,7 +736,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
>  {
>    int res;
>    __no_long_double = 1;
> -  res = __obstack_vprintf_chk (obstack, flag, fmt, arg);
> +  res = __obstack_vprintf_internal (obstack, fmt, arg,
> +				    (flag > 0) ? PRINTF_FORTIFY : 0);
>    __no_long_double = 0;
>    return res;
>  }

Ok.

> diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
> index 5b9782452f..1d6a81c5bf 100644
> --- a/sysdeps/nptl/stdio-lock.h
> +++ b/sysdeps/nptl/stdio-lock.h
> @@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
>  	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \
>  	= (_fp);							      \
>      _IO_flockfile (_IO_acquire_lock_file);
> -#  define _IO_acquire_lock_clear_flags2(_fp) \
> -  do {									      \
> -    FILE *_IO_acquire_lock_file						      \
> -	__attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))	      \
> -	= (_fp);							      \
> -    _IO_flockfile (_IO_acquire_lock_file);
>  # else
>  #  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
> -#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
>  # endif
>  # define _IO_release_lock(_fp) ; } while (0)

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.
  2018-11-15 21:53 ` [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL " Gabriel F. T. Gomes
@ 2018-11-22 18:13   ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-11-22 18:13 UTC (permalink / raw)
  To: libc-alpha



On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> Changed since v2:
> 
>   - Removed #ifdef ASSEMBLER since no longer used.

LGTM, thanks.

> 
> Changed since v1:
> 
>   - Removed libc_hidden_def and libc_hidden_proto from all of the
>     __nldbl_*printf* function, since they are no longer called from
>     within glibc, only from nldbl-*printf*.c files (libnldbl_nonshared.a)
> 
> -- 8< --
> After all that prep work, nldbl-compat.c can now use PRINTF_LDBL_IS_DBL
> instead of __no_long_double to control the behavior of printf-like
> functions; this is the last thing we needed __no_long_double for, so it
> can go away entirely.
> 
> Tested for powerpc and powerpc64le.
> 
> 2018-10-25  Zack Weinberg  <zackw@panix.com>
> 	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
> 
> 	* stdio-common/vfprintf-internal.c
> 	(__vfprintf_internal, __vfwprintf_internal): Don't use __ldbl_is_dbl.
> 	* sysdeps/generic/math_ldbl_opt.h: Remove __ldbl_is_dbl.
> 	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h: Remove __ldbl_is_dbl
> 	and __no_long_double.
> 	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.c: Remove file.
> 	* sysdeps/ieee754/ldbl-opt/Makefile (routines): Remove math_ldbl_opt.
> 	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Remove
> 	libc_hidden_proto and libc_hidden_def from all __nldbl_*printf*
> 	and __nldbl_*syslog* functions.
> 	(__nldbl_cleanup, set_no_long_double, clear_no_long_double): Remove.
> 	(__nldbl___asprintf, __nldbl_dprintf, __nldbl_fprintf)
> 	(__nldbl_fwprintf, __nldbl_printf, __nldbl_sprintf)
> 	(__nldbl_vfprintf, __nldbl___vsprintf, __nldbl_obstack_vprintf)
> 	(__ndlbl_obstack_printf, __nldbl_snprintf, __nldbl_swprintf)
> 	(__nldbl_vasprintf, __nldbl_vdprintf, __nldbl_vfwprintf)
> 	(__nldbl_vprintf, __nldbl_vsnprintf, __ndlbl_vswprintf)
> 	(__nldbl_vwprintf, __nldbl_wprintf):
> 	Directly call the appropriate __v*printf_internal routine, passing
> 	PRINTF_LDBL_IS_DBL.  Do not mess with __no_long_double. Normalize
> 	variable names.
> 	(__nldbl___fprintf_chk, __nldbl___fwprintf_chk)
> 	(__nldbl___printf_chk, __nldbl___snprintf_chk)
> 	(__nldbl___sprintf_chk, __nldbl___swprintf_chk)
> 	(__nldbl___vfprintf_chk, __nldbl___vfwprintf_chk)
> 	(__nldbl___vprintf_chk, __nldbl___vsnprintf_chk)
> 	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
> 	(__nldbl___vwprintf_chk, __nldbl___wprintf_chk)
> 	(__nldbl___vasprintf_chk, __nldbl___asprintf_chk)
> 	(__nldbl___vdprintf_chk, __nldbl___dprintf_chk)
> 	(__nldbl___obstack_vprintf_chk, __nldbl___obstack_printf_chk):
> 	Likewise, and also pass PRINTF_FORTIFY when appropriate.
> 	(__nldbl_syslog, __nldbl_vsyslog):
> 	Directly call __vsyslog_internal, passing PRINTF_LDBL_IS_DBL.
> 	(__nldbl_syslog_chk): Likewise, and also pass PRINTF_FORTIFY when
> 	appropriate.
> 	(__nldbl_vsyslog_chk): Likewise, and also pass PRINTF_FORTIFY when
> 	appropriate.
> ---
>  stdio-common/vfprintf-internal.c         |   4 -
>  sysdeps/generic/math_ldbl_opt.h          |   1 -
>  sysdeps/ieee754/ldbl-opt/Makefile        |   2 +-
>  sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h |   7 -
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c  | 504 +++++++++++++++----------------
>  5 files changed, 238 insertions(+), 280 deletions(-)
> 
> diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
> index 4cc4261ead..61769e0ce1 100644
> --- a/stdio-common/vfprintf-internal.c
> +++ b/stdio-common/vfprintf-internal.c
> @@ -1280,10 +1280,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
>       0 if unknown.  */
>    int readonly_format = 0;
>  
> -  /* Temporarily honor environmental settings.  */
> -  if (__ldbl_is_dbl)
> -    mode_flags |= PRINTF_LDBL_IS_DBL;
> -
>    /* Orient the stream.  */
>  #ifdef ORIENT
>    ORIENT;

Ok.

> diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
> index 92f670dff7..fbd2c82e2f 100644
> --- a/sysdeps/generic/math_ldbl_opt.h
> +++ b/sysdeps/generic/math_ldbl_opt.h
> @@ -15,4 +15,3 @@
>  #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
>  #define ldbl_compat_symbol(lib, local, symbol, version) \
>    compat_symbol (lib, local, symbol, version)
> -#define __ldbl_is_dbl 0

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
> index 6854413fa3..64fdb8cb9e 100644
> --- a/sysdeps/ieee754/ldbl-opt/Makefile
> +++ b/sysdeps/ieee754/ldbl-opt/Makefile
> @@ -8,7 +8,7 @@ endif
>  
>  ifeq ($(subdir),math)
>  libm-routines += s_nexttowardfd
> -routines += math_ldbl_opt nldbl-compat
> +routines += nldbl-compat
>  
>  extra-libs += libnldbl
>  libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> index 1c49036f7b..cbe8156e39 100644
> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> @@ -40,10 +40,3 @@
>    weak_alias (local, symbol)
>  # endif
>  #endif
> -
> -#ifndef __ASSEMBLER__
> -/* Set temporarily to non-zero if long double should be considered
> -   the same as double.  */
> -extern __thread int __no_long_double attribute_tls_model_ie attribute_hidden;
> -# define __ldbl_is_dbl __builtin_expect (__no_long_double, 0)
> -#endif

Ok.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 59b2c9fcdd..f6dd81759d 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -30,43 +30,15 @@
>  
>  #include "nldbl-compat.h"
>  
> -libc_hidden_proto (__nldbl_vfprintf)
>  libc_hidden_proto (__nldbl_vsscanf)
> -libc_hidden_proto (__nldbl_vsprintf)
>  libc_hidden_proto (__nldbl_vfscanf)
>  libc_hidden_proto (__nldbl_vfwscanf)
> -libc_hidden_proto (__nldbl_vdprintf)
>  libc_hidden_proto (__nldbl_vswscanf)
> -libc_hidden_proto (__nldbl_vfwprintf)
> -libc_hidden_proto (__nldbl_vswprintf)
> -libc_hidden_proto (__nldbl_vsnprintf)
> -libc_hidden_proto (__nldbl_vasprintf)
> -libc_hidden_proto (__nldbl_obstack_vprintf)
> -libc_hidden_proto (__nldbl___vfwprintf_chk)
> -libc_hidden_proto (__nldbl___vsnprintf_chk)
> -libc_hidden_proto (__nldbl___vfprintf_chk)
> -libc_hidden_proto (__nldbl___vsyslog_chk)
> -libc_hidden_proto (__nldbl___vsprintf_chk)
> -libc_hidden_proto (__nldbl___vswprintf_chk)
> -libc_hidden_proto (__nldbl___vasprintf_chk)
> -libc_hidden_proto (__nldbl___vdprintf_chk)
> -libc_hidden_proto (__nldbl___obstack_vprintf_chk)
>  libc_hidden_proto (__nldbl___isoc99_vsscanf)
>  libc_hidden_proto (__nldbl___isoc99_vfscanf)
>  libc_hidden_proto (__nldbl___isoc99_vswscanf)
>  libc_hidden_proto (__nldbl___isoc99_vfwscanf)
>  
> -static void
> -__nldbl_cleanup (void *arg)
> -{
> -  __no_long_double = 0;
> -}
> -
> -#define set_no_long_double() \
> -  __libc_cleanup_push (__nldbl_cleanup, NULL); __no_long_double = 1
> -#define clear_no_long_double() \
> -  __no_long_double = 0; __libc_cleanup_pop (0)
> -
>  /* Compatibility with IEEE double as long double.
>     IEEE quad long double is used by default for most programs, so
>     we don't need to split this into one file per function for the
> @@ -76,14 +48,14 @@ int
>  attribute_compat_text_section
>  __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vasprintf (string_ptr, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vasprintf_internal (string_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  weak_alias (__nldbl___asprintf, __nldbl_asprintf)
>  
> @@ -91,28 +63,28 @@ int
>  attribute_compat_text_section
>  __nldbl_dprintf (int d, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vdprintf (d, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_fprintf (FILE *stream, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfprintf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
>  
> @@ -120,28 +92,28 @@ int
>  attribute_compat_text_section weak_function
>  __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfwprintf (stream, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_printf (const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfprintf (stdout, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  strong_alias (__nldbl_printf, __nldbl__IO_printf)
>  
> @@ -149,14 +121,14 @@ int
>  attribute_compat_text_section
>  __nldbl_sprintf (char *s, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vsprintf (s, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vsprintf_internal (s, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  strong_alias (__nldbl_sprintf, __nldbl__IO_sprintf)
>  
> @@ -164,123 +136,93 @@ int
>  attribute_compat_text_section
>  __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
>  {
> -  int done;
> -  set_no_long_double ();
> -  done = __vfprintf_internal (s, fmt, ap, 0);
> -  clear_no_long_double ();
> -  return done;
> +  return __vfprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vfprintf)
>  strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
>  {
> -  int done;
> -  __no_long_double = 1;
> -  done = __vsprintf_internal (string, -1, fmt, ap, 0);
> -  __no_long_double = 0;
> -  return done;
> +  return __vsprintf_internal (string, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
>  strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
>  weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
> -libc_hidden_def (__nldbl_vsprintf)
>  
>  int
>  attribute_compat_text_section
>  __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
>  			 va_list ap)
>  {
> -  int done;
> -  __no_long_double = 1;
> -  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
> -  __no_long_double = 0;
> -  return done;
> +  return __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_obstack_vprintf)
>  
>  int
>  attribute_compat_text_section
>  __nldbl_obstack_printf (struct obstack *obstack, const char *fmt, ...)
>  {
> -  int result;
> +  int ret;
>    va_list ap;
>    va_start (ap, fmt);
> -  result = __nldbl_obstack_vprintf (obstack, fmt, ap);
> +  ret = __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
>    va_end (ap);
> -  return result;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section weak_function
>  __nldbl_snprintf (char *s, size_t maxlen, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vsnprintf (s, maxlen, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vsnprintf_internal (s, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vswprintf (s, n, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vswprintf_internal (s, n, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section weak_function
>  __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
> -  __no_long_double = 0;
> -  return res;
> +  return __vasprintf_internal (result_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vasprintf)
>  
>  int
>  attribute_compat_text_section
> -__nldbl_vdprintf (int d, const char *fmt, va_list arg)
> +__nldbl_vdprintf (int d, const char *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vdprintf_internal (d, fmt, arg, 0);
> -  clear_no_long_double ();
> -  return res;
> +  return __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vdprintf)
>  
>  int
>  attribute_compat_text_section weak_function
>  __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfwprintf_internal (s, fmt, ap, 0);
> -  clear_no_long_double ();
> -  return res;
> +  return __vfwprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vfwprintf)
>  
>  int
>  attribute_compat_text_section
>  __nldbl_vprintf (const char *fmt, va_list ap)
>  {
> -  return __nldbl_vfprintf (stdout, fmt, ap);
> +  return __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
>  
>  int
> @@ -288,13 +230,8 @@ attribute_compat_text_section
>  __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
>  		   va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
> -  __no_long_double = 0;
> -  return res;
> +  return __vsnprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vsnprintf)
>  weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
>  
>  int
> @@ -302,33 +239,28 @@ attribute_compat_text_section weak_function
>  __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
>  		   va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
> -  __no_long_double = 0;
> -  return res;
> +  return __vswprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
> -libc_hidden_def (__nldbl_vswprintf)
>  
>  int
>  attribute_compat_text_section
>  __nldbl_vwprintf (const wchar_t *fmt, va_list ap)
>  {
> -  return __nldbl_vfwprintf (stdout, fmt, ap);
> +  return __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl_wprintf (const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl_vfwprintf (stdout, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> @@ -491,42 +423,51 @@ int
>  attribute_compat_text_section
>  __nldbl___fprintf_chk (FILE *stream, int flag, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vfprintf_chk (stream, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfprintf_internal (stream, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vfwprintf_chk (stream, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwprintf_internal (stream, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___printf_chk (int flag, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vfprintf_chk (stdout, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfprintf_internal (stdout, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
> @@ -534,74 +475,94 @@ attribute_compat_text_section
>  __nldbl___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
>  			const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vsnprintf_chk (s, maxlen, flag, slen, fmt, arg);
> -  va_end (arg);
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  return done;
> +  va_start (ap, fmt);
> +  ret = __vsnprintf_internal (s, maxlen, fmt, ap, mode);
> +  va_end (ap);
> +
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___sprintf_chk (char *s, int flag, size_t slen, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  if (slen == 0)
> +    __chk_fail ();
> +
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vsprintf_chk (s, flag, slen, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vsprintf_internal (s, slen, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
> +__nldbl___swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
>  			const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  if (__glibc_unlikely (slen < maxlen))
> +    __chk_fail ();
> +
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vswprintf_chk (s, n, flag, slen, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vswprintf_internal (s, maxlen, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
> -  clear_no_long_double ();
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vfprintf_internal (s, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vfprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
> -  clear_no_long_double ();
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vfwprintf_internal (s, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vfwprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___vprintf_chk (int flag, const char *fmt, va_list ap)
>  {
> -  return __nldbl___vfprintf_chk (stdout, flag, fmt, ap);
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vfprintf_internal (stdout, fmt, ap, mode);
>  }
>  
>  int
> @@ -612,14 +573,12 @@ __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
>    if (__glibc_unlikely (slen < maxlen))
>      __chk_fail ();
>  
> -  int res;
> -  __no_long_double = 1;
> -  res = __vsnprintf_internal (string, maxlen, fmt, ap,
> -			      (flag > 0) ? PRINTF_FORTIFY : 0);
> -  __no_long_double = 0;
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vsnprintf_internal (string, maxlen, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vsnprintf_chk)
>  
>  int
>  attribute_compat_text_section
> @@ -629,14 +588,12 @@ __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
>    if (slen == 0)
>      __chk_fail ();
>  
> -  int res;
> -  __no_long_double = 1;
> -  res = __vsprintf_internal (string, slen, fmt, ap,
> -			     (flag > 0) ? PRINTF_FORTIFY : 0);
> -  __no_long_double = 0;
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vsprintf_internal (string, slen, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vsprintf_chk)
>  
>  int
>  attribute_compat_text_section
> @@ -646,116 +603,125 @@ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
>    if (__glibc_unlikely (slen < maxlen))
>      __chk_fail ();
>  
> -  int res;
> -  __no_long_double = 1;
> -  res = __vswprintf_internal (string, maxlen, fmt, ap,
> -			      (flag > 0) ? PRINTF_FORTIFY : 0);
> -  __no_long_double = 0;
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vswprintf_internal (string, maxlen, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vswprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___vwprintf_chk (int flag, const wchar_t *fmt, va_list ap)
>  {
> -  return __nldbl___vfwprintf_chk (stdout, flag, fmt, ap);
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vfwprintf_internal (stdout, fmt, ap, mode);
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vfwprintf_chk (stdout, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vfwprintf_internal (stdout, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
> +__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __vasprintf_internal (ptr, fmt, arg,
> -			      (flag > 0) ? PRINTF_FORTIFY : 0);
> -  __no_long_double = 0;
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vasprintf_internal (ptr, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vasprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___asprintf_chk (char **ptr, int flag, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vasprintf_chk (ptr, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vasprintf_internal (ptr, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
> -__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
> +__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list ap)
>  {
> -  int res;
> -  set_no_long_double ();
> -  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
> -  clear_no_long_double ();
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vdprintf_internal (d, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___vdprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___dprintf_chk (int d, int flag, const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___vdprintf_chk (d, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __vdprintf_internal (d, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  int
>  attribute_compat_text_section
>  __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
> -			       const char *fmt, va_list arg)
> +			       const char *fmt, va_list ap)
>  {
> -  int res;
> -  __no_long_double = 1;
> -  res = __obstack_vprintf_internal (obstack, fmt, arg,
> -				    (flag > 0) ? PRINTF_FORTIFY : 0);
> -  __no_long_double = 0;
> -  return res;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __obstack_vprintf_internal (obstack, fmt, ap, mode);
>  }
> -libc_hidden_def (__nldbl___obstack_vprintf_chk)
>  
>  int
>  attribute_compat_text_section
>  __nldbl___obstack_printf_chk (struct obstack *obstack, int flag,
>  			      const char *fmt, ...)
>  {
> -  va_list arg;
> -  int done;
> +  va_list ap;
> +  int ret;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -  va_start (arg, fmt);
> -  done = __nldbl___obstack_vprintf_chk (obstack, flag, fmt, arg);
> -  va_end (arg);
> +  va_start (ap, fmt);
> +  ret = __obstack_vprintf_internal (obstack, fmt, ap, mode);
> +  va_end (ap);
>  
> -  return done;
> +  return ret;
>  }
>  
>  extern __typeof (printf_size) __printf_size;
> @@ -837,18 +803,28 @@ __nldbl_syslog (int pri, const char *fmt, ...)
>  {
>    va_list ap;
>    va_start (ap, fmt);
> -  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
> +  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
>    va_end (ap);
>  }
>  
> +void
> +attribute_compat_text_section
> +__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
> +{
> +  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
> +}
> +
>  void
>  attribute_compat_text_section
>  __nldbl___syslog_chk (int pri, int flag, const char *fmt, ...)
>  {
>    va_list ap;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
>    va_start (ap, fmt);
> -  __nldbl___vsyslog_chk (pri, flag, fmt, ap);
> +  __vsyslog_internal (pri, fmt, ap, mode);
>    va_end(ap);
>  }
>  
> @@ -856,17 +832,11 @@ void
>  attribute_compat_text_section
>  __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
>  {
> -  set_no_long_double ();
> -  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
> -  clear_no_long_double ();
> -}
> -libc_hidden_def (__nldbl___vsyslog_chk)
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
>  
> -void
> -attribute_compat_text_section
> -__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
> -{
> -  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
> +  __vsyslog_internal (pri, fmt, ap, mode);
>  }
>  
>  int
> 

Ok.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio
  2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
                   ` (6 preceding siblings ...)
  2018-11-15 21:53 ` [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL " Gabriel F. T. Gomes
@ 2018-12-02 11:53 ` Florian Weimer
  2018-12-03 13:52   ` Gabriel F. T. Gomes
  7 siblings, 1 reply; 39+ messages in thread
From: Florian Weimer @ 2018-12-02 11:53 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha, Adhemerval Zanella

* Gabriel F. T. Gomes:

> Patches 2, 3, and 5 did not change, but since they depend on previous
> patches in this set, I'm sending them again for completeness.
>
> I added a `Changed since v2' section to each patch in the set describing
> the changes.  But I didn't mention the removal of DCO's signed-off-by in
> each one of them to avoid repetition.
>
> Also, I'm using `git format-patch -M90% -C', as suggested by Adhemerval.

What's the status here?

I think Adhemerval has reviewed all seven patches (and I looked at an
earlier version too), so this should be ready to commit.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio
  2018-12-02 11:53 ` [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Florian Weimer
@ 2018-12-03 13:52   ` Gabriel F. T. Gomes
  2018-12-05 21:00     ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-03 13:52 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha, Adhemerval Zanella

On Sun, 02 Dec 2018, Florian Weimer wrote:

>What's the status here?
>
>I think Adhemerval has reviewed all seven patches (and I looked at an
>earlier version too), so this should be ready to commit.

I'll try to get back to it today (no later than tomorrow).

Thanks for your reviews.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-11-22 17:35   ` Adhemerval Zanella
@ 2018-12-04 15:15     ` Gabriel F. T. Gomes
  2018-12-04 17:37       ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-04 15:15 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Thu, 22 Nov 2018, Adhemerval Zanella wrote:

>On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
>> From: Zack Weinberg <zackw@panix.com>
>>
> 
>The patch looks ok with the exception of the part where it adapts some symbol
>to set _IO_FLAGS2_SCANF_STD on _flags2 *without* acquiring the lock previously.
>I also see the idea of second patch is also to get rid of such mechanism, so
>maybe one option is to combine both patches.
>
>> [...]
>>
>>  int
>>  __isoc99_sscanf (const char *s, const char *format, ...)
>>  {
>>    va_list arg;
>>    int done;
>> +  _IO_strfile sf;
>> +  FILE *f = _IO_strfile_read (&sf, s);
>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>  
>>    va_start (arg, format);
>> -  done = __isoc99_vsscanf (s, format, arg);
>> +  done = __vfscanf_internal (f, format, arg, 0);
>>    va_end (arg);
>>  
>>    return done;  
>
>I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
>Wouldn't be more consistent to fold the second patch in this set, which replace
>_IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
>removed in a subsequent patch?

I have no problems with folding the two patches, however I did not
understand why the lock needs to be acquired/released.  In this function,
`sf' is a variable on the stack, so it cannot be accessed elsewhere by
another thread (compare that against the `stream' argument to
__isoc99_vfscanf, below, where I agree that the lock is needed).

Did I miss something?

>> diff --git a/stdio-common/isoc99_vfscanf.c
>> b/stdio-common/isoc99_vfscanf.c index b80e05f8db..c96ca831ae 100644
>> --- a/stdio-common/isoc99_vfscanf.c
>> +++ b/stdio-common/isoc99_vfscanf.c
>> @@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format,
>> va_list args) 
>>    _IO_acquire_lock_clear_flags2 (stream);
>>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>> -  done = _IO_vfscanf (stream, format, args, NULL);
>> +  done = __vfscanf_internal (stream, format, args, 0);
>>    _IO_release_lock (stream);
>>    return done;
>>  }  

For reference, __isoc99_vfscanf lock acquire/release.

>>  int
>>  __isoc99_vsscanf (const char *string, const char *format, va_list args)
>>  {
>> -  int ret;
>>    _IO_strfile sf;
>> -#ifdef _IO_MTSAFE_IO
>> -  sf._sbf._f._lock = NULL;
>> -#endif
>> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
>> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
>> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
>> -  return ret;
>> +  FILE *f = _IO_strfile_read (&sf, string);
>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>> +  return __vfscanf_internal (f, format, args, 0);
>>  }
>>  libc_hidden_def (__isoc99_vsscanf)  
>
>As before I think it requires to acquire the file lock before setting
>_flags2.

Same as __isoc99_sscanf.

>>  __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
>>  {
>>    va_list arg;
>>    int done;
>> +  _IO_strfile sf;
>> +  struct _IO_wide_data wd;
>> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>  
>>    va_start (arg, format);
>> -  done = __isoc99_vswscanf (s, format, arg);
>> +  done = __vfwscanf_internal (f, format, arg, 0);
>>    va_end (arg);
>>  
>>    return done;  
>
>As before I think it requires to acquire the file lock before setting
>_flags2.

Likewise.

>>  int
>>  __isoc99_vswscanf (const wchar_t *string, const wchar_t *format,
>> va_list args) {
>> -  int ret;
>>    _IO_strfile sf;
>>    struct _IO_wide_data wd;
>> -#ifdef _IO_MTSAFE_IO
>> -  sf._sbf._f._lock = NULL;
>> -#endif
>> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
>> -  _IO_fwide (&sf._sbf._f, 1);
>> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
>> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
>> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
>> -  return ret;
>> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>> +  return __vfwscanf_internal (f, format, args, 0);
>>  }
>>  libc_hidden_def (__isoc99_vswscanf)  
>
>As before I think it requires to acquire the file lock before setting
>_flags2.

Likewise.


I'm willing to squash the first and second patches anyway...  I just want
to make sure I understand your concern.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-11-22 18:11   ` Adhemerval Zanella
@ 2018-12-04 16:20     ` Gabriel F. T. Gomes
  2018-12-04 17:40       ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-04 16:20 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Thu, 22 Nov 2018, Adhemerval Zanella wrote:

>On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
>> From: Zack Weinberg <zackw@panix.com>
>
>I don't recall exactly which patch was the one that actually fixes BZ#11319,
>my previous indication was 'Add __v*printf_internal with flags arguments.'.
>Could you recheck it please?

Yes, sure.  This patch fixes the bug, because of the following change...

>>  int
>> -__vdprintf_chk (int d, int flags, const char *format, va_list arg)
>> +__vdprintf_chk (int d, int flag, const char *format, va_list ap)
>>  {
>> -  struct _IO_FILE_plus tmpfil;
>> -  struct _IO_wide_data wd;
>> -  int done;
>> -
>> -#ifdef _IO_MTSAFE_IO
>> -  tmpfil.file._lock = NULL;
>> -#endif
>> -  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
>> -  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
>> -  _IO_new_file_init_internal (&tmpfil);
>> -  if (_IO_file_attach (&tmpfil.file, d) == NULL)
>> -    {
>> -      _IO_un_link (&tmpfil);
>> -      return EOF;
>> -    }
>> -  tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
>> -
>> -  _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
>> -		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
>> -
>> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>>       can only come from read-only format strings.  */
>> -  if (flags > 0)
>> -    tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
>> -
>> -  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
>> -
>> -  _IO_FINISH (&tmpfil.file);
>> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>>  
>> -  return done;
>> +  return __vdprintf_internal (d, format, ap, mode);

Notice that the call to __vfprintf_internal was replaced with a call to
__vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).

I wrote a test case to check this and I confirm that the problem is
reproducible without this patch, but not with it.  (I'll clean the test up
and send to this list...  Maybe it should get in to avoid regressions).

[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
  2018-12-04 15:15     ` Gabriel F. T. Gomes
@ 2018-12-04 17:37       ` Adhemerval Zanella
  0 siblings, 0 replies; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-04 17:37 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 04/12/2018 13:14, Gabriel F. T. Gomes wrote:
> On Thu, 22 Nov 2018, Adhemerval Zanella wrote:
> 
>> On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
>>> From: Zack Weinberg <zackw@panix.com>
>>>
>>
>> The patch looks ok with the exception of the part where it adapts some symbol
>> to set _IO_FLAGS2_SCANF_STD on _flags2 *without* acquiring the lock previously.
>> I also see the idea of second patch is also to get rid of such mechanism, so
>> maybe one option is to combine both patches.
>>
>>> [...]
>>>
>>>  int
>>>  __isoc99_sscanf (const char *s, const char *format, ...)
>>>  {
>>>    va_list arg;
>>>    int done;
>>> +  _IO_strfile sf;
>>> +  FILE *f = _IO_strfile_read (&sf, s);
>>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>>  
>>>    va_start (arg, format);
>>> -  done = __isoc99_vsscanf (s, format, arg);
>>> +  done = __vfscanf_internal (f, format, arg, 0);
>>>    va_end (arg);
>>>  
>>>    return done;  
>>
>> I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
>> Wouldn't be more consistent to fold the second patch in this set, which replace
>> _IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
>> removed in a subsequent patch?
> 
> I have no problems with folding the two patches, however I did not
> understand why the lock needs to be acquired/released.  In this function,
> `sf' is a variable on the stack, so it cannot be accessed elsewhere by
> another thread (compare that against the `stream' argument to
> __isoc99_vfscanf, below, where I agree that the lock is needed).
> 
> Did I miss something?

You are right, the change looks correct.

> 
>>> diff --git a/stdio-common/isoc99_vfscanf.c
>>> b/stdio-common/isoc99_vfscanf.c index b80e05f8db..c96ca831ae 100644
>>> --- a/stdio-common/isoc99_vfscanf.c
>>> +++ b/stdio-common/isoc99_vfscanf.c
>>> @@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format,
>>> va_list args) 
>>>    _IO_acquire_lock_clear_flags2 (stream);
>>>    stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>> -  done = _IO_vfscanf (stream, format, args, NULL);
>>> +  done = __vfscanf_internal (stream, format, args, 0);
>>>    _IO_release_lock (stream);
>>>    return done;
>>>  }  
> 
> For reference, __isoc99_vfscanf lock acquire/release.

Ack as before.

> 
>>>  int
>>>  __isoc99_vsscanf (const char *string, const char *format, va_list args)
>>>  {
>>> -  int ret;
>>>    _IO_strfile sf;
>>> -#ifdef _IO_MTSAFE_IO
>>> -  sf._sbf._f._lock = NULL;
>>> -#endif
>>> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>>> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>>> -  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
>>> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
>>> -  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
>>> -  return ret;
>>> +  FILE *f = _IO_strfile_read (&sf, string);
>>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>> +  return __vfscanf_internal (f, format, args, 0);
>>>  }
>>>  libc_hidden_def (__isoc99_vsscanf)  
>>
>> As before I think it requires to acquire the file lock before setting
>> _flags2.
> 
> Same as __isoc99_sscanf.

Ack as before.

> 
>>>  __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
>>>  {
>>>    va_list arg;
>>>    int done;
>>> +  _IO_strfile sf;
>>> +  struct _IO_wide_data wd;
>>> +  FILE *f = _IO_strfile_readw (&sf, &wd, s);
>>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>>  
>>>    va_start (arg, format);
>>> -  done = __isoc99_vswscanf (s, format, arg);
>>> +  done = __vfwscanf_internal (f, format, arg, 0);
>>>    va_end (arg);
>>>  
>>>    return done;  
>>
>> As before I think it requires to acquire the file lock before setting
>> _flags2.
> 
> Likewise.

Ack as before.

> 
>>>  int
>>>  __isoc99_vswscanf (const wchar_t *string, const wchar_t *format,
>>> va_list args) {
>>> -  int ret;
>>>    _IO_strfile sf;
>>>    struct _IO_wide_data wd;
>>> -#ifdef _IO_MTSAFE_IO
>>> -  sf._sbf._f._lock = NULL;
>>> -#endif
>>> -  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
>>> -  _IO_fwide (&sf._sbf._f, 1);
>>> -  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
>>> -  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
>>> -  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
>>> -  return ret;
>>> +  FILE *f = _IO_strfile_readw (&sf, &wd, string);
>>> +  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>>> +  return __vfwscanf_internal (f, format, args, 0);
>>>  }
>>>  libc_hidden_def (__isoc99_vswscanf)  
>>
>> As before I think it requires to acquire the file lock before setting
>> _flags2.
> 
> Likewise.
> 
> 
> I'm willing to squash the first and second patches anyway...  I just want
> to make sure I understand your concern.
> 

Current patch looks sorry, sorry for the noise.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-04 16:20     ` Gabriel F. T. Gomes
@ 2018-12-04 17:40       ` Adhemerval Zanella
  2018-12-04 18:01         ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-04 17:40 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 04/12/2018 14:19, Gabriel F. T. Gomes wrote:
> On Thu, 22 Nov 2018, Adhemerval Zanella wrote:
> 
>> On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
>>> From: Zack Weinberg <zackw@panix.com>
>>
>> I don't recall exactly which patch was the one that actually fixes BZ#11319,
>> my previous indication was 'Add __v*printf_internal with flags arguments.'.
>> Could you recheck it please?
> 
> Yes, sure.  This patch fixes the bug, because of the following change...
> 
>>>  int
>>> -__vdprintf_chk (int d, int flags, const char *format, va_list arg)
>>> +__vdprintf_chk (int d, int flag, const char *format, va_list ap)
>>>  {
>>> -  struct _IO_FILE_plus tmpfil;
>>> -  struct _IO_wide_data wd;
>>> -  int done;
>>> -
>>> -#ifdef _IO_MTSAFE_IO
>>> -  tmpfil.file._lock = NULL;
>>> -#endif
>>> -  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
>>> -  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
>>> -  _IO_new_file_init_internal (&tmpfil);
>>> -  if (_IO_file_attach (&tmpfil.file, d) == NULL)
>>> -    {
>>> -      _IO_un_link (&tmpfil);
>>> -      return EOF;
>>> -    }
>>> -  tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
>>> -
>>> -  _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
>>> -		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
>>> -
>>> -  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>>> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>>>       can only come from read-only format strings.  */
>>> -  if (flags > 0)
>>> -    tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
>>> -
>>> -  done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
>>> -
>>> -  _IO_FINISH (&tmpfil.file);
>>> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>>>  
>>> -  return done;
>>> +  return __vdprintf_internal (d, format, ap, mode);
> 
> Notice that the call to __vfprintf_internal was replaced with a call to
> __vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).
> 
> I wrote a test case to check this and I confirm that the problem is
> reproducible without this patch, but not with it.  (I'll clean the test up
> and send to this list...  Maybe it should get in to avoid regressions).
> 
> [1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD
> 

Thanks for confirm it, could you attach the add the testcase as well?
I would prefer to push along with the patch itself, and there is no need
to send a new version for the whole set. Just update this one.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-04 17:40       ` Adhemerval Zanella
@ 2018-12-04 18:01         ` Gabriel F. T. Gomes
  2018-12-04 21:07           ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-04 18:01 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 4370 bytes --]

On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

>Thanks for confirm it, could you attach the add the testcase as well?
>I would prefer to push along with the patch itself, and there is no need
>to send a new version for the whole set. Just update this one.

This is the patch (I hope my email client doesn't screw it)...


From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>
Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	1
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  int ret;
+  int fd = eventfd(0, 0);
+
+  /* man 2 eventfd:
+
+     A write(2) will fail with the error EINVAL if the size of the
+     supplied buffer is less than 8 bytes... */
+  ret = dprintf(fd, "%d", 0);
+
+  TEST_VERIFY (ret < 0);
+  TEST_COMPARE (errno, EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5


[-- Attachment #2: 0001-Add-test-for-bug-11319.patch --]
[-- Type: text/x-patch, Size: 3917 bytes --]

From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>
Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	1
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  int ret;
+  int fd = eventfd(0, 0);
+
+  /* man 2 eventfd:
+
+     A write(2) will fail with the error EINVAL if the size of the
+     supplied buffer is less than 8 bytes... */
+  ret = dprintf(fd, "%d", 0);
+
+  TEST_VERIFY (ret < 0);
+  TEST_COMPARE (errno, EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-04 18:01         ` Gabriel F. T. Gomes
@ 2018-12-04 21:07           ` Adhemerval Zanella
  2018-12-05 16:53             ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-04 21:07 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:
> On Tue, 04 Dec 2018, Adhemerval Zanella wrote:
> 
>> Thanks for confirm it, could you attach the add the testcase as well?
>> I would prefer to push along with the patch itself, and there is no need
>> to send a new version for the whole set. Just update this one.
> 
> This is the patch (I hope my email client doesn't screw it)...

Thanks, below some comments about the regression test.

> 
> 
> From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
> From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>
> Date: Tue, 4 Dec 2018 15:57:57 -0200
> Subject: [PATCH] Add test for bug 11319
> 
> The commit
> 
> commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
> Author: Ulrich Drepper <drepper@redhat.com>
> Date:   Wed Feb 24 16:07:57 2010 -0800
> 
>     Fix reporting of I/O errors in *dprintf functions.
> 
> fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
> __dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
> of libio functions, this bug is also fixed for the foritified functions.
> This patch adds a test case to avoid regressions.
> 
> Tested for powerpc64le and x86_64.
> 
> 	* stdio-common/Makefile (tests): Add tst-bz11319 and
> 	tst-bz11319-fortify2.
> 	(CFLAGS-tst-bz11319-fortify2.c): New macro.
> 	* stdio-common/tst-bz11319-fortify2.c: New file.
> 	* stdio-common/tst-bz11319.c: Likewise.
> ---
>  stdio-common/Makefile               |  6 ++++-
>  stdio-common/tst-bz11319-fortify2.c |  1 +
>  stdio-common/tst-bz11319.c          | 48 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 54 insertions(+), 1 deletion(-)
>  create mode 100644 stdio-common/tst-bz11319-fortify2.c
>  create mode 100644 stdio-common/tst-bz11319.c
> 
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 84bad1fafe..8978b3fb1f 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
>  	 tst-vfprintf-user-type \
>  	 tst-vfprintf-mbs-prec \
>  	 tst-scanf-round \
> -	 tst-renameat2 \
> +	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
>  
>  test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
>  
> @@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
>  # tst-gets.c tests a deprecated function.
>  CFLAGS-tst-gets.c += -Wno-deprecated-declarations
>  
> +# BZ #11319 was first fixed for regular vdprintf, then reopened because
> +# the fortified version had the same bug.
> +CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
> +
>  CPPFLAGS += $(libio-mtsafe)
>  
>  $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1

Ok.

> diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
> new file mode 100644
> index 0000000000..a8df9a39bd
> --- /dev/null
> +++ b/stdio-common/tst-bz11319-fortify2.c
> @@ -0,0 +1 @@
> +#include <tst-bz11319.c>
> diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
> new file mode 100644
> index 0000000000..ce2dee13ae
> --- /dev/null
> +++ b/stdio-common/tst-bz11319.c
> @@ -0,0 +1,48 @@
> +/* Regression test for bug 11319.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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 the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef _GNU_SOURCE
> +# define _GNU_SOURCE	1
> +#endif

I think we can define it regardless

> +
> +#include <errno.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/eventfd.h>

eventfd is Linux specific, so either we need to move this test to Linux
sysdeps or use a platform neutral way to stress this issue.

> +
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> +  int ret;
> +  int fd = eventfd(0, 0);

To stress this issue we just need a valid file descriptor that is seekable
but fail on a write.  Just use a temporary file opened in read-only mode.

> +
> +  /* man 2 eventfd:
> +
> +     A write(2) will fail with the error EINVAL if the size of the
> +     supplied buffer is less than 8 bytes... */
> +  ret = dprintf(fd, "%d", 0);
> +
> +  TEST_VERIFY (ret < 0);
> +  TEST_COMPARE (errno, EINVAL);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-04 21:07           ` Adhemerval Zanella
@ 2018-12-05 16:53             ` Gabriel F. T. Gomes
  2018-12-05 18:14               ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-05 16:53 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Tue, 04 Dec 2018, Adhemerval Zanella wrote:

>On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:
>>
>> +#ifndef _GNU_SOURCE
>> +# define _GNU_SOURCE	1
>> +#endif  
>
>I think we can define it regardless

OK.

>> +#include <errno.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <sys/eventfd.h>  
>
>eventfd is Linux specific, so either we need to move this test to Linux
>sysdeps or use a platform neutral way to stress this issue.

Oh, indeed.

>> +
>> +#include <support/check.h>
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  int ret;
>> +  int fd = eventfd(0, 0);  
>
>To stress this issue we just need a valid file descriptor that is seekable
>but fail on a write.  Just use a temporary file opened in read-only mode.

Does the following patch look better (thanks for the suggestion)?

From d992bc941921988fee31ff8b3fc13fb406f89b93 Mon Sep 17 00:00:00 2001
From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>
Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH v2] Add test for bug 11319

The commit

commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Wed Feb 24 16:07:57 2010 -0800

    Fix reporting of I/O errors in *dprintf functions.

fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.

Tested for powerpc64le and x86_64.

	* stdio-common/Makefile (tests): Add tst-bz11319 and
	tst-bz11319-fortify2.
	(CFLAGS-tst-bz11319-fortify2.c): New macro.
	* stdio-common/tst-bz11319-fortify2.c: New file.
	* stdio-common/tst-bz11319.c: Likewise.
---
 stdio-common/Makefile               |  6 ++++-
 stdio-common/tst-bz11319-fortify2.c |  1 +
 stdio-common/tst-bz11319.c          | 52 +++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 stdio-common/tst-bz11319-fortify2.c
 create mode 100644 stdio-common/tst-bz11319.c

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 tst-vfprintf-user-type \
 	 tst-vfprintf-mbs-prec \
 	 tst-scanf-round \
-	 tst-renameat2 \
+	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
 
 test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
 
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
 # tst-gets.c tests a deprecated function.
 CFLAGS-tst-gets.c += -Wno-deprecated-declarations
 
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
 CPPFLAGS += $(libio-mtsafe)
 
 $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..29fbd729ab
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,52 @@
+/* Regression test for bug 11319.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+  char *tempfile;
+  int ret;
+  FILE *fp;
+
+  /* Create a temporary file and open it in read-only mode.  */
+  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
+  fp = xfopen (tempfile, "r");
+
+  /* Try and write to the temporary file to intentionally fail, then
+     check that dprintf (or __dprintf_chk) return EOF.  */
+  ret = dprintf (fp->_fileno, "%d", 0);
+  TEST_VERIFY (ret == EOF);
+
+  /* Clean up.  */
+  xfclose (fp);
+  if (tempfile)
+    free (tempfile);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.14.5

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 16:53             ` Gabriel F. T. Gomes
@ 2018-12-05 18:14               ` Adhemerval Zanella
  2018-12-05 19:12                 ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-05 18:14 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 05/12/2018 14:53, Gabriel F. T. Gomes wrote:
> On Tue, 04 Dec 2018, Adhemerval Zanella wrote:
> 
>> On 04/12/2018 16:01, Gabriel F. T. Gomes wrote:
>>>
>>> +#ifndef _GNU_SOURCE
>>> +# define _GNU_SOURCE	1
>>> +#endif  
>>
>> I think we can define it regardless
> 
> OK.
> 
>>> +#include <errno.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +#include <sys/eventfd.h>  
>>
>> eventfd is Linux specific, so either we need to move this test to Linux
>> sysdeps or use a platform neutral way to stress this issue.
> 
> Oh, indeed.
> 
>>> +
>>> +#include <support/check.h>
>>> +
>>> +static int
>>> +do_test (void)
>>> +{
>>> +  int ret;
>>> +  int fd = eventfd(0, 0);  
>>
>> To stress this issue we just need a valid file descriptor that is seekable
>> but fail on a write.  Just use a temporary file opened in read-only mode.
> 
> Does the following patch look better (thanks for the suggestion)?
> 
> From d992bc941921988fee31ff8b3fc13fb406f89b93 Mon Sep 17 00:00:00 2001
> From: "Gabriel F. T. Gomes" <gabriel@inconstante.eti.br>
> Date: Tue, 4 Dec 2018 15:57:57 -0200
> Subject: [PATCH v2] Add test for bug 11319
> 
> The commit
> 
> commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
> Author: Ulrich Drepper <drepper@redhat.com>
> Date:   Wed Feb 24 16:07:57 2010 -0800
> 
>     Fix reporting of I/O errors in *dprintf functions.
> 
> fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
> __dprintf_chk and __vdprintf_chk.  As a side-effect of the refactoring
> of libio functions, this bug is also fixed for the foritified functions.
> This patch adds a test case to avoid regressions.
> 
> Tested for powerpc64le and x86_64.
> 
> 	* stdio-common/Makefile (tests): Add tst-bz11319 and
> 	tst-bz11319-fortify2.
> 	(CFLAGS-tst-bz11319-fortify2.c): New macro.
> 	* stdio-common/tst-bz11319-fortify2.c: New file.
> 	* stdio-common/tst-bz11319.c: Likewise.
> ---
>  stdio-common/Makefile               |  6 ++++-
>  stdio-common/tst-bz11319-fortify2.c |  1 +
>  stdio-common/tst-bz11319.c          | 52 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 58 insertions(+), 1 deletion(-)
>  create mode 100644 stdio-common/tst-bz11319-fortify2.c
>  create mode 100644 stdio-common/tst-bz11319.c
> 
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 84bad1fafe..8978b3fb1f 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
>  	 tst-vfprintf-user-type \
>  	 tst-vfprintf-mbs-prec \
>  	 tst-scanf-round \
> -	 tst-renameat2 \
> +	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
>  
>  test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
>  
> @@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
>  # tst-gets.c tests a deprecated function.
>  CFLAGS-tst-gets.c += -Wno-deprecated-declarations
>  
> +# BZ #11319 was first fixed for regular vdprintf, then reopened because
> +# the fortified version had the same bug.
> +CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
> +
>  CPPFLAGS += $(libio-mtsafe)
>  
>  $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
> diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
> new file mode 100644
> index 0000000000..a8df9a39bd
> --- /dev/null
> +++ b/stdio-common/tst-bz11319-fortify2.c
> @@ -0,0 +1 @@
> +#include <tst-bz11319.c>
> diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
> new file mode 100644
> index 0000000000..29fbd729ab
> --- /dev/null
> +++ b/stdio-common/tst-bz11319.c
> @@ -0,0 +1,52 @@
> +/* Regression test for bug 11319.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library 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 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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 the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#define _GNU_SOURCE 1
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/xstdio.h>
> +
> +static int
> +do_test (void)
> +{
> +  char *tempfile;
> +  int ret;
> +  FILE *fp;
> +
> +  /* Create a temporary file and open it in read-only mode.  */
> +  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
> +  fp = xfopen (tempfile, "r");
> +
> +  /* Try and write to the temporary file to intentionally fail, then
> +     check that dprintf (or __dprintf_chk) return EOF.  */
> +  ret = dprintf (fp->_fileno, "%d", 0);
> +  TEST_VERIFY (ret == EOF);
> +
> +  /* Clean up.  */
> +  xfclose (fp);
> +  if (tempfile)
> +    free (tempfile);

For a lack of a better interface (to create/open read-only temporary files
or memfd_create), I think it would be simpler to:

static int
do_test (void)
{ 
  char *tempfile;
  int fd;

  /* Create a temporary file and open it in read-only mode.  */
  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
  fd = xopen (tempfile, O_RDONLY, 0660);

  /* Try and write to the temporary file to intentionally fail, then
     check that dprintf (or __dprintf_chk) return EOF.  */
  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);

  xclose (fd);
  free (tempfile);

  return 0;
}


> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 18:14               ` Adhemerval Zanella
@ 2018-12-05 19:12                 ` Gabriel F. T. Gomes
  2018-12-05 19:18                   ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-05 19:12 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Wed, 05 Dec 2018, Adhemerval Zanella wrote:
>
>For a lack of a better interface (to create/open read-only temporary files
>or memfd_create), I think it would be simpler to:
>
>static int
>do_test (void)
>{ 
>  char *tempfile;
>  int fd;
>
>  /* Create a temporary file and open it in read-only mode.  */
>  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
>  fd = xopen (tempfile, O_RDONLY, 0660);
>
>  /* Try and write to the temporary file to intentionally fail, then
>     check that dprintf (or __dprintf_chk) return EOF.  */
>  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);
>
>  xclose (fd);
>  free (tempfile);
>
>  return 0;
>}

Looks good to me.  Should I post an updated version, or is it OK with the
suggested changes?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 19:12                 ` Gabriel F. T. Gomes
@ 2018-12-05 19:18                   ` Adhemerval Zanella
  2018-12-05 19:27                     ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-05 19:18 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 05/12/2018 17:11, Gabriel F. T. Gomes wrote:
> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:
>>
>> For a lack of a better interface (to create/open read-only temporary files
>> or memfd_create), I think it would be simpler to:
>>
>> static int
>> do_test (void)
>> { 
>>  char *tempfile;
>>  int fd;
>>
>>  /* Create a temporary file and open it in read-only mode.  */
>>  TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
>>  fd = xopen (tempfile, O_RDONLY, 0660);
>>
>>  /* Try and write to the temporary file to intentionally fail, then
>>     check that dprintf (or __dprintf_chk) return EOF.  */
>>  TEST_COMPARE (dprintf (fd, "%d", 0), EOF);
>>
>>  xclose (fd);
>>  free (tempfile);
>>
>>  return 0;
>> }
> 
> Looks good to me.  Should I post an updated version, or is it OK with the
> suggested changes?
> 

I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 19:18                   ` Adhemerval Zanella
@ 2018-12-05 19:27                     ` Gabriel F. T. Gomes
  2018-12-05 19:35                       ` Adhemerval Zanella
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-05 19:27 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>I would suggest you to integrate it on the patch which fixes BZ#11319
>and from my side you don't need to send an update version.

Oh, I see.  Then I'll send it again, because I need to update the commit
message and ChangeLog.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 19:27                     ` Gabriel F. T. Gomes
@ 2018-12-05 19:35                       ` Adhemerval Zanella
  2018-12-05 20:07                         ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Adhemerval Zanella @ 2018-12-05 19:35 UTC (permalink / raw)
  To: Gabriel F. T. Gomes; +Cc: libc-alpha



On 05/12/2018 17:27, Gabriel F. T. Gomes wrote:
> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:
> 
>> I would suggest you to integrate it on the patch which fixes BZ#11319
>> and from my side you don't need to send an update version.
> 
> Oh, I see.  Then I'll send it again, because I need to update the commit
> message and ChangeLog.
> 

Alright.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-05 19:35                       ` Adhemerval Zanella
@ 2018-12-05 20:07                         ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-05 20:07 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Wed, 05 Dec 2018, Adhemerval Zanella wrote:

>On 05/12/2018 17:27, Gabriel F. T. Gomes wrote:
>> On Wed, 05 Dec 2018, Adhemerval Zanella wrote:
>>   
>>> I would suggest you to integrate it on the patch which fixes BZ#11319
>>> and from my side you don't need to send an update version.  
>> 
>> Oh, I see.  Then I'll send it again, because I need to update the commit
>> message and ChangeLog.
>>   
>
>Alright.

Hrm, I thought I would have to rewrite the messages (and that I would be
doubtful about it), but it turned out to be mostly copy-and-paste.  So,
I'll go ahead and push the changes.

Thanks again and sorry about the noise. :)

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio
  2018-12-03 13:52   ` Gabriel F. T. Gomes
@ 2018-12-05 21:00     ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-05 21:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha, Adhemerval Zanella

On Mon, 03 Dec 2018, Gabriel F. T. Gomes wrote:

>On Sun, 02 Dec 2018, Florian Weimer wrote:
>
>>What's the status here?
>>
>>I think Adhemerval has reviewed all seven patches (and I looked at an
>>earlier version too), so this should be ready to commit.  
>
>I'll try to get back to it today (no later than tomorrow).
>
>Thanks for your reviews.

These patches (with the regression test) are now committed and the
bugzilla entry is now marked as resolved/fixed.  Thanks again.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-11-15 21:46 ` [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319) Gabriel F. T. Gomes
  2018-11-22 18:11   ` Adhemerval Zanella
@ 2018-12-18 13:03   ` Szabolcs Nagy
  2018-12-18 16:54     ` Florian Weimer
  1 sibling, 1 reply; 39+ messages in thread
From: Szabolcs Nagy @ 2018-12-18 13:03 UTC (permalink / raw)
  To: Gabriel F. T. Gomes, libc-alpha; +Cc: nd, Sam Tebbs, Zack Weinberg

On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:
> +/* This function is called by regular vsprintf with maxlen set to -1,
> +   and by vsprintf_chk with maxlen set to the size of the output
> +   string.  In the former case, _IO_str_chk_overflow will never be
> +   called; in the latter case it will crash the program if the buffer
> +   overflows.  */
> +
>  int
> -__vsprintf_internal (char *string, const char *format, va_list args,
> +__vsprintf_internal (char *string, size_t maxlen,
> +		     const char *format, va_list args,
>  		     unsigned int mode_flags)
>  {
>    _IO_strfile sf;
> @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
>    sf._sbf._f._lock = NULL;
>  #endif
>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> -  _IO_str_init_static_internal (&sf, string, -1, string);
> +  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
> +  string[0] = '\0';

note that since this change the following code changed behaviour:

#include <stdio.h>
int main()
{
  char buf[20] = "AB";
  sprintf (buf, "%sCD", buf);
  puts (buf);
}

this is ub in iso c, but previously printed "ABCD", but now
buf[0]=0 before the format string is processed, so it is "CD".

this is a heads up, since this pattern seems to appear in existing code,
in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:

sprintf(mess,"  Size:");
for (i=0;i<dim+1;i++)
{
    sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);
}


> +  _IO_str_init_static_internal (&sf, string,
> +				(maxlen == -1) ? -1 : maxlen - 1,
> +				string);
> +
>    ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
> -  _IO_putc_unlocked ('\0', &sf._sbf._f);
> +
> +  *sf._sbf._f._IO_write_ptr = '\0';
>    return ret;
>  }

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-18 13:03   ` Szabolcs Nagy
@ 2018-12-18 16:54     ` Florian Weimer
  2018-12-18 17:32       ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Florian Weimer @ 2018-12-18 16:54 UTC (permalink / raw)
  To: Szabolcs Nagy
  Cc: Gabriel F. T. Gomes, libc-alpha, nd, Sam Tebbs, Zack Weinberg

* Szabolcs Nagy:

> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:
>> +/* This function is called by regular vsprintf with maxlen set to -1,
>> +   and by vsprintf_chk with maxlen set to the size of the output
>> +   string.  In the former case, _IO_str_chk_overflow will never be
>> +   called; in the latter case it will crash the program if the buffer
>> +   overflows.  */
>> +
>>  int
>> -__vsprintf_internal (char *string, const char *format, va_list args,
>> +__vsprintf_internal (char *string, size_t maxlen,
>> +		     const char *format, va_list args,
>>  		     unsigned int mode_flags)
>>  {
>>    _IO_strfile sf;
>> @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
>>    sf._sbf._f._lock = NULL;
>>  #endif
>>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>> -  _IO_str_init_static_internal (&sf, string, -1, string);
>> +  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
>> +  string[0] = '\0';
>
> note that since this change the following code changed behaviour:
>
> #include <stdio.h>
> int main()
> {
>   char buf[20] = "AB";
>   sprintf (buf, "%sCD", buf);
>   puts (buf);
> }
>
> this is ub in iso c, but previously printed "ABCD", but now
> buf[0]=0 before the format string is processed, so it is "CD".
>
> this is a heads up, since this pattern seems to appear in existing code,
> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:
>
> sprintf(mess,"  Size:");
> for (i=0;i<dim+1;i++)
> {
>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);
> }

I think we should make this specific to the fortify flag, even though
it's undefined.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-18 16:54     ` Florian Weimer
@ 2018-12-18 17:32       ` Gabriel F. T. Gomes
  2018-12-19 15:31         ` Szabolcs Nagy
  0 siblings, 1 reply; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-18 17:32 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Szabolcs Nagy, libc-alpha, nd, Sam Tebbs, Zack Weinberg

On Tue, 18 Dec 2018, Florian Weimer wrote:

>* Szabolcs Nagy:
>
>> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:  
>>> +/* This function is called by regular vsprintf with maxlen set to -1,
>>> +   and by vsprintf_chk with maxlen set to the size of the output
>>> +   string.  In the former case, _IO_str_chk_overflow will never be
>>> +   called; in the latter case it will crash the program if the buffer
>>> +   overflows.  */
>>> +
>>>  int
>>> -__vsprintf_internal (char *string, const char *format, va_list args,
>>> +__vsprintf_internal (char *string, size_t maxlen,
>>> +		     const char *format, va_list args,
>>>  		     unsigned int mode_flags)
>>>  {
>>>    _IO_strfile sf;
>>> @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
>>>    sf._sbf._f._lock = NULL;
>>>  #endif
>>>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>>> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>>> -  _IO_str_init_static_internal (&sf, string, -1, string);
>>> +  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
>>> +  string[0] = '\0';  
>>
>> note that since this change the following code changed behaviour:
>>
>> #include <stdio.h>
>> int main()
>> {
>>   char buf[20] = "AB";
>>   sprintf (buf, "%sCD", buf);
>>   puts (buf);
>> }
>>
>> this is ub in iso c, but previously printed "ABCD", but now
>> buf[0]=0 before the format string is processed, so it is "CD".
>>
>> this is a heads up, since this pattern seems to appear in existing code,
>> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:
>>
>> sprintf(mess,"  Size:");
>> for (i=0;i<dim+1;i++)
>> {
>>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);
>> }  
>
>I think we should make this specific to the fortify flag, even though
>it's undefined.

So, do you think that moving the `string[0] = '\0';' statement from
__vsprintf_internal to ___vsprintf_chk (before the second calls the first)
is an adequate fix?

I could write this with an accompanying test case to avoid regressions in
both fortified and non-fortified cases.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-18 17:32       ` Gabriel F. T. Gomes
@ 2018-12-19 15:31         ` Szabolcs Nagy
  2018-12-20 22:17           ` Gabriel F. T. Gomes
  0 siblings, 1 reply; 39+ messages in thread
From: Szabolcs Nagy @ 2018-12-19 15:31 UTC (permalink / raw)
  To: Gabriel F. T. Gomes, Florian Weimer
  Cc: nd, libc-alpha, Sam Tebbs, Zack Weinberg

On 18/12/2018 17:31, Gabriel F. T. Gomes wrote:
> On Tue, 18 Dec 2018, Florian Weimer wrote:
> 
>> * Szabolcs Nagy:
>>
>>> On 15/11/2018 21:44, Gabriel F. T. Gomes wrote:  
>>>> +/* This function is called by regular vsprintf with maxlen set to -1,
>>>> +   and by vsprintf_chk with maxlen set to the size of the output
>>>> +   string.  In the former case, _IO_str_chk_overflow will never be
>>>> +   called; in the latter case it will crash the program if the buffer
>>>> +   overflows.  */
>>>> +
>>>>  int
>>>> -__vsprintf_internal (char *string, const char *format, va_list args,
>>>> +__vsprintf_internal (char *string, size_t maxlen,
>>>> +		     const char *format, va_list args,
>>>>  		     unsigned int mode_flags)
>>>>  {
>>>>    _IO_strfile sf;
>>>> @@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
>>>>    sf._sbf._f._lock = NULL;
>>>>  #endif
>>>>    _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
>>>> -  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
>>>> -  _IO_str_init_static_internal (&sf, string, -1, string);
>>>> +  _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
>>>> +  string[0] = '\0';  
>>>
>>> note that since this change the following code changed behaviour:
>>>
>>> #include <stdio.h>
>>> int main()
>>> {
>>>   char buf[20] = "AB";
>>>   sprintf (buf, "%sCD", buf);
>>>   puts (buf);
>>> }
>>>
>>> this is ub in iso c, but previously printed "ABCD", but now
>>> buf[0]=0 before the format string is processed, so it is "CD".
>>>
>>> this is a heads up, since this pattern seems to appear in existing code,
>>> in particular in SPEC2017 507.cactuBSSN_r/src/PUGH/PughUtils.c:
>>>
>>> sprintf(mess,"  Size:");
>>> for (i=0;i<dim+1;i++)
>>> {
>>>     sprintf(mess,"%s %d",mess,pughGH->GFExtras[dim]->nsize[i]);
>>> }  
>>
>> I think we should make this specific to the fortify flag, even though
>> it's undefined.
> 
> So, do you think that moving the `string[0] = '\0';' statement from
> __vsprintf_internal to ___vsprintf_chk (before the second calls the first)
> is an adequate fix?
> 
> I could write this with an accompanying test case to avoid regressions in
> both fortified and non-fortified cases.
> 


i would just do

if (maxlen == -1)
  .. old code ..
else
  .. new code ..

to revert the old sprintf behaviour.

later the code may be refactored further (it should be
possible to use shared code between sprintf, snprintf
and sprintf_chk, but that requires a lot more changes).


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319)
  2018-12-19 15:31         ` Szabolcs Nagy
@ 2018-12-20 22:17           ` Gabriel F. T. Gomes
  0 siblings, 0 replies; 39+ messages in thread
From: Gabriel F. T. Gomes @ 2018-12-20 22:17 UTC (permalink / raw)
  To: Szabolcs Nagy; +Cc: Florian Weimer, nd, libc-alpha, Sam Tebbs, Zack Weinberg

On Wed, 19 Dec 2018, Szabolcs Nagy wrote:
>
>i would just do
>
>if (maxlen == -1)
>  .. old code ..
>else
>  .. new code ..
>
>to revert the old sprintf behaviour.

I found that just checking for maxlen == -1 is not enough for reverting to
the old behavior, because maxlen could be -1 when __vsprintf_internal is
called from __sprintf_chk and __vsprintf_chk (and not only  from sprintf
and vsprintf).  Thus, I added a new macro that __sprintf_chk and
__vsprintf_chk can set (through mode_flags), to let __vsprintf_internal
know where the call came from, then restore the old behavior.

More important to notice is the fact that the overwriting of the
destination buffer is *not* the only behavior affected by the refactoring.
Before the refactoring, sprintf and vsprintf would use _IO_str_jumps,
whereas __sprintf_chk and __vsprintf_chk would use _IO_str_chk_jumps.
After the refactoring, all use _IO_str_chk_jumps, which would make
sprintf and vsprintf report buffer overflows and terminate the program,
which sounds wrong to me (I haven't noticed this effect on sprintf and
vsprintf before, sorry about that. Maybe I should add an extra test to
avoid something similar in the future).

With the new macro, I can install the same jump table that used to be
installed before the refactoring, thus fully reverting to the old
behaviour.  I have just submitted a new patch at:

https://sourceware.org/ml/libc-alpha/2018-12/msg00838.html

>later the code may be refactored further (it should be
>possible to use shared code between sprintf, snprintf
>and sprintf_chk, but that requires a lot more changes).

It wasn't my intention to suggest that sprintf and snprintf should share
code (although I'm not against it)...  I was just referring to *sprintf,
__*sprintf_chk, and __vsprintf_internal.  Perhaps, I did not understand
what you mean with this comment.

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2018-12-20 21:55 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-15 21:45 [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Gabriel F. T. Gomes
2018-11-15 21:46 ` [PATCH v3 4/7] Add __v*printf_internal with flags arguments Gabriel F. T. Gomes
2018-11-22 17:46   ` Adhemerval Zanella
2018-11-22 17:55   ` Adhemerval Zanella
2018-11-22 17:59     ` Adhemerval Zanella
2018-11-15 21:46 ` [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal " Gabriel F. T. Gomes
2018-11-16 18:34   ` Gabriel F. T. Gomes
2018-11-22 17:35   ` Adhemerval Zanella
2018-12-04 15:15     ` Gabriel F. T. Gomes
2018-12-04 17:37       ` Adhemerval Zanella
2018-11-15 21:46 ` [PATCH v3 5/7] Add __vsyslog_internal, with same flags as __v*printf_internal Gabriel F. T. Gomes
2018-11-22 18:00   ` Adhemerval Zanella
2018-11-15 21:46 ` [PATCH v3 2/7] Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD Gabriel F. T. Gomes
2018-11-22 17:38   ` Adhemerval Zanella
2018-11-15 21:46 ` [PATCH v3 6/7] Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY (bug 11319) Gabriel F. T. Gomes
2018-11-22 18:11   ` Adhemerval Zanella
2018-12-04 16:20     ` Gabriel F. T. Gomes
2018-12-04 17:40       ` Adhemerval Zanella
2018-12-04 18:01         ` Gabriel F. T. Gomes
2018-12-04 21:07           ` Adhemerval Zanella
2018-12-05 16:53             ` Gabriel F. T. Gomes
2018-12-05 18:14               ` Adhemerval Zanella
2018-12-05 19:12                 ` Gabriel F. T. Gomes
2018-12-05 19:18                   ` Adhemerval Zanella
2018-12-05 19:27                     ` Gabriel F. T. Gomes
2018-12-05 19:35                       ` Adhemerval Zanella
2018-12-05 20:07                         ` Gabriel F. T. Gomes
2018-12-18 13:03   ` Szabolcs Nagy
2018-12-18 16:54     ` Florian Weimer
2018-12-18 17:32       ` Gabriel F. T. Gomes
2018-12-19 15:31         ` Szabolcs Nagy
2018-12-20 22:17           ` Gabriel F. T. Gomes
2018-11-15 21:46 ` [PATCH v3 3/7] Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl Gabriel F. T. Gomes
2018-11-22 17:39   ` Adhemerval Zanella
2018-11-15 21:53 ` [PATCH v3 7/7] Use PRINTF_LDBL_IS_DBL " Gabriel F. T. Gomes
2018-11-22 18:13   ` Adhemerval Zanella
2018-12-02 11:53 ` [PATCH v3 0/7] Use more flags parameters instead of global bits in stdio Florian Weimer
2018-12-03 13:52   ` Gabriel F. T. Gomes
2018-12-05 21:00     ` Gabriel F. T. Gomes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).