This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


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

[PATCH] New functions wprintf, fwprintf, swprintf, vwprintf, vfwprintf, vswprintf


Hi,

attached inline is a patch which adds the wprintf family of functions
according to the POSIX-1.2008 definition.

Basically the functions are copied from their non-w counterparts.
However, there's one big change.  So far there were multiple versions of
the __sprint_r functions defined.  Since these functions can be shared
between all versions of vfprintf/vfwprintf, and since especially the
STRING_ONLY variant of these functions is not that small, I made an
additional effort to have only one __sprint_r function and only one
__ssprint_r function, the latter being the STRING_ONLY version.  Using
different names was necessary because the functions are naturally not
static anymore.

The handling of the s, ls, c, lc format specifier follows exactly the
POSIX-1.2008 definition.

Of course I tested this new functionality on Cygwin.  Having said that,
I would very much appreciate if other people on this list would give
this functionality some additional testing.  printf is such a complex
function, I could hardly test it all.

wscanf anybody?


Corinna


	* libc/include/stdio.h (__VALIST): Guard against multiple definition.
	* libc/include/wchar.h: Include stdarg.h.
	(__VALIST): Define conditionally.
	(fwprintf): Declare.
	(swprintf): Declare.
	(vfwprintf): Declare.
	(vswprintf): Declare.
	(vwprintf): Declare.
	(wprintf): Declare.
	(_fwprintf_r): Declare.
	(_swprintf_r): Declare.
	(_vfwprintf_r): Declare.
	(_vswprintf_r): Declare.
	(_vwprintf_r): Declare.
	(_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): Declare.
	(_svfiwprintf_r): 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.
	* libc/stdio/vfwprintf.c: New file.
	* libc/stdio/vswprintf.c: New file.
	* libc/stdio/vwprintf.c: New file.
	* libc/stdio/wprintf.c: New file.


Index: libc/include/stdio.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/stdio.h,v
retrieving revision 1.53
diff -u -p -r1.53 stdio.h
--- libc/include/stdio.h	11 Dec 2008 17:27:55 -0000	1.53
+++ libc/include/stdio.h	5 Mar 2009 18:01:19 -0000
@@ -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: libc/include/wchar.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/wchar.h,v
retrieving revision 1.22
diff -u -p -r1.22 wchar.h
--- libc/include/wchar.h	19 Feb 2009 09:19:40 -0000	1.22
+++ libc/include/wchar.h	5 Mar 2009 18:01:19 -0000
@@ -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 _reen
 __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: libc/stdio/Makefile.am
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/Makefile.am,v
retrieving revision 1.29
diff -u -p -r1.29 Makefile.am
--- libc/stdio/Makefile.am	10 Dec 2008 23:43:12 -0000	1.29
+++ libc/stdio/Makefile.am	5 Mar 2009 18:01:19 -0000
@@ -132,7 +132,12 @@ ELIX_4_SOURCES = \
 	putwchar.c		\
 	ungetwc.c		\
 	vasniprintf.c		\
-	vasnprintf.c
+	vasnprintf.c		\
+	vwprintf.c		\
+	swprintf.c		\
+	vswprintf.c		\
+	wprintf.c		\
+	fwprintf.c
 endif !ELIX_LEVEL_3
 endif !ELIX_LEVEL_2
 endif !ELIX_LEVEL_1
@@ -141,7 +146,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 +186,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 +273,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 +319,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 +334,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: libc/stdio/fwprintf.c
===================================================================
RCS file: libc/stdio/fwprintf.c
diff -N libc/stdio/fwprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/fwprintf.c	5 Mar 2009 18:01:19 -0000
@@ -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: libc/stdio/local.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/local.h,v
retrieving revision 1.26
diff -u -p -r1.26 local.h
--- libc/stdio/local.h	11 Dec 2008 17:27:56 -0000	1.26
+++ libc/stdio/local.h	5 Mar 2009 18:01:19 -0000
@@ -44,6 +44,10 @@ int	      _EXFUN(_svfprintf_r,(struct _r
 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 *));
Index: libc/stdio/stdio.tex
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/stdio.tex,v
retrieving revision 1.12
diff -u -p -r1.12 stdio.tex
--- libc/stdio/stdio.tex	15 Dec 2008 20:31:47 -0000	1.12
+++ libc/stdio/stdio.tex	5 Mar 2009 18:01:19 -0000
@@ -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
Index: libc/stdio/swprintf.c
===================================================================
RCS file: libc/stdio/swprintf.c
diff -N libc/stdio/swprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/swprintf.c	5 Mar 2009 18:01:19 -0000
@@ -0,0 +1,630 @@
+/*
+ * 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]> bytes, 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 D
+			Newlib extension, short for <<%ld>>.
+
+		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 O
+			Newlib extension, short for <<%lo>>.
+
+		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 U
+			Newlib extension, short for <<%lu>>.
+
+		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 bytes 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 <<fputc>>.  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>
+#ifdef _HAVE_STDC
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include "local.h"
+
+int
+#ifdef _HAVE_STDC
+_DEFUN(_swprintf_r, (ptr, str, size, fmt),
+       struct _reent *ptr _AND
+       wchar_t *str          _AND
+       size_t size        _AND
+       _CONST wchar_t *fmt _DOTS)
+#else
+_swprintf_r(ptr, str, size, fmt, va_alist)
+            struct _reent *ptr;
+            wchar_t *str;
+            size_t size;
+            _CONST wchar_t *fmt;
+            va_dcl
+#endif
+{
+  int ret;
+  va_list ap;
+  FILE f;
+
+  if (size > INT_MAX / sizeof (wchar_t))
+    {
+      ptr->_errno = EOVERFLOW;
+      return WEOF;
+    }
+  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. */
+#ifdef _HAVE_STDC
+  va_start (ap, fmt);
+#else
+  va_start (ap);
+#endif
+  ret = _svfwprintf_r (ptr, &f, fmt, ap);
+  va_end (ap);
+  if (ret < WEOF)
+    ptr->_errno = EOVERFLOW;
+  if (size > 0)
+    *f._p = 0;
+  return (ret);
+}
+
+#ifndef _REENT_ONLY
+
+int
+#ifdef _HAVE_STDC
+_DEFUN(swprintf, (str, size, fmt),
+       wchar_t *str   _AND
+       size_t size _AND
+       _CONST wchar_t *fmt _DOTS)
+#else
+swprintf(str, size, fmt, va_alist)
+         wchar_t *str;
+         size_t size;
+         _CONST wchar_t *fmt;
+         va_dcl
+#endif
+{
+  int ret;
+  va_list ap;
+  FILE f;
+  struct _reent *ptr = _REENT;
+
+  if (size > INT_MAX / sizeof (wchar_t))
+    {
+      ptr->_errno = EOVERFLOW;
+      return WEOF;
+    }
+  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. */
+#ifdef _HAVE_STDC
+  va_start (ap, fmt);
+#else
+  va_start (ap);
+#endif
+  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: libc/stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfprintf.c,v
retrieving revision 1.72
diff -u -p -r1.72 vfprintf.c
--- libc/stdio/vfprintf.c	10 Dec 2008 23:43:12 -0000	1.72
+++ libc/stdio/vfprintf.c	5 Mar 2009 18:01:19 -0000
@@ -177,8 +177,18 @@ static char *rcsid = "$Id: vfprintf.c,v 
 #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; \
Index: libc/stdio/vfwprintf.c
===================================================================
RCS file: libc/stdio/vfwprintf.c
diff -N libc/stdio/vfwprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/vfwprintf.c	5 Mar 2009 18:01:19 -0000
@@ -0,0 +1,1897 @@
+/*
+ * 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 WEOF, not 0 */
+	if (cantwrite (data, fp)) {
+		_funlockfile (fp);
+		return (WEOF);
+	}
+
+	/* 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 WEOF;
+		}
+		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':  /* extension */
+			flags |= LONGINT;
+			/*FALLTHROUGH*/
+		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': /* extension */
+			flags |= LONGINT;
+			/*FALLTHROUGH*/
+		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 strlen; 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': /* extension */
+			flags |= LONGINT;
+			/*FALLTHROUGH*/
+		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) ? WEOF : 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. */
+
+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] = {
+  /* 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,
+  /* 18-1f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 20-27 */  FLAG,    OTHER,   OTHER,   FLAG,    DOLLAR,  OTHER,   OTHER,   FLAG,
+  /* 28-2f */  OTHER,   OTHER,   STAR,    FLAG,    OTHER,   FLAG,    DOT,     OTHER,
+  /* 30-37 */  ZERO,    DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,
+  /* 38-3f */  DIGIT,   DIGIT,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 40-47 */  OTHER,   SPEC,    OTHER,   SPEC,    SPEC,    SPEC,    SPEC,    SPEC,
+  /* 48-4f */  OTHER,   OTHER,   OTHER,   OTHER,   MODFR,   OTHER,   OTHER,   SPEC,
+  /* 50-57 */  OTHER,   OTHER,   OTHER,   SPEC,    OTHER,   SPEC,    OTHER,   OTHER,
+  /* 58-5f */  SPEC,    OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 60-67 */  OTHER,   SPEC,    OTHER,   SPEC,    SPEC,    SPEC,    SPEC,    SPEC,
+  /* 68-6f */  MODFR,   SPEC,    MODFR,   OTHER,   MODFR,   OTHER,   SPEC,    SPEC,
+  /* 70-77 */  SPEC,    MODFR,   OTHER,   SPEC,    MODFR,   SPEC,    OTHER,   OTHER,
+  /* 78-7f */  SPEC,    OTHER,   MODFR,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 80-87 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 88-8f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 90-97 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* 98-9f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* a0-a7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* a8-af */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* b0-b7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* b8-bf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* c0-c7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* c8-cf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* d0-d7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* d8-df */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* e0-e7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* e8-ef */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* f0-f7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+  /* f8-ff */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
+};
+
+_CONST static 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 },
+  /* WDIG  */  { DONE,    DONE,    WIDTH,  SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
+  /* WIDTH */  { DONE,    DONE,    DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
+  /* SMOD  */  { DONE,    DONE,    DONE,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
+  /* SDOT  */  { SDOT,    PREC,    DONE,   SMOD,    DONE,   DONE,  VARP,   DONE,   DONE },
+  /* VARW  */  { DONE,    VWDIG,   DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
+  /* VARP  */  { DONE,    VPDIG,   DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
+  /* PREC  */  { DONE,    DONE,    DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
+  /* VWDIG */  { DONE,    DONE,    WIDTH,  DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
+  /* VPDIG */  { DONE,    DONE,    PREC,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
+};
+
+_CONST static 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 },
+  /* WDIG  */  { NOOP,    NOOP,    GETPOS, GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
+  /* WIDTH */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
+  /* SMOD  */  { NOOP,    NOOP,    NOOP,   NOOP,    GETARG, NOOP,  NOOP,   NOOP,   NOOP },
+  /* SDOT  */  { NOOP,    SKIPNUM, NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
+  /* VARW  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, GETPW, NOOP,   NOOP,   NOOP },
+  /* VARP  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, NOOP,  NOOP,   NOOP,   NOOP },
+  /* PREC  */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
+  /* VWDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
+  /* VPDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
+};
+
+/* 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;
+		  case L'D':
+		  case L'U':
+		  case L'O':
+		    spec_type = LONG_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 */
Index: libc/stdio/vswprintf.c
===================================================================
RCS file: libc/stdio/vswprintf.c
diff -N libc/stdio/vswprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/vswprintf.c	5 Mar 2009 18:01:19 -0000
@@ -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 */
Index: libc/stdio/vwprintf.c
===================================================================
RCS file: libc/stdio/vwprintf.c
diff -N libc/stdio/vwprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/vwprintf.c	5 Mar 2009 18:01:19 -0000
@@ -0,0 +1,51 @@
+/*
+ * 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>
+#ifdef _HAVE_STDC
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#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);
+}
Index: libc/stdio/wprintf.c
===================================================================
RCS file: libc/stdio/wprintf.c
diff -N libc/stdio/wprintf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/wprintf.c	5 Mar 2009 18:01:19 -0000
@@ -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 */


-- 
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat


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