diff mbox series

[v2,5/8] Add __v*printf_internal with flags arguments.

Message ID 20181029121650.24544-6-gabriel@inconstante.eti.br
State New
Headers show
Series Use more flags parameters instead of global bits in stdio | expand

Commit Message

Gabriel F. T. Gomes Oct. 29, 2018, 12:16 p.m. UTC
From: Zack Weinberg <zackw@panix.com>

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.
	(LDBL_IS_DBL, DO_FORTIFY): New macros.	Throughout, use
	LDBL_IS_DBL instead of __ldbl_is_dbl, and DO_FORTIFY instead of
	checking _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.

Signed-off-by: Zack Weinberg <zackw@panix.com>
Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
---
 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                          |   40 +-
 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-internal.c        | 2366 +++++++++++++++++++++++++++++++
 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, 2544 insertions(+), 2466 deletions(-)
 create mode 100644 stdio-common/vfprintf-internal.c
 create mode 100644 stdio-common/vfwprintf-internal.c

Comments

Gabriel F. T. Gomes Oct. 29, 2018, 12:20 p.m. UTC | #1
On Mon, 29 Oct 2018, Gabriel F. T. Gomes wrote:

>  - 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)

Original patch attached.
From 1a9bc6e5fa05664324f6eab70cabbf061acce7a4 Mon Sep 17 00:00:00 2001
From: Zack Weinberg <zackw@panix.com>
Date: Wed, 7 Mar 2018 14:32:01 -0500
Subject: [PATCH v2 5/8] Add __v*printf_internal with flags arguments.

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.
	(LDBL_IS_DBL, DO_FORTIFY): New macros.	Throughout, use
	LDBL_IS_DBL instead of __ldbl_is_dbl, and DO_FORTIFY instead of
	checking _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.

Signed-off-by: Zack Weinberg <zackw@panix.com>
Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
---
 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                          |   40 +-
 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-internal.c        | 2366 +++++++++++++++++++++++++++++++
 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, 2544 insertions(+), 2466 deletions(-)
 create mode 100644 stdio-common/vfprintf-internal.c
 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 f90fb2c050..c762cf9b67 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,40 @@ 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.  */
+#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-internal.c b/stdio-common/vfprintf-internal.c
new file mode 100644
index 0000000000..7752ad5b68
--- /dev/null
+++ b/stdio-common/vfprintf-internal.c
@@ -0,0 +1,2366 @@
+/* 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 <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>
+
+/* 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>
+
+#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.  */
+#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 LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
+#define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)
+
+#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	__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	__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 */
+# 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 (DO_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,
+			      unsigned int)
+     __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 thousands_sep,
+			      unsigned int mode_flags);
+
+/* 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, unsigned int mode_flags)
+{
+  /* 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;
+
+  /* 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;
+#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, mode_flags);
+
+  /* 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, mode_flags);
+
+ all_done:
+  if (__glibc_unlikely (workstart != NULL))
+    free (workstart);
+  /* Unlock the stream.  */
+  _IO_funlockfile (s);
+  _IO_cleanup_region_end (0);
+
+  return done;
+}
+
+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,
+		   unsigned int mode_flags)
+{
+  /* 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, DO_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 (DO_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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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,
+		   unsigned int mode_flags)
+{
+  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.  */
+  result = vfprintf (hp, format, args, mode_flags);
+
+  /* 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;
+}
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;
-}
-
-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);
 }
-
-/* 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;
-}
-
-/* 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;
-}
-
-/* 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;
 }
Adhemerval Zanella Netto Nov. 7, 2018, 6:53 p.m. UTC | #2
On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
> 
> 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.

Look good in general with some nits below.

> 
> 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.
> 	(LDBL_IS_DBL, DO_FORTIFY): New macros.	Throughout, use
> 	LDBL_IS_DBL instead of __ldbl_is_dbl, and DO_FORTIFY instead of
> 	checking _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.
> 
> Signed-off-by: Zack Weinberg <zackw@panix.com>
> Signed-off-by: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>

We don't use DCO, but copyright assignments.

> ---
>  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                          |   40 +-
>  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-internal.c        | 2366 +++++++++++++++++++++++++++++++
>  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, 2544 insertions(+), 2466 deletions(-)
>  create mode 100644 stdio-common/vfprintf-internal.c
>  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 f90fb2c050..c762cf9b67 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -658,12 +658,40 @@ 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.  */
> +#define PRINTF_LDBL_IS_DBL 0x0001
> +#define PRINTF_FORTIFY     0x0002

Please extend the flags comment to describe what they do.

>  
>  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)

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;
> 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 -u stdio-common/vfprintf.c.old stdio-common/vfprintf-internal.c.new
> --- stdio-common/vfprintf.c.old	2018-10-26 11:09:08.538713613 -0300
> +++ stdio-common/vfprintf-internal.c.new	2018-10-26 11:08:45.130667960 -0300
> @@ -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.  */
> @@ -63,6 +67,8 @@
>  	}								      \
>      } while (0)
>  #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
> +#define LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
> +#define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)

Do we really gain anything using these defines? I tend to frown on macros
that use internal named variables instead of set them as arguments. Also
this is quite short, I think it is more readable to just use the comparison
directly.

>  
>  #define done_add(val) \
>    do {									      \
> @@ -78,7 +84,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 +111,7 @@
>  # 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 +753,7 @@
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (LDBL_IS_DBL)						      \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -778,7 +784,7 @@
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (LDBL_IS_DBL)						      \
>  	      {								      \
>  		fspec->data_arg_type = PA_DOUBLE;			      \
>  		fspec->info.is_long_double = 0;				      \
> @@ -808,7 +814,7 @@
>  									      \
>  	if (fspec == NULL)						      \
>  	  {								      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (LDBL_IS_DBL)						      \
>  	      is_long_double = 0;					      \
>  									      \
>  	    struct printf_info info = { .prec = prec,			      \
> @@ -838,7 +844,7 @@
>  	else								      \
>  	  {								      \
>  	    ptr = (const void *) &args_value[fspec->data_arg];		      \
> -	    if (__ldbl_is_dbl)						      \
> +	    if (LDBL_IS_DBL)						      \
>  	      fspec->info.is_long_double = 0;				      \
>  	    /* Not supported by *printf functions.  */			      \
>  	    fspec->info.is_binary128 = 0;				      \
> @@ -891,7 +897,7 @@
>        /* NOTREACHED */							      \
>  									      \
>      LABEL (form_number):						      \
> -      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
> +      if (DO_FORTIFY)							      \
>  	{								      \
>  	  if (! readonly_format)					      \
>  	    {								      \
> @@ -1214,7 +1220,8 @@
>  #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 +1230,9 @@
>  			      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 +1244,7 @@
>  
>  /* 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 +1282,12 @@
>       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 +1308,7 @@
>    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 +1697,7 @@
>      }
>    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 +1714,8 @@
>  		   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 +1805,7 @@
>         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, DO_FORTIFY ? '\xff' : '\0',
>  	    nargs * sizeof (*args_type));
>    }
>  
> @@ -1856,7 +1872,7 @@
>        case PA_FLOAT:				/* Promoted.  */
>  	T (PA_DOUBLE, pa_double, double);
>        case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> -	if (__ldbl_is_dbl)
> +	if (LDBL_IS_DBL)
>  	  {
>  	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
>  	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> @@ -1884,7 +1900,7 @@
>        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 (DO_FORTIFY);
>  	__libc_fatal ("*** invalid %N$ use detected ***\n");
>        }
>  
> @@ -2285,7 +2301,8 @@
>  #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 +2335,7 @@
>    _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 +2364,3 @@
>  
>    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 -u /dev/null stdio-common/vfprintf.c.new
> --- /dev/null	2018-10-15 19:30:16.914999855 -0300
> +++ stdio-common/vfprintf.c.new	2018-10-26 11:08:58.758694540 -0300
> @@ -0,0 +1,27 @@
> +/* 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
> +__vfprintf (FILE *fp, const char *format, va_list ap)
> +{
> +  return __vfprintf_internal (fp, format, ap, 0);
> +}
> +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.
Adhemerval Zanella Netto Nov. 8, 2018, 5:24 p.m. UTC | #3
On 07/11/2018 16:53, Adhemerval Zanella wrote:
> 
> 
> On 29/10/2018 09:16, Gabriel F. T. Gomes wrote:
>> From: Zack Weinberg <zackw@panix.com>
>> [...]
>> 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.

Please add a note that it fixes BZ#11319 by unifing both fortified and 
non-fortified vdprintf initialization.
Gabriel F. T. Gomes Nov. 15, 2018, 4:27 p.m. UTC | #4
On Thu, 08 Nov 2018, Adhemerval Zanella wrote:

>Please add a note that it fixes BZ#11319 by unifing both fortified and 
>non-fortified vdprintf initialization.

I'll add this note to patch 7/8, since the fix is there.  Thanks for
checking and closing bug 20231, and for reopening 11319 and pointing it
out to me.
diff mbox series

Patch

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 f90fb2c050..c762cf9b67 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,40 @@  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.  */
+#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 -u stdio-common/vfprintf.c.old stdio-common/vfprintf-internal.c.new
--- stdio-common/vfprintf.c.old	2018-10-26 11:09:08.538713613 -0300
+++ stdio-common/vfprintf-internal.c.new	2018-10-26 11:08:45.130667960 -0300
@@ -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.  */
@@ -63,6 +67,8 @@ 
 	}								      \
     } while (0)
 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
+#define LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
+#define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)
 
 #define done_add(val) \
   do {									      \
@@ -78,7 +84,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 +111,7 @@ 
 # 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 +753,7 @@ 
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -778,7 +784,7 @@ 
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      {								      \
 		fspec->data_arg_type = PA_DOUBLE;			      \
 		fspec->info.is_long_double = 0;				      \
@@ -808,7 +814,7 @@ 
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -838,7 +844,7 @@ 
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      fspec->info.is_long_double = 0;				      \
 	    /* Not supported by *printf functions.  */			      \
 	    fspec->info.is_binary128 = 0;				      \
@@ -891,7 +897,7 @@ 
       /* NOTREACHED */							      \
 									      \
     LABEL (form_number):						      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
+      if (DO_FORTIFY)							      \
 	{								      \
 	  if (! readonly_format)					      \
 	    {								      \
@@ -1214,7 +1220,8 @@ 
 #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 +1230,9 @@ 
 			      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 +1244,7 @@ 
 
 /* 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 +1282,12 @@ 
      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 +1308,7 @@ 
   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 +1697,7 @@ 
     }
   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 +1714,8 @@ 
 		   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 +1805,7 @@ 
        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, DO_FORTIFY ? '\xff' : '\0',
 	    nargs * sizeof (*args_type));
   }
 
@@ -1856,7 +1872,7 @@ 
       case PA_FLOAT:				/* Promoted.  */
 	T (PA_DOUBLE, pa_double, double);
       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
-	if (__ldbl_is_dbl)
+	if (LDBL_IS_DBL)
 	  {
 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
@@ -1884,7 +1900,7 @@ 
       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 (DO_FORTIFY);
 	__libc_fatal ("*** invalid %N$ use detected ***\n");
       }
 
@@ -2285,7 +2301,8 @@ 
 #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 +2335,7 @@ 
   _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 +2364,3 @@ 
 
   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 -u /dev/null stdio-common/vfprintf.c.new
--- /dev/null	2018-10-15 19:30:16.914999855 -0300
+++ stdio-common/vfprintf.c.new	2018-10-26 11:08:58.758694540 -0300
@@ -0,0 +1,27 @@ 
+/* 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
+__vfprintf (FILE *fp, const char *format, va_list ap)
+{
+  return __vfprintf_internal (fp, format, ap, 0);
+}
+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;
 }