This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.



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

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

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

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

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

Ok.

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

Ok.

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

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

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

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

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

Ok.

> diff --git a/stdio-common/vfwscanf-internal.c b/stdio-common/vfwscanf-internal.c
> new file mode 100644
> index 0000000000..26c89270b7
> --- /dev/null
> +++ b/stdio-common/vfwscanf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WSCANF	1
> +#include "vfscanf-internal.c"
> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
> index 26b1a66608..86980464c2 100644
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf.c
> @@ -1,2 +1,26 @@
> -#define COMPILE_WSCANF	1
> -#include "vfscanf.c"
> +/* Implementation and symbols for vfwscanf.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <libioP.h>
> +
> +int
> +__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> +{
> +  return __vfwscanf_internal (s, format, argptr, 0);
> +}
> +ldbl_weak_alias (__vfwscanf, vfwscanf)

Ok.

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

Ok.

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

Ok.

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

Ok.

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

Ok.

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

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

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

Ok.

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

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

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

Ok.

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

Ok.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]