Discussion:
[PATCH v3 0/7] Use more flags parameters instead of global bits in stdio
(too old to reply)
Gabriel F. T. Gomes
2018-11-15 21:44:42 UTC
Permalink
Patches 2, 3, and 5 did not change, but since they depend on previous
patches in this set, I'm sending them again for completeness.

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

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

Thank you.

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

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

Changed since v2:

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

Changed since v1:

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

Not changed since v1:

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

Additional note for review:

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

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

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

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

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

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

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

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

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

Tested for powerpc and powerpc64le.

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

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

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

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

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

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

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

diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index e56ab8bd7d..ee6a99ec6a 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -24,22 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include "libioP.h"
#include "strfile.h"

int
_IO_vsscanf (const char *string, const char *format, va_list args)
{
- int ret;
_IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
- ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_read (&sf, string);
+ return __vfscanf_internal (f, format, args, 0);
}
ldbl_weak_alias (_IO_vsscanf, __vsscanf)
ldbl_weak_alias (_IO_vsscanf, vsscanf)
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
index 5bd1c88412..cb9cbe15cc 100644
--- a/libio/iovswscanf.c
+++ b/libio/iovswscanf.c
@@ -24,24 +24,16 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include "libioP.h"
-#include "strfile.h"
#include <wchar.h>
+#include "strfile.h"

int
__vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
{
- int ret;
_IO_strfile sf;
struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
- _IO_fwide (&sf._sbf._f, 1);
- _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
- ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_readw (&sf, &wd, string);
+ return __vfwscanf_internal (f, format, args, 0);
}
libc_hidden_def (__vswscanf)
ldbl_hidden_def (__vswscanf, vswscanf)
diff --git a/libio/libio.h b/libio/libio.h
index 00f9169613..d4eba2df54 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
libc_hidden_proto (_IO_putc)
libc_hidden_proto (_IO_sgetn)
libc_hidden_proto (_IO_vfprintf)
-libc_hidden_proto (_IO_vfscanf)

#ifdef _IO_MTSAFE_IO
# undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index df2633d858..525dce19ee 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,28 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)

#endif /* _G_HAVE_MMAP */

+/* Flags for __vfscanf_internal and __vfwscanf_internal.
+
+ SCANF_LDBL_IS_DBL indicates whether long double values are to be
+ handled as having the same format as double, in which case the flag
+ should be set to one, or as another format, otherwise.
+
+ SCANF_ISOC99_A, when set to one, indicates that the ISO C99 or POSIX
+ behavior of the scanf functions is to be used, i.e. automatic
+ allocation for input strings with %as, %aS and %a[, a GNU extension,
+ is disabled. This is the behavior that the __isoc99_scanf family of
+ functions use. When the flag is set to zero, automatic allocation is
+ enabled. */
+#define SCANF_LDBL_IS_DBL 0x0001
+#define SCANF_ISOC99_A 0x0002
+
+extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
+ unsigned int flags)
+ attribute_hidden;
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+ unsigned int flags)
+ attribute_hidden;
+
extern int _IO_vscanf (const char *, va_list) __THROW;

#ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 75caac2af5..62900a7128 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -24,7 +24,9 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <stdio.h>
+#ifndef STRFILE_H_
+#define STRFILE_H_
+
#include "libioP.h"

typedef void *(*_IO_alloc_type) (size_t);
@@ -80,3 +82,32 @@ typedef struct
} _IO_wstrnfile;

extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
+
+/* Initialize an _IO_strfile SF to read from narrow string STRING, and
+ return the corresponding FILE object. It is not necessary to fclose
+ the FILE when it is no longer needed. */
+static inline FILE *
+_IO_strfile_read (_IO_strfile *sf, const char *string)
+{
+ sf->_sbf._f._lock = NULL;
+ _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+ _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
+ _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
+ return &sf->_sbf._f;
+}
+
+/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
+ string STRING, and return the corresponding FILE object. It is not
+ necessary to fclose the FILE when it is no longer needed. */
+static inline FILE *
+_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
+ const wchar_t *string)
+{
+ sf->_sbf._f._lock = NULL;
+ _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
+ _IO_fwide (&sf->_sbf._f, 1);
+ _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
+ return &sf->_sbf._f;
+}
+
+#endif /* strfile.h. */
diff --git a/libio/swscanf.c b/libio/swscanf.c
index c8686bcbaf..90f721cc51 100644
--- a/libio/swscanf.c
+++ b/libio/swscanf.c
@@ -15,20 +15,22 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
#include <stdarg.h>
-#include <wchar.h>
+#include "strfile.h"

/* Read formatted input from S, according to the format string FORMAT. */
-/* VARARGS2 */
+
int
__swscanf (const wchar_t *s, const wchar_t *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);

va_start (arg, format);
- done = __vswscanf (s, format, arg);
+ done = __vfwscanf_internal (f, format, arg, 0);
va_end (arg);

return done;
diff --git a/libio/vscanf.c b/libio/vscanf.c
index 9c27122c27..a3e2dd43f2 100644
--- a/libio/vscanf.c
+++ b/libio/vscanf.c
@@ -32,6 +32,6 @@
int
_IO_vscanf (const char *format, va_list args)
{
- return _IO_vfscanf (_IO_stdin, format, args, NULL);
+ return __vfscanf_internal (_IO_stdin, format, args, 0);
}
ldbl_weak_alias (_IO_vscanf, vscanf)
diff --git a/libio/vwscanf.c b/libio/vwscanf.c
index 0d5f558758..7af770c8c3 100644
--- a/libio/vwscanf.c
+++ b/libio/vwscanf.c
@@ -30,6 +30,6 @@
int
__vwscanf (const wchar_t *format, va_list args)
{
- return _IO_vfwscanf (_IO_stdin, format, args, NULL);
+ return __vfwscanf_internal (_IO_stdin, format, args, 0);
}
ldbl_strong_alias (__vwscanf, vwscanf)
diff --git a/libio/wscanf.c b/libio/wscanf.c
index c8cdad0acd..fe27ff6fa6 100644
--- a/libio/wscanf.c
+++ b/libio/wscanf.c
@@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
int done;

va_start (arg, format);
- done = _IO_vfwscanf (stdin, format, arg, NULL);
+ done = __vfwscanf_internal (stdin, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index a10f12ab3c..f3b3ceddbd 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -39,7 +39,8 @@ routines := \
flockfile ftrylockfile funlockfile \
isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
isoc99_vsscanf \
- psiginfo gentempfd
+ psiginfo gentempfd \
+ vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf

aux := errlist siglist printf-parsemb printf-parsewc fxprintf

diff --git a/stdio-common/Versions b/stdio-common/Versions
index b8217578c8..522f302198 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -60,6 +60,9 @@ libc {
GLIBC_2.28 {
renameat2;
}
+ GLIBC_2.29 {
+ # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_29) used in iovfscanf.c etc.
+ }
GLIBC_PRIVATE {
# global variables
_itoa_lower_digits;
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfscanf.c
similarity index 54%
copy from stdio-common/isoc99_scanf.c
copy to stdio-common/iovfscanf.c
index bf7dbe86bb..77e698f665 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/iovfscanf.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Implementation and symbols for _IO_vfscanf.
+ Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
@@ -15,30 +16,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
#include <libioP.h>
+#include <shlib-compat.h>

+/* This function is provided for ports older than GLIBC 2.29 because
+ external callers could theoretically exist. Newer ports do not need,
+ since it is not part of the API. */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)

-/* Read formatted input from stdin according to the format string FORMAT. */
-/* VARARGS1 */
int
-__isoc99_scanf (const char *format, ...)
+attribute_compat_text_section
+__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
{
- va_list arg;
- int done;
-
-#ifdef _IO_MTSAFE_IO
- _IO_acquire_lock_clear_flags2 (stdin);
-#endif
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
- va_start (arg, format);
- done = _IO_vfscanf (stdin, format, arg, NULL);
- va_end (arg);
+ int rv = __vfscanf_internal (fp, format, ap, 0);
+ if (__glibc_unlikely (errp != 0))
+ *errp = (rv == -1);
+ return rv;
+}
+ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);

-#ifdef _IO_MTSAFE_IO
- _IO_release_lock (stdin);
#endif
- return done;
-}
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/iovfwscanf.c
similarity index 54%
copy from stdio-common/isoc99_scanf.c
copy to stdio-common/iovfwscanf.c
index bf7dbe86bb..26a57788cb 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/iovfwscanf.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Implementation and symbols for _IO_vfwscanf.
+ Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
@@ -15,30 +16,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
#include <libioP.h>
+#include <shlib-compat.h>

+/* This function is provided for ports older than GLIBC 2.29 because
+ external callers could theoretically exist. Newer ports do not need,
+ since it is not part of the API. */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)

-/* Read formatted input from stdin according to the format string FORMAT. */
-/* VARARGS1 */
int
-__isoc99_scanf (const char *format, ...)
+attribute_compat_text_section
+__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
{
- va_list arg;
- int done;
-
-#ifdef _IO_MTSAFE_IO
- _IO_acquire_lock_clear_flags2 (stdin);
-#endif
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
- va_start (arg, format);
- done = _IO_vfscanf (stdin, format, arg, NULL);
- va_end (arg);
+ int rv = __vfwscanf_internal (fp, format, ap, 0);
+ if (__glibc_unlikely (errp != 0))
+ *errp = (rv == -1);
+ return rv;
+}
+compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);

-#ifdef _IO_MTSAFE_IO
- _IO_release_lock (stdin);
#endif
- return done;
-}
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 9cdf85e679..4210d11f2b 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
stream->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = _IO_vfscanf (stream, format, arg, NULL);
+ done = __vfscanf_internal (stream, format, arg, 0);
va_end (arg);

_IO_release_lock (stream);
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index bf7dbe86bb..64c873eed9 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = _IO_vfscanf (stdin, format, arg, NULL);
+ done = __vfscanf_internal (stdin, format, arg, 0);
va_end (arg);

#ifdef _IO_MTSAFE_IO
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 56a60a2c05..2c89a03fe9 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,19 +16,20 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>

/* Read formatted input from S, according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_sscanf (const char *s, const char *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = __isoc99_vsscanf (s, format, arg);
+ done = __vfscanf_internal (f, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)

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

_IO_acquire_lock_clear_flags2 (stdin);
stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = _IO_vfscanf (stdin, format, args, NULL);
+ done = __vfscanf_internal (stdin, format, args, 0);
_IO_release_lock (stdin);
return done;
}
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index ac85ef2d0d..02bc0f50e6 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -24,23 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <libioP.h>
-#include <stdio.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>

int
__isoc99_vsscanf (const char *string, const char *format, va_list args)
{
- int ret;
_IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_read (&sf, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
index e61b5f1ad3..de38d70353 100644
--- a/stdio-common/scanf.c
+++ b/stdio-common/scanf.c
@@ -30,7 +30,7 @@ __scanf (const char *format, ...)
int done;

va_start (arg, format);
- done = _IO_vfscanf (stdin, format, arg, NULL);
+ done = __vfscanf_internal (stdin, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
index 88cd641798..e25e9c27a5 100644
--- a/stdio-common/sscanf.c
+++ b/stdio-common/sscanf.c
@@ -16,26 +16,24 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
+#include <libio/strfile.h>

/* Read formatted input from S, according to the format string FORMAT. */
-/* VARARGS2 */
+
int
__sscanf (const char *s, const char *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);

va_start (arg, format);
- done = __vsscanf (s, format, arg);
+ done = __vfscanf_internal (f, format, arg, 0);
va_end (arg);

return done;
}
ldbl_hidden_def (__sscanf, sscanf)
ldbl_strong_alias (__sscanf, sscanf)
-#undef _IO_sscanf
-/* This is for libg++. */
ldbl_strong_alias (__sscanf, _IO_sscanf)
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
similarity index 98%
copy from stdio-common/vfscanf.c
copy to stdio-common/vfscanf-internal.c
index 1ce836a324..13a7a300b7 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Internal functions for the *scanf* implementation.
+ Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
@@ -132,16 +133,13 @@
#include "printf-parse.h" /* Use read_int. */

#define encode_error() do { \
- errval = 4; \
__set_errno (EILSEQ); \
goto errout; \
} while (0)
#define conv_error() do { \
- errval = 2; \
goto errout; \
} while (0)
#define input_error() do { \
- errval = 1; \
if (done == 0) done = EOF; \
goto errout; \
} while (0)
@@ -267,12 +265,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
Return the number of assignments made, or -1 for an input error. */
#ifdef COMPILE_WSCANF
int
-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
- int *errp)
+__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
+ unsigned int mode_flags)
#else
int
-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
- int *errp)
+__vfscanf_internal (FILE *s, const char *format, va_list argptr,
+ unsigned int mode_flags)
#endif
{
va_list arg;
@@ -283,7 +281,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
WINT_T c = 0; /* Last char read. */
int width; /* Maximum field width. */
int flags; /* Modifiers for current format element. */
- int errval = 0;
#ifndef COMPILE_WSCANF
locale_t loc = _NL_CURRENT_LOCALE;
struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
@@ -335,6 +332,12 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
struct char_buffer charbuf;
scratch_buffer_init (&charbuf.scratch);

+ /* Temporarily honor the environmental mode bits. */
+ if (__ldbl_is_dbl)
+ mode_flags |= SCANF_LDBL_IS_DBL;
+ if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+ mode_flags |= SCANF_ISOC99_A;
+
#ifdef __va_copy
__va_copy (arg, argptr);
#else
@@ -566,7 +569,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
}
/* In __isoc99_*scanf %as, %aS and %a[ extension is not
supported at all. */
- if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+ if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))
{
--f;
break;
@@ -2423,7 +2426,8 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
done = EOF;
goto errout;
}
- if ((flags & LONGDBL) && !__ldbl_is_dbl)
+ if ((flags & LONGDBL) \
+ && __glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
{
long double d = __strtold_internal
(char_buffer_start (&charbuf), &tw, flags & GROUP);
@@ -3018,8 +3022,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
UNLOCK_STREAM (s);

scratch_buffer_free (&charbuf.scratch);
- if (errp != NULL)
- *errp |= errval;

if (__glibc_unlikely (done == EOF))
{
@@ -3045,23 +3047,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
}
return done;
}
-
-#ifdef COMPILE_WSCANF
-int
-__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
-{
- return _IO_vfwscanf (s, format, argptr, NULL);
-}
-ldbl_weak_alias (__vfwscanf, vfwscanf)
-#else
-int
-___vfscanf (FILE *s, const char *format, va_list argptr)
-{
- return _IO_vfscanf_internal (s, format, argptr, NULL);
-}
-ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_strong_alias (___vfscanf, __vfscanf)
-ldbl_hidden_def (___vfscanf, __vfscanf)
-ldbl_weak_alias (___vfscanf, vfscanf)
-#endif
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 1ce836a324..5eedca8340 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -15,3053 +15,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-#include <libc-diag.h>
-#include <libc-lock.h>
-#include <locale/localeinfo.h>
-#include <scratch_buffer.h>
-
-#ifdef __GNUC__
-# define HAVE_LONGLONG
-# define LONGLONG long long
-#else
-# define LONGLONG long
-#endif
-
-/* Determine whether we have to handle `long long' at all. */
-#if LONG_MAX == LONG_LONG_MAX
-# define need_longlong 0
-#else
-# define need_longlong 1
-#endif
-
-/* Determine whether we have to handle `long'. */
-#if INT_MAX == LONG_MAX
-# define need_long 0
-#else
-# define need_long 1
-#endif
-
-/* Those are flags in the conversion format. */
-#define LONG 0x0001 /* l: long or double */
-#define LONGDBL 0x0002 /* L: long long or long double */
-#define SHORT 0x0004 /* h: short */
-#define SUPPRESS 0x0008 /* *: suppress assignment */
-#define POINTER 0x0010 /* weird %p pointer (`fake hex') */
-#define NOSKIP 0x0020 /* do not skip blanks */
-#define NUMBER_SIGNED 0x0040 /* signed integer */
-#define GROUP 0x0080 /* ': group numbers */
-#define GNU_MALLOC 0x0100 /* a: malloc strings */
-#define CHAR 0x0200 /* hh: char */
-#define I18N 0x0400 /* I: use locale's digits */
-#define HEXA_FLOAT 0x0800 /* hexadecimal float */
-#define READ_POINTER 0x1000 /* this is a pointer value */
-#define POSIX_MALLOC 0x2000 /* m: malloc strings */
-#define MALLOC (GNU_MALLOC | POSIX_MALLOC)
-
-#include <locale/localeinfo.h>
#include <libioP.h>

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

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

+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
int
attribute_compat_text_section
__nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
{
int res;
set_no_long_double ();
- res = _IO_vfscanf (s, fmt, ap, errp);
+ res = __vfscanf_internal (s, fmt, ap, 0);
clear_no_long_double ();
+ if (__glibc_unlikely (errp != 0))
+ *errp = (res == -1);
return res;
}
+#endif

int
attribute_compat_text_section
@@ -347,7 +351,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = _IO_vfscanf (s, fmt, ap, NULL);
+ res = __vfscanf_internal (s, fmt, ap, 0);
clear_no_long_double ();
return res;
}
@@ -423,7 +427,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = _IO_vfwscanf (s, fmt, ap, NULL);
+ res = __vfwscanf_internal (s, fmt, ap, 0);
clear_no_long_double ();
return res;
}
@@ -1027,7 +1031,6 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
-compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
@@ -1040,6 +1043,12 @@ compat_symbol (libc, __nldbl___printf_fp, __printf_fp, GLIBC_2_0);
compat_symbol (libc, __nldbl_strfmon, strfmon, GLIBC_2_0);
compat_symbol (libc, __nldbl_syslog, syslog, GLIBC_2_0);
compat_symbol (libc, __nldbl_vsyslog, vsyslog, GLIBC_2_0);
+/* This function is not in public headers, but was exported until
+ version 2.29. For platforms that are newer than that, there's no
+ need to expose the symbol. */
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_29)
+compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+# endif
#endif
#if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
compat_symbol (libc, __nldbl___asprintf, __asprintf, GLIBC_2_1);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 0c6a2c47ac..00b07dd48e 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
stream->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = _IO_vfwscanf (stream, format, arg, NULL);
+ done = __vfwscanf_internal (stream, format, arg, 0);
va_end (arg);

_IO_release_lock (stream);
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index ff523db706..40401d0aa1 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -16,20 +16,22 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#include <wchar.h>
+#include <libio/strfile.h>

/* Read formatted input from S, according to the format string FORMAT. */
-/* VARARGS2 */
+
int
__isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = __isoc99_vswscanf (s, format, arg);
+ done = __vfwscanf_internal (f, format, arg, 0);
va_end (arg);

return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index 7beb45b4d3..f70c6b596d 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)

_IO_acquire_lock_clear_flags2 (stream);
stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = _IO_vfwscanf (stream, format, args, NULL);
+ done = __vfwscanf_internal (stream, format, args, 0);
_IO_release_lock (stream);
return done;
}
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index 130769154d..b91eb651a3 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -24,24 +24,16 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <libioP.h>
#include <wchar.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>

int
__isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
{
- int ret;
_IO_strfile sf;
struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
- _IO_fwide (&sf._sbf._f, 1);
- _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_readw (&sf, &wd, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfwscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index 049521b964..eb22c8acae 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)

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

va_start (arg, format);
- done = _IO_vfwscanf (stdin, format, arg, NULL);
+ done = __vfwscanf_internal (stdin, format, arg, 0);
va_end (arg);

_IO_release_lock (stdin);
--
2.14.5
Gabriel F. T. Gomes
2018-11-16 18:34:35 UTC
Permalink
Post by Gabriel F. T. Gomes
- if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+ if (__glibc_likely ((mode_flags & SCANF_ISOC99_A) == 1))
This should have been:

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

Fixed locally. Sorry about that.
Adhemerval Zanella
2018-11-22 17:34:54 UTC
Permalink
Post by Gabriel F. T. Gomes
- 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.
Post by Gabriel F. T. Gomes
- 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.
- 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.
- 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
$ objdump -d --reloc VFSCANF-VISIBLE-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 17
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
$ objdump -d --reloc VFSCANF-HIDDEN-glibc/libc.so | grep "<__nldbl___vfscanf>" -A 5
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.
* 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.
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.
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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?
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
@@ -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++)
- {
- flags |= SUPPRESS;
- break;
-#ifdef COMPILE_WSCANF
- if (thousands != L'\0')
-#else
- if (thousands != NULL)
-#endif
- flags |= GROUP;
- break;
- flags |= I18N;
- break;
- }
-
- /* Find the maximum field width. */
- width = 0;
- if (ISDIGIT ((UCHAR_T) *f))
- width = read_int ((const UCHAR_T **) &f);
- if (width == 0)
- width = -1;
-
- /* Check for type modifiers. */
- switch (*f++)
- {
- /* ints are short ints or chars. */
- if (*f == L_('h'))
- {
- ++f;
- flags |= CHAR;
- }
- else
- flags |= SHORT;
- break;
- if (*f == L_('l'))
- {
- /* A double `l' is equivalent to an `L'. */
- ++f;
- flags |= LONGDBL | LONG;
- }
- else
- /* ints are long ints. */
- flags |= LONG;
- break;
- /* doubles are long doubles, and ints are long long ints. */
- flags |= LONGDBL | LONG;
- break;
- /* 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;
- flags |= POSIX_MALLOC;
- if (*f == L_('l'))
- {
- ++f;
- flags |= LONG;
- }
- break;
- if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
- flags |= LONGDBL;
- else if (sizeof (size_t) > sizeof (unsigned int))
- flags |= LONG;
- break;
- if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))
- flags |= LONGDBL;
- else if (sizeof (uintmax_t) > sizeof (unsigned int))
- flags |= LONG;
- break;
- if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))
- flags |= LONGDBL;
- else if (sizeof (ptrdiff_t) > sizeof (int))
- flags |= LONG;
- break;
- /* 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.
-
-
- Subclause 7.9.6.2
- #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 */
- 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 */
-
- {
-#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;
-
- 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. */
- 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
- ;
-#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 ();
-
- /* 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);
-#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);
-#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;
-
- 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;
-
- /* 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);
- }
-
- /* 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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Post by Gabriel F. T. Gomes
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.
Gabriel F. T. Gomes
2018-12-04 15:14:59 UTC
Permalink
Post by Adhemerval Zanella
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.
Post by Gabriel F. T. Gomes
[...]
int
__isoc99_sscanf (const char *s, const char *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
va_start (arg, format);
- done = __isoc99_vsscanf (s, format, arg);
+ done = __vfscanf_internal (f, format, arg, 0);
va_end (arg);
return done;
I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
Wouldn't be more consistent to fold the second patch in this set, which replace
_IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
removed in a subsequent patch?
I have no problems with folding the two patches, however I did not
understand why the lock needs to be acquired/released. In this function,
`sf' is a variable on the stack, so it cannot be accessed elsewhere by
another thread (compare that against the `stream' argument to
__isoc99_vfscanf, below, where I agree that the lock is needed).

Did I miss something?
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
diff --git a/stdio-common/isoc99_vfscanf.c
b/stdio-common/isoc99_vfscanf.c index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
_IO_acquire_lock_clear_flags2 (stream);
stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = _IO_vfscanf (stream, format, args, NULL);
+ done = __vfscanf_internal (stream, format, args, 0);
_IO_release_lock (stream);
return done;
}
For reference, __isoc99_vfscanf lock acquire/release.
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
__isoc99_vsscanf (const char *string, const char *format, va_list args)
{
- int ret;
_IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_read (&sf, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vsscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
Same as __isoc99_sscanf.
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
__isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
va_start (arg, format);
- done = __isoc99_vswscanf (s, format, arg);
+ done = __vfwscanf_internal (f, format, arg, 0);
va_end (arg);
return done;
As before I think it requires to acquire the file lock before setting
_flags2.
Likewise.
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
__isoc99_vswscanf (const wchar_t *string, const wchar_t *format,
va_list args) {
- int ret;
_IO_strfile sf;
struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
- _IO_fwide (&sf._sbf._f, 1);
- _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_readw (&sf, &wd, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfwscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vswscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
Likewise.


I'm willing to squash the first and second patches anyway... I just want
to make sure I understand your concern.
Adhemerval Zanella
2018-12-04 17:37:24 UTC
Permalink
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
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.
Post by Gabriel F. T. Gomes
[...]
int
__isoc99_sscanf (const char *s, const char *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
va_start (arg, format);
- done = __isoc99_vsscanf (s, format, arg);
+ done = __vfscanf_internal (f, format, arg, 0);
va_end (arg);
return done;
I think it requires acquire/release the 'f' lock before manipulating the its _flags2.
Wouldn't be more consistent to fold the second patch in this set, which replace
_IO_FLAGS2_SCANF_STD by SCANF_ISOC99_A, to avoid add the code which would be just
removed in a subsequent patch?
I have no problems with folding the two patches, however I did not
understand why the lock needs to be acquired/released. In this function,
`sf' is a variable on the stack, so it cannot be accessed elsewhere by
another thread (compare that against the `stream' argument to
__isoc99_vfscanf, below, where I agree that the lock is needed).
Did I miss something?
You are right, the change looks correct.
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
diff --git a/stdio-common/isoc99_vfscanf.c
b/stdio-common/isoc99_vfscanf.c index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
_IO_acquire_lock_clear_flags2 (stream);
stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = _IO_vfscanf (stream, format, args, NULL);
+ done = __vfscanf_internal (stream, format, args, 0);
_IO_release_lock (stream);
return done;
}
For reference, __isoc99_vfscanf lock acquire/release.
Ack as before.
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
__isoc99_vsscanf (const char *string, const char *format, va_list args)
{
- int ret;
_IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_read (&sf, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vsscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
Same as __isoc99_sscanf.
Ack as before.
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
__isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
{
va_list arg;
int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
va_start (arg, format);
- done = __isoc99_vswscanf (s, format, arg);
+ done = __vfwscanf_internal (f, format, arg, 0);
va_end (arg);
return done;
As before I think it requires to acquire the file lock before setting
_flags2.
Likewise.
Ack as before.
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
__isoc99_vswscanf (const wchar_t *string, const wchar_t *format,
va_list args) {
- int ret;
_IO_strfile sf;
struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
- _IO_fwide (&sf._sbf._f, 1);
- _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
- sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
- ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
- return ret;
+ FILE *f = _IO_strfile_readw (&sf, &wd, string);
+ f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+ return __vfwscanf_internal (f, format, args, 0);
}
libc_hidden_def (__isoc99_vswscanf)
As before I think it requires to acquire the file lock before setting
_flags2.
Likewise.
I'm willing to squash the first and second patches anyway... I just want
to make sure I understand your concern.
Current patch looks sorry, sorry for the noise.
Gabriel F. T. Gomes
2018-11-15 21:44:44 UTC
Permalink
From: Zack Weinberg <***@panix.com>

Changes since v2

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

Changes since v1:

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

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

Tested for powerpc and powerpc64le.

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

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

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

diff --git a/libio/libio.h b/libio/libio.h
index d4eba2df54..30cb7d784f 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -92,7 +92,6 @@ typedef union
#define _IO_FLAGS2_NOTCANCEL 2
#define _IO_FLAGS2_FORTIFY 4
#define _IO_FLAGS2_USER_WBUF 8
-#define _IO_FLAGS2_SCANF_STD 16
#define _IO_FLAGS2_NOCLOSE 32
#define _IO_FLAGS2_CLOEXEC 64
#define _IO_FLAGS2_NEED_LOCK 128
diff --git a/libio/libioP.h b/libio/libioP.h
index 525dce19ee..9e971cb96b 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -786,7 +786,7 @@ __attribute__ ((__always_inline__))
_IO_acquire_lock_clear_flags2_fct (FILE **p)
{
FILE *fp = *p;
- fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY | _IO_FLAGS2_SCANF_STD);
+ fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
if ((fp->_flags & _IO_USER_LOCK) == 0)
_IO_funlockfile (fp);
}
@@ -800,8 +800,7 @@ _IO_acquire_lock_clear_flags2_fct (FILE **p)
FILE *_IO_acquire_lock_file = (_fp)
# define _IO_release_lock(_fp) \
if (_IO_acquire_lock_file != NULL) \
- _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY \
- | _IO_FLAGS2_SCANF_STD); \
+ _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY); \
} while (0)
#endif

diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 4210d11f2b..d7b5993f3e 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -20,20 +20,15 @@
#include <stdio.h>

/* Read formatted input from STREAM according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_fscanf (FILE *stream, const char *format, ...)
{
va_list arg;
int done;

- _IO_acquire_lock_clear_flags2 (stream);
- stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
va_start (arg, format);
- done = __vfscanf_internal (stream, format, arg, 0);
+ done = __vfscanf_internal (stream, format, arg, SCANF_ISOC99_A);
va_end (arg);

- _IO_release_lock (stream);
return done;
}
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index 64c873eed9..3998322ea1 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -19,26 +19,16 @@
#include <stdio.h>
#include <libioP.h>

-
/* Read formatted input from stdin according to the format string FORMAT. */
-/* VARARGS1 */
int
__isoc99_scanf (const char *format, ...)
{
va_list arg;
int done;

-#ifdef _IO_MTSAFE_IO
- _IO_acquire_lock_clear_flags2 (stdin);
-#endif
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
va_start (arg, format);
- done = __vfscanf_internal (stdin, format, arg, 0);
+ done = __vfscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
va_end (arg);

-#ifdef _IO_MTSAFE_IO
- _IO_release_lock (stdin);
-#endif
return done;
}
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 2c89a03fe9..c9e5103b81 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -26,10 +26,9 @@ __isoc99_sscanf (const char *s, const char *format, ...)
int done;
_IO_strfile sf;
FILE *f = _IO_strfile_read (&sf, s);
- f->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = __vfscanf_internal (f, format, arg, 0);
+ done = __vfscanf_internal (f, format, arg, SCANF_ISOC99_A);
va_end (arg);

return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index c96ca831ae..3c59c60b3e 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -19,16 +19,9 @@
#include <stdio.h>

/* Read formatted input from STREAM according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_vfscanf (FILE *stream, const char *format, va_list args)
{
- int done;
-
- _IO_acquire_lock_clear_flags2 (stream);
- stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = __vfscanf_internal (stream, format, args, 0);
- _IO_release_lock (stream);
- return done;
+ return __vfscanf_internal (stream, format, args, SCANF_ISOC99_A);
}
libc_hidden_def (__isoc99_vfscanf)
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 72ae72ddee..fc5d609ae7 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -19,15 +19,8 @@
#include <stdio.h>

/* Read formatted input from STDIN according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_vscanf (const char *format, va_list args)
{
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdin);
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = __vfscanf_internal (stdin, format, args, 0);
- _IO_release_lock (stdin);
- return done;
+ return __vfscanf_internal (stdin, format, args, SCANF_ISOC99_A);
}
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index 02bc0f50e6..dfc394bb51 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -31,7 +31,6 @@ __isoc99_vsscanf (const char *string, const char *format, va_list args)
{
_IO_strfile sf;
FILE *f = _IO_strfile_read (&sf, string);
- f->_flags2 |= _IO_FLAGS2_SCANF_STD;
- return __vfscanf_internal (f, format, args, 0);
+ return __vfscanf_internal (f, format, args, SCANF_ISOC99_A);
}
libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 13a7a300b7..f0072d8682 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -335,8 +335,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
/* Temporarily honor the environmental mode bits. */
if (__ldbl_is_dbl)
mode_flags |= SCANF_LDBL_IS_DBL;
- if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
- mode_flags |= SCANF_ISOC99_A;

#ifdef __va_copy
__va_copy (arg, argptr);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 00b07dd48e..5829607916 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -21,20 +21,15 @@
#include <wchar.h>

/* Read formatted input from STREAM according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
{
va_list arg;
int done;

- _IO_acquire_lock_clear_flags2 (stream);
- stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
va_start (arg, format);
- done = __vfwscanf_internal (stream, format, arg, 0);
+ done = __vfwscanf_internal (stream, format, arg, SCANF_ISOC99_A);
va_end (arg);

- _IO_release_lock (stream);
return done;
}
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index 40401d0aa1..f90e56d97f 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -28,10 +28,9 @@ __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
_IO_strfile sf;
struct _IO_wide_data wd;
FILE *f = _IO_strfile_readw (&sf, &wd, s);
- f->_flags2 |= _IO_FLAGS2_SCANF_STD;

va_start (arg, format);
- done = __vfwscanf_internal (f, format, arg, 0);
+ done = __vfwscanf_internal (f, format, arg, SCANF_ISOC99_A);
va_end (arg);

return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index f70c6b596d..715d354b5a 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -20,16 +20,9 @@
#include <wchar.h>

/* Read formatted input from STREAM according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
{
- int done;
-
- _IO_acquire_lock_clear_flags2 (stream);
- stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = __vfwscanf_internal (stream, format, args, 0);
- _IO_release_lock (stream);
- return done;
+ return __vfwscanf_internal (stream, format, args, SCANF_ISOC99_A);
}
libc_hidden_def (__isoc99_vfwscanf)
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index b91eb651a3..0d8ef7611a 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -33,7 +33,6 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
_IO_strfile sf;
struct _IO_wide_data wd;
FILE *f = _IO_strfile_readw (&sf, &wd, string);
- f->_flags2 |= _IO_FLAGS2_SCANF_STD;
- return __vfwscanf_internal (f, format, args, 0);
+ return __vfwscanf_internal (f, format, args, SCANF_ISOC99_A);
}
libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index eb22c8acae..3ac3182608 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -20,15 +20,8 @@
#include <wchar.h>

/* Read formatted input from STDIN according to the format string FORMAT. */
-/* VARARGS2 */
int
__isoc99_vwscanf (const wchar_t *format, va_list args)
{
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdin);
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
- done = __vfwscanf_internal (stdin, format, args, 0);
- _IO_release_lock (stdin);
- return done;
+ return __vfwscanf_internal (stdin, format, args, SCANF_ISOC99_A);
}
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index 59f80d78fb..b9418f7912 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -22,20 +22,15 @@


/* Read formatted input from stdin according to the format string FORMAT. */
-/* VARARGS1 */
int
__isoc99_wscanf (const wchar_t *format, ...)
{
va_list arg;
int done;

- _IO_acquire_lock_clear_flags2 (stdin);
- stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-
va_start (arg, format);
- done = __vfwscanf_internal (stdin, format, arg, 0);
+ done = __vfwscanf_internal (stdin, format, arg, SCANF_ISOC99_A);
va_end (arg);

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

Changes since v2:

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

Changes since v1:

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

Additional note for review:

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

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

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

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

Summary for the changes to each of the affected symbols:

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

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

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

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

__vswprintf:
Similarly, but no external symbol.

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

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

Tested for powerpc and powerpc64le.

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

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

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

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

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

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

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

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

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

diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
index e43a0c7cf1..b9dcb2c9c7 100644
--- a/argp/argp-fmtstream.c
+++ b/argp/argp-fmtstream.c
@@ -42,7 +42,6 @@
#ifdef _LIBC
# include <wchar.h>
# include <libio/libioP.h>
-# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
#endif

#define INIT_BUF_SIZE 200
@@ -409,7 +408,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)

va_start (args, fmt);
avail = fs->end - fs->p;
- out = __vsnprintf (fs->p, avail, fmt, args);
+ out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
va_end (args);
if ((size_t) out >= avail)
size_guess = out + 1;
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 2b6b0775d6..6857391ce2 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
#ifdef _LIBC
char *buf;

- if (_IO_vasprintf (&buf, fmt, ap) < 0)
+ if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
buf = NULL;

__fxprintf (stream, "%s: %s\n",
@@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
#ifdef _LIBC
char *buf;

- if (_IO_vasprintf (&buf, fmt, ap) < 0)
+ if (__vasprintf_internal (&buf, fmt, ap, 0) < 0)
buf = NULL;

__fxprintf (stream, ": %s", buf);
diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
index 5588fe172a..5e48b5940d 100644
--- a/argp/argp-namefrob.h
+++ b/argp/argp-namefrob.h
@@ -98,8 +98,6 @@
#define __strerror_r strerror_r
#undef __strndup
#define __strndup strndup
-#undef __vsnprintf
-#define __vsnprintf vsnprintf

#if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
# define clearerr_unlocked(x) clearerr (x)
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index aeb83077da..63167c1839 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
fp->_flags2 |= _IO_FLAGS2_FORTIFY;

va_start (ap, format);
- done = _IO_vfwprintf (fp, format, ap);
+ done = __vfwprintf_internal (fp, format, ap, 0);
va_end (ap);

if (flag > 0)
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 3ac5a3cd4f..41dd481c34 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
if (flags > 0)
new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;

- result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+ result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);

/* Shrink the buffer to the space we really currently need. */
obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index 48b4741651..dbfebff83f 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
if (flags > 0)
sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;

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

- done = _IO_vfprintf (&tmpfil.file, format, arg);
+ done = __vfprintf_internal (&tmpfil.file, format, arg, 0);

_IO_FINISH (&tmpfil.file);

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

- done = _IO_vfwprintf (fp, format, ap);
+ done = __vfwprintf_internal (fp, format, ap, 0);

if (flag > 0)
fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index d20d0fbd93..95d286f416 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;

_IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
- ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+ ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);

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

- ret = _IO_vfprintf (&f._sbf._f, format, args);
+ ret = __vfprintf_internal (&f._sbf._f, format, args, 0);

*f._sbf._f._IO_write_ptr = '\0';
return ret;
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index c6a7edcacd..4d616f8835 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;

_IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
- ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+ ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);

if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
/* ISO C99 requires swprintf/vswprintf to return an error if the
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index 51b67c159d..fedc7a46bf 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap)
if (flag > 0)
stdout->_flags2 |= _IO_FLAGS2_FORTIFY;

- done = _IO_vfwprintf (stdout, format, ap);
+ done = __vfwprintf_internal (stdout, format, ap, 0);

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

va_start (ap, format);
- done = _IO_vfwprintf (stdout, format, ap);
+ done = __vfwprintf_internal (stdout, format, ap, 0);
va_end (ap);

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

- done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
+ done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0);

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

va_start (arg, format);
- done = __vfwprintf (stream, format, arg);
+ done = __vfwprintf_internal (stream, format, arg, 0);
va_end (arg);

return done;
diff --git a/libio/iolibio.h b/libio/iolibio.h
index 6c94fe6d62..2642d71e4f 100644
--- a/libio/iolibio.h
+++ b/libio/iolibio.h
@@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW;
extern int _IO_sprintf (char *, const char*, ...) __THROW;
extern int _IO_ungetc (int, FILE*) __THROW;
extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW;
-extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW;
-libc_hidden_proto (_IO_vsprintf)
-extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list)
- __THROW;

-struct obstack;
-extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list)
- __THROW;
-extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW;
#define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN))
#define _IO_fseek(__fp, __offset, __whence) \
(_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \
diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
index 78a3a2bd15..1d2ed0f9e7 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -28,7 +28,8 @@
#include <stdio_ext.h>

int
-_IO_vdprintf (int d, const char *format, va_list arg)
+__vdprintf_internal (int d, const char *format, va_list arg,
+ unsigned int mode_flags)
{
struct _IO_FILE_plus tmpfil;
struct _IO_wide_data wd;
@@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg)
_IO_mask_flags (&tmpfil.file, _IO_NO_READS,
_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);

- done = _IO_vfprintf (&tmpfil.file, format, arg);
+ done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags);

if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
done = EOF;
@@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg)

return done;
}
-ldbl_weak_alias (_IO_vdprintf, vdprintf)
+
+int
+__vdprintf (int d, const char *format, va_list arg)
+{
+ return __vdprintf_internal (d, format, arg, 0);
+}
+ldbl_weak_alias (__vdprintf, vdprintf)
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 4def251701..3b1e8292b5 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -28,7 +28,8 @@
#include "strfile.h"

int
-__IO_vsprintf (char *string, const char *format, va_list args)
+__vsprintf_internal (char *string, const char *format, va_list args,
+ unsigned int mode_flags)
{
_IO_strfile sf;
int ret;
@@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args)
_IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
_IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
_IO_str_init_static_internal (&sf, string, -1, string);
- ret = _IO_vfprintf (&sf._sbf._f, format, args);
+ ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
_IO_putc_unlocked ('\0', &sf._sbf._f);
return ret;
}
-ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf)

-ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf)
-ldbl_weak_alias (__IO_vsprintf, vsprintf)
+int
+__vsprintf (char *string, const char *format, va_list args)
+{
+ return __vsprintf_internal (string, format, args, 0);
+}
+
+ldbl_strong_alias (__vsprintf, _IO_vsprintf)
+ldbl_weak_alias (__vsprintf, vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index 30cb7d784f..c188814ccc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW;

extern int _IO_vfscanf (FILE * __restrict, const char * __restrict,
__gnuc_va_list, int *__restrict);
-extern int _IO_vfprintf (FILE *__restrict, const char *__restrict,
- __gnuc_va_list);
extern __ssize_t _IO_padn (FILE *, int, __ssize_t);
extern size_t _IO_sgetn (FILE *, void *, size_t);

@@ -298,8 +296,6 @@ weak_extern (_IO_stdin_used);

extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict,
__gnuc_va_list, int *__restrict);
-extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict,
- __gnuc_va_list);
extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t);
extern void _IO_free_wbackup_area (FILE *) __THROW;

@@ -319,7 +315,6 @@ libc_hidden_proto (_IO_free_wbackup_area)
libc_hidden_proto (_IO_padn)
libc_hidden_proto (_IO_putc)
libc_hidden_proto (_IO_sgetn)
-libc_hidden_proto (_IO_vfprintf)

#ifdef _IO_MTSAFE_IO
# undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index 9e971cb96b..fe52ef1752 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,49 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
extern void _IO_wstr_finish (FILE *, int) __THROW;

-extern int _IO_vasprintf (char **result_ptr, const char *format,
- va_list args) __THROW;
-extern int _IO_vdprintf (int d, const char *format, va_list arg);
-extern int _IO_vsnprintf (char *string, size_t maxlen,
- const char *format, va_list args) __THROW;
+/* Internal versions of v*printf that take an additional flags
+ parameter. */
+extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+
+extern int __vasprintf_internal (char **result_ptr, const char *format,
+ va_list ap, unsigned int mode_flags)
+ attribute_hidden;
+extern int __vdprintf_internal (int d, const char *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
+ va_list ap, unsigned int mode_flags)
+ attribute_hidden;
+
+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+extern int __vsnprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
+ const wchar_t *format, va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden;
+
+/* Flags for __v*printf_internal.
+
+ PRINTF_LDBL_IS_DBL indicates whether long double values are to be
+ handled as having the same format as double, in which case the flag
+ should be set to one, or as another format, otherwise.

+ PRINTF_FORTIFY, when set to one, indicates that fortification checks
+ are to be performed in input parameters. This is used by the
+ __*printf_chk functions, which are used when _FORTIFY_SOURCE is
+ defined to 1 or 2. Otherwise, such checks are ignored. */
+#define PRINTF_LDBL_IS_DBL 0x0001
+#define PRINTF_FORTIFY 0x0002

extern size_t _IO_getline (FILE *,char *, size_t, int, int);
libc_hidden_proto (_IO_getline)
diff --git a/libio/obprintf.c b/libio/obprintf.c
index a74f9467a2..10a4b5c10c 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =


int
-_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
+__obstack_vprintf_internal (struct obstack *obstack, const char *format,
+ va_list args, unsigned int mode_flags)
{
struct obstack_FILE
{
@@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)

new_f.ofile.obstack = obstack;

- result = _IO_vfprintf (&new_f.ofile.file.file, format, args);
+ result = __vfprintf_internal (&new_f.ofile.file.file, format, args,
+ mode_flags);

/* Shrink the buffer to the space we really currently need. */
obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
@@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)

return result;
}
-ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf)

+int
+__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap)
+{
+ return __obstack_vprintf_internal (obstack, format, ap, 0);
+}
+ldbl_weak_alias (__obstack_vprintf, obstack_vprintf)

int
-_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
+__obstack_printf (struct obstack *obstack, const char *format, ...)
{
int result;
va_list ap;
va_start (ap, format);
- result = _IO_obstack_vprintf (obstack, format, ap);
+ result = __obstack_vprintf_internal (obstack, format, ap, 0);
va_end (ap);
return result;
}
-ldbl_weak_alias (_IO_obstack_printf, obstack_printf)
+ldbl_weak_alias (__obstack_printf, obstack_printf)
diff --git a/libio/swprintf.c b/libio/swprintf.c
index 10f722d035..19b3f33198 100644
--- a/libio/swprintf.c
+++ b/libio/swprintf.c
@@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...)
int done;

va_start (arg, format);
- done = __vswprintf (s, n, format, arg);
+ done = __vswprintf_internal (s, n, format, arg, 0);
va_end (arg);

return done;
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
index 6c35d2b108..fabd84f403 100644
--- a/libio/vasprintf.c
+++ b/libio/vasprintf.c
@@ -24,15 +24,13 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <malloc.h>
#include <string.h>
-#include "libioP.h"
-#include "stdio.h"
-#include <stdio_ext.h>
-#include "strfile.h"
+#include <stdlib.h>
+#include <strfile.h>

int
-_IO_vasprintf (char **result_ptr, const char *format, va_list args)
+__vasprintf_internal (char **result_ptr, const char *format, va_list args,
+ unsigned int mode_flags)
{
/* Initial size of the buffer to be used. Will be doubled each time an
overflow occurs. */
@@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
sf._sbf._f._flags &= ~_IO_USER_BUF;
sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
sf._s._free_buffer_unused = (_IO_free_type) free;
- ret = _IO_vfprintf (&sf._sbf._f, format, args);
+ ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
if (ret < 0)
{
free (sf._sbf._f._IO_buf_base);
@@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args)
(*result_ptr)[needed - 1] = '\0';
return ret;
}
-ldbl_weak_alias (_IO_vasprintf, vasprintf)
+
+int
+__vasprintf (char **result_ptr, const char *format, va_list args)
+{
+ return __vasprintf_internal (result_ptr, format, args, 0);
+}
+ldbl_weak_alias (__vasprintf, vasprintf)
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index 39b5500528..35b267abf8 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =


int
-_IO_vsnprintf (char *string, size_t maxlen, const char *format,
- va_list args)
+__vsnprintf_internal (char *string, size_t maxlen, const char *format,
+ va_list args, unsigned int mode_flags)
{
_IO_strnfile sf;
int ret;
@@ -111,11 +111,17 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format,
_IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
string[0] = '\0';
_IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
- ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
+ ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);

if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
*sf.f._sbf._f._IO_write_ptr = '\0';
return ret;
}
-ldbl_weak_alias (_IO_vsnprintf, __vsnprintf)
-ldbl_weak_alias (_IO_vsnprintf, vsnprintf)
+
+int
+___vsnprintf (char *string, size_t maxlen, const char *format, va_list args)
+{
+ return __vsnprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (___vsnprintf, __vsnprintf)
+ldbl_weak_alias (___vsnprintf, vsnprintf)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index bcc473d115..e415e39fc9 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =


int
-_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
- va_list args)
+__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
+ va_list args, unsigned int mode_flags)
{
_IO_wstrnfile sf;
int ret;
@@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
_IO_fwide (&sf.f._sbf._f, 1);
string[0] = L'\0';
_IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
- ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args);
+ ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags);

if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
/* ISO C99 requires swprintf/vswprintf to return an error if the
@@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,

return ret;
}
-weak_alias (_IO_vswprintf, __vswprintf)
-ldbl_weak_alias (_IO_vswprintf, vswprintf)
+
+int
+__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format,
+ va_list args)
+{
+ return __vswprintf_internal (string, maxlen, format, args, 0);
+}
+ldbl_weak_alias (__vswprintf, vswprintf)
diff --git a/libio/vwprintf.c b/libio/vwprintf.c
index 72ebfec92d..e8a529afff 100644
--- a/libio/vwprintf.c
+++ b/libio/vwprintf.c
@@ -25,6 +25,6 @@
int
__vwprintf (const wchar_t *format, __gnuc_va_list arg)
{
- return __vfwprintf (stdout, format, arg);
+ return __vfwprintf_internal (stdout, format, arg, 0);
}
ldbl_strong_alias (__vwprintf, vwprintf)
diff --git a/libio/wprintf.c b/libio/wprintf.c
index 5945f651fc..361cd40a1b 100644
--- a/libio/wprintf.c
+++ b/libio/wprintf.c
@@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...)
int done;

va_start (arg, format);
- done = __vfwprintf (stdout, format, arg);
+ done = __vfwprintf_internal (stdout, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index f3b3ceddbd..84bad1fafe 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -40,7 +40,8 @@ routines := \
isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
isoc99_vsscanf \
psiginfo gentempfd \
- vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
+ vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf \
+ vfprintf-internal vfwprintf-internal

aux := errlist siglist printf-parsemb printf-parsewc fxprintf

diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
index bff858e657..8943ffcae1 100644
--- a/stdio-common/asprintf.c
+++ b/stdio-common/asprintf.c
@@ -16,11 +16,7 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-
#include <libioP.h>
-#define vasprintf(s, f, a) _IO_vasprintf (s, f, a)
-#undef __asprintf

/* Write formatted output from FORMAT to a string which is
allocated with malloc and stored in *STRING_PTR. */
@@ -32,7 +28,7 @@ ___asprintf (char **string_ptr, const char *format, ...)
int done;

va_start (arg, format);
- done = vasprintf (string_ptr, format, arg);
+ done = __vasprintf_internal (string_ptr, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
index 11bd12b838..9adc8ae4c7 100644
--- a/stdio-common/dprintf.c
+++ b/stdio-common/dprintf.c
@@ -16,10 +16,7 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-
#include <libioP.h>
-#define vdprintf(d, f, a) _IO_vdprintf (d, f, a)

/* Write formatted output to D, according to the format string FORMAT. */
/* VARARGS2 */
@@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...)
int done;

va_start (arg, format);
- done = vdprintf (d, format, arg);
+ done = __vdprintf_internal (d, format, arg, 0);
va_end (arg);

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

va_start (arg, format);
- done = vfprintf (stream, format, arg);
+ done = __vfprintf_internal (stream, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
index 8d02b71f91..a028e8edd5 100644
--- a/stdio-common/fxprintf.c
+++ b/stdio-common/fxprintf.c
@@ -27,7 +27,7 @@ static int
locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
{
if (_IO_fwide (fp, 0) <= 0)
- return _IO_vfprintf (fp, fmt, ap);
+ return __vfprintf_internal (fp, fmt, ap, 0);

/* We must convert the narrow format string to a wide one.
Each byte can produce at most one wide character. */
@@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);

if (res != -1)
- res = _IO_vfwprintf (fp, wfmt, ap);
+ res = __vfwprintf_internal (fp, wfmt, ap, 0);

if (used_malloc)
free (wfmt);
diff --git a/stdio-common/printf.c b/stdio-common/printf.c
index 205b5e42df..ea41dd557c 100644
--- a/stdio-common/printf.c
+++ b/stdio-common/printf.c
@@ -30,7 +30,7 @@ __printf (const char *format, ...)
int done;

va_start (arg, format);
- done = vfprintf (stdout, format, arg);
+ done = __vfprintf_internal (stdout, format, arg, 0);
va_end (arg);

return done;
@@ -38,5 +38,4 @@ __printf (const char *format, ...)

#undef _IO_printf
ldbl_strong_alias (__printf, printf);
-/* This is for libg++. */
ldbl_strong_alias (__printf, _IO_printf);
diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
index 29a169b08b..b75e160ea3 100644
--- a/stdio-common/snprintf.c
+++ b/stdio-common/snprintf.c
@@ -16,9 +16,7 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
#include <libioP.h>
-#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)

/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
@@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...)
int done;

va_start (arg, format);
- done = __vsnprintf (s, maxlen, format, arg);
+ done = __vsnprintf_internal (s, maxlen, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index bf5671dde9..77423b292f 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -16,9 +16,7 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
#include <libioP.h>
-#define vsprintf(s, f, a) _IO_vsprintf (s, f, a)

/* Write formatted output into S, according to the format string FORMAT. */
/* VARARGS2 */
@@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
int done;

va_start (arg, format);
- done = vsprintf (s, format, arg);
+ done = __vsprintf_internal (s, format, arg, 0);
va_end (arg);

return done;
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf-internal.c
similarity index 98%
copy from stdio-common/vfprintf.c
copy to stdio-common/vfprintf-internal.c
index ae412e4b84..b0c86e99bd 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf-internal.c
@@ -41,6 +41,10 @@

#include <libioP.h>

+#ifdef COMPILE_WPRINTF
+#include <wctype.h>
+#endif
+
/* In some cases we need extra space for all the output which is not
counted in the width of the string. We assume 32 characters is
enough. */
@@ -78,7 +82,7 @@
} while (0)

#ifndef COMPILE_WPRINTF
-# define vfprintf _IO_vfprintf_internal
+# define vfprintf __vfprintf_internal
# define CHAR_T char
# define UCHAR_T unsigned char
# define INT_T int
@@ -105,7 +109,7 @@ typedef const char *THOUSANDS_SEP_T;
# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
return -1
#else
-# define vfprintf _IO_vfwprintf
+# define vfprintf __vfwprintf_internal
# define CHAR_T wchar_t
/* This is a hack!!! There should be a type uwchar_t. */
# define UCHAR_T unsigned int /* uwchar_t */
@@ -747,7 +751,7 @@ static const uint8_t jump_table[] =
\
if (fspec == NULL) \
{ \
- if (__ldbl_is_dbl) \
+ if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0)) \
is_long_double = 0; \
\
struct printf_info info = { .prec = prec, \
@@ -778,7 +782,7 @@ static const uint8_t jump_table[] =
else \
{ \
ptr = (const void *) &args_value[fspec->data_arg]; \
- if (__ldbl_is_dbl) \
+ if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0)) \
{ \
fspec->data_arg_type = PA_DOUBLE; \
fspec->info.is_long_double = 0; \
@@ -808,7 +812,7 @@ static const uint8_t jump_table[] =
\
if (fspec == NULL) \
{ \
- if (__ldbl_is_dbl) \
+ if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0)) \
is_long_double = 0; \
\
struct printf_info info = { .prec = prec, \
@@ -838,7 +842,7 @@ static const uint8_t jump_table[] =
else \
{ \
ptr = (const void *) &args_value[fspec->data_arg]; \
- if (__ldbl_is_dbl) \
+ if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0)) \
fspec->info.is_long_double = 0; \
/* Not supported by *printf functions. */ \
fspec->info.is_binary128 = 0; \
@@ -891,7 +895,7 @@ static const uint8_t jump_table[] =
/* NOTREACHED */ \
\
LABEL (form_number): \
- if (s->_flags2 & _IO_FLAGS2_FORTIFY) \
+ if ((mode_flags & PRINTF_FORTIFY) != 0) \
{ \
if (! readonly_format) \
{ \
@@ -1214,7 +1218,8 @@ static const uint8_t jump_table[] =
#endif

/* Helper function to provide temporary buffering for unbuffered streams. */
-static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
+static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
+ unsigned int)
__THROW __attribute__ ((noinline));

/* Handle positional format specifiers. */
@@ -1223,7 +1228,9 @@ static int printf_positional (FILE *s,
va_list ap, va_list *ap_savep, int done,
int nspecs_done, const UCHAR_T *lead_str_end,
CHAR_T *work_buffer, int save_errno,
- const char *grouping, THOUSANDS_SEP_T);
+ const char *grouping,
+ THOUSANDS_SEP_T thousands_sep,
+ unsigned int mode_flags);

/* Handle unknown format specifier. */
static int printf_unknown (FILE *, const struct printf_info *,
@@ -1235,7 +1242,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,

/* The function itself. */
int
-vfprintf (FILE *s, const CHAR_T *format, va_list ap)
+vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
{
/* The character used as thousands separator. */
THOUSANDS_SEP_T thousands_sep = 0;
@@ -1273,6 +1280,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
0 if unknown. */
int readonly_format = 0;

+ /* Temporarily honor environmental settings. */
+ if (__ldbl_is_dbl)
+ mode_flags |= PRINTF_LDBL_IS_DBL;
+ if (s->_flags2 & _IO_FLAGS2_FORTIFY)
+ mode_flags |= PRINTF_FORTIFY;
+
/* Orient the stream. */
#ifdef ORIENT
ORIENT;
@@ -1293,7 +1306,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (UNBUFFERED_P (s))
/* Use a helper function which will allocate a local temporary buffer
for the stream and then call us again. */
- return buffered_vfprintf (s, format, ap);
+ return buffered_vfprintf (s, format, ap, mode_flags);

/* Initialize local variables. */
done = 0;
@@ -1682,7 +1695,7 @@ do_positional:
}
done = printf_positional (s, format, readonly_format, ap, &ap_save,
done, nspecs_done, lead_str_end, work_buffer,
- save_errno, grouping, thousands_sep);
+ save_errno, grouping, thousands_sep, mode_flags);

all_done:
if (__glibc_unlikely (workstart != NULL))
@@ -1699,7 +1712,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
va_list ap, va_list *ap_savep, int done, int nspecs_done,
const UCHAR_T *lead_str_end,
CHAR_T *work_buffer, int save_errno,
- const char *grouping, THOUSANDS_SEP_T thousands_sep)
+ const char *grouping, THOUSANDS_SEP_T thousands_sep,
+ unsigned int mode_flags)
{
/* For positional argument handling. */
struct scratch_buffer specsbuf;
@@ -1789,7 +1803,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
now. */
args_size = &args_value[nargs].pa_int;
args_type = &args_size[nargs];
- memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
+ memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
nargs * sizeof (*args_type));
}

@@ -1856,7 +1870,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
case PA_FLOAT: /* Promoted. */
T (PA_DOUBLE, pa_double, double);
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
- if (__ldbl_is_dbl)
+ if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
{
args_value[cnt].pa_double = va_arg (*ap_savep, double);
args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
@@ -1884,7 +1898,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
case -1:
/* Error case. Not all parameters appear in N$ format
strings. We have no way to determine their type. */
- assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
+ assert ((mode_flags & PRINTF_FORTIFY) != 0);
__libc_fatal ("*** invalid %N$ use detected ***\n");
}

@@ -2285,7 +2299,8 @@ static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
#endif

static int
-buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
+buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
+ unsigned int mode_flags)
{
CHAR_T buf[BUFSIZ];
struct helper_file helper;
@@ -2318,11 +2333,7 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)
_IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;

/* Now print to helper instead. */
-#ifndef COMPILE_WPRINTF
- result = _IO_vfprintf (hp, format, args);
-#else
- result = vfprintf (hp, format, args);
-#endif
+ result = vfprintf (hp, format, args, mode_flags);

/* Lock stream. */
__libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
@@ -2351,14 +2362,3 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args)

return result;
}
-
-#undef vfprintf
-#ifdef COMPILE_WPRINTF
-strong_alias (_IO_vfwprintf, __vfwprintf);
-ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
-#else
-ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
-ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
-ldbl_hidden_def (_IO_vfprintf_internal, _IO_vfprintf)
-#endif
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index ae412e4b84..13a10db99b 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -15,2350 +15,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <array_length.h>
-#include <ctype.h>
-#include <limits.h>
-#include <printf.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <wchar.h>
-#include <libc-lock.h>
-#include <sys/param.h>
-#include <_itoa.h>
-#include <locale/localeinfo.h>
-#include <stdio.h>
-#include <scratch_buffer.h>
+#include <libio/libioP.h>

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

ldbl_strong_alias (__vprintf, vprintf)
diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
index 2840512cae..5b33604427 100644
--- a/stdlib/strfrom-skeleton.c
+++ b/stdlib/strfrom-skeleton.c
@@ -106,7 +106,7 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
}

/* The following code to prepare the virtual file has been adapted from the
- function _IO_vsnprintf from libio. */
+ function __vsnprintf_internal from libio. */

if (size == 0)
{
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 468e23dec4..bda84af0bb 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -166,7 +166,7 @@ __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
{
int done;
set_no_long_double ();
- done = _IO_vfprintf (s, fmt, ap);
+ done = __vfprintf_internal (s, fmt, ap, 0);
clear_no_long_double ();
return done;
}
@@ -175,15 +175,16 @@ strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)

int
attribute_compat_text_section
-__nldbl__IO_vsprintf (char *string, const char *fmt, va_list ap)
+__nldbl___vsprintf (char *string, const char *fmt, va_list ap)
{
int done;
__no_long_double = 1;
- done = _IO_vsprintf (string, fmt, ap);
+ done = __vsprintf_internal (string, fmt, ap, 0);
__no_long_double = 0;
return done;
}
-weak_alias (__nldbl__IO_vsprintf, __nldbl_vsprintf)
+strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
+weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
libc_hidden_def (__nldbl_vsprintf)

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

Changes since v2

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

Changed since v1:

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

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

Tested for powerpc and powerpc64le.

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

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

diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index f0072d8682..818b558140 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -332,10 +332,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
struct char_buffer charbuf;
scratch_buffer_init (&charbuf.scratch);

- /* Temporarily honor the environmental mode bits. */
- if (__ldbl_is_dbl)
- mode_flags |= SCANF_LDBL_IS_DBL;
-
#ifdef __va_copy
__va_copy (arg, argptr);
#else
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 91ea27a423..468e23dec4 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -19,7 +19,7 @@

#include <stdarg.h>
#include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
#include <math.h>
#include <wchar.h>
#include <printf.h>
@@ -335,13 +335,10 @@ int
attribute_compat_text_section
__nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
{
- int res;
- set_no_long_double ();
- res = __vfscanf_internal (s, fmt, ap, 0);
- clear_no_long_double ();
+ int ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
if (__glibc_unlikely (errp != 0))
- *errp = (res == -1);
- return res;
+ *errp = (ret == -1);
+ return ret;
}
#endif

@@ -349,11 +346,7 @@ int
attribute_compat_text_section
__nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
{
- int res;
- set_no_long_double ();
- res = __vfscanf_internal (s, fmt, ap, 0);
- clear_no_long_double ();
- return res;
+ return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
}
weak_alias (__nldbl___vfscanf, __nldbl_vfscanf)
libc_hidden_def (__nldbl_vfscanf)
@@ -362,26 +355,26 @@ int
attribute_compat_text_section
__nldbl_sscanf (const char *s, const char *fmt, ...)
{
- va_list arg;
- int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vsscanf (s, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}
strong_alias (__nldbl_sscanf, __nldbl__IO_sscanf)

int
attribute_compat_text_section
-__nldbl___vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___vsscanf (const char *s, const char *fmt, va_list ap)
{
- int res;
- __no_long_double = 1;
- res = _IO_vsscanf (string, fmt, ap);
- __no_long_double = 0;
- return res;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
}
weak_alias (__nldbl___vsscanf, __nldbl_vsscanf)
libc_hidden_def (__nldbl_vsscanf)
@@ -390,46 +383,42 @@ int
attribute_compat_text_section weak_function
__nldbl_vscanf (const char *fmt, va_list ap)
{
- return __nldbl_vfscanf (stdin, fmt, ap);
+ return __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
}

int
attribute_compat_text_section
__nldbl_fscanf (FILE *stream, const char *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vfscanf (stream, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl_scanf (const char *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vfscanf (stdin, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
{
- int res;
- set_no_long_double ();
- res = __vfwscanf_internal (s, fmt, ap, 0);
- clear_no_long_double ();
- return res;
+ return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL);
}
libc_hidden_def (__nldbl_vfwscanf)

@@ -437,25 +426,28 @@ int
attribute_compat_text_section
__nldbl_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vswscanf (s, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
-__nldbl_vswscanf (const wchar_t *string, const wchar_t *fmt, va_list ap)
+__nldbl_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
{
- int res;
- __no_long_double = 1;
- res = vswscanf (string, fmt, ap);
- __no_long_double = 0;
- return res;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+ return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL);
}
libc_hidden_def (__nldbl_vswscanf)

@@ -463,35 +455,35 @@ int
attribute_compat_text_section weak_function
__nldbl_vwscanf (const wchar_t *fmt, va_list ap)
{
- return __nldbl_vfwscanf (stdin, fmt, ap);
+ return __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
}

int
attribute_compat_text_section
__nldbl_fwscanf (FILE *stream, const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vfwscanf (stream, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (stream, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl_wscanf (const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl_vfwscanf (stdin, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL);
+ va_end (ap);

- return done;
+ return ret;
}

int
@@ -866,11 +858,7 @@ int
attribute_compat_text_section
__nldbl___isoc99_vfscanf (FILE *s, const char *fmt, va_list ap)
{
- int res;
- set_no_long_double ();
- res = __isoc99_vfscanf (s, fmt, ap);
- clear_no_long_double ();
- return res;
+ return __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}
libc_hidden_def (__nldbl___isoc99_vfscanf)

@@ -878,25 +866,26 @@ int
attribute_compat_text_section
__nldbl___isoc99_sscanf (const char *s, const char *fmt, ...)
{
- va_list arg;
- int done;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vsscanf (s, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
-__nldbl___isoc99_vsscanf (const char *string, const char *fmt, va_list ap)
+__nldbl___isoc99_vsscanf (const char *s, const char *fmt, va_list ap)
{
- int res;
- __no_long_double = 1;
- res = __isoc99_vsscanf (string, fmt, ap);
- __no_long_double = 0;
- return res;
+ _IO_strfile sf;
+ FILE *f = _IO_strfile_read (&sf, s);
+
+ return __vfscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}
libc_hidden_def (__nldbl___isoc99_vsscanf)

@@ -904,46 +893,44 @@ int
attribute_compat_text_section
__nldbl___isoc99_vscanf (const char *fmt, va_list ap)
{
- return __nldbl___isoc99_vfscanf (stdin, fmt, ap);
+ return __vfscanf_internal (stdin, fmt, ap,
+ SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}

int
attribute_compat_text_section
-__nldbl___isoc99_fscanf (FILE *stream, const char *fmt, ...)
+__nldbl___isoc99_fscanf (FILE *s, const char *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vfscanf (stream, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl___isoc99_scanf (const char *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfscanf_internal (stdin, fmt, ap,
+ SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
{
- int res;
- set_no_long_double ();
- res = __isoc99_vfwscanf (s, fmt, ap);
- clear_no_long_double ();
- return res;
+ return __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}
libc_hidden_def (__nldbl___isoc99_vfwscanf)

@@ -951,26 +938,28 @@ int
attribute_compat_text_section
__nldbl___isoc99_swscanf (const wchar_t *s, const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vswscanf (s, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
-__nldbl___isoc99_vswscanf (const wchar_t *string, const wchar_t *fmt,
- va_list ap)
+__nldbl___isoc99_vswscanf (const wchar_t *s, const wchar_t *fmt, va_list ap)
{
- int res;
- __no_long_double = 1;
- res = __isoc99_vswscanf (string, fmt, ap);
- __no_long_double = 0;
- return res;
+ _IO_strfile sf;
+ struct _IO_wide_data wd;
+ FILE *f = _IO_strfile_readw (&sf, &wd, s);
+
+ return __vfwscanf_internal (f, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}
libc_hidden_def (__nldbl___isoc99_vswscanf)

@@ -978,35 +967,37 @@ int
attribute_compat_text_section
__nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
{
- return __nldbl___isoc99_vfwscanf (stdin, fmt, ap);
+ return __vfwscanf_internal (stdin, fmt, ap,
+ SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
}

int
attribute_compat_text_section
-__nldbl___isoc99_fwscanf (FILE *stream, const wchar_t *fmt, ...)
+__nldbl___isoc99_fwscanf (FILE *s, const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vfwscanf (stream, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (s, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

int
attribute_compat_text_section
__nldbl___isoc99_wscanf (const wchar_t *fmt, ...)
{
- va_list arg;
- int done;
+ va_list ap;
+ int ret;

- va_start (arg, fmt);
- done = __nldbl___isoc99_vfwscanf (stdin, fmt, arg);
- va_end (arg);
+ va_start (ap, fmt);
+ ret = __vfwscanf_internal (stdin, fmt, ap,
+ SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+ va_end (ap);

- return done;
+ return ret;
}

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

Changes since v2:

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

Changes since v1:

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

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

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

obstack_printf_chk and obstack_vprintf_chk are no longer in the same
file.

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

Tested for powerpc and powerpc64le.

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

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

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

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

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

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

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

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

diff --git a/debug/Makefile b/debug/Makefile
index 506cebc3c4..2ef08cf23b 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -45,7 +45,7 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \
gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
- vdprintf_chk obprintf_chk \
+ vdprintf_chk obprintf_chk vobprintf_chk \
longjmp_chk ____longjmp_chk \
fdelt_chk poll_chk ppoll_chk \
explicit_bzero_chk \
diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c
index 9cd4143f2e..eb885c35ca 100644
--- a/debug/asprintf_chk.c
+++ b/debug/asprintf_chk.c
@@ -15,22 +15,24 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>


/* Write formatted output from FORMAT to a string which is
allocated with malloc and stored in *STRING_PTR. */
int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__asprintf_chk (char **result_ptr, int flag, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;

- va_start (arg, format);
- done = __vasprintf_chk (result_ptr, flags, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vasprintf_internal (result_ptr, format, ap, mode);
+ va_end (ap);

- return done;
+ return ret;
}
diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c
index df3867c61c..b5c62827c0 100644
--- a/debug/dprintf_chk.c
+++ b/debug/dprintf_chk.c
@@ -15,21 +15,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>


/* Write formatted output to D, according to the format string FORMAT. */
int
-__dprintf_chk (int d, int flags, const char *format, ...)
+__dprintf_chk (int d, int flag, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;

- va_start (arg, format);
- done = __vdprintf_chk (d, flags, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vdprintf_internal (d, format, ap, mode);
+ va_end (ap);

- return done;
+ return ret;
}
diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
index cff4438afb..14afc073b2 100644
--- a/debug/fprintf_chk.c
+++ b/debug/fprintf_chk.c
@@ -16,29 +16,23 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to FP from the format string FORMAT. */
int
___fprintf_chk (FILE *fp, int flag, const char *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;

va_start (ap, format);
- done = vfprintf (fp, format, ap);
+ ret = __vfprintf_internal (fp, format, ap, mode);
va_end (ap);

- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return ret;
}
ldbl_strong_alias (___fprintf_chk, __fprintf_chk)
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index 63167c1839..10d84ce98b 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -16,28 +16,22 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to FP from the format string FORMAT. */
int
__fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;

va_start (ap, format);
- done = __vfwprintf_internal (fp, format, ap, 0);
+ ret = __vfwprintf_internal (fp, format, ap, mode);
va_end (ap);

- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return ret;
}
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 41dd481c34..c1a8f9e9a9 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -17,99 +17,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-
-#include <stdlib.h>
-#include <libioP.h>
-#include "../libio/strfile.h"
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <obstack.h>
+#include <libio/libioP.h>
#include <stdarg.h>
-#include <stdio_ext.h>
-
-
-struct _IO_obstack_file
-{
- struct _IO_FILE_plus file;
- struct obstack *obstack;
-};
-
-extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
-
-int
-__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
- va_list args)
-{
- struct obstack_FILE
- {
- struct _IO_obstack_file ofile;
- } new_f;
- int result;
- int size;
- int room;
-
-#ifdef _IO_MTSAFE_IO
- new_f.ofile.file.file._lock = NULL;
-#endif
-
- _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
- room = obstack_room (obstack);
- size = obstack_object_size (obstack) + room;
- if (size == 0)
- {
- /* We have to handle the allocation a bit different since the
- `_IO_str_init_static' function would handle a size of zero
- different from what we expect. */
-
- /* Get more memory. */
- obstack_make_room (obstack, 64);
-
- /* Recompute how much room we have. */
- room = obstack_room (obstack);
- size = room;
-
- assert (size != 0);
- }
-
- _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile,
- obstack_base (obstack),
- size, obstack_next_free (obstack));
- /* Now allocate the rest of the current chunk. */
- assert (size == (new_f.ofile.file.file._IO_write_end
- - new_f.ofile.file.file._IO_write_base));
- assert (new_f.ofile.file.file._IO_write_ptr
- == (new_f.ofile.file.file._IO_write_base
- + obstack_object_size (obstack)));
- obstack_blank_fast (obstack, room);
-
- new_f.ofile.obstack = obstack;
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
- can only come from read-only format strings. */
- if (flags > 0)
- new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
- result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
-
- /* Shrink the buffer to the space we really currently need. */
- obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
- - new_f.ofile.file.file._IO_write_end));
-
- return result;
-}
-libc_hidden_def (__obstack_vprintf_chk)


int
-__obstack_printf_chk (struct obstack *obstack, int flags, const char *format,
+__obstack_printf_chk (struct obstack *obstack, int flag, const char *format,
...)
{
- int result;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
+ int ret;
+
va_start (ap, format);
- result = __obstack_vprintf_chk (obstack, flags, format, ap);
+ ret = __obstack_vprintf_internal (obstack, format, ap, mode);
va_end (ap);
- return result;
+
+ return ret;
}
diff --git a/debug/printf_chk.c b/debug/printf_chk.c
index 426dc78386..e035b42590 100644
--- a/debug/printf_chk.c
+++ b/debug/printf_chk.c
@@ -16,29 +16,23 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to stdout from the format string FORMAT. */
int
___printf_chk (int flag, const char *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;

va_start (ap, format);
- done = vfprintf (stdout, format, ap);
+ ret = __vfprintf_internal (stdout, format, ap, mode);
va_end (ap);

- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return ret;
}
ldbl_strong_alias (___printf_chk, __printf_chk)
diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
index cddba37109..984b5e8932 100644
--- a/debug/snprintf_chk.c
+++ b/debug/snprintf_chk.c
@@ -15,25 +15,29 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>


/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-___snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
const char *format, ...)
{
- va_list arg;
- int done;
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();

- va_start (arg, format);
- done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
- va_end (arg);
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;

- return done;
+ va_start (ap, format);
+ ret = __vsnprintf_internal (s, maxlen, format, ap, mode);
+ va_end (ap);
+
+ return ret;
}
ldbl_strong_alias (___snprintf_chk, __snprintf_chk)
diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
index 78214563dd..649e8ab4d5 100644
--- a/debug/sprintf_chk.c
+++ b/debug/sprintf_chk.c
@@ -15,22 +15,27 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
+

/* Write formatted output into S, according to the format string FORMAT. */
-/* VARARGS4 */
int
-___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
+___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
+
+ if (slen == 0)
+ __chk_fail ();

- va_start (arg, format);
- done = __vsprintf_chk (s, flags, slen, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vsprintf_internal (s, slen, format, ap, mode);
+ va_end (ap);

- return done;
+ return ret;
}
ldbl_strong_alias (___sprintf_chk, __sprintf_chk)
diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c
index 35887e48e2..186c17751c 100644
--- a/debug/swprintf_chk.c
+++ b/debug/swprintf_chk.c
@@ -16,20 +16,27 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <wchar.h>
+#include <libio/libioP.h>

-/* Write formatted output into S, according to the format string FORMAT. */
-/* VARARGS5 */
+
+/* Write formatted output into S, according to the format string FORMAT,
+ writing no more than MAXLEN characters. */
int
-__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len,
+__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
const wchar_t *format, ...)
{
- va_list arg;
- int done;
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;

- va_start (arg, format);
- done = __vswprintf_chk (s, n, flag, s_len, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vswprintf_internal (s, maxlen, format, ap, mode);
+ va_end (ap);

- return done;
+ return ret;
}
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index dbfebff83f..f5975ea02a 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -24,72 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <malloc.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>

int
-__vasprintf_chk (char **result_ptr, int flags, const char *format,
- va_list args)
+__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap)
{
- /* Initial size of the buffer to be used. Will be doubled each time an
- overflow occurs. */
- const size_t init_string_size = 100;
- char *string;
- _IO_strfile sf;
- int ret;
- size_t needed;
- size_t allocated;
- /* No need to clear the memory here (unlike for open_memstream) since
- we know we will never seek on the stream. */
- string = (char *) malloc (init_string_size);
- if (string == NULL)
- return -1;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, string, init_string_size, string);
- sf._sbf._f._flags &= ~_IO_USER_BUF;
- sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
- sf._s._free_buffer_unused = (_IO_free_type) free;
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
- if (ret < 0)
- {
- free (sf._sbf._f._IO_buf_base);
- return ret;
- }
- /* Only use realloc if the size we need is of the same (binary)
- order of magnitude then the memory we allocated. */
- needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1;
- allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base;
- if ((allocated >> 1) <= needed)
- *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
- else
- {
- *result_ptr = (char *) malloc (needed);
- if (*result_ptr != NULL)
- {
- memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1);
- free (sf._sbf._f._IO_buf_base);
- }
- else
- /* We have no choice, use the buffer we already have. */
- *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
- }
- if (*result_ptr == NULL)
- *result_ptr = sf._sbf._f._IO_buf_base;
- (*result_ptr)[needed - 1] = '\0';
- return ret;
+ return __vasprintf_internal (result_ptr, format, ap, mode);
}
-libc_hidden_def (__vasprintf_chk)
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index 4386127cfe..e04514e355 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -24,41 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */

-#include <libioP.h>
-#include <stdio_ext.h>
+#include <libio/libioP.h>

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

- return done;
+ return __vdprintf_internal (d, format, ap, mode);
}
-libc_hidden_def (__vdprintf_chk)
diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
index 5babbf611e..44426e14fd 100644
--- a/debug/vfprintf_chk.c
+++ b/debug/vfprintf_chk.c
@@ -15,28 +15,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to FP from the format string FORMAT. */
int
___vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = vfprintf (fp, format, ap);
-
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return __vfprintf_internal (fp, format, ap, mode);
}
-ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk)
ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk)
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index abf2bd6517..3aed308156 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -15,27 +15,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to FP from the format string FORMAT. */
int
__vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfwprintf_internal (fp, format, ap, 0);
-
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return __vfwprintf_internal (fp, format, ap, mode);
}
-libc_hidden_def (__vfwprintf_chk)
diff --git a/debug/asprintf_chk.c b/debug/vobprintf_chk.c
similarity index 61%
copy from debug/asprintf_chk.c
copy to debug/vobprintf_chk.c
index 9cd4143f2e..bed2c98eac 100644
--- a/debug/asprintf_chk.c
+++ b/debug/vobprintf_chk.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Print output of stream to given obstack.
+ Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
@@ -15,22 +16,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <libioP.h>
-#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>


-/* Write formatted output from FORMAT to a string which is
- allocated with malloc and stored in *STRING_PTR. */
int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+ va_list ap)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- va_start (arg, format);
- done = __vasprintf_chk (result_ptr, flags, format, arg);
- va_end (arg);
-
- return done;
+ return __obstack_vprintf_internal (obstack, format, ap, mode);
}
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
index b3b2c53df2..69fcb721ac 100644
--- a/debug/vprintf_chk.c
+++ b/debug/vprintf_chk.c
@@ -15,27 +15,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to stdout from the format string FORMAT. */
int
___vprintf_chk (int flag, const char *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = vfprintf (stdout, format, ap);
-
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return __vfprintf_internal (stdout, format, ap, mode);
}
ldbl_strong_alias (___vprintf_chk, __vprintf_chk)
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index 95d286f416..666a83b701 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -15,56 +15,22 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>

-extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;

/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
- const char *format, va_list args)
+___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+ const char *format, va_list ap)
{
- /* XXX Maybe for less strict version do not fail immediately.
- Though, maxlen is supposed to be the size of buffer pointed
- to by s, so a conforming program can't pass such maxlen
- to *snprintf. */
if (__glibc_unlikely (slen < maxlen))
__chk_fail ();

- _IO_strnfile sf;
- int ret;
-#ifdef _IO_MTSAFE_IO
- sf.f._sbf._f._lock = NULL;
-#endif
-
- /* We need to handle the special case where MAXLEN is 0. Use the
- overflow buffer right from the start. */
- if (maxlen == 0)
- {
- s = sf.overflow_buf;
- maxlen = sizeof (sf.overflow_buf);
- }
-
- _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
- s[0] = '\0';
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
- ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
- *sf.f._sbf._f._IO_write_ptr = '\0';
- return ret;
+ return __vsnprintf_internal (s, maxlen, format, ap, mode);
}
-ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 53f07236ae..c1b1a8da4f 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -15,75 +15,20 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
-
-
-static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
-
-static int
-_IO_str_chk_overflow (FILE *fp, int c)
-{
- /* When we come to here this means the user supplied buffer is
- filled. */
- __chk_fail ();
-}
-
-
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
- JUMP_INIT_DUMMY,
- JUMP_INIT(finish, _IO_str_finish),
- JUMP_INIT(overflow, _IO_str_chk_overflow),
- JUMP_INIT(underflow, _IO_str_underflow),
- JUMP_INIT(uflow, _IO_default_uflow),
- JUMP_INIT(pbackfail, _IO_str_pbackfail),
- JUMP_INIT(xsputn, _IO_default_xsputn),
- JUMP_INIT(xsgetn, _IO_default_xsgetn),
- JUMP_INIT(seekoff, _IO_str_seekoff),
- JUMP_INIT(seekpos, _IO_default_seekpos),
- JUMP_INIT(setbuf, _IO_default_setbuf),
- JUMP_INIT(sync, _IO_default_sync),
- JUMP_INIT(doallocate, _IO_default_doallocate),
- JUMP_INIT(read, _IO_default_read),
- JUMP_INIT(write, _IO_default_write),
- JUMP_INIT(seek, _IO_default_seek),
- JUMP_INIT(close, _IO_default_close),
- JUMP_INIT(stat, _IO_default_stat),
- JUMP_INIT(showmanyc, _IO_default_showmanyc),
- JUMP_INIT(imbue, _IO_default_imbue)
-};
-
+#include <libio/libioP.h>

int
-___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
- va_list args)
+___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+ va_list ap)
{
- _IO_strfile f;
- int ret;
-#ifdef _IO_MTSAFE_IO
- f._sbf._f._lock = NULL;
-#endif
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

if (slen == 0)
__chk_fail ();

- _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
- s[0] = '\0';
- _IO_str_init_static_internal (&f, s, slen - 1, s);
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
- can only come from read-only format strings. */
- if (flags > 0)
- f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
-
- *f._sbf._f._IO_write_ptr = '\0';
- return ret;
+ return __vsprintf_internal (s, slen, format, ap, mode);
}
ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 4d616f8835..2c6fadd463 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -15,60 +15,21 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>


/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
- const wchar_t *format, va_list args)
+__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
+ const wchar_t *format, va_list ap)
{
- /* XXX Maybe for less strict version do not fail immediately.
- Though, maxlen is supposed to be the size of buffer pointed
- to by s, so a conforming program can't pass such maxlen
- to *snprintf. */
if (__glibc_unlikely (slen < maxlen))
__chk_fail ();

- _IO_wstrnfile sf;
- struct _IO_wide_data wd;
- int ret;
-#ifdef _IO_MTSAFE_IO
- sf.f._sbf._f._lock = NULL;
-#endif
-
- /* We need to handle the special case where MAXLEN is 0. Use the
- overflow buffer right from the start. */
- if (__glibc_unlikely (maxlen == 0))
- /* Since we have to write at least the terminating L'\0' a buffer
- length of zero always makes the function fail. */
- return -1;
-
- _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
- _IO_fwide (&sf.f._sbf._f, 1);
- s[0] = L'\0';
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
- ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
-
- if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
- /* ISO C99 requires swprintf/vswprintf to return an error if the
- output does not fit int he provided buffer. */
- return -1;
-
- /* Terminate the string. */
- *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- return ret;
+ return __vswprintf_internal (s, maxlen, format, ap, mode);
}
-libc_hidden_def (__vswprintf_chk)
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index fedc7a46bf..f1e8878a54 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -15,27 +15,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to stdout from the format string FORMAT. */
int
__vwprintf_chk (int flag, const wchar_t *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;

- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfwprintf_internal (stdout, format, ap, 0);
-
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return __vfwprintf_internal (stdout, format, ap, mode);
}
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 819050e5af..9f406e95f8 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -16,29 +16,22 @@
<http://www.gnu.org/licenses/>. */

#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>


/* Write formatted output to stdout from the format string FORMAT. */
int
__wprintf_chk (int flag, const wchar_t *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;

va_start (ap, format);
- done = __vfwprintf_internal (stdout, format, ap, 0);
+ ret = __vfwprintf_internal (stdout, format, ap, mode);
va_end (ap);

- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return ret;
}
diff --git a/include/stdio.h b/include/stdio.h
index 0856d729d9..1b7da0f74d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -216,11 +216,6 @@ libc_hidden_proto (__open_memstream)
libc_hidden_proto (__libc_fatal)
rtld_hidden_proto (__libc_fatal)
libc_hidden_proto (__vsprintf_chk)
-libc_hidden_proto (__vsnprintf_chk)
-libc_hidden_proto (__vfprintf_chk)
-libc_hidden_proto (__vasprintf_chk)
-libc_hidden_proto (__vdprintf_chk)
-libc_hidden_proto (__obstack_vprintf_chk)

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

extern int __isoc99_fwscanf (__FILE *__restrict __stream,
const wchar_t *__restrict __format, ...);
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 3b1e8292b5..08e4002625 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -27,8 +27,47 @@
#include "libioP.h"
#include "strfile.h"

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

int
__vsprintf (char *string, const char *format, va_list args)
{
- return __vsprintf_internal (string, format, args, 0);
+ return __vsprintf_internal (string, -1, format, args, 0);
}

ldbl_strong_alias (__vsprintf, _IO_vsprintf)
diff --git a/libio/libio.h b/libio/libio.h
index c188814ccc..3a93807efc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -90,7 +90,6 @@ typedef union
/* Bits for the _flags2 field. */
#define _IO_FLAGS2_MMAP 1
#define _IO_FLAGS2_NOTCANCEL 2
-#define _IO_FLAGS2_FORTIFY 4
#define _IO_FLAGS2_USER_WBUF 8
#define _IO_FLAGS2_NOCLOSE 32
#define _IO_FLAGS2_CLOEXEC 64
diff --git a/libio/libioP.h b/libio/libioP.h
index fe52ef1752..ce5228e382 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
va_list ap, unsigned int mode_flags)
attribute_hidden;

-extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument,
+ because it's called by both vsprintf and vsprintf_chk. If maxlen is
+ not set to -1, overrunning the buffer will cause a prompt crash.
+ This is the behavior of ordinary (v)sprintf functions, thus they call
+ __vsprintf_internal with that argument set to -1. */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list ap,
unsigned int mode_flags)
attribute_hidden;
+
extern int __vsnprintf_internal (char *string, size_t maxlen,
const char *format, va_list ap,
unsigned int mode_flags)
@@ -818,26 +825,10 @@ _IO_acquire_lock_fct (FILE **p)
_IO_funlockfile (fp);
}

-static inline void
-__attribute__ ((__always_inline__))
-_IO_acquire_lock_clear_flags2_fct (FILE **p)
-{
- FILE *fp = *p;
- fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
- if ((fp->_flags & _IO_USER_LOCK) == 0)
- _IO_funlockfile (fp);
-}
-
#if !defined _IO_MTSAFE_IO && IS_IN (libc)
# define _IO_acquire_lock(_fp) \
- do { \
- FILE *_IO_acquire_lock_file = NULL
-# define _IO_acquire_lock_clear_flags2(_fp) \
- do { \
- FILE *_IO_acquire_lock_file = (_fp)
+ do {
# define _IO_release_lock(_fp) \
- if (_IO_acquire_lock_file != NULL) \
- _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY); \
} while (0)
#endif

diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index 77423b292f..447faa4e25 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
int done;

va_start (arg, format);
- done = __vsprintf_internal (s, format, arg, 0);
+ done = __vsprintf_internal (s, -1, format, arg, 0);
va_end (arg);

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

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

diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 958bbc1834..59b2c9fcdd 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -179,7 +179,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
{
int done;
__no_long_double = 1;
- done = __vsprintf_internal (string, fmt, ap, 0);
+ done = __vsprintf_internal (string, -1, fmt, ap, 0);
__no_long_double = 0;
return done;
}
@@ -579,7 +579,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = __vfprintf_chk (s, flag, fmt, ap);
+ res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -591,7 +591,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = __vfwprintf_chk (s, flag, fmt, ap);
+ res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -609,9 +609,13 @@ attribute_compat_text_section
__nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
const char *fmt, va_list ap)
{
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap);
+ res = __vsnprintf_internal (string, maxlen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -622,9 +626,13 @@ attribute_compat_text_section
__nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
va_list ap)
{
+ if (slen == 0)
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vsprintf_chk (string, flag, slen, fmt, ap);
+ res = __vsprintf_internal (string, slen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -635,9 +643,13 @@ attribute_compat_text_section
__nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
const wchar_t *fmt, va_list ap)
{
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap);
+ res = __vswprintf_internal (string, maxlen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -670,7 +682,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
{
int res;
__no_long_double = 1;
- res = __vasprintf_chk (ptr, flag, fmt, arg);
+ res = __vasprintf_internal (ptr, fmt, arg,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -696,7 +709,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
{
int res;
set_no_long_double ();
- res = __vdprintf_chk (d, flag, fmt, arg);
+ res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -723,7 +736,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
{
int res;
__no_long_double = 1;
- res = __obstack_vprintf_chk (obstack, flag, fmt, arg);
+ res = __obstack_vprintf_internal (obstack, fmt, arg,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
index 5b9782452f..1d6a81c5bf 100644
--- a/sysdeps/nptl/stdio-lock.h
+++ b/sysdeps/nptl/stdio-lock.h
@@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
__attribute__((cleanup (_IO_acquire_lock_fct))) \
= (_fp); \
_IO_flockfile (_IO_acquire_lock_file);
-# define _IO_acquire_lock_clear_flags2(_fp) \
- do { \
- FILE *_IO_acquire_lock_file \
- __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct))) \
- = (_fp); \
- _IO_flockfile (_IO_acquire_lock_file);
# else
# define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
# endif
# define _IO_release_lock(_fp) ; } while (0)
--
2.14.5
Adhemerval Zanella
2018-11-22 18:11:33 UTC
Permalink
Post by Gabriel F. T. Gomes
- Fix copyright statements.
- Add note about the fix for bug 11319.
I don't recall exactly which patch was the one that actually fixes BZ#11319,
my previous indication was 'Add __v*printf_internal with flags arguments.'.
Could you recheck it please?

Besides it the patch LGTM, thanks.
Post by Gabriel F. T. Gomes
- Fixed white-space errors.
- Updated commit message.
- In the declaration of __vsnprintf_internal, in libio/libioP.h,
mention that passing -1 to the maxlen argument is the behavior of
ordinary (v)sprintf function (this was already described in the
commit message, but seems relevant to the code itself).
-- 8< --
The _chk variants of all of the printf functions become much simpler.
This is the last thing that we needed _IO_acquire_lock_clear_flags2
for, so it can go as well. I took the opportunity to make the headers
included and the names of all local variables consistent across all the
affected files.
Since we ultimately want to get rid of __no_long_double as well, it
must be possible to get all of the nontrivial effects of the _chk
functions by calling the _internal functions with appropriate flags.
For most of the __(v)xprintf_chk functions, this is covered by
PRINTF_FORTIFY plus some up-front argument checks that can be
duplicated. However, __(v)sprintf_chk installs a custom jump table so
that it can crash instead of overflowing the output buffer. This
functionality is moved to __vsprintf_internal, which now has a
'maxlen' argument like __vsnprintf_internal; to get the unsafe
behavior of ordinary (v)sprintf, pass -1 for that argument.
obstack_printf_chk and obstack_vprintf_chk are no longer in the same
file.
As a side-effect of the unification of both fortified and non-fortified
vdprintf initialization, this patch fixes bug 11319.
Tested for powerpc and powerpc64le.
[BZ #11319]
Moved here from debug/vsprintf_chk.c.
(__vsprintf_internal): Add 'maxlen' argument. Change the setup
and completion logic for the strfile to match exactly what
__vsprintf_chk used to do, except, when maxlen is -1, pass -1 to
_IO_str_init_static_internal instead of maxlen-1.
(__vsprintf): Pass -1 as maxlen to __vsprintf_internal.
* stdio-common/sprintf.c (__sprintf): Pass -1 as maxlen to
__vsprintf_internal.
* debug/vsprintf_chk.c (__vsprintf_chk)
Directly call __vsprintf_internal, passing PRINTF_FORTIFY if
'flags' argument is positive, and slen as maxlen. No need to lock
the FILE and/or construct a temporary FILE. Minimize and normalize
header inclusions and variable names. Do not libc_hidden_def anything.
* debug/asprintf_chk.c (__asprintf_chk)
* debug/dprintf_chk.c (__dprintf_chk)
* debug/fprintf_chk.c (__fprintf_chk)
* debug/fwprintf_chk.c (__fwprintf_chk)
* debug/printf_chk.c (__printf_chk)
* debug/snprintf_chk.c (__snprintf_chk)
* debug/swprintf_chk.c (__swprintf_chk)
* debug/vasprintf_chk.c (__vasprintf_chk)
* debug/vdprintf_chk.c (__vdprintf_chk)
* debug/vfprintf_chk.c (__vfprintf_chk)
* debug/vfwprintf_chk.c (__vfwprintf_chk)
* debug/vprintf_chk.c (__vprintf_chk)
* debug/vsnprintf_chk.c (__vsnprintf_chk)
* debug/vswprintf_chk.c (__vswprintf_chk)
* debug/vwprintf_chk.c (__vwprintf_chk)
Directly call the corresponding vxxprintf_internal function, passing
PRINTF_FORTIFY if 'flag' argument is positive. No need to lock
the FILE and/or construct a temporary FILE. Minimize and normalize
header inclusions and variable names. Do not libc_hidden_def anything.
* debug/obprintf_chk.c (__obstack_printf_chk): Directly call
__obstack_vprintf_internal.
(__obstack_vprintf_chk): Convert into a wrapper that calls
__obstack_vprintf_internal (these two functions already had the
same code) and move to new file...
* debug/vobprintf_chk.c (__obstack_vprintf_chk): ... here. New
file.
* debug/obprintf.c (__obstack_vprintf_internal): Remove the checking of
the flags argument and the setting of _IO_FLAGS2_FORTIFY.
* debug/Makefile (routines): Add vobprintf_chk.
* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
(__nldbl___vsprintf): Pass -1 as maxlen to __vsprintf_internal.
(__nldbl___vfprintf_chk, __nldbl___vsnprintf_chk)
(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
(__nldbl___vasprintf_chk, __nldbl___vdprintf_chk)
Directly call the corresponding vxxprintf_internal function,
passing PRINTF_FORTIFY if 'flag' argument is positive. If necessary,
duplicate comparison of slen with 0 or maxlen from the corresponding
non-__nldbl function.
* include/stdio.h (__vsnprintf_chk, __vfprintf_chk, __vasprintf_chk)
(__vdprintf_chk, __obstack_vfprintf_chk): Remove libc_hidden_proto.
Remove libc_hidden_proto.
* stdio-common/vfprintf-internal.c
Do not check _IO_FLAGS2_FORTIFY.
* libio/libio.h (_IO_FLAGS2_FORTIFY): Remove.
* libio/libioP.h: Update prototype of __vsprintf_internal and add
a comment explaining why it has the maxlen argument.
(_IO_acquire_lock_clear_flags2_fct): Remove.
(_IO_acquire_lock_clear_flags2): Remove.
(_IO_release_lock): Remove conditional statement which will
now never execute.
(_IO_acquire_lock): Remove variable which is now unused.
* sysdeps/generic/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
* sysdeps/nptl/stdio-lock.h (_IO_acquire_lock_clear_flags2): Remove.
---
debug/Makefile | 2 +-
debug/asprintf_chk.c | 20 ++++---
debug/dprintf_chk.c | 20 ++++---
debug/fprintf_chk.c | 20 +++----
debug/fwprintf_chk.c | 20 +++----
debug/obprintf_chk.c | 96 ++++---------------------------
debug/printf_chk.c | 20 +++----
debug/snprintf_chk.c | 24 ++++----
debug/sprintf_chk.c | 25 ++++----
debug/swprintf_chk.c | 27 +++++----
debug/vasprintf_chk.c | 68 ++--------------------
debug/vdprintf_chk.c | 37 ++----------
debug/vfprintf_chk.c | 21 ++-----
debug/vfwprintf_chk.c | 21 ++-----
debug/{asprintf_chk.c => vobprintf_chk.c} | 23 +++-----
debug/vprintf_chk.c | 20 ++-----
debug/vsnprintf_chk.c | 46 ++-------------
debug/vsprintf_chk.c | 69 +++-------------------
debug/vswprintf_chk.c | 51 ++--------------
debug/vwprintf_chk.c | 21 ++-----
debug/wprintf_chk.c | 21 +++----
include/stdio.h | 5 --
include/wchar.h | 2 -
libio/iovsprintf.c | 54 +++++++++++++++--
libio/libio.h | 1 -
libio/libioP.h | 27 +++------
stdio-common/sprintf.c | 2 +-
stdio-common/vfprintf-internal.c | 2 -
sysdeps/generic/stdio-lock.h | 7 ---
sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 32 ++++++++---
sysdeps/nptl/stdio-lock.h | 7 ---
31 files changed, 247 insertions(+), 564 deletions(-)
copy debug/{asprintf_chk.c => vobprintf_chk.c} (61%)
diff --git a/debug/Makefile b/debug/Makefile
index 506cebc3c4..2ef08cf23b 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -45,7 +45,7 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \
gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
- vdprintf_chk obprintf_chk \
+ vdprintf_chk obprintf_chk vobprintf_chk \
longjmp_chk ____longjmp_chk \
fdelt_chk poll_chk ppoll_chk \
explicit_bzero_chk \
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/asprintf_chk.c b/debug/asprintf_chk.c
index 9cd4143f2e..eb885c35ca 100644
--- a/debug/asprintf_chk.c
+++ b/debug/asprintf_chk.c
@@ -15,22 +15,24 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
/* Write formatted output from FORMAT to a string which is
allocated with malloc and stored in *STRING_PTR. */
int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__asprintf_chk (char **result_ptr, int flag, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
- va_start (arg, format);
- done = __vasprintf_chk (result_ptr, flags, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vasprintf_internal (result_ptr, format, ap, mode);
+ va_end (ap);
- return done;
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/dprintf_chk.c b/debug/dprintf_chk.c
index df3867c61c..b5c62827c0 100644
--- a/debug/dprintf_chk.c
+++ b/debug/dprintf_chk.c
@@ -15,21 +15,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
/* Write formatted output to D, according to the format string FORMAT. */
int
-__dprintf_chk (int d, int flags, const char *format, ...)
+__dprintf_chk (int d, int flag, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
- va_start (arg, format);
- done = __vdprintf_chk (d, flags, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vdprintf_internal (d, format, ap, mode);
+ va_end (ap);
- return done;
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
index cff4438afb..14afc073b2 100644
--- a/debug/fprintf_chk.c
+++ b/debug/fprintf_chk.c
@@ -16,29 +16,23 @@
<http://www.gnu.org/licenses/>. */
#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to FP from the format string FORMAT. */
int
___fprintf_chk (FILE *fp, int flag, const char *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;
va_start (ap, format);
- done = vfprintf (fp, format, ap);
+ ret = __vfprintf_internal (fp, format, ap, mode);
va_end (ap);
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return ret;
}
ldbl_strong_alias (___fprintf_chk, __fprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index 63167c1839..10d84ce98b 100644
--- a/debug/fwprintf_chk.c
+++ b/debug/fwprintf_chk.c
@@ -16,28 +16,22 @@
<http://www.gnu.org/licenses/>. */
#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to FP from the format string FORMAT. */
int
__fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;
va_start (ap, format);
- done = __vfwprintf_internal (fp, format, ap, 0);
+ ret = __vfwprintf_internal (fp, format, ap, mode);
va_end (ap);
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 41dd481c34..c1a8f9e9a9 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -17,99 +17,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-
-#include <stdlib.h>
-#include <libioP.h>
-#include "../libio/strfile.h"
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <obstack.h>
+#include <libio/libioP.h>
#include <stdarg.h>
-#include <stdio_ext.h>
-
-
-struct _IO_obstack_file
-{
- struct _IO_FILE_plus file;
- struct obstack *obstack;
-};
-
-extern const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden;
-
-int
-__obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
- va_list args)
-{
- struct obstack_FILE
- {
- struct _IO_obstack_file ofile;
- } new_f;
- int result;
- int size;
- int room;
-
-#ifdef _IO_MTSAFE_IO
- new_f.ofile.file.file._lock = NULL;
-#endif
-
- _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
- room = obstack_room (obstack);
- size = obstack_object_size (obstack) + room;
- if (size == 0)
- {
- /* We have to handle the allocation a bit different since the
- `_IO_str_init_static' function would handle a size of zero
- different from what we expect. */
-
- /* Get more memory. */
- obstack_make_room (obstack, 64);
-
- /* Recompute how much room we have. */
- room = obstack_room (obstack);
- size = room;
-
- assert (size != 0);
- }
-
- _IO_str_init_static_internal ((struct _IO_strfile_ *) &new_f.ofile,
- obstack_base (obstack),
- size, obstack_next_free (obstack));
- /* Now allocate the rest of the current chunk. */
- assert (size == (new_f.ofile.file.file._IO_write_end
- - new_f.ofile.file.file._IO_write_base));
- assert (new_f.ofile.file.file._IO_write_ptr
- == (new_f.ofile.file.file._IO_write_base
- + obstack_object_size (obstack)));
- obstack_blank_fast (obstack, room);
-
- new_f.ofile.obstack = obstack;
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
- can only come from read-only format strings. */
- if (flags > 0)
- new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
- result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0);
-
- /* Shrink the buffer to the space we really currently need. */
- obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
- - new_f.ofile.file.file._IO_write_end));
-
- return result;
-}
-libc_hidden_def (__obstack_vprintf_chk)
int
-__obstack_printf_chk (struct obstack *obstack, int flags, const char *format,
+__obstack_printf_chk (struct obstack *obstack, int flag, const char *format,
...)
{
- int result;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
+ int ret;
+
va_start (ap, format);
- result = __obstack_vprintf_chk (obstack, flags, format, ap);
+ ret = __obstack_vprintf_internal (obstack, format, ap, mode);
va_end (ap);
- return result;
+
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/printf_chk.c b/debug/printf_chk.c
index 426dc78386..e035b42590 100644
--- a/debug/printf_chk.c
+++ b/debug/printf_chk.c
@@ -16,29 +16,23 @@
<http://www.gnu.org/licenses/>. */
#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to stdout from the format string FORMAT. */
int
___printf_chk (int flag, const char *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;
va_start (ap, format);
- done = vfprintf (stdout, format, ap);
+ ret = __vfprintf_internal (stdout, format, ap, mode);
va_end (ap);
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return ret;
}
ldbl_strong_alias (___printf_chk, __printf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
index cddba37109..984b5e8932 100644
--- a/debug/snprintf_chk.c
+++ b/debug/snprintf_chk.c
@@ -15,25 +15,29 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-___snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
const char *format, ...)
{
- va_list arg;
- int done;
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
- va_start (arg, format);
- done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
- va_end (arg);
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
- return done;
+ va_start (ap, format);
+ ret = __vsnprintf_internal (s, maxlen, format, ap, mode);
+ va_end (ap);
+
+ return ret;
}
ldbl_strong_alias (___snprintf_chk, __snprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
index 78214563dd..649e8ab4d5 100644
--- a/debug/sprintf_chk.c
+++ b/debug/sprintf_chk.c
@@ -15,22 +15,27 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libioP.h>
#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
+
/* Write formatted output into S, according to the format string FORMAT. */
-/* VARARGS4 */
int
-___sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
+___sprintf_chk (char *s, int flag, size_t slen, const char *format, ...)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
+
+ if (slen == 0)
+ __chk_fail ();
- va_start (arg, format);
- done = __vsprintf_chk (s, flags, slen, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vsprintf_internal (s, slen, format, ap, mode);
+ va_end (ap);
- return done;
+ return ret;
}
ldbl_strong_alias (___sprintf_chk, __sprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/swprintf_chk.c b/debug/swprintf_chk.c
index 35887e48e2..186c17751c 100644
--- a/debug/swprintf_chk.c
+++ b/debug/swprintf_chk.c
@@ -16,20 +16,27 @@
<http://www.gnu.org/licenses/>. */
#include <stdarg.h>
-#include <wchar.h>
+#include <libio/libioP.h>
-/* Write formatted output into S, according to the format string FORMAT. */
-/* VARARGS5 */
+
+/* Write formatted output into S, according to the format string FORMAT,
+ writing no more than MAXLEN characters. */
int
-__swprintf_chk (wchar_t *s, size_t n, int flag, size_t s_len,
+__swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
const wchar_t *format, ...)
{
- va_list arg;
- int done;
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+ va_list ap;
+ int ret;
- va_start (arg, format);
- done = __vswprintf_chk (s, n, flag, s_len, format, arg);
- va_end (arg);
+ va_start (ap, format);
+ ret = __vswprintf_internal (s, maxlen, format, ap, mode);
+ va_end (ap);
- return done;
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index dbfebff83f..f5975ea02a 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -24,72 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */
-#include <malloc.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
int
-__vasprintf_chk (char **result_ptr, int flags, const char *format,
- va_list args)
+__vasprintf_chk (char **result_ptr, int flag, const char *format, va_list ap)
{
- /* Initial size of the buffer to be used. Will be doubled each time an
- overflow occurs. */
- const size_t init_string_size = 100;
- char *string;
- _IO_strfile sf;
- int ret;
- size_t needed;
- size_t allocated;
- /* No need to clear the memory here (unlike for open_memstream) since
- we know we will never seek on the stream. */
- string = (char *) malloc (init_string_size);
- if (string == NULL)
- return -1;
-#ifdef _IO_MTSAFE_IO
- sf._sbf._f._lock = NULL;
-#endif
- _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, string, init_string_size, string);
- sf._sbf._f._flags &= ~_IO_USER_BUF;
- sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
- sf._s._free_buffer_unused = (_IO_free_type) free;
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- ret = __vfprintf_internal (&sf._sbf._f, format, args, 0);
- if (ret < 0)
- {
- free (sf._sbf._f._IO_buf_base);
- return ret;
- }
- /* Only use realloc if the size we need is of the same (binary)
- order of magnitude then the memory we allocated. */
- needed = sf._sbf._f._IO_write_ptr - sf._sbf._f._IO_write_base + 1;
- allocated = sf._sbf._f._IO_write_end - sf._sbf._f._IO_write_base;
- if ((allocated >> 1) <= needed)
- *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
- else
- {
- *result_ptr = (char *) malloc (needed);
- if (*result_ptr != NULL)
- {
- memcpy (*result_ptr, sf._sbf._f._IO_buf_base, needed - 1);
- free (sf._sbf._f._IO_buf_base);
- }
- else
- /* We have no choice, use the buffer we already have. */
- *result_ptr = (char *) realloc (sf._sbf._f._IO_buf_base, needed);
- }
- if (*result_ptr == NULL)
- *result_ptr = sf._sbf._f._IO_buf_base;
- (*result_ptr)[needed - 1] = '\0';
- return ret;
+ return __vasprintf_internal (result_ptr, format, ap, mode);
}
-libc_hidden_def (__vasprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index 4386127cfe..e04514e355 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -24,41 +24,14 @@
This exception applies to code released by its copyright holders
in files containing the exception. */
-#include <libioP.h>
-#include <stdio_ext.h>
+#include <libio/libioP.h>
int
-__vdprintf_chk (int d, int flags, const char *format, va_list arg)
+__vdprintf_chk (int d, int flag, const char *format, va_list ap)
{
- struct _IO_FILE_plus tmpfil;
- struct _IO_wide_data wd;
- int done;
-
-#ifdef _IO_MTSAFE_IO
- tmpfil.file._lock = NULL;
-#endif
- _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
- _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
- _IO_new_file_init_internal (&tmpfil);
- if (_IO_file_attach (&tmpfil.file, d) == NULL)
- {
- _IO_un_link (&tmpfil);
- return EOF;
- }
- tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
-
- _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
- _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
-
- _IO_FINISH (&tmpfil.file);
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- return done;
+ return __vdprintf_internal (d, format, ap, mode);
}
-libc_hidden_def (__vdprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
index 5babbf611e..44426e14fd 100644
--- a/debug/vfprintf_chk.c
+++ b/debug/vfprintf_chk.c
@@ -15,28 +15,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to FP from the format string FORMAT. */
int
___vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = vfprintf (fp, format, ap);
-
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return __vfprintf_internal (fp, format, ap, mode);
}
-ldbl_hidden_def (___vfprintf_chk, __vfprintf_chk)
ldbl_strong_alias (___vfprintf_chk, __vfprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c
index abf2bd6517..3aed308156 100644
--- a/debug/vfwprintf_chk.c
+++ b/debug/vfwprintf_chk.c
@@ -15,27 +15,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to FP from the format string FORMAT. */
int
__vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- _IO_acquire_lock_clear_flags2 (fp);
- if (flag > 0)
- fp->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfwprintf_internal (fp, format, ap, 0);
-
- if (flag > 0)
- fp->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (fp);
-
- return done;
+ return __vfwprintf_internal (fp, format, ap, mode);
}
-libc_hidden_def (__vfwprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/asprintf_chk.c b/debug/vobprintf_chk.c
similarity index 61%
copy from debug/asprintf_chk.c
copy to debug/vobprintf_chk.c
index 9cd4143f2e..bed2c98eac 100644
--- a/debug/asprintf_chk.c
+++ b/debug/vobprintf_chk.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Print output of stream to given obstack.
+ Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -15,22 +16,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libioP.h>
-#include <stdarg.h>
-#include <stdio.h>
+#include <libio/libioP.h>
-/* Write formatted output from FORMAT to a string which is
- allocated with malloc and stored in *STRING_PTR. */
int
-__asprintf_chk (char **result_ptr, int flags, const char *format, ...)
+__obstack_vprintf_chk (struct obstack *obstack, int flag, const char *format,
+ va_list ap)
{
- va_list arg;
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- va_start (arg, format);
- done = __vasprintf_chk (result_ptr, flags, format, arg);
- va_end (arg);
-
- return done;
+ return __obstack_vprintf_internal (obstack, format, ap, mode);
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
index b3b2c53df2..69fcb721ac 100644
--- a/debug/vprintf_chk.c
+++ b/debug/vprintf_chk.c
@@ -15,27 +15,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to stdout from the format string FORMAT. */
int
___vprintf_chk (int flag, const char *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = vfprintf (stdout, format, ap);
-
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return __vfprintf_internal (stdout, format, ap, mode);
}
ldbl_strong_alias (___vprintf_chk, __vprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index 95d286f416..666a83b701 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -15,56 +15,22 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
-extern const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden;
/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
- const char *format, va_list args)
+___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+ const char *format, va_list ap)
{
- /* XXX Maybe for less strict version do not fail immediately.
- Though, maxlen is supposed to be the size of buffer pointed
- to by s, so a conforming program can't pass such maxlen
- to *snprintf. */
if (__glibc_unlikely (slen < maxlen))
__chk_fail ();
- _IO_strnfile sf;
- int ret;
-#ifdef _IO_MTSAFE_IO
- sf.f._sbf._f._lock = NULL;
-#endif
-
- /* We need to handle the special case where MAXLEN is 0. Use the
- overflow buffer right from the start. */
- if (maxlen == 0)
- {
- s = sf.overflow_buf;
- maxlen = sizeof (sf.overflow_buf);
- }
-
- _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
- s[0] = '\0';
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
- ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0);
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
- *sf.f._sbf._f._IO_write_ptr = '\0';
- return ret;
+ return __vsnprintf_internal (s, maxlen, format, ap, mode);
}
-ldbl_hidden_def (___vsnprintf_chk, __vsnprintf_chk)
ldbl_strong_alias (___vsnprintf_chk, __vsnprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 53f07236ae..c1b1a8da4f 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -15,75 +15,20 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <stdio.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
-
-
-static int _IO_str_chk_overflow (FILE *fp, int c) __THROW;
-
-static int
-_IO_str_chk_overflow (FILE *fp, int c)
-{
- /* When we come to here this means the user supplied buffer is
- filled. */
- __chk_fail ();
-}
-
-
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
- JUMP_INIT_DUMMY,
- JUMP_INIT(finish, _IO_str_finish),
- JUMP_INIT(overflow, _IO_str_chk_overflow),
- JUMP_INIT(underflow, _IO_str_underflow),
- JUMP_INIT(uflow, _IO_default_uflow),
- JUMP_INIT(pbackfail, _IO_str_pbackfail),
- JUMP_INIT(xsputn, _IO_default_xsputn),
- JUMP_INIT(xsgetn, _IO_default_xsgetn),
- JUMP_INIT(seekoff, _IO_str_seekoff),
- JUMP_INIT(seekpos, _IO_default_seekpos),
- JUMP_INIT(setbuf, _IO_default_setbuf),
- JUMP_INIT(sync, _IO_default_sync),
- JUMP_INIT(doallocate, _IO_default_doallocate),
- JUMP_INIT(read, _IO_default_read),
- JUMP_INIT(write, _IO_default_write),
- JUMP_INIT(seek, _IO_default_seek),
- JUMP_INIT(close, _IO_default_close),
- JUMP_INIT(stat, _IO_default_stat),
- JUMP_INIT(showmanyc, _IO_default_showmanyc),
- JUMP_INIT(imbue, _IO_default_imbue)
-};
-
+#include <libio/libioP.h>
int
-___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
- va_list args)
+___vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+ va_list ap)
{
- _IO_strfile f;
- int ret;
-#ifdef _IO_MTSAFE_IO
- f._sbf._f._lock = NULL;
-#endif
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
if (slen == 0)
__chk_fail ();
- _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
- s[0] = '\0';
- _IO_str_init_static_internal (&f, s, slen - 1, s);
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
- can only come from read-only format strings. */
- if (flags > 0)
- f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- ret = __vfprintf_internal (&f._sbf._f, format, args, 0);
-
- *f._sbf._f._IO_write_ptr = '\0';
- return ret;
+ return __vsprintf_internal (s, slen, format, ap, mode);
}
ldbl_hidden_def (___vsprintf_chk, __vsprintf_chk)
ldbl_strong_alias (___vsprintf_chk, __vsprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 4d616f8835..2c6fadd463 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -15,60 +15,21 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
-#include "../libio/strfile.h"
+#include <libio/libioP.h>
/* Write formatted output into S, according to the format
string FORMAT, writing no more than MAXLEN characters. */
-/* VARARGS5 */
int
-__vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
- const wchar_t *format, va_list args)
+__vswprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
+ const wchar_t *format, va_list ap)
{
- /* XXX Maybe for less strict version do not fail immediately.
- Though, maxlen is supposed to be the size of buffer pointed
- to by s, so a conforming program can't pass such maxlen
- to *snprintf. */
if (__glibc_unlikely (slen < maxlen))
__chk_fail ();
- _IO_wstrnfile sf;
- struct _IO_wide_data wd;
- int ret;
-#ifdef _IO_MTSAFE_IO
- sf.f._sbf._f._lock = NULL;
-#endif
-
- /* We need to handle the special case where MAXLEN is 0. Use the
- overflow buffer right from the start. */
- if (__glibc_unlikely (maxlen == 0))
- /* Since we have to write at least the terminating L'\0' a buffer
- length of zero always makes the function fail. */
- return -1;
-
- _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
- _IO_fwide (&sf.f._sbf._f, 1);
- s[0] = L'\0';
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY;
-
- _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s);
- ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0);
-
- if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf)
- /* ISO C99 requires swprintf/vswprintf to return an error if the
- output does not fit int he provided buffer. */
- return -1;
-
- /* Terminate the string. */
- *sf.f._sbf._f._wide_data->_IO_write_ptr = '\0';
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- return ret;
+ return __vswprintf_internal (s, maxlen, format, ap, mode);
}
-libc_hidden_def (__vswprintf_chk)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c
index fedc7a46bf..f1e8878a54 100644
--- a/debug/vwprintf_chk.c
+++ b/debug/vwprintf_chk.c
@@ -15,27 +15,16 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to stdout from the format string FORMAT. */
int
__vwprintf_chk (int flag, const wchar_t *format, va_list ap)
{
- int done;
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfwprintf_internal (stdout, format, ap, 0);
-
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return __vfwprintf_internal (stdout, format, ap, mode);
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c
index 819050e5af..9f406e95f8 100644
--- a/debug/wprintf_chk.c
+++ b/debug/wprintf_chk.c
@@ -16,29 +16,22 @@
<http://www.gnu.org/licenses/>. */
#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "../libio/libioP.h"
+#include <libio/libioP.h>
/* Write formatted output to stdout from the format string FORMAT. */
int
__wprintf_chk (int flag, const wchar_t *format, ...)
{
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ can only come from read-only format strings. */
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
va_list ap;
- int done;
-
- _IO_acquire_lock_clear_flags2 (stdout);
- if (flag > 0)
- stdout->_flags2 |= _IO_FLAGS2_FORTIFY;
+ int ret;
va_start (ap, format);
- done = __vfwprintf_internal (stdout, format, ap, 0);
+ ret = __vfwprintf_internal (stdout, format, ap, mode);
va_end (ap);
- if (flag > 0)
- stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY;
- _IO_release_lock (stdout);
-
- return done;
+ return ret;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/include/stdio.h b/include/stdio.h
index 0856d729d9..1b7da0f74d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -216,11 +216,6 @@ libc_hidden_proto (__open_memstream)
libc_hidden_proto (__libc_fatal)
rtld_hidden_proto (__libc_fatal)
libc_hidden_proto (__vsprintf_chk)
-libc_hidden_proto (__vsnprintf_chk)
-libc_hidden_proto (__vfprintf_chk)
-libc_hidden_proto (__vasprintf_chk)
-libc_hidden_proto (__vdprintf_chk)
-libc_hidden_proto (__obstack_vprintf_chk)
extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
libc_hidden_proto (__fmemopen)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/include/wchar.h b/include/wchar.h
index d0fe45c3a6..86506d28e9 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -216,8 +216,6 @@ extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
const wchar_t *__restrict __format,
__gnuc_va_list __arg)
/* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
-libc_hidden_proto (__vfwprintf_chk)
-libc_hidden_proto (__vswprintf_chk)
extern int __isoc99_fwscanf (__FILE *__restrict __stream,
const wchar_t *__restrict __format, ...);
Ok.
Post by Gabriel F. T. Gomes
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 3b1e8292b5..08e4002625 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -27,8 +27,47 @@
#include "libioP.h"
#include "strfile.h"
+static int __THROW
+_IO_str_chk_overflow (FILE *fp, int c)
+{
+ /* If we get here, the user-supplied buffer would be overrun by
+ further output. */
+ __chk_fail ();
+}
+
+static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
+{
+ JUMP_INIT_DUMMY,
+ JUMP_INIT(finish, _IO_str_finish),
+ JUMP_INIT(overflow, _IO_str_chk_overflow),
+ JUMP_INIT(underflow, _IO_str_underflow),
+ JUMP_INIT(uflow, _IO_default_uflow),
+ JUMP_INIT(pbackfail, _IO_str_pbackfail),
+ JUMP_INIT(xsputn, _IO_default_xsputn),
+ JUMP_INIT(xsgetn, _IO_default_xsgetn),
+ JUMP_INIT(seekoff, _IO_str_seekoff),
+ JUMP_INIT(seekpos, _IO_default_seekpos),
+ JUMP_INIT(setbuf, _IO_default_setbuf),
+ JUMP_INIT(sync, _IO_default_sync),
+ JUMP_INIT(doallocate, _IO_default_doallocate),
+ JUMP_INIT(read, _IO_default_read),
+ JUMP_INIT(write, _IO_default_write),
+ JUMP_INIT(seek, _IO_default_seek),
+ JUMP_INIT(close, _IO_default_close),
+ JUMP_INIT(stat, _IO_default_stat),
+ JUMP_INIT(showmanyc, _IO_default_showmanyc),
+ JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+/* This function is called by regular vsprintf with maxlen set to -1,
+ and by vsprintf_chk with maxlen set to the size of the output
+ string. In the former case, _IO_str_chk_overflow will never be
+ called; in the latter case it will crash the program if the buffer
+ overflows. */
+
int
-__vsprintf_internal (char *string, const char *format, va_list args,
+__vsprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list args,
unsigned int mode_flags)
{
_IO_strfile sf;
@@ -38,17 +77,22 @@ __vsprintf_internal (char *string, const char *format, va_list args,
sf._sbf._f._lock = NULL;
#endif
_IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
- _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&sf, string, -1, string);
+ _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps;
+ string[0] = '\0';
+ _IO_str_init_static_internal (&sf, string,
+ (maxlen == -1) ? -1 : maxlen - 1,
+ string);
+
ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags);
- _IO_putc_unlocked ('\0', &sf._sbf._f);
+
+ *sf._sbf._f._IO_write_ptr = '\0';
return ret;
}
int
__vsprintf (char *string, const char *format, va_list args)
{
- return __vsprintf_internal (string, format, args, 0);
+ return __vsprintf_internal (string, -1, format, args, 0);
}
ldbl_strong_alias (__vsprintf, _IO_vsprintf)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/libio/libio.h b/libio/libio.h
index c188814ccc..3a93807efc 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -90,7 +90,6 @@ typedef union
/* Bits for the _flags2 field. */
#define _IO_FLAGS2_MMAP 1
#define _IO_FLAGS2_NOTCANCEL 2
-#define _IO_FLAGS2_FORTIFY 4
#define _IO_FLAGS2_USER_WBUF 8
#define _IO_FLAGS2_NOCLOSE 32
#define _IO_FLAGS2_CLOEXEC 64
Ok.
Post by Gabriel F. T. Gomes
diff --git a/libio/libioP.h b/libio/libioP.h
index fe52ef1752..ce5228e382 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -677,9 +677,16 @@ extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
va_list ap, unsigned int mode_flags)
attribute_hidden;
-extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+/* Note: __vsprintf_internal, unlike vsprintf, does take a maxlen argument,
+ because it's called by both vsprintf and vsprintf_chk. If maxlen is
+ not set to -1, overrunning the buffer will cause a prompt crash.
+ This is the behavior of ordinary (v)sprintf functions, thus they call
+ __vsprintf_internal with that argument set to -1. */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+ const char *format, va_list ap,
unsigned int mode_flags)
attribute_hidden;
+
extern int __vsnprintf_internal (char *string, size_t maxlen,
const char *format, va_list ap,
unsigned int mode_flags)
@@ -818,26 +825,10 @@ _IO_acquire_lock_fct (FILE **p)
_IO_funlockfile (fp);
}
-static inline void
-__attribute__ ((__always_inline__))
-_IO_acquire_lock_clear_flags2_fct (FILE **p)
-{
- FILE *fp = *p;
- fp->_flags2 &= ~(_IO_FLAGS2_FORTIFY);
- if ((fp->_flags & _IO_USER_LOCK) == 0)
- _IO_funlockfile (fp);
-}
-
#if !defined _IO_MTSAFE_IO && IS_IN (libc)
# define _IO_acquire_lock(_fp) \
- do { \
- FILE *_IO_acquire_lock_file = NULL
-# define _IO_acquire_lock_clear_flags2(_fp) \
- do { \
- FILE *_IO_acquire_lock_file = (_fp)
+ do {
# define _IO_release_lock(_fp) \
- if (_IO_acquire_lock_file != NULL) \
- _IO_acquire_lock_file->_flags2 &= ~(_IO_FLAGS2_FORTIFY); \
} while (0)
#endif
Ok.
Post by Gabriel F. T. Gomes
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
index 77423b292f..447faa4e25 100644
--- a/stdio-common/sprintf.c
+++ b/stdio-common/sprintf.c
@@ -27,7 +27,7 @@ __sprintf (char *s, const char *format, ...)
int done;
va_start (arg, format);
- done = __vsprintf_internal (s, format, arg, 0);
+ done = __vsprintf_internal (s, -1, format, arg, 0);
va_end (arg);
return done;
Ok.
Post by Gabriel F. T. Gomes
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index b0c86e99bd..4cc4261ead 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1283,8 +1283,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
/* Temporarily honor environmental settings. */
if (__ldbl_is_dbl)
mode_flags |= PRINTF_LDBL_IS_DBL;
- if (s->_flags2 & _IO_FLAGS2_FORTIFY)
- mode_flags |= PRINTF_FORTIFY;
/* Orient the stream. */
#ifdef ORIENT
Ok.
Post by Gabriel F. T. Gomes
diff --git a/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h
index 4a40618545..25ccd07f29 100644
--- a/sysdeps/generic/stdio-lock.h
+++ b/sysdeps/generic/stdio-lock.h
@@ -54,15 +54,8 @@ __libc_lock_define_recursive (typedef, _IO_lock_t)
__attribute__((cleanup (_IO_acquire_lock_fct))) \
= (_fp); \
_IO_flockfile (_IO_acquire_lock_file);
-# define _IO_acquire_lock_clear_flags2(_fp) \
- do { \
- FILE *_IO_acquire_lock_file \
- __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct))) \
- = (_fp); \
- _IO_flockfile (_IO_acquire_lock_file);
# else
# define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
# endif
# define _IO_release_lock(_fp) ; } while (0)
Ok.
Post by Gabriel F. T. Gomes
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 958bbc1834..59b2c9fcdd 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -179,7 +179,7 @@ __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
{
int done;
__no_long_double = 1;
- done = __vsprintf_internal (string, fmt, ap, 0);
+ done = __vsprintf_internal (string, -1, fmt, ap, 0);
__no_long_double = 0;
return done;
}
@@ -579,7 +579,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = __vfprintf_chk (s, flag, fmt, ap);
+ res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -591,7 +591,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
{
int res;
set_no_long_double ();
- res = __vfwprintf_chk (s, flag, fmt, ap);
+ res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -609,9 +609,13 @@ attribute_compat_text_section
__nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
const char *fmt, va_list ap)
{
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vsnprintf_chk (string, maxlen, flag, slen, fmt, ap);
+ res = __vsnprintf_internal (string, maxlen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -622,9 +626,13 @@ attribute_compat_text_section
__nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
va_list ap)
{
+ if (slen == 0)
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vsprintf_chk (string, flag, slen, fmt, ap);
+ res = __vsprintf_internal (string, slen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -635,9 +643,13 @@ attribute_compat_text_section
__nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
const wchar_t *fmt, va_list ap)
{
+ if (__glibc_unlikely (slen < maxlen))
+ __chk_fail ();
+
int res;
__no_long_double = 1;
- res = __vswprintf_chk (string, maxlen, flag, slen, fmt, ap);
+ res = __vswprintf_internal (string, maxlen, fmt, ap,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -670,7 +682,8 @@ __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
{
int res;
__no_long_double = 1;
- res = __vasprintf_chk (ptr, flag, fmt, arg);
+ res = __vasprintf_internal (ptr, fmt, arg,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
@@ -696,7 +709,7 @@ __nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
{
int res;
set_no_long_double ();
- res = __vdprintf_chk (d, flag, fmt, arg);
+ res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
return res;
}
@@ -723,7 +736,8 @@ __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
{
int res;
__no_long_double = 1;
- res = __obstack_vprintf_chk (obstack, flag, fmt, arg);
+ res = __obstack_vprintf_internal (obstack, fmt, arg,
+ (flag > 0) ? PRINTF_FORTIFY : 0);
__no_long_double = 0;
return res;
}
Ok.
Post by Gabriel F. T. Gomes
diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
index 5b9782452f..1d6a81c5bf 100644
--- a/sysdeps/nptl/stdio-lock.h
+++ b/sysdeps/nptl/stdio-lock.h
@@ -94,15 +94,8 @@ typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
__attribute__((cleanup (_IO_acquire_lock_fct))) \
= (_fp); \
_IO_flockfile (_IO_acquire_lock_file);
-# define _IO_acquire_lock_clear_flags2(_fp) \
- do { \
- FILE *_IO_acquire_lock_file \
- __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct))) \
- = (_fp); \
- _IO_flockfile (_IO_acquire_lock_file);
# else
# define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
-# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
# endif
# define _IO_release_lock(_fp) ; } while (0)
Ok.
Gabriel F. T. Gomes
2018-12-04 16:19:46 UTC
Permalink
Post by Adhemerval Zanella
I don't recall exactly which patch was the one that actually fixes BZ#11319,
my previous indication was 'Add __v*printf_internal with flags arguments.'.
Could you recheck it please?
Yes, sure. This patch fixes the bug, because of the following change...
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
-__vdprintf_chk (int d, int flags, const char *format, va_list arg)
+__vdprintf_chk (int d, int flag, const char *format, va_list ap)
{
- struct _IO_FILE_plus tmpfil;
- struct _IO_wide_data wd;
- int done;
-
-#ifdef _IO_MTSAFE_IO
- tmpfil.file._lock = NULL;
-#endif
- _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
- _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
- _IO_new_file_init_internal (&tmpfil);
- if (_IO_file_attach (&tmpfil.file, d) == NULL)
- {
- _IO_un_link (&tmpfil);
- return EOF;
- }
- tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
-
- _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
- _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
-
- _IO_FINISH (&tmpfil.file);
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- return done;
+ return __vdprintf_internal (d, format, ap, mode);
Notice that the call to __vfprintf_internal was replaced with a call to
__vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).

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

[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD
Adhemerval Zanella
2018-12-04 17:39:58 UTC
Permalink
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
I don't recall exactly which patch was the one that actually fixes BZ#11319,
my previous indication was 'Add __v*printf_internal with flags arguments.'.
Could you recheck it please?
Yes, sure. This patch fixes the bug, because of the following change...
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
int
-__vdprintf_chk (int d, int flags, const char *format, va_list arg)
+__vdprintf_chk (int d, int flag, const char *format, va_list ap)
{
- struct _IO_FILE_plus tmpfil;
- struct _IO_wide_data wd;
- int done;
-
-#ifdef _IO_MTSAFE_IO
- tmpfil.file._lock = NULL;
-#endif
- _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
- _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
- _IO_new_file_init_internal (&tmpfil);
- if (_IO_file_attach (&tmpfil.file, d) == NULL)
- {
- _IO_un_link (&tmpfil);
- return EOF;
- }
- tmpfil.file._flags |= _IO_DELETE_DONT_CLOSE;
-
- _IO_mask_flags (&tmpfil.file, _IO_NO_READS,
- _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
-
- /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+ /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
can only come from read-only format strings. */
- if (flags > 0)
- tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY;
-
- done = __vfprintf_internal (&tmpfil.file, format, arg, 0);
-
- _IO_FINISH (&tmpfil.file);
+ unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
- return done;
+ return __vdprintf_internal (d, format, ap, mode);
Notice that the call to __vfprintf_internal was replaced with a call to
__vdprintf_internal, which has the check for EOF (lines 55 and 56 [1]).
I wrote a test case to check this and I confirm that the problem is
reproducible without this patch, but not with it. (I'll clean the test up
and send to this list... Maybe it should get in to avoid regressions).
[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iovdprintf.c;h=78a3a2bd159bfc8020d970cecadeaca6e2312a7b;hb=HEAD
Thanks for confirm it, could you attach the add the testcase as well?
I would prefer to push along with the patch itself, and there is no need
to send a new version for the whole set. Just update this one.
Gabriel F. T. Gomes
2018-12-04 18:01:27 UTC
Permalink
Post by Adhemerval Zanella
Thanks for confirm it, could you attach the add the testcase as well?
I would prefer to push along with the patch itself, and there is no need
to send a new version for the whole set. Just update this one.
This is the patch (I hope my email client doesn't screw it)...


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

The commit

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

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

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

Tested for powerpc64le and x86_64.

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

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
tst-vfprintf-user-type \
tst-vfprintf-mbs-prec \
tst-scanf-round \
- tst-renameat2 \
+ tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \

test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble

@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
# tst-gets.c tests a deprecated function.
CFLAGS-tst-gets.c += -Wno-deprecated-declarations

+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
CPPFLAGS += $(libio-mtsafe)

$(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ int ret;
+ int fd = eventfd(0, 0);
+
+ /* man 2 eventfd:
+
+ A write(2) will fail with the error EINVAL if the size of the
+ supplied buffer is less than 8 bytes... */
+ ret = dprintf(fd, "%d", 0);
+
+ TEST_VERIFY (ret < 0);
+ TEST_COMPARE (errno, EINVAL);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.14.5
Adhemerval Zanella
2018-12-04 21:06:57 UTC
Permalink
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
Thanks for confirm it, could you attach the add the testcase as well?
I would prefer to push along with the patch itself, and there is no need
to send a new version for the whole set. Just update this one.
This is the patch (I hope my email client doesn't screw it)...
Thanks, below some comments about the regression test.
Post by Gabriel F. T. Gomes
From a583fded669048e7d58c760810e30758a5ede286 Mon Sep 17 00:00:00 2001
Date: Tue, 4 Dec 2018 15:57:57 -0200
Subject: [PATCH] Add test for bug 11319
The commit
commit 7ca890b88e6ab7624afb1742a9fffb37ad5b3fc3
Date: Wed Feb 24 16:07:57 2010 -0800
Fix reporting of I/O errors in *dprintf functions.
fixed bug 11319 for dprintf and vdprintf, however, it did not fix it for
__dprintf_chk and __vdprintf_chk. As a side-effect of the refactoring
of libio functions, this bug is also fixed for the foritified functions.
This patch adds a test case to avoid regressions.
Tested for powerpc64le and x86_64.
* stdio-common/Makefile (tests): Add tst-bz11319 and
tst-bz11319-fortify2.
(CFLAGS-tst-bz11319-fortify2.c): New macro.
* stdio-common/tst-bz11319-fortify2.c: New file.
* stdio-common/tst-bz11319.c: Likewise.
---
stdio-common/Makefile | 6 ++++-
stdio-common/tst-bz11319-fortify2.c | 1 +
stdio-common/tst-bz11319.c | 48 +++++++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+), 1 deletion(-)
create mode 100644 stdio-common/tst-bz11319-fortify2.c
create mode 100644 stdio-common/tst-bz11319.c
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
tst-vfprintf-user-type \
tst-vfprintf-mbs-prec \
tst-scanf-round \
- tst-renameat2 \
+ tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
# tst-gets.c tests a deprecated function.
CFLAGS-tst-gets.c += -Wno-deprecated-declarations
+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
CPPFLAGS += $(libio-mtsafe)
$(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1
Ok.
Post by Gabriel F. T. Gomes
diff --git a/stdio-common/tst-bz11319-fortify2.c b/stdio-common/tst-bz11319-fortify2.c
new file mode 100644
index 0000000000..a8df9a39bd
--- /dev/null
+++ b/stdio-common/tst-bz11319-fortify2.c
@@ -0,0 +1 @@
+#include <tst-bz11319.c>
diff --git a/stdio-common/tst-bz11319.c b/stdio-common/tst-bz11319.c
new file mode 100644
index 0000000000..ce2dee13ae
--- /dev/null
+++ b/stdio-common/tst-bz11319.c
@@ -0,0 +1,48 @@
+/* Regression test for bug 11319.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
I think we can define it regardless
Post by Gabriel F. T. Gomes
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
eventfd is Linux specific, so either we need to move this test to Linux
sysdeps or use a platform neutral way to stress this issue.
Post by Gabriel F. T. Gomes
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ int ret;
+ int fd = eventfd(0, 0);
To stress this issue we just need a valid file descriptor that is seekable
but fail on a write. Just use a temporary file opened in read-only mode.
Post by Gabriel F. T. Gomes
+
+
+ A write(2) will fail with the error EINVAL if the size of the
+ supplied buffer is less than 8 bytes... */
+ ret = dprintf(fd, "%d", 0);
+
+ TEST_VERIFY (ret < 0);
+ TEST_COMPARE (errno, EINVAL);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
Gabriel F. T. Gomes
2018-12-05 16:53:37 UTC
Permalink
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
I think we can define it regardless
OK.
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/eventfd.h>
eventfd is Linux specific, so either we need to move this test to Linux
sysdeps or use a platform neutral way to stress this issue.
Oh, indeed.
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ int ret;
+ int fd = eventfd(0, 0);
To stress this issue we just need a valid file descriptor that is seekable
but fail on a write. Just use a temporary file opened in read-only mode.
Does the following patch look better (thanks for the suggestion)?

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

The commit

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

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

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

Tested for powerpc64le and x86_64.

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

diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 84bad1fafe..8978b3fb1f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -64,7 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
tst-vfprintf-user-type \
tst-vfprintf-mbs-prec \
tst-scanf-round \
- tst-renameat2 \
+ tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \

test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble

@@ -164,6 +164,10 @@ CFLAGS-test_rdwr.c += -DOBJPFX=\"$(objpfx)\"
# tst-gets.c tests a deprecated function.
CFLAGS-tst-gets.c += -Wno-deprecated-declarations

+# BZ #11319 was first fixed for regular vdprintf, then reopened because
+# the fortified version had the same bug.
+CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2
+
CPPFLAGS += $(libio-mtsafe)

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

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

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

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

xclose (fd);
free (tempfile);

return 0;
}
Post by Gabriel F. T. Gomes
+
+ return 0;
+}
+
+#include <support/test-driver.c>
Gabriel F. T. Gomes
2018-12-05 19:11:54 UTC
Permalink
Post by Adhemerval Zanella
For a lack of a better interface (to create/open read-only temporary files
static int
do_test (void)
{
char *tempfile;
int fd;
/* Create a temporary file and open it in read-only mode. */
TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
fd = xopen (tempfile, O_RDONLY, 0660);
/* Try and write to the temporary file to intentionally fail, then
check that dprintf (or __dprintf_chk) return EOF. */
TEST_COMPARE (dprintf (fd, "%d", 0), EOF);
xclose (fd);
free (tempfile);
return 0;
}
Looks good to me. Should I post an updated version, or is it OK with the
suggested changes?
Adhemerval Zanella
2018-12-05 19:18:22 UTC
Permalink
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
For a lack of a better interface (to create/open read-only temporary files
static int
do_test (void)
{
char *tempfile;
int fd;
/* Create a temporary file and open it in read-only mode. */
TEST_VERIFY_EXIT (create_temp_file ("tst-bz11319", &tempfile));
fd = xopen (tempfile, O_RDONLY, 0660);
/* Try and write to the temporary file to intentionally fail, then
check that dprintf (or __dprintf_chk) return EOF. */
TEST_COMPARE (dprintf (fd, "%d", 0), EOF);
xclose (fd);
free (tempfile);
return 0;
}
Looks good to me. Should I post an updated version, or is it OK with the
suggested changes?
I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.
Gabriel F. T. Gomes
2018-12-05 19:27:07 UTC
Permalink
Post by Adhemerval Zanella
I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.
Oh, I see. Then I'll send it again, because I need to update the commit
message and ChangeLog.
Adhemerval Zanella
2018-12-05 19:35:17 UTC
Permalink
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.
Oh, I see. Then I'll send it again, because I need to update the commit
message and ChangeLog.
Alright.
Gabriel F. T. Gomes
2018-12-05 20:07:12 UTC
Permalink
Post by Adhemerval Zanella
Post by Gabriel F. T. Gomes
Post by Adhemerval Zanella
I would suggest you to integrate it on the patch which fixes BZ#11319
and from my side you don't need to send an update version.
Oh, I see. Then I'll send it again, because I need to update the commit
message and ChangeLog.
Alright.
Hrm, I thought I would have to rewrite the messages (and that I would be
doubtful about it), but it turned out to be mostly copy-and-paste. So,
I'll go ahead and push the changes.

Thanks again and sorry about the noise. :)
Gabriel F. T. Gomes
2018-11-15 21:44:47 UTC
Permalink
From: Zack Weinberg <***@panix.com>

Changes since v2

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

Changed since v1:

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

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

Tested for powerpc and powerpc64le.

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

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

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

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

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

diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 3be3189ed1..89d3479ebc 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -1,11 +1,16 @@
+#ifndef _LIBC_SYS_SYSLOG_H
+#define _LIBC_SYS_SYSLOG_H 1
#include <misc/sys/syslog.h>
-
#ifndef _ISOMAC
+
libc_hidden_proto (syslog)
-libc_hidden_proto (vsyslog)

-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
- __gnuc_va_list __ap)
- __attribute__ ((__format__ (__printf__, 3, 0)));
-libc_hidden_proto (__vsyslog_chk)
-#endif
+/* __vsyslog_internal uses the same mode_flags bits as
+ __v*printf_internal; see libio/libioP.h. */
+extern void __vsyslog_internal (int pri, const char *fmt, __gnuc_va_list ap,
+ unsigned int mode_flags)
+ attribute_hidden
+ __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#endif /* _ISOMAC */
+#endif /* syslog.h */
diff --git a/misc/syslog.c b/misc/syslog.c
index 644dbe80ec..3a15da41ce 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -53,7 +53,7 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94";

#include <stdarg.h>

-#include <libio/iolibio.h>
+#include <libio/libioP.h>
#include <math_ldbl_opt.h>

#include <kernel-features.h>
@@ -114,24 +114,38 @@ __syslog(int pri, const char *fmt, ...)
va_list ap;

va_start(ap, fmt);
- __vsyslog_chk(pri, -1, fmt, ap);
+ __vsyslog_internal(pri, fmt, ap, 0);
va_end(ap);
}
ldbl_hidden_def (__syslog, syslog)
ldbl_strong_alias (__syslog, syslog)

+void
+__vsyslog(int pri, const char *fmt, va_list ap)
+{
+ __vsyslog_internal(pri, fmt, ap, 0);
+}
+ldbl_weak_alias (__vsyslog, vsyslog)
+
void
__syslog_chk(int pri, int flag, const char *fmt, ...)
{
va_list ap;

va_start(ap, fmt);
- __vsyslog_chk(pri, flag, fmt, ap);
+ __vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
va_end(ap);
}

void
__vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
+{
+ __vsyslog_internal(pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
+}
+
+void
+__vsyslog_internal(int pri, const char *fmt, va_list ap,
+ unsigned int mode_flags)
{
struct tm now_tm;
time_t now;
@@ -215,11 +229,8 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
__set_errno (saved_errno);

/* We have the header. Print the user's format into the
- buffer. */
- if (flag == -1)
- vfprintf (f, fmt, ap);
- else
- __vfprintf_chk (f, flag, fmt, ap);
+ buffer. */
+ __vfprintf_internal (f, fmt, ap, mode_flags);

/* Close the memory stream; this will finalize the data
into a malloc'd buffer in BUF. */
@@ -316,15 +327,6 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
if (buf != failbuf)
free (buf);
}
-libc_hidden_def (__vsyslog_chk)
-
-void
-__vsyslog(int pri, const char *fmt, va_list ap)
-{
- __vsyslog_chk (pri, -1, fmt, ap);
-}
-ldbl_hidden_def (__vsyslog, vsyslog)
-ldbl_weak_alias (__vsyslog, vsyslog)

static struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */

diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index bda84af0bb..958bbc1834 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -843,7 +843,7 @@ attribute_compat_text_section
__nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
{
set_no_long_double ();
- __vsyslog_chk (pri, flag, fmt, ap);
+ __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
clear_no_long_double ();
}
libc_hidden_def (__nldbl___vsyslog_chk)
--
2.14.5
Adhemerval Zanella
2018-11-22 18:00:32 UTC
Permalink
Post by Gabriel F. T. Gomes
Changes since v2
- None, but dependent on previous patch in the set, thus resending.
LGTM.
Post by Gabriel F. T. Gomes
- Fixed white-space errors.
- Removed internal declaration of __vsyslog_chk, because it's no
longer called from within libc. There's a call to it in the inline
definition of vsyslog in bits/syslog.h, but that definition is only
#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
- Removed libc_hidden_def and libc_hidden_proto for vsyslog, as it is
never called internally (it never was).
- Added attribute_hidden to the internal declaration of
__vsyslog_internal. Here are the objdumps of one internal call,
fc790: 94 21 ff f0 stwu r1,-16(r1)
fc794: 38 c0 00 00 li r6,0
fc798: 7c 08 02 a6 mflr r0
fc7a0: 93 c1 00 08 stw r30,8(r1)
fc7a4: 90 01 00 14 stw r0,20(r1)
fc7a8: 7f c8 02 a6 mflr r30
fc7ac: 3f de 00 0a addis r30,r30,10
fc7b0: 3b de 38 54 addi r30,r30,14420
fc7b4: 4b ff f9 9d bl fc150 <__vsyslog_internal>
fc7b8: 80 01 00 14 lwz r0,20(r1)
fc7bc: 83 c1 00 08 lwz r30,8(r1)
fc7c0: 38 21 00 10 addi r1,r1,16
fc7c4: 7c 08 03 a6 mtlr r0
fc7c8: 4e 80 00 20 blr
fc7cc: 60 00 00 00 nop
fc780: 38 c0 00 00 li r6,0
fc784: 4b ff f9 cc b fc150 <__vsyslog_internal>
fc788: 60 00 00 00 nop
fc78c: 60 00 00 00 nop
-- 8< --
__nldbl___vsyslog_chk will ultimately want to pass PRINTF_LDBL_IS_DBL
down to __vfprintf_internal *as well as* possibly setting PRINTF_FORTIFY.
To make that possible, we need a __vsyslog_internal that takes the
same flags as printf. The code in misc/syslog.c does also get a
little simpler.
Tested for powerpc and powerpc64le.
* misc/syslog.c: Include libioP.h, not iolibio.h.
(__vsyslog_internal): New function with the former body of
__vsyslog_chk; takes mode_flags argument same as
__v*printf_internal. Call __vfprintf_internal directly.
(__vsyslog_chk): Now a wrapper around __vsyslog_internal.
Remove libc_hidden_def.
(__syslog, __syslog_chk): Use __vsy