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


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

GNU C Library master sources branch gabriel/powerpc-ieee128-printscan created. glibc-2.28.9000-82-g2c6fc6c


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, gabriel/powerpc-ieee128-printscan has been created
        at  2c6fc6c7c753fef4f4e0b09567e49063cf65698b (commit)

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2c6fc6c7c753fef4f4e0b09567e49063cf65698b

commit 2c6fc6c7c753fef4f4e0b09567e49063cf65698b
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon Jun 4 16:33:57 2018 -0300

    [TEMP] powerpc64le: Convert default long double format to IEEE binary128
    
    Do not commit!
    
    A commit similar to this would be added only when all other changes are
    ready, but without the temporary header redirections (explained below).
    This commit is provided in a personal branch to help other developers
    test the branch.
    
      A note about temporary header redirections:
    
      On powerpc64le, the implementation of long double with IEEE binary128
      format is not complete.  The redirections of the stdio.h, stdlib.h,
      argp.h, err.h, and error.h functions are supposed to be reused from
      bits/stdio-ldbl.h, etc., by changing the definition of
      __LDBL_REDIR_DECL based on the value of __HAVE_FLOAT128_UNLIKE_LDBL.
    
      However, we can only redirect all or none.  In the meantime,
      bits/stdio-ieee128.h, etc. allows us to redirect part of them for
      testing purposes.

diff --git a/argp/argp.h b/argp/argp.h
index fd2b20d..81b8024 100644
--- a/argp/argp.h
+++ b/argp/argp.h
@@ -558,6 +558,16 @@ __NTH (__option_is_end (const struct argp_option *__opt))
 # include <bits/argp-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the argp.h functions
+   are temporarily implemented in bits/argp-ieee128.h.  */
+#include <bits/floatn.h>
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/argp-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif /* argp.h */
diff --git a/libio/stdio.h b/libio/stdio.h
index 739e086..9e7dc38 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -399,9 +399,11 @@ extern int scanf (const char *__restrict __format, ...) __wur;
 extern int sscanf (const char *__restrict __s,
 		   const char *__restrict __format, ...) __THROW;
 
+#include <bits/floatn.h>
 #if defined __USE_ISOC99 && !defined __USE_GNU \
     && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
-    && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+    && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K) \
+    && (!__LONG_DOUBLE_USES_FLOAT128)
 # ifdef __REDIRECT
 /* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
    GNU extension which conflicts with valid %a followed by letter
@@ -449,7 +451,8 @@ extern int vsscanf (const char *__restrict __s,
 
 # if !defined __USE_GNU \
      && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
-     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K) \
+     && (!__LONG_DOUBLE_USES_FLOAT128)
 #  ifdef __REDIRECT
 /* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
    GNU extension which conflicts with valid %a followed by letter
@@ -876,6 +879,17 @@ extern int __overflow (FILE *, int);
 # include <bits/stdio-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the stdio.h functions
+   are supposed to be implemented in bits/stdio-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/stdio-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/stdio-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif /* <stdio.h> included.  */
diff --git a/misc/err.h b/misc/err.h
index f2d4bef..1f852f2 100644
--- a/misc/err.h
+++ b/misc/err.h
@@ -58,4 +58,16 @@ extern void verrx (int __status, const char *, __gnuc_va_list)
 
 __END_DECLS
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the err.h functions
+   are temporarily implemented in bits/err-ieee128.h.  */
+#include <bits/floatn.h>
+#if __HAVE_DISTINCT_FLOAT128 && __LDBL_MANT_DIG__ == 113 && \
+    ! defined __BUILDING_EXTRA_LDBL_FORMAT
+# include <bits/err-ieee128.h>
+#endif
+
+
 #endif	/* err.h */
diff --git a/misc/error.h b/misc/error.h
index ac0c586..ef1651a 100644
--- a/misc/error.h
+++ b/misc/error.h
@@ -49,10 +49,23 @@ extern int error_one_per_line;
 
 #ifdef __LDBL_COMPAT
 # include <bits/error-ldbl.h>
-#else
+#endif
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the error.h functions
+   are temporarily implemented in bits/error-ieee128.h.  */
+#include <bits/floatn.h>
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/error-ieee128.h>
+#endif
+
 /* Do not inline error and error_at_line when long double has the same
-   size of double, because that would invalidate the redirections to the
+   size of double, nor when long double reuses the float128
+   implementation, because that would invalidate the redirections to the
    compatibility functions.  */
+#if !defined __LDBL_COMPAT && !__LONG_DOUBLE_USES_FLOAT128
 # if defined __extern_always_inline && defined __va_arg_pack
 #  include <bits/error.h>
 # endif
diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h
index ee01478..fc3e62e 100644
--- a/misc/sys/syslog.h
+++ b/misc/sys/syslog.h
@@ -210,6 +210,17 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
 # include <bits/syslog-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the syslog.h functions
+   are supposed to be implemented in bits/syslog-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/syslog-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/syslog-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif /* sys/syslog.h */
diff --git a/stdio-common/printf.h b/stdio-common/printf.h
index 06d6743..0aefa74 100644
--- a/stdio-common/printf.h
+++ b/stdio-common/printf.h
@@ -186,6 +186,17 @@ extern int printf_size_info (const struct printf_info *__restrict
 # include <bits/printf-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the printf.h functions
+   are supposed to be implemented in bits/printf-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/printf-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/printf-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif /* printf.h  */
diff --git a/stdlib/monetary.h b/stdlib/monetary.h
index 6da5712..bf78513 100644
--- a/stdlib/monetary.h
+++ b/stdlib/monetary.h
@@ -54,6 +54,17 @@ extern ssize_t strfmon_l (char *__restrict __s, size_t __maxsize,
 # include <bits/monetary-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the monetary.h functions
+   are supposed to be implemented in bits/monetary-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/monetary-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/monetary-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif	/* monetary.h */
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/argp-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/argp-ieee128.h
new file mode 100644
index 0000000..4747199
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/argp-ieee128.h
@@ -0,0 +1,34 @@
+/* Redirections for argp functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the argp.h functions
+   are temporarily implemented in bits/argp-ieee128.h.  */
+
+#ifndef _ARGP_H
+# error "Never include <bits/argp-ibm128.h> directly; use <argp.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (argp_error)
+__IEEE128_REDIR (argp_failure)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/err-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/err-ieee128.h
new file mode 100644
index 0000000..de13c0f
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/err-ieee128.h
@@ -0,0 +1,40 @@
+/* Redirections for err functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the err.h functions
+   are temporarily implemented in bits/err-ieee128.h.  */
+
+#ifndef _ERR_H
+# error "Never include <bits/err-ieee128.h> directly; use <err.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (warn)
+__IEEE128_REDIR (warnx)
+__IEEE128_REDIR (vwarn)
+__IEEE128_REDIR (vwarnx)
+__IEEE128_REDIR (err)
+__IEEE128_REDIR (errx)
+__IEEE128_REDIR (verr)
+__IEEE128_REDIR (verrx)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/error-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/error-ieee128.h
new file mode 100644
index 0000000..596a889
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/error-ieee128.h
@@ -0,0 +1,34 @@
+/* Redirections for error functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the err.h functions
+   are temporarily implemented in bits/err-ieee128.h.  */
+
+#ifndef _ERROR_H
+# error "Never include <bits/error-ieee128.h> directly; use <error.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (error)
+__IEEE128_REDIR (error_at_line)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/long-double.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/long-double.h
new file mode 100644
index 0000000..32452b6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/long-double.h
@@ -0,0 +1,25 @@
+/* Properties of long double type.  ldbl-opt version.
+   Copyright (C) 2016-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  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 __NO_LONG_DOUBLE_MATH
+# define __LONG_DOUBLE_MATH_OPTIONAL	1
+# ifndef __LONG_DOUBLE_128__
+#  define __NO_LONG_DOUBLE_MATH		1
+# endif
+#endif
+#define __LONG_DOUBLE_USES_FLOAT128 (__LDBL_MANT_DIG__ == 113)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/monetary-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/monetary-ieee128.h
new file mode 100644
index 0000000..a620b05
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/monetary-ieee128.h
@@ -0,0 +1,43 @@
+/* Redirections for monetary functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the monetary.h functions
+   are supposed to be implemented in bits/monetary-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/monetary-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+
+#ifndef _MONETARY_H
+# error "Never include <bits/monetary-ieee128.h> directly; use <monetary.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+#define __IEEE128_REDIR_CUSTOM(name, custom) \
+  extern __typeof (name) custom; \
+  extern __typeof (name) name __asm (__ASMNAME (#custom));
+
+__IEEE128_REDIR (strfmon)
+
+#ifdef __USE_GNU
+__IEEE128_REDIR_CUSTOM (strfmon_l, __strfmonieee128_l)
+#endif
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/printf-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/printf-ieee128.h
new file mode 100644
index 0000000..0f07cc9
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/printf-ieee128.h
@@ -0,0 +1,35 @@
+/* Redirections for printf functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the printf.h functions
+   are supposed to be implemented in bits/printf-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/printf-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+
+#ifndef _PRINTF_H
+# error "Never include <bits/printf-ldbl.h> directly; use <printf.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (printf_size)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/stdio-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/stdio-ieee128.h
new file mode 100644
index 0000000..9bb04df
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/stdio-ieee128.h
@@ -0,0 +1,115 @@
+/* Redirections for stdio functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the stdio.h functions
+   are supposed to be implemented in bits/stdio-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/stdio-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+
+#ifndef _STDIO_H
+# error "Never include <bits/stdio-ieee128.h> directly; use <stdio.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+#define __IEEE128_REDIR_CUSTOM(name, custom) \
+  extern __typeof (name) custom; \
+  extern __typeof (name) name __asm (__ASMNAME (#custom));
+
+#define __IEEE128_REDIR_PREFIX(name) \
+  extern __typeof (__##name) __##name##ieee128; \
+  extern __typeof (__##name) __##name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (fprintf)
+__IEEE128_REDIR (printf)
+__IEEE128_REDIR (sprintf)
+__IEEE128_REDIR (vfprintf)
+__IEEE128_REDIR (vprintf)
+__IEEE128_REDIR (vsprintf)
+#if defined __USE_ISOC99 && !defined __USE_GNU \
+    && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+__IEEE128_REDIR_CUSTOM (fscanf, __isoc99_fscanfieee128)
+__IEEE128_REDIR_CUSTOM (scanf, __isoc99_scanfieee128)
+__IEEE128_REDIR_CUSTOM (sscanf, __isoc99_sscanfieee128)
+#else
+__IEEE128_REDIR (fscanf)
+__IEEE128_REDIR (scanf)
+__IEEE128_REDIR (sscanf)
+#endif
+
+#if defined __USE_ISOC99 || defined __USE_UNIX98
+__IEEE128_REDIR (snprintf)
+__IEEE128_REDIR (vsnprintf)
+#endif
+
+#ifdef	__USE_ISOC99
+# if !defined __USE_GNU \
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+__IEEE128_REDIR_CUSTOM (vfscanf, __isoc99_vfscanfieee128)
+__IEEE128_REDIR_CUSTOM (vscanf, __isoc99_vscanfieee128)
+__IEEE128_REDIR_CUSTOM (vsscanf, __isoc99_vsscanfieee128)
+# else
+__IEEE128_REDIR (vfscanf)
+__IEEE128_REDIR (vsscanf)
+__IEEE128_REDIR (vscanf)
+# endif
+#endif
+
+#ifdef __USE_XOPEN2K8
+__IEEE128_REDIR (vdprintf)
+__IEEE128_REDIR (dprintf)
+#endif
+
+#ifdef __USE_GNU
+__IEEE128_REDIR (vasprintf)
+__IEEE128_REDIR_PREFIX (asprintf)
+__IEEE128_REDIR (asprintf)
+__IEEE128_REDIR (obstack_printf)
+__IEEE128_REDIR (obstack_vprintf)
+#endif
+
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+__IEEE128_REDIR_PREFIX (sprintf_chk)
+__IEEE128_REDIR_PREFIX (vsprintf_chk)
+# if defined __USE_ISOC99 || defined __USE_UNIX98
+__IEEE128_REDIR_PREFIX (snprintf_chk)
+__IEEE128_REDIR_PREFIX (vsnprintf_chk)
+# endif
+# if __USE_FORTIFY_LEVEL > 1
+__IEEE128_REDIR_PREFIX (fprintf_chk)
+__IEEE128_REDIR_PREFIX (printf_chk)
+__IEEE128_REDIR_PREFIX (vfprintf_chk)
+__IEEE128_REDIR_PREFIX (vprintf_chk)
+#  ifdef __USE_XOPEN2K8
+__IEEE128_REDIR_PREFIX (dprintf_chk)
+__IEEE128_REDIR_PREFIX (vdprintf_chk)
+#  endif
+#  ifdef __USE_GNU
+__IEEE128_REDIR_PREFIX (asprintf_chk)
+__IEEE128_REDIR_PREFIX (vasprintf_chk)
+__IEEE128_REDIR_PREFIX (obstack_printf_chk)
+__IEEE128_REDIR_PREFIX (obstack_vprintf_chk)
+#  endif
+# endif
+#endif
+/* To be completed with the other functions.  */
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/syslog-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/syslog-ieee128.h
new file mode 100644
index 0000000..641aa15
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/syslog-ieee128.h
@@ -0,0 +1,51 @@
+/* Redirections for syslog functions for -mabi=ieeelongdouble.
+   Copyright (C) 2006-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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the syslog.h functions
+   are supposed to be implemented in bits/syslog-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/syslog-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+
+#ifndef _SYS_SYSLOG_H
+# error "Never include <bits/syslog-ieee128.h> directly; use <sys/syslog.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+#define __IEEE128_REDIR_PREFIX(name) \
+  extern __typeof (__##name) __##name##ieee128; \
+  extern __typeof (__##name) __##name __asm (__ASMNAME ("__" #name "ieee128"));
+
+__IEEE128_REDIR (syslog)
+
+#ifdef __USE_MISC
+__IEEE128_REDIR (vsyslog)
+#endif
+
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+__IEEE128_REDIR_PREFIX (syslog_chk)
+
+# ifdef __USE_MISC
+__IEEE128_REDIR_PREFIX (vsyslog_chk)
+# endif
+#endif
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/bits/wchar-ieee128.h b/sysdeps/ieee754/ldbl-128ibm-compat/bits/wchar-ieee128.h
new file mode 100644
index 0000000..0e39c68
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/bits/wchar-ieee128.h
@@ -0,0 +1,93 @@
+/* Redirections for stdio functions for -mabi=ieeelongdouble.
+   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/>.  */
+
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the wchar.h functions
+   are supposed to be implemented in bits/wchar-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/wchar-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+
+#ifndef _WCHAR_H
+# error "Never include <bits/wchar-ieee128.h> directly; use <wchar.h> instead."
+#endif
+
+#define __IEEE128_REDIR(name) \
+  extern __typeof (name) __##name##ieee128; \
+  extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128"));
+
+#define __IEEE128_REDIR_CUSTOM(name, custom) \
+  extern __typeof (name) custom; \
+  extern __typeof (name) name __asm (__ASMNAME (#custom));
+
+#define __IEEE128_REDIR_PREFIX(name) \
+  extern __typeof (__##name) __##name##ieee128; \
+  extern __typeof (__##name) __##name __asm (__ASMNAME ("__" #name "ieee128"));
+
+#if defined __USE_ISOC95 || defined __USE_UNIX98
+__IEEE128_REDIR (fwprintf);
+__IEEE128_REDIR (wprintf);
+__IEEE128_REDIR (swprintf);
+__IEEE128_REDIR (vfwprintf);
+__IEEE128_REDIR (vwprintf);
+__IEEE128_REDIR (vswprintf);
+# if defined __USE_ISOC99 && !defined __USE_GNU \
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+__IEEE128_REDIR_CUSTOM (fwscanf, __isoc99_fwscanfieee128)
+__IEEE128_REDIR_CUSTOM (wscanf, __isoc99_wscanfieee128)
+__IEEE128_REDIR_CUSTOM (swscanf, __isoc99_swscanfieee128)
+# else
+__IEEE128_REDIR (fwscanf);
+__IEEE128_REDIR (wscanf);
+__IEEE128_REDIR (swscanf);
+# endif
+#endif
+
+#ifdef __USE_ISOC99
+#if 0
+__IEEE128_REDIR_CUSTOM (wcstold, wcstod);
+#endif
+# if !defined __USE_GNU \
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+__IEEE128_REDIR_CUSTOM (vfwscanf, __isoc99_vfwscanfieee128)
+__IEEE128_REDIR_CUSTOM (vwscanf, __isoc99_vwscanfieee128)
+__IEEE128_REDIR_CUSTOM (vswscanf, __isoc99_vswscanfieee128)
+# else
+__IEEE128_REDIR (vfwscanf);
+__IEEE128_REDIR (vwscanf);
+__IEEE128_REDIR (vswscanf);
+# endif
+#endif
+
+#if 0
+#ifdef __USE_GNU
+__IEEE128_REDIR_CUSTOM (wcstold_l, wcstod_l);
+#endif
+#endif
+
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+__IEEE128_REDIR_PREFIX (swprintf_chk)
+__IEEE128_REDIR_PREFIX (vswprintf_chk)
+# if __USE_FORTIFY_LEVEL > 1
+__IEEE128_REDIR_PREFIX (fwprintf_chk)
+__IEEE128_REDIR_PREFIX (wprintf_chk)
+__IEEE128_REDIR_PREFIX (vfwprintf_chk)
+__IEEE128_REDIR_PREFIX (vwprintf_chk)
+# endif
+#endif
diff --git a/sysdeps/powerpc/powerpc64/le/Implies-before b/sysdeps/powerpc/powerpc64/le/Implies-before
index 7c20db4..2139f4d 100644
--- a/sysdeps/powerpc/powerpc64/le/Implies-before
+++ b/sysdeps/powerpc/powerpc64/le/Implies-before
@@ -1,4 +1,5 @@
 # On PowerPC we use the IBM extended long double format.
+ieee754/ldbl-128ibm-compat
 ieee754/ldbl-128ibm
 ieee754/ldbl-opt
 ieee754/dbl-64
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index b0d22eb..4c385ca 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2228,6 +2228,89 @@ GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.28 __argp_errorieee128 F
+GLIBC_2.28 __argp_failureieee128 F
+GLIBC_2.28 __asprintf_chkieee128 F
+GLIBC_2.28 __asprintfieee128 F
+GLIBC_2.28 __dprintf_chkieee128 F
+GLIBC_2.28 __dprintfieee128 F
+GLIBC_2.28 __errieee128 F
+GLIBC_2.28 __error_at_lineieee128 F
+GLIBC_2.28 __errorieee128 F
+GLIBC_2.28 __errxieee128 F
+GLIBC_2.28 __fprintf_chkieee128 F
+GLIBC_2.28 __fprintfieee128 F
+GLIBC_2.28 __fscanfieee128 F
+GLIBC_2.28 __fwprintf_chkieee128 F
+GLIBC_2.28 __fwprintfieee128 F
+GLIBC_2.28 __fwscanfieee128 F
+GLIBC_2.28 __isoc99_fscanfieee128 F
+GLIBC_2.28 __isoc99_fwscanfieee128 F
+GLIBC_2.28 __isoc99_scanfieee128 F
+GLIBC_2.28 __isoc99_sscanfieee128 F
+GLIBC_2.28 __isoc99_swscanfieee128 F
+GLIBC_2.28 __isoc99_vfscanfieee128 F
+GLIBC_2.28 __isoc99_vfwscanfieee128 F
+GLIBC_2.28 __isoc99_vscanfieee128 F
+GLIBC_2.28 __isoc99_vsscanfieee128 F
+GLIBC_2.28 __isoc99_vswscanfieee128 F
+GLIBC_2.28 __isoc99_vwscanfieee128 F
+GLIBC_2.28 __isoc99_wscanfieee128 F
+GLIBC_2.28 __obstack_printf_chkieee128 F
+GLIBC_2.28 __obstack_printfieee128 F
+GLIBC_2.28 __obstack_vprintf_chkieee128 F
+GLIBC_2.28 __obstack_vprintfieee128 F
+GLIBC_2.28 __printf_chkieee128 F
+GLIBC_2.28 __printf_sizeieee128 F
+GLIBC_2.28 __printfieee128 F
+GLIBC_2.28 __scanfieee128 F
+GLIBC_2.28 __snprintf_chkieee128 F
+GLIBC_2.28 __snprintfieee128 F
+GLIBC_2.28 __sprintf_chkieee128 F
+GLIBC_2.28 __sprintfieee128 F
+GLIBC_2.28 __sscanfieee128 F
+GLIBC_2.28 __strfmonieee128 F
+GLIBC_2.28 __strfmonieee128_l F
+GLIBC_2.28 __swprintf_chkieee128 F
+GLIBC_2.28 __swprintfieee128 F
+GLIBC_2.28 __swscanfieee128 F
+GLIBC_2.28 __syslog_chkieee128 F
+GLIBC_2.28 __syslogieee128 F
+GLIBC_2.28 __vasprintf_chkieee128 F
+GLIBC_2.28 __vasprintfieee128 F
+GLIBC_2.28 __vdprintf_chkieee128 F
+GLIBC_2.28 __vdprintfieee128 F
+GLIBC_2.28 __verrieee128 F
+GLIBC_2.28 __verrxieee128 F
+GLIBC_2.28 __vfprintf_chkieee128 F
+GLIBC_2.28 __vfprintfieee128 F
+GLIBC_2.28 __vfscanfieee128 F
+GLIBC_2.28 __vfwprintf_chkieee128 F
+GLIBC_2.28 __vfwprintfieee128 F
+GLIBC_2.28 __vfwscanfieee128 F
+GLIBC_2.28 __vprintf_chkieee128 F
+GLIBC_2.28 __vprintfieee128 F
+GLIBC_2.28 __vscanfieee128 F
+GLIBC_2.28 __vsnprintf_chkieee128 F
+GLIBC_2.28 __vsnprintfieee128 F
+GLIBC_2.28 __vsprintf_chkieee128 F
+GLIBC_2.28 __vsprintfieee128 F
+GLIBC_2.28 __vsscanfieee128 F
+GLIBC_2.28 __vswprintf_chkieee128 F
+GLIBC_2.28 __vswprintfieee128 F
+GLIBC_2.28 __vswscanfieee128 F
+GLIBC_2.28 __vsyslog_chkieee128 F
+GLIBC_2.28 __vsyslogieee128 F
+GLIBC_2.28 __vwarnieee128 F
+GLIBC_2.28 __vwarnxieee128 F
+GLIBC_2.28 __vwprintf_chkieee128 F
+GLIBC_2.28 __vwprintfieee128 F
+GLIBC_2.28 __vwscanfieee128 F
+GLIBC_2.28 __warnieee128 F
+GLIBC_2.28 __warnxieee128 F
+GLIBC_2.28 __wprintf_chkieee128 F
+GLIBC_2.28 __wprintfieee128 F
+GLIBC_2.28 __wscanfieee128 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
index 6c94f3e..7c64f60 100644
--- a/wcsmbs/wchar.h
+++ b/wcsmbs/wchar.h
@@ -634,7 +634,8 @@ extern int swscanf (const wchar_t *__restrict __s,
 
 # if defined __USE_ISOC99 && !defined __USE_GNU \
      && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
-     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K) \
+     && (!__LONG_DOUBLE_USES_FLOAT128)
 #  ifdef __REDIRECT
 /* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
    GNU extension which conflicts with valid %a followed by letter
@@ -689,7 +690,8 @@ extern int vswscanf (const wchar_t *__restrict __s,
 
 # if !defined __USE_GNU \
      && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
-     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
+     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K) \
+     && (!__LONG_DOUBLE_USES_FLOAT128)
 #  ifdef __REDIRECT
 extern int __REDIRECT (vfwscanf, (__FILE *__restrict __s,
 				  const wchar_t *__restrict __format,
@@ -854,6 +856,17 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
 # include <bits/wchar-ldbl.h>
 #endif
 
+/* XXX: DO NOT COMMIT.
+
+   On powerpc64le, the implementation of long double with IEEE binary128
+   format is not complete.  The redirections of the wchar.h functions
+   are supposed to be implemented in bits/wchar-ldbl.h, however, we can
+   only redirect all or none.  In the meantime, bits/wchar-ieee128.h
+   allows us to redirect part of them for testing purposes.  */
+#if __LONG_DOUBLE_USES_FLOAT128
+# include <bits/wchar-ieee128.h>
+#endif
+
 __END_DECLS
 
 #endif /* wchar.h  */

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=fe090b69a53e7e96c1cfffa3650cd528d5c7bc25

commit fe090b69a53e7e96c1cfffa3650cd528d5c7bc25
Author: Rajalakshmi Srinivasaraghavan <raji@linux.vnet.ibm.com>
Date:   Thu Jun 28 15:17:42 2018 +0530

    Redirect strfmon_l long double function
    
    Similarly to what has been done for printf-like functions, more
    specifically to the internal implementation in __vfprintf_internal, this
    patch extends __vstrfmon_l_internal to deal with long double values with
    binary128 format (as a third format option and reusing the float128
    implementation).
    
    2018-06-25  Rajalakshmi Srinivasaraghavan  <raji@linux.vnet.ibm.com>
    	    Gabriel F. T. Gomes  <gabriel@inconstante.eti.br>
    
    	* include/monetary.h (STRFMON_LDBL_USES_FLOAT128): New constant.
    	* stdlib/strfmon_l.c: Include bits/floatn.h.
    	(__vstrfmon_l_internal): Add support for printing long double
    	values reusing the float128 implementation.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == stdlib] (ldbl-extra-routines): Add strfmon and
    	strfmon_l.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__strfmonieee128 and __strfmonieee128_l.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon_l.c: New file.
    	* sysdeps/powerpc/powerpc64/le/Makefile: Add -mabi=ibmlongdouble
    	to build strfmon and strfmon_l.

diff --git a/include/monetary.h b/include/monetary.h
index d12ae03..c9b5b97 100644
--- a/include/monetary.h
+++ b/include/monetary.h
@@ -8,5 +8,6 @@ extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
 
 /* Flags for __vstrfmon_l_internal.  */
 #define STRFMON_LDBL_IS_DBL 0x0001
+#define STRFMON_LDBL_USES_FLOAT128  0x0002
 
 #endif
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index f0ebd99..9ccf523 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <string.h>
 #include "../locale/localeinfo.h"
+#include <bits/floatn.h>
 
 
 #define out_char(Ch)							      \
@@ -96,6 +97,9 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
       {
 	double dbl;
 	long double ldbl;
+#if __HAVE_DISTINCT_FLOAT128
+      _Float128 f128;
+#endif
       }
       fpnum;
       int int_format;
@@ -106,6 +110,7 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
       int group;
       char pad;
       int is_long_double;
+      int is_binary128;
       int p_sign_posn;
       int n_sign_posn;
       int sign_posn;
@@ -150,6 +155,7 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
       group = 1;			/* Print digits grouped.  */
       pad = ' ';			/* Fill character is <SP>.  */
       is_long_double = 0;		/* Double argument by default.  */
+      is_binary128 = 0;		/* Long double argument by default.  */
       p_sign_posn = -2;			/* This indicates whether the */
       n_sign_posn = -2;			/* '(' flag is given.  */
       width = -1;			/* No width specified so far.  */
@@ -270,6 +276,10 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
 	  ++fmt;
 	  if (__glibc_likely ((flags & STRFMON_LDBL_IS_DBL) == 0))
 	    is_long_double = 1;
+#if __HAVE_DISTINCT_FLOAT128
+	  if (__glibc_likely ((flags & STRFMON_LDBL_USES_FLOAT128) != 0))
+	    is_binary128 = is_long_double;
+#endif
 	}
 
       /* Handle format specifier.  */
@@ -324,10 +334,22 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
       /* Now it's time to get the value.  */
       if (is_long_double == 1)
 	{
-	  fpnum.ldbl = va_arg (ap, long double);
-	  is_negative = fpnum.ldbl < 0;
-	  if (is_negative)
-	    fpnum.ldbl = -fpnum.ldbl;
+#if __HAVE_DISTINCT_FLOAT128
+	  if (is_binary128 == 1)
+	    {
+	      fpnum.f128 = va_arg (ap, _Float128);
+	      is_negative = fpnum.f128 < 0;
+	      if (is_negative)
+	        fpnum.f128 = -fpnum.f128;
+	    }
+	  else
+#endif
+	  {
+	    fpnum.ldbl = va_arg (ap, long double);
+	    is_negative = fpnum.ldbl < 0;
+	    if (is_negative)
+	      fpnum.ldbl = -fpnum.ldbl;
+	  }
 	}
       else
 	{
@@ -517,6 +539,7 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
       info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
       info.spec = 'f';
       info.is_long_double = is_long_double;
+      info.is_binary128 = is_binary128;
       info.group = group;
       info.pad = pad;
       info.extra = 1;		/* This means use values from LC_MONETARY.  */
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 3c67d8b..d084cd3 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -429,6 +429,16 @@ $(objpfx)test-syslog-chk-ibm128.out: \
 	$(evaluate-test)
 endif
 
+ifeq ($(subdir),stdlib)
+ldbl-extra-routines += strfmon strfmon_l
+
+# Printing long double values with IEEE binary128 format reuses part
+# of the internal float128 implementation (__printf_fp, __printf_fphex,
+# and __float128 variables and union members).  Thus, the compilation of
+# the following files, must have -mfloat128 passed to the compiler.
+CFLAGS-strfmon_l.c += -mfloat128
+endif
+
 # Add IEEE binary128 files as make targets.
 routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index b7aa9f7..86dd6ab 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -221,5 +221,8 @@ libc {
 
     __errorieee128;
     __error_at_lineieee128;
+
+    __strfmonieee128;
+    __strfmonieee128_l;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon.c
new file mode 100644
index 0000000..743f7cd
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon.c
@@ -0,0 +1,35 @@
+/* Wrapper for strfmon.  IEEE128 version.
+   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 <monetary.h>
+#include <stdarg.h>
+#include <locale/localeinfo.h>
+
+ssize_t
+___ieee128_strfmon (char *s, size_t maxsize, const char *format, ...)
+{
+  va_list ap;
+  ssize_t res;
+
+  va_start (ap, format);
+  res = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE,
+                                       format, ap, STRFMON_LDBL_USES_FLOAT128);
+  va_end (ap);
+  return res;
+}
+weak_alias (___ieee128_strfmon, __strfmonieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon_l.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon_l.c
new file mode 100644
index 0000000..b56e820
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-strfmon_l.c
@@ -0,0 +1,35 @@
+/* Wrapper for strfmon_l.  IEEE128 version.
+   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 <monetary.h>
+#include <stdarg.h>
+#include <locale/localeinfo.h>
+
+ssize_t
+___ieee128_strfmon_l (char *s, size_t maxsize, locale_t loc, const char *format, ...)
+{
+  va_list ap;
+  ssize_t res;
+
+  va_start (ap, format);
+  res = __vstrfmon_l_internal (s, maxsize, loc,
+                                       format, ap, STRFMON_LDBL_USES_FLOAT128);
+  va_end (ap);
+  return res;
+}
+weak_alias (___ieee128_strfmon_l, __strfmonieee128_l)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=511c030a1fc6611fe6801bf02caccbbb319b5571

commit 511c030a1fc6611fe6801bf02caccbbb319b5571
Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
Date:   Mon Jul 30 12:04:40 2018 -0300

    ldbl-128ibm-compat: Compiler flags for stdio functions
    
    Some of the files that provide stdio.h and wchar.h functions have a
    filename prefixed with 'io', such as 'iovsprintf.c'.  On platforms that
    imply ldbl-128ibm-compat, these files must be compiled with the flag
    -mabi=ibmlongdouble.  This patch adds this flag to their compilation.
    
    Notice that this is not required for the other files that provide
    similar functions, because filenames that are not prefixed with 'io'
    have ldbl-128ibm-compat counterparts in the Makefile, which already adds
    -mabi=ibmlongdouble to them.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	(ldbl-ibm128-files): Add $(objpfx)iovdprintf^,
    	$(objpfx)iovsprintf^, $(objpfx)iovsscanf^, $(objpfx)iovswscanf^,
    	$(objpfx)iovfscanf^, and $(objpfx)iovfwscanf^.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index ebe975a..3c67d8b 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -438,6 +438,12 @@ routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 # -mabi=ibmlongdouble.  The following rule ensures that the correct
 # compiler flags are passed to these files.
 ldbl-ibm128-files := $(objpfx)test-%-ibm128^ \
+		     $(objpfx)iovdprintf^ \
+		     $(objpfx)iovsprintf^ \
+		     $(objpfx)iovsscanf^ \
+		     $(objpfx)iovswscanf^ \
+		     $(objpfx)iovfscanf^ \
+		     $(objpfx)iovfwscanf^ \
 		     $(foreach r,$(ldbl-extra-routines),$(objpfx)$(r)^) \
 		     $(foreach r,$(ldbl-extra-routines),$(objpfx)$(r)-internal^)
 obj-suf-foreach = $(foreach suf,$(all-object-suffixes),$(subst ^,$(suf),$(1)))

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=03dda571464050ffd1d82e3b1a997cc4f2d35815

commit 03dda571464050ffd1d82e3b1a997cc4f2d35815
Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
Date:   Tue Jul 24 16:06:23 2018 -0300

    Do not redirect calls to __GI_* symbols, when redirecting to *ieee128
    
    On platforms where long double has IEEE binary128 format as a third
    option (initially, only powerpc64le), many exported functions are
    redirected to their __*ieee128 equivalents.  This redirection is
    provided by installed headers such as stdio-ldbl.h, and is supposed to
    work correctly with user code.
    
    However, during the build of glibc, similar redirections are employed,
    in internal headers such as include/stdio.h, in order to avoid extra PLT
    entries.  These redirections conflict with the redirections to
    __*ieee128, and must be avoided during the build.  This patch protects
    the second redirections with a test for __LONG_DOUBLE_USES_FLOAT128.
    
    	* include/err.h: Protect the redirection of warn, warnx, vwarn,
    	vwarnx, verr, and verrx)
    	* include/stdio.h: Likewise for __asprintf, fprintf, vfprintf,
    	sprintf, and sscanf.
    	* include/sys/syslog.h: Likewise for syslog and vsyslog.
    	* include/wchar.h: Likewise for vswscanf.

diff --git a/include/err.h b/include/err.h
index 7c05cd1..4bfd0f1 100644
--- a/include/err.h
+++ b/include/err.h
@@ -12,12 +12,15 @@ __vwarn_internal (const char *format, __gnuc_va_list ap,
 
 # ifndef _ISOMAC
 
+#if !defined __LONG_DOUBLE_USES_FLOAT128 \
+  || (defined __LONG_DOUBLE_USES_FLOAT128 && __LONG_DOUBLE_USES_FLOAT128 == 0)
 libc_hidden_proto (warn)
 libc_hidden_proto (warnx)
 libc_hidden_proto (vwarn)
 libc_hidden_proto (vwarnx)
 libc_hidden_proto (verr)
 libc_hidden_proto (verrx)
+#  endif
 
 # endif /* !_ISOMAC */
 #endif /* err.h */
diff --git a/include/stdio.h b/include/stdio.h
index 2f28be9..de6789c 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -147,7 +147,10 @@ libc_hidden_proto (__libc_readline_unlocked);
 extern const char *const _sys_errlist_internal[] attribute_hidden;
 extern int _sys_nerr_internal attribute_hidden;
 
+#if !defined __LONG_DOUBLE_USES_FLOAT128 \
+  || (defined __LONG_DOUBLE_USES_FLOAT128 && __LONG_DOUBLE_USES_FLOAT128 == 0)
 libc_hidden_proto (__asprintf)
+#endif
 #  if IS_IN (libc)
 extern FILE *_IO_new_fopen (const char*, const char*);
 #   define fopen(fname, mode) _IO_new_fopen (fname, mode)
@@ -168,14 +171,17 @@ extern int _IO_new_fgetpos (FILE *, __fpos_t *);
 #   define fgetpos(fp, posp) _IO_new_fgetpos (fp, posp)
 #  endif
 
-libc_hidden_proto (dprintf)
 extern __typeof (dprintf) __dprintf
      __attribute__ ((__format__ (__printf__, 2, 3)));
 libc_hidden_proto (__dprintf)
+#if !defined __LONG_DOUBLE_USES_FLOAT128 \
+  || (defined __LONG_DOUBLE_USES_FLOAT128 && __LONG_DOUBLE_USES_FLOAT128 == 0)
+libc_hidden_proto (dprintf)
 libc_hidden_proto (fprintf)
 libc_hidden_proto (vfprintf)
 libc_hidden_proto (sprintf)
 libc_hidden_proto (sscanf)
+#endif
 libc_hidden_proto (fwrite)
 libc_hidden_proto (perror)
 libc_hidden_proto (remove)
diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 459ca70..df5149b 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -3,8 +3,13 @@
 #include <misc/sys/syslog.h>
 #ifndef _ISOMAC
 
+#include <bits/floatn.h>
+
+#if !defined __LONG_DOUBLE_USES_FLOAT128 \
+  || (defined __LONG_DOUBLE_USES_FLOAT128 && __LONG_DOUBLE_USES_FLOAT128 == 0)
 libc_hidden_proto (syslog)
 libc_hidden_proto (vsyslog)
+#endif
 
 /* __vsyslog_internal uses the same mode_flags bits as
    __v*printf_internal; see libio/libioP.h.  */
diff --git a/include/wchar.h b/include/wchar.h
index 90b6e43..2d2c6ba 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -114,7 +114,10 @@ libc_hidden_proto (fputws_unlocked)
 libc_hidden_proto (putwc_unlocked)
 libc_hidden_proto (putwc)
 
+#if !defined __LONG_DOUBLE_USES_FLOAT128 \
+  || (defined __LONG_DOUBLE_USES_FLOAT128 && __LONG_DOUBLE_USES_FLOAT128 == 0)
 libc_hidden_proto (vswscanf)
+#endif
 
 libc_hidden_proto (mbrtowc)
 libc_hidden_proto (wcrtomb)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=47a931d3260b3c0560f54d4336acd8a8d3a7363a

commit 47a931d3260b3c0560f54d4336acd8a8d3a7363a
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Jun 26 17:22:13 2018 -0300

    ldbl-128ibm-compat: Add syslog functions
    
    I'm using 'syslog (LOG_DEBUG, etc.);' in the test case, which I believe
    will not print to the console, but I'm not sure if changing some system
    setting to high verbosity will disturb people's lives.  Please advise.
    :)
    
    -- 8< --
    Similarly to __vfprintf_internal and __vfscanf_internal, the internal
    implementation of syslog functions (__vsyslog_internal) takes a
    'mode_flags' parameter used to select the format of long double
    parameters.  This patch adds variants of the syslog functions that set
    'mode_flags' to PRINTF_LDBL_USES_FLOAT128, thus enabling the correct
    printing of long double values on powerpc64le, when long double has IEEE
    binary128 format (-mabi=ieeelongdouble).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == misc] (ldbl-extra-routines): Add syslog.
    	[subdir == misc] (tests-internal): Add test-syslog-ieee128,
    	test-syslog-ibm128, test-syslog-chk-ieee128, test-syslog-chk-ibm128.
    	[subdir == misc] (CFLAGS-test-syslog-ieee128.c)
    	(CFLAGS-test-syslog-ibm128.c, CFLAGS-test-syslog-chk-ieee128.c)
    	(CFLAGS-test-syslog-chk-ibm128.c): New variables.
    	[subdir == misc] (tests-special): Add
    	$(objpfx)test-syslog-ieee128.out,
    	$(objpfx)test-syslog-ibm128.out,
    	$(objpfx)test-syslog-chk-ieee128.out, and
    	$(objpfx)test-syslog-chk-ibm128.out.
    	[subdir == misc] ($(objpfx)test-syslog-ieee128.out)
    	($(objpfx)test-syslog-ibm128.out)
    	($(objpfx)test-syslog-chk-ieee128.out)
    	($(objpfx)test-syslog-chk-ibm128.out): New build and run rules.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__syslogieee128, __vsyslogieee128, __syslog_chkieee128, and
    	__vsyslog_chkieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-syslog.c:
    	New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat-template.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index c0e5c7f..ebe975a 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -314,7 +314,8 @@ endif
 
 ifeq ($(subdir),misc)
 ldbl-extra-routines += err \
-		       error
+		       error \
+		       syslog
 
 tests-internal += tst-ibm128-warn tst-ieee128-warn
 
@@ -352,6 +353,14 @@ CFLAGS-tst-ieee128-error-verrx.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-tst-ieee128-error-error.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-tst-ieee128-error-error_at_line.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 
+tests-internal += test-syslog-ieee128 test-syslog-ibm128
+CFLAGS-test-syslog-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-syslog-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+tests-internal += test-syslog-chk-ieee128 test-syslog-chk-ibm128
+CFLAGS-test-syslog-chk-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-syslog-chk-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-ibm128-warn.out
 
@@ -372,6 +381,12 @@ tests-special += $(objpfx)tst-ieee128-error-verrx.out
 
 tests-special += $(objpfx)tst-ieee128-error-error.out
 tests-special += $(objpfx)tst-ieee128-error-error_at_line.out
+
+tests-special += $(objpfx)test-syslog-ieee128.out
+tests-special += $(objpfx)test-syslog-ibm128.out
+
+tests-special += $(objpfx)test-syslog-chk-ieee128.out
+tests-special += $(objpfx)test-syslog-chk-ibm128.out
 endif
 
 $(objpfx)tst-%-warn.out: \
@@ -388,6 +403,30 @@ $(objpfx)tst-ieee128-error-%.out: \
   tst-ldbl-error.sh $(objpfx)tst-ieee128-error-%
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
+
+$(objpfx)test-syslog-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh \
+  $(objpfx)test-syslog-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-syslog-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh \
+  $(objpfx)test-syslog-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-syslog-chk-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh \
+  $(objpfx)test-syslog-chk-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-syslog-chk-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh \
+  $(objpfx)test-syslog-chk-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
 endif
 
 # Add IEEE binary128 files as make targets.
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index f59dfb5..b7aa9f7 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -170,6 +170,11 @@ libc {
     __obstack_printf_chkieee128;
     __obstack_vprintf_chkieee128;
 
+    __syslogieee128;
+    __vsyslogieee128;
+    __syslog_chkieee128;
+    __vsyslog_chkieee128;
+
     __fscanfieee128;
     __scanfieee128;
     __sscanfieee128;
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-syslog.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-syslog.c
new file mode 100644
index 0000000..fa16cc9
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-syslog.c
@@ -0,0 +1,65 @@
+/* Wrapper for syslog.  IEEE128 version.
+   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 <stdarg.h>
+#include <libioP.h>
+#include <syslog.h>
+
+void
+___ieee128_syslog (int pri, const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+}
+strong_alias (___ieee128_syslog, __syslogieee128)
+
+void
+___ieee128_vsyslog (int pri, const char *fmt, va_list ap)
+{
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vsyslog, __vsyslogieee128)
+
+void
+___ieee128_syslog_chk (int pri, int flag, const char *fmt, ...)
+{
+  va_list ap;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, fmt);
+  __vsyslog_internal (pri, fmt, ap, mode);
+  va_end (ap);
+}
+strong_alias (___ieee128_syslog_chk, __syslog_chkieee128)
+
+void
+___ieee128_vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  __vsyslog_internal (pri, fmt, ap, mode);
+}
+strong_alias (___ieee128_vsyslog_chk, __vsyslog_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ibm128.c
new file mode 100644
index 0000000..bf42582
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ibm128.c
@@ -0,0 +1 @@
+#include <test-syslog-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ieee128.c
new file mode 100644
index 0000000..bf42582
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ieee128.c
@@ -0,0 +1 @@
+#include <test-syslog-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ldbl-compat.c
new file mode 100644
index 0000000..513b2d2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-chk-ldbl-compat.c
@@ -0,0 +1,6 @@
+#define _FORTIFY_SOURCE 2
+#define SYSLOG_FUNCTION __syslog_chk
+#define SYSLOG_FUNCTION_PARAMS (LOG_DEBUG, 1, "%Lf\n", ld)
+#define VSYSLOG_FUNCTION __vsyslog_chk
+#define VSYSLOG_FUNCTION_PARAMS (LOG_DEBUG, 1, "%Lf\n", ap)
+#include <test-syslog-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ibm128.c
new file mode 100644
index 0000000..8e64440
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ibm128.c
@@ -0,0 +1 @@
+#include <test-syslog-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ieee128.c
new file mode 100644
index 0000000..8e64440
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ieee128.c
@@ -0,0 +1 @@
+#include <test-syslog-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat-template.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat-template.c
new file mode 100644
index 0000000..fe9ecc5
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat-template.c
@@ -0,0 +1,50 @@
+/* Test for the long double variants of *syslog* functions.
+   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 <stdarg.h>
+#include <stddef.h>
+#include <syslog.h>
+
+#include <support/check.h>
+
+static void
+do_test_call (void *last, ...)
+{
+  long double ld = -1;
+  va_list ap;
+
+  /* Make syslog functions write to stderr with LOG_PERROR.  */
+  openlog ("test-syslog", LOG_PERROR | LOG_ODELAY, LOG_USER);
+
+  /* Call syslog functions that take a format string.  */
+  SYSLOG_FUNCTION SYSLOG_FUNCTION_PARAMS;
+  va_start (ap, last);
+  VSYSLOG_FUNCTION VSYSLOG_FUNCTION_PARAMS;
+  va_end (ap);
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+  do_test_call (NULL, ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.c
new file mode 100644
index 0000000..ff0c0a5
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.c
@@ -0,0 +1,6 @@
+#define _FORTIFY_SOURCE 0
+#define SYSLOG_FUNCTION syslog
+#define SYSLOG_FUNCTION_PARAMS (LOG_DEBUG, "%Lf\n", ld)
+#define VSYSLOG_FUNCTION vsyslog
+#define VSYSLOG_FUNCTION_PARAMS (LOG_DEBUG, "%Lf\n", ap)
+#include <test-syslog-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh
new file mode 100644
index 0000000..263c763
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-syslog-ldbl-compat.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Testing of *syslog*.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  2> ${test_program_output} || status=1
+
+cat <<'EOF' |
+test-syslog: -1.000000
+test-syslog: -1.000000
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4f0e59d5212afef878706ac912b981a6b2d4b186

commit 4f0e59d5212afef878706ac912b981a6b2d4b186
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon Jun 25 22:43:24 2018 -0300

    ldbl-128ibm-compat: Add obstack printing functions
    
    Similar to the functions from the *printf family, this patch adds
    implementations for __obstack_*printf* functions that set the
    'mode_flags' parameter to PRINTF_LDBL_USES_FLOAT128, before making calls
    to __vfprintf_internal (indirectly through __obstack_vprintf_internal).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == stdio-common] (ldbl-extra-routines): Add obprintf,
    	obstack_chk, vobstack_chk.
    	[subdir == stdio-common] (tests-internal): Add
    	test-obstack-ieee128, test-obstack-ibm128,
    	test-obstack-chk-ieee128, and test-obstack-chk-ibm128.
    	[subdir == stdio-common] (CFLAGS-test-obstack-ieee128.c)
    	(CFLAGS-test-obstack-ibm128.c, CFLAGS-test-obstack-chk-ieee128.c)
    	(CFLAGS-test-obstack-chk-ibm128.c): New variable.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc) Add
    	__obstack_printfieee128, __obstack_vprintfieee128,
    	__obstack_printf_chkieee128, and __obstack_vprintf_chkieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obprintf.c:
    	New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obstack_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vobstack_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat-template.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat.c:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index a7293e6..c0e5c7f 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -47,7 +47,10 @@ ldbl-extra-routines += printf_size \
 		       isoc99_sscanf \
 		       isoc99_vfscanf \
 		       isoc99_vscanf \
-		       isoc99_vsscanf
+		       isoc99_vsscanf \
+		       obprintf \
+		       obstack_chk \
+		       vobstack_chk
 
 # Printing long double values with IEEE binary128 format reuses part
 # of the internal float128 implementation (__printf_fp, __printf_fphex,
@@ -69,6 +72,14 @@ tests-internal += test-wprintf-ieee128 test-wprintf-ibm128
 CFLAGS-test-wprintf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-wprintf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
+tests-internal += test-obstack-ieee128 test-obstack-ibm128
+CFLAGS-test-obstack-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-obstack-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+tests-internal += test-obstack-chk-ieee128 test-obstack-chk-ibm128
+CFLAGS-test-obstack-chk-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-obstack-chk-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
 tests-internal += test-scanf-ieee128 test-scanf-ibm128
 CFLAGS-test-scanf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-scanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 23c2fd9..f59dfb5 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -165,6 +165,11 @@ libc {
     __vswprintf_chkieee128;
     __vwprintf_chkieee128;
 
+    __obstack_printfieee128;
+    __obstack_vprintfieee128;
+    __obstack_printf_chkieee128;
+    __obstack_vprintf_chkieee128;
+
     __fscanfieee128;
     __scanfieee128;
     __sscanfieee128;
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obprintf.c
new file mode 100644
index 0000000..924838e
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obprintf.c
@@ -0,0 +1,42 @@
+/* Wrapper for obstack_vprintf and obstack_printf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+int
+__ieee128_obstack_vprintf (struct obstack *obstack, const char *format,
+			   va_list ap)
+{
+  return __obstack_vprintf_internal (obstack, format, ap,
+				     PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (__ieee128_obstack_vprintf, __obstack_vprintfieee128)
+
+int
+__ieee128_obstack_printf (struct obstack *obstack, const char *format, ...)
+{
+  int result;
+  va_list ap;
+  va_start (ap, format);
+  result = __obstack_vprintf_internal (obstack, format, ap,
+				       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+  return result;
+}
+strong_alias (__ieee128_obstack_printf, __obstack_printfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obstack_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obstack_chk.c
new file mode 100644
index 0000000..194589c
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-obstack_chk.c
@@ -0,0 +1,39 @@
+/* Wrapper for __obstack_printf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_obstack_printf_chk (struct obstack *obstack, int flag,
+			       const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __obstack_vprintf_internal (obstack, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_obstack_printf_chk, __obstack_printf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vobstack_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vobstack_chk.c
new file mode 100644
index 0000000..fa5182a
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vobstack_chk.c
@@ -0,0 +1,31 @@
+/* Wrapper for __obstack_vprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128__obstack_vprintf_chk  (struct obstack *obstack, int flag,
+				  const char *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __obstack_vprintf_internal (obstack, format, ap, mode);
+}
+strong_alias (___ieee128__obstack_vprintf_chk, __obstack_vprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ibm128.c
new file mode 100644
index 0000000..ca4c9f2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ibm128.c
@@ -0,0 +1 @@
+#include <test-obstack-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ieee128.c
new file mode 100644
index 0000000..ca4c9f2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ieee128.c
@@ -0,0 +1 @@
+#include <test-obstack-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ldbl-compat.c
new file mode 100644
index 0000000..feae8f2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-chk-ldbl-compat.c
@@ -0,0 +1,6 @@
+#define _FORTIFY_SOURCE 2
+#define OBSTACK_FUNCTION __obstack_printf_chk
+#define OBSTACK_FUNCTION_PARAMS (&ob, 1, "%.30Lf", ld)
+#define VOBSTACK_FUNCTION __obstack_vprintf_chk
+#define VOBSTACK_FUNCTION_PARAMS (&ob, 1, "%.30Lf", ap)
+#include <test-obstack-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ibm128.c
new file mode 100644
index 0000000..be88675
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ibm128.c
@@ -0,0 +1 @@
+#include <test-obstack-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ieee128.c
new file mode 100644
index 0000000..be88675
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ieee128.c
@@ -0,0 +1 @@
+#include <test-obstack-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat-template.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat-template.c
new file mode 100644
index 0000000..c82ddc4
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat-template.c
@@ -0,0 +1,64 @@
+/* Test for the long double variants of obstrack*printf functions.
+   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 <malloc.h>
+#include <obstack.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <support/check.h>
+
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+static void
+do_test_call (void *last, ...)
+{
+  const char *expected = "-1.000000000000000000000000000000";
+  char *actual = NULL;
+  long double ld = -1;
+  struct obstack ob;
+  va_list ap;
+
+  obstack_init (&ob);
+  OBSTACK_FUNCTION OBSTACK_FUNCTION_PARAMS;
+  actual = (char *) obstack_finish (&ob);
+  TEST_VERIFY (strncmp (expected, actual, 33) == 0);
+  obstack_free (&ob, NULL);
+  actual = NULL;
+
+  obstack_init (&ob);
+  va_start (ap, last);
+  VOBSTACK_FUNCTION VOBSTACK_FUNCTION_PARAMS;
+  va_end (ap);
+  actual = (char *) obstack_finish (&ob);
+  TEST_VERIFY (strncmp (expected, actual, 33) == 0);
+  obstack_free (&ob, NULL);
+  actual = NULL;
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+  do_test_call (NULL, ld);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat.c
new file mode 100644
index 0000000..3849d25
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-obstack-ldbl-compat.c
@@ -0,0 +1,6 @@
+#define _FORTIFY_SOURCE 0
+#define OBSTACK_FUNCTION obstack_printf
+#define OBSTACK_FUNCTION_PARAMS (&ob, "%.30Lf", ld)
+#define VOBSTACK_FUNCTION obstack_vprintf
+#define VOBSTACK_FUNCTION_PARAMS (&ob, "%.30Lf", ap)
+#include <test-obstack-ldbl-compat-template.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b2386d8bfe74fb7692b1bcb4913bf0f3d1799ac8

commit b2386d8bfe74fb7692b1bcb4913bf0f3d1799ac8
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Wed Jun 20 10:10:24 2018 -0300

    ldbl-128ibm-compat: Add ISO C99 versions of scanf functions
    
    In the format string for *scanf functions, the '%as', '%aS', and '%a[]'
    modifiers behave differently depending on ISO C99 compatibility and on
    _GNU_SOURCE.  When _GNU_SOURCE is not set and when in compatibility with
    ISO C99, these modifiers consume a floating-point argument.  Otherwise,
    they behave like ascanf, and allocate memory for the output.  This patch
    adds the IEEE binary128 variant of these functions for the third long
    double format on powerpc64le.
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == stdio-common] (ldbl-extra-routines): Add
    	isoc99_fscanf, isoc99_scanf, isoc99_sscanf, isoc99_vfscanf,
    	isoc99_vscanf, isoc99_vsscanf,
    	[subdir == wcsmbs] (ldbl-extra-routines): Add isoc99_fwscanf,
    	isoc99_swscanf, isoc99_wscanf, isoc99_vfwscanf, isoc99_vswscanf,
    	and isoc99_vwscanf.
    	[subdir == stdio-common] (tests-internal): Add
    	test-isoc99-scanf-ieee128, test-isoc99-scanf-ibm128,
    	test-isoc99-wscanf-ieee128, and test-isoc99-wscanf-ibm128.
    	[subdir == stdio-common] (CFLAGS-test-isoc99-scanf-ieee128.c)
    	(CFLAGS-test-isoc99-scanf-ibm128.c)
    	(CFLAGS-test-isoc99-wscanf-ieee128.c)
    	(CFLAGS-test-isoc99-wscanf-ibm128.c): New variable.
    	[subdir == stdio-common] ($(objpfx)test-isoc99-scanf-ieee128)
    	($(objpfx)test-isoc99-wscanf-ieee128): Add $(f128-loader-link)
    	to gnulib.
    	[subdir == stdio-common] (tests-special): Add
    	$(objpfx)test-isoc99-scanf-ieee128.out,
    	$(objpfx)test-isoc99-scanf-ibm128.out,
    	$(objpfx)test-isoc99-wscanf-ieee128.out, and
    	$(objpfx)test-isoc99-wscanf-ibm128.out.
    	($(objpfx)test-isoc99-scanf-ieee128.out)
    	($(objpfx)test-isoc99-scanf-ibm128.out)
    	($(objpfx)test-isoc99-wscanf-ieee128.out)
    	($(objpfx)test-isoc99-wscanf-ibm128.out): New build and run rules.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__isoc99_fscanfieee128, __isoc99_scanfieee128,
    	__isoc99_sscanfieee128, __isoc99_vfscanfieee128,
    	__isoc99_vscanfieee128, __isoc99_vsscanfieee128,
    	__isoc99_fwscanfieee128, __isoc99_swscanfieee128,
    	__isoc99_wscanfieee128, __isoc99_vfwscanfieee128,
    	__isoc99_vswscanfieee128, and __isoc99_vwscanfieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fscanf.c:
    	New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fwscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_scanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_sscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfwscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vsscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vwscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_wscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat-template.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c:
    	Protect the declaration of variables based on ISO C99 feature
    	test macros.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 3c13846..a7293e6 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -6,6 +6,15 @@ ldbl-extra-routines += fwscanf \
 		       vwscanf
 endif
 
+ifeq ($(subdir),wcsmbs)
+ldbl-extra-routines += isoc99_fwscanf \
+		       isoc99_swscanf \
+		       isoc99_wscanf \
+		       isoc99_vfwscanf \
+		       isoc99_vswscanf \
+		       isoc99_vwscanf
+endif
+
 ifeq ($(subdir),stdio-common)
 ldbl-extra-routines += printf_size \
 		       asprintf \
@@ -32,7 +41,13 @@ ldbl-extra-routines += printf_size \
 		       vfscanf \
 		       vscanf \
 		       vsscanf \
-		       vfwscanf
+		       vfwscanf \
+		       isoc99_fscanf \
+		       isoc99_scanf \
+		       isoc99_sscanf \
+		       isoc99_vfscanf \
+		       isoc99_vscanf \
+		       isoc99_vsscanf
 
 # Printing long double values with IEEE binary128 format reuses part
 # of the internal float128 implementation (__printf_fp, __printf_fphex,
@@ -66,6 +81,18 @@ CFLAGS-test-wscanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
 $(objpfx)test-wscanf-ieee128: gnulib-tests += $(f128-loader-link)
 
+tests-internal += test-isoc99-scanf-ieee128 test-isoc99-scanf-ibm128
+CFLAGS-test-isoc99-scanf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi -std=c99
+CFLAGS-test-isoc99-scanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi -std=c99
+
+$(objpfx)test-isoc99-scanf-ieee128: gnulib-tests += $(f128-loader-link)
+
+tests-internal += test-isoc99-wscanf-ieee128 test-isoc99-wscanf-ibm128
+CFLAGS-test-isoc99-wscanf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi -std=c99
+CFLAGS-test-isoc99-wscanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi -std=c99
+
+$(objpfx)test-isoc99-wscanf-ieee128: gnulib-tests += $(f128-loader-link)
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)test-printf-ieee128.out
 tests-special += $(objpfx)test-printf-ibm128.out
@@ -78,6 +105,12 @@ tests-special += $(objpfx)test-scanf-ibm128.out
 
 tests-special += $(objpfx)test-wscanf-ieee128.out
 tests-special += $(objpfx)test-wscanf-ibm128.out
+
+tests-special += $(objpfx)test-isoc99-scanf-ieee128.out
+tests-special += $(objpfx)test-isoc99-scanf-ibm128.out
+
+tests-special += $(objpfx)test-isoc99-wscanf-ieee128.out
+tests-special += $(objpfx)test-isoc99-wscanf-ibm128.out
 endif
 
 $(objpfx)test-printf-ieee128.out: \
@@ -128,6 +161,30 @@ $(objpfx)test-wscanf-ibm128.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 
+$(objpfx)test-isoc99-scanf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh \
+  $(objpfx)test-isoc99-scanf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-isoc99-scanf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh \
+  $(objpfx)test-isoc99-scanf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-isoc99-wscanf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh \
+  $(objpfx)test-isoc99-wscanf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-isoc99-wscanf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh \
+  $(objpfx)test-isoc99-wscanf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-size-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index dead38c..23c2fd9 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -181,6 +181,22 @@ libc {
     __vswscanfieee128;
     __vwscanfieee128;
 
+    __isoc99_fscanfieee128;
+    __isoc99_scanfieee128;
+    __isoc99_sscanfieee128;
+
+    __isoc99_vfscanfieee128;
+    __isoc99_vscanfieee128;
+    __isoc99_vsscanfieee128;
+
+    __isoc99_fwscanfieee128;
+    __isoc99_swscanfieee128;
+    __isoc99_wscanfieee128;
+
+    __isoc99_vfwscanfieee128;
+    __isoc99_vswscanfieee128;
+    __isoc99_vwscanfieee128;
+
     __argp_errorieee128;
     __argp_failureieee128;
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fscanf.c
new file mode 100644
index 0000000..3930170
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fscanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for __isoc99_fscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_isoc99_fscanf (FILE *fp, const char *format, ...)
+{
+  va_list arg;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  va_start (arg, format);
+  done = __vfscanf_internal (fp, format, arg, mode_flags);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_fscanf, __isoc99_fscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fwscanf.c
new file mode 100644
index 0000000..d56ecfb
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_fwscanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for __isoc99_fwscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libioP.h>
+
+extern int
+___ieee128_isoc99_fwscanf (FILE *fp, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (fp, format, ap, mode_flags);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_fwscanf, __isoc99_fwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_scanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_scanf.c
new file mode 100644
index 0000000..5b643fb
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_scanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for __isoc99_scanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_isoc99_scanf (const char *format, ...)
+{
+  va_list arg;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  va_start (arg, format);
+  done = __vfscanf_internal (stdin, format, arg, mode_flags);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_scanf, __isoc99_scanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_sscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_sscanf.c
new file mode 100644
index 0000000..480357c
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_sscanf.c
@@ -0,0 +1,39 @@
+/* Wrapper for __isoc99_sscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_isoc99_sscanf (const char *string, const char *format, ...)
+{
+  va_list arg;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  _IO_strfile sf;
+  FILE *fp = _IO_strfile_read (&sf, string);
+
+  va_start (arg, format);
+  done = __vfscanf_internal (fp, format, arg, mode_flags);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_sscanf, __isoc99_sscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c
new file mode 100644
index 0000000..e18779a
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_swscanf.c
@@ -0,0 +1,40 @@
+/* Wrapper for __isoc99_swscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_isoc99_swscanf (const wchar_t *string, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *fp = _IO_strfile_readw (&sf, &wd, string);
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (fp, format, ap, mode_flags);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_swscanf, __isoc99_swscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfscanf.c
new file mode 100644
index 0000000..2d131f7
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for __isoc99_vfscanf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_isoc99_vfscanf (FILE *fp, const char *format, va_list ap)
+{
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfscanf_internal (fp, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vfscanf, __isoc99_vfscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfwscanf.c
new file mode 100644
index 0000000..a281ecc
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vfwscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for __isoc99_vfwscanf.  IEEE128 version.
+   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>
+
+extern int
+___ieee128_isoc99_vfwscanf (FILE *fp, const wchar_t *format, va_list ap)
+{
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfwscanf_internal (fp, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vfwscanf, __isoc99_vfwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vscanf.c
new file mode 100644
index 0000000..6ec60d5
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for __isoc99_vscanf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_isoc99_vscanf (const char *format, va_list ap)
+{
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfscanf_internal (stdin, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vscanf, __isoc99_vscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vsscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vsscanf.c
new file mode 100644
index 0000000..599e868
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vsscanf.c
@@ -0,0 +1,30 @@
+/* Wrapper for __isoc99_vsscanf.  IEEE128 version.
+   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 <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_isoc99_vsscanf (const char *string, const char *format, va_list ap)
+{
+  _IO_strfile sf;
+  FILE *fp = _IO_strfile_read (&sf, string);
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfscanf_internal (fp, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vsscanf, __isoc99_vsscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c
new file mode 100644
index 0000000..3a28616
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vswscanf.c
@@ -0,0 +1,32 @@
+/* Wrapper for __isoc99_vswscanf.  IEEE128 version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+#include <wchar.h>
+#include <strfile.h>
+
+extern int
+___ieee128_isoc99_vswscanf (wchar_t *string, const wchar_t *format, va_list ap)
+{
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *fp = _IO_strfile_readw (&sf, &wd, string);
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfwscanf_internal (fp, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vswscanf, __isoc99_vswscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vwscanf.c
new file mode 100644
index 0000000..b9bd4a7
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_vwscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for __isoc99_vwscanf.  IEEE128 version.
+   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>
+
+extern int
+___ieee128_isoc99_vwscanf (const wchar_t *format, va_list ap)
+{
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+  return __vfwscanf_internal (stdin, format, ap, mode_flags);
+}
+strong_alias (___ieee128_isoc99_vwscanf, __isoc99_vwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_wscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_wscanf.c
new file mode 100644
index 0000000..e78b4a3
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-isoc99_wscanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for __isoc99_wscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libioP.h>
+
+extern int
+___ieee128_isoc99_wscanf (const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+  int mode_flags = SCANF_ISOC99_A | SCANF_LDBL_USES_FLOAT128;
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (stdin, format, ap, mode_flags);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_isoc99_wscanf, __isoc99_wscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ibm128.c
new file mode 100644
index 0000000..70688ac
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ibm128.c
@@ -0,0 +1,13 @@
+#undef _GNU_SOURCE
+/* The following macro definitions are a hack.  They word around disabling
+   the GNU extension while still using a few internal headers.  */
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_int unsigned int
+#define u_long unsigned long
+#include <libio/stdio.h>
+#include <stdlib/stdlib.h>
+#include <string/string.h>
+#include <wcsmbs/wchar.h>
+
+#include <test-isoc99-scanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ieee128.c
new file mode 100644
index 0000000..70688ac
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ieee128.c
@@ -0,0 +1,13 @@
+#undef _GNU_SOURCE
+/* The following macro definitions are a hack.  They word around disabling
+   the GNU extension while still using a few internal headers.  */
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_int unsigned int
+#define u_long unsigned long
+#include <libio/stdio.h>
+#include <stdlib/stdlib.h>
+#include <string/string.h>
+#include <wcsmbs/wchar.h>
+
+#include <test-isoc99-scanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat-template.c
similarity index 65%
copy from sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
copy to sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat-template.c
index 4590e9d..ffc7ca2 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat-template.c
@@ -1,4 +1,4 @@
-/* Test for the long double variants of *scanf functions.
+/* Test for the long double variants of __isoc99_*scanf functions.
    Copyright (C) 2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -24,92 +24,94 @@
 
 #include <support/check.h>
 
-#define CLEAR								\
+#define CLEAR_VARGS							\
   va_start (args, format);						\
-  ld = va_arg (args, long double *);					\
-  *ld = 0;								\
+  ldptr = va_arg (args, long double *);					\
+  fptr = va_arg (args, float *);					\
+  *ldptr = 0;								\
+  *fptr = 0;								\
   va_end (args);
 
-#define CLEAR_VALUE value = 0;
-
-#define CHECK								\
+#define CHECK_VARGS							\
   va_start (args, format);						\
-  ld = va_arg (args, long double *);					\
+  ldptr = va_arg (args, long double *);					\
+  fptr = va_arg (args, float *);					\
   va_end (args);							\
-  if (*ld == -1.0L)							\
+  if (*ldptr == -1 && *fptr == -2)					\
     printf ("OK");							\
   else									\
-    printf ("ERROR (%.60Lf)", *ld);					\
+    printf ("ERROR (%Lf %f)", *ldptr, *fptr);				\
   printf ("\n");
 
+#define CLEAR_VALUE							\
+  ld = 0;								\
+  f = 0;
+
 #define CHECK_VALUE							\
-  if (value == -1.0L)							\
+  if (ld == -1 && f == -2)						\
     printf ("OK");							\
   else									\
-    printf ("ERROR (%.60Lf)", value);					\
+    printf ("ERROR (%Lf %f)", ld, f);					\
   printf ("\n");
 
 static void
 do_test_call (FILE *stream, CHAR *string, const CHAR *format, ...)
 {
-  long double value;
-  long double *ld;
+  float *fptr;
+  float f;
+  long double *ldptr;
+  long double ld;
   va_list args;
 
   CLEAR_VALUE
   printf ("fscanf: ");
-  FSCANF (stream, format, &value);
+  FSCANF (stream, format, &ld, &f);
   CHECK_VALUE
 
   CLEAR_VALUE
   printf ("scanf: ");
-  SCANF (format, &value);
+  SCANF (format, &ld, &f);
   CHECK_VALUE
 
   CLEAR_VALUE
   printf ("sscanf: ");
-  SSCANF (string, format, &value);
+  SSCANF (string, format, &ld, &f);
   CHECK_VALUE
 
-  CLEAR
+  CLEAR_VARGS
   printf ("vfscanf: ");
   va_start (args, format);
   VFSCANF (stream, format, args);
   va_end (args);
-  CHECK
+  CHECK_VARGS
 
-  CLEAR
+  CLEAR_VARGS
   printf ("vscanf: ");
   va_start (args, format);
   VSCANF (format, args);
   va_end (args);
-  CHECK
+  CHECK_VARGS
 
-  CLEAR
+  CLEAR_VARGS
   printf ("vsscanf: ");
   va_start (args, format);
   VSSCANF (string, format, args);
   va_end (args);
-  CHECK
+  CHECK_VARGS
 }
 
 static int
 do_test (void)
 {
   CHAR string[256];
+  float f;
   long double ld;
 
-  /* Scan in decimal notation.  */
-  STRCPY (string,
-	  L ("-1.0\n")
-	  L ("-1.0\n") );
-  do_test_call (stdin, string, L("%Lf"), &ld);
-
-  /* Scan in hexadecimal notation.  */
+  /* Scan floating-point value with '%as'.  */
   STRCPY (string,
-	  L ("-0x1.0p+0\n")
-	  L ("-0x1.0p+0\n") );
-  do_test_call (stdin, string, L("%La"), &ld);
+	  L ("-0x1.0p+0 -0x2.0p+0\n")
+	  L ("-0x1.0p+0 -0x2.0p+0\n") );
+  do_test_call (stdin, string, L("%La %as"), &ld, &f);
 
   return 0;
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.c
new file mode 100644
index 0000000..739b6bb
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.c
@@ -0,0 +1,10 @@
+#define CHAR char
+#define L(x) x
+#define FSCANF fscanf
+#define SSCANF sscanf
+#define SCANF scanf
+#define VFSCANF vfscanf
+#define VSSCANF vsscanf
+#define VSCANF vscanf
+#define STRCPY strcpy
+#include <test-isoc99-scanf-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh
new file mode 100644
index 0000000..fc08bed
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-scanf-ldbl-compat.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Testing of __isoc99_*scanf.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+cat <<'EOF' |
+-0x1.0p+0 -0x2.0p+0
+-0x1.0p+0 -0x2.0p+0
+-0x1.0p+0 -0x2.0p+0
+-0x1.0p+0 -0x2.0p+0
+EOF
+${test_program_prefix} \
+  ${test_program} \
+  - \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+fscanf: OK
+scanf: OK
+sscanf: OK
+vfscanf: OK
+vscanf: OK
+vsscanf: OK
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ibm128.c
new file mode 100644
index 0000000..6be2962
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ibm128.c
@@ -0,0 +1,13 @@
+#undef _GNU_SOURCE
+/* The following macro definitions are a hack.  They word around disabling
+   the GNU extension while still using a few internal headers.  */
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_int unsigned int
+#define u_long unsigned long
+#include <libio/stdio.h>
+#include <stdlib/stdlib.h>
+#include <string/string.h>
+#include <wcsmbs/wchar.h>
+
+#include <test-isoc99-wscanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ieee128.c
new file mode 100644
index 0000000..6be2962
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ieee128.c
@@ -0,0 +1,13 @@
+#undef _GNU_SOURCE
+/* The following macro definitions are a hack.  They word around disabling
+   the GNU extension while still using a few internal headers.  */
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_int unsigned int
+#define u_long unsigned long
+#include <libio/stdio.h>
+#include <stdlib/stdlib.h>
+#include <string/string.h>
+#include <wcsmbs/wchar.h>
+
+#include <test-isoc99-wscanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ldbl-compat.c
new file mode 100644
index 0000000..3ad2964
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-isoc99-wscanf-ldbl-compat.c
@@ -0,0 +1,10 @@
+#define CHAR wchar_t
+#define L(x) L##x
+#define FSCANF fwscanf
+#define SSCANF swscanf
+#define SCANF wscanf
+#define VFSCANF vfwscanf
+#define VSSCANF vswscanf
+#define VSCANF vwscanf
+#define STRCPY wcscpy
+#include <test-isoc99-scanf-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
index 4590e9d..aea4f0d 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
@@ -53,8 +53,10 @@ static void
 do_test_call (FILE *stream, CHAR *string, const CHAR *format, ...)
 {
   long double value;
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
   long double *ld;
   va_list args;
+#endif
 
   CLEAR_VALUE
   printf ("fscanf: ");
@@ -71,6 +73,7 @@ do_test_call (FILE *stream, CHAR *string, const CHAR *format, ...)
   SSCANF (string, format, &value);
   CHECK_VALUE
 
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
   CLEAR
   printf ("vfscanf: ");
   va_start (args, format);
@@ -91,6 +94,7 @@ do_test_call (FILE *stream, CHAR *string, const CHAR *format, ...)
   VSSCANF (string, format, args);
   va_end (args);
   CHECK
+#endif
 }
 
 static int

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=575a514648b35f10fa99f150e64541966d2c1284

commit 575a514648b35f10fa99f150e64541966d2c1284
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Fri Jun 15 13:29:31 2018 -0300

    ldbl-128ibm-compat: Add tests for err.h and error.h functions
    
    Add tests for the functions from err.h and error.h that can take
    positional long double parameters.  Most of the functions tested by this
    patch do not return, so each have an independent test.
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	(tests-internal): Add tst-ibm128-warn, tst-ieee128-warn,
    	tst-ibm128-error-err, tst-ieee128-error-err,
    	tst-ibm128-error-errx, tst-ieee128-error-errx,
    	tst-ibm128-error-verr, tst-ieee128-error-verr,
    	tst-ibm128-error-verrx, tst-ieee128-error-verrx,
    	tst-ibm128-error-error, tst-ieee128-error-error,
    	tst-ibm128-error-error_at_line, and
    	tst-ieee128-error-error_at_line.
    	($(objpfx)tst-ibm128-%.c, $(objpfx)tst-ieee128-%.c): New rules.
    	(CFLAGS-tst-ibm128-warn.c): New variable.
    	(CFLAGS-tst-ibm128-error-err.c): Likewise.
    	(CFLAGS-tst-ibm128-error-errx.c): Likewise.
    	(CFLAGS-tst-ibm128-error-verr.c): Likewise.
    	(CFLAGS-tst-ibm128-error-verrx.c): Likewise.
    	(CFLAGS-tst-ibm128-error-error.c): Likewise.
    	(CFLAGS-tst-ibm128-error-error_at_line.c): Likewise.
    	(CFLAGS-tst-ieee128-warn.c): Likewise.
    	(CFLAGS-tst-ieee128-error-err.c): Likewise.
    	(CFLAGS-tst-ieee128-error-errx.c): Likewise.
    	(CFLAGS-tst-ieee128-error-verr.c): Likewise.
    	(CFLAGS-tst-ieee128-error-verrx.c): Likewise.
    	(CFLAGS-tst-ieee128-error-error.c): Likewise.
    	(CFLAGS-tst-ieee128-error-error_at_line.c): Likewise.
    	[run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-ibm128-warn.out,
    	$(objpfx)tst-ibm128-error-err.out,
    	$(objpfx)tst-ibm128-error-errx.out,
    	$(objpfx)tst-ibm128-error-verr.out,
    	$(objpfx)tst-ibm128-error-verrx.out,
    	$(objpfx)tst-ibm128-error-error.out,
    	$(objpfx)tst-ibm128-error-error_at_line.out,
    	$(objpfx)tst-ieee128-warn.out,
    	$(objpfx)tst-ieee128-error-err.out,
    	$(objpfx)tst-ieee128-error-errx.out,
    	$(objpfx)tst-ieee128-error-verr.out,
    	$(objpfx)tst-ieee128-error-verrx.out, and
    	$(objpfx)tst-ieee128-error-error.out.
    	($(objpfx)tst-%-warn.out, $(objpfx)tst-ibm128-error-%.out)
    	($(objpfx)tst-ieee128-error-%.out): New build and run rules.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 151dd76..3c13846 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -247,6 +247,79 @@ endif
 ifeq ($(subdir),misc)
 ldbl-extra-routines += err \
 		       error
+
+tests-internal += tst-ibm128-warn tst-ieee128-warn
+
+tests-internal += tst-ibm128-error-err tst-ieee128-error-err
+tests-internal += tst-ibm128-error-errx tst-ieee128-error-errx
+tests-internal += tst-ibm128-error-verr tst-ieee128-error-verr
+tests-internal += tst-ibm128-error-verrx tst-ieee128-error-verrx
+
+tests-internal += tst-ibm128-error-error tst-ieee128-error-error
+tests-internal += tst-ibm128-error-error_at_line tst-ieee128-error-error_at_line
+
+$(objpfx)tst-ibm128-%.c: tst-ldbl-%.c
+	cp $< $@
+
+$(objpfx)tst-ieee128-%.c: tst-ldbl-%.c
+	cp $< $@
+
+CFLAGS-tst-ibm128-warn.c += -mabi=ibmlongdouble -Wno-psabi
+
+CFLAGS-tst-ibm128-error-err.c += -mabi=ibmlongdouble -Wno-psabi
+CFLAGS-tst-ibm128-error-errx.c += -mabi=ibmlongdouble -Wno-psabi
+CFLAGS-tst-ibm128-error-verr.c += -mabi=ibmlongdouble -Wno-psabi
+CFLAGS-tst-ibm128-error-verrx.c += -mabi=ibmlongdouble -Wno-psabi
+
+CFLAGS-tst-ibm128-error-error.c += -mabi=ibmlongdouble -Wno-psabi
+CFLAGS-tst-ibm128-error-error_at_line.c += -mabi=ibmlongdouble -Wno-psabi
+
+CFLAGS-tst-ieee128-warn.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+
+CFLAGS-tst-ieee128-error-err.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ieee128-error-errx.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ieee128-error-verr.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ieee128-error-verrx.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+
+CFLAGS-tst-ieee128-error-error.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ieee128-error-error_at_line.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-ibm128-warn.out
+
+tests-special += $(objpfx)tst-ibm128-error-err.out
+tests-special += $(objpfx)tst-ibm128-error-errx.out
+tests-special += $(objpfx)tst-ibm128-error-verr.out
+tests-special += $(objpfx)tst-ibm128-error-verrx.out
+
+tests-special += $(objpfx)tst-ibm128-error-error.out
+tests-special += $(objpfx)tst-ibm128-error-error_at_line.out
+
+tests-special += $(objpfx)tst-ieee128-warn.out
+
+tests-special += $(objpfx)tst-ieee128-error-err.out
+tests-special += $(objpfx)tst-ieee128-error-errx.out
+tests-special += $(objpfx)tst-ieee128-error-verr.out
+tests-special += $(objpfx)tst-ieee128-error-verrx.out
+
+tests-special += $(objpfx)tst-ieee128-error-error.out
+tests-special += $(objpfx)tst-ieee128-error-error_at_line.out
+endif
+
+$(objpfx)tst-%-warn.out: \
+  tst-ldbl-warn.sh $(objpfx)tst-%-warn
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-ibm128-error-%.out: \
+  tst-ldbl-error.sh $(objpfx)tst-ibm128-error-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-ieee128-error-%.out: \
+  tst-ldbl-error.sh $(objpfx)tst-ieee128-error-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
 endif
 
 # Add IEEE binary128 files as make targets.

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=619bafe2614c4b50b50467e3e1a7d1137b8d178e

commit 619bafe2614c4b50b50467e3e1a7d1137b8d178e
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sat Jun 16 16:56:43 2018 -0300

    ldbl-128ibm-compat: Add error.h functions
    
    Use the recently added, internal functions, __error_at_line_internal and
    __error_internal, to provide error.h functions that can take long double
    arguments with IEEE binary128 format on platforms where long double can
    also take double format or some non-IEEE format (currently, this means
    powerpc64le).
    
    Tested for powerpc64le.
    
    	* misc/errorP.h: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == misc] (ldbl-extra-routines): Add error.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__error_at_lineieee128 and __errorieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-error.c: New file.

diff --git a/misc/errorP.h b/misc/errorP.h
new file mode 100644
index 0000000..c61c49c
--- /dev/null
+++ b/misc/errorP.h
@@ -0,0 +1,28 @@
+/* Prototypes for internal error.h functions.
+   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 <stdarg.h>
+
+void
+__error_internal (int status, int errnum, const char *message,
+		  va_list args, unsigned int mode_flags);
+
+void
+__error_at_line_internal (int status, int errnum, const char *file_name,
+			  unsigned int line_number, const char *message,
+			  va_list args, unsigned int mode_flags);
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index fb2b15e..151dd76 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -245,7 +245,8 @@ $(objpfx)tst-ibm128-argp-%.out: \
 endif
 
 ifeq ($(subdir),misc)
-ldbl-extra-routines += err
+ldbl-extra-routines += err \
+		       error
 endif
 
 # Add IEEE binary128 files as make targets.
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index e2b3dda..dead38c 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -192,5 +192,8 @@ libc {
     __errxieee128;
     __verrieee128;
     __verrxieee128;
+
+    __errorieee128;
+    __error_at_lineieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-error.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-error.c
new file mode 100644
index 0000000..9c74e06
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-error.c
@@ -0,0 +1,51 @@
+/* Wrappers for error.h functions.  IEEE128 version.
+   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 <stdarg.h>
+#include <misc/errorP.h>
+#include <libio/libioP.h>
+
+#define IEEE128_ALIAS(name) \
+  strong_alias (___ieee128_##name, __##name##ieee128)
+
+#define IEEE128_DECL(name) ___ieee128_##name
+
+void
+IEEE128_DECL (error) (int status, int errnum, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_internal (status, errnum, message, ap,
+		    PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+}
+IEEE128_ALIAS (error)
+
+void
+IEEE128_DECL (error_at_line) (int status, int errnum,
+			      const char *file_name,
+			      unsigned int line_number,
+			      const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_at_line_internal (status, errnum, file_name, line_number,
+			    message, ap, PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+}
+IEEE128_ALIAS (error_at_line)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2df00dbe0e516edf7cf0a86d7ad3b761b2f6e4a8

commit 2df00dbe0e516edf7cf0a86d7ad3b761b2f6e4a8
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Fri Jun 15 11:24:05 2018 -0300

    ldbl-128ibm-compat: Add err.h functions
    
    Use the recently added, internal functions, __vwarnx_internal and
    __vwarn_internal, to provide err.h functions that can take long double
    arguments with IEEE binary128 format on platforms where long double can
    also take double format or some non-IEEE format (currently, this means
    powerpc64le).
    
    Tested for powerpc64le.
    
    	* misc/errP.h: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == misc] (ldbl-extra-routines): Add err.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__warnieee128, __warnxieee128, __vwarnieee128, __vwarnxieee128
    	__errieee128, __errxieee128, __verrieee128, and __verrxieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-err.c: New file.

diff --git a/misc/errP.h b/misc/errP.h
new file mode 100644
index 0000000..09e1f72
--- /dev/null
+++ b/misc/errP.h
@@ -0,0 +1,28 @@
+/* Prototypes for internal err.h functions.
+   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 <stdarg.h>
+#include <err.h>
+
+void
+__vwarnx_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags);
+
+void
+__vwarn_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags);
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 25d7d3c..fb2b15e 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -244,6 +244,10 @@ $(objpfx)tst-ibm128-argp-%.out: \
 	$(evaluate-test)
 endif
 
+ifeq ($(subdir),misc)
+ldbl-extra-routines += err
+endif
+
 # Add IEEE binary128 files as make targets.
 routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 8e80b2b..e2b3dda 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -183,5 +183,14 @@ libc {
 
     __argp_errorieee128;
     __argp_failureieee128;
+
+    __warnieee128;
+    __warnxieee128;
+    __vwarnieee128;
+    __vwarnxieee128;
+    __errieee128;
+    __errxieee128;
+    __verrieee128;
+    __verrxieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-err.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-err.c
new file mode 100644
index 0000000..8a34508
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-err.c
@@ -0,0 +1,93 @@
+/* Wrappers for err.h functions.  IEEE128 version.
+   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 <stdarg.h>
+#include <misc/errP.h>
+#include <libio/libioP.h>
+
+#define VA(call)							\
+{									\
+  va_list ap;								\
+  va_start (ap, format);						\
+  IEEE128_CALL (call);							\
+  va_end (ap);								\
+}
+
+#define IEEE128_ALIAS(name) \
+  strong_alias (___ieee128_##name, __##name##ieee128)
+
+#define IEEE128_DECL(name) ___ieee128_##name
+#define IEEE128_CALL(name) ___ieee128_##name
+
+void
+IEEE128_DECL (vwarn) (const char *format, __gnuc_va_list ap)
+{
+  __vwarn_internal (format, ap, PRINTF_LDBL_USES_FLOAT128);
+}
+IEEE128_ALIAS (vwarn)
+
+void
+IEEE128_DECL (vwarnx) (const char *format, __gnuc_va_list ap)
+{
+  __vwarnx_internal (format, ap, PRINTF_LDBL_USES_FLOAT128);
+}
+IEEE128_ALIAS (vwarnx)
+
+void
+IEEE128_DECL (warn) (const char *format, ...)
+{
+  VA (vwarn (format, ap))
+}
+IEEE128_ALIAS (warn)
+
+void
+IEEE128_DECL (warnx) (const char *format, ...)
+{
+  VA (vwarnx (format, ap))
+}
+IEEE128_ALIAS (warnx)
+
+void
+IEEE128_DECL (verr) (int status, const char *format, __gnuc_va_list ap)
+{
+  IEEE128_CALL (vwarn) (format, ap);
+  exit (status);
+}
+IEEE128_ALIAS (verr)
+
+void
+IEEE128_DECL (verrx) (int status, const char *format, __gnuc_va_list ap)
+{
+  IEEE128_CALL (vwarnx) (format, ap);
+  exit (status);
+}
+IEEE128_ALIAS (verrx)
+
+void
+IEEE128_DECL (err) (int status, const char *format, ...)
+{
+  VA (verr (status, format, ap))
+}
+IEEE128_ALIAS (err)
+
+void
+IEEE128_DECL (errx) (int status, const char *format, ...)
+{
+  VA (verrx (status, format, ap))
+}
+IEEE128_ALIAS (errx)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=440d8a6c7e476534bfa3e41deb0671a075513c40

commit 440d8a6c7e476534bfa3e41deb0671a075513c40
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Jun 12 22:27:21 2018 -0300

    ldbl-128ibm-compat: Add argp_error and argp_failure
    
    Use the recently added, internal functions, __argp_error_internal and
    __argp_failure_internal, to provide argp_error and argp_failure that can
    take long double arguments with IEEE binary128 format on platforms where
    long double can also take double format or some non-IEEE format
    (currently, this means powerpc64le).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == argp] (ldbl-extra-routines): Add argp-help.
    	[subdir == argp] ($(objpfx)tst-ieee128-argp-%.c)
    	($(objpfx)tst-ibm128-argp-%.c): New rule to copy the test from
    	the non-sysdeps directory to the build directory.
    	[subdir == argp] (tests-internal): Add tst-ieee128-argp-error,
    	tst-ibm128-argp-error, tst-ieee128-argp-failure, and
    	tst-ibm128-argp-failure.
    	[subdir == argp] (CFLAGS-tst-ieee128-argp-error.c): New variable.
    	[subdir == argp] (CFLAGS-tst-ibm128-argp-error.c): Likewise.
    	[subdir == argp] (CFLAGS-tst-ieee128-argp-failure.c): Likewise.
    	[subdir == argp] (CFLAGS-tst-ibm128-argp-failure.c): Likewise.
    	[subdir == argp && run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-ieee128-argp-error.out,
    	$(objpfx)tst-ibm128-argp-error.out,
    	$(objpfx)tst-ieee128-argp-failure.out, and
    	$(objpfx)tst-ibm128-argp-failure.out.
    	[subdir == argp] ($(objpfx)tst-ieee128-argp-%.out)
    	($(objpfx)tst-ibm128-argp-%.out): New build and run rule.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__argp_errorieee128 and __argp_failureieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-argp-help.c: New file.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index b6ea1db..25d7d3c 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -209,6 +209,41 @@ $(objpfx)test-wprintf-chk-ibm128.out: \
 	$(evaluate-test)
 endif
 
+ifeq ($(subdir),argp)
+ldbl-extra-routines += argp-help
+
+$(objpfx)tst-ieee128-argp-%.c: tst-ldbl-argp-%.c
+	cp $< $@
+
+$(objpfx)tst-ibm128-argp-%.c: tst-ldbl-argp-%.c
+	cp $< $@
+
+tests-internal += tst-ieee128-argp-error tst-ibm128-argp-error
+CFLAGS-tst-ieee128-argp-error.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ibm128-argp-error.c += -mabi=ibmlongdouble -Wno-psabi
+
+tests-internal += tst-ieee128-argp-failure tst-ibm128-argp-failure
+CFLAGS-tst-ieee128-argp-failure.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-tst-ibm128-argp-failure.c += -mabi=ibmlongdouble -Wno-psabi
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-ieee128-argp-error.out
+tests-special += $(objpfx)tst-ibm128-argp-error.out
+tests-special += $(objpfx)tst-ieee128-argp-failure.out
+tests-special += $(objpfx)tst-ibm128-argp-failure.out
+endif
+
+$(objpfx)tst-ieee128-argp-%.out: \
+  tst-ldbl-argp-%.sh $(objpfx)tst-ieee128-argp-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-ibm128-argp-%.out: \
+  tst-ldbl-argp-%.sh $(objpfx)tst-ibm128-argp-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+endif
+
 # Add IEEE binary128 files as make targets.
 routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 8b23fdf..8e80b2b 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -180,5 +180,8 @@ libc {
     __vfwscanfieee128;
     __vswscanfieee128;
     __vwscanfieee128;
+
+    __argp_errorieee128;
+    __argp_failureieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-argp-help.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-argp-help.c
new file mode 100644
index 0000000..fe77e63
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-argp-help.c
@@ -0,0 +1,42 @@
+/* Wrapper for argp_error and argp_failure.  IEEE128 version.
+   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 <argp.h>
+#include <libio/libioP.h>
+
+void
+___ieee128_argp_error (const struct argp_state *state, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_error_internal (state, fmt, ap, PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+}
+strong_alias (___ieee128_argp_error, __argp_errorieee128)
+
+void
+___ieee128_argp_failure (const struct argp_state *state, int status,
+			int errnum, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_failure_internal (state, status, errnum, fmt, ap,
+			   PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+}
+strong_alias (___ieee128_argp_failure, __argp_failureieee128)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b687302d4f24ba05c0b96b9d3b14fffe73af1f89

commit b687302d4f24ba05c0b96b9d3b14fffe73af1f89
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon Jun 11 15:48:48 2018 -0300

    ldbl-128ibm-compat: Add wide character scanning functions
    
    Similarly to what was done for regular character scanning functions,
    this patch uses the new mode mask, SCANF_LDBL_USES_FLOAT128, in the
    'mode' argument of the wide characters scanning function,
    __vfwscanf_internal (which is also extended to support scanning
    floating-point values with IEEE binary128, by redirecting calls to
    __wcstold_internal to __wcstof128_internal).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == libio] (ldbl-extra-routines): Add fwscanf, swscanf,
    	wscanf, vswscanf, and vwscanf
    	[subdir == stdio-common] (ldbl-extra-routines): Add vfwscanf.
    	(CFLAGS-vfwscanf-internal.c): Add -mfloat128 to the compiler
    	command used to build vfwscanf-internal.c.  This is needed to
    	extend __vfwscanf_internal with the support to redirect the call
    	to __wcstold_internal to __wcstof128_internal.
    	(tests-internal): Add test-wscanf-ieee128 and test-wscanf-ibm128.
    	(CFLAGS-test-wscanf-ieee128.c): New variable.
    	(CFLAGS-test-wscanf-ibm128.c): Likewise.
    	($(objpfx)test-wscanf-ieee128): Link the loader after libgcc.
    	[run-built-tests] (tests-special): Add
    	$(objpfx)test-wscanf-ieee128.out and
    	$(objpfx)test-wscanf-ibm128.out.
    	($(objpfx)test-wscanf-ieee128.out): New build and run rules.
    	($(objpfx)test-wscanf-ibm128.out): Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions: Add
    	__fwscanfieee128, __swscanfieee128, __wscanfieee128,
    	__vfwscanfieee128, __vswscanfieee128, and __vwscanfieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwscanf.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ibm128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ieee128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ldbl-compat.c:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 0040bfb..b6ea1db 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -1,3 +1,11 @@
+ifeq ($(subdir),libio)
+ldbl-extra-routines += fwscanf \
+		       swscanf \
+		       wscanf \
+		       vswscanf \
+		       vwscanf
+endif
+
 ifeq ($(subdir),stdio-common)
 ldbl-extra-routines += printf_size \
 		       asprintf \
@@ -23,7 +31,8 @@ ldbl-extra-routines += printf_size \
 		       sscanf \
 		       vfscanf \
 		       vscanf \
-		       vsscanf
+		       vsscanf \
+		       vfwscanf
 
 # Printing long double values with IEEE binary128 format reuses part
 # of the internal float128 implementation (__printf_fp, __printf_fphex,
@@ -33,6 +42,7 @@ ldbl-extra-routines += printf_size \
 CFLAGS-vfprintf-internal.c += -mfloat128
 CFLAGS-vfwprintf-internal.c += -mfloat128
 CFLAGS-vfscanf-internal.c += -mfloat128
+CFLAGS-vfwscanf-internal.c += -mfloat128
 
 # Basic tests for the implementation of long double with IEEE binary128
 # format and for the related redirections in installed headers.
@@ -50,6 +60,12 @@ CFLAGS-test-scanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
 $(objpfx)test-scanf-ieee128: gnulib-tests += $(f128-loader-link)
 
+tests-internal += test-wscanf-ieee128 test-wscanf-ibm128
+CFLAGS-test-wscanf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-wscanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+$(objpfx)test-wscanf-ieee128: gnulib-tests += $(f128-loader-link)
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)test-printf-ieee128.out
 tests-special += $(objpfx)test-printf-ibm128.out
@@ -59,6 +75,9 @@ tests-special += $(objpfx)test-wprintf-ibm128.out
 
 tests-special += $(objpfx)test-scanf-ieee128.out
 tests-special += $(objpfx)test-scanf-ibm128.out
+
+tests-special += $(objpfx)test-wscanf-ieee128.out
+tests-special += $(objpfx)test-wscanf-ibm128.out
 endif
 
 $(objpfx)test-printf-ieee128.out: \
@@ -97,6 +116,18 @@ $(objpfx)test-scanf-ibm128.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 
+$(objpfx)test-wscanf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh \
+  $(objpfx)test-wscanf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-wscanf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh \
+  $(objpfx)test-wscanf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-size-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 7971c7a..8b23fdf 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -172,5 +172,13 @@ libc {
     __vfscanfieee128;
     __vscanfieee128;
     __vsscanfieee128;
+
+    __fwscanfieee128;
+    __swscanfieee128;
+    __wscanfieee128;
+
+    __vfwscanfieee128;
+    __vswscanfieee128;
+    __vwscanfieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwscanf.c
new file mode 100644
index 0000000..b4b10cf
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwscanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for fwscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libioP.h>
+
+extern int
+___ieee128_fwscanf (FILE *fp, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (fp, format, ap,
+			      SCANF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_fwscanf, __fwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c
new file mode 100644
index 0000000..c7dfc24
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swscanf.c
@@ -0,0 +1,40 @@
+/* Wrapper for swscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_swscanf (const wchar_t *string, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *fp = _IO_strfile_readw (&sf, &wd, string);
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (fp, format, ap,
+			      SCANF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_swscanf, __swscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwscanf.c
new file mode 100644
index 0000000..de4918f
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vfwscanf.  IEEE128 version.
+   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>
+
+extern int
+___ieee128_vfwscanf (FILE *fp, const wchar_t *format, va_list ap)
+{
+  return __vfwscanf_internal (fp, format, ap,
+			      SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vfwscanf, __vfwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c
new file mode 100644
index 0000000..a241d6b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswscanf.c
@@ -0,0 +1,32 @@
+/* Wrapper for vswscanf.  IEEE128 version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+#include <wchar.h>
+#include <strfile.h>
+
+extern int
+___ieee128_vswscanf (const wchar_t *string, const wchar_t *format,
+		     va_list ap)
+{
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *fp = _IO_strfile_readw (&sf, &wd, string);
+  return __vfwscanf_internal (fp, format, ap, SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vswscanf, __vswscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwscanf.c
new file mode 100644
index 0000000..0944794
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwscanf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vwscanf.  IEEE128 version.
+   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>
+
+extern int
+___ieee128_vwscanf (const wchar_t *format, va_list ap)
+{
+  return __vfwscanf_internal (stdin, format, ap,
+			      SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vwscanf, __vwscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wscanf.c
new file mode 100644
index 0000000..417f326
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wscanf.c
@@ -0,0 +1,35 @@
+/* Wrapper for wscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libioP.h>
+
+extern int
+___ieee128_wscanf (const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfwscanf_internal (stdin, format, ap,
+			      SCANF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_wscanf, __wscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ibm128.c
new file mode 100644
index 0000000..ef21fc4
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ibm128.c
@@ -0,0 +1 @@
+#include <test-wscanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ieee128.c
new file mode 100644
index 0000000..ef21fc4
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ieee128.c
@@ -0,0 +1 @@
+#include <test-wscanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ldbl-compat.c
new file mode 100644
index 0000000..e93cf3b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wscanf-ldbl-compat.c
@@ -0,0 +1,10 @@
+#define CHAR wchar_t
+#define L(x) L##x
+#define FSCANF fwscanf
+#define SSCANF swscanf
+#define SCANF wscanf
+#define VFSCANF vfwscanf
+#define VSSCANF vswscanf
+#define VSCANF vwscanf
+#define STRCPY wcscpy
+#include <test-scanf-ldbl-compat-template.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f9c5ecbb01d8fb6b2fde8820084a57e0f48a262b

commit f9c5ecbb01d8fb6b2fde8820084a57e0f48a262b
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon Jun 11 00:12:28 2018 -0300

    ldbl-128ibm-compat: Add regular character scanning functions
    
    The 'mode' argument to __vfscanf_internal allows the selection of the
    long double format for all long double arguments requested by the format
    string.  Currently, there are two possibilities: long double with the
    same format as double or long double as something else.  The 'something
    else' format varies between architectures, and on powerpc64le, it means
    IBM Extended Precision format.
    
    In preparation for the third option of long double format on
    powerpc64le, this patch uses the new mode mask,
    SCANF_LDBL_USES_FLOAT128, which tells __vfscanf_internal to call
    __strtof128_internal, instead of __strtold_internal, and save the output
    into a _Float128 variable.
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == stdio-common] (ldbl-extra-routines): Add fscanf,
    	scanf, sscanf, vfscanf, vscanf, and vsscanf.
    	(CFLAGS-vfscanf-internal.c): Add -mfloat128 to the compiler
    	command used to build vfscanf-internal.c.  This is needed to
    	extend __vfscanf_internal with the support to redirect the call
    	to __strtold_internal to __strtof128_internal.
    	(tests-internal): Add test-scanf-ieee128 and test-scanf-ibm128.
    	(CFLAGS-test-scanf-ieee128.c): New variable.
    	(CFLAGS-test-scanf-ibm128.c): Likewise.
    	($(objpfx)test-scanf-ieee128): Link the loader after libgcc.
    	[run-built-tests] (tests-special): Add
    	$(objpfx)test-scanf-ieee128.out and
    	$(objpfx)test-scanf-ibm128.out.
    	($(objpfx)test-scanf-ieee128.out): New build and run rule.
    	($(objpfx)test-scanf-ibm128.out): Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__fscanfieee128, __scanfieee128, __sscanfieee128,
    	__vfscanfieee128, __vscanfieee128, and __vsscanfieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fscanf.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-scanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vscanf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsscanf.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 028f1ef..0040bfb 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -17,14 +17,22 @@ ldbl-extra-routines += printf_size \
 		       wprintf \
 		       vfwprintf \
 		       vswprintf \
-		       vwprintf
+		       vwprintf \
+		       fscanf \
+		       scanf \
+		       sscanf \
+		       vfscanf \
+		       vscanf \
+		       vsscanf
 
 # Printing long double values with IEEE binary128 format reuses part
 # of the internal float128 implementation (__printf_fp, __printf_fphex,
-# and __float128 variables and union members).  Thus, the compilation of
-# the following functions, must have -mfloat128 passed to the compiler.
+# and __float128 variables and union members).  Likewise, reading these
+# values reuses __strtof128_internal.  Thus, the compilation of the
+# following functions, must have -mfloat128 passed to the compiler.
 CFLAGS-vfprintf-internal.c += -mfloat128
 CFLAGS-vfwprintf-internal.c += -mfloat128
+CFLAGS-vfscanf-internal.c += -mfloat128
 
 # Basic tests for the implementation of long double with IEEE binary128
 # format and for the related redirections in installed headers.
@@ -36,12 +44,21 @@ tests-internal += test-wprintf-ieee128 test-wprintf-ibm128
 CFLAGS-test-wprintf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-wprintf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
+tests-internal += test-scanf-ieee128 test-scanf-ibm128
+CFLAGS-test-scanf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-scanf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+$(objpfx)test-scanf-ieee128: gnulib-tests += $(f128-loader-link)
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)test-printf-ieee128.out
 tests-special += $(objpfx)test-printf-ibm128.out
 
 tests-special += $(objpfx)test-wprintf-ieee128.out
 tests-special += $(objpfx)test-wprintf-ibm128.out
+
+tests-special += $(objpfx)test-scanf-ieee128.out
+tests-special += $(objpfx)test-scanf-ibm128.out
 endif
 
 $(objpfx)test-printf-ieee128.out: \
@@ -68,6 +85,18 @@ $(objpfx)test-wprintf-ibm128.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 
+$(objpfx)test-scanf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh \
+  $(objpfx)test-scanf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-scanf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh \
+  $(objpfx)test-scanf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-size-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index e438c7c..7971c7a 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -164,5 +164,13 @@ libc {
     __vfwprintf_chkieee128;
     __vswprintf_chkieee128;
     __vwprintf_chkieee128;
+
+    __fscanfieee128;
+    __scanfieee128;
+    __sscanfieee128;
+
+    __vfscanfieee128;
+    __vscanfieee128;
+    __vsscanfieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fscanf.c
new file mode 100644
index 0000000..f51e822
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fscanf.c
@@ -0,0 +1,34 @@
+/* Wrapper for fscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_fscanf (FILE *fp, const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = __vfscanf_internal (fp, format, arg, SCANF_LDBL_USES_FLOAT128);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_fscanf, __fscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-scanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-scanf.c
new file mode 100644
index 0000000..571cf7d
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-scanf.c
@@ -0,0 +1,34 @@
+/* Wrapper for scanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_scanf (const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = __vfscanf_internal (stdin, format, arg, SCANF_LDBL_USES_FLOAT128);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_scanf, __scanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sscanf.c
new file mode 100644
index 0000000..7c93295
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sscanf.c
@@ -0,0 +1,38 @@
+/* Wrapper for sscanf.  IEEE128 version.
+   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 <stdarg.h>
+#include <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_sscanf (const char *string, const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  _IO_strfile sf;
+  FILE *fp = _IO_strfile_read (&sf, string);
+
+  va_start (arg, format);
+  done = __vfscanf_internal (fp, format, arg, SCANF_LDBL_USES_FLOAT128);
+  va_end (arg);
+
+  return done;
+}
+strong_alias (___ieee128_sscanf, __sscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfscanf.c
new file mode 100644
index 0000000..d6654e0
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfscanf.c
@@ -0,0 +1,26 @@
+/* Wrapper for vfscanf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vfscanf (FILE *fp, const char *format, va_list ap)
+{
+  return __vfscanf_internal (fp, format, ap, SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vfscanf, __vfscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vscanf.c
new file mode 100644
index 0000000..5780c06
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vscanf.c
@@ -0,0 +1,26 @@
+/* Wrapper for vscanf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vscanf (const char *format, va_list ap)
+{
+  return __vfscanf_internal (stdin, format, ap, SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vscanf, __vscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsscanf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsscanf.c
new file mode 100644
index 0000000..8ff43a9
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsscanf.c
@@ -0,0 +1,29 @@
+/* Wrapper for vsscanf.  IEEE128 version.
+   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 <strfile.h>
+#include <libioP.h>
+
+extern int
+___ieee128_vsscanf (const char *string, const char *format, va_list ap)
+{
+  _IO_strfile sf;
+  FILE *fp = _IO_strfile_read (&sf, string);
+  return __vfscanf_internal (fp, format, ap, SCANF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vsscanf, __vsscanfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ibm128.c
new file mode 100644
index 0000000..8cdee60
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ibm128.c
@@ -0,0 +1 @@
+#include <test-scanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ieee128.c
new file mode 100644
index 0000000..8cdee60
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ieee128.c
@@ -0,0 +1 @@
+#include <test-scanf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
new file mode 100644
index 0000000..4590e9d
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat-template.c
@@ -0,0 +1,117 @@
+/* Test for the long double variants of *scanf functions.
+   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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <support/check.h>
+
+#define CLEAR								\
+  va_start (args, format);						\
+  ld = va_arg (args, long double *);					\
+  *ld = 0;								\
+  va_end (args);
+
+#define CLEAR_VALUE value = 0;
+
+#define CHECK								\
+  va_start (args, format);						\
+  ld = va_arg (args, long double *);					\
+  va_end (args);							\
+  if (*ld == -1.0L)							\
+    printf ("OK");							\
+  else									\
+    printf ("ERROR (%.60Lf)", *ld);					\
+  printf ("\n");
+
+#define CHECK_VALUE							\
+  if (value == -1.0L)							\
+    printf ("OK");							\
+  else									\
+    printf ("ERROR (%.60Lf)", value);					\
+  printf ("\n");
+
+static void
+do_test_call (FILE *stream, CHAR *string, const CHAR *format, ...)
+{
+  long double value;
+  long double *ld;
+  va_list args;
+
+  CLEAR_VALUE
+  printf ("fscanf: ");
+  FSCANF (stream, format, &value);
+  CHECK_VALUE
+
+  CLEAR_VALUE
+  printf ("scanf: ");
+  SCANF (format, &value);
+  CHECK_VALUE
+
+  CLEAR_VALUE
+  printf ("sscanf: ");
+  SSCANF (string, format, &value);
+  CHECK_VALUE
+
+  CLEAR
+  printf ("vfscanf: ");
+  va_start (args, format);
+  VFSCANF (stream, format, args);
+  va_end (args);
+  CHECK
+
+  CLEAR
+  printf ("vscanf: ");
+  va_start (args, format);
+  VSCANF (format, args);
+  va_end (args);
+  CHECK
+
+  CLEAR
+  printf ("vsscanf: ");
+  va_start (args, format);
+  VSSCANF (string, format, args);
+  va_end (args);
+  CHECK
+}
+
+static int
+do_test (void)
+{
+  CHAR string[256];
+  long double ld;
+
+  /* Scan in decimal notation.  */
+  STRCPY (string,
+	  L ("-1.0\n")
+	  L ("-1.0\n") );
+  do_test_call (stdin, string, L("%Lf"), &ld);
+
+  /* Scan in hexadecimal notation.  */
+  STRCPY (string,
+	  L ("-0x1.0p+0\n")
+	  L ("-0x1.0p+0\n") );
+  do_test_call (stdin, string, L("%La"), &ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.c
new file mode 100644
index 0000000..0759d8a
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.c
@@ -0,0 +1,10 @@
+#define CHAR char
+#define L(x) x
+#define FSCANF fscanf
+#define SSCANF sscanf
+#define SCANF scanf
+#define VFSCANF vfscanf
+#define VSSCANF vsscanf
+#define VSCANF vscanf
+#define STRCPY strcpy
+#include <test-scanf-ldbl-compat-template.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh
new file mode 100644
index 0000000..822b4c3
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-scanf-ldbl-compat.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Testing of *scanf.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+cat <<'EOF' |
+-1.000000000000000000000000000000000000000000000000000000000000
+-1.000000000000000000000000000000000000000000000000000000000000
+-1.000000000000000000000000000000000000000000000000000000000000
+-1.000000000000000000000000000000000000000000000000000000000000
+-0x1.000000000000000000000000000000000000000000000000000000000000p+0
+-0x1.000000000000000000000000000000000000000000000000000000000000p+0
+-0x1.000000000000000000000000000000000000000000000000000000000000p+0
+-0x1.000000000000000000000000000000000000000000000000000000000000p+0
+EOF
+${test_program_prefix} \
+  ${test_program} \
+  - \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+fscanf: OK
+scanf: OK
+sscanf: OK
+vfscanf: OK
+vscanf: OK
+vsscanf: OK
+fscanf: OK
+scanf: OK
+sscanf: OK
+vfscanf: OK
+vscanf: OK
+vsscanf: OK
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3892592567ee9d8001c5528dd31b879446a058e2

commit 3892592567ee9d8001c5528dd31b879446a058e2
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sun Jun 17 17:32:39 2018 -0300

    ldbl-128ibm-compat: Test double values
    
    A single format string can take double and long double parameters at the
    same time.  Internally, these parameters are routed to the same
    function, which correctly reads them and calls the underlying functions
    responsible for the actual conversion to string.  This patch adds a new
    case to test this scenario.
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c:
    	(do_test_call_rarg): Add parameter and use it in the calls
    	to *printf functions under test.
    	(do_test): Add variable and use it in the calls to
    	do_test_call_rarg and do_test_call_varg.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh:
    	Modify expected result.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
index 64d686e..42a1e98 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
@@ -77,13 +77,13 @@ do_test_call_varg (FILE *stream, const char *format, ...)
 }
 
 static void
-do_test_call_rarg (FILE *stream, const char *format, long double ld)
+do_test_call_rarg (FILE *stream, const char *format, long double ld, double d)
 {
   char *buffer = NULL;
   char string[128];
 
   printf ("%20s", "asprintf: ");
-  asprintf (&buffer, format, ld);
+  asprintf (&buffer, format, ld, d);
   if (buffer == NULL)
     printf ("Error using asprintf\n");
   else
@@ -94,24 +94,24 @@ do_test_call_rarg (FILE *stream, const char *format, long double ld)
   printf ("\n");
 
   printf ("%20s", "dprintf: ");
-  dprintf (1, format, ld);
+  dprintf (1, format, ld, d);
   printf ("\n");
 
   printf ("%20s", "fprintf: ");
-  fprintf (stdout, format, ld);
+  fprintf (stdout, format, ld, d);
   printf ("\n");
 
   printf ("%20s", "printf: ");
-  printf (format, ld);
+  printf (format, ld, d);
   printf ("\n");
 
   printf ("%20s", "snprintf: ");
-  snprintf (string, 127, format, ld);
+  snprintf (string, 127, format, ld, d);
   printf ("%s", string);
   printf ("\n");
 
   printf ("%20s", "sprintf: ");
-  sprintf (string, format, ld);
+  sprintf (string, format, ld, d);
   printf ("%s", string);
   printf ("\n");
 }
@@ -120,14 +120,15 @@ static int
 do_test (void)
 {
   long double ld = -1;
+  double d = -1;
 
   /* Print in decimal notation.  */
-  do_test_call_rarg (stdout, "%.60Lf", ld);
-  do_test_call_varg (stdout, "%.60Lf", ld);
+  do_test_call_rarg (stdout, "%.60Lf, %f", ld, d);
+  do_test_call_varg (stdout, "%.60Lf, %f", ld, d);
 
   /* Print in hexadecimal notation.  */
-  do_test_call_rarg (stdout, "%.60La", ld);
-  do_test_call_varg (stdout, "%.60La", ld);
+  do_test_call_rarg (stdout, "%.60La, %a", ld, d);
+  do_test_call_varg (stdout, "%.60La, %a", ld, d);
 
   return 0;
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh
index 62bc5d0..b728c32 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh
@@ -30,30 +30,30 @@ ${test_program_prefix} \
   > ${test_program_output} || status=1
 
 cat <<'EOF' |
-          asprintf: -1.000000000000000000000000000000000000000000000000000000000000
-           dprintf: -1.000000000000000000000000000000000000000000000000000000000000
-           fprintf: -1.000000000000000000000000000000000000000000000000000000000000
-            printf: -1.000000000000000000000000000000000000000000000000000000000000
-          snprintf: -1.000000000000000000000000000000000000000000000000000000000000
-           sprintf: -1.000000000000000000000000000000000000000000000000000000000000
-         vasprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          vdprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          vfprintf: -1.000000000000000000000000000000000000000000000000000000000000
-           vprintf: -1.000000000000000000000000000000000000000000000000000000000000
-         vsnprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          vsprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          asprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-           dprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-           fprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-            printf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          snprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-           sprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-         vasprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          vdprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          vfprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-           vprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-         vsnprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          vsprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          asprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+           dprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+           fprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+            printf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          snprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+           sprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+         vasprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          vdprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          vfprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+           vprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+         vsnprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          vsprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          asprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+           dprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+           fprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+            printf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          snprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+           sprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+         vasprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          vdprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          vfprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+           vprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+         vsnprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          vsprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
 EOF
 cmp - ${test_program_output} > /dev/null 2>&1 ||
 {
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c
index 67ddbc9..71ac3e2 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c
@@ -50,21 +50,22 @@ do_test_call_varg (FILE *stream, const wchar_t *format, ...)
 }
 
 static void
-do_test_call_rarg (FILE *stream, const wchar_t *format, long double ld)
+do_test_call_rarg (FILE *stream, const wchar_t *format, long double ld,
+		   double d)
 {
   wchar_t string[128];
 
   wprintf (L"%20Ls", L"fwprintf: ");
-  fwprintf (stream, format, ld);
+  fwprintf (stream, format, ld, d);
   wprintf (L"\n");
 
   wprintf (L"%20Ls", L"swprintf: ");
-  swprintf (string, 127, format, ld);
+  swprintf (string, 127, format, ld, d);
   wprintf (L"%Ls", string);
   wprintf (L"\n");
 
   wprintf (L"%20Ls", L"wprintf: ");
-  wprintf (format, ld);
+  wprintf (format, ld, d);
   wprintf (L"\n");
 }
 
@@ -72,14 +73,15 @@ static int
 do_test (void)
 {
   long double ld = -1;
+  double d = -1;
 
   /* Print in decimal notation.  */
-  do_test_call_rarg (stdout, L"%.60Lf", ld);
-  do_test_call_varg (stdout, L"%.60Lf", ld);
+  do_test_call_rarg (stdout, L"%.60Lf, %f", ld, d);
+  do_test_call_varg (stdout, L"%.60Lf, %f", ld, d);
 
   /* Print in hexadecimal notation.  */
-  do_test_call_rarg (stdout, L"%.60La", ld);
-  do_test_call_varg (stdout, L"%.60La", ld);
+  do_test_call_rarg (stdout, L"%.60La, %a", ld, d);
+  do_test_call_varg (stdout, L"%.60La, %a", ld, d);
 
   return 0;
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh
index 029006e..d05b3bd 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh
@@ -30,18 +30,18 @@ ${test_program_prefix} \
   > ${test_program_output} || status=1
 
 cat <<'EOF' |
-          fwprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          swprintf: -1.000000000000000000000000000000000000000000000000000000000000
-           wprintf: -1.000000000000000000000000000000000000000000000000000000000000
-         vfwprintf: -1.000000000000000000000000000000000000000000000000000000000000
-         vswprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          vwprintf: -1.000000000000000000000000000000000000000000000000000000000000
-          fwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          swprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-           wprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-         vfwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-         vswprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
-          vwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          fwprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          swprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+           wprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+         vfwprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+         vswprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          vwprintf: -1.000000000000000000000000000000000000000000000000000000000000, -1.000000
+          fwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          swprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+           wprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+         vfwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+         vswprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
+          vwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0, -0x1p+0
 EOF
 cmp - ${test_program_output} > /dev/null 2>&1 ||
 {

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f53200e5f9f8a91a55f4ec316cdbfa0e08574676

commit f53200e5f9f8a91a55f4ec316cdbfa0e08574676
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sun Jun 10 22:40:58 2018 -0300

    ldbl-128ibm-compat: Add wide character, fortified printing functions
    
    Similarly to what was done for the regular character, fortified printing
    functions, this patch combines the mode masks PRINTF_LDBL_USES_FLOAT128
    and PRINTF_FORTIFY to provide wide character versions of fortified
    printf functions.
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile:
    	[subdir == debug] (ldbl-extra-routines): Add
    	fwprintf_chk, swprintf_chk, wprintf_chk, vfwprintf_chk,
    	vswprintf_chk, and vwprintf_chk.
    	[subdir == debug] (tests-internal): Add
    	test-wprintf-chk-ieee128 and test-wprintf-chk-ibm128.
    	[subdir == debug] (CFLAGS-test-wprintf-chk-ieee128.c): New
    	variable to add the relevant -mabi flags to the compilation.
    	[subdir == debug] (CFLAGS-test-wprintf-chk-ibm128.c): Likewise.
    	[subdir == debug && run-built-tests == yes]
    	(tests-special): Add $(objpfx)test-wprintf-chk-ieee128.out, and
    	$(objpfx)test-wprintf-chk-ibm128.out.
    	[subdir == debug] ($(objpfx)test-wprintf-chk-ieee128.out):
    	New build and test rule.
    	[subdir == debug] ($(objpfx)test-wprintf-chk-ibm128.out):
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__fwprintf_chkieee128, __swprintf_chkieee128,
    	__wprintf_chkieee128, __vfwprintf_chkieee128,
    	__vswprintf_chkieee128, and __vwprintf_chkieee128;
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf_chk.c:
    	New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf_chk.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 0a6222c..028f1ef 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -100,15 +100,28 @@ ldbl-extra-routines += asprintf_chk \
 		       vfprintf_chk \
 		       vprintf_chk \
 		       vsnprintf_chk \
-		       vsprintf_chk
+		       vsprintf_chk \
+		       fwprintf_chk \
+		       swprintf_chk \
+		       wprintf_chk \
+		       vfwprintf_chk \
+		       vswprintf_chk \
+		       vwprintf_chk
 
 tests-internal += test-printf-chk-ieee128 test-printf-chk-ibm128
 CFLAGS-test-printf-chk-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-chk-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
+tests-internal += test-wprintf-chk-ieee128 test-wprintf-chk-ibm128
+CFLAGS-test-wprintf-chk-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-wprintf-chk-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)test-printf-chk-ieee128.out
 tests-special += $(objpfx)test-printf-chk-ibm128.out
+
+tests-special += $(objpfx)test-wprintf-chk-ieee128.out
+tests-special += $(objpfx)test-wprintf-chk-ibm128.out
 endif
 
 $(objpfx)test-printf-chk-ieee128.out: \
@@ -122,6 +135,18 @@ $(objpfx)test-printf-chk-ibm128.out: \
   $(objpfx)test-printf-chk-ibm128
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
+
+$(objpfx)test-wprintf-chk-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh \
+  $(objpfx)test-wprintf-chk-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-wprintf-chk-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh \
+  $(objpfx)test-wprintf-chk-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
 endif
 
 # Add IEEE binary128 files as make targets.
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index aac08a3..e438c7c 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -156,5 +156,13 @@ libc {
     __vprintf_chkieee128;
     __vsnprintf_chkieee128;
     __vsprintf_chkieee128;
+
+    __fwprintf_chkieee128;
+    __swprintf_chkieee128;
+    __wprintf_chkieee128;
+
+    __vfwprintf_chkieee128;
+    __vswprintf_chkieee128;
+    __vwprintf_chkieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf_chk.c
new file mode 100644
index 0000000..bdf4863
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __fwprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vfwprintf_internal (fp, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_fwprintf_chk, __fwprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf_chk.c
new file mode 100644
index 0000000..411da9a
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf_chk.c
@@ -0,0 +1,42 @@
+/* Wrapper for __swprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_swprintf_chk (wchar_t *string, size_t maxlen, int flag,
+			size_t slen, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  va_start (ap, format);
+  done = __vswprintf_internal (string, maxlen, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_swprintf_chk, __swprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf_chk.c
new file mode 100644
index 0000000..2d6fe6d
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf_chk.c
@@ -0,0 +1,31 @@
+/* Wrapper for __vfwprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vfwprintf_chk (FILE *fp, int flag, const wchar_t *format,
+			 va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (fp, format, ap, mode);
+}
+strong_alias (___ieee128_vfwprintf_chk, __vfwprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf_chk.c
new file mode 100644
index 0000000..702fdda
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf_chk.c
@@ -0,0 +1,34 @@
+/* Wrapper for __vswprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vswprintf_chk (wchar_t *string, size_t maxlen, int flag,
+			 size_t slen, const wchar_t *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  return __vswprintf_internal (string, maxlen, format, ap, mode);
+}
+strong_alias (___ieee128_vswprintf_chk, __vswprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf_chk.c
new file mode 100644
index 0000000..54f763b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf_chk.c
@@ -0,0 +1,30 @@
+/* Wrapper for __vwprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vwprintf_chk (int flag, const wchar_t *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (stdout, format, ap, mode);
+}
+strong_alias (___ieee128_vwprintf_chk, __vwprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf_chk.c
new file mode 100644
index 0000000..82b6d85
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __wprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_wprintf_chk (int flag, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vfwprintf_internal (stdout, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_wprintf_chk, __wprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ibm128.c
new file mode 100644
index 0000000..5323df7
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ibm128.c
@@ -0,0 +1 @@
+#include <test-wprintf-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ieee128.c
new file mode 100644
index 0000000..5323df7
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ieee128.c
@@ -0,0 +1 @@
+#include <test-wprintf-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.c
new file mode 100644
index 0000000..d68e7fd
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.c
@@ -0,0 +1,89 @@
+/* Test for the long double variants of *w*printf_chk functions.
+   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 _FORTIFY_SOURCE 2
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <wchar.h>
+
+#include <support/check.h>
+
+static void
+do_test_call_varg (FILE *stream, const wchar_t *format, ...)
+{
+  wchar_t string[128];
+  va_list args;
+
+  wprintf (L"%20Ls", L"__vfwprintf_chk: ");
+  va_start (args, format);
+  __vfwprintf_chk (stream, 1, format, args);
+  va_end (args);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"__vswprintf_chk: ");
+  va_start (args, format);
+  __vswprintf_chk (string, 79, 1, 127, format, args);
+  va_end (args);
+  wprintf (L"%Ls", string);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"__vwprintf_chk: ");
+  va_start (args, format);
+  __vwprintf_chk (1, format, args);
+  va_end (args);
+  wprintf (L"\n");
+}
+
+static void
+do_test_call_rarg (FILE *stream, const wchar_t *format, long double ld)
+{
+  wchar_t string[128];
+
+  wprintf (L"%20Ls", L"__fwprintf_chk: ");
+  __fwprintf_chk (stream, 1, format, ld);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"__swprintf_chk: ");
+  __swprintf_chk (string, 79, 1, 127, format, ld);
+  wprintf (L"%Ls", string);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"__wprintf_chk: ");
+  __wprintf_chk (1, format, ld);
+  wprintf (L"\n");
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+
+  /* Print in decimal notation.  */
+  do_test_call_rarg (stdout, L"%.60Lf", ld);
+  do_test_call_varg (stdout, L"%.60Lf", ld);
+
+  /* Print in hexadecimal notation.  */
+  do_test_call_rarg (stdout, L"%.60La", ld);
+  do_test_call_varg (stdout, L"%.60La", ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh
new file mode 100644
index 0000000..e87a2ee
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-chk-ldbl-compat.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Testing of *w*printf_chk.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+    __fwprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __swprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+     __wprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+   __vfwprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+   __vswprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __vwprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __fwprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __swprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+     __wprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+   __vfwprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+   __vswprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __vwprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=55bf89ec51e12ce79089fe39f872adfca0f0c771

commit 55bf89ec51e12ce79089fe39f872adfca0f0c771
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sun Jun 10 15:57:48 2018 -0300

    ldbl-128ibm-compat: Add regular character, fortified printing functions
    
    Since the introduction of internal functions with explicit flags for the
    printf family of functions, the 'mode' parameter can be used to select
    which format long double parameters have (with the mode flags:
    PRINTF_LDBL_IS_DBL and PRINTF_LDBL_USES_FLOAT128), as well as to select
    whether to check for overflows (mode flag: PRINTF_FORTIFY).
    
    This patch combines PRINTF_LDBL_USES_FLOAT128 and PRINTF_FORTIFY to
    provide the IEEE binary128 version of printf-like function for platforms
    where long double can take this format, in addition to the double format
    and to some non-ieee format (currently, this means powerpc64le).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile:
    	[subdir == debug] (ldbl-extra-routines): Add
    	asprintf_chk, dprintf_chk, fprintf_chk, printf_chk,
    	snprintf_chk, sprintf_chk, vasprintf_chk, vdprintf_chk,
    	vfprintf_chk, vprintf_chk, vsnprintf_chk, and vsprintf_chk.
    	[subdir == debug] (tests-internal): Add
    	test-printf-chk-ieee128 and test-printf-chk-ibm128.
    	[subdir == debug] (CFLAGS-test-printf-chk-ieee128.c): New
    	variable to add the relevant -mabi flags to the compilation.
    	[subdir == debug] (CFLAGS-test-printf-chk-ibm128.c): Likewise.
    	[subdir == debug && run-built-tests == yes]
    	(tests-special): Add $(objpfx)test-printf-chk-ieee128.out, and
    	$(objpfx)test-printf-chk-ibm128.out.
    	[subdir == debug] ($(objpfx)test-printf-chk-ieee128.out):
    	New build and test rule.
    	[subdir == debug] ($(objpfx)test-printf-chk-ibm128.out):
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__asprintf_chkieee128, __dprintf_chkieee128, __fprintf_chkieee128,
    	__printf_chkieee128, __snprintf_chkieee128, __sprintf_chkieee128,
    	__vasprintf_chkieee128, __vdprintf_chkieee128, __vfprintf_chkieee128,
    	__vprintf_chkieee128, __vsnprintf_chkieee128, __vsprintf_chkieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf_chk.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf_chk.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ibm128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ieee128.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index a44dfb3..0a6222c 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -88,6 +88,42 @@ $(objpfx)test-printf-size-ibm128.out: \
 	$(evaluate-test)
 endif
 
+ifeq ($(subdir),debug)
+ldbl-extra-routines += asprintf_chk \
+		       dprintf_chk \
+		       fprintf_chk \
+		       printf_chk \
+		       snprintf_chk \
+		       sprintf_chk \
+		       vasprintf_chk \
+		       vdprintf_chk \
+		       vfprintf_chk \
+		       vprintf_chk \
+		       vsnprintf_chk \
+		       vsprintf_chk
+
+tests-internal += test-printf-chk-ieee128 test-printf-chk-ibm128
+CFLAGS-test-printf-chk-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-printf-chk-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)test-printf-chk-ieee128.out
+tests-special += $(objpfx)test-printf-chk-ibm128.out
+endif
+
+$(objpfx)test-printf-chk-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh \
+  $(objpfx)test-printf-chk-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-printf-chk-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh \
+  $(objpfx)test-printf-chk-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+endif
+
 # Add IEEE binary128 files as make targets.
 routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 0485a2b..aac08a3 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -142,5 +142,19 @@ libc {
     __vfwprintfieee128;
     __vswprintfieee128;
     __vwprintfieee128;
+
+    __asprintf_chkieee128;
+    __dprintf_chkieee128;
+    __fprintf_chkieee128;
+    __printf_chkieee128;
+    __snprintf_chkieee128;
+    __sprintf_chkieee128;
+
+    __vasprintf_chkieee128;
+    __vdprintf_chkieee128;
+    __vfprintf_chkieee128;
+    __vprintf_chkieee128;
+    __vsnprintf_chkieee128;
+    __vsprintf_chkieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf_chk.c
new file mode 100644
index 0000000..d3b9ee0
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __asprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_asprintf_chk (char **string_ptr, int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vasprintf_internal (string_ptr, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_asprintf_chk, __asprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf_chk.c
new file mode 100644
index 0000000..7b4ce15
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __dprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_dprintf_chk (int d, int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vdprintf_internal (d, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_dprintf_chk, __dprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf_chk.c
new file mode 100644
index 0000000..a1ec25b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __fprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_fprintf_chk (FILE *fp, int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vfprintf_internal (fp, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_fprintf_chk, __fprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf_chk.c
new file mode 100644
index 0000000..b94ec7d
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf_chk.c
@@ -0,0 +1,38 @@
+/* Wrapper for __printf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_printf_chk (int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, format);
+  done = __vfprintf_internal (stdout, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_printf_chk, __printf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf_chk.c
new file mode 100644
index 0000000..5f5c029
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf_chk.c
@@ -0,0 +1,42 @@
+/* Wrapper for __snprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
+			const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  va_start (ap, format);
+  done = __vsnprintf_internal (s, maxlen, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_snprintf_chk, __snprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf_chk.c
new file mode 100644
index 0000000..5419b30
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf_chk.c
@@ -0,0 +1,42 @@
+/* Wrapper for __sprintf_chk.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_sprintf_chk (char *s, int flag, size_t slen,
+		       const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  if (slen == 0)
+    __chk_fail ();
+
+  va_start (ap, format);
+  done = __vsprintf_internal (s, slen, format, ap, mode);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_sprintf_chk, __sprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf_chk.c
new file mode 100644
index 0000000..5b1b5ad
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf_chk.c
@@ -0,0 +1,31 @@
+/* Wrapper for __vasprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vasprintf_chk (char **result_ptr, int flag, const char *format,
+			 va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (result_ptr, format, ap, mode);
+}
+strong_alias (___ieee128_vasprintf_chk, __vasprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf_chk.c
new file mode 100644
index 0000000..b01fcb6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf_chk.c
@@ -0,0 +1,30 @@
+/* Wrapper for __vdprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vdprintf_chk (int d, int flag, const char *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vdprintf_internal (d, format, ap, mode);
+}
+strong_alias (___ieee128_vdprintf_chk, __vdprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf_chk.c
new file mode 100644
index 0000000..d3a4944
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf_chk.c
@@ -0,0 +1,30 @@
+/* Wrapper for __vfprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (fp, format, ap, mode);
+}
+strong_alias (___ieee128_vfprintf_chk, __vfprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf_chk.c
new file mode 100644
index 0000000..c11d36f
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf_chk.c
@@ -0,0 +1,30 @@
+/* Wrapper for __vprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vprintf_chk (int flag, const char *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (stdout, format, ap, mode);
+}
+strong_alias (___ieee128_vprintf_chk, __vprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf_chk.c
new file mode 100644
index 0000000..9fc43a6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf_chk.c
@@ -0,0 +1,34 @@
+/* Wrapper for __vsnprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vsnprintf_chk (char *string, size_t maxlen, int flag,
+			 size_t slen, const char *format, va_list ap)
+{
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsnprintf_internal (string, maxlen, format, ap, mode);
+}
+strong_alias (___ieee128_vsnprintf_chk, __vsnprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf_chk.c
new file mode 100644
index 0000000..4faf1c1
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf_chk.c
@@ -0,0 +1,34 @@
+/* Wrapper for __vsprintf_chk.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vsprintf_chk (char *string, int flag, size_t slen,
+			const char *format, va_list ap)
+{
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  if (slen == 0)
+    __chk_fail ();
+
+  return __vsprintf_internal (string, slen, format, ap, mode);
+}
+strong_alias (___ieee128_vsprintf_chk, __vsprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ibm128.c
new file mode 100644
index 0000000..7d50284
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ibm128.c
@@ -0,0 +1 @@
+#include <test-printf-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ieee128.c
new file mode 100644
index 0000000..7d50284
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ieee128.c
@@ -0,0 +1 @@
+#include <test-printf-chk-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
similarity index 65%
copy from sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
copy to sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
index 936e85f..2359b57 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
@@ -1,4 +1,4 @@
-/* Test for the long double variants of *printf functions.
+/* Test for the long double variants of *printf_chk functions.
    Copyright (C) 2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -16,9 +16,12 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define _FORTIFY_SOURCE 2
+
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <support/check.h>
 
@@ -27,12 +30,15 @@ do_test_call_varg (FILE *stream, const char *format, ...)
 {
   char *buffer = NULL;
   char string[128];
+  int res;
   va_list args;
 
-  printf ("%20s", "vasprintf: ");
+  printf ("%20s", "__vasprintf_chk: ");
   va_start (args, format);
-  vasprintf (&buffer, format, args);
+  res = __vasprintf_chk (&buffer, 1, format, args);
   va_end (args);
+  if (res == -1)
+    printf ("Error using vasprintf\n");
   if (buffer == NULL)
     printf ("Error using vasprintf\n");
   else
@@ -42,34 +48,34 @@ do_test_call_varg (FILE *stream, const char *format, ...)
     }
   printf ("\n");
 
-  printf ("%20s", "vdprintf: ");
+  printf ("%20s", "__vdprintf_chk: ");
   va_start (args, format);
-  vdprintf (1, format, args);
+  __vdprintf_chk (1, 1, format, args);
   va_end (args);
   printf ("\n");
 
-  printf ("%20s", "vfprintf: ");
+  printf ("%20s", "__vfprintf_chk: ");
   va_start (args, format);
-  vfprintf (stream, format, args);
+  __vfprintf_chk (stream, 1, format, args);
   va_end (args);
   printf ("\n");
 
-  printf ("%20s", "vprintf: ");
+  printf ("%20s", "__vprintf_chk: ");
   va_start (args, format);
-  vprintf (format, args);
+  __vprintf_chk (1, format, args);
   va_end (args);
   printf ("\n");
 
-  printf ("%20s", "vsnprintf: ");
+  printf ("%20s", "__vsnprintf_chk: ");
   va_start (args, format);
-  vsnprintf (string, 127, format, args);
+  __vsnprintf_chk (string, 79, 1, 127, format, args);
   va_end (args);
   printf ("%s", string);
   printf ("\n");
 
-  printf ("%20s", "vsprintf: ");
+  printf ("%20s", "__vsprintf_chk: ");
   va_start (args, format);
-  vsprintf (string, format, args);
+  __vsprintf_chk (string, 1, 127, format, args);
   va_end (args);
   printf ("%s", string);
   printf ("\n");
@@ -80,9 +86,12 @@ do_test_call_rarg (FILE *stream, const char *format, long double ld)
 {
   char *buffer = NULL;
   char string[128];
+  int res;
 
-  printf ("%20s", "asprintf: ");
-  asprintf (&buffer, format, ld);
+  printf ("%20s", "__asprintf_chk: ");
+  res = __asprintf_chk (&buffer, 1, format, ld);
+  if (res == -1)
+    printf ("Error using vasprintf\n");
   if (buffer == NULL)
     printf ("Error using asprintf\n");
   else
@@ -92,25 +101,25 @@ do_test_call_rarg (FILE *stream, const char *format, long double ld)
     }
   printf ("\n");
 
-  printf ("%20s", "dprintf: ");
-  dprintf (1, format, ld);
+  printf ("%20s", "__dprintf_chk: ");
+  __dprintf_chk (1, 1, format, ld);
   printf ("\n");
 
-  printf ("%20s", "fprintf: ");
-  fprintf (stdout, format, ld);
+  printf ("%20s", "__fprintf_chk: ");
+  __fprintf_chk (stdout, 1, format, ld);
   printf ("\n");
 
-  printf ("%20s", "printf: ");
-  printf (format, ld);
+  printf ("%20s", "__printf_chk: ");
+  __printf_chk (1, format, ld);
   printf ("\n");
 
-  printf ("%20s", "snprintf: ");
-  snprintf (string, 127, format, ld);
+  printf ("%20s", "__snprintf_chk: ");
+  __snprintf_chk (string, 79, 1, 127, format, ld);
   printf ("%s", string);
   printf ("\n");
 
-  printf ("%20s", "sprintf: ");
-  sprintf (string, format, ld);
+  printf ("%20s", "__sprintf_chk: ");
+  __sprintf_chk (string, 1, 127, format, ld);
   printf ("%s", string);
   printf ("\n");
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh
new file mode 100644
index 0000000..872e1e2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Testing of *printf.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+    __asprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+     __dprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+     __fprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+      __printf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __snprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+     __sprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+   __vasprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __vdprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __vfprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+     __vprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+   __vsnprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __vsprintf_chk: -1.000000000000000000000000000000000000000000000000000000000000
+    __asprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+     __dprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+     __fprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+      __printf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __snprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+     __sprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+   __vasprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __vdprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __vfprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+     __vprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+   __vsnprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+    __vsprintf_chk: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
index 936e85f..64d686e 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
@@ -19,6 +19,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <support/check.h>
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a4e2f52ca2c598850928fb91e6475298aa636fb9

commit a4e2f52ca2c598850928fb91e6475298aa636fb9
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Fri Jun 8 11:40:45 2018 -0300

    ldbl-128ibm-compat: Add wide character printing functions
    
    Similarly to what was done for regular character printing functions,
    this patch uses the new mode mask, PRINTF_LDBL_USES_FLOAT128, in the
    'mode' argument of the wide characters printing function,
    __vfwprintf_internal (which is also extended to support printing
    floating-point values with IEEE binary128, by saving floating-point
    values into variables of type __float128 and adjusting the parameters to
    __printf_fp and __printf_fphex as if it was a call from a wide-character
    version of strfromf128 (even though such version does not exist)).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile:
    	[subdir == stdio-common] (ldbl-extra-routines): Add fwprintf,
    	swprintf, wprintf, vfwprintf, vswprintf, and vwprintf.
    	[subdir == stdio-common] (CFLAGS-vfwprintf-internal.c): New
    	variable.  Add -mfloat128 to the compilation of
    	vfprintf-internal.c, so that it gets support for the use of
    	__printf_fp and __printf_fphex with __float128 parameter.
    	[subdir == stdio-common] (tests-internal): Add
    	test-wprintf-ieee128 and test-wprintf-ibm128.
    	[subdir == stdio-common] (CFLAGS-test-wprintf-ieee128.c): New
    	variable to add the relevant -mabi flags to the compilation.
    	[subdir == stdio-common] (CFLAGS-test-wprintf-ibm128.c): Likewise.
    	[subdir == stdio-common && run-built-tests == yes]
    	(tests-special): Add $(objpfx)test-wprintf-ieee128.out and
    	$(objpfx)test-wprintf-ibm128.out.
    	[subdir == stdio-common] ($(objpfx)test-wprintf-ieee128.out):
    	New build and test rule.
    	[subdir == stdio-common] ($(objpfx)test-wprintf-ibm128.out):
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions (libc): Add
    	__fwprintfieee128, __swprintfieee128, __wprintfieee128,
    	__vfwprintfieee128, __vswprintfieee128, and __vwprintfieee128.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ibm128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ieee128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh:
    	Likewise.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index a287782..a44dfb3 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -11,13 +11,20 @@ ldbl-extra-routines += printf_size \
 		       vfprintf \
 		       vprintf \
 		       vsnprintf \
-		       vsprintf
+		       vsprintf \
+		       fwprintf \
+		       swprintf \
+		       wprintf \
+		       vfwprintf \
+		       vswprintf \
+		       vwprintf
 
 # Printing long double values with IEEE binary128 format reuses part
 # of the internal float128 implementation (__printf_fp, __printf_fphex,
 # and __float128 variables and union members).  Thus, the compilation of
 # the following functions, must have -mfloat128 passed to the compiler.
 CFLAGS-vfprintf-internal.c += -mfloat128
+CFLAGS-vfwprintf-internal.c += -mfloat128
 
 # Basic tests for the implementation of long double with IEEE binary128
 # format and for the related redirections in installed headers.
@@ -25,9 +32,16 @@ tests-internal += test-printf-ieee128 test-printf-ibm128
 CFLAGS-test-printf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
 
+tests-internal += test-wprintf-ieee128 test-wprintf-ibm128
+CFLAGS-test-wprintf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-wprintf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)test-printf-ieee128.out
 tests-special += $(objpfx)test-printf-ibm128.out
+
+tests-special += $(objpfx)test-wprintf-ieee128.out
+tests-special += $(objpfx)test-wprintf-ibm128.out
 endif
 
 $(objpfx)test-printf-ieee128.out: \
@@ -42,6 +56,18 @@ $(objpfx)test-printf-ibm128.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 
+$(objpfx)test-wprintf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh \
+  $(objpfx)test-wprintf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-wprintf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh \
+  $(objpfx)test-wprintf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
 CFLAGS-test-printf-size-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 6a27bef..0485a2b 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -134,5 +134,13 @@ libc {
     __vprintfieee128;
     __vsnprintfieee128;
     __vsprintfieee128;
+
+    __fwprintfieee128;
+    __swprintfieee128;
+    __wprintfieee128;
+
+    __vfwprintfieee128;
+    __vswprintfieee128;
+    __vwprintfieee128;
   }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf.c
new file mode 100644
index 0000000..dd156c6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fwprintf.c
@@ -0,0 +1,35 @@
+/* Wrapper for fwprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_fwprintf (FILE *fp, const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfwprintf_internal (fp, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_fwprintf, __fwprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf.c
new file mode 100644
index 0000000..d865f13
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-swprintf.c
@@ -0,0 +1,36 @@
+/* Wrapper for swprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_swprintf (wchar_t *string, size_t maxlen,
+		    const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vswprintf_internal (string, maxlen, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_swprintf, __swprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf.c
new file mode 100644
index 0000000..6fd4f7b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfwprintf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vfwprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vfwprintf (FILE *fp, const wchar_t *format, va_list ap)
+{
+  return __vfwprintf_internal (fp, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vfwprintf, __vfwprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf.c
new file mode 100644
index 0000000..0524e17
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vswprintf.c
@@ -0,0 +1,28 @@
+/* Wrapper for vswprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vswprintf (wchar_t *string, size_t maxlen,
+		     const wchar_t *format, va_list ap)
+{
+  return __vswprintf_internal (string, maxlen, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vswprintf, __vswprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf.c
new file mode 100644
index 0000000..4ba26e2
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vwprintf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vwprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vwprintf (const wchar_t *format, va_list ap)
+{
+  return __vfwprintf_internal (stdout, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vwprintf, __vwprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf.c
new file mode 100644
index 0000000..741633f
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-wprintf.c
@@ -0,0 +1,35 @@
+/* Wrapper for wprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_wprintf (const wchar_t *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfwprintf_internal (stdout, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_wprintf, __wprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ibm128.c
new file mode 100644
index 0000000..9e230cd
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ibm128.c
@@ -0,0 +1 @@
+#include <test-wprintf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ieee128.c
new file mode 100644
index 0000000..9e230cd
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ieee128.c
@@ -0,0 +1 @@
+#include <test-wprintf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c
new file mode 100644
index 0000000..67ddbc9
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.c
@@ -0,0 +1,87 @@
+/* Test for the long double variants of *w*printf functions.
+   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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <wchar.h>
+
+#include <support/check.h>
+
+static void
+do_test_call_varg (FILE *stream, const wchar_t *format, ...)
+{
+  wchar_t string[128];
+  va_list args;
+
+  wprintf (L"%20Ls", L"vfwprintf: ");
+  va_start (args, format);
+  vfwprintf (stream, format, args);
+  va_end (args);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"vswprintf: ");
+  va_start (args, format);
+  vswprintf (string, 127, format, args);
+  va_end (args);
+  wprintf (L"%Ls", string);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"vwprintf: ");
+  va_start (args, format);
+  vwprintf (format, args);
+  va_end (args);
+  wprintf (L"\n");
+}
+
+static void
+do_test_call_rarg (FILE *stream, const wchar_t *format, long double ld)
+{
+  wchar_t string[128];
+
+  wprintf (L"%20Ls", L"fwprintf: ");
+  fwprintf (stream, format, ld);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"swprintf: ");
+  swprintf (string, 127, format, ld);
+  wprintf (L"%Ls", string);
+  wprintf (L"\n");
+
+  wprintf (L"%20Ls", L"wprintf: ");
+  wprintf (format, ld);
+  wprintf (L"\n");
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+
+  /* Print in decimal notation.  */
+  do_test_call_rarg (stdout, L"%.60Lf", ld);
+  do_test_call_varg (stdout, L"%.60Lf", ld);
+
+  /* Print in hexadecimal notation.  */
+  do_test_call_rarg (stdout, L"%.60La", ld);
+  do_test_call_varg (stdout, L"%.60La", ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh
new file mode 100644
index 0000000..029006e
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-wprintf-ldbl-compat.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Testing of *w*printf.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+          fwprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          swprintf: -1.000000000000000000000000000000000000000000000000000000000000
+           wprintf: -1.000000000000000000000000000000000000000000000000000000000000
+         vfwprintf: -1.000000000000000000000000000000000000000000000000000000000000
+         vswprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          vwprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          fwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          swprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+           wprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+         vfwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+         vswprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          vwprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ca3383ddabd3c6bc09928fea69e5cd43642d4190

commit ca3383ddabd3c6bc09928fea69e5cd43642d4190
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon May 21 11:25:39 2018 -0300

    ldbl-128ibm-compat: Add regular character printing functions
    
    The 'mode' argument to __vfprintf_internal allows the selection of the
    long double format for all long double arguments requested by the format
    string.  Currently, there are two possibilities: long double with the
    same format as double or long double as something else.  The 'something
    else' format varies between architectures, and on powerpc64le, it means
    IBM Extended Precision format.
    
    In preparation for the third option of long double format on
    powerpc64le, this patch uses the new mode mask,
    PRINTF_LDBL_USES_FLOAT128, which tells __vfprintf_internal to save the
    floating-point values into variables of type __float128 and adjusts the
    parameters to __printf_fp and __printf_fphex as if it was a call from
    strfromf128.
    
    Tested for powerpc64le.
    
    	* elf/tst-addr1.c (do_test): Accept redirections of printf to
    	__printfieee128.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile:
    	[subdir == stdio-common] (ldbl-extra-routines): Add asprintf,
    	dprintf, fprintf, printf, snprintf, sprintf, vasprintf,
    	vdprintf, vfprintf, vprintf, vsnprintf, and vsprintf.
    	[subdir == stdio-common] (CFLAGS-vfprintf-internal.c): New
    	variable.  Add -mfloat128 to the compilation of
    	vfprintf-internal.c, so that it gets support for the use of
    	__printf_fp and __printf_fphex with __float128 parameter.
    	[subdir == stdio-common] (tests-internal): Add
    	test-printf-ieee128 and test-printf-ibm128.
    	[subdir == stdio-common] (CFLAGS-test-printf-ieee128.c): New
    	variable to add the relevant -mabi flags to the compilation.
    	[subdir == stdio-common] (CFLAGS-test-printf-ibm128.c): Likewise.
    	[subdir == stdio-common && run-built-tests == yes]
    	(tests-special): Add $(objpfx)test-printf-ieee128.out and
    	$(objpfx)test-printf-ibm128.out.
    	[subdir == stdio-common] ($(objpfx)test-printf-ieee128.out):
    	New build and test rule.
    	[subdir == stdio-common] ($(objpfx)test-printf-ibm128.out):
    	Likewise.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Versions: (libc): Add
    	__asprintfieee128, __dprintfieee128, __fprintfieee128,
    	__printfieee128, __snprintfieee128, __sprintfieee128,
    	__vasprintfieee128, __vdprintfieee128, __vfprintfieee128,
    	__vprintfieee128, __vsnprintfieee128, and __vsprintfieee128.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf.c: New file.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ibm128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ieee128.c: Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c:
    	Likewise.
    	* sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ldbl-128ibm-compat-abi.h:
    	Likewise.

diff --git a/elf/tst-addr1.c b/elf/tst-addr1.c
index 68ff74a..ee81acd 100644
--- a/elf/tst-addr1.c
+++ b/elf/tst-addr1.c
@@ -19,7 +19,12 @@ do_test (void)
 		rather than in the binary.  printf and _IO_printf
 		are aliased and which one comes first in the
 		hash table is up to the linker.  */
-	     && strcmp (i.dli_sname, "_IO_printf") != 0);
+	     && strcmp (i.dli_sname, "_IO_printf") != 0
+	     /* On architectures where long double with IEEE binary128
+		format is available as a third option (initially, true
+		for powerpc64le), printf may be redirected to
+		__printfieee128.  */
+	     && strcmp (i.dli_sname, "__printfieee128") != 0);
 }
 
 #include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 38ae880..a287782 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -1,5 +1,46 @@
 ifeq ($(subdir),stdio-common)
-ldbl-extra-routines += printf_size
+ldbl-extra-routines += printf_size \
+		       asprintf \
+		       dprintf \
+		       fprintf \
+		       printf \
+		       snprintf \
+		       sprintf \
+		       vasprintf \
+		       vdprintf \
+		       vfprintf \
+		       vprintf \
+		       vsnprintf \
+		       vsprintf
+
+# Printing long double values with IEEE binary128 format reuses part
+# of the internal float128 implementation (__printf_fp, __printf_fphex,
+# and __float128 variables and union members).  Thus, the compilation of
+# the following functions, must have -mfloat128 passed to the compiler.
+CFLAGS-vfprintf-internal.c += -mfloat128
+
+# Basic tests for the implementation of long double with IEEE binary128
+# format and for the related redirections in installed headers.
+tests-internal += test-printf-ieee128 test-printf-ibm128
+CFLAGS-test-printf-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
+CFLAGS-test-printf-ibm128.c += -mabi=ibmlongdouble -Wno-psabi
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)test-printf-ieee128.out
+tests-special += $(objpfx)test-printf-ibm128.out
+endif
+
+$(objpfx)test-printf-ieee128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh \
+  $(objpfx)test-printf-ieee128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)test-printf-ibm128.out: \
+  ../sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh \
+  $(objpfx)test-printf-ibm128
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
 
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 4aa34db..6a27bef 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -120,4 +120,19 @@ libc {
     __wcstoieee128_l;
 
     __printf_sizeieee128;
+
+    __asprintfieee128;
+    __dprintfieee128;
+    __fprintfieee128;
+    __printfieee128;
+    __snprintfieee128;
+    __sprintfieee128;
+
+    __vasprintfieee128;
+    __vdprintfieee128;
+    __vfprintfieee128;
+    __vprintfieee128;
+    __vsnprintfieee128;
+    __vsprintfieee128;
   }
+}
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf.c
new file mode 100644
index 0000000..543b646
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-asprintf.c
@@ -0,0 +1,35 @@
+/* Wrapper for asprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_asprintf (char **string_ptr, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vasprintf_internal (string_ptr, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_asprintf, __asprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf.c
new file mode 100644
index 0000000..2c7ea41
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-dprintf.c
@@ -0,0 +1,34 @@
+/* Wrapper for dprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_dprintf (int d, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vdprintf_internal (d, format, ap, PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_dprintf, __dprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf.c
new file mode 100644
index 0000000..e4b9bc6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-fprintf.c
@@ -0,0 +1,34 @@
+/* Wrapper for fprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_fprintf (FILE *fp, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfprintf_internal (fp, format, ap, PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_fprintf, __fprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf.c
new file mode 100644
index 0000000..acf7479
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-printf.c
@@ -0,0 +1,35 @@
+/* Wrapper for printf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_printf (const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vfprintf_internal (stdout, format, ap,
+			      PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_printf, __printfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf.c
new file mode 100644
index 0000000..f1b4bb8
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-snprintf.c
@@ -0,0 +1,35 @@
+/* Wrapper for snprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_snprintf (char *s, size_t maxlen, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vsnprintf_internal (s, maxlen, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_snprintf, __snprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf.c
new file mode 100644
index 0000000..d0790f0
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-sprintf.c
@@ -0,0 +1,35 @@
+/* Wrapper for sprintf.  IEEE128 version.
+   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 <stdarg.h>
+#include <libio/libioP.h>
+
+extern int
+___ieee128_sprintf (char *s, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  va_start (ap, format);
+  done = __vsprintf_internal (s, -1, format, ap,
+			      PRINTF_LDBL_USES_FLOAT128);
+  va_end (ap);
+
+  return done;
+}
+strong_alias (___ieee128_sprintf, __sprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf.c
new file mode 100644
index 0000000..ae97147
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vasprintf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vasprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vasprintf (char **result_ptr, const char *format, va_list ap)
+{
+  return __vasprintf_internal (result_ptr, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vasprintf, __vasprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf.c
new file mode 100644
index 0000000..d02b562
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vdprintf.c
@@ -0,0 +1,26 @@
+/* Wrapper for vdprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vdprintf (int d, const char *format, va_list ap)
+{
+  return __vdprintf_internal (d, format, ap, PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vdprintf, __vdprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf.c
new file mode 100644
index 0000000..8f5e268
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vfprintf.c
@@ -0,0 +1,26 @@
+/* Wrapper for vfprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vfprintf (FILE *fp, const char *format, va_list ap)
+{
+  return __vfprintf_internal (fp, format, ap, PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vfprintf, __vfprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf.c
new file mode 100644
index 0000000..40ffe87
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vprintf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vprintf (const char *format, va_list ap)
+{
+  return __vfprintf_internal (stdout, format, ap,
+			      PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vprintf, __vprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf.c
new file mode 100644
index 0000000..f597df4
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsnprintf.c
@@ -0,0 +1,28 @@
+/* Wrapper for vsnprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vsnprintf (char *string, size_t maxlen, const char *format,
+		     va_list ap)
+{
+  return __vsnprintf_internal (string, maxlen, format, ap,
+			       PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vsnprintf, __vsnprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf.c
new file mode 100644
index 0000000..29d6e24
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vsprintf.c
@@ -0,0 +1,27 @@
+/* Wrapper for vsprintf.  IEEE128 version.
+   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 <libio/libioP.h>
+
+extern int
+___ieee128_vsprintf (char *string, const char *format, va_list ap)
+{
+  return __vsprintf_internal (string, -1, format, ap,
+			      PRINTF_LDBL_USES_FLOAT128);
+}
+strong_alias (___ieee128_vsprintf, __vsprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ibm128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ibm128.c
new file mode 100644
index 0000000..5de4ea3
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ibm128.c
@@ -0,0 +1 @@
+#include <test-printf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ieee128.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ieee128.c
new file mode 100644
index 0000000..5de4ea3
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ieee128.c
@@ -0,0 +1 @@
+#include <test-printf-ldbl-compat.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
new file mode 100644
index 0000000..936e85f
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
@@ -0,0 +1,134 @@
+/* Test for the long double variants of *printf functions.
+   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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <support/check.h>
+
+static void
+do_test_call_varg (FILE *stream, const char *format, ...)
+{
+  char *buffer = NULL;
+  char string[128];
+  va_list args;
+
+  printf ("%20s", "vasprintf: ");
+  va_start (args, format);
+  vasprintf (&buffer, format, args);
+  va_end (args);
+  if (buffer == NULL)
+    printf ("Error using vasprintf\n");
+  else
+    {
+      printf ("%s", buffer);
+      free (buffer);
+    }
+  printf ("\n");
+
+  printf ("%20s", "vdprintf: ");
+  va_start (args, format);
+  vdprintf (1, format, args);
+  va_end (args);
+  printf ("\n");
+
+  printf ("%20s", "vfprintf: ");
+  va_start (args, format);
+  vfprintf (stream, format, args);
+  va_end (args);
+  printf ("\n");
+
+  printf ("%20s", "vprintf: ");
+  va_start (args, format);
+  vprintf (format, args);
+  va_end (args);
+  printf ("\n");
+
+  printf ("%20s", "vsnprintf: ");
+  va_start (args, format);
+  vsnprintf (string, 127, format, args);
+  va_end (args);
+  printf ("%s", string);
+  printf ("\n");
+
+  printf ("%20s", "vsprintf: ");
+  va_start (args, format);
+  vsprintf (string, format, args);
+  va_end (args);
+  printf ("%s", string);
+  printf ("\n");
+}
+
+static void
+do_test_call_rarg (FILE *stream, const char *format, long double ld)
+{
+  char *buffer = NULL;
+  char string[128];
+
+  printf ("%20s", "asprintf: ");
+  asprintf (&buffer, format, ld);
+  if (buffer == NULL)
+    printf ("Error using asprintf\n");
+  else
+    {
+      printf ("%s", buffer);
+      free (buffer);
+    }
+  printf ("\n");
+
+  printf ("%20s", "dprintf: ");
+  dprintf (1, format, ld);
+  printf ("\n");
+
+  printf ("%20s", "fprintf: ");
+  fprintf (stdout, format, ld);
+  printf ("\n");
+
+  printf ("%20s", "printf: ");
+  printf (format, ld);
+  printf ("\n");
+
+  printf ("%20s", "snprintf: ");
+  snprintf (string, 127, format, ld);
+  printf ("%s", string);
+  printf ("\n");
+
+  printf ("%20s", "sprintf: ");
+  sprintf (string, format, ld);
+  printf ("%s", string);
+  printf ("\n");
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+
+  /* Print in decimal notation.  */
+  do_test_call_rarg (stdout, "%.60Lf", ld);
+  do_test_call_varg (stdout, "%.60Lf", ld);
+
+  /* Print in hexadecimal notation.  */
+  do_test_call_rarg (stdout, "%.60La", ld);
+  do_test_call_varg (stdout, "%.60La", ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh
new file mode 100644
index 0000000..62bc5d0
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Testing of *printf.  IEEE binary128 for powerpc64le version.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  > ${test_program_output} || status=1
+
+cat <<'EOF' |
+          asprintf: -1.000000000000000000000000000000000000000000000000000000000000
+           dprintf: -1.000000000000000000000000000000000000000000000000000000000000
+           fprintf: -1.000000000000000000000000000000000000000000000000000000000000
+            printf: -1.000000000000000000000000000000000000000000000000000000000000
+          snprintf: -1.000000000000000000000000000000000000000000000000000000000000
+           sprintf: -1.000000000000000000000000000000000000000000000000000000000000
+         vasprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          vdprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          vfprintf: -1.000000000000000000000000000000000000000000000000000000000000
+           vprintf: -1.000000000000000000000000000000000000000000000000000000000000
+         vsnprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          vsprintf: -1.000000000000000000000000000000000000000000000000000000000000
+          asprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+           dprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+           fprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+            printf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          snprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+           sprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+         vasprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          vdprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          vfprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+           vprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+         vsnprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+          vsprintf: -0x1.000000000000000000000000000000000000000000000000000000000000p+0
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ldbl-128ibm-compat-abi.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ldbl-128ibm-compat-abi.h
new file mode 100644
index 0000000..6eb0e72
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ldbl-128ibm-compat-abi.h
@@ -0,0 +1,8 @@
+/* ABI version for long double switch to IEEE 128-bit floating point..
+   This is used by the Versions and math_ldbl_opt.h files in
+   sysdeps/ieee754/ldbl-128ibm-compat/.  It gives the ABI version where
+   long double == ibm128 was replaced with long double == _Float128
+   for libm *l functions and libc functions using long double.  */
+
+#define LDBL_IBM128_VERSION		GLIBC_2.28
+#define LDBL_IBM128_COMPAT_VERSION	GLIBC_2_28

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=22c0e3b76d0c1d99d59dd84463e5cb75471f43d7

commit 22c0e3b76d0c1d99d59dd84463e5cb75471f43d7
Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
Date:   Tue Jul 31 10:40:30 2018 -0300

    ldbl-128ibm-compat: Add Makefile routine to control compiler options
    
    Many files from the stdio-common, wcsmbs, argp, misc, and libio
    directories will have IEEE binary128 counterparts.  Setting the correct
    compiler options to these files (original and counterparts) would
    produce a large amount of repetitive Makefile rules.  To avoid this
    repetition, this patch adds a Makefile routine that iterates over the
    files adding or removing the appropriate flags.
    
    Currently, this mechanism only affects printf_size.  Future commits will
    use the mechanism for many more files.
    
    	* sysdeps/ieee754/ldbl-128ibm-compat/Makefile
    	[subdir == stdio-common] (routines): Move the addition of
    	printf_size to ldbl-extra-routines.
    	(ldbl-ibm128-files): New variable.
    	(obj-suf-foreach): New routine.

diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 412beb5..38ae880 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -1,5 +1,5 @@
 ifeq ($(subdir),stdio-common)
-routines += ieee128-printf_size
+ldbl-extra-routines += printf_size
 
 tests-internal += test-printf-size-ieee128 test-printf-size-ibm128
 CFLAGS-test-printf-size-ieee128.c += -mfloat128 -mabi=ieeelongdouble -Wno-psabi
@@ -20,3 +20,23 @@ $(objpfx)test-printf-size-ibm128.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 endif
+
+# Add IEEE binary128 files as make targets.
+routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
+
+# When a platform implies this directory, all files are built with
+# -mabi=ieeelongdouble by default.  However, most of the files that
+# implement floating-point to/from string conversion must be built with
+# -mabi=ibmlongdouble.  The following rule ensures that the correct
+# compiler flags are passed to these files.
+ldbl-ibm128-files := $(objpfx)test-%-ibm128^ \
+		     $(foreach r,$(ldbl-extra-routines),$(objpfx)$(r)^) \
+		     $(foreach r,$(ldbl-extra-routines),$(objpfx)$(r)-internal^)
+obj-suf-foreach = $(foreach suf,$(all-object-suffixes),$(subst ^,$(suf),$(1)))
+
+# Removing -mabi=ieeelongdouble is not required, but helps when
+# analyzing the flags that were passed to the compiler.
+$(call obj-suf-foreach,$(ldbl-ibm128-files)): \
+  sysdep-CFLAGS := $(filter-out -mabi=ieeelongdouble -Wno-psabi, \
+				$(sysdep-CFLAGS)) \
+		   -mabi=ibmlongdouble

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4d0ce4ec680972fcdb7ebf08af9c2c7cb81c9b83

commit 4d0ce4ec680972fcdb7ebf08af9c2c7cb81c9b83
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sun Jun 10 22:42:34 2018 -0300

    Prepare vfscanf to use __strtof128_internal
    
    On powerpc64le, long double can currently take two formats: the same as
    double (-mlong-double-64) or IBM Extended Precision (default with
    -mlong-double-128 or explicitly with -mabi=ibmlongdouble).  The internal
    implementation of scanf-like functions is aware of these possibilites
    and, based on the format in use, properly calls __strtold_internal or
    __strtod_internal, saving the return to a variable of type double or
    long double.
    
    When library support for TS 18661-3 was added to glibc, a new function,
    __strtof128_internal, was added to enable reading of floating-point
    values with IEEE binary128 format into the _Float128 type.  Now that
    powerpc64le is getting support for its third long double format, and
    taking into account that this format is the same as the format of
    _Float128, this patch extends __vfscanf_internal and __vfwscanf_internal
    to call __strtof128_internal when appropriate.  The result gets saved
    into a variable of _Float128 type.
    
    	* libio/libioP.h (SCANF_LDBL_USES_FLOAT128): New macro to be
    	used as a mask for the mode argument of __vfscanf_internal and
    	__vfwscanf_internal.
    	* stdio-common/vfscanf-internal.c
    	[defined COMPILE_WSCANF && __HAVE_FLOAT128_UNLIKE_LDBL]
    	(__strtof128_internal): Define to __wcstof128_internal.
    	(LDBL_USES_FLOAT128): New macro.
    	[__HAVE_FLOAT128_UNLIKE_LDBL] (__vfscanf_internal): Call
    	__strtof128_internal when the format of long double is the same
    	as _Float128.

diff --git a/libio/libioP.h b/libio/libioP.h
index fba4b52..6858d8e 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -731,8 +731,9 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 #endif /* _G_HAVE_MMAP */
 
 /* Flags for __vfscanf_internal and __vfwscanf_internal.  */
-#define SCANF_LDBL_IS_DBL 0x0001
-#define SCANF_ISOC99_A    0x0002
+#define SCANF_LDBL_IS_DBL		0x0001
+#define SCANF_ISOC99_A			0x0002
+#define SCANF_LDBL_USES_FLOAT128	0x0004
 
 extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
                                unsigned int flags);
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 0eb6b5e..d333def 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -97,6 +97,9 @@
 # define __strtold_internal	__wcstold_internal
 # define __strtod_internal	__wcstod_internal
 # define __strtof_internal	__wcstof_internal
+# if __HAVE_FLOAT128_UNLIKE_LDBL
+#  define __strtof128_internal	__wcstof128_internal
+# endif
 
 # define L_(Str)	L##Str
 # define CHAR_T		wchar_t
@@ -332,6 +335,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
   scratch_buffer_init (&charbuf.scratch);
 
 #define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
+#define LDBL_USES_FLOAT128 ((mode_flags & SCANF_LDBL_USES_FLOAT128) != 0)
 #define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
 
 #ifdef __va_copy
@@ -2422,6 +2426,16 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      done = EOF;
 	      goto errout;
 	    }
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+	  if ((flags & LONGDBL) && LDBL_USES_FLOAT128)
+	    {
+	      _Float128 d = __strtof128_internal
+		(char_buffer_start (&charbuf), &tw, flags & GROUP);
+	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
+		*ARG (_Float128 *) = d;
+	    }
+	  else
+#endif
 	  if ((flags & LONGDBL) && LDBL_DISTINCT)
 	    {
 	      long double d = __strtold_internal

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=0421a22175e1ac6a6efa232094c2e7f3a0566535

commit 0421a22175e1ac6a6efa232094c2e7f3a0566535
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Sun Jun 3 17:20:43 2018 -0300

    Prepare vfprintf to use __printf_fp/__printf_fphex with float128 arg
    
    On powerpc64le, long double can currently take two formats: the same as
    double (-mlong-double-64) or IBM Extended Precision (default with
    -mlong-double-128 or explicitly with -mabi=ibmlongdouble).  The internal
    implementation of printf-like functions is aware of these possibilites
    and properly parses floating-point values from the variable arguments,
    before making calls to __printf_fp and __printf_fphex.  These functions
    are also aware of the format possibilites and know how to convert both
    formats to string.
    
    When library support for TS 18661-3 was added to glibc, __printf_fp and
    __printf_fphex were extented with support for an additional type
    (__float128/_Float128) with a different format (binary128).  Now that
    powerpc64le is getting support for its third long double format, and
    taking into account that this format is the same as the format of
    __float128/_Float128, this patch extends __vfprintf_internal to properly
    call __printf_fp and __printf_fphex with this new format.
    
    Tested for powerpc64le (with additional patches to actually enable the
    use of these preparations) and for x86_64.
    
    	* libio/libioP.h (PRINTF_LDBL_USES_FLOAT128): New macro to be
    	used as a mask for the mode argument of __vfprintf_internal.
    	* stdio-common/printf-parse.h (printf_arg): New union member:
    	pa_float128.
    	* stdio-common/vfprintf-internal.c
    	(LDBL_USES_FLOAT128): New macro.
    	(PARSE_FLOAT_VA_ARG_EXTENDED): Likewise.
    	(PARSE_FLOAT_VA_ARG): Likewise.
    	(SETUP_FLOAT128_INFO): Likewise.
    	(process_arg): Use PARSE_FLOAT_VA_ARG_EXTENDED and
    	SETUP_FLOAT128_INFO.
    	[__HAVE_FLOAT128_UNLIKE_LDBL] (printf_positional): Write
    	floating-point value to the new union member, pa_float128.

diff --git a/libio/libioP.h b/libio/libioP.h
index e9446b8..fba4b52 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -687,8 +687,9 @@ extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
                                  unsigned int mode_flags);
 
 /* Flags for __v*printf_internal.  */
-#define PRINTF_LDBL_IS_DBL 0x0001
-#define PRINTF_FORTIFY     0x0002
+#define PRINTF_LDBL_IS_DBL		0x0001
+#define PRINTF_FORTIFY			0x0002
+#define PRINTF_LDBL_USES_FLOAT128	0x0004
 
 extern size_t _IO_getline (FILE *,char *, size_t, int, int);
 libc_hidden_proto (_IO_getline)
diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h
index e07186e..9c79f3c 100644
--- a/stdio-common/printf-parse.h
+++ b/stdio-common/printf-parse.h
@@ -57,6 +57,9 @@ union printf_arg
     unsigned long long int pa_u_long_long_int;
     double pa_double;
     long double pa_long_double;
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+    _Float128 pa_float128;
+#endif
     const char *pa_string;
     const wchar_t *pa_wstring;
     void *pa_pointer;
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index 2d9016e..95d3696 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -68,8 +68,43 @@
     } while (0)
 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
 #define LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
+#define LDBL_USES_FLOAT128 ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0)
 #define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)
 
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+# define PARSE_FLOAT_VA_ARG_EXTENDED(INFO)				      \
+  if (LDBL_USES_FLOAT128 && is_long_double)				      \
+    {									      \
+      INFO.is_binary128 = 1;						      \
+      the_arg.pa_float128 = va_arg (ap, _Float128);			      \
+    }									      \
+  else									      \
+    {									      \
+      PARSE_FLOAT_VA_ARG (INFO)						      \
+    }
+#else
+# define PARSE_FLOAT_VA_ARG_EXTENDED(INFO)				      \
+  PARSE_FLOAT_VA_ARG (INFO)
+#endif
+
+#define PARSE_FLOAT_VA_ARG(INFO)					      \
+  INFO.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);
+
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+# define SETUP_FLOAT128_INFO(INFO)					      \
+  if (LDBL_USES_FLOAT128)						      \
+    INFO.is_binary128 = is_long_double;					      \
+  else									      \
+    INFO.is_binary128 = 0;
+#else
+# define SETUP_FLOAT128_INFO(INFO)					      \
+  INFO.is_binary128 = 0;
+#endif
+
 #define done_add(val) \
   do {									      \
     unsigned int _val = val;						      \
@@ -773,10 +808,7 @@ static const uint8_t jump_table[] =
 					.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);			      \
+	    PARSE_FLOAT_VA_ARG_EXTENDED (info)				      \
 	    ptr = (const void *) &the_arg;				      \
 									      \
 	    function_done = __printf_fp (s, &info, &ptr);		      \
@@ -789,8 +821,7 @@ static const uint8_t jump_table[] =
 		fspec->data_arg_type = PA_DOUBLE;			      \
 		fspec->info.is_long_double = 0;				      \
 	      }								      \
-	    /* Not supported by *printf functions.  */			      \
-	    fspec->info.is_binary128 = 0;				      \
+	    SETUP_FLOAT128_INFO (fspec->info)				      \
 									      \
 	    function_done = __printf_fp (s, &fspec->info, &ptr);	      \
 	  }								      \
@@ -833,10 +864,7 @@ static const uint8_t jump_table[] =
 					.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);			      \
+	    PARSE_FLOAT_VA_ARG_EXTENDED (info)				      \
 	    ptr = (const void *) &the_arg;				      \
 									      \
 	    function_done = __printf_fphex (s, &info, &ptr);		      \
@@ -846,8 +874,7 @@ static const uint8_t jump_table[] =
 	    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;				      \
+	    SETUP_FLOAT128_INFO (fspec->info)				      \
 									      \
 	    function_done = __printf_fphex (s, &fspec->info, &ptr);	      \
 	  }								      \
@@ -1871,6 +1898,10 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
 	  }
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+	else if (LDBL_USES_FLOAT128)
+	  args_value[cnt].pa_float128 = va_arg (*ap_savep, _Float128);
+#endif
 	else
 	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
 	break;
@@ -1889,7 +1920,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
 	      (args_value[cnt].pa_user, ap_savep);
 	  }
 	else
-	  args_value[cnt].pa_long_double = 0.0;
+	  {
+	    args_value[cnt].pa_long_double = 0.0;
+#if __HAVE_FLOAT128_UNLIKE_LDBL
+	    args_value[cnt].pa_float128 = 0;
+#endif
+	  }
 	break;
       case -1:
 	/* Error case.  Not all parameters appear in N$ format

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=cc98b0bef943f973ff1e99796fb9c29ffaef1bcc

commit cc98b0bef943f973ff1e99796fb9c29ffaef1bcc
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Aug 7 18:06:58 2018 -0300

    ldbl-opt: Reuse test cases from misc/ that check long double
    
    This patch adds test cases for the compatibility versions of the
    functions: err, errx, verr, verrx, warn, warnx, vwarn, vwarnx (from
    err.h), error, and error_at_line (from error.h), when long double has
    the same format as double (-mlong-double-64).
    
    Tested for powerpc64le.
    
    	* misc/tst-ldbl-error.sh
    	* sysdeps/ieee754/ldbl-opt/Makefile
    	[subdir == misc] (tests-internal): Add tst-nldbl-warn,
    	tst-nldbl-error-err, tst-nldbl-error-errx, tst-nldbl-error-verr,
    	tst-nldbl-error-verrx, tst-nldbl-error-error, and
    	tst-nldbl-error-error_at_line.
    	(CFLAGS-tst-nldbl-warn.c, CFLAGS-tst-nldbl-error-err.c)
    	(CFLAGS-tst-nldbl-error-errx.c, CFLAGS-tst-nldbl-error-verr.c)
    	(CFLAGS-tst-nldbl-error-verrx.c, CFLAGS-tst-nldbl-error-error.c)
    	(CFLAGS-tst-nldbl-error-error_at_line.c): New variables.
    	[subdir == misc && run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-nldbl-warn.out, $(objpfx)tst-nldbl-error-err.out),
    	$(objpfx)tst-nldbl-error-errx.out),
    	$(objpfx)tst-nldbl-error-verr.out),
    	$(objpfx)tst-nldbl-error-verrx.out),
    	$(objpfx)tst-nldbl-error-error.out), and
    	$(objpfx)tst-nldbl-error-error_at_line.out).
    	($(objpfx)tst-nldbl-warn.out): New build and run rule.
    	($(objpfx)tst-nldbl-error-%.out): Likewise.

diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index 27b1d0f..92b3ac3 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -197,3 +197,46 @@ $(objpfx)tst-nldbl-argp-%.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 endif
+
+# Tests for err.h and error.h functions (reusing the relevant tests from
+# misc/).
+ifeq ($(subdir), misc)
+tests-internal += tst-nldbl-warn
+tests-internal += tst-nldbl-error-err
+tests-internal += tst-nldbl-error-errx
+tests-internal += tst-nldbl-error-verr
+tests-internal += tst-nldbl-error-verrx
+tests-internal += tst-nldbl-error-error
+tests-internal += tst-nldbl-error-error_at_line
+
+$(objpfx)tst-nldbl-%.c: tst-ldbl-%.c
+	cp $< $@
+
+CFLAGS-tst-nldbl-warn.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-err.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-errx.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-verr.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-verrx.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-error.c += -mlong-double-64
+CFLAGS-tst-nldbl-error-error_at_line.c += -mlong-double-64
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-nldbl-warn.out
+tests-special += $(objpfx)tst-nldbl-error-err.out
+tests-special += $(objpfx)tst-nldbl-error-errx.out
+tests-special += $(objpfx)tst-nldbl-error-verr.out
+tests-special += $(objpfx)tst-nldbl-error-verrx.out
+tests-special += $(objpfx)tst-nldbl-error-error.out
+tests-special += $(objpfx)tst-nldbl-error-error_at_line.out
+endif
+
+$(objpfx)tst-nldbl-warn.out: \
+  tst-ldbl-warn.sh $(objpfx)tst-nldbl-warn
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-nldbl-error-%.out: \
+  tst-ldbl-error.sh $(objpfx)tst-nldbl-error-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+endif

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3fb91ab64835752656e2a5dbb48a93326ac75f70

commit 3fb91ab64835752656e2a5dbb48a93326ac75f70
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Wed Aug 8 17:26:22 2018 -0300

    ldbl-opt: Add error and error_at_line
    
    On platforms where long double may have the same format as double
    (-mlong-double-64), error and error_at_line do not take that into
    account and might produce wrong output if a long double conversion is
    requested by the format string ('%Lf').  This patch adds compatibility
    functions for this situation and redirects calls via header magic.
    
    Tested for powerpc64le.
    
    	* include/error.h: Include stdarg.h.  Declare internal functions
    	__error_internal and __error_at_line_internal.
    	* misc/bits/error-ldbl.h: New file.
    	* misc/error.h [__LDBL_COMPAT]: Include bits/error-ldbl.h and
    	avoid the inclusion of bits/error.h.
    	* sysdeps/ieee754/ldbl-opt/Versions (libc): Add __nldbl_error,
    	and __nldbl_error_at_line.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Include error.h.
    	(__nldbl_error, __ndlbl_error_at_line): New functions.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Include error.h.
    	Redirect error and error_at_line.
    	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Update.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.

diff --git a/include/error.h b/include/error.h
index 70f3192..9e96262 100644
--- a/include/error.h
+++ b/include/error.h
@@ -1 +1,15 @@
+#ifndef _ERROR_H
 #include <misc/error.h>
+
+#include <stdarg.h>
+
+void
+__error_internal (int status, int errnum, const char *message,
+		  va_list args, unsigned int mode_flags);
+
+void
+__error_at_line_internal (int status, int errnum, const char *file_name,
+			  unsigned int line_number, const char *message,
+			  va_list args, unsigned int mode_flags);
+
+#endif
diff --git a/misc/bits/error-ldbl.h b/misc/bits/error-ldbl.h
new file mode 100644
index 0000000..d89a3f1
--- /dev/null
+++ b/misc/bits/error-ldbl.h
@@ -0,0 +1,24 @@
+/* Redirections for error.h functions for -mlong-double-64.
+   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 _ERROR_H
+# error "Never include <bits/error-ldbl.h> directly; use <error.h> instead."
+#endif
+
+__LDBL_REDIR_DECL (error)
+__LDBL_REDIR_DECL (error_at_line)
diff --git a/misc/error.h b/misc/error.h
index fcd5ad9..ac0c586 100644
--- a/misc/error.h
+++ b/misc/error.h
@@ -47,9 +47,15 @@ extern unsigned int error_message_count;
    variable controls whether this mode is selected or not.  */
 extern int error_one_per_line;
 
-
-#if defined __extern_always_inline && defined __va_arg_pack
-# include <bits/error.h>
+#ifdef __LDBL_COMPAT
+# include <bits/error-ldbl.h>
+#else
+/* Do not inline error and error_at_line when long double has the same
+   size of double, because that would invalidate the redirections to the
+   compatibility functions.  */
+# if defined __extern_always_inline && defined __va_arg_pack
+#  include <bits/error.h>
+# endif
 #endif
 
 __END_DECLS
diff --git a/sysdeps/ieee754/ldbl-opt/Versions b/sysdeps/ieee754/ldbl-opt/Versions
index 5bc88dd..ced253c 100644
--- a/sysdeps/ieee754/ldbl-opt/Versions
+++ b/sysdeps/ieee754/ldbl-opt/Versions
@@ -82,6 +82,7 @@ libc {
     __nldbl_argp_error; __nldbl_argp_failure;
     __nldbl_warn; __nldbl_vwarn; __nldbl_warnx; __nldbl_vwarnx;
     __nldbl_err; __nldbl_verr; __nldbl_errx; __nldbl_verrx;
+    __nldbl_error; __nldbl_error_at_line;
   }
 }
 libm {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 2bd26fa..c39d667 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -19,6 +19,7 @@
 
 #include <argp.h>
 #include <err.h>
+#include <error.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <libio/strfile.h>
@@ -1095,6 +1096,27 @@ __nldbl_vwarnx (const char *format, __gnuc_va_list ap)
   __vwarnx_internal (format, ap, PRINTF_LDBL_IS_DBL);
 }
 
+void
+__nldbl_error (int status, int errnum, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_internal (status, errnum, message, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
+}
+
+void
+__nldbl_error_at_line (int status, int errnum, const char *file_name,
+		       unsigned int line_number, const char *message,
+		       ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_at_line_internal (status, errnum, file_name, line_number,
+			    message, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
+}
+
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
 compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sprintf, _IO_sprintf, GLIBC_2_0);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index 3ed697c..72b0b2d 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -24,6 +24,7 @@
 #define __NO_LONG_DOUBLE_MATH	1
 #include <argp.h>
 #include <err.h>
+#include <error.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -84,6 +85,8 @@ NLDBL_DECL (err);
 NLDBL_DECL (verr);
 NLDBL_DECL (errx);
 NLDBL_DECL (verrx);
+NLDBL_DECL (error);
+NLDBL_DECL (error_at_line);
 
 /* These do not exist in the normal interface, but must exist in the
    __nldbl interface so that they can be called from libnldbl.  */
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 67b8615..a566b46 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2513,6 +2513,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 2772fb3..484d17a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2473,6 +2473,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index fdd1219..5f01d16 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2518,6 +2518,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index f31f664..b0d22eb 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2231,6 +2231,8 @@ GLIBC_2.28 thrd_yield F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 5c3079a..5f99958 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -2336,6 +2336,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 7b5895a..ebe06e3 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2483,6 +2483,8 @@ GLIBC_2.9 updwtmpx F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 1235d75..71c82ac 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2372,6 +2372,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 3e059c5..2d08ca2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2488,6 +2488,8 @@ GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
 GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_error F
+GLIBC_2.29 __nldbl_error_at_line F
 GLIBC_2.29 __nldbl_errx F
 GLIBC_2.29 __nldbl_verr F
 GLIBC_2.29 __nldbl_verrx F

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b13dc6eceb73a1a64f69ef11146d8ad07a4bb332

commit b13dc6eceb73a1a64f69ef11146d8ad07a4bb332
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Wed Aug 8 09:58:36 2018 -0300

    ldbl-opt: Add err, errx, verr, verrx, warn, warnx, vwarn, and vwarnx
    
    When support for long double format with 128-bits (-mlong-double-128)
    was added for platforms where long double had the same format as double,
    such as powerpc, compatibility versions for the functions listed in the
    commit title were missed.  Since the older format of long double can
    still be used (with -mlong-double-64), using these functions with a
    format string that requests the printing of long double variables will
    produce wrong outputs.
    
    This patch adds the missing compatibility functions and header magic to
    redirect calls to them when -mlong-double-64 is in use.
    
    Tested for powerpc64le.
    
    	* include/err.h: Add prototypes for the internal functions:
    	__vwarnx_internal and __vwarn_internal.
    	* misc/bits/err-ldbl.h: New file.
    	* misc/err.h: Include bits/err-ldbl.h when __LDBL_COMPAT is
    	defined, i.e.: when -mlong-double-64 is in use.
    	* sysdeps/ieee754/ldbl-opt/Versions (libc): Add __nldbl_warn,
    	__nldbl_vwarn, __nldbl_warnx, __nldbl_vwarnx, __nldbl_err,
    	__nldbl_verr, __nldbl_errx, and __nldbl_verrx.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Include err.h.
    	(VA_CALL): New macro.
    	(__nldbl_vwarn, __nldbl_vwarnx, __nldbl_warn, __nldbl_warnx)
    	(__nldbl_verr, __nldbl_verrx, __nldbl_err, __nldbl_errx): New
    	functions.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Include err.h and
    	declare prototypes for the new functions.
    	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Update.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.

diff --git a/include/err.h b/include/err.h
index 3828559..7c05cd1 100644
--- a/include/err.h
+++ b/include/err.h
@@ -1,6 +1,15 @@
 #ifndef _ERR_H
 #include <misc/err.h>
 
+/* Prototypes for internal err.h functions.  */
+void
+__vwarnx_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags);
+
+void
+__vwarn_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags);
+
 # ifndef _ISOMAC
 
 libc_hidden_proto (warn)
diff --git a/misc/bits/err-ldbl.h b/misc/bits/err-ldbl.h
new file mode 100644
index 0000000..dd74c0e
--- /dev/null
+++ b/misc/bits/err-ldbl.h
@@ -0,0 +1,30 @@
+/* Redirections for err.h functions for -mlong-double-64.
+   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 _ERR_H
+# error "Never include <bits/err-ldbl.h> directly; use <err.h> instead."
+#endif
+
+__LDBL_REDIR_DECL (warn)
+__LDBL_REDIR_DECL (vwarn)
+__LDBL_REDIR_DECL (warnx)
+__LDBL_REDIR_DECL (vwarnx)
+__LDBL_REDIR_DECL (err)
+__LDBL_REDIR_DECL (verr)
+__LDBL_REDIR_DECL (errx)
+__LDBL_REDIR_DECL (verrx)
diff --git a/misc/err.h b/misc/err.h
index fec4fd2..f2d4bef 100644
--- a/misc/err.h
+++ b/misc/err.h
@@ -52,6 +52,10 @@ extern void errx (int __status, const char *__format, ...)
 extern void verrx (int __status, const char *, __gnuc_va_list)
      __attribute__ ((__noreturn__, __format__ (__printf__, 2, 0)));
 
+#ifdef __LDBL_COMPAT
+# include <bits/err-ldbl.h>
+#endif
+
 __END_DECLS
 
 #endif	/* err.h */
diff --git a/sysdeps/ieee754/ldbl-opt/Versions b/sysdeps/ieee754/ldbl-opt/Versions
index 855f541..5bc88dd 100644
--- a/sysdeps/ieee754/ldbl-opt/Versions
+++ b/sysdeps/ieee754/ldbl-opt/Versions
@@ -80,6 +80,8 @@ libc {
   }
   GLIBC_2.29 {
     __nldbl_argp_error; __nldbl_argp_failure;
+    __nldbl_warn; __nldbl_vwarn; __nldbl_warnx; __nldbl_vwarnx;
+    __nldbl_err; __nldbl_verr; __nldbl_errx; __nldbl_verrx;
   }
 }
 libm {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 572f377..2bd26fa 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <argp.h>
+#include <err.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <libio/strfile.h>
@@ -1034,6 +1035,66 @@ __nldbl_argp_failure (const struct argp_state *state, int status,
   va_end (ap);
 }
 
+#define VA_CALL(call)							\
+{									\
+  va_list ap;								\
+  va_start (ap, format);						\
+  call (format, ap, PRINTF_LDBL_IS_DBL);				\
+  va_end (ap);								\
+}
+
+void
+__nldbl_err (int status, const char *format, ...)
+{
+  VA_CALL (__vwarn_internal)
+  exit (status);
+}
+
+void
+__nldbl_errx (int status, const char *format, ...)
+{
+  VA_CALL (__vwarnx_internal)
+  exit (status);
+}
+
+void
+__nldbl_verr (int status, const char *format, __gnuc_va_list ap)
+{
+  __vwarn_internal (format, ap, PRINTF_LDBL_IS_DBL);
+  exit (status);
+}
+
+void
+__nldbl_verrx (int status, const char *format, __gnuc_va_list ap)
+{
+  __vwarnx_internal (format, ap, PRINTF_LDBL_IS_DBL);
+  exit (status);
+}
+
+void
+__nldbl_warn (const char *format, ...)
+{
+  VA_CALL (__vwarn_internal)
+}
+
+void
+__nldbl_warnx (const char *format, ...)
+{
+  VA_CALL (__vwarnx_internal)
+}
+
+void
+__nldbl_vwarn (const char *format, __gnuc_va_list ap)
+{
+  __vwarn_internal (format, ap, PRINTF_LDBL_IS_DBL);
+}
+
+void
+__nldbl_vwarnx (const char *format, __gnuc_va_list ap)
+{
+  __vwarnx_internal (format, ap, PRINTF_LDBL_IS_DBL);
+}
+
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
 compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sprintf, _IO_sprintf, GLIBC_2_0);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index 0e685ab..3ed697c 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -23,6 +23,7 @@
 /* Avoid long double prototypes.  */
 #define __NO_LONG_DOUBLE_MATH	1
 #include <argp.h>
+#include <err.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -75,6 +76,14 @@ NLDBL_DECL (__isoc99_vfwscanf);
 NLDBL_DECL (__isoc99_vswscanf);
 NLDBL_DECL (argp_error);
 NLDBL_DECL (argp_failure);
+NLDBL_DECL (warn);
+NLDBL_DECL (vwarn);
+NLDBL_DECL (warnx);
+NLDBL_DECL (vwarnx);
+NLDBL_DECL (err);
+NLDBL_DECL (verr);
+NLDBL_DECL (errx);
+NLDBL_DECL (verrx);
 
 /* These do not exist in the normal interface, but must exist in the
    __nldbl interface so that they can be called from libnldbl.  */
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index a7d79dc..67b8615 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2512,3 +2512,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index dabf2cf..2772fb3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2472,3 +2472,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 5dc2588..fdd1219 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2517,3 +2517,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index b531426..f31f664 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2230,3 +2230,11 @@ GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index b39f28c..5c3079a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -2335,3 +2335,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 2ccb161..7b5895a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2482,3 +2482,11 @@ GLIBC_2.9 updwtmp F
 GLIBC_2.9 updwtmpx F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 9ba3750..1235d75 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2371,3 +2371,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 500b806..3e059c5 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2487,3 +2487,11 @@ GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
 GLIBC_2.29 __nldbl_argp_error F
 GLIBC_2.29 __nldbl_argp_failure F
+GLIBC_2.29 __nldbl_err F
+GLIBC_2.29 __nldbl_errx F
+GLIBC_2.29 __nldbl_verr F
+GLIBC_2.29 __nldbl_verrx F
+GLIBC_2.29 __nldbl_vwarn F
+GLIBC_2.29 __nldbl_vwarnx F
+GLIBC_2.29 __nldbl_warn F
+GLIBC_2.29 __nldbl_warnx F

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a165bbb6602321d304a8c4d4a2167dfffaa5742e

commit a165bbb6602321d304a8c4d4a2167dfffaa5742e
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Jul 3 10:43:13 2018 -0300

    ldbl-opt: Reuse argp tests that print long double
    
    The test cases tst-ldbl-argp-error and tst-ldbl-argp-failure check that
    the conversion specifier '%Lf' correctly prints long double values with
    the default long double format for a platform.  This patch reuses those
    test cases for long double with the same format as double
    (-mlong-double-64).
    
    Tested for powerpc64le.
    
    	* sysdeps/ieee754/ldbl-opt/Makefile
    	[subdir == argp] (tests-internal): Add tst-nldbl-argp-error and
    	tst-nldbl-argp-failure.
    	[subdir == argp] ($(objpfx)tst-nldbl-argp-%.c): New rule.
    	[subdir == argp] (CFLAGS-tst-nldbl-argp-error.c)
    	(CFLAGS-tst-nldbl-argp-failure.c): New variables.
    	[subdir == argp && run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-nldbl-argp-error.out and
    	$(objpfx)tst-nldbl-argp-failure.out.
    	[subdir == argp] ($(objpfx)tst-nldbl-argp-%.out): New build and
    	run rule.

diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index 8fedbb8..27b1d0f 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -176,3 +176,24 @@ tests += test-narrow-macros-ldbl-64
 CFLAGS-test-narrow-macros-ldbl-64.c += -mlong-double-64
 
 endif
+
+# Tests for argp.h functions (reusing the relevant tests from argp/)
+ifeq ($(subdir),argp)
+tests-internal += tst-nldbl-argp-error tst-nldbl-argp-failure
+
+$(objpfx)tst-nldbl-argp-%.c: tst-ldbl-argp-%.c
+	cp $< $@
+
+CFLAGS-tst-nldbl-argp-error.c += -mlong-double-64
+CFLAGS-tst-nldbl-argp-failure.c += -mlong-double-64
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-nldbl-argp-error.out
+tests-special += $(objpfx)tst-nldbl-argp-failure.out
+endif
+
+$(objpfx)tst-nldbl-argp-%.out: \
+  tst-ldbl-argp-%.sh $(objpfx)tst-nldbl-argp-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+endif

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5a90c1ef09effcb5d92fab5b1fba51589d1495ce

commit 5a90c1ef09effcb5d92fab5b1fba51589d1495ce
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Wed Jul 4 11:54:11 2018 -0300

    ldbl-opt: Add arpg_error and argp_failure
    
    The functions argp_error and argp_failure are missing support for
    printing long double values when long double has the same format as
    double.  This patch adds the new functions __nldbl_argp_error and
    __nldbl_argp_failure, as well as header magic to redirect calls to them
    when -mlong-double-64 is in use.
    
    Tested for powerpc64le.
    
    	* argp/argp.h [defined __LDBL_COMPAT]: Include bits/argp-ldbl.h.
    	* argp/bits/argp-ldbl.h: New file.
    	* include/argp.h: Include stdarg.h.  Add prototypes for internal
    	functions: __argp_error_internal and __argp_failure_internal.
    	* sysdeps/ieee754/ldbl-opt/Versions (libc) Add
    	__nldbl_argp_error and __nldbl_argp_failure.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Include argp.h.
    	(__nldbl_argp_error, __nldbl_argp_failure): New functions.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Include argp.h.
    	Redirect argp_error and argp_failure calls.
    	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Update.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
    	Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.

diff --git a/argp/argp.h b/argp/argp.h
index 0f25833..fd2b20d 100644
--- a/argp/argp.h
+++ b/argp/argp.h
@@ -554,6 +554,10 @@ __NTH (__option_is_end (const struct argp_option *__opt))
 # endif
 #endif /* Use extern inlines.  */
 
+#ifdef __LDBL_COMPAT
+# include <bits/argp-ldbl.h>
+#endif
+
 __END_DECLS
 
 #endif /* argp.h */
diff --git a/argp/bits/argp-ldbl.h b/argp/bits/argp-ldbl.h
new file mode 100644
index 0000000..53c7f4c
--- /dev/null
+++ b/argp/bits/argp-ldbl.h
@@ -0,0 +1,25 @@
+/* Redirections for argp functions for -mlong-double-64.
+   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 _ARGP_H
+# error "Never include <bits/argp-ldbl.h> directly; use <argp.h> instead."
+#endif
+
+__LDBL_REDIR_DECL (argp_error)
+__LDBL_REDIR_DECL (argp_failure)
+
diff --git a/include/argp.h b/include/argp.h
index 6cf8782..7077471 100644
--- a/include/argp.h
+++ b/include/argp.h
@@ -1,6 +1,17 @@
 #ifndef _ARGP_H
 #include <argp/argp.h>
 
+/* Prototypes for internal argp.h functions.  */
+#include <stdarg.h>
+void
+__argp_error_internal (const struct argp_state *state, const char *fmt,
+		       va_list ap, unsigned int mode_flags);
+
+void
+__argp_failure_internal (const struct argp_state *state, int status,
+			 int errnum, const char *fmt, va_list ap,
+			 unsigned int mode_flags);
+
 #ifndef _ISOMAC
 extern __typeof (__argp_error) __argp_error attribute_hidden;
 extern __typeof (__argp_failure) __argp_failure attribute_hidden;
diff --git a/sysdeps/ieee754/ldbl-opt/Versions b/sysdeps/ieee754/ldbl-opt/Versions
index af0c4a0..855f541 100644
--- a/sysdeps/ieee754/ldbl-opt/Versions
+++ b/sysdeps/ieee754/ldbl-opt/Versions
@@ -78,6 +78,9 @@ libc {
     __nldbl___dprintf_chk; __nldbl___vdprintf_chk;
     __nldbl___obstack_printf_chk; __nldbl___obstack_vprintf_chk;
   }
+  GLIBC_2.29 {
+    __nldbl_argp_error; __nldbl_argp_failure;
+  }
 }
 libm {
   NLDBL_VERSION {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 450fcd7..572f377 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -17,6 +17,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <argp.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <libio/strfile.h>
@@ -1013,6 +1014,26 @@ __nldbl___isoc99_wscanf (const wchar_t *fmt, ...)
   return ret;
 }
 
+void
+__nldbl_argp_error (const struct argp_state *state, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_error_internal (state, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
+}
+
+void
+__nldbl_argp_failure (const struct argp_state *state, int status,
+			int errnum, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_failure_internal (state, status, errnum, fmt, ap,
+			   PRINTF_LDBL_IS_DBL);
+  va_end (ap);
+}
+
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
 compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sprintf, _IO_sprintf, GLIBC_2_0);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index 4b7f909..0e685ab 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -22,6 +22,7 @@
 
 /* Avoid long double prototypes.  */
 #define __NO_LONG_DOUBLE_MATH	1
+#include <argp.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -72,6 +73,8 @@ NLDBL_DECL (__isoc99_swscanf);
 NLDBL_DECL (__isoc99_vwscanf);
 NLDBL_DECL (__isoc99_vfwscanf);
 NLDBL_DECL (__isoc99_vswscanf);
+NLDBL_DECL (argp_error);
+NLDBL_DECL (argp_failure);
 
 /* These do not exist in the normal interface, but must exist in the
    __nldbl interface so that they can be called from libnldbl.  */
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index e22b916..a7d79dc 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2510,3 +2510,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 45839ed..dabf2cf 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2470,3 +2470,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 344e5ae..5dc2588 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2515,3 +2515,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index e26930e..b531426 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2228,3 +2228,5 @@ GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 8c1781a..b39f28c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -2333,3 +2333,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 3a5ec2a..2ccb161 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2480,3 +2480,5 @@ GLIBC_2.9 pututline F
 GLIBC_2.9 pututxline F
 GLIBC_2.9 updwtmp F
 GLIBC_2.9 updwtmpx F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 04a539f..9ba3750 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2369,3 +2369,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index d308ac8..500b806 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2485,3 +2485,5 @@ GLIBC_2.9 dup3 F
 GLIBC_2.9 epoll_create1 F
 GLIBC_2.9 inotify_init1 F
 GLIBC_2.9 pipe2 F
+GLIBC_2.29 __nldbl_argp_error F
+GLIBC_2.29 __nldbl_argp_failure F

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=525bfa87856c78ff33cec354bfdab4bf63839d81

commit 525bfa87856c78ff33cec354bfdab4bf63839d81
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Wed Jun 6 11:48:49 2018 -0300

    Add internal implementations for argp.h, err.h, and error.h functions
    
    Since the introduction of explicit flags in the internal implementation
    of the printf family of functions, the 'mode' parameter can be used to
    select which format long double parameters have (with the mode flag:
    PRINTF_LDBL_IS_DBL).  This patch uses this feature in the implementation
    of some functions in argp.h, err.h, and error.h (only those that take a
    format string and positional parameters).  Future patches will add
    support for 'nldbl' and 'ieee128' versions of these functions.
    
    Tested for powerpc64le.
    
    	* argp/argp-help.c (__argp_error_internal): New function,
    	renamed from __argp_error, but that takes a 'mode_flags'
    	parameter to control the format of long double parameters.
    	(__argp_error): Converted into a call __argp_error_internal.
    	(__argp_failure_internal): New function, renamed from
    	__argp_failure, but that takes a 'mode_flags' parameter.
    	(__argp_failure): Converted into a call __argp_failure_internal.
    	* misc/err.c: [defined _LIBC] Include libioP.h for the
    	definitions of __vfprintf_internal and __vfwprintf_internal.
    	(convert_and_print): Add 'mode_flags' parameter.  Call
    	__vfwprintf_internal, instead of __vfwprintf.
    	(__vwarnx_internal): New function, renamed from vwarnx, but that
    	takes a 'mode_flags' parameter.
    	(vwarnx): Converted into a call to __vwarnx_internal.
    	(__vwarn_internal): New function, renamed from vwarn, but that
    	takes a 'mode_flags' parameter.
    	(vwarn): Converted into a call to __vwarn_internal.
    	* misc/error.c: Include libioP.h for the definitions of
    	__vfprintf_internal and __vfwprintf_internal.
    	(error_tail): Add 'mode_flags' parameter. Call
    	__vfprintf_internal and __vfwprintf_internal.
    	(__error_internal): New function, renamed from error, but that
    	takes a 'mode_flags' parameter.
    	(error): Converted into a call to __error_internal.
    	(__error_at_line_internal): New function, renamed from
    	error_at_line, but that takes a 'mode_flags' parameter.
    	(error_at_line): Converted into a call to
    	__error_at_line_internal.

diff --git a/argp/argp-help.c b/argp/argp-help.c
index 9f25338..6113cb2 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -1750,7 +1750,8 @@ weak_alias (__argp_state_help, argp_state_help)
    by the program name and `:', to stderr, and followed by a `Try ... --help'
    message, then exit (1).  */
 void
-__argp_error (const struct argp_state *state, const char *fmt, ...)
+__argp_error_internal (const struct argp_state *state, const char *fmt,
+		       va_list ap, unsigned int mode_flags)
 {
   if (!state || !(state->flags & ARGP_NO_ERRS))
     {
@@ -1758,18 +1759,14 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
 
       if (stream)
 	{
-	  va_list ap;
-
 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
 	  __flockfile (stream);
 #endif
 
-	  va_start (ap, fmt);
-
 #ifdef _LIBC
 	  char *buf;
 
-	  if (__vasprintf (&buf, fmt, ap) < 0)
+	  if (__vasprintf_internal (&buf, fmt, ap, mode_flags) < 0)
 	    buf = NULL;
 
 	  __fxprintf (stream, "%s: %s\n",
@@ -1782,21 +1779,27 @@ __argp_error (const struct argp_state *state, const char *fmt, ...)
 	  putc_unlocked (':', stream);
 	  putc_unlocked (' ', stream);
 
-	  vfprintf (stream, fmt, ap);
+	  __vfprintf_internal (stream, fmt, ap, mode_flags);
 
 	  putc_unlocked ('\n', stream);
 #endif
 
 	  __argp_state_help (state, stream, ARGP_HELP_STD_ERR);
 
-	  va_end (ap);
-
 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
 	  __funlockfile (stream);
 #endif
 	}
     }
 }
+void
+__argp_error (const struct argp_state *state, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_error_internal (state, fmt, ap, 0);
+  va_end (ap);
+}
 #ifdef weak_alias
 weak_alias (__argp_error, argp_error)
 #endif
@@ -1810,8 +1813,9 @@ weak_alias (__argp_error, argp_error)
    *parsing errors*, and the former is for other problems that occur during
    parsing but don't reflect a (syntactic) problem with the input.  */
 void
-__argp_failure (const struct argp_state *state, int status, int errnum,
-		const char *fmt, ...)
+__argp_failure_internal (const struct argp_state *state, int status,
+			 int errnum, const char *fmt, va_list ap,
+			 unsigned int mode_flags)
 {
   if (!state || !(state->flags & ARGP_NO_ERRS))
     {
@@ -1833,13 +1837,10 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 
 	  if (fmt)
 	    {
-	      va_list ap;
-
-	      va_start (ap, fmt);
 #ifdef _LIBC
 	      char *buf;
 
-	      if (__vasprintf (&buf, fmt, ap) < 0)
+	      if (__vasprintf_internal (&buf, fmt, ap, mode_flags) < 0)
 		buf = NULL;
 
 	      __fxprintf (stream, ": %s", buf);
@@ -1849,10 +1850,8 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 	      putc_unlocked (':', stream);
 	      putc_unlocked (' ', stream);
 
-	      vfprintf (stream, fmt, ap);
+	      __vfprintf_internal (stream, fmt, ap, mode_flags);
 #endif
-
-	      va_end (ap);
 	    }
 
 	  if (errnum)
@@ -1887,6 +1886,15 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 	}
     }
 }
+void
+__argp_failure (const struct argp_state *state, int status, int errnum,
+		const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  __argp_failure_internal (state, status, errnum, fmt, ap, 0);
+  va_end (ap);
+}
 #ifdef weak_alias
 weak_alias (__argp_failure, argp_failure)
 #endif
diff --git a/misc/err.c b/misc/err.c
index 2b836e8..e46bda3 100644
--- a/misc/err.c
+++ b/misc/err.c
@@ -27,6 +27,10 @@
 #define flockfile(s) _IO_flockfile (s)
 #define funlockfile(s) _IO_funlockfile (s)
 
+#ifdef _LIBC
+# include <../libio/libioP.h>
+#endif
+
 extern char *__progname;
 
 #define VA(call)							      \
@@ -38,7 +42,8 @@ extern char *__progname;
 }
 
 static void
-convert_and_print (const char *format, __gnuc_va_list ap)
+convert_and_print (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags)
 {
 #define ALLOCA_LIMIT	2000
   size_t len;
@@ -79,32 +84,33 @@ convert_and_print (const char *format, __gnuc_va_list ap)
     /* The string cannot be converted.  */
     wformat = (wchar_t *) L"???";
 
-  __vfwprintf (stderr, wformat, ap);
+  __vfwprintf_internal (stderr, wformat, ap, mode_flags);
 }
 
 void
-vwarnx (const char *format, __gnuc_va_list ap)
+__vwarnx_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags)
 {
   flockfile (stderr);
   if (_IO_fwide (stderr, 0) > 0)
     {
       __fwprintf (stderr, L"%s: ", __progname);
-      convert_and_print (format, ap);
+      convert_and_print (format, ap, mode_flags);
       putwc_unlocked (L'\n', stderr);
     }
   else
     {
       fprintf (stderr, "%s: ", __progname);
       if (format)
-	vfprintf (stderr, format, ap);
+	__vfprintf_internal (stderr, format, ap, mode_flags);
       putc_unlocked ('\n', stderr);
     }
   funlockfile (stderr);
 }
-libc_hidden_def (vwarnx)
 
 void
-vwarn (const char *format, __gnuc_va_list ap)
+__vwarn_internal (const char *format, __gnuc_va_list ap,
+		   unsigned int mode_flags)
 {
   int error = errno;
 
@@ -114,7 +120,7 @@ vwarn (const char *format, __gnuc_va_list ap)
       __fwprintf (stderr, L"%s: ", __progname);
       if (format)
 	{
-	  convert_and_print (format, ap);
+	  convert_and_print (format, ap, mode_flags);
 	  fputws_unlocked (L": ", stderr);
 	}
       __set_errno (error);
@@ -125,7 +131,7 @@ vwarn (const char *format, __gnuc_va_list ap)
       fprintf (stderr, "%s: ", __progname);
       if (format)
 	{
-	  vfprintf (stderr, format, ap);
+	  __vfprintf_internal (stderr, format, ap, mode_flags);
 	  fputs_unlocked (": ", stderr);
 	}
       __set_errno (error);
@@ -133,8 +139,20 @@ vwarn (const char *format, __gnuc_va_list ap)
     }
   funlockfile (stderr);
 }
+
+void
+vwarn (const char *format, __gnuc_va_list ap)
+{
+  __vwarn_internal (format, ap, 0);
+}
 libc_hidden_def (vwarn)
 
+void
+vwarnx (const char *format, __gnuc_va_list ap)
+{
+  __vwarnx_internal (format, ap, 0);
+}
+libc_hidden_def (vwarnx)
 
 void
 warn (const char *format, ...)
diff --git a/misc/error.c b/misc/error.c
index b4e8b6c..9f8067e 100644
--- a/misc/error.c
+++ b/misc/error.c
@@ -39,6 +39,7 @@
 # include <stdbool.h>
 # include <stdint.h>
 # include <wchar.h>
+# include <../libio/libioP.h>
 # define mbsrtowcs __mbsrtowcs
 # define USE_UNLOCKED_IO 0
 # define _GL_ATTRIBUTE_FORMAT_PRINTF(a, b)
@@ -200,7 +201,8 @@ print_errno_message (int errnum)
 }
 
 static void _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) _GL_ARG_NONNULL ((3))
-error_tail (int status, int errnum, const char *message, va_list args)
+error_tail (int status, int errnum, const char *message, va_list args,
+	    unsigned int mode_flags)
 {
 #if _LIBC
   if (_IO_fwide (stderr, 0) > 0)
@@ -261,14 +263,14 @@ error_tail (int status, int errnum, const char *message, va_list args)
 	  wmessage = (wchar_t *) L"???";
 	}
 
-      __vfwprintf (stderr, wmessage, args);
+      __vfwprintf_internal (stderr, wmessage, args, mode_flags);
 
       if (use_malloc)
 	free (wmessage);
     }
   else
 #endif
-    vfprintf (stderr, message, args);
+    __vfprintf_internal (stderr, message, args, mode_flags);
   va_end (args);
 
   ++error_message_count;
@@ -290,10 +292,9 @@ error_tail (int status, int errnum, const char *message, va_list args)
    If ERRNUM is nonzero, print its corresponding system error message.
    Exit with status STATUS if it is nonzero.  */
 void
-error (int status, int errnum, const char *message, ...)
+__error_internal (int status, int errnum, const char *message,
+		  va_list args, unsigned int mode_flags)
 {
-  va_list args;
-
 #if defined _LIBC && defined __libc_ptf_call
   /* We do not want this call to be cut short by a thread
      cancellation.  Therefore disable cancellation for now.  */
@@ -317,8 +318,7 @@ error (int status, int errnum, const char *message, ...)
 #endif
     }
 
-  va_start (args, message);
-  error_tail (status, errnum, message, args);
+  error_tail (status, errnum, message, args, mode_flags);
 
 #ifdef _LIBC
   _IO_funlockfile (stderr);
@@ -327,17 +327,25 @@ error (int status, int errnum, const char *message, ...)
 # endif
 #endif
 }
+
+void
+error (int status, int errnum, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_internal (status, errnum, message, ap, 0);
+  va_end (ap);
+}
 
 /* Sometimes we want to have at most one error per line.  This
    variable controls whether this mode is selected or not.  */
 int error_one_per_line;
 
 void
-error_at_line (int status, int errnum, const char *file_name,
-	       unsigned int line_number, const char *message, ...)
+__error_at_line_internal (int status, int errnum, const char *file_name,
+			  unsigned int line_number, const char *message,
+			  va_list args, unsigned int mode_flags)
 {
-  va_list args;
-
   if (error_one_per_line)
     {
       static const char *old_file_name;
@@ -388,8 +396,7 @@ error_at_line (int status, int errnum, const char *file_name,
 	   file_name, line_number);
 #endif
 
-  va_start (args, message);
-  error_tail (status, errnum, message, args);
+  error_tail (status, errnum, message, args, mode_flags);
 
 #ifdef _LIBC
   _IO_funlockfile (stderr);
@@ -399,6 +406,17 @@ error_at_line (int status, int errnum, const char *file_name,
 #endif
 }
 
+void
+error_at_line (int status, int errnum, const char *file_name,
+	       unsigned int line_number, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  __error_at_line_internal (status, errnum, file_name, line_number,
+			    message, ap, 0);
+  va_end (ap);
+}
+
 #ifdef _LIBC
 /* Make the weak alias.  */
 # undef error

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=45e5a6d4cc7f57ec68443021a810aa70e0cc3029

commit 45e5a6d4cc7f57ec68443021a810aa70e0cc3029
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:32:04 2018 -0500

    Use PRINTF_LDBL_IS_DBL instead of __ldbl_is_dbl.
    
    After all that prep work, nldbl-compat.c can now use PRINTF_LDBL_IS_DBL
    instead of __no_long_double to control the behavior of printf-like
    functions; this is the last thing we needed __no_long_double for, so it
    can go away entirely.
    
    	* stdio-common/vfprintf-internal.c
    	(__vfprintf_internal, __vfwprintf_internal): Don't use __ldbl_is_dbl.
    	* sysdeps/generic/math_ldbl_opt.h: Remove __ldbl_is_dbl.
    	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h: Remove __ldbl_is_dbl
    	and __no_long_double.
    	* sysdeps/ieee754/ldbl-opt/math_ldbl_opt.c: Remove file.
    	* sysdeps/ieee754/ldbl-opt/Makefile (routines): Remove math_ldbl_opt.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
    	(__nldbl_cleanup, set_no_long_double, clear_no_long_double): Remove.
    	(__nldbl___asprintf, __nldbl_dprintf, __nldbl_fprintf)
    	(__nldbl_fwprintf, __nldbl_printf, __nldbl_sprintf)
    	(__nldbl_vfprintf, __nldbl___vsprintf, __nldbl_obstack_vprintf)
    	(__ndlbl_obstack_printf, __nldbl_snprintf, __nldbl_swprintf)
    	(__nldbl_vasprintf, __nldbl_vdprintf, __nldbl_vfwprintf)
    	(__nldbl_vprintf, __nldbl_vsnprintf, __ndlbl_vswprintf)
    	(__nldbl_vwprintf, __nldbl_wprintf):
    	Directly call the appropriate __v*printf_internal routine, passing
    	PRINTF_LDBL_IS_DBL.  Do not mess with __no_long_double. Normalize
    	variable names.
    	(__nldbl___fprintf_chk, __nldbl___fwprintf_chk)
    	(__nldbl___printf_chk, __nldbl___snprintf_chk)
    	(__nldbl___sprintf_chk, __nldbl___swprintf_chk)
    	(__nldbl___vfprintf_chk, __nldbl___vfwprintf_chk)
    	(__nldbl___vprintf_chk, __nldbl___vsnprintf_chk)
    	(__nldbl___vsprintf_chk, __nldbl___vswprintf_chk)
    	(__nldbl___vwprintf_chk, __nldbl___wprintf_chk)
    	(__nldbl___vasprintf_chk, __nldbl___asprintf_chk)
    	(__nldbl___vdprintf_chk, __nldbl___dprintf_chk)
    	(__nldbl___obstack_vprintf_chk, __nldbl___obstack_printf_chk):
    	Likewise, and also pass PRINTF_FORTIFY when appropriate.
    	(__nldbl_syslog, __nldbl_vsyslog):
    	Directly call __vsyslog_internal, passing PRINTF_LDBL_IS_DBL.
    	(__nldbl_syslog_chk): Likewise, and also pass PRINTF_FORTIFY when
    	appropriate.
    	(__nldbl_vsyslog_chk): Likewise, and also pass PRINTF_FORTIFY when
    	appropriate.  Remove libc_hidden_proto and libc_hidden_def.

diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index e2f44b7..2d9016e 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1282,10 +1282,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
      0 if unknown.  */
   int readonly_format = 0;
 
-  /* Temporarily honor environmental settings.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= PRINTF_LDBL_IS_DBL;
-
   /* Orient the stream.  */
 #ifdef ORIENT
   ORIENT;
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 92f670d..fbd2c82 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -15,4 +15,3 @@
 #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/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index ef790ad..8fedbb8 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -8,7 +8,7 @@ endif
 
 ifeq ($(subdir),math)
 libm-routines += s_nexttowardfd
-routines += math_ldbl_opt nldbl-compat
+routines += nldbl-compat
 
 extra-libs += libnldbl
 libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index 70471e9..57ca3ae 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -40,8 +40,4 @@
 #endif
 
 #ifndef __ASSEMBLER__
-/* Set temporarily to non-zero if long double should be considered
-   the same as double.  */
-extern __thread int __no_long_double attribute_tls_model_ie attribute_hidden;
-# define __ldbl_is_dbl __builtin_expect (__no_long_double, 0)
 #endif
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 1b67de8..450fcd7 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -45,7 +45,6 @@ libc_hidden_proto (__nldbl_obstack_vprintf)
 libc_hidden_proto (__nldbl___vfwprintf_chk)
 libc_hidden_proto (__nldbl___vsnprintf_chk)
 libc_hidden_proto (__nldbl___vfprintf_chk)
-libc_hidden_proto (__nldbl___vsyslog_chk)
 libc_hidden_proto (__nldbl___vsprintf_chk)
 libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___vasprintf_chk)
@@ -56,17 +55,6 @@ libc_hidden_proto (__nldbl___isoc99_vfscanf)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
 libc_hidden_proto (__nldbl___isoc99_vfwscanf)
 
-static void
-__nldbl_cleanup (void *arg)
-{
-  __no_long_double = 0;
-}
-
-#define set_no_long_double() \
-  __libc_cleanup_push (__nldbl_cleanup, NULL); __no_long_double = 1
-#define clear_no_long_double() \
-  __no_long_double = 0; __libc_cleanup_pop (0)
-
 /* Compatibility with IEEE double as long double.
    IEEE quad long double is used by default for most programs, so
    we don't need to split this into one file per function for the
@@ -76,14 +64,14 @@ int
 attribute_compat_text_section
 __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vasprintf (string_ptr, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (string_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl___asprintf, __nldbl_asprintf)
 
@@ -91,28 +79,28 @@ int
 attribute_compat_text_section
 __nldbl_dprintf (int d, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vdprintf (d, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_fprintf (FILE *stream, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
 
@@ -120,28 +108,28 @@ int
 attribute_compat_text_section weak_function
 __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stream, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_printf (const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_printf, __nldbl__IO_printf)
 
@@ -149,14 +137,14 @@ int
 attribute_compat_text_section
 __nldbl_sprintf (char *s, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsprintf (s, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 strong_alias (__nldbl_sprintf, __nldbl__IO_sprintf)
 
@@ -164,11 +152,7 @@ int
 attribute_compat_text_section
 __nldbl_vfprintf (FILE *s, const char *fmt, va_list ap)
 {
-  int done;
-  set_no_long_double ();
-  done = __vfprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return done;
+  return __vfprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfprintf)
 strong_alias (__nldbl_vfprintf, __nldbl__IO_vfprintf)
@@ -177,11 +161,7 @@ int
 attribute_compat_text_section
 __nldbl___vsprintf (char *string, const char *fmt, va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __vsprintf_internal (string, -1, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __vsprintf_internal (string, -1, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 strong_alias (__nldbl___vsprintf, __nldbl__IO_vsprintf)
 weak_alias (__nldbl___vsprintf, __nldbl_vsprintf)
@@ -192,11 +172,7 @@ attribute_compat_text_section
 __nldbl_obstack_vprintf (struct obstack *obstack, const char *fmt,
 			 va_list ap)
 {
-  int done;
-  __no_long_double = 1;
-  done = __obstack_vprintf_internal (obstack, fmt, ap, 0);
-  __no_long_double = 0;
-  return done;
+  return __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_obstack_vprintf)
 
@@ -204,63 +180,55 @@ int
 attribute_compat_text_section
 __nldbl_obstack_printf (struct obstack *obstack, const char *fmt, ...)
 {
-  int result;
+  int ret;
   va_list ap;
   va_start (ap, fmt);
-  result = __nldbl_obstack_vprintf (obstack, fmt, ap);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
-  return result;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_snprintf (char *s, size_t maxlen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vsnprintf (s, maxlen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vswprintf (s, n, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, n, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section weak_function
 __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (result_ptr, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vasprintf_internal (result_ptr, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vasprintf)
 
 int
 attribute_compat_text_section
-__nldbl_vdprintf (int d, const char *fmt, va_list arg)
+__nldbl_vdprintf (int d, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, 0);
-  clear_no_long_double ();
-  return res;
+  return __vdprintf_internal (d, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vdprintf)
 
@@ -268,11 +236,7 @@ int
 attribute_compat_text_section weak_function
 __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, 0);
-  clear_no_long_double ();
-  return res;
+  return __vfwprintf_internal (s, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vfwprintf)
 
@@ -280,7 +244,7 @@ int
 attribute_compat_text_section
 __nldbl_vprintf (const char *fmt, va_list ap)
 {
-  return __nldbl_vfprintf (stdout, fmt, ap);
+  return __vfprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
@@ -288,11 +252,7 @@ attribute_compat_text_section
 __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vsnprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vsnprintf)
 weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
@@ -302,11 +262,7 @@ attribute_compat_text_section weak_function
 __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
 		   va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap, 0);
-  __no_long_double = 0;
-  return res;
+  return __vswprintf_internal (string, maxlen, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 libc_hidden_def (__nldbl_vswprintf)
 
@@ -314,21 +270,21 @@ int
 attribute_compat_text_section
 __nldbl_vwprintf (const wchar_t *fmt, va_list ap)
 {
-  return __nldbl_vfwprintf (stdout, fmt, ap);
+  return __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
 }
 
 int
 attribute_compat_text_section
 __nldbl_wprintf (const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
 
-  va_start (arg, fmt);
-  done = __nldbl_vfwprintf (stdout, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, PRINTF_LDBL_IS_DBL);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
@@ -491,42 +447,51 @@ int
 attribute_compat_text_section
 __nldbl___fprintf_chk (FILE *stream, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stream, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stream, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___printf_chk (int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
@@ -534,54 +499,72 @@ attribute_compat_text_section
 __nldbl___snprintf_chk (char *s, size_t maxlen, int flag, size_t slen,
 			const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
 
-  va_start (arg, fmt);
-  done = __nldbl___vsnprintf_chk (s, maxlen, flag, slen, fmt, arg);
-  va_end (arg);
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  return done;
+  va_start (ap, fmt);
+  ret = __vsnprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
+
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___sprintf_chk (char *s, int flag, size_t slen, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (slen == 0)
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vsprintf_chk (s, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vsprintf_internal (s, slen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
+__nldbl___swprintf_chk (wchar_t *s, size_t maxlen, int flag, size_t slen,
 			const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  if (__glibc_unlikely (slen < maxlen))
+    __chk_fail ();
+
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vswprintf_chk (s, n, flag, slen, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vswprintf_internal (s, maxlen, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (s, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vfprintf_chk)
 
@@ -589,11 +572,11 @@ int
 attribute_compat_text_section
 __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vfwprintf_internal (s, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (s, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vfwprintf_chk)
 
@@ -601,7 +584,11 @@ int
 attribute_compat_text_section
 __nldbl___vprintf_chk (int flag, const char *fmt, va_list ap)
 {
-  return __nldbl___vfprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
@@ -612,12 +599,11 @@ __nldbl___vsnprintf_chk (char *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsnprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsnprintf_internal (string, maxlen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vsnprintf_chk)
 
@@ -629,12 +615,11 @@ __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt,
   if (slen == 0)
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vsprintf_internal (string, slen, fmt, ap,
-			     (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vsprintf_internal (string, slen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vsprintf_chk)
 
@@ -646,12 +631,11 @@ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
   if (__glibc_unlikely (slen < maxlen))
     __chk_fail ();
 
-  int res;
-  __no_long_double = 1;
-  res = __vswprintf_internal (string, maxlen, fmt, ap,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vswprintf_internal (string, maxlen, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vswprintf_chk)
 
@@ -659,33 +643,39 @@ int
 attribute_compat_text_section
 __nldbl___vwprintf_chk (int flag, const wchar_t *fmt, va_list ap)
 {
-  return __nldbl___vfwprintf_chk (stdout, flag, fmt, ap);
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vfwprintf_internal (stdout, fmt, ap, mode);
 }
 
 int
 attribute_compat_text_section
 __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vfwprintf_chk (stdout, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vfwprintf_internal (stdout, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list arg)
+__nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __vasprintf_internal (ptr, fmt, arg,
-			      (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (ptr, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vasprintf_chk)
 
@@ -693,25 +683,28 @@ int
 attribute_compat_text_section
 __nldbl___asprintf_chk (char **ptr, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vasprintf_chk (ptr, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vasprintf_internal (ptr, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
-__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list arg)
+__nldbl___vdprintf_chk (int d, int flag, const char *fmt, va_list ap)
 {
-  int res;
-  set_no_long_double ();
-  res = __vdprintf_internal (d, fmt, arg, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vdprintf_internal (d, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___vdprintf_chk)
 
@@ -719,27 +712,29 @@ int
 attribute_compat_text_section
 __nldbl___dprintf_chk (int d, int flag, const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___vdprintf_chk (d, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __vdprintf_internal (d, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 int
 attribute_compat_text_section
 __nldbl___obstack_vprintf_chk (struct obstack *obstack, int flag,
-			       const char *fmt, va_list arg)
+			       const char *fmt, va_list ap)
 {
-  int res;
-  __no_long_double = 1;
-  res = __obstack_vprintf_internal (obstack, fmt, arg,
-				    (flag > 0) ? PRINTF_FORTIFY : 0);
-  __no_long_double = 0;
-  return res;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __obstack_vprintf_internal (obstack, fmt, ap, mode);
 }
 libc_hidden_def (__nldbl___obstack_vprintf_chk)
 
@@ -748,14 +743,17 @@ attribute_compat_text_section
 __nldbl___obstack_printf_chk (struct obstack *obstack, int flag,
 			      const char *fmt, ...)
 {
-  va_list arg;
-  int done;
+  va_list ap;
+  int ret;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-  va_start (arg, fmt);
-  done = __nldbl___obstack_vprintf_chk (obstack, flag, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  ret = __obstack_vprintf_internal (obstack, fmt, ap, mode);
+  va_end (ap);
 
-  return done;
+  return ret;
 }
 
 extern __typeof (printf_size) __printf_size;
@@ -837,18 +835,28 @@ __nldbl_syslog (int pri, const char *fmt, ...)
 {
   va_list ap;
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
   va_end (ap);
 }
 
 void
 attribute_compat_text_section
+__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
+{
+  __vsyslog_internal (pri, fmt, ap, PRINTF_LDBL_IS_DBL);
+}
+
+void
+attribute_compat_text_section
 __nldbl___syslog_chk (int pri, int flag, const char *fmt, ...)
 {
   va_list ap;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
   va_start (ap, fmt);
-  __nldbl___vsyslog_chk (pri, flag, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
   va_end(ap);
 }
 
@@ -856,17 +864,11 @@ void
 attribute_compat_text_section
 __nldbl___vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
 {
-  set_no_long_double ();
-  __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
-  clear_no_long_double ();
-}
-libc_hidden_def (__nldbl___vsyslog_chk)
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
 
-void
-attribute_compat_text_section
-__nldbl_vsyslog (int pri, const char *fmt, va_list ap)
-{
-  __nldbl___vsyslog_chk (pri, -1, fmt, ap);
+  __vsyslog_internal (pri, fmt, ap, mode);
 }
 
 int

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=7e1e9eab7337232f233656af376dbc6359073796

commit 7e1e9eab7337232f233656af376dbc6359073796
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:32:03 2018 -0500

    Use PRINTF_FORTIFY instead of _IO_FLAGS2_FORTIFY.
    
    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.
    
    	* libio/iovsprintf.c (_IO_str_chk_overflow, _IO_str_chk_jumps):
    	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.
    	* libio/libioP.h: Update prototype of __vsprintf_internal and add
    	a comment explaining why it has the maxlen argument.
    
    	* 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/obprintf_chk.c (__obstack_printf_chk, __obstack_vprintf_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_vprintf_chk): Move to new file...
    	* debug/vobprintf_chk.c: ... here.
    	* 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 (_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.

diff --git a/debug/Makefile b/debug/Makefile
index 506cebc..2ef08cf 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 9cd4143..eb885c3 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 df3867c..b5c6282 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 cff4438..14afc07 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 63167c1..10d84ce 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 41dd481..c1a8f9e 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 426dc78..e035b42 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 cddba37..984b5e8 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 7821456..649e8ab 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 35887e4..186c177 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 dbfebff..f5975ea 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 4386127..e04514e 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 5babbf6..44426e1 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 abf2bd6..3aed308 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 58%
copy from debug/asprintf_chk.c
copy to debug/vobprintf_chk.c
index 9cd4143..edfbe8f 100644
--- a/debug/asprintf_chk.c
+++ b/debug/vobprintf_chk.c
@@ -1,5 +1,7 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Print output of stream to given obstack.
+   Copyright (C) 1996-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -15,22 +17,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 b3b2c53..69fcb72 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 95d286f..666a83b 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 53f0723..c1b1a8d 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 4d616f8..2c6fadd 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 fedc7a4..f1e8878 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 819050e..9f406e9 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 aa4ccf8..2f28be9 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -220,11 +220,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 1db0ac8..90b6e43 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -226,8 +226,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 cf4b997..513ca03 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 1025f33..68dac44 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 eca1f3a..e9446b8 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -672,8 +672,13 @@ extern int __vdprintf_internal (int d, const char *format, va_list ap,
 extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
                                        va_list ap, unsigned int mode_flags);
 
-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.  */
+extern int __vsprintf_internal (char *string, size_t maxlen,
+                                const char *format, va_list ap,
                                 unsigned int mode_flags);
+
 extern int __vsnprintf_internal (char *string, size_t maxlen,
                                  const char *format, va_list ap,
                                  unsigned int mode_flags);
@@ -788,26 +793,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 77423b2..447faa4 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 d8716f4..e2f44b7 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1285,8 +1285,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 4a40618..25ccd07 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 17fc49a..1b67de8 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 5b97824..1d6a81c 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)
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b4e7b3a3bb04d3775bf4c0b39551da5d7ece3dda

commit b4e7b3a3bb04d3775bf4c0b39551da5d7ece3dda
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:32:02 2018 -0500

    Add __vsyslog_internal, with same flags as __v*printf_internal.
    
    __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.
    
    	* 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 libc_hidden_proto for __vsyslog_chk.
    
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c (__nldbl___vsyslog_chk):
    	Use __vsyslog_internal.

diff --git a/include/sys/syslog.h b/include/sys/syslog.h
index 3be3189..459ca70 100644
--- a/include/sys/syslog.h
+++ b/include/sys/syslog.h
@@ -1,11 +1,20 @@
+#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)
 
+/* __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__ ((__format__ (__printf__, 2, 0)));
+
 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
+
+#endif /* _ISOMAC */
+#endif /* syslog.h */
diff --git a/misc/syslog.c b/misc/syslog.c
index 644dbe8..eb1283a 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,25 +114,40 @@ __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_hidden_def (__vsyslog, vsyslog)
+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;
 	int fd;
@@ -216,10 +231,7 @@ __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
 
 	    /* 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);
+            __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 +328,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 02b0241..17fc49a 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)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=47eadca9ca233c2c998e3550a370ffbe533538f7

commit 47eadca9ca233c2c998e3550a370ffbe533538f7
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:32:01 2018 -0500

    Add __v*printf_internal with flags arguments.
    
    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
    *is* exported, so that one sticks around.
    
    	* libio/libioP.h (__vfprintf_internal, __vfwprintf_internal)
    	(__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal)
    	(__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal):
    	New functions.
    	(PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants.
    	(_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes.
    
    	* stdio-common/vfprintf-internal.c: Rename from vfprintf.c.
    	Include wctype.h here if COMPILE_WPRINTF is defined.
    	Define __vfprintf_internal or __vfwprintf_internal, depending
    	on COMPILE_WPRINTF.
    	Temporarily, on entry to this function, update mode_flags
    	according to the environmental settings corresponding to
    	PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY.
    	(LDBL_IS_DBL, DO_FORTIFY): New macros.	Throughout, use
    	LDBL_IS_DBL instead of __ldbl_is_dbl, and DO_FORTIFY instead of
    	checking _IO_FLAGS2_FORTIFY on the destination FILE.
    	* stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c.
    	Include vfprintf-internal.c.  Don't include wctype.h.
    	* stdio-common/vfprintf.c: New file.  Just define __vfprintf
    	as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf
    	and vfprintf.
    	* stdio-common/vfwprintf.c: New file.  Just define __vfwprintf
    	as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf
    	and vfwprintf.
    	* stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal.
    
    	* libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal
    	and add mode_flags argument; use __vfprintf_internal.
    	(__vdprintf): New function.  Alias vdprintf to this.
    	* libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly.
    	* libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly.
    	* libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly.
    	(__obstack_printf): Use __obstack_printf_internal.
    	* libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with
    	public aliases __vsnprintf and vsnprintf.
    	* 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 for _IO_vfprintf.
    	Remove declaration of _IO_vfwprintf.
    	* libio/iolibio.h: Remove libc_hidden_proto for _IO_vsprintf.
    	Remove declarations of _IO_vswprintf, _IO_obstack_printf, and
    	_IO_obstack_printf.
    	* include/stdio.h: Add libc_hidden_proto for __vsnprintf and
    	prototype for __vasprintf.
    
    	* argp/argp-fmtstream.c: Use __vsnprintf, not _IO_vsnprintf.
    	* argp/argp-help.c: Use __vasprintf, not _IO_vasprintf.
    	* argp/argp-namefrob.c: Update to match.

diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c
index e43a0c7..2be2f52 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
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 2b6b077..9f25338 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 (&buf, fmt, ap) < 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 (&buf, fmt, ap) < 0)
 		buf = NULL;
 
 	      __fxprintf (stream, ": %s", buf);
diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h
index 5588fe1..60381e7 100644
--- a/argp/argp-namefrob.h
+++ b/argp/argp-namefrob.h
@@ -98,6 +98,8 @@
 #define __strerror_r strerror_r
 #undef __strndup
 #define __strndup strndup
+#undef __vasprintf
+#define __vasprintf vasprintf
 #undef __vsnprintf
 #define __vsnprintf vsnprintf
 
diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c
index aeb8307..63167c1 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 3ac5a3c..41dd481 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 48b4741..dbfebff 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 bc713b4..4386127 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 1ffd18c..abf2bd6 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 d20d0fb..95d286f 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 9a443bb..53f0723 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 c6a7edc..4d616f8 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 51b67c1..fedc7a4 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 17023b6..819050e 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 76cd31f..b9634af 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 9162d4e..aa4ccf8 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -17,6 +17,10 @@ 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)));
+libc_hidden_proto (__vsnprintf)
+extern int __vasprintf (char **__result_ptr, const char *__restrict __format,
+			va_list args)
+     __attribute__ ((__format__ (__printf__, 2, 0)));
 extern int __vfscanf (FILE *__restrict __s,
 		      const char *__restrict __format,
 		      __gnuc_va_list __arg)
diff --git a/libio/fwprintf.c b/libio/fwprintf.c
index fab63a8..9903f1f 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 6c94fe6..c37faab 100644
--- a/libio/iolibio.h
+++ b/libio/iolibio.h
@@ -52,14 +52,7 @@ 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 78a3a2b..afdeff0 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 4def251..cf4b997 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 30cb7d7..1025f33 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -298,8 +298,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 +317,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 135c8f9..eca1f3a 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -658,12 +658,32 @@ 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);
+extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap,
+                                 unsigned int mode_flags);
+
+extern int __vasprintf_internal (char **result_ptr, const char *format,
+                                 va_list ap, unsigned int mode_flags);
+extern int __vdprintf_internal (int d, const char *format, va_list ap,
+                                unsigned int mode_flags);
+extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt,
+                                       va_list ap, unsigned int mode_flags);
+
+extern int __vsprintf_internal (char *string, const char *format, va_list ap,
+                                unsigned int mode_flags);
+extern int __vsnprintf_internal (char *string, size_t maxlen,
+                                 const char *format, va_list ap,
+                                 unsigned int mode_flags);
+extern int __vswprintf_internal (wchar_t *string, size_t maxlen,
+                                 const wchar_t *format, va_list ap,
+                                 unsigned int mode_flags);
+
+/* Flags for __v*printf_internal.  */
+#define PRINTF_LDBL_IS_DBL 0x0001
+#define PRINTF_FORTIFY     0x0002
 
 extern size_t _IO_getline (FILE *,char *, size_t, int, int);
 libc_hidden_proto (_IO_getline)
diff --git a/libio/obprintf.c b/libio/obprintf.c
index a74f946..6bb51a4 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 10f722d..19b3f33 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 6c35d2b..e03cdf4 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 39b5500..8a5d0ba 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,18 @@ _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_hidden_def (___vsnprintf, __vsnprintf)
+ldbl_weak_alias (___vsnprintf, vsnprintf)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index bcc473d..71d4e6c 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 72ebfec..e8a529a 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 5945f65..361cd40 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 f3b3ced..84bad1f 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 bff858e..5f5ca6c 100644
--- a/stdio-common/asprintf.c
+++ b/stdio-common/asprintf.c
@@ -16,11 +16,8 @@
    <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 +29,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 11bd12b..9adc8ae 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 2bbf14b..c8f8ac4 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 c4a1146..d74364c 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 205b5e4..ea41dd5 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 29a169b..b75e160 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 bf5671d..77423b2 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 ae412e4..d8716f4 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.  */
@@ -63,6 +67,8 @@
 	}								      \
     } while (0)
 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
+#define LDBL_IS_DBL (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
+#define DO_FORTIFY  ((mode_flags & PRINTF_FORTIFY) != 0)
 
 #define done_add(val) \
   do {									      \
@@ -78,7 +84,7 @@
   } while (0)
 
 #ifndef COMPILE_WPRINTF
-# define vfprintf	_IO_vfprintf_internal
+# define vfprintf	__vfprintf_internal
 # define CHAR_T		char
 # define UCHAR_T	unsigned char
 # define INT_T		int
@@ -105,7 +111,7 @@ 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 +753,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -778,7 +784,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      {								      \
 		fspec->data_arg_type = PA_DOUBLE;			      \
 		fspec->info.is_long_double = 0;				      \
@@ -808,7 +814,7 @@ static const uint8_t jump_table[] =
 									      \
 	if (fspec == NULL)						      \
 	  {								      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)						      \
 	      is_long_double = 0;					      \
 									      \
 	    struct printf_info info = { .prec = prec,			      \
@@ -838,7 +844,7 @@ static const uint8_t jump_table[] =
 	else								      \
 	  {								      \
 	    ptr = (const void *) &args_value[fspec->data_arg];		      \
-	    if (__ldbl_is_dbl)						      \
+	    if (LDBL_IS_DBL)                                            \
 	      fspec->info.is_long_double = 0;				      \
 	    /* Not supported by *printf functions.  */			      \
 	    fspec->info.is_binary128 = 0;				      \
@@ -891,7 +897,7 @@ static const uint8_t jump_table[] =
       /* NOTREACHED */							      \
 									      \
     LABEL (form_number):						      \
-      if (s->_flags2 & _IO_FLAGS2_FORTIFY)				      \
+      if (DO_FORTIFY)							      \
 	{								      \
 	  if (! readonly_format)					      \
 	    {								      \
@@ -1214,7 +1220,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 +1230,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 +1244,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 +1282,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 +1308,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 +1697,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 +1714,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 +1805,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, DO_FORTIFY ? '\xff' : '\0',
 	    nargs * sizeof (*args_type));
   }
 
@@ -1856,7 +1872,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 (LDBL_IS_DBL)
 	  {
 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
@@ -1884,7 +1900,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 (DO_FORTIFY);
 	__libc_fatal ("*** invalid %N$ use detected ***\n");
       }
 
@@ -2285,7 +2301,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 +2335,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 +2364,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 ae412e4..13a10db 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 0000000..cefaf2f
--- /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 2c3cd06..5d65eb7 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 d459642..0da8ba7 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 2840512..c178780 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 from libio.  */
 
   if (size == 0)
     {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 06c5c40..02b0241 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;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b39df80bc0daeaed2e5499a018ceea63f53a3f00

commit b39df80bc0daeaed2e5499a018ceea63f53a3f00
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:32:00 2018 -0500

    Use SCANF_LDBL_IS_DBL instead of __ldbl_is_dbl.
    
    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.
    
    	* 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.

diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 32aee6e..0eb6b5e 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -333,9 +333,6 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
 
 #define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
 #define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
-  /* Temporarily honor the environmental mode bits.  */
-  if (__ldbl_is_dbl)
-    mode_flags |= SCANF_LDBL_IS_DBL;
 
 #ifdef __va_copy
   __va_copy (arg, argptr);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index a53b1ce..06c5c40 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,42 @@ 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 rv;
 
-  va_start (arg, fmt);
-  done = __nldbl___isoc99_vfscanf (stdin, fmt, arg);
-  va_end (arg);
+  va_start (ap, fmt);
+  rv = __vfscanf_internal (stdin, fmt, ap, SCANF_LDBL_IS_DBL | SCANF_ISOC99_A);
+  va_end (ap);
 
-  return done;
+  return rv;
 }
 
 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 +936,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)
 
@@ -983,30 +970,30 @@ __nldbl___isoc99_vwscanf (const wchar_t *fmt, va_list ap)
 
 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)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8686cf8597d43af6cee2cc405e643502e3f34a55

commit 8686cf8597d43af6cee2cc405e643502e3f34a55
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:31:59 2018 -0500

    Use SCANF_ISOC99_A instead of _IO_FLAGS2_SCANF_STD.
    
    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.
    
    	* 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.

diff --git a/libio/libio.h b/libio/libio.h
index d4eba2d..30cb7d7 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 e2e9387..135c8f9 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -773,7 +773,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);
 }
@@ -787,8 +787,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 4210d11..e788ac4 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -27,13 +27,9 @@ __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 64c873e..98b0a19 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -19,26 +19,17 @@
 #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 95b94a6..c53130e 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -27,10 +27,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 c96ca83..0bc2ad9 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -23,12 +23,6 @@
 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 72ae72d..1a270b0 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -23,11 +23,5 @@
 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 02bc0f5..dfc394b 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 a7fd09c..32aee6e 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -336,8 +336,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 00b07dd..b01826e 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -28,13 +28,9 @@ __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 40401d0..f90e56d 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 f70c6b5..f9d0a38 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -24,12 +24,6 @@
 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 b91eb65..0d8ef76 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 eb22c8a..5e4f44d 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -24,11 +24,5 @@
 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 59f80d7..a0f24e1 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -29,13 +29,9 @@ __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;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=86fbc498baec34d02ef7ac316c9eae924c97ca34

commit 86fbc498baec34d02ef7ac316c9eae924c97ca34
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:31:58 2018 -0500

    Add __vfscanf_internal and __vfwscanf_internal with flags arguments.
    
    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.
    
    	* 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_WPRINTF; don't define any other public symbols.
    	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, stdio-common/vfwscanf.c: New files
    	defining the public entry points vfscanf and vfwscanf respectively.
    	* stdio-common/iovfscanf.c, stdio-common/iovfwscanf.c: New files
    	defining the compat symbols _IO_vfscanf and _IO_vfwscanf respectively.
    	* stdio-common/Makefile (routines): Add vfscanf-internal,
    	vfwscanf-internal, iovfscanf, iovfwscanf.
            * stdio-common/Versions: Mention GLIBC_2.28, 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.
    
    	* libio/iovsscanf.c, libio/vscanf.c, libio/vwscanf.c, libio/wscanf.c
    	* libio/iovswscanf.c, stdio-common/isoc99_fscanf.c
    	* stdio-common/isoc99_scanf.c, stdio-common/isoc99_vfscanf.c
    	* stdio-common/isoc99_vscanf.c, stdio-common/isoc99_vsscanf.c
    	* stdio-common/scanf.c, sysdeps/ieee754/ldbl-opt/nldbl-compat.c
    	* wcsmbs/isoc99_fwscanf.c, wcsmbs/isoc99_vfwscanf.c
    	* wcsmbs/isoc99_vswscanf.c, wcsmbs/isoc99_vwscanf.c
    	* wcsmbs/isoc99_wscanf.c: Use __vfscanf_internal instead of
    	_IO_vfscanf, and/or __vfwscanf_internal instead of _IO_vfwscanf.
    
    	* libio/iovsscanf.c, stdio-common/isoc99_vsscanf.c:
    	Use _IO_strfile_read.  Clean up includes.
    	* stdio-common/sscanf.c, stdio-common/isoc99_sscanf.c:
    	Use _IO_strfile_read to set up a FILE, and then call
    	__vfwcanf_internal directly.  Clean up includes.
    
    	* libio/iovswscanf.c, wcsmbs/isoc99_vswscanf.c:
    	Use _IO_strfile_readw.  Clean up includes.
    	* libio/swscanf.c, wcsmbs/isoc99_swscanf.c:
    	Use _IO_strfile_readw to set up a FILE, and then call
    	__vfwscanf_internal directly.  Clean up includes.

diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index e56ab8b..ee6a99e 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 5bd1c88..cb9cbe1 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 00f9169..d4eba2d 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 df2633d..e2e9387 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,15 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 
 #endif /* _G_HAVE_MMAP */
 
+/* Flags for __vfscanf_internal and __vfwscanf_internal.  */
+#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);
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+                                unsigned int flags);
+
 extern int _IO_vscanf (const char *, va_list) __THROW;
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 75caac2..62900a7 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 c8686bc..90f721c 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 9c27122..a3e2dd4 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 0d5f558..7af770c 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 c8cdad0..fe27ff6 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 a10f12a..f3b3ced 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/scanf.c b/stdio-common/iovfscanf.c
similarity index 69%
copy from stdio-common/scanf.c
copy to stdio-common/iovfscanf.c
index e61b5f1..fb347d6 100644
--- a/stdio-common/scanf.c
+++ b/stdio-common/iovfscanf.c
@@ -15,24 +15,20 @@
    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>
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 
-/* Read formatted input from stdin according to the format string FORMAT.  */
-/* VARARGS1 */
 int
-__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;
-
-  va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
-  va_end (arg);
-
-  return done;
+  int rv = __vfscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
 }
-ldbl_strong_alias (__scanf, scanf)
+ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+
+#endif
diff --git a/libio/swscanf.c b/stdio-common/iovfwscanf.c
similarity index 69%
copy from libio/swscanf.c
copy to stdio-common/iovfwscanf.c
index c8686bc..73936f6 100644
--- a/libio/swscanf.c
+++ b/stdio-common/iovfwscanf.c
@@ -16,21 +16,19 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <libioP.h>
-#include <stdarg.h>
-#include <wchar.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 
-/* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
 int
-__swscanf (const wchar_t *s, const wchar_t *format, ...)
+attribute_compat_text_section
+__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
 {
-  va_list arg;
-  int done;
-
-  va_start (arg, format);
-  done = __vswscanf (s, format, arg);
-  va_end (arg);
-
-  return done;
+  int rv = __vfwscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
 }
-ldbl_strong_alias (__swscanf, swscanf)
+compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
+
+#endif
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 9cdf85e..4210d11 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 bf7dbe8..64c873e 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 56a60a2..95b94a6 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,8 +16,7 @@
    <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 */
@@ -26,9 +25,12 @@ __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 b80e05f..c96ca83 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 0b747f8..72ae72d 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 ac85ef2..02bc0f5 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 e61b5f1..de38d70 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 88cd641..e25e9c2 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 1ce836a..a7fd09c 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -132,16 +132,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 +264,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 +280,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 +331,14 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   struct char_buffer charbuf;
   scratch_buffer_init (&charbuf.scratch);
 
+#define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
+#define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
+  /* 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 +570,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 (USE_ISOC99_A)
 	    {
 	      --f;
 	      break;
@@ -2423,7 +2427,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      done = EOF;
 	      goto errout;
 	    }
-	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
+	  if ((flags & LONGDBL) && LDBL_DISTINCT)
 	    {
 	      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 1ce836a..5eedca8 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 0000000..26c8927
--- /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 26b1a66..0554b7e 100644
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf.c
@@ -1,2 +1,25 @@
-#define COMPILE_WSCANF	1
-#include "vfscanf.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 <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 8a5d8ba..92f670d 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 61ba784..70471e9 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -20,10 +20,14 @@
   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)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 # 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 07ad993..a53b1ce 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_28)
 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,9 @@ 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);
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+#endif
 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);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 0c6a2c4..00b07dd 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 ff523db..40401d0 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 7beb45b..f70c6b5 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 1307691..b91eb65 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 049521b..eb22c8a 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 abfbd50..59f80d7 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);

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a67acd3b44e272d13bc0a3afe62a4c2b48fc5f4a

commit a67acd3b44e272d13bc0a3afe62a4c2b48fc5f4a
Author: Zack Weinberg <zackw@panix.com>
Date:   Wed Mar 7 14:31:57 2018 -0500

    Use STRFMON_LDBL_IS_DBL instead of __ldbl_is_dbl.
    
    This patch takes the first step toward removing the global flag
    __ldbl_is_dbl, creating a __vstrfmon_l_internal that takes a flags
    parameter instead.
    
    This change arguably makes the generated code slightly worse on
    architectures where __ldbl_is_dbl is never true; right now, on those
    architectures, it's a compile-time constant; after this change, the
    compiler could theoretically prove that __vstrfmon_l_internal was
    never called with a nonzero flags argument, but it would probably need
    LTO to do it.  This is not performance critical code and I tend to
    think that the maintainability benefits of removing action at a
    distance are worth it.  However, we _could_ wrap the runtime flag
    check with a macro that was defined to ignore its argument and always
    return false on architectures where __ldbl_is_dbl is never true, if
    people think the codegen benefits are important.
    
    	* include/monetary.h (STRFMON_LDBL_IS_DBL): New constant.
    	(__vstrfmon_l): Rename to __vstrfmon_l_internal and add flags
    	argument.
    	* stdlib/strfmon_l.c (__vstrfmon_l): Rename to __vstrfmon_l_internal
    	and add flags argument.	 Check flags instead of __ldbl_is_dbl when
    	deciding whether to set is_long_double.
    	(__strfmon_l): Call __vstrfmon_l_internal instead of __vstrfmon_l,
    	passing zero for flags argument.
    	* stdlib/strfmon.c (strfmon): Same change as made to __strfmon_l.
    
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
    	(__nldbl___vstrfmon, __nldbl___vstrfmon_l)
    	(__nldbl_strfmon, __nldbl___strfmon_l): Call __vstrfmon_l_internal
    	directly, passing STRFMON_LDBL_IS_DBL for flags argument.  Normalize
    	variable names.  Remove libc_hidden_def/libc_hidden_proto.
    	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h: Don't use NLDBL_DECL
    	for __nldbl___vstrfmon_l.
    
    	* manual/locale.texi: Update a reference to vstrfmon_l in comments.

diff --git a/include/monetary.h b/include/monetary.h
index c130ed5..d12ae03 100644
--- a/include/monetary.h
+++ b/include/monetary.h
@@ -2,7 +2,11 @@
 #ifndef _ISOMAC
 #include <stdarg.h>
 
-extern ssize_t __vstrfmon_l (char *s, size_t maxsize, locale_t loc,
-			     const char *format, va_list ap)
-     attribute_hidden;
+extern ssize_t __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
+                                      const char *format, va_list ap,
+                                      unsigned int flags);
+
+/* Flags for __vstrfmon_l_internal.  */
+#define STRFMON_LDBL_IS_DBL 0x0001
+
 #endif
diff --git a/manual/locale.texi b/manual/locale.texi
index dabb959..720e0ca 100644
--- a/manual/locale.texi
+++ b/manual/locale.texi
@@ -1209,10 +1209,11 @@ numbers according to these rules.
 
 @deftypefun ssize_t strfmon (char *@var{s}, size_t @var{maxsize}, const char *@var{format}, @dots{})
 @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
-@c It (and strfmon_l) both call vstrfmon_l, which, besides accessing the
-@c locale object passed to it, accesses the active locale through
-@c isdigit (but to_digit assumes ASCII digits only).  It may call
-@c __printf_fp (@mtslocale @ascuheap @acsmem) and guess_grouping (safe).
+@c It (and strfmon_l) both call __vstrfmon_l_internal, which, besides
+@c accessing the locale object passed to it, accesses the active
+@c locale through isdigit (but to_digit assumes ASCII digits only).
+@c It may call __printf_fp (@mtslocale @ascuheap @acsmem) and
+@c guess_grouping (safe).
 The @code{strfmon} function is similar to the @code{strftime} function
 in that it takes a buffer, its size, a format string,
 and values to write into the buffer as text in a form specified
diff --git a/stdlib/strfmon.c b/stdlib/strfmon.c
index 01980d3..2b742c7 100644
--- a/stdlib/strfmon.c
+++ b/stdlib/strfmon.c
@@ -30,7 +30,8 @@ __strfmon (char *s, size_t maxsize, const char *format, ...)
 
   va_start (ap, format);
 
-  ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
+  ssize_t res = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE,
+                                       format, ap, 0);
 
   va_end (ap);
 
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index cd3796c..f0ebd99 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -76,8 +76,8 @@
    too.  Some of the information contradicts the information which can
    be specified in format string.  */
 ssize_t
-__vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
-	      va_list ap)
+__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
+                       const char *format, va_list ap, unsigned int flags)
 {
   struct __locale_data *current = loc->__locales[LC_MONETARY];
   _IO_strfile f;
@@ -268,7 +268,7 @@ __vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
       if (*fmt == 'L')
 	{
 	  ++fmt;
-	  if (!__ldbl_is_dbl)
+	  if (__glibc_likely ((flags & STRFMON_LDBL_IS_DBL) == 0))
 	    is_long_double = 1;
 	}
 
@@ -608,7 +608,7 @@ ___strfmon_l (char *s, size_t maxsize, locale_t loc, const char *format, ...)
 
   va_start (ap, format);
 
-  ssize_t res = __vstrfmon_l (s, maxsize, loc, format, ap);
+  ssize_t res = __vstrfmon_l_internal (s, maxsize, loc, format, ap, 0);
 
   va_end (ap);
 
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index ffb5fab..07ad993 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -51,8 +51,6 @@ libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___vasprintf_chk)
 libc_hidden_proto (__nldbl___vdprintf_chk)
 libc_hidden_proto (__nldbl___obstack_vprintf_chk)
-libc_hidden_proto (__nldbl___vstrfmon)
-libc_hidden_proto (__nldbl___vstrfmon_l)
 libc_hidden_proto (__nldbl___isoc99_vsscanf)
 libc_hidden_proto (__nldbl___isoc99_vfscanf)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
@@ -780,12 +778,13 @@ attribute_compat_text_section
 __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
 {
   va_list ap;
-  ssize_t res;
+  ssize_t ret;
 
   va_start (ap, format);
-  res = __nldbl___vstrfmon (s, maxsize, format, ap);
+  ret = __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
+                               STRFMON_LDBL_IS_DBL);
   va_end (ap);
-  return res;
+  return ret;
 }
 
 ssize_t
@@ -794,12 +793,13 @@ __nldbl___strfmon_l (char *s, size_t maxsize, locale_t loc,
 		     const char *format, ...)
 {
   va_list ap;
-  ssize_t res;
+  ssize_t ret;
 
   va_start (ap, format);
-  res = __nldbl___vstrfmon_l (s, maxsize, loc, format, ap);
+  ret = __vstrfmon_l_internal (s, maxsize, loc, format, ap,
+                               STRFMON_LDBL_IS_DBL);
   va_end (ap);
-  return res;
+  return ret;
 }
 weak_alias (__nldbl___strfmon_l, __nldbl_strfmon_l)
 
@@ -807,28 +807,18 @@ ssize_t
 attribute_compat_text_section
 __nldbl___vstrfmon (char *s, size_t maxsize, const char *format, va_list ap)
 {
-  ssize_t res;
-  __no_long_double = 1;
-  res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
-  __no_long_double = 0;
-  va_end (ap);
-  return res;
+  return __vstrfmon_l_internal (s, maxsize, _NL_CURRENT_LOCALE, format, ap,
+				STRFMON_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl___vstrfmon)
 
 ssize_t
 attribute_compat_text_section
 __nldbl___vstrfmon_l (char *s, size_t maxsize, locale_t loc,
 		      const char *format, va_list ap)
 {
-  ssize_t res;
-  __no_long_double = 1;
-  res = __vstrfmon_l (s, maxsize, loc, format, ap);
-  __no_long_double = 0;
-  va_end (ap);
-  return res;
+  return __vstrfmon_l_internal (s, maxsize, loc, format, ap,
+				STRFMON_LDBL_IS_DBL);
 }
-libc_hidden_def (__nldbl___vstrfmon_l)
 
 void
 attribute_compat_text_section
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index 888f561..4b7f909 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -60,7 +60,6 @@ NLDBL_DECL (vsyslog);
 NLDBL_DECL (qecvt);
 NLDBL_DECL (qfcvt);
 NLDBL_DECL (qgcvt);
-NLDBL_DECL (__vstrfmon_l);
 NLDBL_DECL (__isoc99_scanf);
 NLDBL_DECL (__isoc99_fscanf);
 NLDBL_DECL (__isoc99_sscanf);
@@ -74,10 +73,13 @@ NLDBL_DECL (__isoc99_vwscanf);
 NLDBL_DECL (__isoc99_vfwscanf);
 NLDBL_DECL (__isoc99_vswscanf);
 
-/* This one does not exist in the normal interface, only
-   __nldbl___vstrfmon really exists.  */
+/* These do not exist in the normal interface, but must exist in the
+   __nldbl interface so that they can be called from libnldbl.  */
 extern ssize_t __nldbl___vstrfmon (char *, size_t, const char *, va_list)
   __THROW;
+extern ssize_t __nldbl___vstrfmon_l (char *, size_t, locale_t, const char *,
+				     va_list)
+  __THROW;
 
 /* These don't use __typeof because they were not declared by the headers,
    since we don't compile with _FORTIFY_SOURCE.  */

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=beae179da55d1b982a79f076e20a8a4275ea512f

commit beae179da55d1b982a79f076e20a8a4275ea512f
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Aug 7 10:39:47 2018 -0300

    Add tests with floating-point arguments for err* and verr* functions
    
    Similarly to what has been done for argp_error, and argp_failure, as
    well as for warn, warnx, vwarn, and vwarnx, this patch adds new tests
    for the following functions: err, errx, verr, verrx, error, and
    error_at_line.  The new tests check that the conversion of long double
    variables into string works correctly on the default format of the type.
    Future patches will reuse these tests for other formats that long double
    can take.  Since the functions do not return, each of them has its own
    test case file.
    
    Tested for powerpc64le.
    
    	* misc/Makefile (tests-internal): Add tst-ldbl-error-err
    	tst-ldbl-error-errx, tst-ldbl-error-verr, tst-ldbl-error-verrx,
    	tst-ldbl-error-error, and tst-ldbl-error-error_at_line.
    	[run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-ldbl-warn.out, $(objpfx)tst-ldbl-error-err.out,
    	$(objpfx)tst-ldbl-error-errx.out,
    	$(objpfx)tst-ldbl-error-verr.out,
    	$(objpfx)tst-ldbl-error-verrx.out,
    	$(objpfx)tst-ldbl-error-error.out, and
    	$(objpfx)tst-ldbl-error-error_at_line.out.
    	($(objpfx)tst-ldbl-error-%.out): New build and run rule.
    	* misc/tst-ldbl-error-err.c: New file.
    	* misc/tst-ldbl-error-error.c: Likewise.
    	* misc/tst-ldbl-error-error_at_line.c: Likewise.
    	* misc/tst-ldbl-error-errx.c: Likewise.
    	* misc/tst-ldbl-error-template.c: Likewise.
    	* misc/tst-ldbl-error-verr.c: Likewise.
    	* misc/tst-ldbl-error-verrx.c: Likewise.
    	* misc/tst-ldbl-error.sh: Likewise.

diff --git a/misc/Makefile b/misc/Makefile
index eb77b87..ca0c6b3 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -90,12 +90,24 @@ tests-internal := tst-atomic tst-atomic-long tst-allocate_once
 tests-static := tst-empty
 
 tests-internal += tst-ldbl-warn
+tests-internal += tst-ldbl-error-err
+tests-internal += tst-ldbl-error-errx
+tests-internal += tst-ldbl-error-verr
+tests-internal += tst-ldbl-error-verrx
+tests-internal += tst-ldbl-error-error
+tests-internal += tst-ldbl-error-error_at_line
 
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-error1-mem.out \
   $(objpfx)tst-allocate_once-mem.out
 
 tests-special += $(objpfx)tst-ldbl-warn.out
+tests-special += $(objpfx)tst-ldbl-error-err.out
+tests-special += $(objpfx)tst-ldbl-error-errx.out
+tests-special += $(objpfx)tst-ldbl-error-verr.out
+tests-special += $(objpfx)tst-ldbl-error-verrx.out
+tests-special += $(objpfx)tst-ldbl-error-error.out
+tests-special += $(objpfx)tst-ldbl-error-error_at_line.out
 endif
 
 $(objpfx)tst-ldbl-warn.out: \
@@ -103,6 +115,11 @@ $(objpfx)tst-ldbl-warn.out: \
 	$(SHELL) $^ '$(test-program-prefix)' $@; \
 	$(evaluate-test)
 
+$(objpfx)tst-ldbl-error-%.out: \
+  tst-ldbl-error.sh $(objpfx)tst-ldbl-error-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-tsearch.c += $(uses-callbacks)
 CFLAGS-lsearch.c += $(uses-callbacks)
diff --git a/misc/tst-ldbl-error-err.c b/misc/tst-ldbl-error-err.c
new file mode 100644
index 0000000..9a57b13
--- /dev/null
+++ b/misc/tst-ldbl-error-err.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		err
+#define ERROR_FUNCTION_PARAMS	(0, format, ld)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error-error.c b/misc/tst-ldbl-error-error.c
new file mode 100644
index 0000000..be06513
--- /dev/null
+++ b/misc/tst-ldbl-error-error.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		error
+#define ERROR_FUNCTION_PARAMS	(0, 0, format, ld)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error-error_at_line.c b/misc/tst-ldbl-error-error_at_line.c
new file mode 100644
index 0000000..ca4cea1
--- /dev/null
+++ b/misc/tst-ldbl-error-error_at_line.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		error_at_line
+#define ERROR_FUNCTION_PARAMS	(0, 0, "", 1234, format, ld)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error-errx.c b/misc/tst-ldbl-error-errx.c
new file mode 100644
index 0000000..bf3e6ac
--- /dev/null
+++ b/misc/tst-ldbl-error-errx.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		errx
+#define ERROR_FUNCTION_PARAMS	(0, format, ld)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error-template.c b/misc/tst-ldbl-error-template.c
new file mode 100644
index 0000000..24fd580
--- /dev/null
+++ b/misc/tst-ldbl-error-template.c
@@ -0,0 +1,45 @@
+/* Test for the long double conversions in *err* functions.
+   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 <err.h>
+#include <error.h>
+#include <stdarg.h>
+
+#include <support/check.h>
+
+static void
+do_test_call (long double ld, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  ERROR_FUNCTION ERROR_FUNCTION_PARAMS;
+  va_end (args);
+}
+
+static int
+do_test (void)
+{
+  long double ld = -1;
+
+  do_test_call (ld, "%.60Lf", ld);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-ldbl-error-verr.c b/misc/tst-ldbl-error-verr.c
new file mode 100644
index 0000000..9ac51f1
--- /dev/null
+++ b/misc/tst-ldbl-error-verr.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		verr
+#define ERROR_FUNCTION_PARAMS	(0, format, args)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error-verrx.c b/misc/tst-ldbl-error-verrx.c
new file mode 100644
index 0000000..995f4a2
--- /dev/null
+++ b/misc/tst-ldbl-error-verrx.c
@@ -0,0 +1,3 @@
+#define ERROR_FUNCTION		verrx
+#define ERROR_FUNCTION_PARAMS	(0, format, args)
+#include <tst-ldbl-error-template.c>
diff --git a/misc/tst-ldbl-error.sh b/misc/tst-ldbl-error.sh
new file mode 100644
index 0000000..cec3f53
--- /dev/null
+++ b/misc/tst-ldbl-error.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Test for the long double conversions in *err* functions.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  2> ${test_program_output} || status=1
+
+# This script is shared among different test cases that have different
+# names and print different messages, however, the goal of the tests is
+# to detect if floating-point conversions worked, not if the messages
+# and filenames are correct, thus:
+#
+# Remove the trailing messages, if any.
+sed -i ${test_program_output} -e "s/: Success//"
+#
+# Remove the program name.
+sed -i ${test_program_output} -e "s/.*tst-[^:]*: //"
+#
+# Remove the line number annotation (error_at_line).
+sed -i ${test_program_output} -e "s/.*1234: //"
+
+cat <<'EOF' |
+-1.000000000000000000000000000000000000000000000000000000000000
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3d79acd1030e9e7a135a25e77b4713a8f6df19bd

commit 3d79acd1030e9e7a135a25e77b4713a8f6df19bd
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Mon Aug 6 12:06:03 2018 -0300

    Add test for warn, warnx, vwarn, and vwarnx with floating-point parameters
    
    Similarly to what has been done for argp_error and argp_failure, this
    patch patch adds new tests for the warn, warnx, vwarn, and vwarnx
    functions.  The new tests use the format string to request the
    conversion of long double parameters into string.  Currently, these
    tests only check that the default format of the long double type works.
    Future patches will extend the test for platforms that can have an
    optional format for long double.
    
    Tested for powerpc64le.
    
    	* misc/Makefile (tests-internal): Add tst-ldbl-warn.
    	[run-built-tests == yes] (test-special): Add
    	$(objpfx)tst-ldbl-warn.out.
    	($(objpfx)tst-ldbl-warn.out): New build and run rule.
    	* misc/tst-ldbl-warn.c: New file.
    	* misc/tst-ldbl-warn.sh: Likewise.

diff --git a/misc/Makefile b/misc/Makefile
index b7be2bc..eb77b87 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -89,11 +89,20 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
 tests-internal := tst-atomic tst-atomic-long tst-allocate_once
 tests-static := tst-empty
 
+tests-internal += tst-ldbl-warn
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-error1-mem.out \
   $(objpfx)tst-allocate_once-mem.out
+
+tests-special += $(objpfx)tst-ldbl-warn.out
 endif
 
+$(objpfx)tst-ldbl-warn.out: \
+  tst-ldbl-warn.sh $(objpfx)tst-ldbl-warn
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-tsearch.c += $(uses-callbacks)
 CFLAGS-lsearch.c += $(uses-callbacks)
diff --git a/misc/tst-ldbl-warn.c b/misc/tst-ldbl-warn.c
new file mode 100644
index 0000000..db771b5
--- /dev/null
+++ b/misc/tst-ldbl-warn.c
@@ -0,0 +1,61 @@
+/* Test for the long double conversions in *warn* functions.
+   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 <err.h>
+#include <stdarg.h>
+
+#include <support/check.h>
+
+static void
+do_test_call_varg (const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  vwarn (format, args);
+  va_end (args);
+
+  va_start (args, format);
+  vwarnx (format, args);
+  va_end (args);
+}
+
+static void
+do_test_call_rarg (const char *format, long double ld1, double d1,
+		   long double ld2, double d2)
+{
+  warn (format, ld1, d1, ld2, d2);
+  warnx (format, ld1, d1, ld2, d2);
+}
+
+static int
+do_test (void)
+{
+  double d1 = -2;
+  double d2 = -4;
+  long double ld1 = -1;
+  long double ld2 = -3;
+
+  /* Print in decimal notation.  */
+  do_test_call_rarg ("%Lf - %f - %Lf - %f", ld1, d1, ld2, d2);
+  do_test_call_varg ("%Lf - %f - %Lf - %f", ld1, d1, ld2, d2);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-ldbl-warn.sh b/misc/tst-ldbl-warn.sh
new file mode 100644
index 0000000..5827be9
--- /dev/null
+++ b/misc/tst-ldbl-warn.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Test for the long double conversions in *warn* functions.
+# 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/>.
+
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+${test_program_prefix} \
+  ${test_program} \
+  2> ${test_program_output} || status=1
+
+# Remove the program name from the output, because checking the program
+# name is out of the scope of this test case.
+sed -i "s/.*tst-[^:]*: //" ${test_program_output}
+
+cat <<'EOF' |
+-1.000000 - -2.000000 - -3.000000 - -4.000000: Success
+-1.000000 - -2.000000 - -3.000000 - -4.000000
+-1.000000 - -2.000000 - -3.000000 - -4.000000: Success
+-1.000000 - -2.000000 - -3.000000 - -4.000000
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1ee4d535974f6a988d0db710e739e5625a271254

commit 1ee4d535974f6a988d0db710e739e5625a271254
Author: Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
Date:   Tue Jun 12 22:27:21 2018 -0300

    Add tests for argp_error and argp_failure with floating-point parameters
    
    The functions argp_error and argp_failure, from argp.h, have a format
    string as parameter, which can possibly request the printing of
    floating-point values.  These values could be of long double type, which
    can have different formats, depending on the architecture and on
    compilation parameters (for instance, on powerpc, long double values can
    have double format (-mlong-double-64) or IBM Extended Precision format
    (-mlong-double-128).
    
    This patch adds tests for argp_error and argp_failure that contain a
    format string with double and long double conversion specifiers ('%f'
    and '%Lf').  These tests automatically check that the default format of
    the long double type works.  A future patch will extend the test for
    platforms that can have an optional format for long double.
    
    Tested for powerpc64le.
    
    	* argp/Makefile: (tests-internal): Add tst-ldbl-argp-error and
    	tst-ldbl-argp-failure.
    	[run-built-tests == yes] (tests-special): Add
    	$(objpfx)tst-ldbl-argp-error.out and
    	$(objpfx)tst-ldbl-argp-failure.out.
    	($(objpfx)tst-ldbl-argp-error.out)
    	($(objpfx)tst-ldbl-argp-failure.out): New build and run rule.
    	* argp/tst-ldbl-argp-error.c: New file.
    	* argp/tst-ldbl-argp-error.sh: Likewise.
    	* argp/tst-ldbl-argp-failure.c: Likewise.
    	* argp/tst-ldbl-argp-failure.sh: Likewise.
    	* argp/tst-ldbl-argp-template.c: Likewise.

diff --git a/argp/Makefile b/argp/Makefile
index 6e4799c..8ca95c7 100644
--- a/argp/Makefile
+++ b/argp/Makefile
@@ -35,4 +35,16 @@ CFLAGS-argp-fmtstream.c += -fexceptions
 bug-argp1-ARGS = -- --help
 bug-argp2-ARGS = -- -d 111 --dstaddr 222 -p 333 --peer 444
 
+tests-internal += tst-ldbl-argp-error tst-ldbl-argp-failure
+
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-ldbl-argp-error.out
+tests-special += $(objpfx)tst-ldbl-argp-failure.out
+endif
+
+$(objpfx)tst-ldbl-argp-%.out: \
+  tst-ldbl-argp-%.sh $(objpfx)tst-ldbl-argp-%
+	$(SHELL) $^ '$(test-program-prefix)' $@; \
+	$(evaluate-test)
+
 include ../Rules
diff --git a/argp/tst-ldbl-argp-error.c b/argp/tst-ldbl-argp-error.c
new file mode 100644
index 0000000..8b24bd9
--- /dev/null
+++ b/argp/tst-ldbl-argp-error.c
@@ -0,0 +1,3 @@
+#define ARGP_FUNCTION		argp_error
+#define ARGP_FUNCTION_PARAMS	(state, "%Lf%f%Lf%f", (long double) -1, (double) -2, (long double) -3, (double) -4)
+#include <tst-ldbl-argp-template.c>
diff --git a/argp/Makefile b/argp/tst-ldbl-argp-error.sh
similarity index 51%
copy from argp/Makefile
copy to argp/tst-ldbl-argp-error.sh
index 6e4799c..49a3c62 100644
--- a/argp/Makefile
+++ b/argp/tst-ldbl-argp-error.sh
@@ -1,4 +1,6 @@
-# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+#!/bin/sh
+# Testing of long double conversions in argp_error.
+# 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,24 +17,30 @@
 # License along with the GNU C Library; if not, see
 # <http://www.gnu.org/licenses/>.
 
-#
-#	Makefile for argp.
-#
-subdir	:= argp
-
-include ../Makeconfig
-
-headers		= argp.h
-routines	= $(addprefix argp-, ba fmtstream fs-xinl help parse pv \
-				     pvh xinl eexst)
-
-tests		= argp-test tst-argp1 bug-argp1 tst-argp2 bug-argp2
-
-CFLAGS-argp-help.c += $(uses-callbacks) -fexceptions
-CFLAGS-argp-parse.c += $(uses-callbacks)
-CFLAGS-argp-fmtstream.c += -fexceptions
-
-bug-argp1-ARGS = -- --help
-bug-argp2-ARGS = -- -d 111 --dstaddr 222 -p 333 --peer 444
-
-include ../Rules
+set -e
+
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
+
+status=0
+
+# Allow argp_error to end with non-zero exit status, run the test
+# program, then restore the exit-on-error behavior
+set +e
+${test_program_prefix} \
+  ${test_program} \
+  2> ${test_program_output}
+set -e
+
+cat <<'EOF' |
+test-argp: -1.000000-2.000000-3.000000-4.000000
+Try `test-argp --help' or `test-argp --usage' for more information.
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
+
+exit $status
diff --git a/argp/tst-ldbl-argp-failure.c b/argp/tst-ldbl-argp-failure.c
new file mode 100644
index 0000000..92a82ce
--- /dev/null
+++ b/argp/tst-ldbl-argp-failure.c
@@ -0,0 +1,3 @@
+#define ARGP_FUNCTION		argp_failure
+#define ARGP_FUNCTION_PARAMS	(state, 0, 0, "%Lf%f%Lf%f", (long double) -1, (double) -2, (long double) -3, (double) -4)
+#include <tst-ldbl-argp-template.c>
diff --git a/argp/Makefile b/argp/tst-ldbl-argp-failure.sh
similarity index 54%
copy from argp/Makefile
copy to argp/tst-ldbl-argp-failure.sh
index 6e4799c..f3f2517 100644
--- a/argp/Makefile
+++ b/argp/tst-ldbl-argp-failure.sh
@@ -1,4 +1,6 @@
-# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+#!/bin/sh
+# Testing of long double conversions in argp_failure.
+# 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,24 +17,29 @@
 # License along with the GNU C Library; if not, see
 # <http://www.gnu.org/licenses/>.
 
-#
-#	Makefile for argp.
-#
-subdir	:= argp
+set -e
 
-include ../Makeconfig
+test_program=$1; shift
+test_program_prefix=$1; shift
+test_program_output=$1; shift
 
-headers		= argp.h
-routines	= $(addprefix argp-, ba fmtstream fs-xinl help parse pv \
-				     pvh xinl eexst)
+status=0
 
-tests		= argp-test tst-argp1 bug-argp1 tst-argp2 bug-argp2
+# Allow argp_failure to end with non-zero exit status, run the test
+# program, then restore the exit-on-error behavior
+set +e
+${test_program_prefix} \
+  ${test_program} \
+  2> ${test_program_output}
+set -e
 
-CFLAGS-argp-help.c += $(uses-callbacks) -fexceptions
-CFLAGS-argp-parse.c += $(uses-callbacks)
-CFLAGS-argp-fmtstream.c += -fexceptions
+cat <<'EOF' |
+test-argp: -1.000000-2.000000-3.000000-4.000000
+EOF
+cmp - ${test_program_output} > /dev/null 2>&1 ||
+{
+  status=1
+  echo "*** output comparison failed"
+}
 
-bug-argp1-ARGS = -- --help
-bug-argp2-ARGS = -- -d 111 --dstaddr 222 -p 333 --peer 444
-
-include ../Rules
+exit $status
diff --git a/argp/tst-ldbl-argp-template.c b/argp/tst-ldbl-argp-template.c
new file mode 100644
index 0000000..f52cd35
--- /dev/null
+++ b/argp/tst-ldbl-argp-template.c
@@ -0,0 +1,69 @@
+/* Testing of long double conversions in argp.h functions.
+   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 <argp.h>
+#include <string.h>
+
+#include <support/check.h>
+
+static const struct argp_option
+options[] =
+{
+  { "test", 't', "format", 0, "Run argp function with a format string", 0 },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+static error_t
+parser (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+      case 't':
+	ARGP_FUNCTION ARGP_FUNCTION_PARAMS;
+	break;
+      default:
+	return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static struct argp
+argp =
+{
+  options, parser
+};
+
+static int
+do_test (void)
+{
+  int remaining;
+  int argc = 3;
+  char *argv[4] =
+    {
+      (char *) "test-argp",
+      (char *) "--test",
+      (char *) "%Lf - %f - %Lf - %f",
+      NULL
+    };
+
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>

-----------------------------------------------------------------------


hooks/post-receive
-- 
GNU C Library master sources


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