aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common')
-rw-r--r--stdio-common/fxprintf.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
index 5ed0bb033b..82d4f2e235 100644
--- a/stdio-common/fxprintf.c
+++ b/stdio-common/fxprintf.c
@@ -16,14 +16,50 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <assert.h>
-#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
-#include <wchar.h>
+#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
#include <libioP.h>
+static int
+locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
+{
+ if (_IO_fwide (fp, 0) <= 0)
+ return _IO_vfprintf (fp, fmt, ap);
+
+ /* We must convert the narrow format string to a wide one.
+ Each byte can produce at most one wide character. */
+ wchar_t *wfmt;
+ mbstate_t mbstate;
+ int res;
+ int used_malloc = 0;
+ size_t len = strlen (fmt) + 1;
+
+ if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ if (__libc_use_alloca (len * sizeof (wchar_t)))
+ wfmt = alloca (len * sizeof (wchar_t));
+ else if ((wfmt = malloc (len * sizeof (wchar_t))) == NULL)
+ return -1;
+ else
+ used_malloc = 1;
+
+ memset (&mbstate, 0, sizeof mbstate);
+ res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
+
+ if (res != -1)
+ res = _IO_vfwprintf (fp, wfmt, ap);
+
+ if (used_malloc)
+ free (wfmt);
+
+ return res;
+}
int
__fxprintf (FILE *fp, const char *fmt, ...)
@@ -33,23 +69,31 @@ __fxprintf (FILE *fp, const char *fmt, ...)
va_list ap;
va_start (ap, fmt);
+ _IO_flockfile (fp);
- int res;
- if (_IO_fwide (fp, 0) > 0)
- {
- size_t len = strlen (fmt) + 1;
- wchar_t wfmt[len];
- for (size_t i = 0; i < len; ++i)
- {
- assert (isascii (fmt[i]));
- wfmt[i] = fmt[i];
- }
- res = __vfwprintf (fp, wfmt, ap);
- }
- else
- res = _IO_vfprintf (fp, fmt, ap);
+ int res = locked_vfxprintf (fp, fmt, ap);
+ _IO_funlockfile (fp);
va_end (ap);
+ return res;
+}
+int
+__fxprintf_nocancel (FILE *fp, const char *fmt, ...)
+{
+ if (fp == NULL)
+ fp = stderr;
+
+ va_list ap;
+ va_start (ap, fmt);
+ _IO_flockfile (fp);
+ int save_flags2 = ((_IO_FILE *)fp)->_flags2;
+ ((_IO_FILE *)fp)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ int res = locked_vfxprintf (fp, fmt, ap);
+
+ ((_IO_FILE *)fp)->_flags2 = save_flags2;
+ _IO_funlockfile (fp);
+ va_end (ap);
return res;
}