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