summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--newlib/ChangeLog31
-rw-r--r--newlib/libc/include/stdio.h2
-rw-r--r--newlib/libc/include/wchar.h25
-rw-r--r--newlib/libc/stdio/Makefile.am40
-rw-r--r--newlib/libc/stdio/Makefile.in87
-rw-r--r--newlib/libc/stdio/fwprintf.c56
-rw-r--r--newlib/libc/stdio/local.h52
-rw-r--r--newlib/libc/stdio/stdio.tex8
-rw-r--r--newlib/libc/stdio/swprintf.c592
-rw-r--r--newlib/libc/stdio/vfprintf.c113
-rw-r--r--newlib/libc/stdio/vfwprintf.c1777
-rw-r--r--newlib/libc/stdio/vswprintf.c71
-rw-r--r--newlib/libc/stdio/vwprintf.c47
-rw-r--r--newlib/libc/stdio/wprintf.c58
14 files changed, 2887 insertions, 72 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index 3e4018267..7c8a6406f 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -1,3 +1,34 @@
+2009-03-06 Corinna Vinschen <corinna@vinschen.de>
+
+ * libc/include/stdio.h (__VALIST): Guard against multiple definition.
+ * libc/include/wchar.h: Include stdarg.h.
+ (__VALIST): Define conditionally.
+ (fwprintf, swprintf, vfwprintf, vswprintf, vwprintf, wprintf: Declare.
+ (_fwprintf_r, _swprintf_r, _vfwprintf_r, _vswprintf_r, _vwprintf_r,
+ _wprintf_r): Declare.
+ * libc/stdio/Makefile.am: Add new files.
+ * libc/stdio/Makefile.in: Regenerate.
+ * libc/stdio/fwprintf.c: New file.
+ * libc/stdio/local.h (_svfwprintf_r, _svfiwprintf_r): Declare.
+ (__CH_CLASS, __STATE, __ACTION): Move definition from vfprintf.c here
+ and move to the __ namespace.
+ (__chclass, __state_table, __action_table): Declare.
+ * libc/stdio/stdio.tex: Add new documentation references.
+ * libc/stdio/swprintf.c: New file.
+ * libc/stdio/vfprintf.c (__SPRINT): New macro to call the right
+ __sprint_r function according to compilation unit. Use throughout.
+ (__ssprint_r): Rename STRING_ONLY variant from __sprint_r.
+ Make externaly available. Only define if INTEGER_ONLY is defined.
+ (__sprint_r): Make externaly available. Only define if INTEGER_ONLY
+ is defined. Handle stream orientation.
+ (__sbprintf): Copy FILE's _flags2 member as well.
+ (__chclass, __state_table, __action_table): Prepend __ to name and
+ make externally available.
+ * libc/stdio/vfwprintf.c: New file.
+ * libc/stdio/vswprintf.c: New file.
+ * libc/stdio/vwprintf.c: New file.
+ * libc/stdio/wprintf.c: New file.
+
2009-03-03 Corinna Vinschen <corinna@vinschen.de>
* libc/locale/locale.c (_setlocale_r): New implementation based on
diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index a55dd6969..fd58a25b3 100644
--- a/newlib/libc/include/stdio.h
+++ b/newlib/libc/include/stdio.h
@@ -164,11 +164,13 @@ typedef _fpos64_t fpos64_t;
* Functions defined in ANSI C standard.
*/
+#ifndef __VALIST
#ifdef __GNUC__
#define __VALIST __gnuc_va_list
#else
#define __VALIST char*
#endif
+#endif
FILE * _EXFUN(tmpfile, (void));
char * _EXFUN(tmpnam, (char *));
diff --git a/newlib/libc/include/wchar.h b/newlib/libc/include/wchar.h
index ad905e2bf..37529a97f 100644
--- a/newlib/libc/include/wchar.h
+++ b/newlib/libc/include/wchar.h
@@ -10,6 +10,9 @@
#define __need_wint_t
#include <stddef.h>
+#define __need___va_list
+#include <stdarg.h>
+
/* For _mbstate_t definition. */
#include <sys/_types.h>
@@ -129,6 +132,28 @@ wint_t _EXFUN (_ungetwc_r, (struct _reent *, wint_t wc, __FILE *));
__FILE *_EXFUN (open_wmemstream, (wchar_t **, size_t *));
__FILE *_EXFUN (_open_wmemstream_r, (struct _reent *, wchar_t **, size_t *));
+#ifndef __VALIST
+#ifdef __GNUC__
+#define __VALIST __gnuc_va_list
+#else
+#define __VALIST char*
+#endif
+#endif
+
+int _EXFUN(fwprintf, (__FILE *, const wchar_t *, ...));
+int _EXFUN(swprintf, (wchar_t *, size_t, const wchar_t *, ...));
+int _EXFUN(vfwprintf, (__FILE *, const wchar_t *, __VALIST));
+int _EXFUN(vswprintf, (wchar_t *, size_t, const wchar_t *, __VALIST));
+int _EXFUN(vwprintf, (const wchar_t *, __VALIST));
+int _EXFUN(wprintf, (const wchar_t *, ...));
+
+int _EXFUN(_fwprintf_r, (struct _reent *, __FILE *, const wchar_t *, ...));
+int _EXFUN(_swprintf_r, (struct _reent *, wchar_t *, size_t, const wchar_t *, ...));
+int _EXFUN(_vfwprintf_r, (struct _reent *, __FILE *, const wchar_t *, __VALIST));
+int _EXFUN(_vswprintf_r, (struct _reent *, wchar_t *, size_t, const wchar_t *, __VALIST));
+int _EXFUN(_vwprintf_r, (struct _reent *, const wchar_t *, __VALIST));
+int _EXFUN(_wprintf_r, (struct _reent *, const wchar_t *, ...));
+
#define getwc(fp) fgetwc(fp)
#define putwc(wc,fp) fputwc((wc), (fp))
#ifndef _REENT_ONLY
diff --git a/newlib/libc/stdio/Makefile.am b/newlib/libc/stdio/Makefile.am
index c7111e2c8..23840bcee 100644
--- a/newlib/libc/stdio/Makefile.am
+++ b/newlib/libc/stdio/Makefile.am
@@ -125,14 +125,20 @@ ELIX_4_SOURCES = \
fputws.c \
funopen.c \
fwide.c \
+ fwprintf.c \
getwc.c \
getwchar.c \
open_memstream.c \
putwc.c \
putwchar.c \
+ swprintf.c \
ungetwc.c \
vasniprintf.c \
- vasnprintf.c
+ vasnprintf.c \
+ vswprintf.c \
+ vwprintf.c \
+ wprintf.c
+
endif !ELIX_LEVEL_3
endif !ELIX_LEVEL_2
endif !ELIX_LEVEL_1
@@ -141,7 +147,9 @@ LIBADD_OBJS = \
$(lpfx)svfiprintf.$(oext) $(lpfx)svfprintf.$(oext) \
$(lpfx)svfiscanf.$(oext) $(lpfx)svfscanf.$(oext) \
$(lpfx)vfiprintf.$(oext) $(lpfx)vfprintf.$(oext) \
- $(lpfx)vfscanf.$(oext) $(lpfx)vfiscanf.$(oext)
+ $(lpfx)vfscanf.$(oext) $(lpfx)vfiscanf.$(oext) \
+ $(lpfx)svfiwprintf.$(oext) $(lpfx)svfwprintf.$(oext) \
+ $(lpfx)vfiwprintf.$(oext) $(lpfx)vfwprintf.$(oext)
libstdio_la_LDFLAGS = -Xcompiler -nostdlib
@@ -179,6 +187,18 @@ $(lpfx)svfprintf.$(oext): vfprintf.c
$(lpfx)svfiprintf.$(oext): vfprintf.c
$(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -DSTRING_ONLY -c $(srcdir)/vfprintf.c -o $@
+$(lpfx)vfwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)vfiwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)svfwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DSTRING_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)svfiwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -DSTRING_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
$(lpfx)vfscanf.$(oext): vfscanf.c
$(LIB_COMPILE) -c $(srcdir)/vfscanf.c -o $@
@@ -254,12 +274,14 @@ CHEWOUT_FILES = \
siscanf.def \
sprintf.def \
sscanf.def \
+ swprintf.def \
tmpfile.def \
tmpnam.def \
ungetc.def \
ungetwc.def \
vfprintf.def \
vfscanf.def \
+ vfwprintf.def \
viprintf.def \
viscanf.def
@@ -298,9 +320,10 @@ $(lpfx)funopen.$(oext): local.h
$(lpfx)fvwrite.$(oext): local.h fvwrite.h
$(lpfx)fwalk.$(oext): local.h
$(lpfx)fwide.$(oext): local.h
+$(lpfx)fwprintf.$(oext): local.h
+$(lpfx)fwrite.$(oext): local.h fvwrite.h
$(lpfx)getwc.$(oext): local.h
$(lpfx)getwchar.$(oext): local.h
-$(lpfx)fwrite.$(oext): local.h fvwrite.h
$(lpfx)iscanf.$(oext): local.h
$(lpfx)makebuf.$(oext): local.h
$(lpfx)open_memstream.$(oext): local.h
@@ -312,25 +335,30 @@ $(lpfx)scanf.$(oext): local.h
$(lpfx)setbuf.$(oext): local.h
$(lpfx)setvbuf.$(oext): local.h
$(lpfx)siprintf.$(oext): local.h
+$(lpfx)siscanf.$(oext): local.h
$(lpfx)sniprintf.$(oext): local.h
$(lpfx)sprintf.$(oext): local.h
-$(lpfx)siscanf.$(oext): local.h
$(lpfx)sscanf.$(oext): local.h
$(lpfx)stdio.$(oext): local.h
$(lpfx)svfiprintf.$(oext): local.h
$(lpfx)svfiscanf.$(oext): local.h floatio.h
$(lpfx)svfprintf.$(oext): local.h
$(lpfx)svfscanf.$(oext): local.h floatio.h
+$(lpfx)swprintf.$(oext): local.h
$(lpfx)ungetc.$(oext): local.h
$(lpfx)ungetwc.$(oext): local.h
$(lpfx)vfiprintf.$(oext): local.h
-$(lpfx)vfprintf.$(oext): local.h
$(lpfx)vfiscanf.$(oext): local.h floatio.h
+$(lpfx)vfprintf.$(oext): local.h
$(lpfx)vfscanf.$(oext): local.h floatio.h
+$(lpfx)vfwprintf.$(oext): local.h
$(lpfx)viscanf.$(oext): local.h
$(lpfx)vscanf.$(oext): local.h
-$(lpfx)vsniprintf.$(oext): local.h
$(lpfx)vsiscanf.$(oext): local.h
+$(lpfx)vsniprintf.$(oext): local.h
$(lpfx)vsscanf.$(oext): local.h
+$(lpfx)vswprintf.$(oext): local.h
+$(lpfx)vwprintf.$(oext): local.h
$(lpfx)wbuf.$(oext): local.h fvwrite.h
+$(lpfx)wprintf.$(oext): local.h
$(lpfx)wsetup.$(oext): local.h
diff --git a/newlib/libc/stdio/Makefile.in b/newlib/libc/stdio/Makefile.in
index 7beaa0ab3..a40e8af22 100644
--- a/newlib/libc/stdio/Makefile.in
+++ b/newlib/libc/stdio/Makefile.in
@@ -60,7 +60,9 @@ am__DEPENDENCIES_1 = $(lpfx)svfiprintf.$(oext) \
$(lpfx)svfprintf.$(oext) $(lpfx)svfiscanf.$(oext) \
$(lpfx)svfscanf.$(oext) $(lpfx)vfiprintf.$(oext) \
$(lpfx)vfprintf.$(oext) $(lpfx)vfscanf.$(oext) \
- $(lpfx)vfiscanf.$(oext)
+ $(lpfx)vfiscanf.$(oext) $(lpfx)svfiwprintf.$(oext) \
+ $(lpfx)svfwprintf.$(oext) $(lpfx)vfiwprintf.$(oext) \
+ $(lpfx)vfwprintf.$(oext)
am__objects_1 = lib_a-clearerr.$(OBJEXT) lib_a-fclose.$(OBJEXT) \
lib_a-fdopen.$(OBJEXT) lib_a-feof.$(OBJEXT) \
lib_a-ferror.$(OBJEXT) lib_a-fflush.$(OBJEXT) \
@@ -123,14 +125,19 @@ am__objects_1 = lib_a-clearerr.$(OBJEXT) lib_a-fclose.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-fputws.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-funopen.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-fwide.$(OBJEXT) \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-fwprintf.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-getwc.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-getwchar.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-open_memstream.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-putwc.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-putwchar.$(OBJEXT) \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-swprintf.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-ungetwc.$(OBJEXT) \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vasniprintf.$(OBJEXT) \
-@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vasnprintf.$(OBJEXT)
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vasnprintf.$(OBJEXT) \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vswprintf.$(OBJEXT) \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vwprintf.$(OBJEXT) \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-wprintf.$(OBJEXT)
@USE_LIBTOOL_FALSE@am_lib_a_OBJECTS = $(am__objects_1) \
@USE_LIBTOOL_FALSE@ $(am__objects_2) $(am__objects_3)
lib_a_OBJECTS = $(am_lib_a_OBJECTS)
@@ -166,14 +173,19 @@ am__objects_4 = clearerr.lo fclose.lo fdopen.lo feof.lo ferror.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fputws.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ funopen.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fwide.lo \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fwprintf.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ getwc.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ getwchar.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ open_memstream.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ putwc.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ putwchar.lo \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ swprintf.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ ungetwc.lo \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasniprintf.lo \
-@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.lo
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.lo \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vswprintf.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vwprintf.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ wprintf.c
@USE_LIBTOOL_TRUE@am_libstdio_la_OBJECTS = $(am__objects_4) \
@USE_LIBTOOL_TRUE@ $(am__objects_5) $(am__objects_6)
libstdio_la_OBJECTS = $(am_libstdio_la_OBJECTS)
@@ -470,14 +482,19 @@ GENERAL_SOURCES = \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fputws.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ funopen.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fwide.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fwprintf.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ getwc.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ getwchar.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ open_memstream.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ putwc.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ putwchar.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ swprintf.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ ungetwc.c \
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasniprintf.c \
-@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.c
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vswprintf.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vwprintf.c \
+@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ wprintf.c
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_TRUE@ELIX_4_SOURCES =
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_TRUE@ELIX_4_SOURCES =
@@ -486,7 +503,9 @@ LIBADD_OBJS = \
$(lpfx)svfiprintf.$(oext) $(lpfx)svfprintf.$(oext) \
$(lpfx)svfiscanf.$(oext) $(lpfx)svfscanf.$(oext) \
$(lpfx)vfiprintf.$(oext) $(lpfx)vfprintf.$(oext) \
- $(lpfx)vfscanf.$(oext) $(lpfx)vfiscanf.$(oext)
+ $(lpfx)vfscanf.$(oext) $(lpfx)vfiscanf.$(oext) \
+ $(lpfx)svfiwprintf.$(oext) $(lpfx)svfwprintf.$(oext) \
+ $(lpfx)vfiwprintf.$(oext) $(lpfx)vfwprintf.$(oext)
libstdio_la_LDFLAGS = -Xcompiler -nostdlib
@USE_LIBTOOL_TRUE@noinst_LTLIBRARIES = libstdio.la
@@ -565,12 +584,14 @@ CHEWOUT_FILES = \
siscanf.def \
sprintf.def \
sscanf.def \
+ swprintf.def \
tmpfile.def \
tmpnam.def \
ungetc.def \
ungetwc.def \
vfprintf.def \
vfscanf.def \
+ vfwprintf.def \
viprintf.def \
viscanf.def
@@ -1299,6 +1320,36 @@ lib_a-vasnprintf.o: vasnprintf.c
lib_a-vasnprintf.obj: vasnprintf.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vasnprintf.obj `if test -f 'vasnprintf.c'; then $(CYGPATH_W) 'vasnprintf.c'; else $(CYGPATH_W) '$(srcdir)/vasnprintf.c'; fi`
+lib_a-vwprintf.o: vwprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vwprintf.o `test -f 'vwprintf.c' || echo '$(srcdir)/'`vwprintf.c
+
+lib_a-vwprintf.obj: vwprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vwprintf.obj `if test -f 'vwprintf.c'; then $(CYGPATH_W) 'vwprintf.c'; else $(CYGPATH_W) '$(srcdir)/vwprintf.c'; fi`
+
+lib_a-swprintf.o: swprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-swprintf.o `test -f 'swprintf.c' || echo '$(srcdir)/'`swprintf.c
+
+lib_a-swprintf.obj: swprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-swprintf.obj `if test -f 'swprintf.c'; then $(CYGPATH_W) 'swprintf.c'; else $(CYGPATH_W) '$(srcdir)/swprintf.c'; fi`
+
+lib_a-vswprintf.o: vswprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vswprintf.o `test -f 'vswprintf.c' || echo '$(srcdir)/'`vswprintf.c
+
+lib_a-vswprintf.obj: vswprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vswprintf.obj `if test -f 'vswprintf.c'; then $(CYGPATH_W) 'vswprintf.c'; else $(CYGPATH_W) '$(srcdir)/vswprintf.c'; fi`
+
+lib_a-wprintf.o: wprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wprintf.o `test -f 'wprintf.c' || echo '$(srcdir)/'`wprintf.c
+
+lib_a-wprintf.obj: wprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wprintf.obj `if test -f 'wprintf.c'; then $(CYGPATH_W) 'wprintf.c'; else $(CYGPATH_W) '$(srcdir)/wprintf.c'; fi`
+
+lib_a-fwprintf.o: fwprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-fwprintf.o `test -f 'fwprintf.c' || echo '$(srcdir)/'`fwprintf.c
+
+lib_a-fwprintf.obj: fwprintf.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-fwprintf.obj `if test -f 'fwprintf.c'; then $(CYGPATH_W) 'fwprintf.c'; else $(CYGPATH_W) '$(srcdir)/fwprintf.c'; fi`
+
mostlyclean-libtool:
-rm -f *.lo
@@ -1468,6 +1519,18 @@ $(lpfx)svfprintf.$(oext): vfprintf.c
$(lpfx)svfiprintf.$(oext): vfprintf.c
$(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -DSTRING_ONLY -c $(srcdir)/vfprintf.c -o $@
+$(lpfx)vfwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)vfiwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)svfwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DSTRING_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
+$(lpfx)svfiwprintf.$(oext): vfwprintf.c
+ $(LIB_COMPILE) -fshort-enums -DINTEGER_ONLY -DSTRING_ONLY -c $(srcdir)/vfwprintf.c -o $@
+
$(lpfx)vfscanf.$(oext): vfscanf.c
$(LIB_COMPILE) -c $(srcdir)/vfscanf.c -o $@
@@ -1507,9 +1570,10 @@ $(lpfx)funopen.$(oext): local.h
$(lpfx)fvwrite.$(oext): local.h fvwrite.h
$(lpfx)fwalk.$(oext): local.h
$(lpfx)fwide.$(oext): local.h
+$(lpfx)fwprintf.$(oext): local.h
+$(lpfx)fwrite.$(oext): local.h fvwrite.h
$(lpfx)getwc.$(oext): local.h
$(lpfx)getwchar.$(oext): local.h
-$(lpfx)fwrite.$(oext): local.h fvwrite.h
$(lpfx)iscanf.$(oext): local.h
$(lpfx)makebuf.$(oext): local.h
$(lpfx)open_memstream.$(oext): local.h
@@ -1521,27 +1585,32 @@ $(lpfx)scanf.$(oext): local.h
$(lpfx)setbuf.$(oext): local.h
$(lpfx)setvbuf.$(oext): local.h
$(lpfx)siprintf.$(oext): local.h
+$(lpfx)siscanf.$(oext): local.h
$(lpfx)sniprintf.$(oext): local.h
$(lpfx)sprintf.$(oext): local.h
-$(lpfx)siscanf.$(oext): local.h
$(lpfx)sscanf.$(oext): local.h
$(lpfx)stdio.$(oext): local.h
$(lpfx)svfiprintf.$(oext): local.h
$(lpfx)svfiscanf.$(oext): local.h floatio.h
$(lpfx)svfprintf.$(oext): local.h
$(lpfx)svfscanf.$(oext): local.h floatio.h
+$(lpfx)swprintf.$(oext): local.h
$(lpfx)ungetc.$(oext): local.h
$(lpfx)ungetwc.$(oext): local.h
$(lpfx)vfiprintf.$(oext): local.h
-$(lpfx)vfprintf.$(oext): local.h
$(lpfx)vfiscanf.$(oext): local.h floatio.h
+$(lpfx)vfprintf.$(oext): local.h
$(lpfx)vfscanf.$(oext): local.h floatio.h
+$(lpfx)vfwprintf.$(oext): local.h
$(lpfx)viscanf.$(oext): local.h
$(lpfx)vscanf.$(oext): local.h
-$(lpfx)vsniprintf.$(oext): local.h
$(lpfx)vsiscanf.$(oext): local.h
+$(lpfx)vsniprintf.$(oext): local.h
$(lpfx)vsscanf.$(oext): local.h
+$(lpfx)vswprintf.$(oext): local.h
+$(lpfx)vwprintf.$(oext): local.h
$(lpfx)wbuf.$(oext): local.h fvwrite.h
+$(lpfx)wprintf.$(oext): local.h
$(lpfx)wsetup.$(oext): local.h
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/newlib/libc/stdio/fwprintf.c b/newlib/libc/stdio/fwprintf.c
new file mode 100644
index 000000000..76065e965
--- /dev/null
+++ b/newlib/libc/stdio/fwprintf.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* doc in swprintf.c */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+
+int
+_DEFUN(_fwprintf_r, (ptr, fp, fmt),
+ struct _reent *ptr _AND
+ FILE *fp _AND
+ const wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+
+ va_start (ap, fmt);
+ ret = _vfwprintf_r (ptr, fp, fmt, ap);
+ va_end (ap);
+ return ret;
+}
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(fwprintf, (fp, fmt),
+ FILE *fp _AND
+ const wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+
+ va_start (ap, fmt);
+ ret = _vfwprintf_r (_REENT, fp, fmt, ap);
+ va_end (ap);
+ return ret;
+}
+
+#endif /* ! _REENT_ONLY */
diff --git a/newlib/libc/stdio/local.h b/newlib/libc/stdio/local.h
index 29e7cc6c1..1e1e042d2 100644
--- a/newlib/libc/stdio/local.h
+++ b/newlib/libc/stdio/local.h
@@ -44,6 +44,10 @@ int _EXFUN(_svfprintf_r,(struct _reent *, FILE *, const char *,
int _EXFUN(_svfiprintf_r,(struct _reent *, FILE *, const char *,
va_list)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
+int _EXFUN(_svfwprintf_r,(struct _reent *, FILE *, const wchar_t *,
+ va_list));
+int _EXFUN(_svfiwprintf_r,(struct _reent *, FILE *, const wchar_t *,
+ va_list));
extern FILE *_EXFUN(__sfp,(struct _reent *));
extern int _EXFUN(__sflags,(struct _reent *,_CONST char*, int*));
extern int _EXFUN(__srefill_r,(struct _reent *,FILE *));
@@ -167,3 +171,51 @@ _VOID _EXFUN(__sfp_lock_release,(_VOID));
_VOID _EXFUN(__sinit_lock_acquire,(_VOID));
_VOID _EXFUN(__sinit_lock_release,(_VOID));
#endif
+
+/* Types used in positional argument support in vfprinf/vfwprintf.
+ The implementation is char/wchar_t dependent but the class and state
+ tables are only defined once in vfprintf.c. */
+typedef enum {
+ ZERO, /* '0' */
+ DIGIT, /* '1-9' */
+ DOLLAR, /* '$' */
+ MODFR, /* spec modifier */
+ SPEC, /* format specifier */
+ DOT, /* '.' */
+ STAR, /* '*' */
+ FLAG, /* format flag */
+ OTHER, /* all other chars */
+ MAX_CH_CLASS /* place-holder */
+} __CH_CLASS;
+
+typedef enum {
+ START, /* start */
+ SFLAG, /* seen a flag */
+ WDIG, /* seen digits in width area */
+ WIDTH, /* processed width */
+ SMOD, /* seen spec modifier */
+ SDOT, /* seen dot */
+ VARW, /* have variable width specifier */
+ VARP, /* have variable precision specifier */
+ PREC, /* processed precision */
+ VWDIG, /* have digits in variable width specification */
+ VPDIG, /* have digits in variable precision specification */
+ DONE, /* done */
+ MAX_STATE, /* place-holder */
+} __STATE;
+
+typedef enum {
+ NOOP, /* do nothing */
+ NUMBER, /* build a number from digits */
+ SKIPNUM, /* skip over digits */
+ GETMOD, /* get and process format modifier */
+ GETARG, /* get and process argument */
+ GETPW, /* get variable precision or width */
+ GETPWB, /* get variable precision or width and pushback fmt char */
+ GETPOS, /* get positional parameter value */
+ PWPOS, /* get positional parameter value for variable width or precision */
+} __ACTION;
+
+_CONST __CH_CLASS __chclass[256];
+_CONST __STATE __state_table[MAX_STATE][MAX_CH_CLASS];
+_CONST __ACTION __action_table[MAX_STATE][MAX_CH_CLASS];
diff --git a/newlib/libc/stdio/stdio.tex b/newlib/libc/stdio/stdio.tex
index f2a7cfcc1..b3a69fc1d 100644
--- a/newlib/libc/stdio/stdio.tex
+++ b/newlib/libc/stdio/stdio.tex
@@ -84,12 +84,14 @@ structure.
* siscanf:: Scan and format input (integer only)
* sprintf:: Write formatted output
* sscanf:: Scan and format input
+* swprintf:: Write formatted wide character output
* tmpfile:: Create a temporary file
* tmpnam:: Generate name for a temporary file
* ungetc:: Push data back into a stream
* ungetwc:: Push wide character data back into a stream
* vfprintf:: Format variable argument list
* vfscanf:: Scan variable argument list
+* vfwprintf:: Format variable wide character argument list
* viprintf:: Format variable argument list (integer only)
* viscanf:: Scan variable format list (integer only)
@end menu
@@ -275,6 +277,9 @@ structure.
@include stdio/sscanf.def
@page
+@include stdio/swprintf.def
+
+@page
@include stdio/tmpfile.def
@page
@@ -293,6 +298,9 @@ structure.
@include stdio/vfscanf.def
@page
+@include stdio/vfwprintf.def
+
+@page
@include stdio/viprintf.def
@page
diff --git a/newlib/libc/stdio/swprintf.c b/newlib/libc/stdio/swprintf.c
new file mode 100644
index 000000000..0d0e4d933
--- /dev/null
+++ b/newlib/libc/stdio/swprintf.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 1990, 2007 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+FUNCTION
+<<swprintf>>, <<fwprintf>>, <<wprintf>>---wide character format output
+
+INDEX
+ fwprintf
+INDEX
+ _fwprintf_r
+INDEX
+ wprintf
+INDEX
+ _wprintf_r
+INDEX
+ swprintf
+INDEX
+ _swprintf_r
+
+ANSI_SYNOPSIS
+ #include <stdio.h>
+
+ int wprintf(const wchar_t *<[format]>, ...);
+ int fwprintf(FILE *<[fd]>, const wchar_t *<[format]>, ...);
+ int swprintf(wchar_t *<[str]>, const wchar_t *<[format]>, ...);
+
+ int _wprintf_r(struct _reent *<[ptr]>, const wchar_t *<[format]>, ...);
+ int _fwprintf_r(struct _reent *<[ptr]>, FILE *<[fd]>,
+ const wchar_t *<[format]>, ...);
+ int _swprintf_r(struct _reent *<[ptr]>, wchar_t *<[str]>,
+ const wchar_t *<[format]>, ...);
+
+DESCRIPTION
+ <<wprintf>> accepts a series of arguments, applies to each a
+ format specifier from <<*<[format]>>>, and writes the
+ formatted data to <<stdout>>, without a terminating NUL
+ wide character. The behavior of <<wprintf>> is undefined if there
+ are not enough arguments for the format. <<wprintf>> returns
+ when it reaches the end of the format string. If there are
+ more arguments than the format requires, excess arguments are
+ ignored.
+
+ <<fwprintf>> is like <<wprintf>>, except that output is directed
+ to the stream <[fd]> rather than <<stdout>>.
+
+ <<swprintf>> is like <<wprintf>>, except that output is directed
+ to the buffer <[str]>, and the resulting string length is limited
+ to at most <[size]> wide characters, including the terminating
+ <<NUL>>. As a special case, if <[size]> is 0, <[str]> can be NULL,
+ and <<swprintf>> merely calculates how many bytes would be printed.
+
+ For <<swprintf>> the behavior is undefined if the output
+ <<*<[str]>>> overlaps with one of the arguments. Behavior is also
+ undefined if the argument for <<%n>> within <<*<[format]>>>
+ overlaps another argument.
+
+ <[format]> is a pointer to a wide character string containing two
+ types of objects: ordinary characters (other than <<%>>),
+ which are copied unchanged to the output, and conversion
+ specifications, each of which is introduced by <<%>>. (To
+ include <<%>> in the output, use <<%%>> in the format string.)
+ A conversion specification has the following form:
+
+. %[<[pos]>][<[flags]>][<[width]>][.<[prec]>][<[size]>]<[type]>
+
+ The fields of the conversion specification have the following
+ meanings:
+
+ O+
+ o <[pos]>
+
+ Conversions normally consume arguments in the order that they
+ are presented. However, it is possible to consume arguments
+ out of order, and reuse an argument for more than one
+ conversion specification (although the behavior is undefined
+ if the same argument is requested with different types), by
+ specifying <[pos]>, which is a decimal integer followed by
+ '$'. The integer must be between 1 and <NL_ARGMAX> from
+ limits.h, and if argument <<%n$>> is requested, all earlier
+ arguments must be requested somewhere within <[format]>. If
+ positional parameters are used, then all conversion
+ specifications except for <<%%>> must specify a position.
+
+ o <[flags]>
+
+ <[flags]> is an optional sequence of characters which control
+ output justification, numeric signs, decimal points, trailing
+ zeros, and octal and hex prefixes. The flag characters are
+ minus (<<->>), plus (<<+>>), space ( ), zero (<<0>>), sharp
+ (<<#>>), and quote (<<'>>). They can appear in any
+ combination, although not all flags can be used for all
+ conversion specification types.
+
+ o+
+ o '
+ Since newlib only supports the C locale, this
+ flag has no effect in this implementation.
+ But in other locales, when <[type]> is <<i>>,
+ <<d>>, <<u>>, <<f>>, <<F>>, <<g>>, or <<G>>,
+ the locale-dependent thousand's separator is
+ inserted prior to zero padding.
+
+ o -
+ The result of the conversion is left
+ justified, and the right is padded with
+ blanks. If you do not use this flag, the
+ result is right justified, and padded on the
+ left.
+
+ o +
+ The result of a signed conversion (as
+ determined by <[type]> of <<d>>, <<i>>, <<a>>,
+ <<A>>, <<e>>, <<E>>, <<f>>, <<F>>, <<g>>, or
+ <<G>>) will always begin with a plus or minus
+ sign. (If you do not use this flag, positive
+ values do not begin with a plus sign.)
+
+ o " " (space)
+ If the first character of a signed conversion
+ specification is not a sign, or if a signed
+ conversion results in no characters, the
+ result will begin with a space. If the space
+ ( ) flag and the plus (<<+>>) flag both
+ appear, the space flag is ignored.
+
+ o 0
+ If the <[type]> character is <<d>>, <<i>>,
+ <<o>>, <<u>>, <<x>>, <<X>>, <<a>>, <<A>>,
+ <<e>>, <<E>>, <<f>>, <<g>>, or <<G>>: leading
+ zeros are used to pad the field width
+ (following any indication of sign or base); no
+ spaces are used for padding. If the zero
+ (<<0>>) and minus (<<->>) flags both appear,
+ the zero (<<0>>) flag will be ignored. For
+ <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, and <<X>>
+ conversions, if a precision <[prec]> is
+ specified, the zero (<<0>>) flag is ignored.
+
+ Note that <<0>> is interpreted as a flag, not
+ as the beginning of a field width.
+
+ o #
+ The result is to be converted to an
+ alternative form, according to the <[type]>
+ character:
+
+ o+
+ o o
+ Increases precision to force the first
+ digit of the result to be a zero.
+
+ o x
+ A non-zero result will have a <<0x>>
+ prefix.
+
+ o X
+ A non-zero result will have a <<0X>>
+ prefix.
+
+ o a, A, e, E, f, or F
+ The result will always contain a
+ decimal point even if no digits follow
+ the point. (Normally, a decimal point
+ appears only if a digit follows it.)
+ Trailing zeros are removed.
+
+ o g or G
+ The result will always contain a
+ decimal point even if no digits follow
+ the point. Trailing zeros are not
+ removed.
+
+ o all others
+ Undefined.
+
+ o-
+ o-
+
+ o <[width]>
+
+ <[width]> is an optional minimum field width. You can
+ either specify it directly as a decimal integer, or
+ indirectly by using instead an asterisk (<<*>>), in
+ which case an <<int>> argument is used as the field
+ width. If positional arguments are used, then the
+ width must also be specified positionally as <<*m$>>,
+ with m as a decimal integer. Negative field widths
+ are treated as specifying the minus (<<->>) flag for
+ left justfication, along with a positive field width.
+ The resulting format may be wider than the specified
+ width.
+
+ o <[prec]>
+
+ <[prec]> is an optional field; if present, it is
+ introduced with `<<.>>' (a period). You can specify
+ the precision either directly as a decimal integer or
+ indirectly by using an asterisk (<<*>>), in which case
+ an <<int>> argument is used as the precision. If
+ positional arguments are used, then the precision must
+ also be specified positionally as <<*m$>>, with m as a
+ decimal integer. Supplying a negative precision is
+ equivalent to omitting the precision. If only a
+ period is specified the precision is zero. The effect
+ depends on the conversion <[type]>.
+
+ o+
+ o d, i, o, u, x, or X
+ Minimum number of digits to appear. If no
+ precision is given, defaults to 1.
+
+ o a or A
+ Number of digits to appear after the decimal
+ point. If no precision is given, the
+ precision defaults to the minimum needed for
+ an exact representation.
+
+ o e, E, f or F
+ Number of digits to appear after the decimal
+ point. If no precision is given, the
+ precision defaults to 6.
+
+ o g or G
+ Maximum number of significant digits. A
+ precision of 0 is treated the same as a
+ precision of 1. If no precision is given, the
+ precision defaults to 6.
+
+ o s or S
+ Maximum number of characters to print from the
+ string. If no precision is given, the entire
+ string is printed.
+
+ o all others
+ undefined.
+
+ o-
+
+ o <[size]>
+
+ <[size]> is an optional modifier that changes the data
+ type that the corresponding argument has. Behavior is
+ unspecified if a size is given that does not match the
+ <[type]>.
+
+ o+
+ o hh
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument should be
+ converted to a <<signed char>> or <<unsigned
+ char>> before printing.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<signed char>>.
+
+ o h
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument should be
+ converted to a <<short>> or <<unsigned short>>
+ before printing.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<short>>.
+
+ o l
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument is a
+ <<long>> or <<unsigned long>>.
+
+ With <<c>>, specifies that the argument has
+ type <<wint_t>>.
+
+ With <<s>>, specifies that the argument is a
+ pointer to <<wchar_t>>.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<long>>.
+
+ With <<a>>, <<A>>, <<e>>, <<E>>, <<f>>, <<F>>,
+ <<g>>, or <<G>>, has no effect (because of
+ vararg promotion rules, there is no need to
+ distinguish between <<float>> and <<double>>).
+
+ o ll
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument is a
+ <<long long>> or <<unsigned long long>>.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<long long>>.
+
+ o j
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument is an
+ <<intmax_t>> or <<uintmax_t>>.
+
+ With <<n>>, specifies that the argument is a
+ pointer to an <<intmax_t>>.
+
+ o z
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument is a
+ <<ssize_t>> or <<size_t>>.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<ssize_t>>.
+
+ o t
+ With <<d>>, <<i>>, <<o>>, <<u>>, <<x>>, or
+ <<X>>, specifies that the argument is a
+ <<ptrdiff_t>>.
+
+ With <<n>>, specifies that the argument is a
+ pointer to a <<ptrdiff_t>>.
+
+ o L
+ With <<a>>, <<A>>, <<e>>, <<E>>, <<f>>, <<F>>,
+ <<g>>, or <<G>>, specifies that the argument
+ is a <<long double>>.
+
+ o-
+
+ o <[type]>
+
+ <[type]> specifies what kind of conversion <<wprintf>>
+ performs. Here is a table of these:
+
+ o+
+ o %
+ Prints the percent character (<<%>>).
+
+ o c
+ If no <<l>> qualifier is present, the int argument shall
+ be converted to a wide character as if by calling
+ the btowc() function and the resulting wide character
+ shall be written. Otherwise, the wint_t argument
+ shall be converted to wchar_t, and written.
+
+ o C
+ Short for <<%lc>>.
+
+ o s
+ If no <<l>> qualifier is present, the application
+ shall ensure that the argument is a pointer to a
+ character array containing a character sequence
+ beginning in the initial shift state. Characters
+ from the array shall be converted as if by repeated
+ calls to the mbrtowc() function, with the conversion
+ state described by an mbstate_t object initialized to
+ zero before the first character is converted, and
+ written up to (but not including) the terminating
+ null wide character. If the precision is specified,
+ no more than that many wide characters shall be
+ written. If the precision is not specified, or is
+ greater than the size of the array, the application
+ shall ensure that the array contains a null wide
+ character.
+
+ If an <<l>> qualifier is present, the application
+ shall ensure that the argument is a pointer to an
+ array of type wchar_t. Wide characters from the array
+ shall be written up to (but not including) a
+ terminating null wide character. If no precision is
+ specified, or is greater than the size of the array,
+ the application shall ensure that the array contains
+ a null wide character. If a precision is specified,
+ no more than that many wide characters shall be
+ written.
+
+ o S
+ Short for <<%ls>>.
+
+ o d or i
+ Prints a signed decimal integer; takes an
+ <<int>>. Leading zeros are inserted as
+ necessary to reach the precision. A precision
+ of 0 produces an empty string.
+
+ o o
+ Prints an unsigned octal integer; takes an
+ <<unsigned>>. Leading zeros are inserted as
+ necessary to reach the precision. A precision
+ of 0 produces an empty string.
+
+ o u
+ Prints an unsigned decimal integer; takes an
+ <<unsigned>>. Leading zeros are inserted as
+ necessary to reach the precision. A precision
+ of 0 produces an empty string.
+
+ o x
+ Prints an unsigned hexadecimal integer (using
+ <<abcdef>> as digits beyond <<9>>); takes an
+ <<unsigned>>. Leading zeros are inserted as
+ necessary to reach the precision. A precision
+ of 0 produces an empty string.
+
+ o X
+ Like <<x>>, but uses <<ABCDEF>> as digits
+ beyond <<9>>.
+
+ o f
+ Prints a signed value of the form
+ <<[-]9999.9999>>, with the precision
+ determining how many digits follow the decimal
+ point; takes a <<double>> (remember that
+ <<float>> promotes to <<double>> as a vararg).
+ The low order digit is rounded to even. If
+ the precision results in at most DECIMAL_DIG
+ digits, the result is rounded correctly; if
+ more than DECIMAL_DIG digits are printed, the
+ result is only guaranteed to round back to the
+ original value.
+
+ If the value is infinite, the result is
+ <<inf>>, and no zero padding is performed. If
+ the value is not a number, the result is
+ <<nan>>, and no zero padding is performed.
+
+ o F
+ Like <<f>>, but uses <<INF>> and <<NAN>> for
+ non-finite numbers.
+
+ o e
+ Prints a signed value of the form
+ <<[-]9.9999e[+|-]999>>; takes a <<double>>.
+ The digit before the decimal point is non-zero
+ if the value is non-zero. The precision
+ determines how many digits appear between
+ <<.>> and <<e>>, and the exponent always
+ contains at least two digits. The value zero
+ has an exponent of zero. If the value is not
+ finite, it is printed like <<f>>.
+
+ o E
+ Like <<e>>, but using <<E>> to introduce the
+ exponent, and like <<F>> for non-finite
+ values.
+
+ o g
+ Prints a signed value in either <<f>> or <<e>>
+ form, based on the given value and
+ precision---an exponent less than -4 or
+ greater than the precision selects the <<e>>
+ form. Trailing zeros and the decimal point
+ are printed only if necessary; takes a
+ <<double>>.
+
+ o G
+ Like <<g>>, except use <<F>> or <<E>> form.
+
+ o a
+ Prints a signed value of the form
+ <<[-]0x1.ffffp[+|-]9>>; takes a <<double>>.
+ The letters <<abcdef>> are used for digits
+ beyond <<9>>. The precision determines how
+ many digits appear after the decimal point.
+ The exponent contains at least one digit, and
+ is a decimal value representing the power of
+ 2; a value of 0 has an exponent of 0.
+ Non-finite values are printed like <<f>>.
+
+ o A
+ Like <<a>>, except uses <<X>>, <<P>>, and
+ <<ABCDEF>> instead of lower case.
+
+ o n
+ Takes a pointer to <<int>>, and stores a count
+ of the number of bytes written so far. No
+ output is created.
+
+ o p
+ Takes a pointer to <<void>>, and prints it in
+ an implementation-defined format. This
+ implementation is similar to <<%#tx>>), except
+ that <<0x>> appears even for the NULL pointer.
+
+ o-
+ O-
+
+ <<_wprintf_r>>, <<_fwprintf_r>>, <<_swprintf_r>>, are simply
+ reentrant versions of the functions above.
+
+RETURNS
+On success, <<swprintf>> return the number of wide characters in
+the output string, except the concluding <<NUL>> is not counted.
+<<wprintf>> and <<fwprintf>> return the number of characters transmitted.
+
+If an error occurs, the result of <<wprintf>>, <<fwprintf>>, and
+<<swprintf>> is a negative value. For <<wprintf>> and <<fwprintf>>,
+<<errno>> may be set according to <<fputwc>>. For <<snwprintf>>, <<errno>>
+may be set to EOVERFLOW if <[size]> or the output length exceeds
+INT_MAX / sizeof (wchar_t).
+
+PORTABILITY
+POSIX-1.2008
+
+Depending on how newlib was configured, not all format specifiers are
+supported.
+
+Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
+<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
+*/
+
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include "local.h"
+
+int
+_DEFUN(_swprintf_r, (ptr, str, size, fmt),
+ struct _reent *ptr _AND
+ wchar_t *str _AND
+ size_t size _AND
+ _CONST wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+ FILE f;
+
+ if (size > INT_MAX / sizeof (wchar_t))
+ {
+ ptr->_errno = EOVERFLOW;
+ return EOF;
+ }
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *) str;
+ f._bf._size = f._w = (size > 0 ? (size - 1) * sizeof (wchar_t) : 0);
+ f._file = -1; /* No file. */
+ va_start (ap, fmt);
+ ret = _svfwprintf_r (ptr, &f, fmt, ap);
+ va_end (ap);
+ if (ret < EOF)
+ ptr->_errno = EOVERFLOW;
+ if (size > 0)
+ *f._p = 0;
+ return (ret);
+}
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(swprintf, (str, size, fmt),
+ wchar_t *str _AND
+ size_t size _AND
+ _CONST wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+ FILE f;
+ struct _reent *ptr = _REENT;
+
+ if (size > INT_MAX / sizeof (wchar_t))
+ {
+ ptr->_errno = EOVERFLOW;
+ return EOF;
+ }
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *) str;
+ f._bf._size = f._w = (size > 0 ? (size - 1) * sizeof (wchar_t) : 0);
+ f._file = -1; /* No file. */
+ va_start (ap, fmt);
+ ret = _svfwprintf_r (ptr, &f, fmt, ap);
+ va_end (ap);
+ if (ret < EOF)
+ ptr->_errno = EOVERFLOW;
+ if (size > 0)
+ *f._p = 0;
+ return (ret);
+}
+
+#endif
diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c
index ac1d919b8..e81b068ee 100644
--- a/newlib/libc/stdio/vfprintf.c
+++ b/newlib/libc/stdio/vfprintf.c
@@ -177,8 +177,18 @@ static char *rcsid = "$Id$";
#endif
#ifdef STRING_ONLY
-static int
-_DEFUN(__sprint_r, (ptr, fp, uio),
+#define __SPRINT __ssprint_r
+#else
+#define __SPRINT __sprint_r
+#endif
+
+/* The __sprint_r/__ssprint_r functions are shared between all versions of
+ vfprintf and vfwprintf. They must only be defined once, which we do in
+ the INTEGER_ONLY versions here. */
+#ifdef STRING_ONLY
+#ifdef INTEGER_ONLY
+int
+_DEFUN(__ssprint_r, (ptr, fp, uio),
struct _reent *ptr _AND
FILE *fp _AND
register struct __suio *uio)
@@ -268,29 +278,51 @@ err:
uio->uio_iovcnt = 0;
return EOF;
}
+#endif /* INTEGER_ONLY */
#else /* !STRING_ONLY */
+#ifdef INTEGER_ONLY
/*
* Flush out all the vectors defined by the given uio,
* then reset it so that it can be reused.
*/
-static int
+int
_DEFUN(__sprint_r, (ptr, fp, uio),
struct _reent *ptr _AND
FILE *fp _AND
register struct __suio *uio)
{
- register int err;
+ register int err = 0;
if (uio->uio_resid == 0) {
uio->uio_iovcnt = 0;
return (0);
}
- err = __sfvwrite_r(ptr, fp, uio);
+ if (fp->_flags2 & __SWID) {
+ struct __siov *iov;
+ wchar_t *p;
+ int i, len;
+
+ iov = uio->uio_iov;
+ for (; uio->uio_resid != 0;
+ uio->uio_resid -= len * sizeof (wchar_t), iov++) {
+ p = (wchar_t *) iov->iov_base;
+ len = iov->iov_len / sizeof (wchar_t);
+ for (i = 0; i < len; i++) {
+ if (_fputwc_r (ptr, p[i], fp) == WEOF) {
+ err = -1;
+ goto out;
+ }
+ }
+ }
+ } else
+ err = __sfvwrite_r(ptr, fp, uio);
+out:
uio->uio_resid = 0;
uio->uio_iovcnt = 0;
return (err);
}
+#endif /* INTEGER_ONLY */
/*
* Helper function for `fprintf to unbuffered unix file': creates a
@@ -310,6 +342,7 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
/* copy the important variables */
fake._flags = fp->_flags & ~__SNBF;
+ fake._flags2 = fp->_flags2;
fake._file = fp->_file;
fake._cookie = fp->_cookie;
fake._write = fp->_write;
@@ -564,7 +597,7 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
uio.uio_resid += (len); \
iovp++; \
if (++uio.uio_iovcnt >= NIOV) { \
- if (__sprint_r(data, fp, &uio)) \
+ if (__SPRINT(data, fp, &uio)) \
goto error; \
iovp = iov; \
} \
@@ -579,7 +612,7 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
} \
}
#define FLUSH() { \
- if (uio.uio_resid && __sprint_r(data, fp, &uio)) \
+ if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
goto error; \
uio.uio_iovcnt = 0; \
iovp = iov; \
@@ -1642,48 +1675,12 @@ exponent(char *p0, int exp, int fmtch)
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-typedef enum {
- ZERO, /* '0' */
- DIGIT, /* '1-9' */
- DOLLAR, /* '$' */
- MODFR, /* spec modifier */
- SPEC, /* format specifier */
- DOT, /* '.' */
- STAR, /* '*' */
- FLAG, /* format flag */
- OTHER, /* all other chars */
- MAX_CH_CLASS /* place-holder */
-} CH_CLASS;
-
-typedef enum {
- START, /* start */
- SFLAG, /* seen a flag */
- WDIG, /* seen digits in width area */
- WIDTH, /* processed width */
- SMOD, /* seen spec modifier */
- SDOT, /* seen dot */
- VARW, /* have variable width specifier */
- VARP, /* have variable precision specifier */
- PREC, /* processed precision */
- VWDIG, /* have digits in variable width specification */
- VPDIG, /* have digits in variable precision specification */
- DONE, /* done */
- MAX_STATE, /* place-holder */
-} STATE;
-
-typedef enum {
- NOOP, /* do nothing */
- NUMBER, /* build a number from digits */
- SKIPNUM, /* skip over digits */
- GETMOD, /* get and process format modifier */
- GETARG, /* get and process argument */
- GETPW, /* get variable precision or width */
- GETPWB, /* get variable precision or width and pushback fmt char */
- GETPOS, /* get positional parameter value */
- PWPOS, /* get positional parameter value for variable width or precision */
-} ACTION;
-
-_CONST static CH_CLASS chclass[256] = {
+/* The below constant state tables are shared between all versions of
+ vfprintf and vfwprintf. They must only be defined once, which we do in
+ the STRING_ONLY/INTEGER_ONLY versions here. */
+#if defined (STRING_ONLY) && defined(INTEGER_ONLY)
+
+_CONST __CH_CLASS __chclass[256] = {
/* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
@@ -1718,7 +1715,7 @@ _CONST static CH_CLASS chclass[256] = {
/* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
};
-_CONST static STATE state_table[MAX_STATE][MAX_CH_CLASS] = {
+_CONST __STATE __state_table[MAX_STATE][MAX_CH_CLASS] = {
/* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
/* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
/* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
@@ -1733,7 +1730,7 @@ _CONST static STATE state_table[MAX_STATE][MAX_CH_CLASS] = {
/* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE },
};
-_CONST static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = {
+_CONST __ACTION __action_table[MAX_STATE][MAX_CH_CLASS] = {
/* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
/* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
/* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
@@ -1748,6 +1745,8 @@ _CONST static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = {
/* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },
};
+#endif /* STRING_ONLY && INTEGER_ONLY */
+
/* function to get positional parameter N where n = N - 1 */
static union arg_val *
_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
@@ -1764,9 +1763,9 @@ _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
int number, flags;
int spec_type;
int numargs = *numargs_p;
- CH_CLASS chtype;
- STATE state, next_state;
- ACTION action;
+ __CH_CLASS chtype;
+ __STATE state, next_state;
+ __ACTION action;
int pos, last_arg;
int max_pos_arg = n;
/* Only need types that can be reached via vararg promotions. */
@@ -1818,9 +1817,9 @@ _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
while (state != DONE)
{
ch = *fmt++;
- chtype = chclass[ch];
- next_state = state_table[state][chtype];
- action = action_table[state][chtype];
+ chtype = __chclass[ch];
+ next_state = __state_table[state][chtype];
+ action = __action_table[state][chtype];
state = next_state;
switch (action)
diff --git a/newlib/libc/stdio/vfwprintf.c b/newlib/libc/stdio/vfwprintf.c
new file mode 100644
index 000000000..991a2d52f
--- /dev/null
+++ b/newlib/libc/stdio/vfwprintf.c
@@ -0,0 +1,1777 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+FUNCTION
+<<vfwprintf>>, <<vwprintf>>, <<vswprintf>>---wide character format argument list
+
+INDEX
+ vfwprintf
+INDEX
+ _vfwprintf_r
+INDEX
+ vwprintf
+INDEX
+ _vwprintf_r
+INDEX
+ vswprintf
+INDEX
+ _vswprintf_r
+
+ANSI_SYNOPSIS
+ #include <stdio.h>
+ #include <stdarg.h>
+ int vwprintf(const wchar_t *<[fmt]>, va_list <[list]>);
+ int vfwprintf(FILE *<[fp]>, const wchar_t *<[fmt]>, va_list <[list]>);
+ int vswprintf(wchar_t *<[str]>, const wchar_t *<[fmt]>,
+ va_list <[list]>);
+
+ int _vwprintf_r(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
+ va_list <[list]>);
+ int _vfwprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
+ const wchar_t *<[fmt]>, va_list <[list]>);
+ int _vswprintf_r(struct _reent *<[reent]>, wchar_t *<[str]>,
+ const wchar_t *<[fmt]>, va_list <[list]>);
+
+DESCRIPTION
+<<vwprintf>>, <<vfwprintf>> and <<vswprintf>> are (respectively) variants
+of <<wprintf>>, <<fwprintf>> and <<swprintf>>. They differ only in allowing
+their caller to pass the variable argument list as a <<va_list>> object
+(initialized by <<va_start>>) rather than directly accepting a variable
+number of arguments. The caller is responsible for calling <<va_end>>.
+
+<<_vwprintf_r>>, <<_vfwprintf_r>> and <<_vswprintf_r>> are reentrant
+versions of the above.
+
+RETURNS
+The return values are consistent with the corresponding functions.
+
+PORTABILITY
+POSIX-1.2008
+
+Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
+<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
+*/
+
+/*
+ * Actual wprintf innards.
+ *
+ * This code is large and complicated...
+ */
+#include <newlib.h>
+
+#ifdef INTEGER_ONLY
+# define VFWPRINTF vfiwprintf
+# ifdef STRING_ONLY
+# define _VFWPRINTF_R _svfiwprintf_r
+# else
+# define _VFWPRINTF_R _vfiwprintf_r
+# endif
+#else
+# define VFWPRINTF vfwprintf
+# ifdef STRING_ONLY
+# define _VFWPRINTF_R _svfwprintf_r
+# else
+# define _VFWPRINTF_R _vfwprintf_r
+# endif
+# ifndef NO_FLOATING_POINT
+# define FLOATING_POINT
+# endif
+#endif
+
+#define _NO_POS_ARGS
+#ifdef _WANT_IO_POS_ARGS
+# undef _NO_POS_ARGS
+#endif
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <wchar.h>
+#include <sys/lock.h>
+#include <stdarg.h>
+#include "local.h"
+#include "fvwrite.h"
+#include "vfieeefp.h"
+
+/* Currently a test is made to see if long double processing is warranted.
+ This could be changed in the future should the _ldtoa_r code be
+ preferred over _dtoa_r. */
+#define _NO_LONGDBL
+#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+#endif
+
+#define _NO_LONGLONG
+#if defined _WANT_IO_LONG_LONG \
+ && (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
+# undef _NO_LONGLONG
+#endif
+
+int _EXFUN(_VFWPRINTF_R, (struct _reent *, FILE *, _CONST wchar_t *, va_list));
+/* Defined in vfprintf.c. */
+#ifdef STRING_ONLY
+#define __SPRINT __ssprint_r
+#else
+#define __SPRINT __sprint_r
+#endif
+int _EXFUN(__SPRINT, (struct _reent *, FILE *, register struct __suio *));
+
+#ifndef STRING_ONLY
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+_DEFUN(__sbwprintf, (rptr, fp, fmt, ap),
+ struct _reent *rptr _AND
+ register FILE *fp _AND
+ _CONST wchar_t *fmt _AND
+ va_list ap)
+{
+ int ret;
+ FILE fake;
+ unsigned char buf[BUFSIZ];
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._flags2 = fp->_flags2;
+ fake._file = fp->_file;
+ fake._cookie = fp->_cookie;
+ fake._write = fp->_write;
+
+ /* set up the buffer */
+ fake._bf._base = fake._p = buf;
+ fake._bf._size = fake._w = sizeof (buf);
+ fake._lbfsize = 0; /* not actually used, but Just In Case */
+#ifndef __SINGLE_THREAD__
+ __lock_init_recursive (fake._lock);
+#endif
+
+ /* do the work, then copy any error status */
+ ret = _VFWPRINTF_R (rptr, &fake, fmt, ap);
+ if (ret >= 0 && _fflush_r (rptr, &fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+
+#ifndef __SINGLE_THREAD__
+ __lock_close_recursive (fake._lock);
+#endif
+ return (ret);
+}
+#endif /* !STRING_ONLY */
+
+
+#ifdef FLOATING_POINT
+# include <locale.h>
+# include <math.h>
+
+/* For %La, an exponent of 15 bits occupies the exponent character, a
+ sign, and up to 5 digits. */
+# define MAXEXPLEN 7
+# define DEFPREC 6
+
+# ifdef _NO_LONGDBL
+
+extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
+ int, int *, int *, char **));
+
+# define _PRINTF_FLOAT_TYPE double
+# define _DTOA_R _dtoa_r
+# define FREXP frexp
+
+# else /* !_NO_LONGDBL */
+
+extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
+ int, int *, int *, char **));
+
+extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
+
+# define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
+# define _DTOA_R _ldtoa_r
+/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
+ converts a finite value into infinity. */
+/* # define FREXP frexpl */
+# define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
+# endif /* !_NO_LONGDBL */
+
+static wchar_t *wcvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, wchar_t *,
+ int *, int, int *, wchar_t *);
+
+static int wexponent(wchar_t *, int, int);
+
+#endif /* FLOATING_POINT */
+
+/* BUF must be big enough for the maximum %#llo (assuming long long is
+ at most 64 bits, this would be 23 characters), the maximum
+ multibyte character %C, and the maximum default precision of %La
+ (assuming long double is at most 128 bits with 113 bits of
+ mantissa, this would be 29 characters). %e, %f, and %g use
+ reentrant storage shared with mprec. All other formats that use
+ buf get by with fewer characters. Making BUF slightly bigger
+ reduces the need for malloc in %.*a and %S, when large precision or
+ long strings are processed. */
+#define BUF 40
+#if defined _MB_CAPABLE && MB_LEN_MAX > BUF
+# undef BUF
+# define BUF MB_LEN_MAX
+#endif
+
+#ifndef _NO_LONGLONG
+# define quad_t long long
+# define u_quad_t unsigned long long
+#else
+# define quad_t long
+# define u_quad_t unsigned long
+#endif
+
+typedef quad_t * quad_ptr_t;
+typedef _PTR void_ptr_t;
+typedef char * char_ptr_t;
+typedef wchar_t* wchar_ptr_t;
+typedef long * long_ptr_t;
+typedef int * int_ptr_t;
+typedef short * short_ptr_t;
+
+#ifndef _NO_POS_ARGS
+# ifdef NL_ARGMAX
+# define MAX_POS_ARGS NL_ARGMAX
+# else
+# define MAX_POS_ARGS 32
+# endif
+
+union arg_val
+{
+ int val_int;
+ u_int val_u_int;
+ long val_long;
+ u_long val_u_long;
+ float val_float;
+ double val_double;
+ _LONG_DOUBLE val__LONG_DOUBLE;
+ int_ptr_t val_int_ptr_t;
+ short_ptr_t val_short_ptr_t;
+ long_ptr_t val_long_ptr_t;
+ char_ptr_t val_char_ptr_t;
+ wchar_ptr_t val_wchar_ptr_t;
+ quad_ptr_t val_quad_ptr_t;
+ void_ptr_t val_void_ptr_t;
+ quad_t val_quad_t;
+ u_quad_t val_u_quad_t;
+ wint_t val_wint_t;
+};
+
+static union arg_val *
+_EXFUN(get_arg, (struct _reent *data, int n, wchar_t *fmt,
+ va_list *ap, int *numargs, union arg_val *args,
+ int *arg_type, wchar_t **last_fmt));
+#endif /* !_NO_POS_ARGS */
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - L'0')
+#define is_digit(c) ((unsigned)to_digit (c) <= 9)
+#define to_char(n) ((n) + L'0')
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x001 /* alternate form */
+#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGDBL 0x008 /* long double */
+#define LONGINT 0x010 /* long integer */
+#ifndef _NO_LONGLONG
+# define QUADINT 0x020 /* quad integer */
+#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
+ that %lld behaves the same as %ld, not as %d, as expected if:
+ sizeof (long long) = sizeof long > sizeof int */
+# define QUADINT LONGINT
+#endif
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+#ifdef _WANT_IO_C99_FORMATS
+# define CHARINT 0x200 /* char as integer */
+#else /* define as 0, to make SARG and UARG occupy fewer instructions */
+# define CHARINT 0
+#endif
+
+#ifndef STRING_ONLY
+int
+_DEFUN(VFWPRINTF, (fp, fmt0, ap),
+ FILE * fp _AND
+ _CONST wchar_t *fmt0 _AND
+ va_list ap)
+{
+ int result;
+ result = _VFWPRINTF_R (_REENT, fp, fmt0, ap);
+ return result;
+}
+#endif /* STRING_ONLY */
+
+int
+_DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
+ struct _reent *data _AND
+ FILE * fp _AND
+ _CONST wchar_t *fmt0 _AND
+ va_list ap)
+{
+ register wchar_t *fmt; /* format string */
+ register wint_t ch; /* character from fmt */
+ register int n, m; /* handy integers (short term usage) */
+ register wchar_t *cp; /* handy char pointer (short term usage) */
+ register struct __siov *iovp;/* for PRINT macro */
+ register int flags; /* flags as above */
+ wchar_t *fmt_anchor; /* current format spec being processed */
+#ifndef _NO_POS_ARGS
+ int N; /* arg number */
+ int arg_index; /* index into args processed directly */
+ int numargs; /* number of varargs read */
+ wchar_t *saved_fmt; /* saved fmt pointer */
+ union arg_val args[MAX_POS_ARGS];
+ int arg_type[MAX_POS_ARGS];
+ int is_pos_arg; /* is current format positional? */
+ int old_is_pos_arg; /* is current format positional? */
+#endif
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format (%.3d), or -1 */
+ wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
+#ifdef FLOATING_POINT
+ wchar_t decimal_point;
+#ifdef _MB_CAPABLE
+ mbstate_t state; /* mbtowc calls from library must not change state */
+#endif
+ wchar_t softsign; /* temporary negative sign for floats */
+ union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
+# define _fpvalue (_double_.fp)
+ int expt; /* integer value of exponent */
+ int expsize = 0; /* character count for expstr */
+ int ndig = 0; /* actual number of digits returned by wcvt */
+ wchar_t expstr[MAXEXPLEN]; /* buffer for exponent string */
+#endif /* FLOATING_POINT */
+ u_quad_t _uquad; /* integer arguments %[diouxX] */
+ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec */
+ int size = 0; /* size of converted field or string */
+ wchar_t *xdigs = NULL; /* digits for [xX] conversion */
+#define NIOV 8
+ struct __suio uio; /* output information: summary */
+ struct __siov iov[NIOV];/* ... and individual io vectors */
+ wchar_t buf[BUF]; /* space for %c, %S, %[diouxX], %[aA] */
+ wchar_t ox[2]; /* space for 0x hex-prefix */
+ wchar_t *malloc_buf = NULL;/* handy pointer for malloced buffers */
+
+ /*
+ * Choose PADSIZE to trade efficiency vs. size. If larger printf
+ * fields occur frequently, increase PADSIZE and make the initialisers
+ * below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+ static _CONST wchar_t blanks[PADSIZE] =
+ {L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' ',
+ L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' '};
+ static _CONST wchar_t zeroes[PADSIZE] =
+ {L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0',
+ L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0'};
+
+#ifdef FLOATING_POINT
+#ifdef _MB_CAPABLE
+ memset (&state, '\0', sizeof (state));
+ _mbrtowc_r (data, &decimal_point, _localeconv_r (data)->decimal_point,
+ MB_CUR_MAX, &state);
+#else
+ decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point;
+#endif
+#endif
+ /*
+ * BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) { \
+ iovp->iov_base = (char *) (ptr); \
+ iovp->iov_len = (len) * sizeof (wchar_t); \
+ uio.uio_resid += (len) * sizeof (wchar_t); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) { \
+ if (__SPRINT(data, fp, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+}
+#define PAD(howmany, with) { \
+ if ((n = (howmany)) > 0) { \
+ while (n > PADSIZE) { \
+ PRINT (with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT (with, n); \
+ } \
+}
+#define FLUSH() { \
+ if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+}
+
+ /* Macros to support positional arguments */
+#ifndef _NO_POS_ARGS
+# define GET_ARG(n, ap, type) \
+ (is_pos_arg \
+ ? (n < numargs \
+ ? args[n].val_##type \
+ : get_arg (data, n, fmt_anchor, &ap, &numargs, args, \
+ arg_type, &saved_fmt)->val_##type) \
+ : (arg_index++ < numargs \
+ ? args[n].val_##type \
+ : (numargs < MAX_POS_ARGS \
+ ? args[numargs++].val_##type = va_arg (ap, type) \
+ : va_arg (ap, type))))
+#else
+# define GET_ARG(n, ap, type) (va_arg (ap, type))
+#endif
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#ifndef _NO_LONGLONG
+#define SARG() \
+ (flags&QUADINT ? GET_ARG (N, ap, quad_t) : \
+ flags&LONGINT ? GET_ARG (N, ap, long) : \
+ flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
+ flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
+ (long)GET_ARG (N, ap, int))
+#define UARG() \
+ (flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \
+ flags&LONGINT ? GET_ARG (N, ap, u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
+ flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
+ (u_long)GET_ARG (N, ap, u_int))
+#else
+#define SARG() \
+ (flags&LONGINT ? GET_ARG (N, ap, long) : \
+ flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
+ flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
+ (long)GET_ARG (N, ap, int))
+#define UARG() \
+ (flags&LONGINT ? GET_ARG (N, ap, u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
+ flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
+ (u_long)GET_ARG (N, ap, u_int))
+#endif
+
+#ifndef STRING_ONLY
+ /* Initialize std streams if not dealing with sprintf family. */
+ CHECK_INIT (data, fp);
+ _flockfile (fp);
+
+ ORIENT(fp, 1);
+
+ /* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */
+ if (cantwrite (data, fp)) {
+ _funlockfile (fp);
+ return (EOF);
+ }
+
+ /* optimise fwprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0) {
+ _funlockfile (fp);
+ return (__sbwprintf (data, fp, fmt0, ap));
+ }
+#else /* STRING_ONLY */
+ /* Create initial buffer if we are called by asprintf family. */
+ if (fp->_flags & __SMBF && !fp->_bf._base)
+ {
+ fp->_bf._base = fp->_p = _malloc_r (data, 64);
+ if (!fp->_p)
+ {
+ data->_errno = ENOMEM;
+ return EOF;
+ }
+ fp->_bf._size = 64;
+ }
+#endif /* STRING_ONLY */
+
+ fmt = (wchar_t *)fmt0;
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+#ifndef _NO_POS_ARGS
+ arg_index = 0;
+ saved_fmt = NULL;
+ arg_type[0] = -1;
+ numargs = 0;
+ is_pos_arg = 0;
+#endif
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ cp = fmt;
+ while (*fmt != L'\0' && *fmt != L'%')
+ ++fmt;
+ if ((m = fmt - cp) != 0) {
+ PRINT (cp, m);
+ ret += m;
+ }
+ if (*fmt == L'\0')
+ goto done;
+ fmt_anchor = fmt;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = L'\0';
+#ifndef _NO_POS_ARGS
+ N = arg_index;
+ is_pos_arg = 0;
+#endif
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+#ifdef _WANT_IO_C99_FORMATS
+ case L'\'':
+ /* The ' flag is required by POSIX, but not C99.
+ In the C locale, LC_NUMERIC requires
+ thousands_sep to be the empty string. And since
+ no other locales are supported (yet), this flag
+ is currently a no-op. */
+ goto rflag;
+#endif
+ case L' ':
+ /*
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = L' ';
+ goto rflag;
+ case L'#':
+ flags |= ALT;
+ goto rflag;
+ case L'*':
+#ifndef _NO_POS_ARGS
+ /* we must check for positional arg used for dynamic width */
+ n = N;
+ old_is_pos_arg = is_pos_arg;
+ is_pos_arg = 0;
+ if (is_digit (*fmt)) {
+ wchar_t *old_fmt = fmt;
+
+ n = 0;
+ ch = *fmt++;
+ do {
+ n = 10 * n + to_digit (ch);
+ ch = *fmt++;
+ } while (is_digit (ch));
+
+ if (ch == L'$') {
+ if (n <= MAX_POS_ARGS) {
+ n -= 1;
+ is_pos_arg = 1;
+ }
+ else
+ goto error;
+ }
+ else {
+ fmt = old_fmt;
+ goto rflag;
+ }
+ }
+#endif /* !_NO_POS_ARGS */
+
+ /*
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ width = GET_ARG (n, ap, int);
+#ifndef _NO_POS_ARGS
+ is_pos_arg = old_is_pos_arg;
+#endif
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case L'-':
+ flags |= LADJUST;
+ goto rflag;
+ case L'+':
+ sign = L'+';
+ goto rflag;
+ case L'.':
+ if ((ch = *fmt++) == L'*') {
+#ifndef _NO_POS_ARGS
+ /* we must check for positional arg used for dynamic width */
+ n = N;
+ old_is_pos_arg = is_pos_arg;
+ is_pos_arg = 0;
+ if (is_digit (*fmt)) {
+ wchar_t *old_fmt = fmt;
+
+ n = 0;
+ ch = *fmt++;
+ do {
+ n = 10 * n + to_digit (ch);
+ ch = *fmt++;
+ } while (is_digit (ch));
+
+ if (ch == L'$') {
+ if (n <= MAX_POS_ARGS) {
+ n -= 1;
+ is_pos_arg = 1;
+ }
+ else
+ goto error;
+ }
+ else {
+ fmt = old_fmt;
+ goto rflag;
+ }
+ }
+#endif /* !_NO_POS_ARGS */
+ prec = GET_ARG (n, ap, int);
+#ifndef _NO_POS_ARGS
+ is_pos_arg = old_is_pos_arg;
+#endif
+ if (prec < 0)
+ prec = -1;
+ goto rflag;
+ }
+ n = 0;
+ while (is_digit (ch)) {
+ n = 10 * n + to_digit (ch);
+ ch = *fmt++;
+ }
+ prec = n < 0 ? -1 : n;
+ goto reswitch;
+ case L'0':
+ /*
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case L'1': case L'2': case L'3': case L'4':
+ case L'5': case L'6': case L'7': case L'8': case L'9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit (ch);
+ ch = *fmt++;
+ } while (is_digit (ch));
+#ifndef _NO_POS_ARGS
+ if (ch == L'$') {
+ if (n <= MAX_POS_ARGS) {
+ N = n - 1;
+ is_pos_arg = 1;
+ goto rflag;
+ }
+ else
+ goto error;
+ }
+#endif /* !_NO_POS_ARGS */
+ width = n;
+ goto reswitch;
+#ifdef FLOATING_POINT
+ case L'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case L'h':
+#ifdef _WANT_IO_C99_FORMATS
+ if (*fmt == L'h') {
+ fmt++;
+ flags |= CHARINT;
+ } else
+#endif
+ flags |= SHORTINT;
+ goto rflag;
+ case L'l':
+#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
+ if (*fmt == L'l') {
+ fmt++;
+ flags |= QUADINT;
+ } else
+#endif
+ flags |= LONGINT;
+ goto rflag;
+ case L'q': /* extension */
+ flags |= QUADINT;
+ goto rflag;
+#ifdef _WANT_IO_C99_FORMATS
+ case L'j':
+ if (sizeof (intmax_t) == sizeof (long))
+ flags |= LONGINT;
+ else
+ flags |= QUADINT;
+ goto rflag;
+ case L'z':
+ if (sizeof (size_t) < sizeof (int))
+ /* POSIX states size_t is 16 or more bits, as is short. */
+ flags |= SHORTINT;
+ else if (sizeof (size_t) == sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (size_t) <= sizeof (long))
+ flags |= LONGINT;
+ else
+ /* POSIX states that at least one programming
+ environment must support size_t no wider than
+ long, but that means other environments can
+ have size_t as wide as long long. */
+ flags |= QUADINT;
+ goto rflag;
+ case L't':
+ if (sizeof (ptrdiff_t) < sizeof (int))
+ /* POSIX states ptrdiff_t is 16 or more bits, as
+ is short. */
+ flags |= SHORTINT;
+ else if (sizeof (ptrdiff_t) == sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (ptrdiff_t) <= sizeof (long))
+ flags |= LONGINT;
+ else
+ /* POSIX states that at least one programming
+ environment must support ptrdiff_t no wider than
+ long, but that means other environments can
+ have ptrdiff_t as wide as long long. */
+ flags |= QUADINT;
+ goto rflag;
+ case L'C':
+#endif /* _WANT_IO_C99_FORMATS */
+ case L'c':
+ cp = buf;
+ if (ch == L'c' && !(flags & LONGINT)) {
+ wint_t wc = btowc ((int) GET_ARG (N, ap, int));
+ if (wc == WEOF) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ cp[0] = (wchar_t) wc;
+ }
+ else
+ {
+ cp[0] = GET_ARG (N, ap, int);
+ }
+ cp[1] = L'\0';
+ size = 1;
+ sign = L'\0';
+ break;
+ case L'd':
+ case L'i':
+ _uquad = SARG ();
+#ifndef _NO_LONGLONG
+ if ((quad_t)_uquad < 0)
+#else
+ if ((long) _uquad < 0)
+#endif
+ {
+
+ _uquad = -_uquad;
+ sign = L'-';
+ }
+ base = DEC;
+ goto number;
+#ifdef FLOATING_POINT
+# ifdef _WANT_IO_C99_FORMATS
+ case L'a':
+ case L'A':
+ case L'F':
+# endif
+ case L'e':
+ case L'E':
+ case L'f':
+ case L'g':
+ case L'G':
+# ifdef _NO_LONGDBL
+ if (flags & LONGDBL) {
+ _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
+ } else {
+ _fpvalue = GET_ARG (N, ap, double);
+ }
+
+ /* do this before tricky precision changes
+
+ If the output is infinite or NaN, leading
+ zeros are not permitted. Otherwise, scanf
+ could not read what printf wrote.
+ */
+ if (isinf (_fpvalue)) {
+ if (_fpvalue < 0)
+ sign = '-';
+ if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
+ cp = L"INF";
+ else
+ cp = L"inf";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+ if (isnan (_fpvalue)) {
+ if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
+ cp = L"NAN";
+ else
+ cp = L"nan";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+
+# else /* !_NO_LONGDBL */
+
+ if (flags & LONGDBL) {
+ _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
+ } else {
+ _fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double);
+ }
+
+ /* do this before tricky precision changes */
+ expt = _ldcheck (&_fpvalue);
+ if (expt == 2) {
+ if (_fpvalue < 0)
+ sign = L'-';
+ if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
+ cp = L"INF";
+ else
+ cp = L"inf";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+ if (expt == 1) {
+ if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
+ cp = L"NAN";
+ else
+ cp = L"nan";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+# endif /* !_NO_LONGDBL */
+
+ cp = buf;
+# ifdef _WANT_IO_C99_FORMATS
+ if (ch == L'a' || ch == L'A') {
+ ox[0] = L'0';
+ ox[1] = ch == L'a' ? L'x' : L'X';
+ flags |= HEXPREFIX;
+ if (prec >= BUF)
+ {
+ if ((malloc_buf =
+ (wchar_t *)_malloc_r (data, (prec + 1) * sizeof (wchar_t)))
+ == NULL)
+ {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ cp = malloc_buf;
+ }
+ } else
+# endif /* _WANT_IO_C99_FORMATS */
+ if (prec == -1) {
+ prec = DEFPREC;
+ } else if ((ch == L'g' || ch == L'G') && prec == 0) {
+ prec = 1;
+ }
+
+ flags |= FPT;
+
+ cp = wcvt (data, _fpvalue, prec, flags, &softsign,
+ &expt, ch, &ndig, cp);
+
+ if (ch == L'g' || ch == L'G') {
+ if (expt <= -4 || expt > prec)
+ ch -= 2; /* 'e' or 'E' */
+ else
+ ch = L'g';
+ }
+# ifdef _WANT_IO_C99_FORMATS
+ else if (ch == L'F')
+ ch = L'f';
+# endif
+ if (ch <= L'e') { /* 'a', 'A', 'e', or 'E' fmt */
+ --expt;
+ expsize = wexponent (expstr, expt, ch);
+ size = expsize + ndig;
+ if (ndig > 1 || flags & ALT)
+ ++size;
+ } else if (ch == L'f') { /* f fmt */
+ if (expt > 0) {
+ size = expt;
+ if (prec || flags & ALT)
+ size += prec + 1;
+ } else /* "0.X" */
+ size = (prec || flags & ALT)
+ ? prec + 2
+ : 1;
+ } else if (expt >= ndig) { /* fixed g fmt */
+ size = expt;
+ if (flags & ALT)
+ ++size;
+ } else
+ size = ndig + (expt > 0 ?
+ 1 : 2 - expt);
+
+ if (softsign)
+ sign = L'-';
+ break;
+#endif /* FLOATING_POINT */
+ case L'n':
+#ifndef _NO_LONGLONG
+ if (flags & QUADINT)
+ *GET_ARG (N, ap, quad_ptr_t) = ret;
+ else
+#endif
+ if (flags & LONGINT)
+ *GET_ARG (N, ap, long_ptr_t) = ret;
+ else if (flags & SHORTINT)
+ *GET_ARG (N, ap, short_ptr_t) = ret;
+#ifdef _WANT_IO_C99_FORMATS
+ else if (flags & CHARINT)
+ *GET_ARG (N, ap, char_ptr_t) = ret;
+#endif
+ else
+ *GET_ARG (N, ap, int_ptr_t) = ret;
+ continue; /* no output */
+ case L'o':
+ _uquad = UARG ();
+ base = OCT;
+ goto nosign;
+ case L'p':
+ /*
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ /* NOSTRICT */
+ _uquad = (uintptr_t) GET_ARG (N, ap, void_ptr_t);
+ base = HEX;
+ xdigs = L"0123456789abcdef";
+ flags |= HEXPREFIX;
+ ox[0] = L'0';
+ ox[1] = ch = L'x';
+ goto nosign;
+ case L's':
+#ifdef _WANT_IO_C99_FORMATS
+ case L'S':
+#endif
+ sign = '\0';
+ cp = GET_ARG (N, ap, wchar_ptr_t);
+#ifndef __OPTIMIZE_SIZE__
+ /* Behavior is undefined if the user passed a
+ NULL string when precision is not 0.
+ However, if we are not optimizing for size,
+ we might as well mirror glibc behavior. */
+ if (cp == NULL) {
+ cp = L"(null)";
+ size = ((unsigned) prec > 6U) ? 6 : prec;
+ }
+ else
+#endif /* __OPTIMIZE_SIZE__ */
+#ifdef _MB_CAPABLE
+ if (ch == L's' && !(flags & LONGINT)) {
+ char *arg = (char *) cp;
+ size_t insize = 0, nchars = 0, nconv = 0;
+ mbstate_t ps;
+ wchar_t *p;
+
+ if (prec >= 0) {
+ char *p = arg;
+ memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
+ while (nchars < (size_t)prec) {
+ nconv = mbrlen (p, MB_CUR_MAX, &ps);
+ if (nconv == 0 || nconv == (size_t)-1 ||
+ nconv == (size_t)-2)
+ break;
+ p += nconv;
+ ++nchars;
+ insize += nconv;
+ }
+ if (nconv == (size_t) -1 || nconv == (size_t) -2) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ } else
+ insize = strlen(arg);
+ if (insize >= BUF) {
+ if ((malloc_buf = (wchar_t *) _malloc_r (data, (insize + 1) * sizeof (wchar_t)))
+ == NULL) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ cp = malloc_buf;
+ } else
+ cp = buf;
+ memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
+ p = cp;
+ while (insize != 0) {
+ nconv = _mbrtowc_r (data, p, arg, insize, &ps);
+ if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
+ break;
+ ++p;
+ arg += nconv;
+ insize -= nconv;
+ }
+ if (nconv == (size_t) -1 || nconv == (size_t) -2) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ *p = L'\0';
+ size = p - cp;
+ }
+ else
+#endif /* _MB_CAPABLE */
+ if (prec >= 0) {
+ /*
+ * can't use wcslen; can only look for the
+ * NUL in the first `prec' characters, and
+ * strlen () will go further.
+ */
+ wchar_t *p = wmemchr (cp, L'\0', prec);
+
+ if (p != NULL) {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ } else
+ size = prec;
+ } else
+ size = wcslen (cp);
+
+ break;
+ case L'u':
+ _uquad = UARG ();
+ base = DEC;
+ goto nosign;
+ case L'X':
+ xdigs = L"0123456789ABCDEF";
+ goto hex;
+ case 'x':
+ xdigs = L"0123456789abcdef";
+hex: _uquad = UARG ();
+ base = HEX;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT && _uquad != 0) {
+ ox[0] = L'0';
+ ox[1] = ch;
+ flags |= HEXPREFIX;
+ }
+
+ /* unsigned conversions */
+nosign: sign = L'\0';
+ /*
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ */
+ cp = buf + BUF;
+ if (_uquad != 0 || prec != 0) {
+ /*
+ * Unsigned mod is hard, and unsigned mod
+ * by a constant is easier than that by
+ * a variable; hence this switch.
+ */
+ switch (base) {
+ case OCT:
+ do {
+ *--cp = to_char (_uquad & 7);
+ _uquad >>= 3;
+ } while (_uquad);
+ /* handle octal leading 0 */
+ if (flags & ALT && *cp != L'0')
+ *--cp = L'0';
+ break;
+
+ case DEC:
+ /* many numbers are 1 digit */
+ while (_uquad >= 10) {
+ *--cp = to_char (_uquad % 10);
+ _uquad /= 10;
+ }
+ *--cp = to_char (_uquad);
+ break;
+
+ case HEX:
+ do {
+ *--cp = xdigs[_uquad & 15];
+ _uquad >>= 4;
+ } while (_uquad);
+ break;
+
+ default:
+ cp = L"bug in vfprintf: bad base";
+ size = wcslen (cp);
+ goto skipsize;
+ }
+ }
+ /*
+ * ...result is to be converted to an 'alternate form'.
+ * For o conversion, it increases the precision to force
+ * the first digit of the result to be a zero."
+ * -- ANSI X3J11
+ *
+ * To demonstrate this case, compile and run:
+ * printf ("%#.0o",0);
+ */
+ else if (base == OCT && (flags & ALT))
+ *--cp = L'0';
+
+ size = buf + BUF - cp;
+ skipsize:
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == L'\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = L'\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ * If flags&FPT, ch must be in [aAeEfg].
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (flags & HEXPREFIX)
+ realsz+= 2;
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD (width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ PRINT (&sign, 1);
+ if (flags & HEXPREFIX)
+ PRINT (ox, 2);
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD (width - realsz, zeroes);
+
+ /* leading zeroes from decimal precision */
+ PAD (dprec - size, zeroes);
+
+ /* the string or number proper */
+#ifdef FLOATING_POINT
+ if ((flags & FPT) == 0) {
+ PRINT (cp, size);
+ } else { /* glue together f_p fragments */
+ if (ch >= L'f') { /* 'f' or 'g' */
+ if (_fpvalue == 0) {
+ /* kludge for __dtoa irregularity */
+ PRINT (L"0", 1);
+ if (expt < ndig || flags & ALT) {
+ PRINT (&decimal_point, 1);
+ PAD (ndig - 1, zeroes);
+ }
+ } else if (expt <= 0) {
+ PRINT (L"0", 1);
+ if (expt || ndig || flags & ALT) {
+ PRINT (&decimal_point, 1);
+ PAD (-expt, zeroes);
+ PRINT (cp, ndig);
+ }
+ } else if (expt >= ndig) {
+ PRINT (cp, ndig);
+ PAD (expt - ndig, zeroes);
+ if (flags & ALT)
+ PRINT (&decimal_point, 1);
+ } else {
+ PRINT (cp, expt);
+ cp += expt;
+ PRINT (&decimal_point, 1);
+ PRINT (cp, ndig - expt);
+ }
+ } else { /* 'a', 'A', 'e', or 'E' */
+ if (ndig > 1 || flags & ALT) {
+ PRINT (cp, 1);
+ cp++;
+ PRINT (&decimal_point, 1);
+ if (_fpvalue) {
+ PRINT (cp, ndig - 1);
+ } else /* 0.[0..] */
+ /* __dtoa irregularity */
+ PAD (ndig - 1, zeroes);
+ } else /* XeYYY */
+ PRINT (cp, 1);
+ PRINT (expstr, expsize);
+ }
+ }
+#else /* !FLOATING_POINT */
+ PRINT (cp, size);
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD (width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += width > realsz ? width : realsz;
+
+ FLUSH (); /* copy out the I/O vectors */
+
+ if (malloc_buf != NULL) {
+ _free_r (data, malloc_buf);
+ malloc_buf = NULL;
+ }
+ }
+done:
+ FLUSH ();
+error:
+ if (malloc_buf != NULL)
+ _free_r (data, malloc_buf);
+#ifndef STRING_ONLY
+ _funlockfile (fp);
+#endif
+ return (__sferror (fp) ? EOF : ret);
+ /* NOTREACHED */
+}
+
+#ifdef FLOATING_POINT
+
+/* Using reentrant DATA, convert finite VALUE into a string of digits
+ with no decimal point, using NDIGITS precision and FLAGS as guides
+ to whether trailing zeros must be included. Set *SIGN to nonzero
+ if VALUE was negative. Set *DECPT to the exponent plus one. Set
+ *LENGTH to the length of the returned string. CH must be one of
+ [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
+ otherwise the return value shares the mprec reentrant storage. */
+static wchar_t *
+wcvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
+ wchar_t *sign, int *decpt, int ch, int *length, wchar_t *buf)
+{
+ int mode, dsgn;
+# ifdef _NO_LONGDBL
+ union double_union tmp;
+
+ tmp.d = value;
+ if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
+ value = -value;
+ *sign = L'-';
+ } else
+ *sign = L'\0';
+# else /* !_NO_LONGDBL */
+ union
+ {
+ struct ldieee ieee;
+ _LONG_DOUBLE val;
+ } ld;
+
+ ld.val = value;
+ if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
+ value = -value;
+ *sign = L'-';
+ } else
+ *sign = L'\0';
+# endif /* !_NO_LONGDBL */
+
+# ifdef _WANT_IO_C99_FORMATS
+ if (ch == L'a' || ch == L'A') {
+ wchar_t *digits, *bp, *rve;
+ /* This code assumes FLT_RADIX is a power of 2. The initial
+ division ensures the digit before the decimal will be less
+ than FLT_RADIX (unless it is rounded later). There is no
+ loss of precision in these calculations. */
+ value = FREXP (value, decpt) / 8;
+ if (!value)
+ *decpt = 1;
+ digits = ch == L'a' ? L"0123456789abcdef" : L"0123456789ABCDEF";
+ bp = buf;
+ do {
+ value *= 16;
+ mode = (int) value;
+ value -= mode;
+ *bp++ = digits[mode];
+ } while (ndigits-- && value);
+ if (value > 0.5 || (value == 0.5 && mode & 1)) {
+ /* round to even */
+ rve = bp;
+ while (*--rve == digits[0xf]) {
+ *rve = L'0';
+ }
+ *rve = *rve == L'9' ? digits[0xa] : *rve + 1;
+ } else {
+ while (ndigits-- >= 0) {
+ *bp++ = L'0';
+ }
+ }
+ *length = bp - buf;
+ return buf;
+ }
+# endif /* _WANT_IO_C99_FORMATS */
+ if (ch == L'f' || ch == L'F') {
+ mode = 3; /* ndigits after the decimal point */
+ } else {
+ /* To obtain ndigits after the decimal point for the 'e'
+ * and 'E' formats, round to ndigits + 1 significant
+ * figures.
+ */
+ if (ch == L'e' || ch == L'E') {
+ ndigits++;
+ }
+ mode = 2; /* ndigits significant digits */
+ }
+
+ {
+ char *digits, *bp, *rve;
+#ifndef _MB_CAPABLE
+ int i;
+#endif
+
+ digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
+
+ if ((ch != L'g' && ch != L'G') || flags & ALT) { /* Print trailing zeros */
+ bp = digits + ndigits;
+ if (ch == L'f' || ch == L'F') {
+ if (*digits == L'0' && value)
+ *decpt = -ndigits + 1;
+ bp += *decpt;
+ }
+ if (value == 0) /* kludge for __dtoa irregularity */
+ rve = bp;
+ while (rve < bp)
+ *rve++ = '0';
+ }
+#ifdef _MB_CAPABLE
+ *length = _mbsnrtowcs_r (data, buf, (const char **) &digits,
+ rve - digits, BUF, NULL);
+#else
+ *length = rve - digits;
+ for (i = 0; i < *length && i < BUF; ++i)
+ buf[i] = (wchar_t) digits[i];
+#endif
+ return buf;
+ }
+}
+
+static int
+wexponent(wchar_t *p0, int exp, int fmtch)
+{
+ register wchar_t *p, *t;
+ wchar_t expbuf[MAXEXPLEN];
+# ifdef _WANT_IO_C99_FORMATS
+ int isa = fmtch == L'a' || fmtch == L'A';
+# else
+# define isa 0
+# endif
+
+ p = p0;
+ *p++ = isa ? L'p' - L'a' + fmtch : fmtch;
+ if (exp < 0) {
+ exp = -exp;
+ *p++ = L'-';
+ }
+ else
+ *p++ = L'+';
+ t = expbuf + MAXEXPLEN;
+ if (exp > 9) {
+ do {
+ *--t = to_char (exp % 10);
+ } while ((exp /= 10) > 9);
+ *--t = to_char (exp);
+ for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
+ }
+ else {
+ if (!isa)
+ *p++ = L'0';
+ *p++ = to_char (exp);
+ }
+ return (p - p0);
+}
+#endif /* FLOATING_POINT */
+
+
+#ifndef _NO_POS_ARGS
+
+/* Positional argument support.
+ Written by Jeff Johnston
+
+ Copyright (c) 2002 Red Hat Incorporated.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ The name of Red Hat Incorporated may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* function to get positional parameter N where n = N - 1 */
+static union arg_val *
+_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
+ struct _reent *data _AND
+ int n _AND
+ wchar_t *fmt _AND
+ va_list *ap _AND
+ int *numargs_p _AND
+ union arg_val *args _AND
+ int *arg_type _AND
+ wchar_t **last_fmt)
+{
+ wchar_t ch;
+ int number, flags;
+ int spec_type;
+ int numargs = *numargs_p;
+ __CH_CLASS chtype;
+ __STATE state, next_state;
+ __ACTION action;
+ int pos, last_arg;
+ int max_pos_arg = n;
+ /* Only need types that can be reached via vararg promotions. */
+ enum types { INT, LONG_INT, QUAD_INT, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
+
+ /* if this isn't the first call, pick up where we left off last time */
+ if (*last_fmt != NULL)
+ fmt = *last_fmt;
+
+ /* we need to process either to end of fmt string or until we have actually
+ read the desired parameter from the vararg list. */
+ while (*fmt && n >= numargs)
+ {
+ while (*fmt != L'\0' && *fmt != L'%')
+ fmt += 1;
+
+ if (*fmt == L'\0')
+ break;
+ state = START;
+ flags = 0;
+ pos = -1;
+ number = 0;
+ spec_type = INT;
+
+ /* Use state/action table to process format specifiers. We ignore invalid
+ formats and we are only interested in information that tells us how to
+ read the vararg list. */
+ while (state != DONE)
+ {
+ ch = *fmt++;
+ chtype = ch < (wchar_t) 256 ? __chclass[ch] : OTHER;
+ next_state = __state_table[state][chtype];
+ action = __action_table[state][chtype];
+ state = next_state;
+
+ switch (action)
+ {
+ case GETMOD: /* we have format modifier */
+ switch (ch)
+ {
+ case L'h':
+ /* No flag needed, since short and char promote to int. */
+ break;
+ case L'L':
+ flags |= LONGDBL;
+ break;
+ case L'q':
+ flags |= QUADINT;
+ break;
+# ifdef _WANT_IO_C99_FORMATS
+ case L'j':
+ if (sizeof (intmax_t) == sizeof (long))
+ flags |= LONGINT;
+ else
+ flags |= QUADINT;
+ break;
+ case L'z':
+ if (sizeof (size_t) <= sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (size_t) <= sizeof (long))
+ flags |= LONGINT;
+ else
+ /* POSIX states that at least one programming
+ environment must support size_t no wider than
+ long, but that means other environments can
+ have size_t as wide as long long. */
+ flags |= QUADINT;
+ break;
+ case L't':
+ if (sizeof (ptrdiff_t) <= sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (ptrdiff_t) <= sizeof (long))
+ flags |= LONGINT;
+ else
+ /* POSIX states that at least one programming
+ environment must support ptrdiff_t no wider than
+ long, but that means other environments can
+ have ptrdiff_t as wide as long long. */
+ flags |= QUADINT;
+ break;
+# endif /* _WANT_IO_C99_FORMATS */
+ case L'l':
+ default:
+# if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
+ if (*fmt == L'l')
+ {
+ flags |= QUADINT;
+ ++fmt;
+ }
+ else
+# endif
+ flags |= LONGINT;
+ break;
+ }
+ break;
+ case GETARG: /* we have format specifier */
+ {
+ numargs &= (MAX_POS_ARGS - 1);
+ /* process the specifier and translate it to a type to fetch from varargs */
+ switch (ch)
+ {
+ case L'd':
+ case L'i':
+ case L'o':
+ case L'x':
+ case L'X':
+ case L'u':
+ if (flags & LONGINT)
+ spec_type = LONG_INT;
+# ifndef _NO_LONGLONG
+ else if (flags & QUADINT)
+ spec_type = QUAD_INT;
+# endif
+ else
+ spec_type = INT;
+ break;
+# ifdef _WANT_IO_C99_FORMATS
+ case L'a':
+ case L'A':
+ case L'F':
+# endif
+ case L'f':
+ case L'g':
+ case L'G':
+ case L'E':
+ case L'e':
+# ifndef _NO_LONGDBL
+ if (flags & LONGDBL)
+ spec_type = LONG_DOUBLE;
+ else
+# endif
+ spec_type = DOUBLE;
+ break;
+ case L's':
+# ifdef _WANT_IO_C99_FORMATS
+ case L'S':
+# endif
+ case L'p':
+ case L'n':
+ spec_type = CHAR_PTR;
+ break;
+ case L'c':
+# ifdef _WANT_IO_C99_FORMATS
+ if (flags & LONGINT)
+ spec_type = WIDE_CHAR;
+ else
+# endif
+ spec_type = INT;
+ break;
+# ifdef _WANT_IO_C99_FORMATS
+ case L'C':
+ spec_type = WIDE_CHAR;
+ break;
+# endif
+ }
+
+ /* if we have a positional parameter, just store the type, otherwise
+ fetch the parameter from the vararg list */
+ if (pos != -1)
+ arg_type[pos] = spec_type;
+ else
+ {
+ switch (spec_type)
+ {
+ case LONG_INT:
+ args[numargs++].val_long = va_arg (*ap, long);
+ break;
+ case QUAD_INT:
+ args[numargs++].val_quad_t = va_arg (*ap, quad_t);
+ break;
+ case WIDE_CHAR:
+ args[numargs++].val_wint_t = va_arg (*ap, wint_t);
+ break;
+ case INT:
+ args[numargs++].val_int = va_arg (*ap, int);
+ break;
+ case CHAR_PTR:
+ args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
+ break;
+ case DOUBLE:
+ args[numargs++].val_double = va_arg (*ap, double);
+ break;
+ case LONG_DOUBLE:
+ args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
+ break;
+ }
+ }
+ }
+ break;
+ case GETPOS: /* we have positional specifier */
+ if (arg_type[0] == -1)
+ memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
+ pos = number - 1;
+ max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
+ break;
+ case PWPOS: /* we have positional specifier for width or precision */
+ if (arg_type[0] == -1)
+ memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
+ number -= 1;
+ arg_type[number] = INT;
+ max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
+ break;
+ case GETPWB: /* we require format pushback */
+ --fmt;
+ /* fallthrough */
+ case GETPW: /* we have a variable precision or width to acquire */
+ args[numargs++].val_int = va_arg (*ap, int);
+ break;
+ case NUMBER: /* we have a number to process */
+ number = (ch - '0');
+ while ((ch = *fmt) != '\0' && is_digit (ch))
+ {
+ number = number * 10 + (ch - '0');
+ ++fmt;
+ }
+ break;
+ case SKIPNUM: /* we have a number to skip */
+ while ((ch = *fmt) != '\0' && is_digit (ch))
+ ++fmt;
+ break;
+ case NOOP:
+ default:
+ break; /* do nothing */
+ }
+ }
+ }
+
+ /* process all arguments up to at least the one we are looking for and if we
+ have seen the end of the string, then process up to the max argument needed */
+ if (*fmt == '\0')
+ last_arg = max_pos_arg;
+ else
+ last_arg = n;
+
+ while (numargs <= last_arg)
+ {
+ switch (arg_type[numargs])
+ {
+ case LONG_INT:
+ args[numargs++].val_long = va_arg (*ap, long);
+ break;
+ case QUAD_INT:
+ args[numargs++].val_quad_t = va_arg (*ap, quad_t);
+ break;
+ case CHAR_PTR:
+ args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
+ break;
+ case DOUBLE:
+ args[numargs++].val_double = va_arg (*ap, double);
+ break;
+ case LONG_DOUBLE:
+ args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
+ break;
+ case WIDE_CHAR:
+ args[numargs++].val_wint_t = va_arg (*ap, wint_t);
+ break;
+ case INT:
+ default:
+ args[numargs++].val_int = va_arg (*ap, int);
+ break;
+ }
+ }
+
+ /* alter the global numargs value and keep a reference to the last bit of the fmt
+ string we processed here because the caller will continue processing where we started */
+ *numargs_p = numargs;
+ *last_fmt = fmt;
+ return &args[n];
+}
+#endif /* !_NO_POS_ARGS */
diff --git a/newlib/libc/stdio/vswprintf.c b/newlib/libc/stdio/vswprintf.c
new file mode 100644
index 000000000..5c70f1b92
--- /dev/null
+++ b/newlib/libc/stdio/vswprintf.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* doc in vfwprintf.c */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "%W% (Berkeley) %G%";
+#endif /* LIBC_SCCS and not lint */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <errno.h>
+
+int
+_DEFUN(_vswprintf_r, (ptr, str, size, fmt, ap),
+ struct _reent *ptr _AND
+ wchar_t *str _AND
+ size_t size _AND
+ const wchar_t *fmt _AND
+ va_list ap)
+{
+ int ret;
+ FILE f;
+
+ if (size > INT_MAX / sizeof (wchar_t))
+ {
+ ptr->_errno = EOVERFLOW;
+ return EOF;
+ }
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *) str;
+ f._bf._size = f._w = (size > 0 ? (size - 1) * sizeof (wchar_t) : 0);
+ f._file = -1; /* No file. */
+ ret = _svfwprintf_r (ptr, &f, fmt, ap);
+ if (ret < EOF)
+ ptr->_errno = EOVERFLOW;
+ if (size > 0)
+ *f._p = 0;
+ return ret;
+}
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(vswprintf, (str, size, fmt, ap),
+ wchar_t *str _AND
+ size_t size _AND
+ const wchar_t *fmt _AND
+ va_list ap)
+{
+ return _vswprintf_r (_REENT, str, size, fmt, ap);
+}
+
+#endif /* !_REENT_ONLY */
diff --git a/newlib/libc/stdio/vwprintf.c b/newlib/libc/stdio/vwprintf.c
new file mode 100644
index 000000000..ce28fdabb
--- /dev/null
+++ b/newlib/libc/stdio/vwprintf.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* doc in vfwprintf.c */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include "local.h"
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(vwprintf, (fmt, ap),
+ _CONST wchar_t *fmt _AND
+ va_list ap)
+{
+ _REENT_SMALL_CHECK_INIT (_REENT);
+ return _vfwprintf_r (_REENT, _stdout_r (_REENT), fmt, ap);
+}
+
+#endif /* !_REENT_ONLY */
+
+int
+_DEFUN(_vwprintf_r, (ptr, fmt, ap),
+ struct _reent *ptr _AND
+ _CONST wchar_t *fmt _AND
+ va_list ap)
+{
+ _REENT_SMALL_CHECK_INIT (ptr);
+ return _vfwprintf_r (ptr, _stdout_r (ptr), fmt, ap);
+}
diff --git a/newlib/libc/stdio/wprintf.c b/newlib/libc/stdio/wprintf.c
new file mode 100644
index 000000000..69dea53c6
--- /dev/null
+++ b/newlib/libc/stdio/wprintf.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* doc in swprintf.c */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include "local.h"
+
+int
+_DEFUN(_wprintf_r, (ptr, fmt),
+ struct _reent *ptr _AND
+ const wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+
+ _REENT_SMALL_CHECK_INIT (ptr);
+ va_start (ap, fmt);
+ ret = _vfwprintf_r (ptr, _stdout_r (ptr), fmt, ap);
+ va_end (ap);
+ return ret;
+}
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(wprintf, (fmt),
+ const wchar_t *fmt _DOTS)
+{
+ int ret;
+ va_list ap;
+ struct _reent *ptr = _REENT;
+
+ _REENT_SMALL_CHECK_INIT (ptr);
+ va_start (ap, fmt);
+ ret = _vfwprintf_r (ptr, _stdout_r (ptr), fmt, ap);
+ va_end (ap);
+ return ret;
+}
+
+#endif /* ! _REENT_ONLY */