This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH v3 1/7] Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
On 15/11/2018 19:44, Gabriel F. T. Gomes wrote:
> From: Zack Weinberg <zackw@panix.com>
>
> Changed since v2:
>
> - Expand comments about SCANF_LDBL_IS_DBL and SCANF_ISOC99_A.
> - Remove parameter-less macros LDBL_DISTINCT and USE_ISOC99_A. Paste
> their code directly where it is used.
> - Use Static_assert rather than `...' in ldbl_compat_symbol.
> - Fix copyright statements.
The patch looks ok with the exception of the part where it adapts some symbol
to set _IO_FLAGS2_SCANF_STD on _flags2 *without* acquiring the lock previously.
I also see the idea of second patch is also to get rid of such mechanism, so
maybe one option is to combine both patches.
>
> Changed since v1:
>
> - Added one line comment to new files.
> - In nldbl-compat.c, added explanation for the need to use
> '#if SHLIB_COMPAT' within 'if LONG_DOUBLE_COMPAT'. Also moved the
> block further down, for stylistic reasons [1].
> - Added attribute_hidden to the internal (libioP.h) declarations of
> __vfscanf_internal and __vfwscanf_internal [2].
> - Added comment explaining the reason for the use of SHLIB_COMPAT on
> stdio-common/iovfscanf.c and stdio-common/iovfwscanf.c.
> - Converted the definition of ldbl_compat_symbol from an expansion of
> compat_symbol to '...', because ldbl_compat_symbol is also not
> supposed to be used outside of '#if SHLIB_COMPAT' statements. In my
> opinion, it's better to make this clear in the definition of
> ldbl_compat_symbol itself, rather than having to go to the
> definition of compat_symbol to learn this (if people think that this
> is not the best option, I can revert this change (In that case, the
> definition of ldbl_compat_symbol could be moved outside the '#if
> SHARED' block). Added a comment with this explanation.
> - Added signed-off-by statements.
> - Replaced 2.28 with 2.29 to adjust for the next release.
>
> Not changed since v1:
>
> - Florian suggested that the need for ldbl_compat_symbol is
> questionable, because we could define LONG_DOUBLE_COMPAT_VERSION to
> GLIBC_2_0 by default (pretending that the long double transition
> happened for all other platforms), then use it in compat_symbol
> calls, which would create the compat symbols for _IO_vfscanf and
> _IO_vfwscanf with that version.
> That would work, because all the functions that will use
> ldbl_compat_symbol after this patch set were actually introduced
> before GLIBC_2_0. However, for newer functions, such as swscanf,
> that wouldn't work, if we ever need to do something similar.
>
> Additional note for review:
>
> - Reviewing the changes from vfscanf.c to vfscanf-internal.c in the
> original patch would be vey hard, because git doesn't detect the
> filename change. To make review a little easier, I did as Zack did
> and manually edited the diff. I'll reply to this thread and attach
> the original patch if someone wants to apply it.
> (ping me if I forget it)
>
> [1] https://sourceware.org/ml/libc-alpha/2018-03/msg00309.html
>
> [2] As a result, internal calls to __vfscanf_internal, on powerpc, do
> not use the PLT, the following blocks show the difference:
>
> Without __attribute__ (hidden):
> $ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
> 0014ea00 <__nldbl___vfscanf>:
> 14ea00: 94 21 ff f0 stwu r1,-16(r1)
> 14ea04: 38 c0 00 01 li r6,1
> 14ea08: 7c 08 02 a6 mflr r0
> 14ea0c: 42 9f 00 05 bcl 20,4*cr7+so,14ea10 <__nldbl___vfscanf+0x10>
> 14ea10: 93 c1 00 08 stw r30,8(r1)
> 14ea14: 90 01 00 14 stw r0,20(r1)
> 14ea18: 7f c8 02 a6 mflr r30
> 14ea1c: 3f de 00 05 addis r30,r30,5
> 14ea20: 3b de 15 e4 addi r30,r30,5604
> 14ea24: 4b f0 b8 0d bl 5a230 <__vfscanf_internal>
> 14ea28: 80 01 00 14 lwz r0,20(r1)
> 14ea2c: 83 c1 00 08 lwz r30,8(r1)
> 14ea30: 38 21 00 10 addi r1,r1,16
> 14ea34: 7c 08 03 a6 mtlr r0
> 14ea38: 4e 80 00 20 blr
> 14ea3c: 60 00 00 00 nop
>
> With __attribute__ (hidden):
> $ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
> 0014e8b0 <__nldbl___vfscanf>:
> 14e8b0: 38 c0 00 01 li r6,1
> 14e8b4: 4b f0 b8 bc b 5a170 <__vfscanf_internal>
> 14e8b8: 60 00 00 00 nop
> 14e8bc: 60 00 00 00 nop
>
> -- 8< --
> There are two flags currently defined: SCANF_LDBL_IS_DBL is the mode
> used by __nldbl_ scanf variants, and SCANF_ISOC99_A is the mode used
> by __isoc99_ scanf variants. In this patch, the new functions honor
> these flag bits if they're set, but they still also look at the
> corresponding bits of environmental state, and callers all pass zero.
>
> The new functions do *not* have the "errp" argument possessed by
> _IO_vfscanf and _IO_vfwscanf. All internal callers passed NULL for
> that argument. External callers could theoretically exist, so I
> preserved wrappers, but they are flagged as compat symbols and they
> don't preserve the three-way distinction among types of errors that
> was formerly exposed. These functions probably should have been in
> the list of deprecated _IO_ symbols in 2.27 NEWS -- they're not just
> aliases for vfscanf and vfwscanf.
>
> (It was necessary to introduce ldbl_compat_symbol for _IO_vfscanf.
> Please check that part of the patch very carefully, I am still not
> confident I understand all of the details of ldbl-opt.)
>
> This patch also introduces helper inlines in libio/strfile.h that
> encapsulate the process of initializing an _IO_strfile object for
> reading. This allows us to call __vfscanf_internal directly from
> sscanf, and __vfwscanf_internal directly from swscanf, without
> duplicating the initialization code. (Previously, they called their
> v-counterparts, but that won't work if we want to control *both* C99
> mode and ldbl-is-dbl mode using the flags argument to__vfscanf_internal.)
> It's still a little awkward, especially for wide strfiles, but it's
> much better than what we had.
>
> Tested for powerpc and powerpc64le.
>
> 2018-10-16 Zack Weinberg <zackw@panix.com>
> Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
>
> * libio/libioP.h (SCANF_LDBL_IS_DBL, SCANF_ISOC99_A): New constants.
> (__vfscanf_internal, __vfwscanf_internal): New function prototypes.
> * libio/libio.h: Remove libc_hidden_proto for _IO_vfscanf.
> * libio/strfile.h: Add multiple inclusion guard.
> (_IO_strfile_read, _IO_strfile_readw): New inline functions.
>
> * sysdeps/generic/math_ldbl_opt.h: Include shlib-compat.h, for
> consistency with the other version of this file.
> (ldbl_compat_symbol): New macro.
> * sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h (ldbl_compat_symbol):
> New macro.
>
> * stdio-common/vfscanf-internal.c: Rename from vfscanf.c.
> Define __vfscanf_internal or __vfwscanf_internal, depending on
> COMPILE_WSCANF; don't define any other public symbols.
> Remove errval and code to set errp.
> Temporarily check __ldbl_is_dbl and _IO_FLAGS2_SCANF_STD as well
> as the mode_flags argument.
> (encode_error, conv_error, input_error): Don't set errval.
> * stdio-common/vfwscanf-internal.c: Rename from vfwscanf.c.
> Include vfscanf-internal.c.
> * stdio-common/vfscanf.c: New file defining the public entry
> point vfscanf, which calls __vfscanf_internal.
> * stdio-common/vfwscanf.c: New file defining the public entry
> point vfwscanf, which calls __vfwscanf_internal.
>
> * stdio-common/iovfscanf.c: New file.
> * stdio-common/iovfwscanf.c: Likewise.
>
> * stdio-common/Makefile (routines): Add vfscanf-internal,
> vfwscanf-internal, iovfscanf, iovfwscanf.
> * stdio-common/Versions: Mention GLIBC_2.29, so that
> it can be used in SHLIB_COMPAT expressions.
> * sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl__IO_vfscanf):
> Wrap definition and compat_symbol line in #if SHLIB_COMPAT.
> Call __vfscanf_internal, instead of _IO_vfscanf.
> (__nldbl___vfscanf): Call __vfscanf_internal, instead of
> _IO_vfscanf.
> (__nldbl_vfwscanf): Call __vfwscanf_internal, instead of
> _IO_vfwscanf.
>
> * libio/iovsscanf.c: Clean up includes, when possible. Use
> _IO_strfile_read or _IO_strfile_readw, when needed. Call
> __vfscanf_internal or __vfwscanf_internal directly.
> * libio/iovswscanf.c: Likewise.
> * libio/swscanf.c: Likewise.
> * libio/vscanf.c: Likewise.
> * libio/vwscanf.c: Likewise.
> * libio/wscanf.c: Likewise.
> * stdio-common/isoc99_fscanf.c: Likewise.
> * stdio-common/isoc99_scanf.c: Likewise.
> * stdio-common/isoc99_sscanf.c: Likewise.
> * stdio-common/isoc99_vfscanf.c: Likewise.
> * stdio-common/isoc99_vscanf.c: Likewise.
> * stdio-common/isoc99_vsscanf.c: Likewise.
> * stdio-common/scanf.c: Likewise.
> * stdio-common/sscanf.c: Likewise.
> * wcsmbs/isoc99_fwscanf.c: Likewise.
> * wcsmbs/isoc99_swscanf.c: Likewise.
> * wcsmbs/isoc99_vfwscanf.c: Likewise.
> * wcsmbs/isoc99_vswscanf.c: Likewise.
> * wcsmbs/isoc99_vwscanf.c: Likewise.
> * wcsmbs/isoc99_wscanf.c: Likewise.
> ---
> libio/iovsscanf.c | 12 +-
> libio/iovswscanf.c | 14 +-
> libio/libio.h | 1 -
> libio/libioP.h | 22 +
> libio/strfile.h | 33 +-
> libio/swscanf.c | 10 +-
> libio/vscanf.c | 2 +-
> libio/vwscanf.c | 2 +-
> libio/wscanf.c | 2 +-
> stdio-common/Makefile | 3 +-
> stdio-common/Versions | 3 +
> stdio-common/{isoc99_scanf.c => iovfscanf.c} | 36 +-
> stdio-common/{isoc99_scanf.c => iovfwscanf.c} | 36 +-
> stdio-common/isoc99_fscanf.c | 2 +-
> stdio-common/isoc99_scanf.c | 2 +-
> stdio-common/isoc99_sscanf.c | 9 +-
> stdio-common/isoc99_vfscanf.c | 2 +-
> stdio-common/isoc99_vscanf.c | 2 +-
> stdio-common/isoc99_vsscanf.c | 17 +-
> stdio-common/scanf.c | 2 +-
> stdio-common/sscanf.c | 12 +-
> stdio-common/{vfscanf.c => vfscanf-internal.c} | 48 +-
> stdio-common/vfscanf.c | 3042 +-----------------------
> stdio-common/vfwscanf-internal.c | 2 +
> stdio-common/vfwscanf.c | 28 +-
> sysdeps/generic/math_ldbl_opt.h | 4 +
> sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h | 6 +
> sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 17 +-
> wcsmbs/isoc99_fwscanf.c | 2 +-
> wcsmbs/isoc99_swscanf.c | 12 +-
> wcsmbs/isoc99_vfwscanf.c | 2 +-
> wcsmbs/isoc99_vswscanf.c | 16 +-
> wcsmbs/isoc99_vwscanf.c | 2 +-
> wcsmbs/isoc99_wscanf.c | 2 +-
> 34 files changed, 204 insertions(+), 3203 deletions(-)
> copy stdio-common/{isoc99_scanf.c => iovfscanf.c} (54%)
> copy stdio-common/{isoc99_scanf.c => iovfwscanf.c} (54%)
> copy stdio-common/{vfscanf.c => vfscanf-internal.c} (98%)
> create mode 100644 stdio-common/vfwscanf-internal.c
>
> diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
> index e56ab8bd7d..ee6a99ec6a 100644
> --- a/libio/iovsscanf.c
> +++ b/libio/iovsscanf.c
> @@ -24,22 +24,14 @@
> This exception applies to code released by its copyright holders
> in files containing the exception. */
>
> -#include "libioP.h"
> #include "strfile.h"
>
> int
> _IO_vsscanf (const char *string, const char *format, va_list args)
> {
> - int ret;
> _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> - sf._sbf._f._lock = NULL;
> -#endif
> - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> - _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> - _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> - ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> - return ret;
> + FILE *f = _IO_strfile_read (&sf, string);
> + return __vfscanf_internal (f, format, args, 0);
> }
> ldbl_weak_alias (_IO_vsscanf, __vsscanf)
> ldbl_weak_alias (_IO_vsscanf, vsscanf)
Ok.
> diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
> index 5bd1c88412..cb9cbe15cc 100644
> --- a/libio/iovswscanf.c
> +++ b/libio/iovswscanf.c
> @@ -24,24 +24,16 @@
> This exception applies to code released by its copyright holders
> in files containing the exception. */
>
> -#include "libioP.h"
> -#include "strfile.h"
> #include <wchar.h>
> +#include "strfile.h"
>
> int
> __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
> {
> - int ret;
> _IO_strfile sf;
> struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> - sf._sbf._f._lock = NULL;
> -#endif
> - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> - _IO_fwide (&sf._sbf._f, 1);
> - _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> - ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> - return ret;
> + FILE *f = _IO_strfile_readw (&sf, &wd, string);
> + return __vfwscanf_internal (f, format, args, 0);
> }
> libc_hidden_def (__vswscanf)
> ldbl_hidden_def (__vswscanf, vswscanf)
Ok.
> diff --git a/libio/libio.h b/libio/libio.h
> index 00f9169613..d4eba2df54 100644
> --- a/libio/libio.h
> +++ b/libio/libio.h
> @@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
> libc_hidden_proto (_IO_putc)
> libc_hidden_proto (_IO_sgetn)
> libc_hidden_proto (_IO_vfprintf)
> -libc_hidden_proto (_IO_vfscanf)
>
> #ifdef _IO_MTSAFE_IO
> # undef _IO_peekc
Ok.
> diff --git a/libio/libioP.h b/libio/libioP.h
> index df2633d858..525dce19ee 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -704,6 +704,28 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
>
> #endif /* _G_HAVE_MMAP */
>
> +/* Flags for __vfscanf_internal and __vfwscanf_internal.
> +
> + SCANF_LDBL_IS_DBL indicates whether long double values are to be
> + handled as having the same format as double, in which case the flag
> + should be set to one, or as another format, otherwise.
> +
> + SCANF_ISOC99_A, when set to one, indicates that the ISO C99 or POSIX
> + behavior of the scanf functions is to be used, i.e. automatic
> + allocation for input strings with %as, %aS and %a[, a GNU extension,
> + is disabled. This is the behavior that the __isoc99_scanf family of
> + functions use. When the flag is set to zero, automatic allocation is
> + enabled. */
> +#define SCANF_LDBL_IS_DBL 0x0001
> +#define SCANF_ISOC99_A 0x0002
> +
> +extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
> + unsigned int flags)
> + attribute_hidden;
> +extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
> + unsigned int flags)
> + attribute_hidden;
> +
> extern int _IO_vscanf (const char *, va_list) __THROW;
>
> #ifdef _IO_MTSAFE_IO
Ok.
> diff --git a/libio/strfile.h b/libio/strfile.h
> index 75caac2af5..62900a7128 100644
> --- a/libio/strfile.h
> +++ b/libio/strfile.h
> @@ -24,7 +24,9 @@
> This exception applies to code released by its copyright holders
> in files containing the exception. */
>
> -#include <stdio.h>
> +#ifndef STRFILE_H_
> +#define STRFILE_H_
> +
> #include "libioP.h"
>
> typedef void *(*_IO_alloc_type) (size_t);
> @@ -80,3 +82,32 @@ typedef struct
> } _IO_wstrnfile;
>
> extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
> +
> +/* Initialize an _IO_strfile SF to read from narrow string STRING, and
> + return the corresponding FILE object. It is not necessary to fclose
> + the FILE when it is no longer needed. */
> +static inline FILE *
> +_IO_strfile_read (_IO_strfile *sf, const char *string)
> +{
> + sf->_sbf._f._lock = NULL;
> + _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> + _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
> + _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
> + return &sf->_sbf._f;
> +}
> +
> +/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
> + string STRING, and return the corresponding FILE object. It is not
> + necessary to fclose the FILE when it is no longer needed. */
> +static inline FILE *
> +_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
> + const wchar_t *string)
> +{
> + sf->_sbf._f._lock = NULL;
> + _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
> + _IO_fwide (&sf->_sbf._f, 1);
> + _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
> + return &sf->_sbf._f;
> +}
> +
> +#endif /* strfile.h. */
Ok.
> diff --git a/libio/swscanf.c b/libio/swscanf.c
> index c8686bcbaf..90f721cc51 100644
> --- a/libio/swscanf.c
> +++ b/libio/swscanf.c
> @@ -15,20 +15,22 @@
> License along with the GNU C Library; if not, see
> <http://www.gnu.org/licenses/>. */
>
> -#include <libioP.h>
> #include <stdarg.h>
> -#include <wchar.h>
> +#include "strfile.h"
>
> /* Read formatted input from S, according to the format string FORMAT. */
> -/* VARARGS2 */
> +
> int
> __swscanf (const wchar_t *s, const wchar_t *format, ...)
> {
> va_list arg;
> int done;
> + _IO_strfile sf;
> + struct _IO_wide_data wd;
> + FILE *f = _IO_strfile_readw (&sf, &wd, s);
>
> va_start (arg, format);
> - done = __vswscanf (s, format, arg);
> + done = __vfwscanf_internal (f, format, arg, 0);
> va_end (arg);
>
> return done;
Ok.
> diff --git a/libio/vscanf.c b/libio/vscanf.c
> index 9c27122c27..a3e2dd43f2 100644
> --- a/libio/vscanf.c
> +++ b/libio/vscanf.c
> @@ -32,6 +32,6 @@
> int
> _IO_vscanf (const char *format, va_list args)
> {
> - return _IO_vfscanf (_IO_stdin, format, args, NULL);
> + return __vfscanf_internal (_IO_stdin, format, args, 0);
> }
> ldbl_weak_alias (_IO_vscanf, vscanf)
Ok.
> diff --git a/libio/vwscanf.c b/libio/vwscanf.c
> index 0d5f558758..7af770c8c3 100644
> --- a/libio/vwscanf.c
> +++ b/libio/vwscanf.c
> @@ -30,6 +30,6 @@
> int
> __vwscanf (const wchar_t *format, va_list args)
> {
> - return _IO_vfwscanf (_IO_stdin, format, args, NULL);
> + return __vfwscanf_internal (_IO_stdin, format, args, 0);
> }
> ldbl_strong_alias (__vwscanf, vwscanf)
Ok.
> diff --git a/libio/wscanf.c b/libio/wscanf.c
> index c8cdad0acd..fe27ff6fa6 100644
> --- a/libio/wscanf.c
> +++ b/libio/wscanf.c
> @@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
> int done;
>
> va_start (arg, format);
> - done = _IO_vfwscanf (stdin, format, arg, NULL);
> + done = __vfwscanf_internal (stdin, format, arg, 0);
> va_end (arg);
>
> return done;
Ok.
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index a10f12ab3c..f3b3ceddbd 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -39,7 +39,8 @@ routines := \
> flockfile ftrylockfile funlockfile \
> isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
> isoc99_vsscanf \
> - psiginfo gentempfd
> + psiginfo gentempfd \
> + vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
>
> aux := errlist siglist printf-parsemb printf-parsewc fxprintf
>
Ok.
> diff --git a/stdio-common/Versions b/stdio-common/Versions
> index b8217578c8..522f302198 100644
> --- a/stdio-common/Versions
> +++ b/stdio-common/Versions
> @@ -60,6 +60,9 @@ libc {
> GLIBC_2.28 {
> renameat2;
> }
> + GLIBC_2.29 {
> + # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) used in iovfscanf.c etc.
> + }
> GLIBC_PRIVATE {
> # global variables
> _itoa_lower_digits;
Ok.
> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfscanf.c
> similarity index 54%
> copy from stdio-common/isoc99_scanf.c
> copy to stdio-common/iovfscanf.c
> index bf7dbe86bb..77e698f665 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/iovfscanf.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Implementation and symbols for _IO_vfscanf.
> + Copyright (C) 2018 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -15,30 +16,23 @@
> License along with the GNU C Library; if not, see
> <http://www.gnu.org/licenses/>. */
>
> -#include <stdarg.h>
> -#include <stdio.h>
> #include <libioP.h>
> +#include <shlib-compat.h>
>
> +/* This function is provided for ports older than GLIBC 2.29 because
> + external callers could theoretically exist. Newer ports do not need,
> + since it is not part of the API. */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>
> -/* Read formatted input from stdin according to the format string FORMAT. */
> -/* VARARGS1 */
> int
> -__isoc99_scanf (const char *format, ...)
> +attribute_compat_text_section
> +__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
> {
> - va_list arg;
> - int done;
> -
> -#ifdef _IO_MTSAFE_IO
> - _IO_acquire_lock_clear_flags2 (stdin);
> -#endif
> - stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
> - va_start (arg, format);
> - done = _IO_vfscanf (stdin, format, arg, NULL);
> - va_end (arg);
> + int rv = __vfscanf_internal (fp, format, ap, 0);
> + if (__glibc_unlikely (errp != 0))
> + *errp = (rv == -1);
> + return rv;
> +}
> +ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
>
> -#ifdef _IO_MTSAFE_IO
> - _IO_release_lock (stdin);
> #endif
> - return done;
> -}
Ok.
> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfwscanf.c
> similarity index 54%
> copy from stdio-common/isoc99_scanf.c
> copy to stdio-common/iovfwscanf.c
> index bf7dbe86bb..26a57788cb 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/iovfwscanf.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Implementation and symbols for _IO_vfwscanf.
> + Copyright (C) 1991-2018 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -15,30 +16,23 @@
> License along with the GNU C Library; if not, see
> <http://www.gnu.org/licenses/>. */
>
> -#include <stdarg.h>
> -#include <stdio.h>
> #include <libioP.h>
> +#include <shlib-compat.h>
>
> +/* This function is provided for ports older than GLIBC 2.29 because
> + external callers could theoretically exist. Newer ports do not need,
> + since it is not part of the API. */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
>
> -/* Read formatted input from stdin according to the format string FORMAT. */
> -/* VARARGS1 */
> int
> -__isoc99_scanf (const char *format, ...)
> +attribute_compat_text_section
> +__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
> {
> - va_list arg;
> - int done;
> -
> -#ifdef _IO_MTSAFE_IO
> - _IO_acquire_lock_clear_flags2 (stdin);
> -#endif
> - stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> -
> - va_start (arg, format);
> - done = _IO_vfscanf (stdin, format, arg, NULL);
> - va_end (arg);
> + int rv = __vfwscanf_internal (fp, format, ap, 0);
> + if (__glibc_unlikely (errp != 0))
> + *errp = (rv == -1);
> + return rv;
> +}
> +compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
>
> -#ifdef _IO_MTSAFE_IO
> - _IO_release_lock (stdin);
> #endif
> - return done;
> -}
Ok.
> diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
> index 9cdf85e679..4210d11f2b 100644
> --- a/stdio-common/isoc99_fscanf.c
> +++ b/stdio-common/isoc99_fscanf.c
> @@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
> stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = _IO_vfscanf (stream, format, arg, NULL);
> + done = __vfscanf_internal (stream, format, arg, 0);
> va_end (arg);
>
> _IO_release_lock (stream);
Ok.
> diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
> index bf7dbe86bb..64c873eed9 100644
> --- a/stdio-common/isoc99_scanf.c
> +++ b/stdio-common/isoc99_scanf.c
> @@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
> stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = _IO_vfscanf (stdin, format, arg, NULL);
> + done = __vfscanf_internal (stdin, format, arg, 0);
> va_end (arg);
>
> #ifdef _IO_MTSAFE_IO
Ok.
> diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
> index 56a60a2c05..2c89a03fe9 100644
> --- a/stdio-common/isoc99_sscanf.c
> +++ b/stdio-common/isoc99_sscanf.c
> @@ -16,19 +16,20 @@
> <http://www.gnu.org/licenses/>. */
>
> #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> +#include <libio/strfile.h>
>
> /* Read formatted input from S, according to the format string FORMAT. */
> -/* VARARGS2 */
> int
> __isoc99_sscanf (const char *s, const char *format, ...)
> {
> va_list arg;
> int done;
> + _IO_strfile sf;
> + FILE *f = _IO_strfile_read (&sf, s);
> + f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = __isoc99_vsscanf (s, format, arg);
> + done = __vfscanf_internal (f, format, arg, 0);
> va_end (arg);
>
> return done;
I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
Wouldn't be more consistent to fold the second patch in this set, which replace
_IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
removed in a subsequent patch?
> diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
> index b80e05f8db..c96ca831ae 100644
> --- a/stdio-common/isoc99_vfscanf.c
> +++ b/stdio-common/isoc99_vfscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
>
> _IO_acquire_lock_clear_flags2 (stream);
> stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> - done = _IO_vfscanf (stream, format, args, NULL);
> + done = __vfscanf_internal (stream, format, args, 0);
> _IO_release_lock (stream);
> return done;
> }
Ok.
> diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
> index 0b747f85ba..72ae72ddee 100644
> --- a/stdio-common/isoc99_vscanf.c
> +++ b/stdio-common/isoc99_vscanf.c
> @@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
>
> _IO_acquire_lock_clear_flags2 (stdin);
> stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> - done = _IO_vfscanf (stdin, format, args, NULL);
> + done = __vfscanf_internal (stdin, format, args, 0);
> _IO_release_lock (stdin);
> return done;
> }
Ok.
> diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
> index ac85ef2d0d..02bc0f50e6 100644
> --- a/stdio-common/isoc99_vsscanf.c
> +++ b/stdio-common/isoc99_vsscanf.c
> @@ -24,23 +24,14 @@
> This exception applies to code released by its copyright holders
> in files containing the exception. */
>
> -#include <libioP.h>
> -#include <stdio.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>
> int
> __isoc99_vsscanf (const char *string, const char *format, va_list args)
> {
> - int ret;
> _IO_strfile sf;
> -#ifdef _IO_MTSAFE_IO
> - sf._sbf._f._lock = NULL;
> -#endif
> - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
> - _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
> - _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
> - sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> - ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
> - return ret;
> + FILE *f = _IO_strfile_read (&sf, string);
> + f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> + return __vfscanf_internal (f, format, args, 0);
> }
> libc_hidden_def (__isoc99_vsscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
> diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
> index e61b5f1ad3..de38d70353 100644
> --- a/stdio-common/scanf.c
> +++ b/stdio-common/scanf.c
> @@ -30,7 +30,7 @@ __scanf (const char *format, ...)
> int done;
>
> va_start (arg, format);
> - done = _IO_vfscanf (stdin, format, arg, NULL);
> + done = __vfscanf_internal (stdin, format, arg, 0);
> va_end (arg);
>
> return done;
Ok.
> diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
> index 88cd641798..e25e9c27a5 100644
> --- a/stdio-common/sscanf.c
> +++ b/stdio-common/sscanf.c
> @@ -16,26 +16,24 @@
> <http://www.gnu.org/licenses/>. */
>
> #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
> +#include <libio/strfile.h>
>
> /* Read formatted input from S, according to the format string FORMAT. */
> -/* VARARGS2 */
> +
> int
> __sscanf (const char *s, const char *format, ...)
> {
> va_list arg;
> int done;
> + _IO_strfile sf;
> + FILE *f = _IO_strfile_read (&sf, s);
>
> va_start (arg, format);
> - done = __vsscanf (s, format, arg);
> + done = __vfscanf_internal (f, format, arg, 0);
> va_end (arg);
>
> return done;
> }
> ldbl_hidden_def (__sscanf, sscanf)
> ldbl_strong_alias (__sscanf, sscanf)
> -#undef _IO_sscanf
> -/* This is for libg++. */
> ldbl_strong_alias (__sscanf, _IO_sscanf)
Ok.
> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
> similarity index 98%
> copy from stdio-common/vfscanf.c
> copy to stdio-common/vfscanf-internal.c
Ok.
> index 1ce836a324..13a7a300b7 100644
> --- a/stdio-common/vfscanf.c
> +++ b/stdio-common/vfscanf-internal.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
> +/* Internal functions for the *scanf* implementation.
> + Copyright (C) 1991-2018 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -132,16 +133,13 @@
> #include "printf-parse.h" /* Use read_int. */
>
> #define encode_error() do { \
> - errval = 4; \
> __set_errno (EILSEQ); \
> goto errout; \
> } while (0)
> #define conv_error() do { \
> - errval = 2; \
> goto errout; \
> } while (0)
> #define input_error() do { \
> - errval = 1; \
> if (done == 0) done = EOF; \
> goto errout; \
> } while (0)
> @@ -267,12 +265,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
> Return the number of assignments made, or -1 for an input error. */
> #ifdef COMPILE_WSCANF
> int
> -_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
> - int *errp)
> +__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
> + unsigned int mode_flags)
> #else
> int
> -_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> - int *errp)
> +__vfscanf_internal (FILE *s, const char *format, va_list argptr,
> + unsigned int mode_flags)
> #endif
> {
> va_list arg;
> @@ -283,7 +281,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> WINT_T c = 0; /* Last char read. */
> int width; /* Maximum field width. */
> int flags; /* Modifiers for current format element. */
> - int errval = 0;
> #ifndef COMPILE_WSCANF
> locale_t loc = _NL_CURRENT_LOCALE;
> struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
> @@ -335,6 +332,12 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> struct char_buffer charbuf;
> scratch_buffer_init (&charbuf.scratch);
>
> + /* Temporarily honor the environmental mode bits. */
> + if (__ldbl_is_dbl)
> + mode_flags |= SCANF_LDBL_IS_DBL;
> + if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> + mode_flags |= SCANF_ISOC99_A;
> +> #ifdef __va_copy
> __va_copy (arg, argptr);
> #else
> @@ -566,7 +569,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> }
> /* In __isoc99_*scanf %as, %aS and %a[ extension is not
> supported at all. */
> - if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> + if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))
> {
> --f;
> break;
> @@ -2423,7 +2426,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> done = EOF;
> goto errout;
> }
> - if ((flags & LONGDBL) && !__ldbl_is_dbl)
> + if ((flags & LONGDBL) \
> + && __glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
> {
> long double d = __strtold_internal
> (char_buffer_start (&charbuf), &tw, flags & GROUP);
> @@ -3018,8 +3022,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> UNLOCK_STREAM (s);
>
> scratch_buffer_free (&charbuf.scratch);
> - if (errp != NULL)
> - *errp |= errval;
>
> if (__glibc_unlikely (done == EOF))
> {
> @@ -3045,23 +3047,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> }
> return done;
> }
> -
> -#ifdef COMPILE_WSCANF
> -int
> -__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> -{
> - return _IO_vfwscanf (s, format, argptr, NULL);
> -}
> -ldbl_weak_alias (__vfwscanf, vfwscanf)
> -#else
> -int
> -___vfscanf (FILE *s, const char *format, va_list argptr)
> -{
> - return _IO_vfscanf_internal (s, format, argptr, NULL);
> -}
> -ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_strong_alias (___vfscanf, __vfscanf)
> -ldbl_hidden_def (___vfscanf, __vfscanf)
> -ldbl_weak_alias (___vfscanf, vfscanf)
> -#endif
Ok.
> diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
> index 1ce836a324..5eedca8340 100644
> --- a/stdio-common/vfscanf.c
> +++ b/stdio-common/vfscanf.c
Another option instead of -M which might generate more consise patches in
case of rename plus small rewrites is the -B option. In this case, -B/90%
avoid sending the full file removal and detect is has moved to another one
with some modifications.
> @@ -15,3053 +15,13 @@
> License along with the GNU C Library; if not, see
> <http://www.gnu.org/licenses/>. */
>
> -#include <assert.h>
> -#include <errno.h>
> -#include <limits.h>
> -#include <ctype.h>
> -#include <stdarg.h>
> -#include <stdbool.h>
> -#include <stdio.h>
> -#include <stdint.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <wchar.h>
> -#include <wctype.h>
> -#include <libc-diag.h>
> -#include <libc-lock.h>
> -#include <locale/localeinfo.h>
> -#include <scratch_buffer.h>
> -
> -#ifdef __GNUC__
> -# define HAVE_LONGLONG
> -# define LONGLONG long long
> -#else
> -# define LONGLONG long
> -#endif
> -
> -/* Determine whether we have to handle `long long' at all. */
> -#if LONG_MAX == LONG_LONG_MAX
> -# define need_longlong 0
> -#else
> -# define need_longlong 1
> -#endif
> -
> -/* Determine whether we have to handle `long'. */
> -#if INT_MAX == LONG_MAX
> -# define need_long 0
> -#else
> -# define need_long 1
> -#endif
> -
> -/* Those are flags in the conversion format. */
> -#define LONG 0x0001 /* l: long or double */
> -#define LONGDBL 0x0002 /* L: long long or long double */
> -#define SHORT 0x0004 /* h: short */
> -#define SUPPRESS 0x0008 /* *: suppress assignment */
> -#define POINTER 0x0010 /* weird %p pointer (`fake hex') */
> -#define NOSKIP 0x0020 /* do not skip blanks */
> -#define NUMBER_SIGNED 0x0040 /* signed integer */
> -#define GROUP 0x0080 /* ': group numbers */
> -#define GNU_MALLOC 0x0100 /* a: malloc strings */
> -#define CHAR 0x0200 /* hh: char */
> -#define I18N 0x0400 /* I: use locale's digits */
> -#define HEXA_FLOAT 0x0800 /* hexadecimal float */
> -#define READ_POINTER 0x1000 /* this is a pointer value */
> -#define POSIX_MALLOC 0x2000 /* m: malloc strings */
> -#define MALLOC (GNU_MALLOC | POSIX_MALLOC)
> -
> -#include <locale/localeinfo.h>
> #include <libioP.h>
>
> -#ifdef COMPILE_WSCANF
> -# define ungetc(c, s) ((void) (c == WEOF \
> - || (--read_in, \
> - _IO_sputbackwc (s, c))))
> -# define ungetc_not_eof(c, s) ((void) (--read_in, \
> - _IO_sputbackwc (s, c)))
> -# define inchar() (c == WEOF ? ((errno = inchar_errno), WEOF) \
> - : ((c = _IO_getwc_unlocked (s)), \
> - (void) (c != WEOF \
> - ? ++read_in \
> - : (size_t) (inchar_errno = errno)), c))
> -
> -# define ISSPACE(Ch) iswspace (Ch)
> -# define ISDIGIT(Ch) iswdigit (Ch)
> -# define ISXDIGIT(Ch) iswxdigit (Ch)
> -# define TOLOWER(Ch) towlower (Ch)
> -# define ORIENT if (_IO_fwide (s, 1) != 1) return WEOF
> -# define __strtoll_internal __wcstoll_internal
> -# define __strtoull_internal __wcstoull_internal
> -# define __strtol_internal __wcstol_internal
> -# define __strtoul_internal __wcstoul_internal
> -# define __strtold_internal __wcstold_internal
> -# define __strtod_internal __wcstod_internal
> -# define __strtof_internal __wcstof_internal
> -
> -# define L_(Str) L##Str
> -# define CHAR_T wchar_t
> -# define UCHAR_T unsigned int
> -# define WINT_T wint_t
> -# undef EOF
> -# define EOF WEOF
> -#else
> -# define ungetc(c, s) ((void) ((int) c == EOF \
> - || (--read_in, \
> - _IO_sputbackc (s, (unsigned char) c))))
> -# define ungetc_not_eof(c, s) ((void) (--read_in, \
> - _IO_sputbackc (s, (unsigned char) c)))
> -# define inchar() (c == EOF ? ((errno = inchar_errno), EOF) \
> - : ((c = _IO_getc_unlocked (s)), \
> - (void) (c != EOF \
> - ? ++read_in \
> - : (size_t) (inchar_errno = errno)), c))
> -# define ISSPACE(Ch) __isspace_l (Ch, loc)
> -# define ISDIGIT(Ch) __isdigit_l (Ch, loc)
> -# define ISXDIGIT(Ch) __isxdigit_l (Ch, loc)
> -# define TOLOWER(Ch) __tolower_l ((unsigned char) (Ch), loc)
> -# define ORIENT if (_IO_vtable_offset (s) == 0 \
> - && _IO_fwide (s, -1) != -1) \
> - return EOF
> -
> -# define L_(Str) Str
> -# define CHAR_T char
> -# define UCHAR_T unsigned char
> -# define WINT_T int
> -#endif
> -
> -#include "printf-parse.h" /* Use read_int. */
> -
> -#define encode_error() do { \
> - errval = 4; \
> - __set_errno (EILSEQ); \
> - goto errout; \
> - } while (0)
> -#define conv_error() do { \
> - errval = 2; \
> - goto errout; \
> - } while (0)
> -#define input_error() do { \
> - errval = 1; \
> - if (done == 0) done = EOF; \
> - goto errout; \
> - } while (0)
> -#define add_ptr_to_free(ptr) \
> - do \
> - { \
> - if (ptrs_to_free == NULL \
> - || ptrs_to_free->count == (sizeof (ptrs_to_free->ptrs) \
> - / sizeof (ptrs_to_free->ptrs[0]))) \
> - { \
> - struct ptrs_to_free *new_ptrs = alloca (sizeof (*ptrs_to_free)); \
> - new_ptrs->count = 0; \
> - new_ptrs->next = ptrs_to_free; \
> - ptrs_to_free = new_ptrs; \
> - } \
> - ptrs_to_free->ptrs[ptrs_to_free->count++] = (ptr); \
> - } \
> - while (0)
> -#define ARGCHECK(s, format) \
> - do \
> - { \
> - /* Check file argument for consistence. */ \
> - CHECK_FILE (s, EOF); \
> - if (s->_flags & _IO_NO_READS) \
> - { \
> - __set_errno (EBADF); \
> - return EOF; \
> - } \
> - else if (format == NULL) \
> - { \
> - __set_errno (EINVAL); \
> - return EOF; \
> - } \
> - } while (0)
> -#define LOCK_STREAM(S) \
> - __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, (S)); \
> - _IO_flockfile (S)
> -#define UNLOCK_STREAM(S) \
> - _IO_funlockfile (S); \
> - __libc_cleanup_region_end (0)
> -
> -struct ptrs_to_free
> -{
> - size_t count;
> - struct ptrs_to_free *next;
> - char **ptrs[32];
> -};
> -
> -struct char_buffer {
> - CHAR_T *current;
> - CHAR_T *end;
> - struct scratch_buffer scratch;
> -};
> -
> -/* Returns a pointer to the first CHAR_T object in the buffer. Only
> - valid if char_buffer_add (BUFFER, CH) has been called and
> - char_buffer_error (BUFFER) is false. */
> -static inline CHAR_T *
> -char_buffer_start (const struct char_buffer *buffer)
> -{
> - return (CHAR_T *) buffer->scratch.data;
> -}
> -
> -/* Returns the number of CHAR_T objects in the buffer. Only valid if
> - char_buffer_error (BUFFER) is false. */
> -static inline size_t
> -char_buffer_size (const struct char_buffer *buffer)
> -{
> - return buffer->current - char_buffer_start (buffer);
> -}
> -
> -/* Reinitializes BUFFER->current and BUFFER->end to cover the entire
> - scratch buffer. */
> -static inline void
> -char_buffer_rewind (struct char_buffer *buffer)
> -{
> - buffer->current = char_buffer_start (buffer);
> - buffer->end = buffer->current + buffer->scratch.length / sizeof (CHAR_T);
> -}
> -
> -/* Returns true if a previous call to char_buffer_add (BUFFER, CH)
> - failed. */
> -static inline bool
> -char_buffer_error (const struct char_buffer *buffer)
> -{
> - return __glibc_unlikely (buffer->current == NULL);
> -}
> -
> -/* Slow path for char_buffer_add. */
> -static void
> -char_buffer_add_slow (struct char_buffer *buffer, CHAR_T ch)
> -{
> - if (char_buffer_error (buffer))
> - return;
> - size_t offset = buffer->end - (CHAR_T *) buffer->scratch.data;
> - if (!scratch_buffer_grow_preserve (&buffer->scratch))
> - {
> - buffer->current = NULL;
> - buffer->end = NULL;
> - return;
> - }
> - char_buffer_rewind (buffer);
> - buffer->current += offset;
> - *buffer->current++ = ch;
> -}
> -
> -/* Adds CH to BUFFER. This function does not report any errors, check
> - for them with char_buffer_error. */
> -static inline void
> -char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
> - __attribute__ ((always_inline));
> -static inline void
> -char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
> -{
> - if (__glibc_unlikely (buffer->current == buffer->end))
> - char_buffer_add_slow (buffer, ch);
> - else
> - *buffer->current++ = ch;
> -}
> -
> -/* Read formatted input from S according to the format string
> - FORMAT, using the argument list in ARG.
> - Return the number of assignments made, or -1 for an input error. */
> -#ifdef COMPILE_WSCANF
> -int
> -_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
> - int *errp)
> -#else
> -int
> -_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
> - int *errp)
> -#endif
> -{
> - va_list arg;
> - const CHAR_T *f = format;
> - UCHAR_T fc; /* Current character of the format. */
> - WINT_T done = 0; /* Assignments done. */
> - size_t read_in = 0; /* Chars read in. */
> - WINT_T c = 0; /* Last char read. */
> - int width; /* Maximum field width. */
> - int flags; /* Modifiers for current format element. */
> - int errval = 0;
> -#ifndef COMPILE_WSCANF
> - locale_t loc = _NL_CURRENT_LOCALE;
> - struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
> -#endif
> -
> - /* Errno of last failed inchar call. */
> - int inchar_errno = 0;
> - /* Status for reading F-P nums. */
> - char got_digit, got_dot, got_e, got_sign;
> - /* If a [...] is a [^...]. */
> - CHAR_T not_in;
> -#define exp_char not_in
> - /* Base for integral numbers. */
> - int base;
> - /* Decimal point character. */
> -#ifdef COMPILE_WSCANF
> - wint_t decimal;
> -#else
> - const char *decimal;
> -#endif
> - /* The thousands character of the current locale. */
> -#ifdef COMPILE_WSCANF
> - wint_t thousands;
> -#else
> - const char *thousands;
> -#endif
> - struct ptrs_to_free *ptrs_to_free = NULL;
> - /* State for the conversions. */
> - mbstate_t state;
> - /* Integral holding variables. */
> - union
> - {
> - long long int q;
> - unsigned long long int uq;
> - long int l;
> - unsigned long int ul;
> - } num;
> - /* Character-buffer pointer. */
> - char *str = NULL;
> - wchar_t *wstr = NULL;
> - char **strptr = NULL;
> - ssize_t strsize = 0;
> - /* We must not react on white spaces immediately because they can
> - possibly be matched even if in the input stream no character is
> - available anymore. */
> - int skip_space = 0;
> - /* Workspace. */
> - CHAR_T *tw; /* Temporary pointer. */
> - struct char_buffer charbuf;
> - scratch_buffer_init (&charbuf.scratch);
> -
> -#ifdef __va_copy
> - __va_copy (arg, argptr);
> -#else
> - arg = (va_list) argptr;
> -#endif
> -
> -#ifdef ORIENT
> - ORIENT;
> -#endif
> -
> - ARGCHECK (s, format);
> -
> - {
> -#ifndef COMPILE_WSCANF
> - struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
> -#endif
> -
> - /* Figure out the decimal point character. */
> -#ifdef COMPILE_WSCANF
> - decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
> -#else
> - decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
> -#endif
> - /* Figure out the thousands separator character. */
> -#ifdef COMPILE_WSCANF
> - thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
> -#else
> - thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
> - if (*thousands == '\0')
> - thousands = NULL;
> -#endif
> - }
> -
> - /* Lock the stream. */
> - LOCK_STREAM (s);
> -
> -
> -#ifndef COMPILE_WSCANF
> - /* From now on we use `state' to convert the format string. */
> - memset (&state, '\0', sizeof (state));
> -#endif
> -
> - /* Run through the format string. */
> - while (*f != '\0')
> - {
> - unsigned int argpos;
> - /* Extract the next argument, which is of type TYPE.
> - For a %N$... spec, this is the Nth argument from the beginning;
> - otherwise it is the next argument after the state now in ARG. */
> -#ifdef __va_copy
> -# define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
> - ({ unsigned int pos = argpos; \
> - va_list arg; \
> - __va_copy (arg, argptr); \
> - while (--pos > 0) \
> - (void) va_arg (arg, void *); \
> - va_arg (arg, type); \
> - }))
> -#else
> -# if 0
> - /* XXX Possible optimization. */
> -# define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
> - ({ va_list arg = (va_list) argptr; \
> - arg = (va_list) ((char *) arg \
> - + (argpos - 1) \
> - * __va_rounded_size (void *)); \
> - va_arg (arg, type); \
> - }))
> -# else
> -# define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
> - ({ unsigned int pos = argpos; \
> - va_list arg = (va_list) argptr; \
> - while (--pos > 0) \
> - (void) va_arg (arg, void *); \
> - va_arg (arg, type); \
> - }))
> -# endif
> -#endif
> -
> -#ifndef COMPILE_WSCANF
> - if (!isascii ((unsigned char) *f))
> - {
> - /* Non-ASCII, may be a multibyte. */
> - int len = __mbrlen (f, strlen (f), &state);
> - if (len > 0)
> - {
> - do
> - {
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> - else if (c != (unsigned char) *f++)
> - {
> - ungetc_not_eof (c, s);
> - conv_error ();
> - }
> - }
> - while (--len > 0);
> - continue;
> - }
> - }
> -#endif
> -
> - fc = *f++;
> - if (fc != '%')
> - {
> - /* Remember to skip spaces. */
> - if (ISSPACE (fc))
> - {
> - skip_space = 1;
> - continue;
> - }
> -
> - /* Read a character. */
> - c = inchar ();
> -
> - /* Characters other than format specs must just match. */
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> - /* We saw white space char as the last character in the format
> - string. Now it's time to skip all leading white space. */
> - if (skip_space)
> - {
> - while (ISSPACE (c))
> - if (__glibc_unlikely (inchar () == EOF))
> - input_error ();
> - skip_space = 0;
> - }
> -
> - if (__glibc_unlikely (c != fc))
> - {
> - ungetc (c, s);
> - conv_error ();
> - }
> -
> - continue;
> - }
> -
> - /* This is the start of the conversion string. */
> - flags = 0;
> -
> - /* Initialize state of modifiers. */
> - argpos = 0;
> -
> - /* Prepare temporary buffer. */
> - char_buffer_rewind (&charbuf);
> -
> - /* Check for a positional parameter specification. */
> - if (ISDIGIT ((UCHAR_T) *f))
> - {
> - argpos = read_int ((const UCHAR_T **) &f);
> - if (*f == L_('$'))
> - ++f;
> - else
> - {
> - /* Oops; that was actually the field width. */
> - width = argpos;
> - argpos = 0;
> - goto got_width;
> - }
> - }
> -
> - /* Check for the assignment-suppressing, the number grouping flag,
> - and the signal to use the locale's digit representation. */
> - while (*f == L_('*') || *f == L_('\'') || *f == L_('I'))
> - switch (*f++)
> - {
> - case L_('*'):
> - flags |= SUPPRESS;
> - break;
> - case L_('\''):
> -#ifdef COMPILE_WSCANF
> - if (thousands != L'\0')
> -#else
> - if (thousands != NULL)
> -#endif
> - flags |= GROUP;
> - break;
> - case L_('I'):
> - flags |= I18N;
> - break;
> - }
> -
> - /* Find the maximum field width. */
> - width = 0;
> - if (ISDIGIT ((UCHAR_T) *f))
> - width = read_int ((const UCHAR_T **) &f);
> - got_width:
> - if (width == 0)
> - width = -1;
> -
> - /* Check for type modifiers. */
> - switch (*f++)
> - {
> - case L_('h'):
> - /* ints are short ints or chars. */
> - if (*f == L_('h'))
> - {
> - ++f;
> - flags |= CHAR;
> - }
> - else
> - flags |= SHORT;
> - break;
> - case L_('l'):
> - if (*f == L_('l'))
> - {
> - /* A double `l' is equivalent to an `L'. */
> - ++f;
> - flags |= LONGDBL | LONG;
> - }
> - else
> - /* ints are long ints. */
> - flags |= LONG;
> - break;
> - case L_('q'):
> - case L_('L'):
> - /* doubles are long doubles, and ints are long long ints. */
> - flags |= LONGDBL | LONG;
> - break;
> - case L_('a'):
> - /* The `a' is used as a flag only if followed by `s', `S' or
> - `['. */
> - if (*f != L_('s') && *f != L_('S') && *f != L_('['))
> - {
> - --f;
> - break;
> - }
> - /* In __isoc99_*scanf %as, %aS and %a[ extension is not
> - supported at all. */
> - if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
> - {
> - --f;
> - break;
> - }
> - /* String conversions (%s, %[) take a `char **'
> - arg and fill it in with a malloc'd pointer. */
> - flags |= GNU_MALLOC;
> - break;
> - case L_('m'):
> - flags |= POSIX_MALLOC;
> - if (*f == L_('l'))
> - {
> - ++f;
> - flags |= LONG;
> - }
> - break;
> - case L_('z'):
> - if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
> - flags |= LONGDBL;
> - else if (sizeof (size_t) > sizeof (unsigned int))
> - flags |= LONG;
> - break;
> - case L_('j'):
> - if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))
> - flags |= LONGDBL;
> - else if (sizeof (uintmax_t) > sizeof (unsigned int))
> - flags |= LONG;
> - break;
> - case L_('t'):
> - if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))
> - flags |= LONGDBL;
> - else if (sizeof (ptrdiff_t) > sizeof (int))
> - flags |= LONG;
> - break;
> - default:
> - /* Not a recognized modifier. Backup. */
> - --f;
> - break;
> - }
> -
> - /* End of the format string? */
> - if (__glibc_unlikely (*f == L_('\0')))
> - conv_error ();
> -
> - /* Find the conversion specifier. */
> - fc = *f++;
> - if (skip_space || (fc != L_('[') && fc != L_('c')
> - && fc != L_('C') && fc != L_('n')))
> - {
> - /* Eat whitespace. */
> - int save_errno = errno;
> - __set_errno (0);
> - do
> - /* We add the additional test for EOF here since otherwise
> - inchar will restore the old errno value which might be
> - EINTR but does not indicate an interrupt since nothing
> - was read at this time. */
> - if (__builtin_expect ((c == EOF || inchar () == EOF)
> - && errno == EINTR, 0))
> - input_error ();
> - while (ISSPACE (c));
> - __set_errno (save_errno);
> - ungetc (c, s);
> - skip_space = 0;
> - }
> -
> - switch (fc)
> - {
> - case L_('%'): /* Must match a literal '%'. */
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> - if (__glibc_unlikely (c != fc))
> - {
> - ungetc_not_eof (c, s);
> - conv_error ();
> - }
> - break;
> -
> - case L_('n'): /* Answer number of assignments done. */
> - /* Corrigendum 1 to ISO C 1990 describes the allowed flags
> - with the 'n' conversion specifier. */
> - if (!(flags & SUPPRESS))
> - {
> - /* Don't count the read-ahead. */
> - if (need_longlong && (flags & LONGDBL))
> - *ARG (long long int *) = read_in;
> - else if (need_long && (flags & LONG))
> - *ARG (long int *) = read_in;
> - else if (flags & SHORT)
> - *ARG (short int *) = read_in;
> - else if (!(flags & CHAR))
> - *ARG (int *) = read_in;
> - else
> - *ARG (char *) = read_in;
> -
> -#ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1
> - /* We have a severe problem here. The ISO C standard
> - contradicts itself in explaining the effect of the %n
> - format in `scanf'. While in ISO C:1990 and the ISO C
> - Amendement 1:1995 the result is described as
> -
> - Execution of a %n directive does not effect the
> - assignment count returned at the completion of
> - execution of the f(w)scanf function.
> -
> - in ISO C Corrigendum 1:1994 the following was added:
> -
> - Subclause 7.9.6.2
> - Add the following fourth example:
> - In:
> - #include <stdio.h>
> - int d1, d2, n1, n2, i;
> - i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
> - the value 123 is assigned to d1 and the value3 to n1.
> - Because %n can never get an input failure the value
> - of 3 is also assigned to n2. The value of d2 is not
> - affected. The value 3 is assigned to i.
> -
> - We go for now with the historically correct code from ISO C,
> - i.e., we don't count the %n assignments. When it ever
> - should proof to be wrong just remove the #ifdef above. */
> - ++done;
> -#endif
> - }
> - break;
> -
> - case L_('c'): /* Match characters. */
> - if ((flags & LONG) == 0)
> - {
> - if (width == -1)
> - width = 1;
> -
> -#define STRING_ARG(Str, Type, Width) \
> - do if (!(flags & SUPPRESS)) \
> - { \
> - if (flags & MALLOC) \
> - { \
> - /* The string is to be stored in a malloc'd buffer. */ \
> - /* For %mS using char ** is actually wrong, but \
> - shouldn't make a difference on any arch glibc \
> - supports and would unnecessarily complicate \
> - things. */ \
> - strptr = ARG (char **); \
> - if (strptr == NULL) \
> - conv_error (); \
> - /* Allocate an initial buffer. */ \
> - strsize = Width; \
> - *strptr = (char *) malloc (strsize * sizeof (Type)); \
> - Str = (Type *) *strptr; \
> - if (Str != NULL) \
> - add_ptr_to_free (strptr); \
> - else if (flags & POSIX_MALLOC) \
> - { \
> - done = EOF; \
> - goto errout; \
> - } \
> - } \
> - else \
> - Str = ARG (Type *); \
> - if (Str == NULL) \
> - conv_error (); \
> - } while (0)
> -#ifdef COMPILE_WSCANF
> - STRING_ARG (str, char, 100);
> -#else
> - STRING_ARG (str, char, (width > 1024 ? 1024 : width));
> -#endif
> -
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> -#ifdef COMPILE_WSCANF
> - /* We have to convert the wide character(s) into multibyte
> - characters and store the result. */
> - memset (&state, '\0', sizeof (state));
> -
> - do
> - {
> - size_t n;
> -
> - if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
> - && *strptr + strsize - str <= MB_LEN_MAX)
> - {
> - /* We have to enlarge the buffer if the `m' flag
> - was given. */
> - size_t strleng = str - *strptr;
> - char *newstr;
> -
> - newstr = (char *) realloc (*strptr, strsize * 2);
> - if (newstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch effort. */
> - newstr = (char *) realloc (*strptr,
> - strleng + MB_LEN_MAX);
> - if (newstr == NULL)
> - {
> - /* c can't have `a' flag, only `m'. */
> - done = EOF;
> - goto errout;
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize = strleng + MB_LEN_MAX;
> - }
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize *= 2;
> - }
> - }
> -
> - n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
> - if (__glibc_unlikely (n == (size_t) -1))
> - /* No valid wide character. */
> - input_error ();
> -
> - /* Increment the output pointer. Even if we don't
> - write anything. */
> - str += n;
> - }
> - while (--width > 0 && inchar () != EOF);
> -#else
> - if (!(flags & SUPPRESS))
> - {
> - do
> - {
> - if ((flags & MALLOC)
> - && (char *) str == *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - size_t newsize
> - = strsize
> - + (strsize >= width ? width - 1 : strsize);
> -
> - str = (char *) realloc (*strptr, newsize);
> - if (str == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - str = (char *) realloc (*strptr, strsize + 1);
> - if (str == NULL)
> - {
> - /* c can't have `a' flag, only `m'. */
> - done = EOF;
> - goto errout;
> - }
> - else
> - {
> - *strptr = (char *) str;
> - str += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) str;
> - str += strsize;
> - strsize = newsize;
> - }
> - }
> - *str++ = c;
> - }
> - while (--width > 0 && inchar () != EOF);
> - }
> - else
> - while (--width > 0 && inchar () != EOF);
> -#endif
> -
> - if (!(flags & SUPPRESS))
> - {
> - if ((flags & MALLOC) && str - *strptr != strsize)
> - {
> - char *cp = (char *) realloc (*strptr, str - *strptr);
> - if (cp != NULL)
> - *strptr = cp;
> - }
> - strptr = NULL;
> - ++done;
> - }
> -
> - break;
> - }
> - /* FALLTHROUGH */
> - case L_('C'):
> - if (width == -1)
> - width = 1;
> -
> - STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
> -
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> -#ifdef COMPILE_WSCANF
> - /* Just store the incoming wide characters. */
> - if (!(flags & SUPPRESS))
> - {
> - do
> - {
> - if ((flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - size_t newsize
> - = strsize + (strsize > width ? width - 1 : strsize);
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - newsize * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch effort. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (strsize + 1)
> - * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - /* C or lc can't have `a' flag, only `m'
> - flag. */
> - done = EOF;
> - goto errout;
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize = newsize;
> - }
> - }
> - *wstr++ = c;
> - }
> - while (--width > 0 && inchar () != EOF);
> - }
> - else
> - while (--width > 0 && inchar () != EOF);
> -#else
> - {
> - /* We have to convert the multibyte input sequence to wide
> - characters. */
> - char buf[1];
> - mbstate_t cstate;
> -
> - memset (&cstate, '\0', sizeof (cstate));
> -
> - do
> - {
> - /* This is what we present the mbrtowc function first. */
> - buf[0] = c;
> -
> - if (!(flags & SUPPRESS) && (flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - size_t newsize
> - = strsize + (strsize > width ? width - 1 : strsize);
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - newsize * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch effort. */
> - wstr = (wchar_t *) realloc (*strptr,
> - ((strsize + 1)
> - * sizeof (wchar_t)));
> - if (wstr == NULL)
> - {
> - /* C or lc can't have `a' flag, only `m' flag. */
> - done = EOF;
> - goto errout;
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize = newsize;
> - }
> - }
> -
> - while (1)
> - {
> - size_t n;
> -
> - n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
> - buf, 1, &cstate);
> -
> - if (n == (size_t) -2)
> - {
> - /* Possibly correct character, just not enough
> - input. */
> - if (__glibc_unlikely (inchar () == EOF))
> - encode_error ();
> -
> - buf[0] = c;
> - continue;
> - }
> -
> - if (__glibc_unlikely (n != 1))
> - encode_error ();
> -
> - /* We have a match. */
> - break;
> - }
> -
> - /* Advance the result pointer. */
> - ++wstr;
> - }
> - while (--width > 0 && inchar () != EOF);
> - }
> -#endif
> -
> - if (!(flags & SUPPRESS))
> - {
> - if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
> - {
> - wchar_t *cp = (wchar_t *) realloc (*strptr,
> - ((wstr
> - - (wchar_t *) *strptr)
> - * sizeof (wchar_t)));
> - if (cp != NULL)
> - *strptr = (char *) cp;
> - }
> - strptr = NULL;
> -
> - ++done;
> - }
> -
> - break;
> -
> - case L_('s'): /* Read a string. */
> - if (!(flags & LONG))
> - {
> - STRING_ARG (str, char, 100);
> -
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> -#ifdef COMPILE_WSCANF
> - memset (&state, '\0', sizeof (state));
> -#endif
> -
> - do
> - {
> - if (ISSPACE (c))
> - {
> - ungetc_not_eof (c, s);
> - break;
> - }
> -
> -#ifdef COMPILE_WSCANF
> - /* This is quite complicated. We have to convert the
> - wide characters into multibyte characters and then
> - store them. */
> - {
> - size_t n;
> -
> - if (!(flags & SUPPRESS) && (flags & MALLOC)
> - && *strptr + strsize - str <= MB_LEN_MAX)
> - {
> - /* We have to enlarge the buffer if the `a' or `m'
> - flag was given. */
> - size_t strleng = str - *strptr;
> - char *newstr;
> -
> - newstr = (char *) realloc (*strptr, strsize * 2);
> - if (newstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - newstr = (char *) realloc (*strptr,
> - strleng + MB_LEN_MAX);
> - if (newstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the
> - string and stop converting,
> - so at least we don't skip any input. */
> - ((char *) (*strptr))[strleng] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize = strleng + MB_LEN_MAX;
> - }
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize *= 2;
> - }
> - }
> -
> - n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c,
> - &state);
> - if (__glibc_unlikely (n == (size_t) -1))
> - encode_error ();
> -
> - assert (n <= MB_LEN_MAX);
> - str += n;
> - }
> -#else
> - /* This is easy. */
> - if (!(flags & SUPPRESS))
> - {
> - *str++ = c;
> - if ((flags & MALLOC)
> - && (char *) str == *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - str = (char *) realloc (*strptr, 2 * strsize);
> - if (str == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - str = (char *) realloc (*strptr, strsize + 1);
> - if (str == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the
> - string and stop converting,
> - so at least we don't skip any input. */
> - ((char *) (*strptr))[strsize - 1] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) str;
> - str += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) str;
> - str += strsize;
> - strsize *= 2;
> - }
> - }
> - }
> -#endif
> - }
> - while ((width <= 0 || --width > 0) && inchar () != EOF);
> -
> - if (!(flags & SUPPRESS))
> - {
> -#ifdef COMPILE_WSCANF
> - /* We have to emit the code to get into the initial
> - state. */
> - char buf[MB_LEN_MAX];
> - size_t n = __wcrtomb (buf, L'\0', &state);
> - if (n > 0 && (flags & MALLOC)
> - && str + n >= *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - size_t strleng = str - *strptr;
> - char *newstr;
> -
> - newstr = (char *) realloc (*strptr, strleng + n + 1);
> - if (newstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the string
> - and stop converting, so at least we don't
> - skip any input. */
> - ((char *) (*strptr))[strleng] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize = strleng + n + 1;
> - }
> - }
> -
> - str = __mempcpy (str, buf, n);
> -#endif
> - *str++ = '\0';
> -
> - if ((flags & MALLOC) && str - *strptr != strsize)
> - {
> - char *cp = (char *) realloc (*strptr, str - *strptr);
> - if (cp != NULL)
> - *strptr = cp;
> - }
> - strptr = NULL;
> -
> - ++done;
> - }
> - break;
> - }
> - /* FALLTHROUGH */
> -
> - case L_('S'):
> - {
> -#ifndef COMPILE_WSCANF
> - mbstate_t cstate;
> -#endif
> -
> - /* Wide character string. */
> - STRING_ARG (wstr, wchar_t, 100);
> -
> - c = inchar ();
> - if (__builtin_expect (c == EOF, 0))
> - input_error ();
> -
> -#ifndef COMPILE_WSCANF
> - memset (&cstate, '\0', sizeof (cstate));
> -#endif
> -
> - do
> - {
> - if (ISSPACE (c))
> - {
> - ungetc_not_eof (c, s);
> - break;
> - }
> -
> -#ifdef COMPILE_WSCANF
> - /* This is easy. */
> - if (!(flags & SUPPRESS))
> - {
> - *wstr++ = c;
> - if ((flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (2 * strsize)
> - * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (strsize + 1)
> - * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the string
> - and stop converting, so at least we don't
> - skip any input. */
> - ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize *= 2;
> - }
> - }
> - }
> -#else
> - {
> - char buf[1];
> -
> - buf[0] = c;
> -
> - while (1)
> - {
> - size_t n;
> -
> - n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
> - buf, 1, &cstate);
> -
> - if (n == (size_t) -2)
> - {
> - /* Possibly correct character, just not enough
> - input. */
> - if (__glibc_unlikely (inchar () == EOF))
> - encode_error ();
> -
> - buf[0] = c;
> - continue;
> - }
> -
> - if (__glibc_unlikely (n != 1))
> - encode_error ();
> -
> - /* We have a match. */
> - ++wstr;
> - break;
> - }
> -
> - if (!(flags & SUPPRESS) && (flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (2 * strsize
> - * sizeof (wchar_t)));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch effort. */
> - wstr = (wchar_t *) realloc (*strptr,
> - ((strsize + 1)
> - * sizeof (wchar_t)));
> - if (wstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the
> - string and stop converting, so at
> - least we don't skip any input. */
> - ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize *= 2;
> - }
> - }
> - }
> -#endif
> - }
> - while ((width <= 0 || --width > 0) && inchar () != EOF);
> -
> - if (!(flags & SUPPRESS))
> - {
> - *wstr++ = L'\0';
> -
> - if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
> - {
> - wchar_t *cp = (wchar_t *) realloc (*strptr,
> - ((wstr
> - - (wchar_t *) *strptr)
> - * sizeof(wchar_t)));
> - if (cp != NULL)
> - *strptr = (char *) cp;
> - }
> - strptr = NULL;
> -
> - ++done;
> - }
> - }
> - break;
> -
> - case L_('x'): /* Hexadecimal integer. */
> - case L_('X'): /* Ditto. */
> - base = 16;
> - goto number;
> -
> - case L_('o'): /* Octal integer. */
> - base = 8;
> - goto number;
> -
> - case L_('u'): /* Unsigned decimal integer. */
> - base = 10;
> - goto number;
> -
> - case L_('d'): /* Signed decimal integer. */
> - base = 10;
> - flags |= NUMBER_SIGNED;
> - goto number;
> -
> - case L_('i'): /* Generic number. */
> - base = 0;
> - flags |= NUMBER_SIGNED;
> -
> - number:
> - c = inchar ();
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> - /* Check for a sign. */
> - if (c == L_('-') || c == L_('+'))
> - {
> - char_buffer_add (&charbuf, c);
> - if (width > 0)
> - --width;
> - c = inchar ();
> - }
> -
> - /* Look for a leading indication of base. */
> - if (width != 0 && c == L_('0'))
> - {
> - if (width > 0)
> - --width;
> -
> - char_buffer_add (&charbuf, c);
> - c = inchar ();
> -
> - if (width != 0 && TOLOWER (c) == L_('x'))
> - {
> - if (base == 0)
> - base = 16;
> - if (base == 16)
> - {
> - if (width > 0)
> - --width;
> - c = inchar ();
> - }
> - }
> - else if (base == 0)
> - base = 8;
> - }
> -
> - if (base == 0)
> - base = 10;
> -
> - if (base == 10 && __builtin_expect ((flags & I18N) != 0, 0))
> - {
> - int from_level;
> - int to_level;
> - int level;
> -#ifdef COMPILE_WSCANF
> - const wchar_t *wcdigits[10];
> - const wchar_t *wcdigits_extended[10];
> -#else
> - const char *mbdigits[10];
> - const char *mbdigits_extended[10];
> -#endif
> - /* "to_inpunct" is a map from ASCII digits to their
> - equivalent in locale. This is defined for locales
> - which use an extra digits set. */
> - wctrans_t map = __wctrans ("to_inpunct");
> - int n;
> -
> - from_level = 0;
> -#ifdef COMPILE_WSCANF
> - to_level = _NL_CURRENT_WORD (LC_CTYPE,
> - _NL_CTYPE_INDIGITS_WC_LEN) - 1;
> -#else
> - to_level = (uint32_t) curctype->values[_NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_MB_LEN)].word - 1;
> -#endif
> -
> - /* Get the alternative digit forms if there are any. */
> - if (__glibc_unlikely (map != NULL))
> - {
> - /* Adding new level for extra digits set in locale file. */
> - ++to_level;
> -
> - for (n = 0; n < 10; ++n)
> - {
> -#ifdef COMPILE_WSCANF
> - wcdigits[n] = (const wchar_t *)
> - _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
> -
> - wchar_t *wc_extended = (wchar_t *)
> - alloca ((to_level + 2) * sizeof (wchar_t));
> - __wmemcpy (wc_extended, wcdigits[n], to_level);
> - wc_extended[to_level] = __towctrans (L'0' + n, map);
> - wc_extended[to_level + 1] = '\0';
> - wcdigits_extended[n] = wc_extended;
> -#else
> - mbdigits[n]
> - = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
> -
> - /* Get the equivalent wide char in map. */
> - wint_t extra_wcdigit = __towctrans (L'0' + n, map);
> -
> - /* Convert it to multibyte representation. */
> - mbstate_t state;
> - memset (&state, '\0', sizeof (state));
> -
> - char extra_mbdigit[MB_LEN_MAX];
> - size_t mblen
> - = __wcrtomb (extra_mbdigit, extra_wcdigit, &state);
> -
> - if (mblen == (size_t) -1)
> - {
> - /* Ignore this new level. */
> - map = NULL;
> - break;
> - }
> -
> - /* Calculate the length of mbdigits[n]. */
> - const char *last_char = mbdigits[n];
> - for (level = 0; level < to_level; ++level)
> - last_char = strchr (last_char, '\0') + 1;
> -
> - size_t mbdigits_len = last_char - mbdigits[n];
> -
> - /* Allocate memory for extended multibyte digit. */
> - char *mb_extended;
> - mb_extended = (char *) alloca (mbdigits_len + mblen + 1);
> -
> - /* And get the mbdigits + extra_digit string. */
> - *(char *) __mempcpy (__mempcpy (mb_extended, mbdigits[n],
> - mbdigits_len),
> - extra_mbdigit, mblen) = '\0';
> - mbdigits_extended[n] = mb_extended;
> -#endif
> - }
> - }
> -
> - /* Read the number into workspace. */
> - while (c != EOF && width != 0)
> - {
> - /* In this round we get the pointer to the digit strings
> - and also perform the first round of comparisons. */
> - for (n = 0; n < 10; ++n)
> - {
> - /* Get the string for the digits with value N. */
> -#ifdef COMPILE_WSCANF
> -
> - /* wcdigits_extended[] is fully set in the loop
> - above, but the test for "map != NULL" is done
> - inside the loop here and outside the loop there. */
> - DIAG_PUSH_NEEDS_COMMENT;
> - DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized");
> -
> - if (__glibc_unlikely (map != NULL))
> - wcdigits[n] = wcdigits_extended[n];
> - else
> - wcdigits[n] = (const wchar_t *)
> - _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
> - wcdigits[n] += from_level;
> -
> - DIAG_POP_NEEDS_COMMENT;
> -
> - if (c == (wint_t) *wcdigits[n])
> - {
> - to_level = from_level;
> - break;
> - }
> -
> - /* Advance the pointer to the next string. */
> - ++wcdigits[n];
> -#else
> - const char *cmpp;
> - int avail = width > 0 ? width : INT_MAX;
> -
> - if (__glibc_unlikely (map != NULL))
> - mbdigits[n] = mbdigits_extended[n];
> - else
> - mbdigits[n]
> - = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
> -
> - for (level = 0; level < from_level; level++)
> - mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -
> - cmpp = mbdigits[n];
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - {
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> -
> - if (*cmpp == '\0')
> - {
> - if (width > 0)
> - width = avail;
> - to_level = from_level;
> - break;
> - }
> -
> - /* We are pushing all read characters back. */
> - if (cmpp > mbdigits[n])
> - {
> - ungetc (c, s);
> - while (--cmpp > mbdigits[n])
> - ungetc_not_eof ((unsigned char) *cmpp, s);
> - c = (unsigned char) *cmpp;
> - }
> -
> - /* Advance the pointer to the next string. */
> - mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -#endif
> - }
> -
> - if (n == 10)
> - {
> - /* Have not yet found the digit. */
> - for (level = from_level + 1; level <= to_level; ++level)
> - {
> - /* Search all ten digits of this level. */
> - for (n = 0; n < 10; ++n)
> - {
> -#ifdef COMPILE_WSCANF
> - if (c == (wint_t) *wcdigits[n])
> - break;
> -
> - /* Advance the pointer to the next string. */
> - ++wcdigits[n];
> -#else
> - const char *cmpp;
> - int avail = width > 0 ? width : INT_MAX;
> -
> - cmpp = mbdigits[n];
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - {
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> -
> - if (*cmpp == '\0')
> - {
> - if (width > 0)
> - width = avail;
> - break;
> - }
> -
> - /* We are pushing all read characters back. */
> - if (cmpp > mbdigits[n])
> - {
> - ungetc (c, s);
> - while (--cmpp > mbdigits[n])
> - ungetc_not_eof ((unsigned char) *cmpp, s);
> - c = (unsigned char) *cmpp;
> - }
> -
> - /* Advance the pointer to the next string. */
> - mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
> -#endif
> - }
> -
> - if (n < 10)
> - {
> - /* Found it. */
> - from_level = level;
> - to_level = level;
> - break;
> - }
> - }
> - }
> -
> - if (n < 10)
> - c = L_('0') + n;
> - else if (flags & GROUP)
> - {
> - /* Try matching against the thousands separator. */
> -#ifdef COMPILE_WSCANF
> - if (c != thousands)
> - break;
> -#else
> - const char *cmpp = thousands;
> - int avail = width > 0 ? width : INT_MAX;
> -
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - {
> - char_buffer_add (&charbuf, c);
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> -
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> -
> - if (*cmpp != '\0')
> - {
> - /* We are pushing all read characters back. */
> - if (cmpp > thousands)
> - {
> - charbuf.current -= cmpp - thousands;
> - ungetc (c, s);
> - while (--cmpp > thousands)
> - ungetc_not_eof ((unsigned char) *cmpp, s);
> - c = (unsigned char) *cmpp;
> - }
> - break;
> - }
> -
> - if (width > 0)
> - width = avail;
> -
> - /* The last thousands character will be added back by
> - the char_buffer_add below. */
> - --charbuf.current;
> -#endif
> - }
> - else
> - break;
> -
> - char_buffer_add (&charbuf, c);
> - if (width > 0)
> - --width;
> -
> - c = inchar ();
> - }
> - }
> - else
> - /* Read the number into workspace. */
> - while (c != EOF && width != 0)
> - {
> - if (base == 16)
> - {
> - if (!ISXDIGIT (c))
> - break;
> - }
> - else if (!ISDIGIT (c) || (int) (c - L_('0')) >= base)
> - {
> - if (base == 10 && (flags & GROUP))
> - {
> - /* Try matching against the thousands separator. */
> -#ifdef COMPILE_WSCANF
> - if (c != thousands)
> - break;
> -#else
> - const char *cmpp = thousands;
> - int avail = width > 0 ? width : INT_MAX;
> -
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - {
> - char_buffer_add (&charbuf, c);
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> -
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> -
> - if (*cmpp != '\0')
> - {
> - /* We are pushing all read characters back. */
> - if (cmpp > thousands)
> - {
> - charbuf.current -= cmpp - thousands;
> - ungetc (c, s);
> - while (--cmpp > thousands)
> - ungetc_not_eof ((unsigned char) *cmpp, s);
> - c = (unsigned char) *cmpp;
> - }
> - break;
> - }
> -
> - if (width > 0)
> - width = avail;
> -
> - /* The last thousands character will be added back by
> - the char_buffer_add below. */
> - --charbuf.current;
> -#endif
> - }
> - else
> - break;
> - }
> - char_buffer_add (&charbuf, c);
> - if (width > 0)
> - --width;
> -
> - c = inchar ();
> - }
> -
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> -
> - if (char_buffer_size (&charbuf) == 0
> - || (char_buffer_size (&charbuf) == 1
> - && (char_buffer_start (&charbuf)[0] == L_('+')
> - || char_buffer_start (&charbuf)[0] == L_('-'))))
> - {
> - /* There was no number. If we are supposed to read a pointer
> - we must recognize "(nil)" as well. */
> - if (__builtin_expect (char_buffer_size (&charbuf) == 0
> - && (flags & READ_POINTER)
> - && (width < 0 || width >= 5)
> - && c == '('
> - && TOLOWER (inchar ()) == L_('n')
> - && TOLOWER (inchar ()) == L_('i')
> - && TOLOWER (inchar ()) == L_('l')
> - && inchar () == L_(')'), 1))
> - /* We must produce the value of a NULL pointer. A single
> - '0' digit is enough. */
> - char_buffer_add (&charbuf, L_('0'));
> - else
> - {
> - /* The last read character is not part of the number
> - anymore. */
> - ungetc (c, s);
> -
> - conv_error ();
> - }
> - }
> - else
> - /* The just read character is not part of the number anymore. */
> - ungetc (c, s);
> -
> - /* Convert the number. */
> - char_buffer_add (&charbuf, L_('\0'));
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> - if (need_longlong && (flags & LONGDBL))
> - {
> - if (flags & NUMBER_SIGNED)
> - num.q = __strtoll_internal
> - (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> - else
> - num.uq = __strtoull_internal
> - (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> - }
> - else
> - {
> - if (flags & NUMBER_SIGNED)
> - num.l = __strtol_internal
> - (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> - else
> - num.ul = __strtoul_internal
> - (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
> - }
> - if (__glibc_unlikely (char_buffer_start (&charbuf) == tw))
> - conv_error ();
> -
> - if (!(flags & SUPPRESS))
> - {
> - if (flags & NUMBER_SIGNED)
> - {
> - if (need_longlong && (flags & LONGDBL))
> - *ARG (LONGLONG int *) = num.q;
> - else if (need_long && (flags & LONG))
> - *ARG (long int *) = num.l;
> - else if (flags & SHORT)
> - *ARG (short int *) = (short int) num.l;
> - else if (!(flags & CHAR))
> - *ARG (int *) = (int) num.l;
> - else
> - *ARG (signed char *) = (signed char) num.ul;
> - }
> - else
> - {
> - if (need_longlong && (flags & LONGDBL))
> - *ARG (unsigned LONGLONG int *) = num.uq;
> - else if (need_long && (flags & LONG))
> - *ARG (unsigned long int *) = num.ul;
> - else if (flags & SHORT)
> - *ARG (unsigned short int *)
> - = (unsigned short int) num.ul;
> - else if (!(flags & CHAR))
> - *ARG (unsigned int *) = (unsigned int) num.ul;
> - else
> - *ARG (unsigned char *) = (unsigned char) num.ul;
> - }
> - ++done;
> - }
> - break;
> -
> - case L_('e'): /* Floating-point numbers. */
> - case L_('E'):
> - case L_('f'):
> - case L_('F'):
> - case L_('g'):
> - case L_('G'):
> - case L_('a'):
> - case L_('A'):
> - c = inchar ();
> - if (width > 0)
> - --width;
> - if (__glibc_unlikely (c == EOF))
> - input_error ();
> -
> - got_digit = got_dot = got_e = got_sign = 0;
> -
> - /* Check for a sign. */
> - if (c == L_('-') || c == L_('+'))
> - {
> - got_sign = 1;
> - char_buffer_add (&charbuf, c);
> - if (__glibc_unlikely (width == 0 || inchar () == EOF))
> - /* EOF is only an input error before we read any chars. */
> - conv_error ();
> - if (width > 0)
> - --width;
> - }
> -
> - /* Take care for the special arguments "nan" and "inf". */
> - if (TOLOWER (c) == L_('n'))
> - {
> - /* Maybe "nan". */
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('a'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('n'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - /* It is "nan". */
> - goto scan_float;
> - }
> - else if (TOLOWER (c) == L_('i'))
> - {
> - /* Maybe "inf" or "infinity". */
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('n'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('f'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - /* It is as least "inf". */
> - if (width != 0 && inchar () != EOF)
> - {
> - if (TOLOWER (c) == L_('i'))
> - {
> - if (width > 0)
> - --width;
> - /* Now we have to read the rest as well. */
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('n'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('i'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('t'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - if (__builtin_expect (width == 0
> - || inchar () == EOF
> - || TOLOWER (c) != L_('y'), 0))
> - conv_error ();
> - if (width > 0)
> - --width;
> - char_buffer_add (&charbuf, c);
> - }
> - else
> - /* Never mind. */
> - ungetc (c, s);
> - }
> - goto scan_float;
> - }
> -
> - exp_char = L_('e');
> - if (width != 0 && c == L_('0'))
> - {
> - char_buffer_add (&charbuf, c);
> - c = inchar ();
> - if (width > 0)
> - --width;
> - if (width != 0 && TOLOWER (c) == L_('x'))
> - {
> - /* It is a number in hexadecimal format. */
> - char_buffer_add (&charbuf, c);
> -
> - flags |= HEXA_FLOAT;
> - exp_char = L_('p');
> -
> - /* Grouping is not allowed. */
> - flags &= ~GROUP;
> - c = inchar ();
> - if (width > 0)
> - --width;
> - }
> - else
> - got_digit = 1;
> - }
> -
> - while (1)
> - {
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> - if (ISDIGIT (c))
> - {
> - char_buffer_add (&charbuf, c);
> - got_digit = 1;
> - }
> - else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c))
> - {
> - char_buffer_add (&charbuf, c);
> - got_digit = 1;
> - }
> - else if (got_e && charbuf.current[-1] == exp_char
> - && (c == L_('-') || c == L_('+')))
> - char_buffer_add (&charbuf, c);
> - else if (got_digit && !got_e
> - && (CHAR_T) TOLOWER (c) == exp_char)
> - {
> - char_buffer_add (&charbuf, exp_char);
> - got_e = got_dot = 1;
> - }
> - else
> - {
> -#ifdef COMPILE_WSCANF
> - if (! got_dot && c == decimal)
> - {
> - char_buffer_add (&charbuf, c);
> - got_dot = 1;
> - }
> - else if ((flags & GROUP) != 0 && ! got_dot && c == thousands)
> - char_buffer_add (&charbuf, c);
> - else
> - {
> - /* The last read character is not part of the number
> - anymore. */
> - ungetc (c, s);
> - break;
> - }
> -#else
> - const char *cmpp = decimal;
> - int avail = width > 0 ? width : INT_MAX;
> -
> - if (! got_dot)
> - {
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> -
> - if (*cmpp == '\0')
> - {
> - /* Add all the characters. */
> - for (cmpp = decimal; *cmpp != '\0'; ++cmpp)
> - char_buffer_add (&charbuf, (unsigned char) *cmpp);
> - if (width > 0)
> - width = avail;
> - got_dot = 1;
> - }
> - else
> - {
> - /* Figure out whether it is a thousands separator.
> - There is one problem: we possibly read more than
> - one character. We cannot push them back but since
> - we know that parts of the `decimal' string matched,
> - we can compare against it. */
> - const char *cmp2p = thousands;
> -
> - if ((flags & GROUP) != 0 && ! got_dot)
> - {
> - while (cmp2p - thousands < cmpp - decimal
> - && *cmp2p == decimal[cmp2p - thousands])
> - ++cmp2p;
> - if (cmp2p - thousands == cmpp - decimal)
> - {
> - while ((unsigned char) *cmp2p == c && avail >= 0)
> - if (*++cmp2p == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - }
> - }
> -
> - if (cmp2p != NULL && *cmp2p == '\0')
> - {
> - /* Add all the characters. */
> - for (cmpp = thousands; *cmpp != '\0'; ++cmpp)
> - char_buffer_add (&charbuf, (unsigned char) *cmpp);
> - if (width > 0)
> - width = avail;
> - }
> - else
> - {
> - /* The last read character is not part of the number
> - anymore. */
> - ungetc (c, s);
> - break;
> - }
> - }
> -#endif
> - }
> -
> - if (width == 0 || inchar () == EOF)
> - break;
> -
> - if (width > 0)
> - --width;
> - }
> -
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> -
> - wctrans_t map;
> - if (__builtin_expect ((flags & I18N) != 0, 0)
> - /* Hexadecimal floats make no sense, fixing localized
> - digits with ASCII letters. */
> - && !(flags & HEXA_FLOAT)
> - /* Minimum requirement. */
> - && (char_buffer_size (&charbuf) == got_sign || got_dot)
> - && (map = __wctrans ("to_inpunct")) != NULL)
> - {
> - /* Reget the first character. */
> - inchar ();
> -
> - /* Localized digits, decimal points, and thousands
> - separator. */
> - wint_t wcdigits[12];
> -
> - /* First get decimal equivalent to check if we read it
> - or not. */
> - wcdigits[11] = __towctrans (L'.', map);
> -
> - /* If we have not read any character or have just read
> - locale decimal point which matches the decimal point
> - for localized FP numbers, then we may have localized
> - digits. Note, we test GOT_DOT above. */
> -#ifdef COMPILE_WSCANF
> - if (char_buffer_size (&charbuf) == got_sign
> - || (char_buffer_size (&charbuf) == got_sign + 1
> - && wcdigits[11] == decimal))
> -#else
> - char mbdigits[12][MB_LEN_MAX + 1];
> -
> - mbstate_t state;
> - memset (&state, '\0', sizeof (state));
> -
> - bool match_so_far = char_buffer_size (&charbuf) == got_sign;
> - size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
> - if (mblen != (size_t) -1)
> - {
> - mbdigits[11][mblen] = '\0';
> - match_so_far |=
> - (char_buffer_size (&charbuf) == strlen (decimal) + got_sign
> - && strcmp (decimal, mbdigits[11]) == 0);
> - }
> - else
> - {
> - size_t decimal_len = strlen (decimal);
> - /* This should always be the case but the data comes
> - from a file. */
> - if (decimal_len <= MB_LEN_MAX)
> - {
> - match_so_far |= (char_buffer_size (&charbuf)
> - == decimal_len + got_sign);
> - memcpy (mbdigits[11], decimal, decimal_len + 1);
> - }
> - else
> - match_so_far = false;
> - }
> -
> - if (match_so_far)
> -#endif
> - {
> - bool have_locthousands = (flags & GROUP) != 0;
> -
> - /* Now get the digits and the thousands-sep equivalents. */
> - for (int n = 0; n < 11; ++n)
> - {
> - if (n < 10)
> - wcdigits[n] = __towctrans (L'0' + n, map);
> - else if (n == 10)
> - {
> - wcdigits[10] = __towctrans (L',', map);
> - have_locthousands &= wcdigits[10] != L'\0';
> - }
> -
> -#ifndef COMPILE_WSCANF
> - memset (&state, '\0', sizeof (state));
> -
> - size_t mblen = __wcrtomb (mbdigits[n], wcdigits[n],
> - &state);
> - if (mblen == (size_t) -1)
> - {
> - if (n == 10)
> - {
> - if (have_locthousands)
> - {
> - size_t thousands_len = strlen (thousands);
> - if (thousands_len <= MB_LEN_MAX)
> - memcpy (mbdigits[10], thousands,
> - thousands_len + 1);
> - else
> - have_locthousands = false;
> - }
> - }
> - else
> - /* Ignore checking against localized digits. */
> - goto no_i18nflt;
> - }
> - else
> - mbdigits[n][mblen] = '\0';
> -#endif
> - }
> -
> - /* Start checking against localized digits, if
> - conversion is done correctly. */
> - while (1)
> - {
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> - if (got_e && charbuf.current[-1] == exp_char
> - && (c == L_('-') || c == L_('+')))
> - char_buffer_add (&charbuf, c);
> - else if (char_buffer_size (&charbuf) > got_sign && !got_e
> - && (CHAR_T) TOLOWER (c) == exp_char)
> - {
> - char_buffer_add (&charbuf, exp_char);
> - got_e = got_dot = 1;
> - }
> - else
> - {
> - /* Check against localized digits, decimal point,
> - and thousands separator. */
> - int n;
> - for (n = 0; n < 12; ++n)
> - {
> -#ifdef COMPILE_WSCANF
> - if (c == wcdigits[n])
> - {
> - if (n < 10)
> - char_buffer_add (&charbuf, L_('0') + n);
> - else if (n == 11 && !got_dot)
> - {
> - char_buffer_add (&charbuf, decimal);
> - got_dot = 1;
> - }
> - else if (n == 10 && have_locthousands
> - && ! got_dot)
> - char_buffer_add (&charbuf, thousands);
> - else
> - /* The last read character is not part
> - of the number anymore. */
> - n = 12;
> -
> - break;
> - }
> -#else
> - const char *cmpp = mbdigits[n];
> - int avail = width > 0 ? width : INT_MAX;
> -
> - while ((unsigned char) *cmpp == c && avail >= 0)
> - if (*++cmpp == '\0')
> - break;
> - else
> - {
> - if (avail == 0 || inchar () == EOF)
> - break;
> - --avail;
> - }
> - if (*cmpp == '\0')
> - {
> - if (width > 0)
> - width = avail;
> -
> - if (n < 10)
> - char_buffer_add (&charbuf, L_('0') + n);
> - else if (n == 11 && !got_dot)
> - {
> - /* Add all the characters. */
> - for (cmpp = decimal; *cmpp != '\0';
> - ++cmpp)
> - char_buffer_add (&charbuf,
> - (unsigned char) *cmpp);
> -
> - got_dot = 1;
> - }
> - else if (n == 10 && (flags & GROUP) != 0
> - && ! got_dot)
> - {
> - /* Add all the characters. */
> - for (cmpp = thousands; *cmpp != '\0';
> - ++cmpp)
> - char_buffer_add (&charbuf,
> - (unsigned char) *cmpp);
> - }
> - else
> - /* The last read character is not part
> - of the number anymore. */
> - n = 12;
> -
> - break;
> - }
> -
> - /* We are pushing all read characters back. */
> - if (cmpp > mbdigits[n])
> - {
> - ungetc (c, s);
> - while (--cmpp > mbdigits[n])
> - ungetc_not_eof ((unsigned char) *cmpp, s);
> - c = (unsigned char) *cmpp;
> - }
> -#endif
> - }
> -
> - if (n >= 12)
> - {
> - /* The last read character is not part
> - of the number anymore. */
> - ungetc (c, s);
> - break;
> - }
> - }
> -
> - if (width == 0 || inchar () == EOF)
> - break;
> -
> - if (width > 0)
> - --width;
> - }
> - }
> -
> -#ifndef COMPILE_WSCANF
> - no_i18nflt:
> - ;
> -#endif
> - }
> -
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> -
> - /* Have we read any character? If we try to read a number
> - in hexadecimal notation and we have read only the `0x'
> - prefix this is an error. */
> - if (__glibc_unlikely (char_buffer_size (&charbuf) == got_sign
> - || ((flags & HEXA_FLOAT)
> - && (char_buffer_size (&charbuf)
> - == 2 + got_sign))))
> - conv_error ();
> -
> - scan_float:
> - /* Convert the number. */
> - char_buffer_add (&charbuf, L_('\0'));
> - if (char_buffer_error (&charbuf))
> - {
> - __set_errno (ENOMEM);
> - done = EOF;
> - goto errout;
> - }
> - if ((flags & LONGDBL) && !__ldbl_is_dbl)
> - {
> - long double d = __strtold_internal
> - (char_buffer_start (&charbuf), &tw, flags & GROUP);
> - if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> - *ARG (long double *) = d;
> - }
> - else if (flags & (LONG | LONGDBL))
> - {
> - double d = __strtod_internal
> - (char_buffer_start (&charbuf), &tw, flags & GROUP);
> - if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> - *ARG (double *) = d;
> - }
> - else
> - {
> - float d = __strtof_internal
> - (char_buffer_start (&charbuf), &tw, flags & GROUP);
> - if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
> - *ARG (float *) = d;
> - }
> -
> - if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))
> - conv_error ();
> -
> - if (!(flags & SUPPRESS))
> - ++done;
> - break;
> -
> - case L_('['): /* Character class. */
> - if (flags & LONG)
> - STRING_ARG (wstr, wchar_t, 100);
> - else
> - STRING_ARG (str, char, 100);
> -
> - if (*f == L_('^'))
> - {
> - ++f;
> - not_in = 1;
> - }
> - else
> - not_in = 0;
> -
> - if (width < 0)
> - /* There is no width given so there is also no limit on the
> - number of characters we read. Therefore we set width to
> - a very high value to make the algorithm easier. */
> - width = INT_MAX;
> -
> -#ifdef COMPILE_WSCANF
> - /* Find the beginning and the end of the scanlist. We are not
> - creating a lookup table since it would have to be too large.
> - Instead we search each time through the string. This is not
> - a constant lookup time but who uses this feature deserves to
> - be punished. */
> - tw = (wchar_t *) f; /* Marks the beginning. */
> -
> - if (*f == L']')
> - ++f;
> -
> - while ((fc = *f++) != L'\0' && fc != L']');
> -
> - if (__glibc_unlikely (fc == L'\0'))
> - conv_error ();
> - wchar_t *twend = (wchar_t *) f - 1;
> -#else
> - /* Fill WP with byte flags indexed by character.
> - We will use this flag map for matching input characters. */
> - if (!scratch_buffer_set_array_size
> - (&charbuf.scratch, UCHAR_MAX + 1, 1))
> - {
> - done = EOF;
> - goto errout;
> - }
> - memset (charbuf.scratch.data, '\0', UCHAR_MAX + 1);
> -
> - fc = *f;
> - if (fc == ']' || fc == '-')
> - {
> - /* If ] or - appears before any char in the set, it is not
> - the terminator or separator, but the first char in the
> - set. */
> - ((char *)charbuf.scratch.data)[fc] = 1;
> - ++f;
> - }
> -
> - while ((fc = *f++) != '\0' && fc != ']')
> - if (fc == '-' && *f != '\0' && *f != ']'
> - && (unsigned char) f[-2] <= (unsigned char) *f)
> - {
> - /* Add all characters from the one before the '-'
> - up to (but not including) the next format char. */
> - for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
> - ((char *)charbuf.scratch.data)[fc] = 1;
> - }
> - else
> - /* Add the character to the flag map. */
> - ((char *)charbuf.scratch.data)[fc] = 1;
> -
> - if (__glibc_unlikely (fc == '\0'))
> - conv_error();
> -#endif
> -
> - if (flags & LONG)
> - {
> - size_t now = read_in;
> -#ifdef COMPILE_WSCANF
> - if (__glibc_unlikely (inchar () == WEOF))
> - input_error ();
> -
> - do
> - {
> - wchar_t *runp;
> -
> - /* Test whether it's in the scanlist. */
> - runp = tw;
> - while (runp < twend)
> - {
> - if (runp[0] == L'-' && runp[1] != '\0'
> - && runp + 1 != twend
> - && runp != tw
> - && (unsigned int) runp[-1] <= (unsigned int) runp[1])
> - {
> - /* Match against all characters in between the
> - first and last character of the sequence. */
> - wchar_t wc;
> -
> - for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
> - if ((wint_t) wc == c)
> - break;
> -
> - if (wc <= runp[1] && !not_in)
> - break;
> - if (wc <= runp[1] && not_in)
> - {
> - /* The current character is not in the
> - scanset. */
> - ungetc (c, s);
> - goto out;
> - }
> -
> - runp += 2;
> - }
> - else
> - {
> - if ((wint_t) *runp == c && !not_in)
> - break;
> - if ((wint_t) *runp == c && not_in)
> - {
> - ungetc (c, s);
> - goto out;
> - }
> -
> - ++runp;
> - }
> - }
> -
> - if (runp == twend && !not_in)
> - {
> - ungetc (c, s);
> - goto out;
> - }
> -
> - if (!(flags & SUPPRESS))
> - {
> - *wstr++ = c;
> -
> - if ((flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (2 * strsize)
> - * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - wstr = (wchar_t *)
> - realloc (*strptr, (strsize + 1)
> - * sizeof (wchar_t));
> - if (wstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the string
> - and stop converting, so at least we don't
> - skip any input. */
> - ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize *= 2;
> - }
> - }
> - }
> - }
> - while (--width > 0 && inchar () != WEOF);
> - out:
> -#else
> - char buf[MB_LEN_MAX];
> - size_t cnt = 0;
> - mbstate_t cstate;
> -
> - if (__glibc_unlikely (inchar () == EOF))
> - input_error ();
> -
> - memset (&cstate, '\0', sizeof (cstate));
> -
> - do
> - {
> - if (((char *) charbuf.scratch.data)[c] == not_in)
> - {
> - ungetc_not_eof (c, s);
> - break;
> - }
> -
> - /* This is easy. */
> - if (!(flags & SUPPRESS))
> - {
> - size_t n;
> -
> - /* Convert it into a wide character. */
> - buf[0] = c;
> - n = __mbrtowc (wstr, buf, 1, &cstate);
> -
> - if (n == (size_t) -2)
> - {
> - /* Possibly correct character, just not enough
> - input. */
> - ++cnt;
> - assert (cnt < MB_LEN_MAX);
> - continue;
> - }
> - cnt = 0;
> -
> - ++wstr;
> - if ((flags & MALLOC)
> - && wstr == (wchar_t *) *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - wstr = (wchar_t *) realloc (*strptr,
> - (2 * strsize
> - * sizeof (wchar_t)));
> - if (wstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - wstr = (wchar_t *)
> - realloc (*strptr, ((strsize + 1)
> - * sizeof (wchar_t)));
> - if (wstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the
> - string and stop converting,
> - so at least we don't skip any input. */
> - ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - ++strsize;
> - }
> - }
> - else
> - {
> - *strptr = (char *) wstr;
> - wstr += strsize;
> - strsize *= 2;
> - }
> - }
> - }
> -
> - if (--width <= 0)
> - break;
> - }
> - while (inchar () != EOF);
> -
> - if (__glibc_unlikely (cnt != 0))
> - /* We stopped in the middle of recognizing another
> - character. That's a problem. */
> - encode_error ();
> -#endif
> -
> - if (__glibc_unlikely (now == read_in))
> - /* We haven't succesfully read any character. */
> - conv_error ();
> -
> - if (!(flags & SUPPRESS))
> - {
> - *wstr++ = L'\0';
> -
> - if ((flags & MALLOC)
> - && wstr - (wchar_t *) *strptr != strsize)
> - {
> - wchar_t *cp = (wchar_t *)
> - realloc (*strptr, ((wstr - (wchar_t *) *strptr)
> - * sizeof(wchar_t)));
> - if (cp != NULL)
> - *strptr = (char *) cp;
> - }
> - strptr = NULL;
> -
> - ++done;
> - }
> - }
> - else
> - {
> - size_t now = read_in;
> -
> - if (__glibc_unlikely (inchar () == EOF))
> - input_error ();
> -
> -#ifdef COMPILE_WSCANF
> -
> - memset (&state, '\0', sizeof (state));
> -
> - do
> - {
> - wchar_t *runp;
> - size_t n;
> -
> - /* Test whether it's in the scanlist. */
> - runp = tw;
> - while (runp < twend)
> - {
> - if (runp[0] == L'-' && runp[1] != '\0'
> - && runp + 1 != twend
> - && runp != tw
> - && (unsigned int) runp[-1] <= (unsigned int) runp[1])
> - {
> - /* Match against all characters in between the
> - first and last character of the sequence. */
> - wchar_t wc;
> -
> - for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
> - if ((wint_t) wc == c)
> - break;
> -
> - if (wc <= runp[1] && !not_in)
> - break;
> - if (wc <= runp[1] && not_in)
> - {
> - /* The current character is not in the
> - scanset. */
> - ungetc (c, s);
> - goto out2;
> - }
> -
> - runp += 2;
> - }
> - else
> - {
> - if ((wint_t) *runp == c && !not_in)
> - break;
> - if ((wint_t) *runp == c && not_in)
> - {
> - ungetc (c, s);
> - goto out2;
> - }
> -
> - ++runp;
> - }
> - }
> -
> - if (runp == twend && !not_in)
> - {
> - ungetc (c, s);
> - goto out2;
> - }
> -
> - if (!(flags & SUPPRESS))
> - {
> - if ((flags & MALLOC)
> - && *strptr + strsize - str <= MB_LEN_MAX)
> - {
> - /* Enlarge the buffer. */
> - size_t strleng = str - *strptr;
> - char *newstr;
> -
> - newstr = (char *) realloc (*strptr, 2 * strsize);
> - if (newstr == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - newstr = (char *) realloc (*strptr,
> - strleng + MB_LEN_MAX);
> - if (newstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the string
> - and stop converting, so at least we don't
> - skip any input. */
> - ((char *) (*strptr))[strleng] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize = strleng + MB_LEN_MAX;
> - }
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize *= 2;
> - }
> - }
> - }
> -
> - n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
> - if (__glibc_unlikely (n == (size_t) -1))
> - encode_error ();
> -
> - assert (n <= MB_LEN_MAX);
> - str += n;
> - }
> - while (--width > 0 && inchar () != WEOF);
> - out2:
> -#else
> - do
> - {
> - if (((char *) charbuf.scratch.data)[c] == not_in)
> - {
> - ungetc_not_eof (c, s);
> - break;
> - }
> -
> - /* This is easy. */
> - if (!(flags & SUPPRESS))
> - {
> - *str++ = c;
> - if ((flags & MALLOC)
> - && (char *) str == *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - size_t newsize = 2 * strsize;
> -
> - allocagain:
> - str = (char *) realloc (*strptr, newsize);
> - if (str == NULL)
> - {
> - /* Can't allocate that much. Last-ditch
> - effort. */
> - if (newsize > strsize + 1)
> - {
> - newsize = strsize + 1;
> - goto allocagain;
> - }
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the
> - string and stop converting,
> - so at least we don't skip any input. */
> - ((char *) (*strptr))[strsize - 1] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = (char *) str;
> - str += strsize;
> - strsize = newsize;
> - }
> - }
> - }
> - }
> - while (--width > 0 && inchar () != EOF);
> -#endif
> -
> - if (__glibc_unlikely (now == read_in))
> - /* We haven't succesfully read any character. */
> - conv_error ();
> -
> - if (!(flags & SUPPRESS))
> - {
> -#ifdef COMPILE_WSCANF
> - /* We have to emit the code to get into the initial
> - state. */
> - char buf[MB_LEN_MAX];
> - size_t n = __wcrtomb (buf, L'\0', &state);
> - if (n > 0 && (flags & MALLOC)
> - && str + n >= *strptr + strsize)
> - {
> - /* Enlarge the buffer. */
> - size_t strleng = str - *strptr;
> - char *newstr;
> -
> - newstr = (char *) realloc (*strptr, strleng + n + 1);
> - if (newstr == NULL)
> - {
> - if (flags & POSIX_MALLOC)
> - {
> - done = EOF;
> - goto errout;
> - }
> - /* We lose. Oh well. Terminate the string
> - and stop converting, so at least we don't
> - skip any input. */
> - ((char *) (*strptr))[strleng] = '\0';
> - strptr = NULL;
> - ++done;
> - conv_error ();
> - }
> - else
> - {
> - *strptr = newstr;
> - str = newstr + strleng;
> - strsize = strleng + n + 1;
> - }
> - }
> -
> - str = __mempcpy (str, buf, n);
> -#endif
> - *str++ = '\0';
> -
> - if ((flags & MALLOC) && str - *strptr != strsize)
> - {
> - char *cp = (char *) realloc (*strptr, str - *strptr);
> - if (cp != NULL)
> - *strptr = cp;
> - }
> - strptr = NULL;
> -
> - ++done;
> - }
> - }
> - break;
> -
> - case L_('p'): /* Generic pointer. */
> - base = 16;
> - /* A PTR must be the same size as a `long int'. */
> - flags &= ~(SHORT|LONGDBL);
> - if (need_long)
> - flags |= LONG;
> - flags |= READ_POINTER;
> - goto number;
> -
> - default:
> - /* If this is an unknown format character punt. */
> - conv_error ();
> - }
> - }
> -
> - /* The last thing we saw int the format string was a white space.
> - Consume the last white spaces. */
> - if (skip_space)
> - {
> - do
> - c = inchar ();
> - while (ISSPACE (c));
> - ungetc (c, s);
> - }
> -
> - errout:
> - /* Unlock stream. */
> - UNLOCK_STREAM (s);
> -
> - scratch_buffer_free (&charbuf.scratch);
> - if (errp != NULL)
> - *errp |= errval;
> -
> - if (__glibc_unlikely (done == EOF))
> - {
> - if (__glibc_unlikely (ptrs_to_free != NULL))
> - {
> - struct ptrs_to_free *p = ptrs_to_free;
> - while (p != NULL)
> - {
> - for (size_t cnt = 0; cnt < p->count; ++cnt)
> - {
> - free (*p->ptrs[cnt]);
> - *p->ptrs[cnt] = NULL;
> - }
> - p = p->next;
> - ptrs_to_free = p;
> - }
> - }
> - }
> - else if (__glibc_unlikely (strptr != NULL))
> - {
> - free (*strptr);
> - *strptr = NULL;
> - }
> - return done;
> -}
> -
> -#ifdef COMPILE_WSCANF
> -int
> -__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> -{
> - return _IO_vfwscanf (s, format, argptr, NULL);
> -}
> -ldbl_weak_alias (__vfwscanf, vfwscanf)
> -#else
> int
> ___vfscanf (FILE *s, const char *format, va_list argptr)
> {
> - return _IO_vfscanf_internal (s, format, argptr, NULL);
> + return __vfscanf_internal (s, format, argptr, 0);
> }
> -ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
> -ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
> ldbl_strong_alias (___vfscanf, __vfscanf)
> ldbl_hidden_def (___vfscanf, __vfscanf)
> ldbl_weak_alias (___vfscanf, vfscanf)
> -#endif
Ok.
> diff --git a/stdio-common/vfwscanf-internal.c b/stdio-common/vfwscanf-internal.c
> new file mode 100644
> index 0000000000..26c89270b7
> --- /dev/null
> +++ b/stdio-common/vfwscanf-internal.c
> @@ -0,0 +1,2 @@
> +#define COMPILE_WSCANF 1
> +#include "vfscanf-internal.c"
> diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
> index 26b1a66608..86980464c2 100644
> --- a/stdio-common/vfwscanf.c
> +++ b/stdio-common/vfwscanf.c
> @@ -1,2 +1,26 @@
> -#define COMPILE_WSCANF 1
> -#include "vfscanf.c"
> +/* Implementation and symbols for vfwscanf.
> + Copyright (C) 2018 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <libioP.h>
> +
> +int
> +__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
> +{
> + return __vfwscanf_internal (s, format, argptr, 0);
> +}
> +ldbl_weak_alias (__vfwscanf, vfwscanf)
Ok.
> diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
> index 8a5d8ba107..92f670dff7 100644
> --- a/sysdeps/generic/math_ldbl_opt.h
> +++ b/sysdeps/generic/math_ldbl_opt.h
> @@ -6,9 +6,13 @@
> for platforms where compatibility symbols are required for a previous
> ABI that defined long double functions as aliases for the double code. */
>
> +#include <shlib-compat.h>
> +
> #define LONG_DOUBLE_COMPAT(lib, introduced) 0
> #define long_double_symbol(lib, local, symbol)
> #define ldbl_hidden_def(local, name) libc_hidden_def (name)
> #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
> #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +#define ldbl_compat_symbol(lib, local, symbol, version) \
> + compat_symbol (lib, local, symbol, version)
> #define __ldbl_is_dbl 0
Ok.
> diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> index 61ba784f86..1c49036f7b 100644
> --- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> +++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
> @@ -20,10 +20,16 @@
> long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
> # define long_double_symbol_1(lib, local, symbol, version) \
> versioned_symbol (lib, local, symbol, version)
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> + compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
> #else
> # define ldbl_hidden_def(local, name) libc_hidden_def (name)
> # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
> # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
> +/* Same as compat_symbol, ldbl_compat_symbol is not to be used outside
> + '#if SHLIB_COMPAT' statement and should fail if it is. */
> +# define ldbl_compat_symbol(lib, local, symbol, version) \
> + _Static_assert (0, "ldbl_compat_symbol should be used inside SHLIB_COMPAT");
> # ifndef __ASSEMBLER__
> /* Note that weak_alias cannot be used - it is defined to nothing
> in most of the C files. */
Ok.
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index 7a1e89c1a3..91ea27a423 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -330,16 +330,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
> return done;
> }
>
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> int
> attribute_compat_text_section
> __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
> {
> int res;
> set_no_long_double ();
> - res = _IO_vfscanf (s, fmt, ap, errp);
> + res = __vfscanf_internal (s, fmt, ap, 0);
> clear_no_long_double ();
> + if (__glibc_unlikely (errp != 0))
> + *errp = (res == -1);
> return res;
> }
> +#endif
>
> int
> attribute_compat_text_section
> @@ -347,7 +351,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
> {
> int res;
> set_no_long_double ();
> - res = _IO_vfscanf (s, fmt, ap, NULL);
> + res = __vfscanf_internal (s, fmt, ap, 0);
> clear_no_long_double ();
> return res;
> }
> @@ -423,7 +427,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
> {
> int res;
> set_no_long_double ();
> - res = _IO_vfwscanf (s, fmt, ap, NULL);
> + res = __vfwscanf_internal (s, fmt, ap, 0);
> clear_no_long_double ();
> return res;
> }
> @@ -1027,7 +1031,6 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
> compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
> compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
> compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
> -compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
> compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
> compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
> @@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
> compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
> compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
> compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
> +/* This function is not in public headers, but was exported until
> + version 2.29. For platforms that are newer than that, there's no
> + need to expose the symbol. */
> +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
> +compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
> +# endif
> #endif
> #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
> compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);
Ok.
> diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
> index 0c6a2c47ac..00b07dd48e 100644
> --- a/wcsmbs/isoc99_fwscanf.c
> +++ b/wcsmbs/isoc99_fwscanf.c
> @@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
> stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = _IO_vfwscanf (stream, format, arg, NULL);
> + done = __vfwscanf_internal (stream, format, arg, 0);
> va_end (arg);
>
> _IO_release_lock (stream);
Ok.
> diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
> index ff523db706..40401d0aa1 100644
> --- a/wcsmbs/isoc99_swscanf.c
> +++ b/wcsmbs/isoc99_swscanf.c
> @@ -16,20 +16,22 @@
> <http://www.gnu.org/licenses/>. */
>
> #include <stdarg.h>
> -#include <stdio.h>
> -#include <libioP.h>
> -#include <wchar.h>
> +#include <libio/strfile.h>
>
> /* Read formatted input from S, according to the format string FORMAT. */
> -/* VARARGS2 */
> +
> int
> __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
> {
> va_list arg;
> int done;
> + _IO_strfile sf;
> + struct _IO_wide_data wd;
> + FILE *f = _IO_strfile_readw (&sf, &wd, s);
> + f->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = __isoc99_vswscanf (s, format, arg);
> + done = __vfwscanf_internal (f, format, arg, 0);
> va_end (arg);
>
> return done;
As before I think it requires to acquire the file lock before setting
_flags2.
> diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
> index 7beb45b4d3..f70c6b596d 100644
> --- a/wcsmbs/isoc99_vfwscanf.c
> +++ b/wcsmbs/isoc99_vfwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
>
> _IO_acquire_lock_clear_flags2 (stream);
> stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
> - done = _IO_vfwscanf (stream, format, args, NULL);
> + done = __vfwscanf_internal (stream, format, args, 0);
> _IO_release_lock (stream);
> return done;
> }
Ok.
> diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
> index 130769154d..b91eb651a3 100644
> --- a/wcsmbs/isoc99_vswscanf.c
> +++ b/wcsmbs/isoc99_vswscanf.c
> @@ -24,24 +24,16 @@
> This exception applies to code released by its copyright holders
> in files containing the exception. */
>
> -#include <libioP.h>
> #include <wchar.h>
> -#include "../libio/strfile.h"
> +#include <libio/strfile.h>
>
> int
> __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
> {
> - int ret;
> _IO_strfile sf;
> struct _IO_wide_data wd;
> -#ifdef _IO_MTSAFE_IO
> - sf._sbf._f._lock = NULL;
> -#endif
> - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
> - _IO_fwide (&sf._sbf._f, 1);
> - _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
> - sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
> - ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
> - return ret;
> + FILE *f = _IO_strfile_readw (&sf, &wd, string);
> + f->_flags2 |= _IO_FLAGS2_SCANF_STD;
> + return __vfwscanf_internal (f, format, args, 0);
> }
> libc_hidden_def (__isoc99_vswscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
> diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
> index 049521b964..eb22c8acae 100644
> --- a/wcsmbs/isoc99_vwscanf.c
> +++ b/wcsmbs/isoc99_vwscanf.c
> @@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
>
> _IO_acquire_lock_clear_flags2 (stdin);
> stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
> - done = _IO_vfwscanf (stdin, format, args, NULL);
> + done = __vfwscanf_internal (stdin, format, args, 0);
> _IO_release_lock (stdin);
> return done;
> }
Ok.
> diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
> index abfbd50c11..59f80d78fb 100644
> --- a/wcsmbs/isoc99_wscanf.c
> +++ b/wcsmbs/isoc99_wscanf.c
> @@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
> stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
>
> va_start (arg, format);
> - done = _IO_vfwscanf (stdin, format, arg, NULL);
> + done = __vfwscanf_internal (stdin, format, arg, 0);
> va_end (arg);
>
> _IO_release_lock (stdin);
>
Ok.