OSDN Git Service

* libc/include/stdio.h (__VALIST): Guard against multiple definition.
authorcorinna <corinna>
Fri, 6 Mar 2009 09:55:52 +0000 (09:55 +0000)
committercorinna <corinna>
Fri, 6 Mar 2009 09:55:52 +0000 (09:55 +0000)
* 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.

14 files changed:
newlib/ChangeLog
newlib/libc/include/stdio.h
newlib/libc/include/wchar.h
newlib/libc/stdio/Makefile.am
newlib/libc/stdio/Makefile.in
newlib/libc/stdio/fwprintf.c [new file with mode: 0644]
newlib/libc/stdio/local.h
newlib/libc/stdio/stdio.tex
newlib/libc/stdio/swprintf.c [new file with mode: 0644]
newlib/libc/stdio/vfprintf.c
newlib/libc/stdio/vfwprintf.c [new file with mode: 0644]
newlib/libc/stdio/vswprintf.c [new file with mode: 0644]
newlib/libc/stdio/vwprintf.c [new file with mode: 0644]
newlib/libc/stdio/wprintf.c [new file with mode: 0644]

index 3e40182..7c8a640 100644 (file)
@@ -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
index a55dd69..fd58a25 100644 (file)
@@ -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 *));
index ad905e2..37529a9 100644 (file)
@@ -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
index c7111e2..23840bc 100644 (file)
@@ -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
index 7beaa0a..a40e8af 100644 (file)
@@ -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 (file)
index 0000000..76065e9
--- /dev/null
@@ -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 */
index 29e7cc6..1e1e042 100644 (file)
@@ -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];
index f2a7cfc..b3a69fc 100644 (file)
@@ -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 (file)
index 0000000..0d0e4d9
--- /dev/null
@@ -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
index ac1d919..e81b068 100644 (file)
@@ -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 (file)
index 0000000..991a2d5
--- /dev/null
@@ -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 (file)
index 0000000..5c70f1b
--- /dev/null
@@ -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 (file)
index 0000000..ce28fda
--- /dev/null
@@ -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 (file)
index 0000000..69dea53
--- /dev/null
@@ -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 */