Commit 9df0177f33

Andrew Kelley <andrew@ziglang.org>
2024-01-08 07:59:42
mingw: add the mingw stdio functions back
We would rather use the ucrt for these, but sometimes dependencies on the mingw stdio functions creep in. 仕方ない. The cost is only paid if they are used; otherwise the symbols are garbage-collected at link time.
1 parent 99922c2
lib/libc/mingw/stdio/mingw_asprintf.c
@@ -0,0 +1,32 @@
+#define _GNU_SOURCE
+#define __CRT__NO_INLINE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int __mingw_asprintf(char ** __restrict__ ret,
+                     const char * __restrict__ format,
+                     ...) {
+  va_list ap;
+  int len;
+  va_start(ap,format);
+  /* Get Length */
+  len = __mingw_vsnprintf(NULL,0,format,ap);
+  if (len < 0) goto _end;
+  /* +1 for \0 terminator. */
+  *ret = malloc(len + 1);
+  /* Check malloc fail*/
+  if (!*ret) {
+    len = -1;
+    goto _end;
+  }
+  /* Write String */
+  __mingw_vsnprintf(*ret,len+1,format,ap);
+  /* Terminate explicitly */
+  (*ret)[len] = '\0';
+  _end:
+  va_end(ap);
+  return len;
+}
+
lib/libc/mingw/stdio/mingw_dummy__lock.c
@@ -0,0 +1,12 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <internal.h>
+
+void __cdecl _lock(int locknum);
+void __cdecl _unlock(int locknum);
+void __cdecl _lock(__UNUSED_PARAM(int locknum)) { }
+void __cdecl _unlock(__UNUSED_PARAM(int locknum)) { }
lib/libc/mingw/stdio/mingw_fprintf.c
@@ -0,0 +1,58 @@
+/* fprintf.c
+ *
+ * $Id: fprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "fprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "fprintf" will normally be invoked by calling
+ * "__mingw_fprintf()" in preference to a direct reference to "fprintf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "fprint()".  Users who then
+ * wish to use this implementation may either call "__mingw_fprintf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "fprintf()" to "__mingw_fprintf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "fprintf()" in user
+ * code will ALWAYS be redirected to "__mingw_fprintf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "fprintf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_fprintf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __fprintf (FILE *, const APICHAR *, ...) __MINGW_NOTHROW;
+
+int __cdecl __fprintf(FILE *stream, const APICHAR *fmt, ...)
+{
+  register int retval;
+  va_list argv; va_start( argv, fmt );
+  _lock_file( stream );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
+  _unlock_file( stream );
+  va_end( argv );
+  return retval;
+}
lib/libc/mingw/stdio/mingw_fprintfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_fprintf.c"
+
lib/libc/mingw/stdio/mingw_fscanf.c
@@ -0,0 +1,21 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int __mingw_vfscanf (FILE *stream, const char *format, va_list argp);
+
+int __mingw_fscanf (FILE *stream, const char *format, ...);
+
+int
+__mingw_fscanf (FILE *stream, const char *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vfscanf (stream, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
lib/libc/mingw/stdio/mingw_fwscanf.c
@@ -0,0 +1,21 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int __mingw_vfwscanf (FILE *stream, const wchar_t *format, va_list argp);
+
+int __mingw_fwscanf (FILE *stream, const wchar_t *format, ...);
+
+int
+__mingw_fwscanf (FILE *stream, const wchar_t *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vfwscanf (stream, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
lib/libc/mingw/stdio/mingw_lock.c
@@ -0,0 +1,102 @@
+#define _CRTIMP
+#include <stdio.h>
+#include <synchapi.h>
+#include "internal.h"
+
+/***
+ * Copy of MS functions _lock_file, _unlock_file which are missing from
+ * msvcrt.dll and msvcr80.dll. They are needed to atomic/lock stdio
+ * functions (printf, fprintf, vprintf, vfprintf). We need exactly the same
+ * lock that MS uses in msvcrt.dll because we can mix mingw-w64 code with
+ * original MS functions (puts, fputs for example).
+***/ 
+
+
+_CRTIMP void __cdecl _lock(int locknum);
+_CRTIMP void __cdecl _unlock(int locknum);
+#define _STREAM_LOCKS   16
+#define _IOLOCKED       0x8000
+
+
+/***
+* _lock_file - Lock a FILE
+*
+*Purpose:
+*       Assert the lock for a stdio-level file
+*
+*Entry:
+*       pf = __piob[] entry (pointer to a FILE or _FILEX)
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void __cdecl _lock_file( FILE *pf )
+{
+    /*
+     * The way the FILE (pointed to by pf) is locked depends on whether
+     * it is part of _iob[] or not
+     */
+    if ( (pf >= __acrt_iob_func(0)) && (pf <= __acrt_iob_func(_IOB_ENTRIES-1)) )
+    {
+        /*
+         * FILE lies in _iob[] so the lock lies in _locktable[].
+         */
+        _lock( _STREAM_LOCKS + (int)(pf - __acrt_iob_func(0)) );
+        /* We set _IOLOCKED to indicate we locked the stream */
+        pf->_flag |= _IOLOCKED;
+    }
+    else
+        /*
+         * Not part of _iob[]. Therefore, *pf is a _FILEX and the
+         * lock field of the struct is an initialized critical
+         * section.
+         */
+        EnterCriticalSection( &(((_FILEX *)pf)->lock) );
+}
+
+void *__MINGW_IMP_SYMBOL(_lock_file) = _lock_file;
+
+
+/***
+* _unlock_file - Unlock a FILE
+*
+*Purpose:
+*       Release the lock for a stdio-level file
+*
+*Entry:
+*       pf = __piob[] entry (pointer to a FILE or _FILEX)
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void __cdecl _unlock_file( FILE *pf )
+{
+    /*
+     * The way the FILE (pointed to by pf) is unlocked depends on whether
+     * it is part of _iob[] or not
+     */
+    if ( (pf >= __acrt_iob_func(0)) && (pf <= __acrt_iob_func(_IOB_ENTRIES-1)) )
+    {
+        /*
+         * FILE lies in _iob[] so the lock lies in _locktable[].
+         * We reset _IOLOCKED to indicate we unlock the stream.
+         */
+        pf->_flag &= ~_IOLOCKED;
+        _unlock( _STREAM_LOCKS + (int)(pf - __acrt_iob_func(0)) );
+    }
+    else
+        /*
+         * Not part of _iob[]. Therefore, *pf is a _FILEX and the
+         * lock field of the struct is an initialized critical
+         * section.
+         */
+        LeaveCriticalSection( &(((_FILEX *)pf)->lock) );
+}
+
+void *__MINGW_IMP_SYMBOL(_unlock_file) = _unlock_file;
lib/libc/mingw/stdio/mingw_pformat.c
@@ -0,0 +1,3312 @@
+/* pformat.c
+ *
+ * $Id: pformat.c,v 1.9 2011/01/07 22:57:00 keithmarshall Exp $
+ *
+ * Provides a core implementation of the formatting capabilities
+ * common to the entire `printf()' family of functions; it conforms
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ * The elements of this implementation which deal with the formatting
+ * of floating point numbers, (i.e. the `%e', `%E', `%f', `%F', `%g'
+ * and `%G' format specifiers, but excluding the hexadecimal floating
+ * point `%a' and `%A' specifiers), make use of the `__gdtoa' function
+ * written by David M. Gay, and are modelled on his sample code, which
+ * has been deployed under its accompanying terms of use:--
+ *
+ ******************************************************************
+ * Copyright (C) 1997, 1999, 2001 Lucent Technologies
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and this
+ * permission notice and warranty disclaimer appear in supporting
+ * documentation, and that the name of Lucent or any of its entities
+ * not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ *
+ * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ ******************************************************************
+ *
+ */
+
+#define __LARGE_MBSTATE_T
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <locale.h>
+#include <wchar.h>
+
+#ifdef __ENABLE_DFP
+#ifndef __STDC_WANT_DEC_FP__
+#define __STDC_WANT_DEC_FP__ 1
+#endif
+
+#include "../math/DFP/dfp_internal.h"
+#endif /* __ENABLE_DFP */
+
+#include <math.h>
+
+/* FIXME: The following belongs in values.h, but current MinGW
+ * has nothing useful there!  OTOH, values.h is not a standard
+ * header, and its use may be considered obsolete; perhaps it
+ * is better to just keep these definitions here.
+ */
+
+#include <pshpack1.h>
+/* workaround gcc bug */
+#if defined(__GNUC__) && !defined(__clang__)
+#define ATTRIB_GCC_STRUCT __attribute__((gcc_struct))
+#else
+#define ATTRIB_GCC_STRUCT
+#endif
+typedef struct ATTRIB_GCC_STRUCT __tI128 {
+  int64_t digits[2];
+} __tI128;
+
+typedef struct ATTRIB_GCC_STRUCT __tI128_2 {
+  uint32_t digits32[4];
+} __tI128_2;
+
+typedef union ATTRIB_GCC_STRUCT __uI128 {
+  __tI128 t128;
+  __tI128_2 t128_2;
+} __uI128;
+#include <poppack.h>
+
+#ifndef _VALUES_H
+/*
+ * values.h
+ *
+ */
+#define _VALUES_H
+
+#include <limits.h>
+
+#define _TYPEBITS(type)     (sizeof(type) * CHAR_BIT)
+
+#if defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP)
+#define LLONGBITS           _TYPEBITS(__tI128)
+#else
+#define LLONGBITS           _TYPEBITS(long long)
+#endif
+
+#endif /* !defined _VALUES_H -- end of file */
+
+#include "mingw_pformat.h"
+
+/* Bit-map constants, defining the internal format control
+ * states, which propagate through the flags.
+ */
+#define PFORMAT_GROUPED     0x00001000
+#define PFORMAT_HASHED      0x00000800
+#define PFORMAT_LJUSTIFY    0x00000400
+#define PFORMAT_ZEROFILL    0x00000200
+
+#define PFORMAT_JUSTIFY    (PFORMAT_LJUSTIFY | PFORMAT_ZEROFILL)
+#define PFORMAT_IGNORE      -1
+
+#define PFORMAT_SIGNED      0x000001C0
+#define PFORMAT_POSITIVE    0x00000100
+#define PFORMAT_NEGATIVE    0x00000080
+#define PFORMAT_ADDSPACE    0x00000040
+
+#define PFORMAT_XCASE       0x00000020
+
+#define PFORMAT_LDOUBLE     0x00000004
+
+#ifdef __ENABLE_DFP
+#define PFORMAT_DECIM32     0x00020000
+#define PFORMAT_DECIM64     0x00040000
+#define PFORMAT_DECIM128    0x00080000
+#endif
+
+/* `%o' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_OMASK       0x00000007
+#define PFORMAT_OSHIFT      0x00000003
+
+/* `%x' and `%X' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_XMASK       0x0000000F
+#define PFORMAT_XSHIFT      0x00000004
+
+/* The radix point character, used in floating point formats, is
+ * localised on the basis of the active LC_NUMERIC locale category.
+ * It is stored locally, as a `wchar_t' entity, which is converted
+ * to a (possibly multibyte) character on output.  Initialisation
+ * of the stored `wchar_t' entity, together with a record of its
+ * effective multibyte character length, is required each time
+ * `__pformat()' is entered, (static storage would not be thread
+ * safe), but this initialisation is deferred until it is actually
+ * needed; on entry, the effective character length is first set to
+ * the following value, (and the `wchar_t' entity is zeroed), to
+ * indicate that a call of `localeconv()' is needed, to complete
+ * the initialisation.
+ */
+#define PFORMAT_RPINIT      -3
+
+/* The floating point format handlers return the following value
+ * for the radix point position index, when the argument value is
+ * infinite, or not a number.
+ */
+#define PFORMAT_INFNAN      -32768
+
+typedef union
+{
+  /* A data type agnostic representation,
+   * for printf arguments of any integral data type...
+   */
+  signed long             __pformat_long_t;
+  signed long long        __pformat_llong_t;
+  unsigned long           __pformat_ulong_t;
+  unsigned long long      __pformat_ullong_t;
+  unsigned short          __pformat_ushort_t;
+  unsigned char           __pformat_uchar_t;
+  signed short            __pformat_short_t;
+  signed char             __pformat_char_t;
+  void *                  __pformat_ptr_t;
+  __uI128                 __pformat_u128_t;
+} __pformat_intarg_t;
+
+typedef enum
+{
+  /* Format interpreter state indices...
+   * (used to identify the active phase of format string parsing).
+   */
+  PFORMAT_INIT = 0,
+  PFORMAT_SET_WIDTH,
+  PFORMAT_GET_PRECISION,
+  PFORMAT_SET_PRECISION,
+  PFORMAT_END
+} __pformat_state_t;
+
+typedef enum
+{
+  /* Argument length classification indices...
+   * (used for arguments representing integer data types).
+   */
+  PFORMAT_LENGTH_INT = 0,
+  PFORMAT_LENGTH_SHORT,
+  PFORMAT_LENGTH_LONG,
+  PFORMAT_LENGTH_LLONG,
+  PFORMAT_LENGTH_LLONG128,
+  PFORMAT_LENGTH_CHAR
+} __pformat_length_t;
+/*
+ * And a macro to map any arbitrary data type to an appropriate
+ * matching index, selected from those above; the compiler should
+ * collapse this to a simple assignment.
+ */
+
+#ifdef __GNUC__
+/* provides for some deadcode elimination via compile time eval */
+#define __pformat_arg_length(x) \
+__builtin_choose_expr (                                         \
+  __builtin_types_compatible_p (typeof (x), __tI128),           \
+   PFORMAT_LENGTH_LLONG128,                                     \
+    __builtin_choose_expr (                                     \
+      __builtin_types_compatible_p (typeof (x), long long),     \
+        PFORMAT_LENGTH_LLONG,                                   \
+    __builtin_choose_expr (                                     \
+      __builtin_types_compatible_p (typeof (x), long),          \
+        PFORMAT_LENGTH_LONG,                                    \
+    __builtin_choose_expr (                                     \
+      __builtin_types_compatible_p (typeof (x), short),         \
+        PFORMAT_LENGTH_SHORT,                                   \
+    __builtin_choose_expr (                                     \
+      __builtin_types_compatible_p (typeof (x), char),          \
+        PFORMAT_LENGTH_CHAR,                                    \
+    __builtin_choose_expr (                                     \
+      __builtin_types_compatible_p (typeof (x), __uI128),       \
+        PFORMAT_LENGTH_LLONG128,                                \
+    __builtin_choose_expr (                                              \
+      __builtin_types_compatible_p (typeof (x), unsigned long),          \
+        PFORMAT_LENGTH_LONG,                                             \
+    __builtin_choose_expr (                                              \
+      __builtin_types_compatible_p (typeof (x), unsigned long long),     \
+        PFORMAT_LENGTH_LLONG,                                            \
+    __builtin_choose_expr (                                              \
+      __builtin_types_compatible_p (typeof (x), unsigned short),         \
+        PFORMAT_LENGTH_SHORT,                                            \
+    __builtin_choose_expr (                                              \
+      __builtin_types_compatible_p (typeof (x), unsigned char),          \
+        PFORMAT_LENGTH_CHAR,                                             \
+  PFORMAT_LENGTH_INT))))))))))
+
+#else
+#define __pformat_arg_length( type )    \
+  sizeof( type ) == sizeof( __tI128 )   ? PFORMAT_LENGTH_LLONG128 : \
+  sizeof( type ) == sizeof( long long ) ? PFORMAT_LENGTH_LLONG : \
+  sizeof( type ) == sizeof( long )      ? PFORMAT_LENGTH_LONG  : \
+  sizeof( type ) == sizeof( short )     ? PFORMAT_LENGTH_SHORT : \
+  sizeof( type ) == sizeof( char )      ? PFORMAT_LENGTH_CHAR  : \
+  /* should never need this default */    PFORMAT_LENGTH_INT
+#endif
+
+typedef struct
+{
+  /* Formatting and output control data...
+   * An instance of this control block is created, (on the stack),
+   * for each call to `__pformat()', and is passed by reference to
+   * each of the output handlers, as required.
+   */
+  void *         dest;
+  int            flags;
+  int            width;
+  int            precision;
+  int            rplen;
+  wchar_t        rpchr;
+  int            thousands_chr_len;
+  wchar_t        thousands_chr;
+  int            count;
+  int            quota;
+  int            expmin;
+} __pformat_t;
+
+#if defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP)
+/* trim leading, leave at least n characters */
+static char * __bigint_trim_leading_zeroes(char *in, int n){
+  char *src = in;
+  int len = strlen(in);
+  while( len > n && *++src == '0') len--;
+
+  /* we want to null terminator too */
+  memmove(in, src, strlen(src) + 1);
+  return in;
+}
+
+/* LSB first */
+static
+void __bigint_to_string(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){
+  int64_t digitsize = sizeof(*digits) * 8;
+  int64_t shiftpos = digitlen * digitsize - 1;
+  memset(buff, 0, bufflen);
+
+  while(shiftpos >= 0) {
+    /* increment */
+    for(uint32_t i = 0; i < bufflen - 1; i++){
+      buff[i] += (buff[i] > 4) ? 3 : 0;
+    }
+
+    /* shift left */
+    for(uint32_t i = 0; i < bufflen - 1; i++)
+      buff[i] <<= 1;
+
+    /* shift in */
+    buff[bufflen - 2] |= digits[shiftpos / digitsize] & (0x1 << (shiftpos % digitsize)) ? 1 : 0;
+
+    /* overflow check */
+    for(uint32_t i = bufflen - 1; i > 0; i--){
+      buff[i - 1] |= (buff[i] > 0xf);
+      buff[i] &= 0x0f;
+    }
+    shiftpos--;
+  }
+
+  for(uint32_t i = 0; i < bufflen - 1; i++){
+    buff[i] += '0';
+  }
+  buff[bufflen - 1] = '\0';
+}
+
+#if defined(__ENABLE_PRINTF128)
+/* LSB first, hex version */
+static
+void __bigint_to_stringx(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen, int upper){
+  int32_t stride = sizeof(*digits) * 2;
+  uint32_t lastpos = 0;
+
+  for(uint32_t i = 0; i < digitlen * stride; i++){
+    int32_t buffpos = bufflen - i - 2;
+    buff[buffpos] = (digits[ i / stride ] & (0xf << 4 * (i % stride))) >> ( 4 * (i % stride));
+    buff[buffpos] += (buff[buffpos] > 9) ? ((upper) ? 0x7 : 0x27) : 0;
+    buff[buffpos] += '0';
+    lastpos = buffpos;
+    if(buffpos == 0) break; /* sanity check */
+  }
+  memset(buff, '0', lastpos);
+  buff[bufflen - 1] = '\0';
+}
+
+/* LSB first, octet version */
+static
+void __bigint_to_stringo(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){
+  const uint32_t digitsize = sizeof(*digits) * 8;
+  const uint64_t bits = digitsize * digitlen;
+  uint32_t pos = bufflen - 2;
+  uint32_t reg = 0;
+  for(uint32_t i = 0; i <= bits; i++){
+    reg |= (digits[ i / digitsize] & (0x1 << (i % digitsize))) ? 1 << (i % 3) : 0;
+    if( (i && ( i + 1) % 3 == 0) || (i + 1) == bits){ /* make sure all is committed after last bit */
+      buff[pos] = '0' + reg;
+      reg = 0;
+      if(!pos) break; /* sanity check */
+      pos--;
+    }
+  }
+  if(pos < bufflen - 1)
+    memset(buff,'0', pos + 1);
+  buff[bufflen - 1] = '\0';
+}
+#endif /* defined(__ENABLE_PRINTF128) */
+#endif /* defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP) */
+
+static
+void __pformat_putc( int c, __pformat_t *stream )
+{
+  /* Place a single character into the `__pformat()' output queue,
+   * provided any specified output quota has not been exceeded.
+   */
+  if( (stream->flags & PFORMAT_NOLIMIT) || (stream->quota > stream->count) )
+  {
+    /* Either there was no quota specified,
+     * or the active quota has not yet been reached.
+     */
+    if( stream->flags & PFORMAT_TO_FILE )
+      /*
+       * This is single character output to a FILE stream...
+       */
+      __fputc(c, (FILE *)(stream->dest));
+
+    else
+      /* Whereas, this is to an internal memory buffer...
+       */
+      ((APICHAR *)(stream->dest))[stream->count] = c;
+  }
+  ++stream->count;
+}
+
+static
+void __pformat_putchars( const char *s, int count, __pformat_t *stream )
+{
+#ifndef __BUILD_WIDEAPI
+  /* Handler for `%c' and (indirectly) `%s' conversion specifications.
+   *
+   * Transfer characters from the string buffer at `s', character by
+   * character, up to the number of characters specified by `count', or
+   * if `precision' has been explicitly set to a value less than `count',
+   * stopping after the number of characters specified for `precision',
+   * to the `__pformat()' output stream.
+   *
+   * Characters to be emitted are passed through `__pformat_putc()', to
+   * ensure that any specified output quota is honoured.
+   */
+  if( (stream->precision >= 0) && (count > stream->precision) )
+    /*
+     * Ensure that the maximum number of characters transferred doesn't
+     * exceed any explicitly set `precision' specification.
+     */
+    count = stream->precision;
+
+  /* Establish the width of any field padding required...
+   */
+  if( stream->width > count )
+    /*
+     * as the number of spaces equivalent to the number of characters
+     * by which those to be emitted is fewer than the field width...
+     */
+    stream->width -= count;
+
+  else
+    /* ignoring any width specification which is insufficient.
+     */
+    stream->width = PFORMAT_IGNORE;
+
+  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+    /*
+     * When not doing flush left justification, (i.e. the `-' flag
+     * is not set), any residual unreserved field width must appear
+     * as blank padding, to the left of the output string.
+     */
+    while( stream->width-- )
+      __pformat_putc( '\x20', stream );
+
+  /* Emit the data...
+   */
+  while( count-- )
+    /*
+     * copying the requisite number of characters from the input.
+     */
+    __pformat_putc( *s++, stream );
+
+  /* If we still haven't consumed the entire specified field width,
+   * we must be doing flush left justification; any residual width
+   * must be filled with blanks, to the right of the output value.
+   */
+  while( stream->width-- > 0 )
+    __pformat_putc( '\x20', stream );
+
+#else  /* __BUILD_WIDEAPI */
+
+  int len;
+
+  if( (stream->precision >= 0) && (count > stream->precision) )
+    count = stream->precision;
+
+  if( (stream->flags & PFORMAT_TO_FILE) && (stream->flags & PFORMAT_NOLIMIT) )
+  {
+    int __cdecl __ms_fwprintf(FILE *, const wchar_t *, ...);
+
+    if( stream->width > count )
+    {
+      if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
+        len = __ms_fwprintf( (FILE *)(stream->dest), L"%*.*S", stream->width, count, s );
+      else
+        len = __ms_fwprintf( (FILE *)(stream->dest), L"%-*.*S", stream->width, count, s );
+    }
+    else
+    {
+      len = __ms_fwprintf( (FILE *)(stream->dest), L"%.*S", count, s );
+    }
+    if( len > 0 )
+      stream->count += len;
+    stream->width = PFORMAT_IGNORE;
+    return;
+  }
+
+  if( stream->width > count )
+    stream->width -= count;
+  else
+    stream->width = PFORMAT_IGNORE;
+
+  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+    while( stream->width-- )
+      __pformat_putc( '\x20', stream );
+
+  {
+    /* mbrtowc */
+    size_t l;
+    wchar_t w[12], *p;
+    while( count > 0 )
+    {
+      mbstate_t ps;
+      memset(&ps, 0, sizeof(ps) );
+      --count;
+      p = &w[0];
+      l = mbrtowc (p, s, strlen (s), &ps);
+      if (!l)
+        break;
+      if ((ssize_t)l < 0)
+      {
+        l = 1;
+        w[0] = (wchar_t) *s;
+      }
+      s += l;
+      __pformat_putc((int)w[0], stream);
+    }
+  }
+
+  while( stream->width-- > 0 )
+    __pformat_putc( '\x20', stream );
+
+#endif  /* __BUILD_WIDEAPI */
+}
+
+static
+void __pformat_puts( const char *s, __pformat_t *stream )
+{
+  /* Handler for `%s' conversion specifications.
+   *
+   * Transfer a NUL terminated character string, character by character,
+   * stopping when the end of the string is encountered, or if `precision'
+   * has been explicitly set, when the specified number of characters has
+   * been emitted, if that is less than the length of the input string,
+   * to the `__pformat()' output stream.
+   *
+   * This is implemented as a trivial call to `__pformat_putchars()',
+   * passing the length of the input string as the character count,
+   * (after first verifying that the input pointer is not NULL).
+   */
+  if( s == NULL ) s = "(null)";
+
+  if( stream->precision >= 0 )
+    __pformat_putchars( s, strnlen( s, stream->precision ), stream );
+  else
+    __pformat_putchars( s, strlen( s ), stream );
+}
+
+static
+void __pformat_wputchars( const wchar_t *s, int count, __pformat_t *stream )
+{
+#ifndef __BUILD_WIDEAPI
+  /* Handler for `%C'(`%lc') and `%S'(`%ls') conversion specifications;
+   * (this is a wide character variant of `__pformat_putchars()').
+   *
+   * Each multibyte character sequence to be emitted is passed, byte
+   * by byte, through `__pformat_putc()', to ensure that any specified
+   * output quota is honoured.
+   */
+  char buf[16];
+  mbstate_t state;
+  int len = wcrtomb(buf, L'\0', &state);
+
+  if( (stream->precision >= 0) && (count > stream->precision) )
+    /*
+     * Ensure that the maximum number of characters transferred doesn't
+     * exceed any explicitly set `precision' specification.
+     */
+    count = stream->precision;
+
+  /* Establish the width of any field padding required...
+   */
+  if( stream->width > count )
+    /*
+     * as the number of spaces equivalent to the number of characters
+     * by which those to be emitted is fewer than the field width...
+     */
+    stream->width -= count;
+
+  else
+    /* ignoring any width specification which is insufficient.
+     */
+    stream->width = PFORMAT_IGNORE;
+
+  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+    /*
+     * When not doing flush left justification, (i.e. the `-' flag
+     * is not set), any residual unreserved field width must appear
+     * as blank padding, to the left of the output string.
+     */
+    while( stream->width-- )
+      __pformat_putc( '\x20', stream );
+
+  /* Emit the data, converting each character from the wide
+   * to the multibyte domain as we go...
+   */
+  while( (count-- > 0) && ((len = wcrtomb( buf, *s++, &state )) > 0) )
+  {
+    char *p = buf;
+    while( len-- > 0 )
+      __pformat_putc( *p++, stream );
+  }
+
+  /* If we still haven't consumed the entire specified field width,
+   * we must be doing flush left justification; any residual width
+   * must be filled with blanks, to the right of the output value.
+   */
+  while( stream->width-- > 0 )
+    __pformat_putc( '\x20', stream );
+
+#else  /* __BUILD_WIDEAPI */
+
+  int len;
+
+  if( (stream->precision >= 0) && (count > stream->precision) )
+    count = stream->precision;
+
+  if( (stream->flags & PFORMAT_TO_FILE) && (stream->flags & PFORMAT_NOLIMIT) )
+  {
+    int __cdecl __ms_fwprintf(FILE *, const wchar_t *, ...);
+
+    if( stream->width > count )
+    {
+      if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
+        len = __ms_fwprintf( (FILE *)(stream->dest), L"%*.*s", stream->width, count, s );
+      else
+        len = __ms_fwprintf( (FILE *)(stream->dest), L"%-*.*s", stream->width, count, s );
+    }
+    else
+    {
+      len = __ms_fwprintf( (FILE *)(stream->dest), L"%.*s", count, s );
+    }
+    if( len > 0 )
+      stream->count += len;
+    stream->width = PFORMAT_IGNORE;
+    return;
+  }
+
+  if( stream->width > count )
+    stream->width -= count;
+  else
+    stream->width = PFORMAT_IGNORE;
+
+  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+    while( stream->width-- )
+      __pformat_putc( '\x20', stream );
+
+  len = count;
+  while(len-- > 0 && *s != 0)
+  {
+      __pformat_putc(*s++, stream);
+  }
+
+  while( stream->width-- > 0 )
+    __pformat_putc( '\x20', stream );
+
+#endif  /* __BUILD_WIDEAPI */
+}
+
+static
+void __pformat_wcputs( const wchar_t *s, __pformat_t *stream )
+{
+  /* Handler for `%S' (`%ls') conversion specifications.
+   *
+   * Transfer a NUL terminated wide character string, character by
+   * character, converting to its equivalent multibyte representation
+   * on output, and stopping when the end of the string is encountered,
+   * or if `precision' has been explicitly set, when the specified number
+   * of characters has been emitted, if that is less than the length of
+   * the input string, to the `__pformat()' output stream.
+   *
+   * This is implemented as a trivial call to `__pformat_wputchars()',
+   * passing the length of the input string as the character count,
+   * (after first verifying that the input pointer is not NULL).
+   */
+  if( s == NULL ) s = L"(null)";
+
+  if( stream->precision >= 0 )
+    __pformat_wputchars( s, wcsnlen( s, stream->precision ), stream );
+  else
+    __pformat_wputchars( s, wcslen( s ), stream );
+}
+
+static
+int __pformat_int_bufsiz( int bias, int size, __pformat_t *stream )
+{
+  /* Helper to establish the size of the internal buffer, which
+   * is required to queue the ASCII decomposition of an integral
+   * data value, prior to transfer to the output stream.
+   */
+  size = ((size - 1 + LLONGBITS) / size) + bias;
+  size += (stream->precision > 0) ? stream->precision : 0;
+  if ((stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
+    size += (size / 3);
+  return (size > stream->width) ? size : stream->width;
+}
+
+static
+void __pformat_int( __pformat_intarg_t value, __pformat_t *stream )
+{
+  /* Handler for `%d', `%i' and `%u' conversion specifications.
+   *
+   * Transfer the ASCII representation of an integer value parameter,
+   * formatted as a decimal number, to the `__pformat()' output queue;
+   * output will be truncated, if any specified quota is exceeded.
+   */
+  int32_t bufflen = __pformat_int_bufsiz(1, PFORMAT_OSHIFT, stream);
+#ifdef __ENABLE_PRINTF128
+  char *tmp_buff = NULL;
+#endif
+  char *buf = NULL;
+  char *p;
+  int precision;
+
+  buf = alloca(bufflen);
+  p = buf;
+  if( stream->flags & PFORMAT_NEGATIVE )
+#ifdef __ENABLE_PRINTF128
+  {
+    /* The input value might be negative, (i.e. it is a signed value)...
+     */
+    if( value.__pformat_u128_t.t128.digits[1] < 0) {
+      /*
+       * It IS negative, but we want to encode it as unsigned,
+       * displayed with a leading minus sign, so convert it...
+       */
+      /* two's complement */
+      value.__pformat_u128_t.t128.digits[0] = ~value.__pformat_u128_t.t128.digits[0];
+      value.__pformat_u128_t.t128.digits[1] = ~value.__pformat_u128_t.t128.digits[1];
+      value.__pformat_u128_t.t128.digits[0] += 1;
+      value.__pformat_u128_t.t128.digits[1] += (!value.__pformat_u128_t.t128.digits[0]) ? 1 : 0;
+    } else
+      /* It is unequivocally a POSITIVE value, so turn off the
+       * request to prefix it with a minus sign...
+       */
+      stream->flags &= ~PFORMAT_NEGATIVE;
+  }
+
+  tmp_buff = alloca(bufflen);
+  /* Encode the input value for display...
+   */
+  __bigint_to_string(value.__pformat_u128_t.t128_2.digits32,
+    4, tmp_buff, bufflen);
+  __bigint_trim_leading_zeroes(tmp_buff,1);
+
+  memset(p,0,bufflen);
+  for(int32_t i = strlen(tmp_buff) - 1; i >= 0; i--){
+  if ( i && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
+        && (i % 4) == 3)
+      {
+        *p++ = ',';
+      }
+      *p++ = tmp_buff[i];
+    if( i > bufflen - 1) break; /* sanity chec */
+    if(  tmp_buff[i] == '\0' ) break; /* end */
+  }
+#else
+  {
+    /* The input value might be negative, (i.e. it is a signed value)...
+     */
+    if( value.__pformat_llong_t < 0LL )
+      /*
+       * It IS negative, but we want to encode it as unsigned,
+       * displayed with a leading minus sign, so convert it...
+       */
+      value.__pformat_llong_t = -value.__pformat_llong_t;
+
+    else
+      /* It is unequivocally a POSITIVE value, so turn off the
+       * request to prefix it with a minus sign...
+       */
+      stream->flags &= ~PFORMAT_NEGATIVE;
+  }
+while( value.__pformat_ullong_t )
+  {
+    /* decomposing it into its constituent decimal digits,
+     * in order from least significant to most significant, using
+     * the local buffer as a LIFO queue in which to store them.
+     */
+    if (p != buf && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
+        && ((p - buf) % 4) == 3)
+      {
+        *p++ = ',';
+      }
+    *p++ = '0' + (unsigned char)(value.__pformat_ullong_t % 10LL);
+    value.__pformat_ullong_t /= 10LL;
+  }
+#endif
+
+  if(  (stream->precision > 0)
+  &&  ((precision = stream->precision - (p - buf)) > 0)  )
+    /*
+     * We have not yet queued sufficient digits to fill the field width
+     * specified for minimum `precision'; pad with zeros to achieve this.
+     */
+    while( precision-- > 0 )
+      *p++ = '0';
+
+  if( (p == buf) && (stream->precision != 0) )
+    /*
+     * Input value was zero; make sure we print at least one digit,
+     * unless the precision is also explicitly zero.
+     */
+    *p++ = '0';
+
+  if( (stream->width > 0) && ((stream->width -= p - buf) > 0) )
+  {
+    /* We have now queued sufficient characters to display the input value,
+     * at the desired precision, but this will not fill the output field...
+     */
+    if( stream->flags & PFORMAT_SIGNED )
+      /*
+       * We will fill one additional space with a sign...
+       */
+      stream->width--;
+
+    if(  (stream->precision < 0)
+    &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
+      /*
+       * and the `0' flag is in effect, so we pad the remaining spaces,
+       * to the left of the displayed value, with zeros.
+       */
+      while( stream->width-- > 0 )
+        *p++ = '0';
+
+    else if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
+      /*
+       * the `0' flag is not in effect, and neither is the `-' flag,
+       * so we pad to the left of the displayed value with spaces, so that
+       * the value appears right justified within the output field.
+       */
+      while( stream->width-- > 0 )
+        __pformat_putc( '\x20', stream );
+  }
+
+  if( stream->flags & PFORMAT_NEGATIVE )
+    /*
+     * A negative value needs a sign...
+     */
+    *p++ = '-';
+
+  else if( stream->flags & PFORMAT_POSITIVE )
+    /*
+     * A positive value may have an optionally displayed sign...
+     */
+    *p++ = '+';
+
+  else if( stream->flags & PFORMAT_ADDSPACE )
+    /*
+     * Space was reserved for displaying a sign, but none was emitted...
+     */
+    *p++ = '\x20';
+
+  while( p > buf )
+    /*
+     * Emit the accumulated constituent digits,
+     * in order from most significant to least significant...
+     */
+    __pformat_putc( *--p, stream );
+
+  while( stream->width-- > 0 )
+    /*
+     * The specified output field has not yet been completely filled;
+     * the `-' flag must be in effect, resulting in a displayed value which
+     * appears left justified within the output field; we must pad the field
+     * to the right of the displayed value, by emitting additional spaces,
+     * until we reach the rightmost field boundary.
+     */
+    __pformat_putc( '\x20', stream );
+}
+
+static
+void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream )
+{
+  /* Handler for `%o', `%p', `%x' and `%X' conversions.
+   *
+   * These can be implemented using a simple `mask and shift' strategy;
+   * set up the mask and shift values appropriate to the conversion format,
+   * and allocate a suitably sized local buffer, in which to queue encoded
+   * digits of the formatted value, in preparation for output.
+   */
+  int width;
+  int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT;
+  int bufflen = __pformat_int_bufsiz(2, shift, stream);
+  char *buf = NULL;
+#ifdef __ENABLE_PRINTF128
+  char *tmp_buf = NULL;
+#endif
+  char *p;
+  buf = alloca(bufflen);
+  p = buf;
+#ifdef __ENABLE_PRINTF128
+  tmp_buf = alloca(bufflen);
+  if(fmt == 'o'){
+    __bigint_to_stringo(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen);
+  } else {
+    __bigint_to_stringx(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen, !(fmt & PFORMAT_XCASE));
+  }
+  __bigint_trim_leading_zeroes(tmp_buf,0);
+
+  memset(buf,0,bufflen);
+  for(int32_t i = strlen(tmp_buf); i >= 0; i--)
+    *p++ = tmp_buf[i];
+#else
+  int mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK;
+  while( value.__pformat_ullong_t )
+  {
+    /* Encode the specified non-zero input value as a sequence of digits,
+     * in the appropriate `base' encoding and in reverse digit order, each
+     * encoded in its printable ASCII form, with no leading zeros, using
+     * the local buffer as a LIFO queue in which to store them.
+     */
+    char *q;
+    if( (*(q = p++) = '0' + (value.__pformat_ullong_t & mask)) > '9' )
+      *q = (*q + 'A' - '9' - 1) | (fmt & PFORMAT_XCASE);
+    value.__pformat_ullong_t >>= shift;
+  }
+#endif
+
+  if( p == buf )
+    /*
+     * Nothing was queued; input value must be zero, which should never be
+     * emitted in the `alternative' PFORMAT_HASHED style.
+     */
+    stream->flags &= ~PFORMAT_HASHED;
+
+  if( ((width = stream->precision) > 0) && ((width -= p - buf) > 0) )
+    /*
+     * We have not yet queued sufficient digits to fill the field width
+     * specified for minimum `precision'; pad with zeros to achieve this.
+     */
+    while( width-- > 0 )
+      *p++ = '0';
+
+  else if( (fmt == 'o') && (stream->flags & PFORMAT_HASHED) )
+    /*
+     * The field width specified for minimum `precision' has already
+     * been filled, but the `alternative' PFORMAT_HASHED style for octal
+     * output requires at least one initial zero; that will not have
+     * been queued, so add it now.
+     */
+    *p++ = '0';
+
+  if( (p == buf) && (stream->precision != 0) )
+    /*
+     * Still nothing queued for output, but the `precision' has not been
+     * explicitly specified as zero, (which is necessary if no output for
+     * an input value of zero is desired); queue exactly one zero digit.
+     */
+    *p++ = '0';
+
+  if( stream->width > (width = p - buf) )
+    /*
+     * Specified field width exceeds the minimum required...
+     * Adjust so that we retain only the additional padding width.
+     */
+    stream->width -= width;
+
+  else
+    /* Ignore any width specification which is insufficient.
+     */
+    stream->width = PFORMAT_IGNORE;
+
+  if( ((width = stream->width) > 0)
+  &&  (fmt != 'o') && (stream->flags & PFORMAT_HASHED)  )
+    /*
+     * For `%#x' or `%#X' formats, (which have the `#' flag set),
+     * further reduce the padding width to accommodate the radix
+     * indicating prefix.
+     */
+    width -= 2;
+
+  if(  (width > 0) && (stream->precision < 0)
+  &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
+    /*
+     * When the `0' flag is set, and not overridden by the `-' flag,
+     * or by a specified precision, add sufficient leading zeros to
+     * consume the remaining field width.
+     */
+    while( width-- > 0 )
+      *p++ = '0';
+
+  if( (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
+  {
+    /* For formats other than octal, the PFORMAT_HASHED output style
+     * requires the addition of a two character radix indicator, as a
+     * prefix to the actual encoded numeric value.
+     */
+    *p++ = fmt;
+    *p++ = '0';
+  }
+
+  if( (width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+    /*
+     * When not doing flush left justification, (i.e. the `-' flag
+     * is not set), any residual unreserved field width must appear
+     * as blank padding, to the left of the output value.
+     */
+    while( width-- > 0 )
+      __pformat_putc( '\x20', stream );
+
+  while( p > buf )
+    /*
+     * Move the queued output from the local buffer to the ultimate
+     * destination, in LIFO order.
+     */
+    __pformat_putc( *--p, stream );
+
+  /* If we still haven't consumed the entire specified field width,
+   * we must be doing flush left justification; any residual width
+   * must be filled with blanks, to the right of the output value.
+   */
+  while( width-- > 0 )
+    __pformat_putc( '\x20', stream );
+}
+
+typedef union
+{
+  /* A multifaceted representation of an IEEE extended precision,
+   * (80-bit), floating point number, facilitating access to its
+   * component parts.
+   */
+  double                 __pformat_fpreg_double_t;
+  long double            __pformat_fpreg_ldouble_t;
+  struct
+  { unsigned long long   __pformat_fpreg_mantissa;
+    signed short         __pformat_fpreg_exponent;
+  };
+  unsigned short         __pformat_fpreg_bitmap[5];
+  unsigned int           __pformat_fpreg_bits;
+} __pformat_fpreg_t;
+
+#ifdef _WIN32
+/* TODO: make this unconditional in final release...
+ * (see note at head of associated `#else' block.
+ */
+#include "../gdtoa/gdtoa.h"
+
+static __pformat_fpreg_t init_fpreg_ldouble( long double val )
+{
+  __pformat_fpreg_t x;
+  x.__pformat_fpreg_ldouble_t = val;
+
+  if( sizeof( double ) == sizeof( long double ) )
+  {
+    /* Here, __pformat_fpreg_t expects to be initialized with a 80 bit long
+     * double, but this platform doesn't have long doubles that differ from
+     * regular 64 bit doubles. Therefore manually convert the 64 bit float
+     * value to an 80 bit float value.
+     */
+    int exp = (x.__pformat_fpreg_mantissa >> 52) & 0x7ff;
+    unsigned long long mant = x.__pformat_fpreg_mantissa & 0x000fffffffffffffULL;
+    int topbit = exp ? 1 : 0;
+    int signbit = x.__pformat_fpreg_mantissa >> 63;
+
+    if (exp == 0x7ff)
+      exp = 0x7fff;
+    else if (exp != 0)
+      exp = exp - 1023 + 16383;
+    else if (mant != 0) {
+      /* Denormal when stored as a 64 bit double, but becomes a normal when
+       * converted to 80 bit long double form. */
+      exp = 1 - 1023 + 16383;
+      while (!(mant & 0x0010000000000000ULL)) {
+        /* Normalize the mantissa. */
+        mant <<= 1;
+        exp--;
+      }
+      topbit = 1; /* The top bit, which is implicit in the 64 bit form. */
+    }
+    x.__pformat_fpreg_mantissa = (mant << 11) | ((unsigned long long)topbit << 63);
+    x.__pformat_fpreg_exponent = exp | (signbit << 15);
+  }
+
+  return x;
+}
+
+static
+char *__pformat_cvt( int mode, long double val, int nd, int *dp, int *sign )
+{
+  /* Helper function, derived from David M. Gay's `g_xfmt()', calling
+   * his `__gdtoa()' function in a manner to provide extended precision
+   * replacements for `ecvt()' and `fcvt()'.
+   */
+  int k; unsigned int e = 0; char *ep;
+  static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0, 14 /* Int_max */ };
+  __pformat_fpreg_t x = init_fpreg_ldouble( val );
+
+  k = __fpclassifyl( val );
+
+  /* Classify the argument into an appropriate `__gdtoa()' category...
+   */
+  if( k & FP_NAN )
+    /*
+     * identifying infinities or not-a-number...
+     */
+    k = (k & FP_NORMAL) ? STRTOG_Infinite : STRTOG_NaN;
+
+  else if( k & FP_NORMAL )
+  {
+    /* normal and near-zero `denormals'...
+     */
+    if( k & FP_ZERO )
+    {
+      /* with appropriate exponent adjustment for a `denormal'...
+       */
+      k = STRTOG_Denormal;
+      e = 1 - 0x3FFF - 63;
+    }
+    else
+    {
+      /* or with `normal' exponent adjustment...
+       */
+      k = STRTOG_Normal;
+      e = (x.__pformat_fpreg_exponent & 0x7FFF) - 0x3FFF - 63;
+    }
+  }
+
+  else
+    /* or, if none of the above, it's a zero, (positive or negative).
+     */
+    k = STRTOG_Zero;
+
+  /* Check for negative values, always treating NaN as unsigned...
+   * (return value is zero for positive/unsigned; non-zero for negative).
+   */
+  *sign = (k == STRTOG_NaN) ? 0 : x.__pformat_fpreg_exponent & 0x8000;
+
+  /* Finally, get the raw digit string, and radix point position index.
+   */
+  return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, &k, mode, nd, dp, &ep );
+}
+
+static
+char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
+{
+  /* A convenience wrapper for the above...
+   * it emulates `ecvt()', but takes a `long double' argument.
+   */
+  return __pformat_cvt( 2, x, precision, dp, sign );
+}
+
+static
+char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
+{
+  /* A convenience wrapper for the above...
+   * it emulates `fcvt()', but takes a `long double' argument.
+   */
+  return __pformat_cvt( 3, x, precision, dp, sign );
+}
+
+/* The following are required, to clean up the `__gdtoa()' memory pool,
+ * after processing the data returned by the above.
+ */
+#define __pformat_ecvt_release( value ) __freedtoa( value )
+#define __pformat_fcvt_release( value ) __freedtoa( value )
+
+#else
+/*
+ * TODO: remove this before final release; it is included here as a
+ * convenience for testing, without requiring a working `__gdtoa()'.
+ */
+static
+char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
+{
+  /* Define in terms of `ecvt()'...
+   */
+  char *retval = ecvt( (double)(x), precision, dp, sign );
+  if( isinf( x ) || isnan( x ) )
+  {
+    /* emulating `__gdtoa()' reporting for infinities and NaN.
+     */
+    *dp = PFORMAT_INFNAN;
+    if( *retval == '-' )
+    {
+      /* Need to force the `sign' flag, (particularly for NaN).
+       */
+      ++retval; *sign = 1;
+    }
+  }
+  return retval;
+}
+
+static
+char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
+{
+  /* Define in terms of `fcvt()'...
+   */
+  char *retval = fcvt( (double)(x), precision, dp, sign );
+  if( isinf( x ) || isnan( x ) )
+  {
+    /* emulating `__gdtoa()' reporting for infinities and NaN.
+     */
+    *dp = PFORMAT_INFNAN;
+    if( *retval == '-' )
+    {
+      /* Need to force the `sign' flag, (particularly for NaN).
+       */
+      ++retval; *sign = 1;
+    }
+  }
+  return retval;
+}
+
+/* No memory pool clean up needed, for these emulated cases...
+ */
+#define __pformat_ecvt_release( value ) /* nothing to be done */
+#define __pformat_fcvt_release( value ) /* nothing to be done */
+
+/* TODO: end of conditional to be removed. */
+#endif
+
+static
+void __pformat_emit_radix_point( __pformat_t *stream )
+{
+  /* Helper to place a localised representation of the radix point
+   * character at the ultimate destination, when formatting fixed or
+   * floating point numbers.
+   */
+  if( stream->rplen == PFORMAT_RPINIT )
+  {
+    /* Radix point initialisation not yet completed;
+     * establish a multibyte to `wchar_t' converter...
+     */
+    int len; wchar_t rpchr; mbstate_t state;
+
+    /* Initialise the conversion state...
+     */
+    memset( &state, 0, sizeof( state ) );
+
+    /* Fetch and convert the localised radix point representation...
+     */
+    if( (len = mbrtowc( &rpchr, localeconv()->decimal_point, 16, &state )) > 0 )
+      /*
+       * and store it, if valid.
+       */
+      stream->rpchr = rpchr;
+
+    /* In any case, store the reported effective multibyte length,
+     * (or the error flag), marking initialisation as `done'.
+     */
+    stream->rplen = len;
+  }
+
+  if( stream->rpchr != (wchar_t)(0) )
+  {
+    /* We have a localised radix point mark;
+     * establish a converter to make it a multibyte character...
+     */
+#ifdef __BUILD_WIDEAPI
+   __pformat_putc (stream->rpchr, stream);
+#else
+    int len; char buf[len = stream->rplen]; mbstate_t state;
+
+    /* Initialise the conversion state...
+     */
+    memset( &state, 0, sizeof( state ) );
+
+    /* Convert the `wchar_t' representation to multibyte...
+     */
+    if( (len = wcrtomb( buf, stream->rpchr, &state )) > 0 )
+    {
+      /* and copy to the output destination, when valid...
+       */
+      char *p = buf;
+      while( len-- > 0 )
+        __pformat_putc( *p++, stream );
+    }
+
+    else
+      /* otherwise fall back to plain ASCII '.'...
+       */
+      __pformat_putc( '.', stream );
+#endif
+  }
+  else
+    /* No localisation: just use ASCII '.'...
+     */
+    __pformat_putc( '.', stream );
+}
+
+static
+void __pformat_emit_numeric_value( int c, __pformat_t *stream )
+{
+  /* Convenience helper to transfer numeric data from an internal
+   * formatting buffer to the ultimate destination...
+   */
+  if( c == '.' )
+    /*
+     * converting this internal representation of the the radix
+     * point to the appropriately localised representation...
+     */
+    __pformat_emit_radix_point( stream );
+  else if (c == ',')
+    {
+      wchar_t wcs;
+      if ((wcs = stream->thousands_chr) != 0)
+        __pformat_wputchars (&wcs, 1, stream);
+    }
+  else
+    /* and passing all other characters through, unmodified.
+     */
+    __pformat_putc( c, stream );
+}
+
+static
+void __pformat_emit_inf_or_nan( int sign, char *value, __pformat_t *stream )
+{
+  /* Helper to emit INF or NAN where a floating point value
+   * resolves to one of these special states.
+   */
+  int i;
+  char buf[4];
+  char *p = buf;
+
+  /* We use the string formatting helper to display INF/NAN,
+   * but we don't want truncation if the precision set for the
+   * original floating point output request was insufficient;
+   * ignore it!
+   */
+  stream->precision = PFORMAT_IGNORE;
+
+  if( sign )
+    /*
+     * Negative infinity: emit the sign...
+     */
+    *p++ = '-';
+
+  else if( stream->flags & PFORMAT_POSITIVE )
+    /*
+     * Not negative infinity, but '+' flag is in effect;
+     * thus, we emit a positive sign...
+     */
+    *p++ = '+';
+
+  else if( stream->flags & PFORMAT_ADDSPACE )
+    /*
+     * No sign required, but space was reserved for it...
+     */
+    *p++ = '\x20';
+
+  /* Copy the appropriate status indicator, up to a maximum of
+   * three characters, transforming to the case corresponding to
+   * the format specification...
+   */
+  for( i = 3; i > 0; --i )
+    *p++ = (*value++ & ~PFORMAT_XCASE) | (stream->flags & PFORMAT_XCASE);
+
+  /* and emit the result.
+   */
+  __pformat_putchars( buf, p - buf, stream );
+}
+
+static
+void __pformat_emit_float( int sign, char *value, int len, __pformat_t *stream )
+{
+  /* Helper to emit a fixed point representation of numeric data,
+   * as encoded by a prior call to `ecvt()' or `fcvt()'; (this does
+   * NOT include the exponent, for floating point format).
+   */
+  if( len > 0 )
+  {
+    /* The magnitude of `x' is greater than or equal to 1.0...
+     * reserve space in the output field, for the required number of
+     * decimal digits to be placed before the decimal point...
+     */
+    if( stream->width >= len)
+      /*
+       * adjusting as appropriate, when width is sufficient...
+       */
+      stream->width -= len;
+
+    else
+      /* or simply ignoring the width specification, if not.
+       */
+      stream->width = PFORMAT_IGNORE;
+  }
+
+  else if( stream->width > 0 )
+    /*
+     * The magnitude of `x' is less than 1.0...
+     * reserve space for exactly one zero before the decimal point.
+     */
+    stream->width--;
+
+  /* Reserve additional space for the digits which will follow the
+   * decimal point...
+   */
+  if( (stream->width >= 0) && (stream->width > stream->precision) )
+    /*
+     * adjusting appropriately, when sufficient width remains...
+     * (note that we must check both of these conditions, because
+     * precision may be more negative than width, as a result of
+     * adjustment to provide extra padding when trailing zeros
+     * are to be discarded from "%g" format conversion with a
+     * specified field width, but if width itself is negative,
+     * then there is explicitly to be no padding anyway).
+     */
+    stream->width -= stream->precision;
+
+  else
+    /* or again, ignoring the width specification, if not.
+     */
+    stream->width = PFORMAT_IGNORE;
+
+  /* Reserve space in the output field, for display of the decimal point,
+   * unless the precision is explicity zero, with the `#' flag not set.
+   */
+  if ((stream->width > 0)
+      && ((stream->precision > 0) || (stream->flags & PFORMAT_HASHED)))
+    stream->width--;
+
+  if (len > 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
+    {
+      int cths = ((len + 2) / 3) - 1;
+      while (cths > 0 && stream->width > 0)
+        {
+          --cths; stream->width--;
+        }
+    }
+
+  /* Reserve space in the output field, for display of the sign of the
+   * formatted value, if required; (i.e. if the value is negative, or if
+   * either the `space' or `+' formatting flags are set).
+   */
+  if( (stream->width > 0) && (sign || (stream->flags & PFORMAT_SIGNED)) )
+    stream->width--;
+
+  /* Emit any padding space, as required to correctly right justify
+   * the output within the alloted field width.
+   */
+  if( (stream->width > 0) && ((stream->flags & PFORMAT_JUSTIFY) == 0) )
+    while( stream->width-- > 0 )
+      __pformat_putc( '\x20', stream );
+
+  /* Emit the sign indicator, as appropriate...
+   */
+  if( sign )
+    /*
+     * mandatory, for negative values...
+     */
+    __pformat_putc( '-', stream );
+
+  else if( stream->flags & PFORMAT_POSITIVE )
+    /*
+     * optional, for positive values...
+     */
+    __pformat_putc( '+', stream );
+
+  else if( stream->flags & PFORMAT_ADDSPACE )
+    /*
+     * or just fill reserved space, when the space flag is in effect.
+     */
+    __pformat_putc( '\x20', stream );
+
+  /* If the `0' flag is in effect, and not overridden by the `-' flag,
+   * then zero padding, to fill out the field, goes here...
+   */
+  if(  (stream->width > 0)
+  &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
+    while( stream->width-- > 0 )
+      __pformat_putc( '0', stream );
+
+  /* Emit the digits of the encoded numeric value...
+   */
+  if( len > 0 )
+  {
+    /*
+     * ...beginning with those which precede the radix point,
+     * and appending any necessary significant trailing zeros.
+     */
+    do {
+      __pformat_putc( *value ? *value++ : '0', stream);
+      --len;
+      if (len != 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
+          && (len % 3) == 0)
+        __pformat_wputchars (&stream->thousands_chr, 1, stream);
+    }
+    while (len > 0);
+  }
+  else
+    /* The magnitude of the encoded value is less than 1.0, so no
+     * digits precede the radix point; we emit a mandatory initial
+     * zero, followed immediately by the radix point.
+     */
+    __pformat_putc( '0', stream );
+
+  /* Unless the encoded value is integral, AND the radix point
+   * is not expressly demanded by the `#' flag, we must insert
+   * the appropriately localised radix point mark here...
+   */
+  if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
+    __pformat_emit_radix_point( stream );
+
+  /* When the radix point offset, `len', is negative, this implies
+   * that additional zeros must appear, following the radix point,
+   * and preceding the first significant digit...
+   */
+  if( len < 0 )
+  {
+    /* To accommodate these, we adjust the precision, (reducing it
+     * by adding a negative value), and then we emit as many zeros
+     * as are required.
+     */
+    stream->precision += len;
+    do __pformat_putc( '0', stream );
+       while( ++len < 0 );
+  }
+
+  /* Now we emit any remaining significant digits, or trailing zeros,
+   * until the required precision has been achieved.
+   */
+  while( stream->precision-- > 0 )
+    __pformat_putc( *value ? *value++ : '0', stream );
+}
+
+static
+void __pformat_emit_efloat( int sign, char *value, int e, __pformat_t *stream )
+{
+  /* Helper to emit a floating point representation of numeric data,
+   * as encoded by a prior call to `ecvt()' or `fcvt()'; (this DOES
+   * include the following exponent).
+   */
+  int exp_width = 1;
+  __pformat_intarg_t exponent; exponent.__pformat_llong_t = e -= 1;
+
+  /* Determine how many digit positions are required for the exponent.
+   */
+  while( (e /= 10) != 0 )
+    exp_width++;
+
+  /* Ensure that this is at least as many as the standard requirement.
+   * The C99 standard requires the expenent to contain at least two
+   * digits, unless specified explicitly otherwise.
+   */
+  if (stream->expmin == -1)
+    stream->expmin = 2;
+  if( exp_width < stream->expmin )
+    exp_width = stream->expmin;
+
+  /* Adjust the residual field width allocation, to allow for the
+   * number of exponent digits to be emitted, together with a sign
+   * and exponent separator...
+   */
+  if( stream->width > (exp_width += 2) )
+    stream->width -= exp_width;
+
+  else
+    /* ignoring the field width specification, if insufficient.
+     */
+    stream->width = PFORMAT_IGNORE;
+
+  /* Emit the significand, as a fixed point value with one digit
+   * preceding the radix point.
+   */
+  __pformat_emit_float( sign, value, 1, stream );
+
+  /* Reset precision, to ensure the mandatory minimum number of
+   * exponent digits will be emitted, and set the flags to ensure
+   * the sign is displayed.
+   */
+  stream->precision = stream->expmin;
+  stream->flags |= PFORMAT_SIGNED;
+
+  /* Emit the exponent separator.
+   */
+  __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
+
+  /* Readjust the field width setting, such that it again allows
+   * for the digits of the exponent, (which had been discounted when
+   * computing any left side padding requirement), so that they are
+   * correctly included in the computation of any right side padding
+   * requirement, (but here we exclude the exponent separator, which
+   * has been emitted, and so counted already).
+   */
+  stream->width += exp_width - 1;
+
+  /* And finally, emit the exponent itself, as a signed integer,
+   * with any padding required to achieve flush left justification,
+   * (which will be added automatically, by `__pformat_int()').
+   */
+  __pformat_int( exponent, stream );
+}
+
+static
+void __pformat_float( long double x, __pformat_t *stream )
+{
+  /* Handler for `%f' and `%F' format specifiers.
+   *
+   * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()'
+   * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
+   * output in fixed point format.
+   */
+  int sign, intlen; char *value;
+
+  /* Establish the precision for the displayed value, defaulting to six
+   * digits following the decimal point, if not explicitly specified.
+   */
+  if( stream->precision < 0 )
+    stream->precision = 6;
+
+  /* Encode the input value as ASCII, for display...
+   */
+  value = __pformat_fcvt( x, stream->precision, &intlen, &sign );
+
+  if( intlen == PFORMAT_INFNAN )
+    /*
+     * handle cases of `infinity' or `not-a-number'...
+     */
+    __pformat_emit_inf_or_nan( sign, value, stream );
+
+  else
+  { /* or otherwise, emit the formatted result.
+     */
+    __pformat_emit_float( sign, value, intlen, stream );
+
+    /* and, if there is any residual field width as yet unfilled,
+     * then we must be doing flush left justification, so pad out to
+     * the right hand field boundary.
+     */
+    while( stream->width-- > 0 )
+      __pformat_putc( '\x20', stream );
+  }
+
+  /* Clean up `__pformat_fcvt()' memory allocation for `value'...
+   */
+  __pformat_fcvt_release( value );
+}
+
+#ifdef __ENABLE_DFP
+
+typedef struct decimal128_decode {
+  int64_t significand[2];
+  int32_t exponent;
+  int sig_neg;
+  int exp_neg;
+} decimal128_decode;
+
+static uint32_t dec128_decode(decimal128_decode *result, const _Decimal128 deci){
+  int64_t significand2;
+  int64_t significand1;
+  int32_t exp_part;
+  int8_t sig_sign;
+  ud128 in;
+  in.d = deci;
+
+  if(in.t0.bits == 0x3){ /*case 11 */
+    /* should not enter here */
+    sig_sign = in.t2.sign;
+    exp_part = in.t2.exponent;
+    significand1 = in.t2.mantissaL;
+    significand2 = (in.t2.mantissaH | (0x1ULL << 49));
+  } else {
+    sig_sign = in.t1.sign;
+    exp_part = in.t1.exponent;
+    significand1 = in.t1.mantissaL;
+    significand2 = in.t1.mantissaH;
+  }
+  exp_part -= 6176; /* exp bias */
+
+  result->significand[0] = significand1;
+  result->significand[1] = significand2; /* higher */
+  result->exponent = exp_part;
+  result->exp_neg = (exp_part < 0 )? 1 : 0;
+  result->sig_neg = sig_sign;
+
+  return 0;
+}
+
+static
+void  __pformat_efloat_decimal(_Decimal128 x, __pformat_t *stream ){
+  decimal128_decode in;
+  char str_exp[8];
+  char str_sig[40];
+  int floatclass = __fpclassifyd128(x);
+
+  /* precision control */
+  int32_t prec = ( (stream->precision < 0) || (stream->precision > 38) ) ?
+    6 : stream->precision;
+  int32_t max_prec;
+  int32_t exp_strlen;
+
+  dec128_decode(&in,x);
+
+  if((floatclass & FP_INFINITE) == FP_INFINITE){
+    stream->precision = 3;
+    if(stream->flags & PFORMAT_SIGNED)
+      __pformat_putc( in.sig_neg ? '-' : '+', stream );
+    __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "inf" : "INF", stream);
+    return;
+  } else if(floatclass & FP_NAN){
+    stream->precision = 3;
+    if(stream->flags & PFORMAT_SIGNED)
+      __pformat_putc( in.sig_neg ? '-' : '+', stream );
+    __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "nan" : "NAN", stream);
+    return;
+  }
+
+  /* Stringify significand */
+  __bigint_to_string(
+    (uint32_t[4]){in.significand[0] & 0x0ffffffff, in.significand[0] >> 32, in.significand[1] & 0x0ffffffff, in.significand[1] >> 32 },
+    4, str_sig, sizeof(str_sig));
+  __bigint_trim_leading_zeroes(str_sig,1);
+  max_prec = strlen(str_sig+1);
+
+  /* Try to canonize exponent */
+  in.exponent += max_prec;
+  in.exp_neg = (in.exponent < 0 ) ? 1 : 0;
+
+  /* stringify exponent */
+  __bigint_to_string(
+    (uint32_t[1]) { in.exp_neg ? -in.exponent : in.exponent},
+    1, str_exp, sizeof(str_exp));
+  exp_strlen = strlen(__bigint_trim_leading_zeroes(str_exp,3));
+
+  /* account for dot, +-e */
+  for(int32_t spacers = 0; spacers < stream->width - max_prec - exp_strlen - 4; spacers++)
+    __pformat_putc( ' ', stream );
+
+  /* optional sign */
+  if (in.sig_neg || (stream->flags & PFORMAT_SIGNED)) {
+    __pformat_putc( in.sig_neg ? '-' : '+', stream );
+  } else if( stream->width - max_prec - exp_strlen - 4 > 0 ) {
+    __pformat_putc( ' ', stream );
+  }
+  stream->width = 0;
+  /* s.sss form */
+  __pformat_putc(str_sig[0], stream);
+  if(prec) {
+    /* str_sig[prec+1] = '\0';*/
+    __pformat_emit_radix_point(stream);
+    __pformat_putchars(str_sig+1, prec, stream);
+
+    /* Pad with 0s */
+    for(int i = max_prec; i < prec; i++)
+      __pformat_putc('0', stream);
+  }
+
+  stream->precision = exp_strlen; /* force puts to emit */
+
+  __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
+  __pformat_putc( in.exp_neg ? '-' : '+', stream );
+
+  for(int32_t trailing = 0; trailing < 3 - exp_strlen; trailing++)
+    __pformat_putc('0', stream);
+  __pformat_putchars(str_exp, exp_strlen,stream);
+}
+
+static
+void  __pformat_float_decimal(_Decimal128 x, __pformat_t *stream ){
+  decimal128_decode in;
+  char str_exp[8];
+  char str_sig[40];
+  int floatclass = __fpclassifyd128(x);
+
+  /* precision control */
+  int prec = ( (stream->precision < 0) || (stream->precision > 38) ) ?
+    6 : stream->precision;
+  int max_prec;
+
+  dec128_decode(&in,x);
+
+  if((floatclass & FP_INFINITE) == FP_INFINITE){
+    stream->precision = 3;
+    if(stream->flags & PFORMAT_SIGNED)
+      __pformat_putc( in.sig_neg ? '-' : '+', stream );
+    __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "inf" : "INF", stream);
+    return;
+  } else if(floatclass & FP_NAN){
+    stream->precision = 3;
+    if(stream->flags & PFORMAT_SIGNED)
+      __pformat_putc( in.sig_neg ? '-' : '+', stream );
+    __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "nan" : "NAN", stream);
+    return;
+  }
+
+  /* Stringify significand */
+  __bigint_to_string(
+    (uint32_t[4]){in.significand[0] & 0x0ffffffff, in.significand[0] >> 32, in.significand[1] & 0x0ffffffff, in.significand[1] >> 32 },
+    4, str_sig, sizeof(str_sig));
+  __bigint_trim_leading_zeroes(str_sig,0);
+  max_prec = strlen(str_sig);
+
+  /* stringify exponent */
+  __bigint_to_string(
+    (uint32_t[1]) { in.exp_neg ? -in.exponent : in.exponent},
+    1, str_exp, sizeof(str_exp));
+  __bigint_trim_leading_zeroes(str_exp,0);
+
+  int32_t decimal_place = max_prec + in.exponent;
+  int32_t sig_written = 0;
+
+  /*account for . +- */
+  for(int32_t spacers = 0; spacers < stream->width - decimal_place - prec - 2; spacers++)
+    __pformat_putc( ' ', stream );
+
+  if (in.sig_neg || (stream->flags & PFORMAT_SIGNED)) {
+    __pformat_putc( in.sig_neg ? '-' : '+', stream );
+  } else if(stream->width - decimal_place - prec - 1 > 0){
+    __pformat_putc( ' ', stream );
+  }
+
+  if(decimal_place <= 0){ /* easy mode */
+    __pformat_putc( '0', stream );
+    points:
+    __pformat_emit_radix_point(stream);
+    for(int32_t written = 0; written < prec; written++){
+      if(decimal_place < 0){ /* leading 0s */
+        decimal_place++;
+        __pformat_putc( '0', stream );
+      /* significand */
+      } else if ( sig_written < max_prec ){
+        __pformat_putc( str_sig[sig_written], stream );
+        sig_written++;
+      } else { /* trailing 0s */
+        __pformat_putc( '0', stream );
+      }
+    }
+  } else { /* hard mode */
+    for(; sig_written < decimal_place; sig_written++){
+      __pformat_putc( str_sig[sig_written], stream );
+      if(sig_written == max_prec - 1) break;
+    }
+    decimal_place -= sig_written;
+    for(; decimal_place > 0; decimal_place--)
+      __pformat_putc( '0', stream );
+      goto points;
+  }
+
+  return;
+}
+
+static
+void  __pformat_gfloat_decimal(_Decimal128 x, __pformat_t *stream ){
+  int prec = ( (stream->precision < 0)) ?
+    6 : stream->precision;
+  decimal128_decode in;
+  dec128_decode(&in,x);
+  if(in.exponent > prec) __pformat_efloat_decimal(x,stream);
+  else __pformat_float_decimal(x,stream);
+}
+
+#endif /* __ENABLE_DFP */
+
+static
+void __pformat_efloat( long double x, __pformat_t *stream )
+{
+  /* Handler for `%e' and `%E' format specifiers.
+   *
+   * This wraps calls to `__pformat_cvt()', `__pformat_emit_efloat()'
+   * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
+   * output in floating point format.
+   */
+  int sign, intlen; char *value;
+
+  /* Establish the precision for the displayed value, defaulting to six
+   * digits following the decimal point, if not explicitly specified.
+   */
+  if( stream->precision < 0 )
+    stream->precision = 6;
+
+  /* Encode the input value as ASCII, for display...
+   */
+  value = __pformat_ecvt( x, stream->precision + 1, &intlen, &sign );
+
+  if( intlen == PFORMAT_INFNAN )
+    /*
+     * handle cases of `infinity' or `not-a-number'...
+     */
+    __pformat_emit_inf_or_nan( sign, value, stream );
+
+  else
+    /* or otherwise, emit the formatted result.
+     */
+    __pformat_emit_efloat( sign, value, intlen, stream );
+
+  /* Clean up `__pformat_ecvt()' memory allocation for `value'...
+   */
+  __pformat_ecvt_release( value );
+}
+
+static
+void __pformat_gfloat( long double x, __pformat_t *stream )
+{
+  /* Handler for `%g' and `%G' format specifiers.
+   *
+   * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()',
+   * `__pformat_emit_efloat()' and `__pformat_emit_inf_or_nan()', as
+   * appropriate, to achieve output in the more suitable of either
+   * fixed or floating point format.
+   */
+  int sign, intlen; char *value;
+
+  /* Establish the precision for the displayed value, defaulting to
+   * six significant digits, if not explicitly specified...
+   */
+  if( stream->precision < 0 )
+    stream->precision = 6;
+
+  /* or to a minimum of one digit, otherwise...
+   */
+  else if( stream->precision == 0 )
+    stream->precision = 1;
+
+  /* Encode the input value as ASCII, for display.
+   */
+  value = __pformat_ecvt( x, stream->precision, &intlen, &sign );
+
+  if( intlen == PFORMAT_INFNAN )
+    /*
+     * Handle cases of `infinity' or `not-a-number'.
+     */
+    __pformat_emit_inf_or_nan( sign, value, stream );
+
+  else if( (-4 < intlen) && (intlen <= stream->precision) )
+  {
+    /* Value lies in the acceptable range for fixed point output,
+     * (i.e. the exponent is no less than minus four, and the number
+     * of significant digits which precede the radix point is fewer
+     * than the least number which would overflow the field width,
+     * specified or implied by the established precision).
+     */
+    if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
+      /*
+       * The `#' flag is in effect...
+       * Adjust precision to retain the specified number of significant
+       * digits, with the proper number preceding the radix point, and
+       * the balance following it...
+       */
+      stream->precision -= intlen;
+
+    else
+      /* The `#' flag is not in effect...
+       * Here we adjust the precision to accommodate all digits which
+       * precede the radix point, but we truncate any balance following
+       * it, to suppress output of non-significant trailing zeros...
+       */
+      if( ((stream->precision = strlen( value ) - intlen) < 0)
+        /*
+         * This may require a compensating adjustment to the field
+         * width, to accommodate significant trailing zeros, which
+         * precede the radix point...
+         */
+      && (stream->width > 0)  )
+        stream->width += stream->precision;
+
+    /* Now, we format the result as any other fixed point value.
+     */
+    __pformat_emit_float( sign, value, intlen, stream );
+
+    /* If there is any residual field width as yet unfilled, then
+     * we must be doing flush left justification, so pad out to the
+     * right hand field boundary.
+     */
+    while( stream->width-- > 0 )
+      __pformat_putc( '\x20', stream );
+  }
+
+  else
+  { /* Value lies outside the acceptable range for fixed point;
+     * one significant digit will precede the radix point, so we
+     * decrement the precision to retain only the appropriate number
+     * of additional digits following it, when we emit the result
+     * in floating point format.
+     */
+    if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
+      /*
+       * The `#' flag is in effect...
+       * Adjust precision to emit the specified number of significant
+       * digits, with one preceding the radix point, and the balance
+       * following it, retaining any non-significant trailing zeros
+       * which are required to exactly match the requested precision...
+       */
+      stream->precision--;
+
+    else
+      /* The `#' flag is not in effect...
+       * Adjust precision to emit only significant digits, with one
+       * preceding the radix point, and any others following it, but
+       * suppressing non-significant trailing zeros...
+       */
+      stream->precision = strlen( value ) - 1;
+
+    /* Now, we format the result as any other floating point value.
+     */
+    __pformat_emit_efloat( sign, value, intlen, stream );
+  }
+
+  /* Clean up `__pformat_ecvt()' memory allocation for `value'.
+   */
+  __pformat_ecvt_release( value );
+}
+
+static
+void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
+{
+  /* Helper for emitting floating point data, originating as
+   * either `double' or `long double' type, as a hexadecimal
+   * representation of the argument value.
+   */
+  char buf[18 + 6], *p = buf;
+  __pformat_intarg_t exponent; short exp_width = 2;
+
+  if (value.__pformat_fpreg_mantissa != 0 ||
+     value.__pformat_fpreg_exponent != 0)
+  {
+    /* Reduce the exponent since the leading digit emited will start at
+     * the 4th bit from the highest order bit instead, the later being
+     * the leading digit of the floating point. Don't do this adjustment
+     * if the value is an actual zero.
+     */
+    value.__pformat_fpreg_exponent -= 3;
+  }
+
+  /* The mantissa field of the argument value representation can
+   * accommodate at most 16 hexadecimal digits, of which one will
+   * be placed before the radix point, leaving at most 15 digits
+   * to satisfy any requested precision; thus...
+   */
+  if( (stream->precision >= 0) && (stream->precision < 15) )
+  {
+    /* When the user specifies a precision within this range,
+     * we want to adjust the mantissa, to retain just the number
+     * of digits required, rounding up when the high bit of the
+     * leftmost discarded digit is set; (mask of 0x08 accounts
+     * for exactly one digit discarded, shifting 4 bits per
+     * digit, with up to 14 additional digits, to consume the
+     * full availability of 15 precision digits).
+     */
+
+    /* We then shift the mantissa one bit position back to the
+     * right, to guard against possible overflow when the rounding
+     * adjustment is added.
+     */
+    value.__pformat_fpreg_mantissa >>= 1;
+
+    /* We now add the rounding adjustment, noting that to keep the
+     * 0x08 mask aligned with the shifted mantissa, we also need to
+     * shift it right by one bit initially, changing its starting
+     * value to 0x04...
+     */
+    value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision));
+    if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL )
+      /*
+       * When the rounding adjustment would not have overflowed,
+       * then we shift back to the left again, to fill the vacated
+       * bit we reserved to accommodate the carry.
+       */
+      value.__pformat_fpreg_mantissa <<= 1;
+
+    else
+    {
+      /* Otherwise the rounding adjustment would have overflowed,
+       * so the carry has already filled the vacated bit; the effect
+       * of this is equivalent to an increment of the exponent. We will
+       * discard a whole digit to match glibc's behavior.
+       */
+      value.__pformat_fpreg_exponent += 4;
+      value.__pformat_fpreg_mantissa >>= 3;
+    }
+
+    /* We now complete the rounding to the required precision, by
+     * shifting the unwanted digits out, from the right hand end of
+     * the mantissa.
+     */
+    value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision);
+  }
+
+  /* Don't print anything if mantissa is zero unless we have to satisfy
+   * desired precision.
+   */
+  if( value.__pformat_fpreg_mantissa || stream->precision > 0 )
+  {
+    /* Encode the significant digits of the mantissa in hexadecimal
+     * ASCII notation, ready for transfer to the output stream...
+     */
+    for( int i=stream->precision >= 15 || stream->precision < 0 ? 16 : stream->precision + 1; i>0; --i )
+    {
+      /* taking the rightmost digit in each pass...
+       */
+      unsigned c = value.__pformat_fpreg_mantissa & 0xF;
+      if( i == 1 )
+      {
+        /* inserting the radix point, when we reach the last,
+         * (i.e. the most significant digit), unless we found no
+         * less significant digits, with no mandatory radix point
+         * inclusion, and no additional required precision...
+         */
+        if( (p > buf)
+        ||  (stream->flags & PFORMAT_HASHED) || (stream->precision > 0)  )
+        {
+          /*
+           * Internally, we represent the radix point as an ASCII '.';
+           * we will replace it with any locale specific alternative,
+           * at the time of transfer to the ultimate destination.
+           */
+          *p++ = '.';
+        }
+      }
+
+      else if( stream->precision > 0 )
+        /*
+        * we have not yet fulfilled the desired precision,
+        * and we have not yet found the most significant digit,
+        * so account for the current digit, within the field
+        * width required to meet the specified precision.
+        */
+        stream->precision--;
+
+      if( (c > 0) || (p > buf) || (stream->precision >= 0) )
+      {
+        /*
+         * Ignoring insignificant trailing zeros, (unless required to
+         * satisfy specified precision), store the current encoded digit
+         * into the pending output buffer, in LIFO order, and using the
+         * appropriate case for digits in the `A'..`F' range.
+         */
+        *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0';
+      }
+      /* Shift out the current digit, (4-bit logical shift right),
+       * to align the next more significant digit to be extracted,
+       * and encoded in the next pass.
+       */
+      value.__pformat_fpreg_mantissa >>= 4;
+    }
+  }
+
+  if( p == buf )
+  {
+    /* Nothing has been queued for output...
+     * We need at least one zero, and possibly a radix point.
+     */
+    if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
+      *p++ = '.';
+
+    *p++ = '0';
+  }
+
+  if( stream->width > 0 )
+  {
+  /* Adjust the user specified field width, to account for the
+   * number of digits minimally required, to display the encoded
+   * value, at the requested precision.
+   *
+   * FIXME: this uses the minimum number of digits possible for
+   * representation of the binary exponent, in strict conformance
+   * with C99 and POSIX specifications.  Although there appears to
+   * be no Microsoft precedent for doing otherwise, we may wish to
+   * relate this to the `_get_output_format()' result, to maintain
+   * consistency with `%e', `%f' and `%g' styles.
+   */
+    int min_width = p - buf;
+    int exponent2 = value.__pformat_fpreg_exponent;
+
+    /* If we have not yet queued sufficient digits to fulfil the
+     * requested precision, then we must adjust the minimum width
+     * specification, to accommodate the additional digits which
+     * are required to do so.
+     */
+    if( stream->precision > 0 )
+      min_width += stream->precision;
+
+    /* Adjust the minimum width requirement, to accomodate the
+     * sign, radix indicator and at least one exponent digit...
+     */
+    min_width += stream->flags & PFORMAT_SIGNED ? 6 : 5;
+    while( (exponent2 = exponent2 / 10) != 0 )
+    {
+      /* and increase as required, if additional exponent digits
+       * are needed, also saving the exponent field width adjustment,
+       * for later use when that is emitted.
+       */
+      min_width++;
+      exp_width++;
+    }
+
+    if( stream->width > min_width )
+    {
+      /* When specified field width exceeds the minimum required,
+       * adjust to retain only the excess...
+       */
+      stream->width -= min_width;
+
+      /* and then emit any required left side padding spaces.
+       */
+      if( (stream->flags & PFORMAT_JUSTIFY) == 0 )
+        while( stream->width-- > 0 )
+          __pformat_putc( '\x20', stream );
+    }
+
+    else
+      /* Specified field width is insufficient; just ignore it!
+       */
+      stream->width = PFORMAT_IGNORE;
+  }
+
+  /* Emit the sign of the encoded value, as required...
+   */
+  if( stream->flags & PFORMAT_NEGATIVE )
+    /*
+     * this is mandatory, to indicate a negative value...
+     */
+    __pformat_putc( '-', stream );
+
+  else if( stream->flags & PFORMAT_POSITIVE )
+    /*
+     * but this is optional, for a positive value...
+     */
+    __pformat_putc( '+', stream );
+
+  else if( stream->flags & PFORMAT_ADDSPACE )
+    /*
+     * with this optional alternative.
+     */
+    __pformat_putc( '\x20', stream );
+
+  /* Prefix a `0x' or `0X' radix indicator to the encoded value,
+   * with case appropriate to the format specification.
+   */
+  __pformat_putc( '0', stream );
+  __pformat_putc( 'X' | (stream->flags & PFORMAT_XCASE), stream );
+
+  /* If the `0' flag is in effect...
+   * Zero padding, to fill out the field, goes here...
+   */
+  if( (stream->width > 0) && (stream->flags & PFORMAT_ZEROFILL) )
+    while( stream->width-- > 0 )
+      __pformat_putc( '0', stream );
+
+  /* Next, we emit the encoded value, without its exponent...
+   */
+  while( p > buf )
+    __pformat_emit_numeric_value( *--p, stream );
+
+  /* followed by any additional zeros needed to satisfy the
+   * precision specification...
+   */
+  while( stream->precision-- > 0 )
+    __pformat_putc( '0', stream );
+
+  /* then the exponent prefix, (C99 and POSIX specify `p'),
+   * in the case appropriate to the format specification...
+   */
+  __pformat_putc( 'P' | (stream->flags & PFORMAT_XCASE), stream );
+
+  /* and finally, the decimal representation of the binary exponent,
+   * as a signed value with mandatory sign displayed, in a field width
+   * adjusted to accommodate it, LEFT justified, with any additional
+   * right side padding remaining from the original field width.
+   */
+  stream->width += exp_width;
+  stream->flags |= PFORMAT_SIGNED;
+  /* sign extend */
+  exponent.__pformat_u128_t.t128.digits[1] = (value.__pformat_fpreg_exponent < 0) ? -1 : 0;
+  exponent.__pformat_u128_t.t128.digits[0] = value.__pformat_fpreg_exponent;
+  __pformat_int( exponent, stream );
+}
+
+static
+void __pformat_xldouble( long double x, __pformat_t *stream )
+{
+  /* Handler for `%La' and `%LA' format specifiers, (with argument
+   * value specified as `long double' type).
+   */
+  unsigned sign_bit = 0;
+  __pformat_fpreg_t z = init_fpreg_ldouble( x );
+
+  /* First check for NaN; it is emitted unsigned...
+   */
+  if( isnan( x ) )
+    __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
+
+  else
+  { /* Capture the sign bit up-front, so we can show it correctly
+     * even when the argument value is zero or infinite.
+     */
+    if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
+      stream->flags |= PFORMAT_NEGATIVE;
+
+    /* Check for infinity, (positive or negative)...
+     */
+    if( isinf( x ) )
+      /*
+       * displaying the appropriately signed indicator,
+       * when appropriate.
+       */
+      __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
+
+    else
+    { /* The argument value is a representable number...
+       * extract the effective value of the biased exponent...
+       */
+      z.__pformat_fpreg_exponent &= 0x7FFF;
+      if( z.__pformat_fpreg_exponent == 0 )
+      {
+        /* A biased exponent value of zero means either a
+         * true zero value, if the mantissa field also has
+         * a zero value, otherwise...
+         */
+        if( z.__pformat_fpreg_mantissa != 0 )
+        {
+          /* ...this mantissa represents a subnormal value.
+           */
+          z.__pformat_fpreg_exponent = 1 - 0x3FFF;
+        }
+      }
+      else
+        /* This argument represents a non-zero normal number;
+         * eliminate the bias from the exponent...
+         */
+        z.__pformat_fpreg_exponent -= 0x3FFF;
+
+      /* Finally, hand the adjusted representation off to the
+       * generalised hexadecimal floating point format handler...
+       */
+      __pformat_emit_xfloat( z, stream );
+    }
+  }
+}
+
+static
+void __pformat_xdouble( double x, __pformat_t *stream )
+{
+  /* Handler for `%la' and `%lA' format specifiers, (with argument
+   * value specified as `double' type).
+   */
+  unsigned sign_bit = 0;
+  __pformat_fpreg_t z = init_fpreg_ldouble( (long double)x );
+
+  /* First check for NaN; it is emitted unsigned...
+   */
+  if( isnan( x ) )
+    __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
+
+  else
+  { /* Capture the sign bit up-front, so we can show it correctly
+     * even when the argument value is zero or infinite.
+     */
+    if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
+      stream->flags |= PFORMAT_NEGATIVE;
+
+    /* Check for infinity, (positive or negative)...
+     */
+    if( isinf( x ) )
+      /*
+       * displaying the appropriately signed indicator,
+       * when appropriate.
+       */
+      __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
+
+    else
+    { /* The argument value is a representable number...
+       * extract the effective value of the biased exponent...
+       */
+      z.__pformat_fpreg_exponent &= 0x7FFF;
+
+      /* If the double value was a denormalized number, it might have been renormalized by
+       * the conversion to long double. We will redenormalize it.
+       */
+      if( z.__pformat_fpreg_exponent != 0 && z.__pformat_fpreg_exponent <= (0x3FFF - 0x3FF) )
+      {
+        int shifted = (0x3FFF - 0x3FF) - z.__pformat_fpreg_exponent + 1;
+        z.__pformat_fpreg_mantissa >>= shifted;
+        z.__pformat_fpreg_exponent += shifted;
+      }
+
+      if( z.__pformat_fpreg_exponent == 0 )
+      {
+        /* A biased exponent value of zero means either a
+         * true zero value, if the mantissa field also has
+         * a zero value, otherwise...
+         */
+        if( z.__pformat_fpreg_mantissa != 0 )
+        {
+          /* ...this mantissa represents a subnormal value.
+           */
+          z.__pformat_fpreg_exponent = 1 - 0x3FF + 3;
+        }
+      }
+      else
+        /* This argument represents a non-zero normal number;
+         * eliminate the bias from the exponent...
+         */
+        z.__pformat_fpreg_exponent -= 0x3FFF - 3;
+
+      /* Shift the mantissa so the leading 4 bits digit is 0 or 1.
+       * The exponent was also adjusted by 3 previously.
+       */
+      z.__pformat_fpreg_mantissa >>= 3;
+
+      /* Finally, hand the adjusted representation off to the
+       * generalised hexadecimal floating point format handler...
+       */
+      __pformat_emit_xfloat( z, stream );
+    }
+  }
+}
+
+int
+__pformat (int flags, void *dest, int max, const APICHAR *fmt, va_list argv)
+{
+  int c;
+  int saved_errno = errno;
+
+  __pformat_t stream =
+  {
+    /* Create and initialise a format control block
+     * for this output request.
+     */
+    dest,                                       /* output goes to here        */
+    flags &= PFORMAT_TO_FILE | PFORMAT_NOLIMIT, /* only these valid initially */
+    PFORMAT_IGNORE,                             /* no field width yet         */
+    PFORMAT_IGNORE,                             /* nor any precision spec     */
+    PFORMAT_RPINIT,                             /* radix point uninitialised  */
+    (wchar_t)(0),                               /* leave it unspecified       */
+    0,
+    (wchar_t)(0),                               /* leave it unspecified       */
+    0,                                          /* zero output char count     */
+    max,                                        /* establish output limit     */
+    -1                                          /* exponent chars preferred;
+                                                   -1 means to be determined. */
+  };
+
+#ifdef __BUILD_WIDEAPI
+  const APICHAR *literal_string_start = NULL;
+#endif
+
+  format_scan: while( (c = *fmt++) != 0 )
+  {
+    /* Format string parsing loop...
+     * The entry point is labelled, so that we can return to the start state
+     * from within the inner `conversion specification' interpretation loop,
+     * as soon as a conversion specification has been resolved.
+     */
+    if( c == '%' )
+    {
+      /* Initiate parsing of a `conversion specification'...
+       */
+      __pformat_intarg_t argval;
+      __pformat_state_t  state = PFORMAT_INIT;
+      __pformat_length_t length = PFORMAT_LENGTH_INT;
+
+      /* Save the current format scan position, so that we can backtrack
+       * in the event of encountering an invalid format specification...
+       */
+      const APICHAR *backtrack = fmt;
+
+      /* Restart capture for dynamic field width and precision specs...
+       */
+      int *width_spec = &stream.width;
+
+  #ifdef __BUILD_WIDEAPI
+      if (literal_string_start)
+      {
+        stream.width = stream.precision = PFORMAT_IGNORE;
+        __pformat_wputchars( literal_string_start, fmt - literal_string_start - 1, &stream );
+        literal_string_start = NULL;
+      }
+  #endif
+
+      /* Reset initial state for flags, width and precision specs...
+       */
+      stream.flags = flags;
+      stream.width = stream.precision = PFORMAT_IGNORE;
+
+      while( *fmt )
+      {
+        switch( c = *fmt++ )
+        {
+          /* Data type specifiers...
+           * All are terminal, so exit the conversion spec parsing loop
+           * with a `goto format_scan', thus resuming at the outer level
+           * in the regular format string parser.
+           */
+          case '%':
+            /*
+             * Not strictly a data type specifier...
+             * it simply converts as a literal `%' character.
+             *
+             * FIXME: should we require this to IMMEDIATELY follow the
+             * initial `%' of the "conversion spec"?  (glibc `printf()'
+             * on GNU/Linux does NOT appear to require this, but POSIX
+             * and SUSv3 do seem to demand it).
+             */
+    #ifndef __BUILD_WIDEAPI
+            __pformat_putc( c, &stream );
+    #else
+        stream.width = stream.precision = PFORMAT_IGNORE;
+        __pformat_wputchars( L"%", 1, &stream );
+    #endif
+            goto format_scan;
+
+          case 'C':
+            /*
+             * Equivalent to `%lc'; set `length' accordingly,
+             * and simply fall through.
+             */
+            length = PFORMAT_LENGTH_LONG;
+
+            /* fallthrough */
+
+          case 'c':
+            /*
+             * Single, (or single multibyte), character output...
+             *
+             * We handle these by copying the argument into our local
+             * `argval' buffer, and then we pass the address of that to
+             * either `__pformat_putchars()' or `__pformat_wputchars()',
+             * as appropriate, effectively formatting it as a string of
+             * the appropriate type, with a length of one.
+             *
+             * A side effect of this method of handling character data
+             * is that, if the user sets a precision of zero, then no
+             * character is actually emitted; we don't want that, so we
+             * forcibly override any user specified precision.
+             */
+            stream.precision = PFORMAT_IGNORE;
+
+            /* Now we invoke the appropriate format handler...
+             */
+            if( (length == PFORMAT_LENGTH_LONG)
+            ||  (length == PFORMAT_LENGTH_LLONG)  )
+            {
+              /* considering any `long' type modifier as a reference to
+               * `wchar_t' data, (which is promoted to an `int' argument)...
+               */
+              wchar_t iargval = (wchar_t)(va_arg( argv, int ));
+              __pformat_wputchars( &iargval, 1, &stream );
+            }
+            else
+            { /* while anything else is simply taken as `char', (which
+               * is also promoted to an `int' argument)...
+               */
+              argval.__pformat_uchar_t = (unsigned char)(va_arg( argv, int ));
+              __pformat_putchars( (char *)(&argval), 1, &stream );
+            }
+            goto format_scan;
+
+          case 'S':
+            /*
+             * Equivalent to `%ls'; set `length' accordingly,
+             * and simply fall through.
+             */
+            length = PFORMAT_LENGTH_LONG;
+
+            /* fallthrough */
+
+          case 's':
+            if( (length == PFORMAT_LENGTH_LONG)
+                 || (length == PFORMAT_LENGTH_LLONG))
+            {
+              /* considering any `long' type modifier as a reference to
+               * a `wchar_t' string...
+               */
+              __pformat_wcputs( va_arg( argv, wchar_t * ), &stream );
+            }
+            else
+              /* This is normal string output;
+               * we simply invoke the appropriate handler...
+               */
+              __pformat_puts( va_arg( argv, char * ), &stream );
+            goto format_scan;
+          case 'm': /* strerror (errno)  */
+            __pformat_puts (strerror (saved_errno), &stream);
+            goto format_scan;
+
+          case 'o':
+          case 'u':
+          case 'x':
+          case 'X':
+            /*
+             * Unsigned integer values; octal, decimal or hexadecimal format...
+             */
+            stream.flags &= ~PFORMAT_POSITIVE;
+#if __ENABLE_PRINTF128
+        argval.__pformat_u128_t.t128.digits[1] = 0LL; /* no sign extend needed */
+            if( length == PFORMAT_LENGTH_LLONG128 )
+              argval.__pformat_u128_t.t128 = va_arg( argv, __tI128 );
+            else
+#endif
+        if( length == PFORMAT_LENGTH_LLONG ) {
+              /*
+               * with an `unsigned long long' argument, which we
+               * process `as is'...
+               */
+              argval.__pformat_ullong_t = va_arg( argv, unsigned long long );
+
+            } else if( length == PFORMAT_LENGTH_LONG ) {
+              /*
+               * or with an `unsigned long', which we promote to
+               * `unsigned long long'...
+               */
+              argval.__pformat_ullong_t = va_arg( argv, unsigned long );
+
+            } else
+            { /* or for any other size, which will have been promoted
+               * to `unsigned int', we select only the appropriately sized
+               * least significant segment, and again promote to the same
+               * size as `unsigned long long'...
+               */
+              argval.__pformat_ullong_t = va_arg( argv, unsigned int );
+              if( length == PFORMAT_LENGTH_SHORT )
+                /*
+                 * from `unsigned short'...
+                 */
+                argval.__pformat_ullong_t = argval.__pformat_ushort_t;
+
+              else if( length == PFORMAT_LENGTH_CHAR )
+                /*
+                 * or even from `unsigned char'...
+                 */
+                argval.__pformat_ullong_t = argval.__pformat_uchar_t;
+            }
+
+            /* so we can pass any size of argument to either of two
+             * common format handlers...
+             */
+            if( c == 'u' )
+              /*
+               * depending on whether output is to be encoded in
+               * decimal format...
+               */
+              __pformat_int( argval, &stream );
+
+            else
+              /* or in octal or hexadecimal format...
+               */
+              __pformat_xint( c, argval, &stream );
+
+            goto format_scan;
+
+          case 'd':
+          case 'i':
+            /*
+             * Signed integer values; decimal format...
+             * This is similar to `u', but must process `argval' as signed,
+             * and be prepared to handle negative numbers.
+             */
+            stream.flags |= PFORMAT_NEGATIVE;
+#if __ENABLE_PRINTF128
+            if( length == PFORMAT_LENGTH_LLONG128 ) {
+              argval.__pformat_u128_t.t128 = va_arg( argv, __tI128 );
+          goto skip_sign; /* skip sign extend */
+            } else
+#endif
+            if( length == PFORMAT_LENGTH_LLONG ){
+              /*
+               * The argument is a `long long' type...
+               */
+              argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, long long );
+            } else if( length == PFORMAT_LENGTH_LONG ) {
+              /*
+               * or here, a `long' type...
+               */
+              argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, long );
+            } else
+            { /* otherwise, it's an `int' type...
+               */
+              argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, int );
+              if( length == PFORMAT_LENGTH_SHORT )
+                /*
+                 * but it was promoted from a `short' type...
+                 */
+                argval.__pformat_u128_t.t128.digits[0] = argval.__pformat_short_t;
+              else if( length == PFORMAT_LENGTH_CHAR )
+                /*
+                 * or even from a `char' type...
+                 */
+                argval.__pformat_u128_t.t128.digits[0] = argval.__pformat_char_t;
+            }
+
+            /* In any case, all share a common handler...
+             */
+        argval.__pformat_u128_t.t128.digits[1] = (argval.__pformat_llong_t < 0) ? -1LL : 0LL;
+#if __ENABLE_PRINTF128
+        skip_sign:
+#endif
+            __pformat_int( argval, &stream );
+            goto format_scan;
+
+          case 'p':
+            /*
+             * Pointer argument; format as hexadecimal, subject to...
+             */
+            if( (state == PFORMAT_INIT) && (stream.flags == flags) )
+            {
+              /* Here, the user didn't specify any particular
+               * formatting attributes.  We must choose a default
+               * which will be compatible with Microsoft's (broken)
+               * scanf() implementation, (i.e. matching the default
+               * used by MSVCRT's printf(), which appears to resemble
+               * "%0.8X" for 32-bit pointers); in particular, we MUST
+               * NOT adopt a GNU-like format resembling "%#x", because
+               * Microsoft's scanf() will choke on the "0x" prefix.
+               */
+              stream.flags |= PFORMAT_ZEROFILL;
+              stream.precision = 2 * sizeof( uintptr_t );
+            }
+            argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, uintptr_t );
+            argval.__pformat_u128_t.t128.digits[1] = 0;
+            __pformat_xint( 'x', argval, &stream );
+            goto format_scan;
+
+          case 'e':
+            /*
+             * Floating point format, with lower case exponent indicator
+             * and lower case `inf' or `nan' representation when required;
+             * select lower case mode, and simply fall through...
+             */
+            stream.flags |= PFORMAT_XCASE;
+
+            /* fallthrough */
+
+          case 'E':
+            /*
+             * Floating point format, with upper case exponent indicator
+             * and upper case `INF' or `NAN' representation when required,
+             * (or lower case for all of these, on fall through from above);
+             * select lower case mode, and simply fall through...
+             */
+#ifdef __ENABLE_DFP
+            if( stream.flags & PFORMAT_DECIM32 )
+              /* Is a 32bit decimal float */
+              __pformat_efloat_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM64 )
+              /*
+               * Is a 64bit decimal float
+               */
+              __pformat_efloat_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM128 )
+              /*
+               * Is a 128bit decimal float
+               */
+              __pformat_efloat_decimal(va_arg( argv, _Decimal128 ), &stream );
+            else
+#endif /* __ENABLE_DFP */
+            if( stream.flags & PFORMAT_LDOUBLE )
+              /*
+               * for a `long double' argument...
+               */
+              __pformat_efloat( va_arg( argv, long double ), &stream );
+
+            else
+              /* or just a `double', which we promote to `long double',
+               * so the two may share a common format handler.
+               */
+              __pformat_efloat( (long double)(va_arg( argv, double )), &stream );
+
+            goto format_scan;
+
+          case 'f':
+            /*
+             * Fixed point format, using lower case for `inf' and
+             * `nan', when appropriate; select lower case mode, and
+             * simply fall through...
+             */
+            stream.flags |= PFORMAT_XCASE;
+
+            /* fallthrough */
+
+          case 'F':
+            /*
+             * Fixed case format using upper case, or lower case on
+             * fall through from above, for `INF' and `NAN'...
+             */
+#ifdef __ENABLE_DFP
+            if( stream.flags & PFORMAT_DECIM32 )
+              /* Is a 32bit decimal float */
+              __pformat_float_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM64 )
+              /*
+               * Is a 64bit decimal float
+               */
+              __pformat_float_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM128 )
+              /*
+               * Is a 128bit decimal float
+               */
+              __pformat_float_decimal(va_arg( argv, _Decimal128 ), &stream );
+            else
+#endif /* __ENABLE_DFP */
+            if( stream.flags & PFORMAT_LDOUBLE )
+              /*
+               * for a `long double' argument...
+               */
+              __pformat_float( va_arg( argv, long double ), &stream );
+
+            else
+              /* or just a `double', which we promote to `long double',
+               * so the two may share a common format handler.
+               */
+              __pformat_float( (long double)(va_arg( argv, double )), &stream );
+
+            goto format_scan;
+
+          case 'g':
+            /*
+             * Generalised floating point format, with lower case
+             * exponent indicator when required; select lower case
+             * mode, and simply fall through...
+             */
+            stream.flags |= PFORMAT_XCASE;
+
+            /* fallthrough */
+
+          case 'G':
+            /*
+             * Generalised floating point format, with upper case,
+             * or on fall through from above, with lower case exponent
+             * indicator when required...
+             */
+#ifdef __ENABLE_DFP
+            if( stream.flags & PFORMAT_DECIM32 )
+              /* Is a 32bit decimal float */
+              __pformat_gfloat_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM64 )
+              /*
+               * Is a 64bit decimal float
+               */
+              __pformat_gfloat_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
+            else if( stream.flags & PFORMAT_DECIM128 )
+              /*
+               * Is a 128bit decimal float
+               */
+              __pformat_gfloat_decimal(va_arg( argv, _Decimal128 ), &stream );
+            else
+#endif /* __ENABLE_DFP */
+           if( stream.flags & PFORMAT_LDOUBLE )
+              /*
+               * for a `long double' argument...
+               */
+              __pformat_gfloat( va_arg( argv, long double ), &stream );
+
+            else
+              /* or just a `double', which we promote to `long double',
+               * so the two may share a common format handler.
+               */
+              __pformat_gfloat( (long double)(va_arg( argv, double )), &stream );
+
+            goto format_scan;
+
+          case 'a':
+            /*
+             * Hexadecimal floating point format, with lower case radix
+             * and exponent indicators; select the lower case mode, and
+             * fall through...
+             */
+            stream.flags |= PFORMAT_XCASE;
+
+            /* fallthrough */
+
+          case 'A':
+            /*
+             * Hexadecimal floating point format; handles radix and
+             * exponent indicators in either upper or lower case...
+             */
+            if( sizeof( double ) != sizeof( long double ) && stream.flags & PFORMAT_LDOUBLE )
+              /*
+               * with a `long double' argument...
+               */
+              __pformat_xldouble( va_arg( argv, long double ), &stream );
+
+            else
+              /* or just a `double'.
+               */
+              __pformat_xdouble( va_arg( argv, double ), &stream );
+
+            goto format_scan;
+
+          case 'n':
+            /*
+             * Save current output character count...
+             */
+            if( length == PFORMAT_LENGTH_CHAR )
+              /*
+               * to a signed `char' destination...
+               */
+              *va_arg( argv, char * ) = stream.count;
+
+            else if( length == PFORMAT_LENGTH_SHORT )
+              /*
+               * or to a signed `short'...
+               */
+              *va_arg( argv, short * ) = stream.count;
+
+            else if( length == PFORMAT_LENGTH_LONG )
+              /*
+               * or to a signed `long'...
+               */
+              *va_arg( argv, long * ) = stream.count;
+
+            else if( length == PFORMAT_LENGTH_LLONG )
+              /*
+               * or to a signed `long long'...
+               */
+              *va_arg( argv, long long * ) = stream.count;
+
+            else
+              /*
+               * or, by default, to a signed `int'.
+               */
+              *va_arg( argv, int * ) = stream.count;
+
+            goto format_scan;
+
+          /* Argument length modifiers...
+           * These are non-terminal; each sets the format parser
+           * into the PFORMAT_END state, and ends with a `break'.
+           */
+          case 'h':
+            /*
+             * Interpret the argument as explicitly of a `short'
+             * or `char' data type, truncated from the standard
+             * length defined for integer promotion.
+             */
+            if( *fmt == 'h' )
+            {
+              /* Modifier is `hh'; data type is `char' sized...
+               * Skip the second `h', and set length accordingly.
+               */
+              ++fmt;
+              length = PFORMAT_LENGTH_CHAR;
+            }
+
+            else
+              /* Modifier is `h'; data type is `short' sized...
+               */
+              length = PFORMAT_LENGTH_SHORT;
+
+            state = PFORMAT_END;
+            break;
+
+          case 'j':
+            /*
+             * Interpret the argument as being of the same size as
+             * a `intmax_t' entity...
+             */
+            length = __pformat_arg_length( intmax_t );
+            state = PFORMAT_END;
+            break;
+
+#         ifdef _WIN32
+
+            case 'I':
+              /*
+               * The MSVCRT implementation of the printf() family of
+               * functions explicitly uses...
+               */
+#ifdef __ENABLE_PRINTF128
+              if( (fmt[0] == '1') && (fmt[1] == '2') && (fmt[2] == '8')){
+                length = PFORMAT_LENGTH_LLONG128;
+                fmt += 3;
+              } else
+#endif
+              if( (fmt[0] == '6') && (fmt[1] == '4') )
+              {
+                /* I64' instead of `ll',
+                 * when referring to `long long' integer types...
+                 */
+                length = PFORMAT_LENGTH_LLONG;
+                fmt += 2;
+              } else
+              if( (fmt[0] == '3') && (fmt[1] == '2') )
+              {
+                /* and `I32' instead of `l',
+                 * when referring to `long' integer types...
+                 */
+                length = PFORMAT_LENGTH_LONG;
+                fmt += 2;
+              }
+
+              else
+                /* or unqualified `I' instead of `t' or `z',
+                 * when referring to `ptrdiff_t' or `size_t' entities;
+                 * (we will choose to map it to `ptrdiff_t').
+                 */
+                length = __pformat_arg_length( ptrdiff_t );
+
+              state = PFORMAT_END;
+              break;
+
+#         endif
+
+#ifdef __ENABLE_DFP
+          case 'H':
+              stream.flags |= PFORMAT_DECIM32;
+              state = PFORMAT_END;
+              break;
+
+          case 'D':
+            /*
+             * Interpret the argument as explicitly of a
+             * `_Decimal64' or `_Decimal128' data type.
+             */
+            if( *fmt == 'D' )
+            {
+              /* Modifier is `DD'; data type is `_Decimal128' sized...
+               * Skip the second `D', and set length accordingly.
+               */
+              ++fmt;
+              stream.flags |= PFORMAT_DECIM128;
+            }
+
+            else
+              /* Modifier is `D'; data type is `_Decimal64' sized...
+               */
+              stream.flags |= PFORMAT_DECIM64;
+
+              state = PFORMAT_END;
+              break;
+#endif /* __ENABLE_DFP */
+          case 'l':
+            /*
+             * Interpret the argument as explicitly of a
+             * `long' or `long long' data type.
+             */
+            if( *fmt == 'l' )
+            {
+              /* Modifier is `ll'; data type is `long long' sized...
+               * Skip the second `l', and set length accordingly.
+               */
+              ++fmt;
+              length = PFORMAT_LENGTH_LLONG;
+            }
+
+            else
+              /* Modifier is `l'; data type is `long' sized...
+               */
+              length = PFORMAT_LENGTH_LONG;
+
+            state = PFORMAT_END;
+            break;
+
+          case 'L':
+            /*
+             * Identify the appropriate argument as a `long double',
+             * when associated with `%a', `%A', `%e', `%E', `%f', `%F',
+             * `%g' or `%G' format specifications.
+             */
+            stream.flags |= PFORMAT_LDOUBLE;
+            state = PFORMAT_END;
+            break;
+
+          case 't':
+            /*
+             * Interpret the argument as being of the same size as
+             * a `ptrdiff_t' entity...
+             */
+            length = __pformat_arg_length( ptrdiff_t );
+            state = PFORMAT_END;
+            break;
+
+          case 'z':
+            /*
+             * Interpret the argument as being of the same size as
+             * a `size_t' entity...
+             */
+            length = __pformat_arg_length( size_t );
+            state = PFORMAT_END;
+            break;
+
+          /* Precision indicator...
+           * May appear once only; it must precede any modifier
+           * for argument length, or any data type specifier.
+           */
+          case '.':
+            if( state < PFORMAT_GET_PRECISION )
+            {
+              /* We haven't seen a precision specification yet,
+               * so initialise it to zero, (in case no digits follow),
+               * and accept any following digits as the precision.
+               */
+              stream.precision = 0;
+              width_spec = &stream.precision;
+              state = PFORMAT_GET_PRECISION;
+            }
+
+            else
+              /* We've already seen a precision specification,
+               * so this is just junk; proceed to end game.
+               */
+              state = PFORMAT_END;
+
+            /* Either way, we must not fall through here.
+             */
+            break;
+
+          /* Variable field width, or precision specification,
+           * derived from the argument list...
+           */
+          case '*':
+            /*
+             * When this appears...
+             */
+            if(   width_spec
+            &&  ((state == PFORMAT_INIT) || (state == PFORMAT_GET_PRECISION)) )
+            {
+              /* in proper context; assign to field width
+               * or precision, as appropriate.
+               */
+              if( (*width_spec = va_arg( argv, int )) < 0 )
+              {
+                /* Assigned value was negative...
+                 */
+                if( state == PFORMAT_INIT )
+                {
+                  /* For field width, this is equivalent to
+                   * a positive value with the `-' flag...
+                   */
+                  stream.flags |= PFORMAT_LJUSTIFY;
+                  stream.width = -stream.width;
+                }
+
+                else
+                  /* while as a precision specification,
+                   * it should simply be ignored.
+                   */
+                  stream.precision = PFORMAT_IGNORE;
+              }
+            }
+
+            else
+              /* out of context; give up on width and precision
+               * specifications for this conversion.
+               */
+              state = PFORMAT_END;
+
+            /* Mark as processed...
+             * we must not see `*' again, in this context.
+             */
+            width_spec = NULL;
+            break;
+
+          /* Formatting flags...
+           * Must appear while in the PFORMAT_INIT state,
+           * and are non-terminal, so again, end with `break'.
+           */
+          case '#':
+            /*
+             * Select alternate PFORMAT_HASHED output style.
+             */
+            if( state == PFORMAT_INIT )
+              stream.flags |= PFORMAT_HASHED;
+            break;
+
+          case '+':
+            /*
+             * Print a leading sign with numeric output,
+             * for both positive and negative values.
+             */
+            if( state == PFORMAT_INIT )
+              stream.flags |= PFORMAT_POSITIVE;
+            break;
+
+          case '-':
+            /*
+             * Select left justification of displayed output
+             * data, within the output field width, instead of
+             * the default flush right justification.
+             */
+            if( state == PFORMAT_INIT )
+              stream.flags |= PFORMAT_LJUSTIFY;
+            break;
+
+            case '\'':
+              /*
+               * This is an XSI extension to the POSIX standard,
+               * which we do not support, at present.
+               */
+              if (state == PFORMAT_INIT)
+              {
+                stream.flags |= PFORMAT_GROUPED; /* $$$$ */
+                int len; wchar_t rpchr; mbstate_t cstate;
+                memset (&cstate, 0, sizeof(state));
+                if ((len = mbrtowc( &rpchr, localeconv()->thousands_sep, 16, &cstate)) > 0)
+                    stream.thousands_chr = rpchr;
+                stream.thousands_chr_len = len;
+              }
+              break;
+
+          case '\x20':
+            /*
+             * Reserve a single space, within the output field,
+             * for display of the sign of signed data; this will
+             * be occupied by the minus sign, if the data value
+             * is negative, or by a plus sign if the data value
+             * is positive AND the `+' flag is also present, or
+             * by a space otherwise.  (Technically, this flag
+             * is redundant, if the `+' flag is present).
+             */
+            if( state == PFORMAT_INIT )
+              stream.flags |= PFORMAT_ADDSPACE;
+            break;
+
+          case '0':
+            /*
+             * May represent a flag, to activate the `pad with zeros'
+             * option, or it may simply be a digit in a width or in a
+             * precision specification...
+             */
+            if( state == PFORMAT_INIT )
+            {
+              /* This is the flag usage...
+               */
+              stream.flags |= PFORMAT_ZEROFILL;
+              break;
+            }
+
+            /* fallthrough */
+
+          default:
+            /*
+             * If we didn't match anything above, then we will check
+             * for digits, which we may accumulate to generate field
+             * width or precision specifications...
+             */
+            if( (state < PFORMAT_END) && ('9' >= c) && (c >= '0') )
+            {
+              if( state == PFORMAT_INIT )
+                /*
+                 * Initial digits explicitly relate to field width...
+                 */
+                state = PFORMAT_SET_WIDTH;
+
+              else if( state == PFORMAT_GET_PRECISION )
+                /*
+                 * while those following a precision indicator
+                 * explicitly relate to precision.
+                 */
+                state = PFORMAT_SET_PRECISION;
+
+              if( width_spec )
+              {
+                /* We are accepting a width or precision specification...
+                 */
+                if( *width_spec < 0 )
+                  /*
+                   * and accumulation hasn't started yet; we simply
+                   * initialise the accumulator with the current digit
+                   * value, converting from ASCII to decimal.
+                   */
+                  *width_spec = c - '0';
+
+                else
+                  /* Accumulation has already started; we perform a
+                   * `leftwise decimal digit shift' on the accumulator,
+                   * (i.e. multiply it by ten), then add the decimal
+                   * equivalent value of the current digit.
+                   */
+                  *width_spec = *width_spec * 10 + c - '0';
+              }
+            }
+
+            else
+            {
+              /* We found a digit out of context, or some other character
+               * with no designated meaning; reject this format specification,
+               * backtrack, and emit it as literal text...
+               */
+              fmt = backtrack;
+      #ifndef __BUILD_WIDEAPI
+              __pformat_putc( '%', &stream );
+      #else
+          stream.width = stream.precision = PFORMAT_IGNORE;
+          __pformat_wputchars( L"%", 1, &stream );
+      #endif
+              goto format_scan;
+            }
+        }
+      }
+    }
+
+    else
+      /* We just parsed a character which is not included within any format
+       * specification; we simply emit it as a literal.
+       */
+  #ifndef __BUILD_WIDEAPI
+      __pformat_putc( c, &stream );
+  #else
+      if (literal_string_start == NULL)
+        literal_string_start = fmt - 1;
+  #endif
+  }
+
+  /* When we have fully dispatched the format string, the return value is the
+   * total number of bytes we transferred to the output destination.
+   */
+#ifdef __BUILD_WIDEAPI
+  if (literal_string_start)
+  {
+    stream.width = stream.precision = PFORMAT_IGNORE;
+    __pformat_wputchars( literal_string_start, fmt - literal_string_start - 1, &stream );
+  }
+#endif
+
+  return stream.count;
+}
+
+/* $RCSfile: pformat.c,v $Revision: 1.9 $: end of file */
+
lib/libc/mingw/stdio/mingw_pformat.h
@@ -0,0 +1,99 @@
+#ifndef PFORMAT_H
+/*
+ * pformat.h
+ *
+ * $Id: pformat.h,v 1.1 2008/07/28 23:24:20 keithmarshall Exp $
+ *
+ * A private header, defining the `pformat' API; it is to be included
+ * in each compilation unit implementing any of the `printf' family of
+ * functions, but serves no useful purpose elsewhere.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ */
+#define PFORMAT_H
+
+/* The following macros reproduce definitions from _mingw.h,
+ * so that compilation will not choke, if using any compiler
+ * other than the MinGW implementation of GCC.
+ */
+#ifndef __cdecl
+# ifdef __GNUC__
+#  define __cdecl __attribute__((__cdecl__))
+# else
+#  define __cdecl
+# endif
+#endif
+
+#ifndef __MINGW_GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+#  define __MINGW_GNUC_PREREQ( major, minor )\
+     (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+# else
+#  define __MINGW_GNUC_PREREQ( major, minor )
+# endif
+#endif
+
+#ifndef  __MINGW_NOTHROW
+# if __MINGW_GNUC_PREREQ( 3, 3 )
+#  define __MINGW_NOTHROW  __attribute__((__nothrow__))
+# else
+#  define __MINGW_NOTHROW
+# endif
+#endif
+
+#ifdef __BUILD_WIDEAPI
+#define APICHAR	wchar_t
+#else
+#define APICHAR char
+#endif
+
+/* The following are the declarations specific to the `pformat' API...
+ */
+#define PFORMAT_TO_FILE     0x2000
+#define PFORMAT_NOLIMIT     0x4000
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ /*
+  * Map MinGW specific function names, for use in place of the generic
+  * implementation defined equivalent function names.
+  */
+#ifdef __BUILD_WIDEAPI
+# define __pformat        __mingw_wpformat
+#define __fputc(X,STR) fputwc((wchar_t) (X), (STR))
+
+# define __printf         __mingw_wprintf
+# define __fprintf        __mingw_fwprintf
+# define __sprintf        __mingw_swprintf
+# define __snprintf       __mingw_snwprintf
+
+# define __vprintf        __mingw_vwprintf
+# define __vfprintf       __mingw_vfwprintf
+# define __vsprintf       __mingw_vswprintf
+# define __vsnprintf      __mingw_vsnwprintf
+#else
+# define __pformat        __mingw_pformat
+#define __fputc(X,STR) fputc((X), (STR))
+
+# define __printf         __mingw_printf
+# define __fprintf        __mingw_fprintf
+# define __sprintf        __mingw_sprintf
+# define __snprintf       __mingw_snprintf
+
+# define __vprintf        __mingw_vprintf
+# define __vfprintf       __mingw_vfprintf
+# define __vsprintf       __mingw_vsprintf
+# define __vsnprintf      __mingw_vsnprintf
+#endif /* __BUILD_WIDEAPI */
+#endif
+
+int __cdecl __pformat(int, void *, int, const APICHAR *, va_list) __MINGW_NOTHROW;
+#endif /* !defined PFORMAT_H */
lib/libc/mingw/stdio/mingw_pformatw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_pformat.c"
+
lib/libc/mingw/stdio/mingw_printf.c
@@ -0,0 +1,59 @@
+/* printf.c
+ *
+ * $Id: printf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "printf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "printf" will normally be invoked by calling
+ * "__mingw_printf()" in preference to a direct reference to "printf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "print()".  Users who then
+ * wish to use this implementation may either call "__mingw_printf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "printf()" to "__mingw_printf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "printf()" in user
+ * code will ALWAYS be redirected to "__mingw_printf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "printf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_printf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __printf(const APICHAR *, ...) __MINGW_NOTHROW;
+
+int __cdecl __printf(const APICHAR *fmt, ...)
+{
+  register int retval;
+  va_list argv; va_start( argv, fmt );
+  _lock_file( stdout );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
+  _unlock_file( stdout );
+  va_end( argv );
+  return retval;
+}
+
lib/libc/mingw/stdio/mingw_printfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_printf.c"
+
lib/libc/mingw/stdio/mingw_scanf.c
@@ -0,0 +1,28 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int __mingw_vfscanf (FILE *stream, const char *format, va_list argp);
+
+int __mingw_scanf (const char *format, ...);
+int __mingw_vscanf (const char *format, va_list argp);
+
+int
+__mingw_scanf (const char *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vfscanf (stdin, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
+int
+__mingw_vscanf (const char *format, va_list argp)
+{
+  return __mingw_vfscanf (stdin, format, argp);
+}
+
lib/libc/mingw/stdio/mingw_snprintf.c
@@ -0,0 +1,40 @@
+/* snprintf.c
+ *
+ * $Id: snprintf.c,v 1.3 2008/07/28 23:24:20 keithmarshall Exp $
+ *
+ * Provides an implementation of the "snprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, replacing the redirection through
+ * libmoldnames.a, to the MSVCRT standard "_snprintf" function; (the
+ * standard MSVCRT function remains available, and may  be invoked
+ * directly, using this fully qualified form of its name).
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __snprintf (APICHAR *, size_t, const APICHAR *fmt, ...) __MINGW_NOTHROW;
+int __cdecl __vsnprintf (APICHAR *, size_t, const APICHAR *fmt, va_list) __MINGW_NOTHROW;
+
+int __cdecl __snprintf(APICHAR *buf, size_t length, const APICHAR *fmt, ...)
+{
+  va_list argv; va_start( argv, fmt );
+  register int retval = __vsnprintf( buf, length, fmt, argv );
+  va_end( argv );
+  return retval;
+}
lib/libc/mingw/stdio/mingw_snprintfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_snprintf.c"
+
lib/libc/mingw/stdio/mingw_sprintf.c
@@ -0,0 +1,56 @@
+/* sprintf.c
+ *
+ * $Id: sprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "sprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "sprintf" will normally be invoked by calling
+ * "__mingw_sprintf()" in preference to a direct reference to "sprintf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "sprint()".  Users who then
+ * wish to use this implementation may either call "__mingw_sprintf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "sprintf()" to "__mingw_sprintf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "sprintf()" in user
+ * code will ALWAYS be redirected to "__mingw_sprintf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "sprintf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_sprintf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __sprintf (APICHAR *, const APICHAR *, ...) __MINGW_NOTHROW;
+
+int __cdecl __sprintf(APICHAR *buf, const APICHAR *fmt, ...)
+{
+  register int retval;
+  va_list argv; va_start( argv, fmt );
+  buf[retval = __pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
+  va_end( argv );
+  return retval;
+}
lib/libc/mingw/stdio/mingw_sprintfw.c
@@ -0,0 +1,10 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+#define _CRT_NON_CONFORMING_SWPRINTFS 1
+
+#include "mingw_sprintf.c"
+
lib/libc/mingw/stdio/mingw_sscanf.c
@@ -0,0 +1,20 @@
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern int __mingw_vsscanf (const char *buf, const char *format, va_list argp);
+
+int __mingw_sscanf (const char *buf, const char *format, ...);
+
+int
+__mingw_sscanf (const char *buf, const char *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vsscanf (buf, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
lib/libc/mingw/stdio/mingw_swscanf.c
@@ -0,0 +1,20 @@
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern int __mingw_vswscanf (const wchar_t *buf, const wchar_t *format, va_list argp);
+
+int __mingw_swscanf (const wchar_t *buf, const wchar_t *format, ...);
+
+int
+__mingw_swscanf (const wchar_t *buf, const wchar_t *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vswscanf (buf, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
lib/libc/mingw/stdio/mingw_vasprintf.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+#define __CRT__NO_INLINE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int __mingw_vasprintf(char ** __restrict__ ret,
+                      const char * __restrict__ format,
+                      va_list ap) {
+  int len;
+  /* Get Length */
+  len = __mingw_vsnprintf(NULL,0,format,ap);
+  if (len < 0) return -1;
+  /* +1 for \0 terminator. */
+  *ret = malloc(len + 1);
+  /* Check malloc fail*/
+  if (!*ret) return -1;
+  /* Write String */
+  __mingw_vsnprintf(*ret,len+1,format,ap);
+  /* Terminate explicitly */
+  (*ret)[len] = '\0';
+  return len;
+}
+
lib/libc/mingw/stdio/mingw_vfprintf.c
@@ -0,0 +1,58 @@
+/* vfprintf.c
+ *
+ * $Id: vfprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "vfprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "vfprintf" will normally be invoked by calling
+ * "__mingw_vfprintf()" in preference to a direct reference to "vfprintf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "vfprint()".  Users who then
+ * wish to use this implementation may either call "__mingw_vfprintf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "vfprintf()" to "__mingw_vfprintf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "vfprintf()" in user
+ * code will ALWAYS be redirected to "__mingw_vfprintf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "vfprintf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_vfprintf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __vfprintf (FILE *, const APICHAR *, va_list) __MINGW_NOTHROW;
+
+int __cdecl __vfprintf(FILE *stream, const APICHAR *fmt, va_list argv)
+{
+  register int retval;
+
+  _lock_file( stream );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
+  _unlock_file( stream );
+
+  return retval;
+}
lib/libc/mingw/stdio/mingw_vfprintfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_vfprintf.c"
+
lib/libc/mingw/stdio/mingw_vfscanf.c
@@ -0,0 +1,1632 @@
+/*
+ This Software is provided under the Zope Public License (ZPL) Version 2.1.
+
+ Copyright (c) 2011 by the mingw-w64 project
+
+ See the AUTHORS file for the list of contributors to the mingw-w64 project.
+
+ This license has been certified as open source. It has also been designated
+ as GPL compatible by the Free Software Foundation (FSF).
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions in source code must retain the accompanying copyright
+      notice, this list of conditions, and the following disclaimer.
+   2. Redistributions in binary form must reproduce the accompanying
+      copyright notice, this list of conditions, and the following disclaimer
+      in the documentation and/or other materials provided with the
+      distribution.
+   3. Names of the copyright holders must not be used to endorse or promote
+      products derived from this software without prior written permission
+      from the copyright holders.
+   4. The right to distribute this software or to use it for any purpose does
+      not give you the right to use Servicemarks (sm) or Trademarks (tm) of
+      the copyright holders.  Use of them is covered by separate agreement
+      with the copyright holders.
+   5. If any files are modified, you must cause the modified files to carry
+      prominent notices stating that you changed the files and the date of
+      any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+ 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 COPYRIGHT HOLDERS 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.
+*/
+
+#define __LARGE_MBSTATE_T
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <locale.h>
+#include <errno.h>
+
+/* Helper flags for conversion.  */
+#define IS_C		0x0001
+#define IS_S		0x0002
+#define IS_L		0x0004
+#define IS_LL		0x0008
+#define IS_SIGNED_NUM	0x0010
+#define IS_POINTER	0x0020
+#define IS_HEX_FLOAT	0x0040
+#define IS_SUPPRESSED	0x0080
+#define USE_GROUP	0x0100
+#define USE_GNU_ALLOC	0x0200
+#define USE_POSIX_ALLOC	0x0400
+
+#define IS_ALLOC_USED	(USE_GNU_ALLOC | USE_POSIX_ALLOC)
+
+/* internal stream structure with back-buffer.  */
+typedef struct _IFP
+{
+  __extension__ union {
+    void *fp;
+    const char *str;
+  };
+  int bch[1024];
+  unsigned int is_string : 1;
+  int back_top;
+  unsigned int seen_eof : 1;
+} _IFP;
+
+static void *
+get_va_nth (va_list argp, unsigned int n)
+{
+  va_list ap;
+  if (!n) abort ();
+  va_copy (ap, argp);
+  while (--n > 0)
+    (void) va_arg(ap, void *);
+  return va_arg (ap, void *);
+}
+
+static void
+optimize_alloc (char **p, char *end, size_t alloc_sz)
+{
+  size_t need_sz;
+  char *h;
+
+  if (!p || !*p)
+    return;
+
+  need_sz = end - *p;
+  if (need_sz == alloc_sz)
+    return;
+
+  if ((h = (char *) realloc (*p, need_sz)) != NULL)
+    *p = h;
+}
+
+static void
+back_ch (int c, _IFP *s, size_t *rin, int not_eof)
+{
+  if (!not_eof && c == EOF)
+    return;
+  if (s->is_string == 0)
+    {
+      FILE *fp = s->fp;
+      ungetc (c, fp);
+      rin[0] -= 1;
+      return;
+    }
+  rin[0] -= 1;
+  s->bch[s->back_top] = c;
+  s->back_top += 1;
+}
+
+static int
+in_ch (_IFP *s, size_t *rin)
+{
+  int r;
+  if (s->back_top)
+  {
+    s->back_top -= 1;
+    r = s->bch[s->back_top];
+    rin[0] += 1;
+  }
+  else if (s->seen_eof)
+  {
+    return EOF;
+  }
+  else if (s->is_string)
+  {
+    const char *ps = s->str;
+    r = ((int) *ps) & 0xff;
+    ps++;
+    if (r != 0)
+    {
+      rin[0] += 1;
+      s->str = ps;
+      return r;
+    }
+    s->seen_eof = 1;
+    return EOF;
+  }
+  else
+  {
+    FILE *fp = (FILE *) s->fp;
+    r = getc (fp);
+    if (r != EOF)
+      rin[0] += 1;
+    else s->seen_eof = 1;
+  }
+  return r;
+}
+
+static int
+match_string (_IFP *s, size_t *rin, int *c, const char *str)
+{
+  int ch = *c;
+
+  if (*str == 0)
+    return 1;
+
+  if (*str != (char) tolower (ch))
+    return 0;
+  ++str;
+  while (*str != 0)
+  {
+    if ((ch = in_ch (s, rin)) == EOF)
+    {
+      c[0] = ch;
+      return 0;
+    }
+
+    if (*str != (char) tolower (ch))
+    {
+      c[0] = ch;
+      return 0;
+    }
+    ++str;
+  }
+  c[0] = ch;
+  return 1;
+}
+
+struct gcollect
+{
+  size_t count;
+  struct gcollect *next;
+  char **ptrs[32];
+};
+
+static void
+release_ptrs (struct gcollect **pt, char **wbuf)
+{
+  struct gcollect *pf;
+  size_t cnt;
+
+  if (wbuf)
+    {
+      free (*wbuf);
+      *wbuf = NULL;
+    }
+  if (!pt || (pf = *pt) == NULL)
+    return;
+  while (pf != NULL)
+    {
+      struct gcollect *pf_sv = pf;
+      for (cnt = 0; cnt < pf->count; ++cnt)
+	{
+	  free (*pf->ptrs[cnt]);
+	  *pf->ptrs[cnt] = NULL;
+	}
+      pf = pf->next;
+      free (pf_sv);
+    }
+  *pt = NULL;
+}
+
+static int
+cleanup_return (int rval, struct gcollect **pfree, char **strp, char **wbuf)
+{
+  if (rval == EOF)
+      release_ptrs (pfree, wbuf);
+  else
+    {
+      if (pfree)
+        {
+          struct gcollect *pf = *pfree, *pf_sv;
+          while (pf != NULL)
+            {
+              pf_sv = pf;
+              pf = pf->next;
+              free (pf_sv);
+            }
+          *pfree = NULL;
+        }
+      if (strp != NULL)
+	{
+	  free (*strp);
+	  *strp = NULL;
+	}
+      if (wbuf)
+	{
+	  free (*wbuf);
+	  *wbuf = NULL;
+	}
+    }
+  return rval;
+}
+
+static struct gcollect *
+resize_gcollect (struct gcollect *pf)
+{
+  struct gcollect *np;
+  if (pf && pf->count < 32)
+    return pf;
+  np = malloc (sizeof (struct gcollect));
+  np->count = 0;
+  np->next = pf;
+  return np;
+}
+
+static char *
+resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, char *old)
+{
+  char *wbuf;
+  size_t nsz;
+  if (*wbuf_max_sz != wpsz)
+    return old;
+  nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
+  if (!old)
+    wbuf = (char *) malloc (nsz);
+  else
+    wbuf = (char *) realloc (old, nsz);
+  if (!wbuf)
+  {
+    if (old)
+      free (old);
+  }
+  else
+    *wbuf_max_sz = nsz;
+  return wbuf;
+}
+
+static int
+__mingw_sformat (_IFP *s, const char *format, va_list argp)
+{
+  const char *f = format;
+  struct gcollect *gcollect = NULL;
+  size_t read_in = 0, wbuf_max_sz = 0, cnt;
+  ssize_t str_sz = 0;
+  char *str = NULL, **pstr = NULL, *wbuf = NULL;
+  wchar_t *wstr = NULL;
+  int rval = 0, c = 0, ignore_ws = 0;
+  va_list arg;
+  unsigned char fc;
+  unsigned int npos;
+  int width, flags, base = 0, errno_sv;
+  size_t wbuf_cur_sz, read_in_sv, new_sz, n;
+  char seen_dot, seen_exp, is_neg, not_in;
+  char *tmp_wbuf_ptr, buf[MB_LEN_MAX];
+  const char *lc_decimal_point, *lc_thousands_sep;
+  mbstate_t state, cstate;
+  union {
+    unsigned long long ull;
+    unsigned long ul;
+    long long ll;
+    long l;
+  } cv_val;
+
+  arg = argp;
+
+  if (!s || s->fp == NULL || !format)
+    {
+      errno = EINVAL;
+      return EOF;
+    }
+
+  memset (&state, 0, sizeof (state));
+
+  lc_decimal_point = localeconv()->decimal_point;
+  lc_thousands_sep = localeconv()->thousands_sep;
+  if (lc_thousands_sep != NULL && *lc_thousands_sep == 0)
+    lc_thousands_sep = NULL;
+
+  while (*f != 0)
+    {
+      if (!isascii ((unsigned char) *f))
+	{
+	  int len;
+
+	  if ((len = mbrlen (f, strlen (f), &state)) > 0)
+	    {
+	      do
+		{
+		  if ((c = in_ch (s, &read_in)) == EOF || c != (unsigned char) *f++)
+		    {
+		      back_ch (c, s, &read_in, 1);
+		      return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+		    }
+		}
+	      while (--len > 0);
+
+	      continue;
+	    }
+	}
+
+      fc = *f++;
+      if (fc != '%')
+        {
+          if (isspace (fc))
+            ignore_ws = 1;
+          else
+	    {
+	      if ((c = in_ch (s, &read_in)) == EOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      if (ignore_ws)
+		{
+		  ignore_ws = 0;
+		  if (isspace (c))
+		    {
+		      do
+			{
+			  if ((c = in_ch (s, &read_in)) == EOF)
+			    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+			}
+		      while (isspace (c));
+		    }
+		}
+
+	      if (c != fc)
+		{
+		  back_ch (c, s, &read_in, 0);
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  continue;
+	}
+
+      width = flags = 0;
+      npos = 0;
+      wbuf_cur_sz = 0;
+
+      if (isdigit ((unsigned char) *f))
+	{
+	  const char *svf = f;
+	  npos = (unsigned char) *f++ - '0';
+	  while (isdigit ((unsigned char) *f))
+	    npos = npos * 10 + ((unsigned char) *f++ - '0');
+	  if (*f != '$')
+	    {
+	      npos = 0;
+	      f = svf;
+	    }
+	  else
+	    f++;
+	}
+
+      do
+	{
+	  if (*f == '*')
+	    flags |= IS_SUPPRESSED;
+	  else if (*f == '\'')
+	    {
+	      if (lc_thousands_sep)
+		flags |= USE_GROUP;
+	    }
+	  else if (*f == 'I')
+	    {
+	      /* we don't support locale's digits (i18N), but ignore it for now silently.  */
+	      ;
+#ifdef _WIN32
+              if (f[1] == '6' && f[2] == '4')
+                {
+		  flags |= IS_LL | IS_L;
+		  f += 2;
+		}
+	      else if (f[1] == '3' && f[2] == '2')
+		{
+		  flags |= IS_L;
+		  f += 2;
+		}
+	      else
+	        {
+#ifdef _WIN64
+		  flags |= IS_LL | IS_L;
+#else
+		  flags |= IS_L;
+#endif
+		}
+#endif
+	    }
+	  else
+	    break;
+	  ++f;
+        }
+      while (1);
+
+      while (isdigit ((unsigned char) *f))
+	width = width * 10 + ((unsigned char) *f++ - '0');
+
+      if (!width)
+	width = -1;
+
+      switch (*f)
+	{
+	case 'h':
+	  ++f;
+	  flags |= (*f == 'h' ? IS_C : IS_S);
+	  if (*f == 'h')
+	    ++f;
+	  break;
+	case 'l':
+	  ++f;
+	  flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
+	  if (*f == 'l')
+	    ++f;
+	  break;
+	case 'q': case 'L':
+	  ++f;
+	  flags |= IS_LL | IS_L;
+	  break;
+	case 'a':
+	  if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
+	    break;
+	  ++f;
+	  flags |= USE_GNU_ALLOC;
+	  break;
+	case 'm':
+	  flags |= USE_POSIX_ALLOC;
+	  ++f;
+	  if (*f == 'l')
+	    {
+	      flags |= IS_L;
+	      f++;
+	    }
+	  break;
+	case 'z':
+#ifdef _WIN64
+	  flags |= IS_LL | IS_L;
+#else
+	  flags |= IS_L;
+#endif
+	  ++f;
+	  break;
+	case 'j':
+	  if (sizeof (uintmax_t) > sizeof (unsigned long))
+	    flags |= IS_LL;
+	  else if (sizeof (uintmax_t) > sizeof (unsigned int))
+	    flags |= IS_L;
+	  ++f;
+	  break;
+	case 't':
+#ifdef _WIN64
+	  flags |= IS_LL;
+#else
+	  flags |= IS_L;
+#endif
+	  ++f;
+	  break;
+	case 0:
+	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	default:
+	  break;
+	}
+
+      if (*f == 0)
+	return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+      fc = *f++;
+      if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
+	{
+	  errno_sv = errno;
+	  errno = 0;
+	  do
+	    {
+	      if ((c == EOF || (c = in_ch (s, &read_in)) == EOF)
+	          && errno == EINTR)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	    }
+	  while (isspace (c));
+
+	  ignore_ws = 0;
+	  errno = errno_sv;
+	  back_ch (c, s, &read_in, 0);
+	}
+
+      switch (fc)
+        {
+        case 'c':
+          if ((flags & IS_L) != 0)
+            fc = 'C';
+          break;
+        case 's':
+          if ((flags & IS_L) != 0)
+            fc = 'S';
+          break;
+        }
+
+      switch (fc)
+	{
+	case '%':
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	  if (c != fc)
+	    {
+	      back_ch (c, s, &read_in, 1);
+	      return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	    }
+	  break;
+
+	case 'n':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_LL) != 0)
+		*(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
+	      else if ((flags & IS_L) != 0)
+		*(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
+	      else if ((flags & IS_S) != 0)
+		*(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
+	      else if ((flags & IS_C) != 0)
+	        *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
+	      else
+		*(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
+	    }
+	  break;
+
+	case 'c':
+	  if (width == -1)
+	    width = 1;
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		  if (npos != 0)
+		    pstr = (char **) get_va_nth (argp, npos);
+		  else
+		    pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		  str_sz = (width > 1024 ? 1024 : width);
+		  if ((str = *pstr = (char *) malloc (str_sz)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      do
+		{
+		  if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+		    {
+		      new_sz = str_sz + (str_sz >= width ? width - 1 : str_sz);
+		      while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+			     && new_sz > (size_t) (str_sz + 1))
+			new_sz = str_sz + 1;
+		      if (!str)
+			{
+			  release_ptrs (&gcollect, &wbuf);
+			  return EOF;
+			}
+		      *pstr = str;
+		      str += str_sz;
+		      str_sz = new_sz;
+		    }
+		  *str++ = c;
+		}
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+	    }
+	  else
+	    while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      optimize_alloc (pstr, str, str_sz);
+	      pstr = NULL;
+	      ++rval;
+	    }
+
+	  break;
+
+	case 'C':
+	  if (width == -1)
+	    width = 1;
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		  if (npos != 0)
+		    pstr = (char **) get_va_nth (argp, npos);
+		  else
+		    pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = (width > 1024 ? 1024 : width);
+		  *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
+		  if ((wstr = (wchar_t *) *pstr) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    wstr = (wchar_t *) get_va_nth (argp, npos);
+		  else
+		    wstr = va_arg (arg, wchar_t *);
+		  if (!wstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  memset (&cstate, 0, sizeof (cstate));
+
+	  do
+	    {
+	      buf[0] = c;
+
+	      if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
+		  && wstr == ((wchar_t *) *pstr + str_sz))
+		{
+		  new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
+
+		  while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+			 && new_sz > (size_t) (str_sz + 1))
+		    new_sz = str_sz + 1;
+		  if (!wstr)
+		    {
+		      release_ptrs (&gcollect, &wbuf);
+		      return EOF;
+		    }
+		  *pstr = (char *) wstr;
+		  wstr += str_sz;
+		  str_sz = new_sz;
+		}
+
+	      while (1)
+		{
+		  n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
+
+		  if (n == (size_t) -2)
+		    {
+		      if ((c = in_ch (s, &read_in)) == EOF)
+			{
+			  errno = EILSEQ;
+			  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+			}
+
+		      buf[0] = c;
+		      continue;
+		    }
+
+		  if (n != 1)
+		    {
+			errno = EILSEQ;
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		    }
+		  break;
+		}
+
+	      ++wstr;
+	    }
+	  while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 's':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		 if (npos != 0)
+		   pstr = (char **) get_va_nth (argp, npos);
+		 else
+		   pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		  str_sz = 100;
+		  if ((str = *pstr = (char *) malloc (100)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  do
+	    {
+	      if (isspace (c))
+		{
+		  back_ch (c, s, &read_in, 1);
+		  break;
+		}
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  *str++ = c;
+		  if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+		    {
+		      new_sz = str_sz * 2;
+
+		      while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+			     && new_sz > (size_t) (str_sz + 1))
+			new_sz = str_sz + 1;
+		      if (!str)
+			{
+			  if ((flags & USE_POSIX_ALLOC) == 0)
+			    {
+			      (*pstr)[str_sz - 1] = 0;
+			      pstr = NULL;
+			      ++rval;
+			    }
+			  return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+			}
+		      *pstr = str;
+		      str += str_sz;
+		      str_sz = new_sz;
+		    }
+		}
+	    }
+	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      *str++ = 0;
+	      optimize_alloc (pstr, str, str_sz);
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 'S':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		  if (npos != 0)
+		    pstr = (char **) get_va_nth (argp, npos);
+		  else
+		    pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		  str_sz = 100;
+		  *pstr = (char *) malloc (100 * sizeof (wchar_t));
+		  if ((wstr = (wchar_t *) *pstr) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    wstr = (wchar_t *) get_va_nth (argp, npos);
+		  else
+		    wstr = va_arg (arg, wchar_t *);
+		  if (!wstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  memset (&cstate, 0, sizeof (cstate));
+
+	  do
+	    {
+	      if (isspace (c))
+		{
+		  back_ch (c, s, &read_in, 1);
+		  break;
+		}
+
+	      buf[0] = c;
+
+	      while (1)
+		{
+		  n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
+
+		  if (n == (size_t) -2)
+		    {
+		      if ((c = in_ch (s, &read_in)) == EOF)
+			{
+			  errno = EILSEQ;
+			  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+			}
+
+		      buf[0] = c;
+		      continue;
+		    }
+
+		  if (n != 1)
+		    {
+		      errno = EILSEQ;
+		      return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		    }
+
+		  ++wstr;
+		  break;
+		}
+
+	      if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
+		  && wstr == ((wchar_t *) *pstr + str_sz))
+		{
+		  new_sz = str_sz * 2;
+		  while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+			 && new_sz > (size_t) (str_sz + 1))
+		    new_sz = str_sz + 1;
+		  if (!wstr)
+		    {
+		      if ((flags & USE_POSIX_ALLOC) == 0)
+			{
+			  ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+			  pstr = NULL;
+			  ++rval;
+			}
+		      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		    }
+		  *pstr = (char *) wstr;
+		  wstr += str_sz;
+		  str_sz = new_sz;
+		}
+	    }
+	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      *wstr++ = 0;
+	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 'd': case 'i':
+	case 'o': case 'p':
+	case 'u':
+	case 'x': case 'X':
+	  switch (fc)
+	    {
+	    case 'd':
+	      flags |= IS_SIGNED_NUM;
+	      base = 10;
+	      break;
+	    case 'i':
+	      flags |= IS_SIGNED_NUM;
+	      base = 0;
+	      break;
+	    case 'o':
+	      base = 8;
+	      break;
+	    case 'p':
+	      base = 16;
+	      flags &= ~(IS_S | IS_LL | IS_L);
+    #ifdef _WIN64
+	      flags |= IS_LL;
+    #endif
+	      flags |= IS_L | IS_POINTER;
+	      break;
+	    case 'u':
+	      base = 10;
+	      break;
+	    case 'x': case 'X':
+	      base = 16;
+	      break;
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	  if (c == '+' || c == '-')
+	    {
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+	      if (width > 0)
+		--width;
+	      c = in_ch (s, &read_in);
+	    }
+	  if (width != 0 && c == '0')
+	    {
+	      if (width > 0)
+		--width;
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+	      c = in_ch (s, &read_in);
+
+	      if (width != 0 && tolower (c) == 'x')
+		{
+		  if (!base)
+		    base = 16;
+		  if (base == 16)
+		    {
+		      if (width > 0)
+			--width;
+		      c = in_ch (s, &read_in);
+		    }
+		}
+	      else if (!base)
+		base = 8;
+	    }
+
+	  if (!base)
+	    base = 10;
+
+	  while (c != EOF && width != 0)
+	    {
+	      if (base == 16)
+		{
+		  if (!isxdigit (c))
+		    break;
+		}
+	      else if (!isdigit (c) || (int) (c - '0') >= base)
+		{
+		  const char *p = lc_thousands_sep;
+		  int remain;
+
+		  if (base != 10 || (flags & USE_GROUP) == 0)
+		    break;
+		  remain = width > 0 ? width : INT_MAX;
+		  while ((unsigned char) *p == c && remain >= 0)
+		    {
+		      /* As our conversion routines aren't supporting thousands
+			 separators, we are filtering them here.  */
+
+		      ++p;
+		      if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+			break;
+		      --remain;
+		    }
+
+		  if (*p != 0)
+		    {
+		      if (p > lc_thousands_sep)
+			{
+			  back_ch (c, s, &read_in, 0);
+			  while (--p > lc_thousands_sep)
+			    back_ch ((unsigned char) *p, s, &read_in, 1);
+			  c = (unsigned char) *p;
+			}
+		      break;
+		    }
+
+		  if (width > 0)
+		    width = remain;
+		  --wbuf_cur_sz;
+		}
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+	      if (width > 0)
+		--width;
+
+	      c = in_ch (s, &read_in);
+	    }
+
+	  if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
+	    {
+	      if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
+	          && match_string (s, &read_in, &c, "(nil)"))
+		{
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = '0';
+		}
+	      else
+		{
+		  back_ch (c, s, &read_in, 0);
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+	  else
+	    back_ch (c, s, &read_in, 0);
+
+	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	  wbuf[wbuf_cur_sz++] = 0;
+
+	  if ((flags & IS_LL))
+	    {
+	      if (flags & IS_SIGNED_NUM)
+		cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	      else
+		cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base);
+	    }
+	  else
+	    {
+	      if (flags & IS_SIGNED_NUM)
+		cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	      else
+		cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base);
+	    }
+	  if (wbuf == tmp_wbuf_ptr)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_SIGNED_NUM) != 0)
+		{
+		  if ((flags & IS_LL) != 0)
+		    *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
+		  else if ((flags & IS_L) != 0)
+		    *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
+		  else if ((flags & IS_S) != 0)
+		    *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
+		  else if ((flags & IS_C) != 0)
+		    *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
+		  else
+		    *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
+		}
+	      else
+		{
+		  if ((flags & IS_LL) != 0)
+		    *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
+		  else if ((flags & IS_L) != 0)
+		    *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
+		  else if ((flags & IS_S) != 0)
+		    *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
+		      = (unsigned short) cv_val.ul;
+		  else if ((flags & IS_C) != 0)
+		    *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
+		  else
+		    *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
+		}
+	      ++rval;
+	    }
+	  break;
+
+	case 'e': case 'E':
+	case 'f': case 'F':
+	case 'g': case 'G':
+	case 'a': case 'A':
+	  if (width > 0)
+	    --width;
+	  if ((c = in_ch (s, &read_in)) == EOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  seen_dot = seen_exp = 0;
+	  is_neg = (c == '-' ? 1 : 0);
+
+	  if (c == '-' || c == '+')
+	    {
+	      if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	      if (width > 0)
+		--width;
+	    }
+
+	  if (tolower (c) == 'n')
+	    {
+	      const char *match_txt = "nan";
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+
+	      ++match_txt;
+	      do
+		{
+		  if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+		  ++match_txt;
+		}
+	      while (*match_txt != 0);
+	    }
+	  else if (tolower (c) == 'i')
+	    {
+	      const char *match_txt = "inf";
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+
+	      ++match_txt;
+	      do
+		{
+		  if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+		  ++match_txt;
+		}
+	      while (*match_txt != 0);
+
+	      if (width != 0 && (c = in_ch (s, &read_in)) != EOF && tolower (c) == 'i')
+		{
+		  match_txt = "inity";
+
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+		  ++match_txt;
+
+		  do
+		    {
+		      if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		      if (width > 0)
+			--width;
+
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		      ++match_txt;
+		    }
+		  while (*match_txt != 0);
+		}
+	      else if (width != 0 && c != EOF)
+	        back_ch (c, s, &read_in, 0);
+	    }
+	  else
+	    {
+	      not_in = 'e';
+	      if (width != 0 && c == '0')
+		{
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+
+		  c = in_ch (s, &read_in);
+		  if (width > 0)
+		    --width;
+		  if (width != 0 && tolower (c) == 'x')
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+
+		      flags |= IS_HEX_FLOAT;
+		      not_in = 'p';
+
+		      flags &= ~USE_GROUP;
+		      c = in_ch (s, &read_in);
+		      if (width > 0)
+			--width;
+		    }
+		}
+
+	      while (1)
+		{
+		  if (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c))
+		      || (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in && (c == '-' || c == '+')))
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		    }
+		  else if (wbuf_cur_sz > 0 && !seen_exp && (char) tolower (c) == not_in)
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = not_in;
+		      seen_exp = seen_dot = 1;
+		    }
+		  else
+		    {
+		      const char *p = lc_decimal_point;
+		      int remain = width > 0 ? width : INT_MAX;
+
+		      if (! seen_dot)
+			{
+			  while ((unsigned char) *p == c && remain >= 0)
+			    {
+			      ++p;
+			      if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+				break;
+			      --remain;
+			    }
+			}
+
+		      if (*p == 0)
+			{
+			  for (p = lc_decimal_point; *p != 0; ++p)
+			    {
+			      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+			      wbuf[wbuf_cur_sz++] = (unsigned char) *p;
+			    }
+			  if (width > 0)
+			    width = remain;
+			  seen_dot = 1;
+			}
+		      else
+			{
+			  const char *pp = lc_thousands_sep;
+
+			  if (!seen_dot && (flags & USE_GROUP) != 0)
+			    {
+			      while ((pp - lc_thousands_sep) < (p - lc_decimal_point)
+				     && *pp == lc_decimal_point[(pp - lc_thousands_sep)])
+				++pp;
+			      if ((pp - lc_thousands_sep) == (p - lc_decimal_point))
+				{
+				  while ((unsigned char) *pp == c && remain >= 0)
+				    {
+				      ++pp;
+				      if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+					break;
+				      --remain;
+				    }
+				}
+			    }
+
+			  if (pp != NULL && *pp == 0)
+			    {
+			      /* As our conversion routines aren't supporting thousands
+				 separators, we are filtering them here.  */
+			      if (width > 0)
+				width = remain;
+			    }
+			  else
+			    {
+			      back_ch (c, s, &read_in, 0);
+			      break;
+			    }
+			}
+		    }
+
+		  if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
+		    break;
+
+		  if (width > 0)
+		    --width;
+		}
+
+	      if (!wbuf_cur_sz || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	    }
+
+	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	  wbuf[wbuf_cur_sz++] = 0;
+
+	  if ((flags & IS_LL) != 0)
+	    {
+	      long double ld;
+	      ld = __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+	        *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -ld : ld;
+	    }
+	  else if ((flags & IS_L) != 0)
+	    {
+	      double d;
+	      d = (double) __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+		*(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
+	    }
+	  else
+	    {
+	      float d = __mingw_strtof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+		*(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
+	    }
+
+	  if (wbuf == tmp_wbuf_ptr)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    ++rval;
+	  break;
+
+	case '[':
+	  if ((flags & IS_L) != 0)
+	    {
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  if ((flags & IS_ALLOC_USED) != 0)
+		    {
+		      if (npos != 0)
+			pstr = (char **) get_va_nth (argp, npos);
+		      else
+			pstr = va_arg (arg, char **);
+
+		      if (!pstr)
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		      str_sz = 100;
+		      *pstr = (char *) malloc (100 * sizeof (wchar_t));
+
+		      if ((wstr = (wchar_t *) *pstr) == NULL)
+			return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		      gcollect = resize_gcollect (gcollect);
+		      gcollect->ptrs[gcollect->count++] = pstr;
+		    }
+		  else
+		    {
+		      if (npos != 0)
+			wstr = (wchar_t *) get_va_nth (argp, npos);
+		      else
+			wstr = va_arg (arg, wchar_t *);
+		      if (!wstr)
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		    }
+		}
+	    }
+	  else if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		  if (npos != 0)
+		    pstr = (char **) get_va_nth (argp, npos);
+		  else
+		    pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+		  str_sz = 100;
+		  if ((str = *pstr = (char *) malloc (100)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  not_in = (*f == '^' ? 1 : 0);
+	  if (*f == '^')
+	    f++;
+
+	  if (width < 0)
+	    width = INT_MAX;
+
+	  if (wbuf_max_sz < 256)
+	    {
+	      wbuf_max_sz = 256;
+	      if (wbuf)
+	        free (wbuf);
+	      wbuf = (char *) malloc (wbuf_max_sz);
+	    }
+	  memset (wbuf, 0, 256);
+
+	  fc = *f;
+	  if (fc == ']' || fc == '-')
+	    {
+	      wbuf[fc] = 1;
+	      ++f;
+	    }
+
+	  while ((fc = *f++) != 0 && fc != ']')
+	    {
+	      if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f)
+		{
+		  for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
+		    wbuf[fc] = 1;
+		}
+	      else
+		wbuf[fc] = 1;
+	    }
+
+	  if (!fc)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_L) != 0)
+	    {
+	      read_in_sv = read_in;
+	      cnt = 0;
+
+	      if ((c = in_ch (s, &read_in)) == EOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      memset (&cstate, 0, sizeof (cstate));
+
+	      do
+		{
+		  if (wbuf[c] == not_in)
+		    {
+		      back_ch (c, s, &read_in, 1);
+		      break;
+		    }
+
+		  if ((flags & IS_SUPPRESSED) == 0)
+		    {
+		      buf[0] = c;
+		      n = mbrtowc (wstr, buf, 1, &cstate);
+
+		      if (n == (size_t) -2)
+			{
+			  ++cnt;
+			  continue;
+			}
+		      cnt = 0;
+
+		      ++wstr;
+		      if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
+			{
+			  new_sz = str_sz * 2;
+			  while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+			  	 && new_sz > (size_t) (str_sz + 1))
+			    new_sz = str_sz + 1;
+			  if (!wstr)
+			    {
+			      if ((flags & USE_POSIX_ALLOC) == 0)
+				{
+				  ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+				  pstr = NULL;
+				  ++rval;
+				}
+			      else
+				rval = EOF;
+			      return cleanup_return (rval, &gcollect, pstr, &wbuf);
+			    }
+			  *pstr = (char *) wstr;
+			  wstr += str_sz;
+			  str_sz = new_sz;
+			}
+		    }
+
+		  if (--width <= 0)
+		    break;
+		}
+	      while ((c = in_ch (s, &read_in)) != EOF);
+
+	      if (cnt != 0)
+		{
+		  errno = EILSEQ;
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+
+	      if (read_in_sv == read_in)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  *wstr++ = 0;
+		  optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+		  pstr = NULL;
+		  ++rval;
+		}
+	    }
+	  else
+	    {
+	      read_in_sv = read_in;
+
+	      if ((c = in_ch (s, &read_in)) == EOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      do
+		{
+		  if (wbuf[c] == not_in)
+		    {
+		      back_ch (c, s, &read_in, 1);
+		      break;
+		    }
+
+		  if ((flags & IS_SUPPRESSED) == 0)
+		    {
+		      *str++ = c;
+		      if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+			{
+			  new_sz = str_sz * 2;
+
+			  while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+			         && new_sz > (size_t) (str_sz + 1))
+			    new_sz = str_sz + 1;
+			  if (!str)
+			    {
+			      if ((flags & USE_POSIX_ALLOC) == 0)
+				{
+				  (*pstr)[str_sz - 1] = 0;
+				  pstr = NULL;
+				  ++rval;
+				}
+			      else
+			        rval = EOF;
+			      return cleanup_return (rval, &gcollect, pstr, &wbuf);
+			    }
+			  *pstr = str;
+			  str += str_sz;
+			  str_sz = new_sz;
+			}
+		    }
+		}
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+	      if (read_in_sv == read_in)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  *str++ = 0;
+		  optimize_alloc (pstr, str, str_sz);
+		  pstr = NULL;
+		  ++rval;
+		}
+	    }
+	  break;
+
+	default:
+	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	}
+    }
+
+  if (ignore_ws)
+    {
+      while (isspace ((c = in_ch (s, &read_in))));
+      back_ch (c, s, &read_in, 0);
+    }
+
+  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+}
+
+int
+__mingw_vfscanf (FILE *s, const char *format, va_list argp)
+{
+  _IFP ifp;
+  memset (&ifp, 0, sizeof (_IFP));
+  ifp.fp = s;
+  return __mingw_sformat (&ifp, format, argp);
+}
+
+int
+__mingw_vsscanf (const char *s, const char *format, va_list argp)
+{
+  _IFP ifp;
+  memset (&ifp, 0, sizeof (_IFP));
+  ifp.str = s;
+  ifp.is_string = 1;
+  return __mingw_sformat (&ifp, format, argp);
+}
+
lib/libc/mingw/stdio/mingw_vprintf.c
@@ -0,0 +1,58 @@
+/* vprintf.c
+ *
+ * $Id: vprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "vprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "vprintf" will normally be invoked by calling
+ * "__mingw_vprintf()" in preference to a direct reference to "vprintf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "vprint()".  Users who then
+ * wish to use this implementation may either call "__mingw_vprintf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "vprintf()" to "__mingw_vprintf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "vprintf()" in user
+ * code will ALWAYS be redirected to "__mingw_vprintf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "vprintf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_vprintf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __vprintf (const APICHAR *, va_list) __MINGW_NOTHROW;
+
+int __cdecl __vprintf(const APICHAR *fmt, va_list argv)
+{
+  register int retval;
+
+  _lock_file( stdout );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
+  _unlock_file( stdout );
+
+  return retval;
+}
lib/libc/mingw/stdio/mingw_vprintfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_vprintf.c"
+
lib/libc/mingw/stdio/mingw_vsnprintf.c
@@ -0,0 +1,52 @@
+/* vsnprintf.c
+ *
+ * $Id: vsnprintf.c,v 1.3 2008/07/28 23:24:20 keithmarshall Exp $
+ *
+ * Provides an implementation of the "vsnprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, replacing the redirection through
+ * libmoldnames.a, to the MSVCRT standard "_vsnprintf" function; (the
+ * standard MSVCRT function remains available, and may  be invoked
+ * directly, using this fully qualified form of its name).
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __vsnprintf (APICHAR *, size_t, const APICHAR *fmt, va_list) __MINGW_NOTHROW;
+int __cdecl __vsnprintf(APICHAR *buf, size_t length, const APICHAR *fmt, va_list argv )
+{
+  register int retval;
+
+  if( length == (size_t)(0) )
+    /*
+     * No buffer; simply compute and return the size required,
+     * without actually emitting any data.
+     */
+    return __pformat( 0, buf, 0, fmt, argv);
+
+  /* If we get to here, then we have a buffer...
+   * Emit data up to the limit of buffer length less one,
+   * then add the requisite NUL terminator.
+   */
+  retval = __pformat( 0, buf, --length, fmt, argv );
+  buf[retval < (int) length ? retval : (int)length] = '\0';
+
+  return retval;
+}
+
lib/libc/mingw/stdio/mingw_vsnprintfw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "mingw_vsnprintf.c"
+
lib/libc/mingw/stdio/mingw_vsprintf.c
@@ -0,0 +1,54 @@
+/* vsprintf.c
+ *
+ * $Id: vsprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
+ *
+ * Provides an implementation of the "vsprintf" function, conforming
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.  This
+ * is included in libmingwex.a, whence it may replace the Microsoft
+ * function of the same name.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This implementation of "vsprintf" will normally be invoked by calling
+ * "__mingw_vsprintf()" in preference to a direct reference to "vsprintf()"
+ * itself; this leaves the MSVCRT implementation as the default, which
+ * will be deployed when user code invokes "vsprint()".  Users who then
+ * wish to use this implementation may either call "__mingw_vsprintf()"
+ * directly, or may use conditional preprocessor defines, to redirect
+ * references to "vsprintf()" to "__mingw_vsprintf()".
+ *
+ * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
+ * recommended convention, such that references to "vsprintf()" in user
+ * code will ALWAYS be redirected to "__mingw_vsprintf()"; if this option
+ * is adopted, then users wishing to use the MSVCRT implementation of
+ * "vsprintf()" will be forced to use a "back-door" mechanism to do so.
+ * Such a "back-door" mechanism is provided with MinGW, allowing the
+ * MSVCRT implementation to be called as "__msvcrt_vsprintf()"; however,
+ * since users may not expect this behaviour, a standard libmingwex.a
+ * installation does not employ this option.
+ *
+ *
+ * This is free software.  You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "mingw_pformat.h"
+
+int __cdecl __vsprintf (APICHAR *, const APICHAR *, va_list) __MINGW_NOTHROW;
+
+int __cdecl __vsprintf(APICHAR *buf, const APICHAR *fmt, va_list argv)
+{
+  register int retval;
+  buf[retval = __pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
+  return retval;
+}
lib/libc/mingw/stdio/mingw_vsprintfw.c
@@ -0,0 +1,10 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+#define _CRT_NON_CONFORMING_SWPRINTFS 1
+
+#include "mingw_vsprintf.c"
+
lib/libc/mingw/stdio/mingw_wscanf.c
@@ -0,0 +1,28 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int __mingw_vfwscanf (FILE *stream, const wchar_t *format, va_list argp);
+
+int __mingw_wscanf (const wchar_t *format, ...);
+int __mingw_vwscanf (const wchar_t *format, va_list argp);
+
+int
+__mingw_wscanf (const wchar_t *format, ...)
+{
+  va_list argp;
+  int r;
+
+  va_start (argp, format);
+  r = __mingw_vfwscanf (stdin, format, argp);
+  va_end (argp);
+
+  return r;
+}
+
+int
+__mingw_vwscanf (const wchar_t *format, va_list argp)
+{
+  return __mingw_vfwscanf (stdin, format, argp);
+}
+
lib/libc/mingw/stdio/mingw_wvfscanf.c
@@ -0,0 +1,1631 @@
+/*
+ This Software is provided under the Zope Public License (ZPL) Version 2.1.
+
+ Copyright (c) 2011 by the mingw-w64 project
+
+ See the AUTHORS file for the list of contributors to the mingw-w64 project.
+
+ This license has been certified as open source. It has also been designated
+ as GPL compatible by the Free Software Foundation (FSF).
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions in source code must retain the accompanying copyright
+      notice, this list of conditions, and the following disclaimer.
+   2. Redistributions in binary form must reproduce the accompanying
+      copyright notice, this list of conditions, and the following disclaimer
+      in the documentation and/or other materials provided with the
+      distribution.
+   3. Names of the copyright holders must not be used to endorse or promote
+      products derived from this software without prior written permission
+      from the copyright holders.
+   4. The right to distribute this software or to use it for any purpose does
+      not give you the right to use Servicemarks (sm) or Trademarks (tm) of
+      the copyright holders.  Use of them is covered by separate agreement
+      with the copyright holders.
+   5. If any files are modified, you must cause the modified files to carry
+      prominent notices stating that you changed the files and the date of
+      any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+ 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 COPYRIGHT HOLDERS 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.
+*/
+
+#define __LARGE_MBSTATE_T
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <locale.h>
+#include <errno.h>
+
+#ifndef CP_UTF8
+#define CP_UTF8 65001
+#endif
+
+#ifndef MB_ERR_INVALID_CHARS
+#define MB_ERR_INVALID_CHARS 0x00000008
+#endif
+
+/* Helper flags for conversion.  */
+#define IS_C		0x0001
+#define IS_S		0x0002
+#define IS_L		0x0004
+#define IS_LL		0x0008
+#define IS_SIGNED_NUM	0x0010
+#define IS_POINTER	0x0020
+#define IS_HEX_FLOAT	0x0040
+#define IS_SUPPRESSED	0x0080
+#define USE_GROUP	0x0100
+#define USE_GNU_ALLOC	0x0200
+#define USE_POSIX_ALLOC	0x0400
+
+#define IS_ALLOC_USED	(USE_GNU_ALLOC | USE_POSIX_ALLOC)
+
+/* internal stream structure with back-buffer.  */
+typedef struct _IFP
+{
+  __extension__ union {
+    void *fp;
+    const wchar_t *str;
+  };
+  int bch[1024];
+  unsigned int is_string : 1;
+  int back_top;
+  unsigned int seen_eof : 1;
+} _IFP;
+
+static void *
+get_va_nth (va_list argp, unsigned int n)
+{
+  va_list ap;
+  if (!n)
+    abort ();
+  va_copy (ap, argp);
+  while (--n > 0)
+    (void) va_arg(ap, void *);
+  return va_arg (ap, void *);
+}
+
+static void
+optimize_alloc (char **p, char *end, size_t alloc_sz)
+{
+  size_t need_sz;
+  char *h;
+
+  if (!p || !*p)
+    return;
+
+  need_sz = end - *p;
+  if (need_sz == alloc_sz)
+    return;
+
+  if ((h = (char *) realloc (*p, need_sz)) != NULL)
+    *p = h;
+}
+
+static void
+back_ch (int c, _IFP *s, size_t *rin, int not_eof)
+{
+  if (!not_eof && c == WEOF)
+    return;
+  if (s->is_string == 0)
+    {
+      FILE *fp = s->fp;
+      ungetwc (c, fp);
+      rin[0] -= 1;
+      return;
+    }
+  rin[0] -= 1;
+  s->bch[s->back_top] = c;
+  s->back_top += 1;
+}
+
+static int
+in_ch (_IFP *s, size_t *rin)
+{
+  int r;
+  if (s->back_top)
+  {
+    s->back_top -= 1;
+    r = s->bch[s->back_top];
+    rin[0] += 1;
+  }
+  else if (s->seen_eof)
+  {
+    return WEOF;
+  }
+  else if (s->is_string)
+  {
+    const wchar_t *ps = s->str;
+    r = ((int) *ps) & 0xffff;
+    ps++;
+    if (r != 0)
+    {
+      rin[0] += 1;
+      s->str = ps;
+      return r;
+    }
+    s->seen_eof = 1;
+    return WEOF;
+  }
+  else
+  {
+    FILE *fp = (FILE *) s->fp;
+    r = getwc (fp);
+    if (r != WEOF)
+      rin[0] += 1;
+    else s->seen_eof = 1;
+  }
+  return r;
+}
+
+static int
+match_string (_IFP *s, size_t *rin, wint_t *c, const wchar_t *str)
+{
+  int ch = *c;
+
+  if (*str == 0)
+    return 1;
+
+  if (*str != (wchar_t) towlower (ch))
+    return 0;
+  ++str;
+  while (*str != 0)
+  {
+    if ((ch = in_ch (s, rin)) == WEOF)
+    {
+      c[0] = ch;
+      return 0;
+    }
+
+    if (*str != (wchar_t) towlower (ch))
+    {
+      c[0] = ch;
+      return 0;
+    }
+    ++str;
+  }
+  c[0] = ch;
+  return 1;
+}
+
+struct gcollect
+{
+  size_t count;
+  struct gcollect *next;
+  char **ptrs[32];
+};
+
+static void
+release_ptrs (struct gcollect **pt, wchar_t **wbuf)
+{
+  struct gcollect *pf;
+  size_t cnt;
+
+  if (wbuf)
+    {
+      free (*wbuf);
+      *wbuf = NULL;
+    }
+  if (!pt || (pf = *pt) == NULL)
+    return;
+  while (pf != NULL)
+    {
+      struct gcollect *pf_sv = pf;
+      for (cnt = 0; cnt < pf->count; ++cnt)
+	{
+	  free (*pf->ptrs[cnt]);
+	  *pf->ptrs[cnt] = NULL;
+	}
+      pf = pf->next;
+      free (pf_sv);
+    }
+  *pt = NULL;
+}
+
+static int
+cleanup_return (int rval, struct gcollect **pfree, char **strp, wchar_t **wbuf)
+{
+  if (rval == EOF)
+      release_ptrs (pfree, wbuf);
+  else
+    {
+      if (pfree)
+        {
+          struct gcollect *pf = *pfree, *pf_sv;
+          while (pf != NULL)
+            {
+              pf_sv = pf;
+              pf = pf->next;
+              free (pf_sv);
+            }
+          *pfree = NULL;
+        }
+      if (strp != NULL)
+	{
+	  free (*strp);
+	  *strp = NULL;
+	}
+      if (wbuf)
+	{
+	  free (*wbuf);
+	  *wbuf = NULL;
+	}
+    }
+  return rval;
+}
+
+static struct gcollect *
+resize_gcollect (struct gcollect *pf)
+{
+  struct gcollect *np;
+  if (pf && pf->count < 32)
+    return pf;
+  np = malloc (sizeof (struct gcollect));
+  np->count = 0;
+  np->next = pf;
+  return np;
+}
+
+static wchar_t *
+resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, wchar_t *old)
+{
+  wchar_t *wbuf;
+  size_t nsz;
+  if (*wbuf_max_sz != wpsz)
+    return old;
+  nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
+  if (!old)
+    wbuf = (wchar_t *) malloc (nsz * sizeof (wchar_t));
+  else
+    wbuf = (wchar_t *) realloc (old, nsz * sizeof (wchar_t));
+  if (!wbuf)
+  {
+    if (old)
+      free (old);
+  }
+  else
+    *wbuf_max_sz = nsz;
+  return wbuf;
+}
+
+static int
+__mingw_swformat (_IFP *s, const wchar_t *format, va_list argp)
+{
+  const wchar_t *f = format;
+  struct gcollect *gcollect = NULL;
+  size_t read_in = 0, wbuf_max_sz = 0;
+  ssize_t str_sz = 0;
+  char *str = NULL, **pstr = NULL;;
+  wchar_t *wstr = NULL, *wbuf = NULL;
+  wint_t c = 0, rval = 0;
+  int ignore_ws = 0;
+  va_list arg;
+  size_t wbuf_cur_sz, str_len, read_in_sv, new_sz, n;
+  unsigned int fc, npos;
+  int width, flags, base = 0, errno_sv, clen;
+  char seen_dot, seen_exp, is_neg, *nstr, buf[MB_LEN_MAX];
+  wchar_t wc, not_in, *tmp_wbuf_ptr, *temp_wbuf_end, *wbuf_iter;
+  wint_t lc_decimal_point, lc_thousands_sep;
+  mbstate_t state;
+  union {
+    unsigned long long ull;
+    unsigned long ul;
+    long long ll;
+    long l;
+  } cv_val;
+
+  arg = argp;
+
+  if (!s || s->fp == NULL || !format)
+    {
+      errno = EINVAL;
+      return EOF;
+    }
+
+  memset (&state, 0, sizeof(state));
+  clen = mbrtowc( &wc, localeconv()->decimal_point, 16, &state);
+  lc_decimal_point = (clen > 0 ? wc : '.');
+  memset( &state, 0, sizeof( state ) );
+  clen = mbrtowc( &wc, localeconv()->thousands_sep, 16, &state);
+  lc_thousands_sep = (clen > 0 ? wc : 0);
+
+  while (*f != 0)
+    {
+      fc = *f++;
+      if (fc != '%')
+        {
+          if (iswspace (fc))
+	    ignore_ws = 1;
+	  else
+	    {
+	      if ((c = in_ch (s, &read_in)) == WEOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      if (ignore_ws)
+		{
+		  ignore_ws = 0;
+		  if (iswspace (c))
+		    {
+		      do
+			{
+			  if ((c = in_ch (s, &read_in)) == WEOF)
+			    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+			}
+		      while (iswspace (c));
+		    }
+		}
+
+	      if (c != fc)
+		{
+		  back_ch (c, s, &read_in, 0);
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  continue;
+	}
+
+      width = flags = 0;
+      npos = 0;
+      wbuf_cur_sz = 0;
+
+      if (iswdigit ((unsigned int) *f))
+	{
+	  const wchar_t *svf = f;
+	  npos = (unsigned int) *f++ - '0';
+	  while (iswdigit ((unsigned int) *f))
+	    npos = npos * 10 + ((unsigned int) *f++ - '0');
+	  if (*f != '$')
+	    {
+	      npos = 0;
+	      f = svf;
+	    }
+	  else
+	    f++;
+	}
+
+      do
+	{
+	  if (*f == '*')
+	    flags |= IS_SUPPRESSED;
+	  else if (*f == '\'')
+	    {
+	      if (lc_thousands_sep)
+		flags |= USE_GROUP;
+	    }
+	  else if (*f == 'I')
+	    {
+	      /* we don't support locale's digits (i18N), but ignore it for now silently.  */
+	      ;
+#ifdef _WIN32
+              if (f[1] == '6' && f[2] == '4')
+                {
+		  flags |= IS_LL | IS_L;
+		  f += 2;
+		}
+	      else if (f[1] == '3' && f[2] == '2')
+		{
+		  flags |= IS_L;
+		  f += 2;
+		}
+	      else
+	        {
+#ifdef _WIN64
+		  flags |= IS_LL | IS_L;
+#else
+		  flags |= IS_L;
+#endif
+		}
+#endif
+	    }
+	  else
+	    break;
+	  ++f;
+        }
+      while (1);
+
+      while (iswdigit ((unsigned char) *f))
+	width = width * 10 + ((unsigned char) *f++ - '0');
+
+      if (!width)
+	width = -1;
+
+      switch (*f)
+	{
+	case 'h':
+	  ++f;
+	  flags |= (*f == 'h' ? IS_C : IS_S);
+	  if (*f == 'h')
+	    ++f;
+	  break;
+	case 'l':
+	  ++f;
+	  flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
+	  if (*f == 'l')
+	    ++f;
+	  break;
+	case 'q': case 'L':
+	  ++f;
+	  flags |= IS_LL | IS_L;
+	  break;
+	case 'a':
+	  if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
+	    break;
+	  ++f;
+	  flags |= USE_GNU_ALLOC;
+	  break;
+	case 'm':
+	  flags |= USE_POSIX_ALLOC;
+	  ++f;
+	  if (*f == 'l')
+	    {
+	      flags |= IS_L;
+	      ++f;
+	    }
+	  break;
+	case 'z':
+#ifdef _WIN64
+	  flags |= IS_LL | IS_L;
+#else
+	  flags |= IS_L;
+#endif
+	  ++f;
+	  break;
+	case 'j':
+	  if (sizeof (uintmax_t) > sizeof (unsigned long))
+	    flags |= IS_LL;
+	  else if (sizeof (uintmax_t) > sizeof (unsigned int))
+	    flags |= IS_L;
+	  ++f;
+	  break;
+	case 't':
+#ifdef _WIN64
+	  flags |= IS_LL;
+#else
+	  flags |= IS_L;
+#endif
+	  ++f;
+	  break;
+	case 0:
+	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	default:
+	  break;
+	}
+
+      if (*f == 0)
+	return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+      fc = *f++;
+      if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
+	{
+	  errno_sv = errno;
+	  errno = 0;
+	  do
+	    {
+	      if ((c == WEOF || (c = in_ch (s, &read_in)) == WEOF) && errno == EINTR)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	    }
+	  while (iswspace (c));
+
+	  ignore_ws = 0;
+	  errno = errno_sv;
+	  back_ch (c, s, &read_in, 0);
+	}
+
+      switch (fc)
+        {
+        case 'c':
+          if ((flags & IS_L) != 0)
+            fc = 'C';
+          break;
+        case 's':
+          if ((flags & IS_L) != 0)
+            fc = 'S';
+          break;
+        }
+
+      switch (fc)
+	{
+	case '%':
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	  if (c != fc)
+	    {
+	      back_ch (c, s, &read_in, 1);
+	      return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	    }
+	  break;
+
+	case 'n':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_LL) != 0)
+		*(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
+	      else if ((flags & IS_L) != 0)
+		*(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
+	      else if ((flags & IS_S) != 0)
+		*(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
+	      else if ((flags & IS_C) != 0)
+	        *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
+	      else
+		*(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
+	    }
+	  break;
+
+	case 'c':
+	  if (width == -1)
+	    width = 1;
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		   if (npos != 0)
+		     pstr = (char **) get_va_nth (argp, npos);
+		   else
+		     pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = 100;
+		  if ((str = *pstr = (char *) malloc (100)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		     str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  memset (&state, 0, sizeof (state));
+
+	  do
+	    {
+	      if ((flags & IS_SUPPRESSED) == 0 && (flags & USE_POSIX_ALLOC) != 0
+		  && (str + MB_CUR_MAX) >= (*pstr + str_sz))
+		{
+		  new_sz = str_sz * 2;
+		  str_len = (str - *pstr);
+		  while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
+			 && new_sz > (str_len + MB_CUR_MAX))
+		    new_sz = str_len + MB_CUR_MAX;
+		  if (!nstr)
+		    {
+		      release_ptrs (&gcollect, &wbuf);
+		      return EOF;
+		    }
+		  *pstr = nstr;
+		  str = nstr + str_len;
+		  str_sz = new_sz;
+		}
+
+	      n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
+	      if (n == (size_t) -1LL)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+	      str += n;
+	    }
+	  while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      optimize_alloc (pstr, str, str_sz);
+	      pstr = NULL;
+	      ++rval;
+	    }
+
+	  break;
+
+	case 'C':
+	  if (width == -1)
+	    width = 1;
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		 if (npos != 0)
+		   pstr = (char **) get_va_nth (argp, npos);
+		 else
+		   pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = (width > 1024 ? 1024 : width);
+		  *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
+		  if ((wstr = (wchar_t *) *pstr) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+		  if ((wstr = (wchar_t *) *pstr) != NULL)
+		    {
+		      gcollect = resize_gcollect (gcollect);
+		      gcollect->ptrs[gcollect->count++] = pstr;
+		    }
+		}
+	      else
+		{
+		  if (npos != 0)
+		    wstr = (wchar_t *) get_va_nth (argp, npos);
+		  else
+		    wstr = va_arg (arg, wchar_t *);
+		  if (!wstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      do
+		{
+		  if ((flags & IS_ALLOC_USED) != 0
+		      && wstr == ((wchar_t *) *pstr + str_sz))
+		    {
+		      new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
+		      while ((wstr = (wchar_t *) realloc (*pstr,
+						  new_sz * sizeof (wchar_t))) == NULL
+			     && new_sz > (size_t) (str_sz + 1))
+			new_sz = str_sz + 1;
+		      if (!wstr)
+			{
+			  release_ptrs (&gcollect, &wbuf);
+			  return EOF;
+			}
+		      *pstr = (char *) wstr;
+		      wstr += str_sz;
+		      str_sz = new_sz;
+		    }
+		  *wstr++ = c;
+		}
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
+	    }
+	  else
+	    {
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
+	    }
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 's':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		 if (npos != 0)
+		   pstr = (char **) get_va_nth (argp, npos);
+		 else
+		   pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = 100;
+		  if ((str = *pstr = (char *) malloc (100)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  memset (&state, 0, sizeof (state));
+
+	  do
+	    {
+	      if (iswspace (c))
+		{
+		  back_ch (c, s, &read_in, 1);
+		  break;
+		}
+
+	      {
+		if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
+		    && (str + MB_CUR_MAX) >= (*pstr + str_sz))
+		  {
+		    new_sz = str_sz * 2;
+		    str_len = (str - *pstr);
+
+		    while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
+			   && new_sz > (str_len + MB_CUR_MAX))
+		      new_sz = str_len + MB_CUR_MAX;
+		    if (!nstr)
+		      {
+			if ((flags & USE_POSIX_ALLOC) == 0)
+			  {
+			    (*pstr)[str_len] = 0;
+			    pstr = NULL;
+			    ++rval;
+			  }
+			return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		      }
+		    *pstr = nstr;
+		    str = nstr + str_len;
+		    str_sz = new_sz;
+		  }
+
+		n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c,
+			       &state);
+		if (n == (size_t) -1LL)
+		{
+		  errno = EILSEQ;
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+
+		str += n;
+	      }
+	    }
+	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      n = wcrtomb (buf, 0, &state);
+	      if (n > 0 && (flags & IS_ALLOC_USED) != 0
+		  && (str + n) >= (*pstr + str_sz))
+		{
+		  str_len = (str - *pstr);
+
+		  if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
+		    {
+		      if ((flags & USE_POSIX_ALLOC) == 0)
+			{
+			  (*pstr)[str_len] = 0;
+			  pstr = NULL;
+			  ++rval;
+			}
+		      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		    }
+		  *pstr = nstr;
+		  str = nstr + str_len;
+		  str_sz = str_len + n + 1;
+		}
+
+	      if (n)
+	      {
+		memcpy (str, buf, n);
+		str += n;
+	      }
+	      *str++ = 0;
+
+	      optimize_alloc (pstr, str, str_sz);
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 'S':
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		 if (npos != 0)
+		   pstr = (char **) get_va_nth (argp, npos);
+		 else
+		   pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = 100;
+		  *pstr = (char *) malloc (100 * sizeof (wchar_t));
+		  if ((wstr = (wchar_t *) *pstr) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    wstr = (wchar_t *) get_va_nth (argp, npos);
+		  else
+		    wstr = va_arg (arg, wchar_t *);
+		  if (!wstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  do
+	    {
+	      if (iswspace (c))
+		{
+		  back_ch (c, s, &read_in, 1);
+		  break;
+		}
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  *wstr++ = c;
+		  if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
+		    {
+		      new_sz = str_sz * 2;
+
+		      while ((wstr = (wchar_t *) realloc (*pstr,
+						  new_sz * sizeof (wchar_t))) == NULL
+			      && new_sz > (size_t) (str_sz + 1))
+			new_sz = str_sz + 1;
+		      if (!wstr)
+			{
+			  if ((flags & USE_POSIX_ALLOC) == 0)
+			    {
+			      ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+			      pstr = NULL;
+			      ++rval;
+			    }
+			  return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+			}
+		      *pstr = (char *) wstr;
+		      wstr += str_sz;
+		      str_sz = new_sz;
+		    }
+		}
+	    }
+	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      *wstr++ = 0;
+
+	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+	      pstr = NULL;
+	      ++rval;
+	    }
+	  break;
+
+	case 'd': case 'i':
+	case 'o': case 'p':
+	case 'u':
+	case 'x': case 'X':
+	  switch (fc)
+	    {
+	    case 'd':
+	      flags |= IS_SIGNED_NUM;
+	      base = 10;
+	      break;
+	    case 'i':
+	      flags |= IS_SIGNED_NUM;
+	      base = 0;
+	      break;
+	    case 'o':
+	      base = 8;
+	      break;
+	    case 'p':
+	      base = 16;
+	      flags &= ~(IS_S | IS_LL | IS_L);
+    #ifdef _WIN64
+	      flags |= IS_LL;
+    #endif
+	      flags |= IS_L | IS_POINTER;
+	      break;
+	    case 'u':
+	      base = 10;
+	      break;
+	    case 'x': case 'X':
+	      base = 16;
+	      break;
+	    }
+
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  if (c == '+' || c == '-')
+	    {
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+
+	      if (width > 0)
+		--width;
+	      c = in_ch (s, &read_in);
+	    }
+
+	  if (width != 0 && c == '0')
+	    {
+	      if (width > 0)
+		--width;
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+
+	      c = in_ch (s, &read_in);
+
+	      if (width != 0 && towlower (c) == 'x')
+		{
+		  if (!base)
+		    base = 16;
+		  if (base == 16)
+		    {
+		      if (width > 0)
+			--width;
+		      c = in_ch (s, &read_in);
+		    }
+		}
+	      else if (!base)
+		base = 8;
+	    }
+
+	  if (!base)
+	    base = 10;
+
+	  while (c != WEOF && width != 0)
+	    {
+	      if (base == 16)
+		{
+		  if (!iswxdigit (c))
+		    break;
+		}
+	      else if (!iswdigit (c) || (int) (c - '0') >= base)
+		{
+		  if (base != 10 || (flags & USE_GROUP) == 0 || c != lc_thousands_sep)
+		    break;
+		}
+	      if (c != lc_thousands_sep)
+	        {
+	          wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	          wbuf[wbuf_cur_sz++] = c;
+		}
+
+	      if (width > 0)
+		--width;
+
+	      c = in_ch (s, &read_in);
+	    }
+
+	  if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
+	    {
+	      if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
+		  && match_string (s, &read_in, &c, L"(nil)"))
+		{
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = '0';
+		}
+	      else
+		{
+		  back_ch (c, s, &read_in, 0);
+		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+	  else
+	    back_ch (c, s, &read_in, 0);
+
+	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	  wbuf[wbuf_cur_sz++] = 0;
+
+	  if ((flags & IS_LL) != 0)
+	    {
+	      if ((flags & IS_SIGNED_NUM) != 0)
+		cv_val.ll = wcstoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	      else
+		cv_val.ull = wcstoull (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	    }
+	  else
+	    {
+	      if ((flags & IS_SIGNED_NUM) != 0)
+		cv_val.l = wcstol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	      else
+		cv_val.ul = wcstoul (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+	    }
+	  if (wbuf == tmp_wbuf_ptr)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_SIGNED_NUM) != 0)
+		{
+		  if ((flags & IS_LL) != 0)
+		    *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
+		  else if ((flags & IS_L) != 0)
+		    *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
+		  else if ((flags & IS_S) != 0)
+		    *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
+		  else if ((flags & IS_C) != 0)
+		    *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
+		  else
+		    *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
+		}
+	      else
+		{
+		  if ((flags & IS_LL) != 0)
+		    *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
+		  else if ((flags & IS_L) != 0)
+		    *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
+		  else if ((flags & IS_S) != 0)
+		    *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
+		      = (unsigned short) cv_val.ul;
+		  else if ((flags & IS_C) != 0)
+		    *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
+		  else
+		    *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
+		}
+	      ++rval;
+	    }
+	  break;
+
+	case 'e': case 'E':
+	case 'f': case 'F':
+	case 'g': case 'G':
+	case 'a': case 'A':
+	  if (width > 0)
+	    --width;
+	  if ((c = in_ch (s, &read_in)) == WEOF)
+	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	  seen_dot = seen_exp = 0;
+	  is_neg = (c == '-' ? 1 : 0);
+
+	  if (c == '-' || c == '+')
+	    {
+	      if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	      if (width > 0)
+		--width;
+	    }
+
+	  if (towlower (c) == 'n')
+	    {
+	      const wchar_t *match_txt = L"nan";
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+	      
+	      ++match_txt;
+	      do
+		{
+		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
+		      || towlower (c) != match_txt[0])
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+		  ++match_txt;
+		}
+	      while (*match_txt != 0);
+	    }
+	  else if (towlower (c) == 'i')
+	    {
+	      const wchar_t *match_txt = L"inf";
+
+	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	      wbuf[wbuf_cur_sz++] = c;
+
+	      ++match_txt;
+	      do
+		{
+		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
+		      || towlower (c) != match_txt[0])
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+		  ++match_txt;
+		}
+	      while (*match_txt != 0);
+
+	      if (width != 0 && (c = in_ch (s, &read_in)) != WEOF && towlower (c) == 'i')
+		{
+		  match_txt = L"inity";
+		  if (width > 0)
+		    --width;
+
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+
+		  ++match_txt;
+		  do
+		    {
+		      if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
+			  || towlower (c) != match_txt[0])
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		      if (width > 0)
+			--width;
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		      ++match_txt;
+		    }
+		  while (*match_txt != 0);
+		}
+	      else if (width != 0 && c != WEOF)
+	        back_ch (c, s, &read_in, 0);
+	    }
+	  else
+	    {
+	      not_in = 'e';
+	      if (width != 0 && c == '0')
+		{
+		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		  wbuf[wbuf_cur_sz++] = c;
+
+		  c = in_ch (s, &read_in);
+		  if (width > 0)
+		    --width;
+		  if (width != 0 && towlower (c) == 'x')
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		      flags |= IS_HEX_FLOAT;
+		      not_in = 'p';
+
+		      flags &= ~USE_GROUP;
+		      c = in_ch (s, &read_in);
+		      if (width > 0)
+			--width;
+		    }
+		}
+
+	      while (1)
+		{
+		  if (iswdigit (c))
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		    }
+		  else if (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && iswxdigit (c))
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		    }
+		  else if (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in
+			   && (c == '-' || c == '+'))
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = c;
+		    }
+		  else if (wbuf_cur_sz > 0 && !seen_exp
+			   && (wchar_t) towlower (c) == not_in)
+		    {
+		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+		      wbuf[wbuf_cur_sz++] = not_in;
+
+		      seen_exp = seen_dot = 1;
+		    }
+		  else
+		    {
+		      if (!seen_dot && c == lc_decimal_point)
+			{
+			  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+			  wbuf[wbuf_cur_sz++] = c;
+
+			  seen_dot = 1;
+			}
+		      else if ((flags & USE_GROUP) != 0 && !seen_dot && c == lc_thousands_sep)
+			{
+			  /* As our conversion routines aren't supporting thousands
+			     separators, we are filtering them here.  */
+			}
+		      else
+			{
+			  back_ch (c, s, &read_in, 0);
+			  break;
+			}
+		    }
+
+		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
+		    break;
+
+		  if (width > 0)
+		    --width;
+		}
+
+	      if (wbuf_cur_sz == 0 || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	    }
+
+	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+	  wbuf[wbuf_cur_sz++] = 0;
+
+	  if ((flags & IS_LL) != 0)
+	    {
+	      long double d = __mingw_wcstold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+		*(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -d : d;
+	    }
+	  else if ((flags & IS_L) != 0)
+	    {
+	      double d = __mingw_wcstod (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+		*(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
+	    }
+	  else
+	    {
+	      float d = __mingw_wcstof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+		*(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
+	    }
+
+	  if (wbuf == tmp_wbuf_ptr)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	  if ((flags & IS_SUPPRESSED) == 0)
+	    ++rval;
+	  break;
+
+	case '[':
+	  if ((flags & IS_L) != 0)
+	    {
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  if ((flags & IS_ALLOC_USED) != 0)
+		    {
+		     if (npos != 0)
+		       pstr = (char **) get_va_nth (argp, npos);
+		     else
+		       pstr = va_arg (arg, char **);
+
+		      if (!pstr)
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		      str_sz = 100;
+		      *pstr = (char *) malloc (100 * sizeof (wchar_t));
+		      if ((wstr = (wchar_t *) *pstr) == NULL)
+			return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+		      gcollect = resize_gcollect (gcollect);
+		      gcollect->ptrs[gcollect->count++] = pstr;
+		    }
+		  else
+		    {
+		      if (npos != 0)
+			wstr = (wchar_t *) get_va_nth (argp, npos);
+		      else
+			wstr = va_arg (arg, wchar_t *);
+		      if (!wstr)
+			return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		    }
+		}
+
+	    }
+	  else if ((flags & IS_SUPPRESSED) == 0)
+	    {
+	      if ((flags & IS_ALLOC_USED) != 0)
+		{
+		 if (npos != 0)
+		   pstr = (char **) get_va_nth (argp, npos);
+		 else
+		   pstr = va_arg (arg, char **);
+
+		  if (!pstr)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  str_sz = 100;
+		  if ((str = *pstr = (char *) malloc (100)) == NULL)
+		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+		  gcollect = resize_gcollect (gcollect);
+		  gcollect->ptrs[gcollect->count++] = pstr;
+		}
+	      else
+		{
+		  if (npos != 0)
+		    str = (char *) get_va_nth (argp, npos);
+		  else
+		    str = va_arg (arg, char *);
+		  if (!str)
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		}
+	    }
+
+	  not_in = (*f == '^' ? 1 : 0);
+	  if (*f == '^')
+	    f++;
+
+	  if (width < 0)
+	    width = INT_MAX;
+
+	  tmp_wbuf_ptr = (wchar_t *) f;
+
+	  if (*f == L']')
+	    ++f;
+
+	  while ((fc = *f++) != 0 && fc != L']');
+
+	  if (fc == 0)
+	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	  temp_wbuf_end = (wchar_t *) f - 1;
+
+	  if ((flags & IS_L) != 0)
+	    {
+	      read_in_sv = read_in;
+
+	      if ((c = in_ch (s, &read_in)) == WEOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      do
+		{
+		  int ended = 0;
+		  for (wbuf_iter = tmp_wbuf_ptr; wbuf_iter < temp_wbuf_end;)
+		    {
+		      if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
+			  && (wbuf_iter + 1) != temp_wbuf_end
+			  && wbuf_iter != tmp_wbuf_ptr
+			  && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
+			{
+			  for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
+
+			  if (wc <= wbuf_iter[1] && !not_in)
+			    break;
+			  if (wc <= wbuf_iter[1] && not_in)
+			    {
+			      back_ch (c, s, &read_in, 0);
+			      ended = 1;
+			      break;
+			    }
+
+			  wbuf_iter += 2;
+			}
+		      else
+			{
+			  if ((wint_t) *wbuf_iter == c && !not_in)
+			    break;
+			  if ((wint_t) *wbuf_iter == c && not_in)
+			    {
+			      back_ch (c, s, &read_in, 0);
+			      ended = 1;
+			      break;
+			    }
+
+			  ++wbuf_iter;
+			}
+		    }
+		  if (ended)
+		    break;
+
+		  if (wbuf_iter == temp_wbuf_end && !not_in)
+		    {
+		      back_ch (c, s, &read_in, 0);
+		      break;
+		    }
+
+		  if ((flags & IS_SUPPRESSED) == 0)
+		    {
+		      *wstr++ = c;
+
+		      if ((flags & IS_ALLOC_USED) != 0
+			  && wstr == ((wchar_t *) *pstr + str_sz))
+			{
+			  new_sz = str_sz * 2;
+			  while ((wstr = (wchar_t *) realloc (*pstr,
+						      new_sz * sizeof (wchar_t))) == NULL
+				 && new_sz > (size_t) (str_sz + 1))
+			    new_sz = str_sz + 1;
+			  if (!wstr)
+			    {
+			      if ((flags & USE_POSIX_ALLOC) == 0)
+				{
+				  ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+				  pstr = NULL;
+				  ++rval;
+				}
+			      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+			    }
+			  *pstr = (char *) wstr;
+			  wstr += str_sz;
+			  str_sz = new_sz;
+			}
+		    }
+		}
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
+
+	      if (read_in_sv == read_in)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  *wstr++ = 0;
+
+		  optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+		  pstr = NULL;
+		  ++rval;
+		}
+	    }
+	  else
+	    {
+	      read_in_sv = read_in;
+
+	      if ((c = in_ch (s, &read_in)) == WEOF)
+		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+	      memset (&state, 0, sizeof (state));
+
+	      do
+		{
+		  int ended = 0;
+		  wbuf_iter = tmp_wbuf_ptr;
+		  while (wbuf_iter < temp_wbuf_end)
+		    {
+		      if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
+			  && (wbuf_iter + 1) != temp_wbuf_end
+			  && wbuf_iter != tmp_wbuf_ptr
+			  && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
+			{
+			  for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
+
+			  if (wc <= wbuf_iter[1] && !not_in)
+			    break;
+			  if (wc <= wbuf_iter[1] && not_in)
+			    {
+			      back_ch (c, s, &read_in, 0);
+			      ended = 1;
+			      break;
+			    }
+
+			  wbuf_iter += 2;
+			}
+		      else
+			{
+			  if ((wint_t) *wbuf_iter == c && !not_in)
+			    break;
+			  if ((wint_t) *wbuf_iter == c && not_in)
+			    {
+			      back_ch (c, s, &read_in, 0);
+			      ended = 1;
+			      break;
+			    }
+
+			  ++wbuf_iter;
+			}
+		    }
+
+		  if (ended)
+		    break;
+		  if (wbuf_iter == temp_wbuf_end && !not_in)
+		    {
+		      back_ch (c, s, &read_in, 0);
+		      break;
+		    }
+
+		  if ((flags & IS_SUPPRESSED) == 0)
+		    {
+		      if ((flags & IS_ALLOC_USED) != 0
+			  && (str + MB_CUR_MAX) >= (*pstr + str_sz))
+			{
+			  new_sz = str_sz * 2;
+			  str_len = (str - *pstr);
+
+			  while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
+			  	 && new_sz > (str_len + MB_CUR_MAX))
+			    new_sz = str_len + MB_CUR_MAX;
+			  if (!nstr)
+			    {
+			      if ((flags & USE_POSIX_ALLOC) == 0)
+				{
+				  ((*pstr))[str_len] = 0;
+				  pstr = NULL;
+				  ++rval;
+				}
+			      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+			    }
+			  *pstr = nstr;
+			  str = nstr + str_len;
+			  str_sz = new_sz;
+			}
+		    }
+
+		  n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
+		  if (n == (size_t) -1LL)
+		  {
+		    errno = EILSEQ;
+		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
+		  }
+
+		  str += n;
+		}
+	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
+
+	      if (read_in_sv == read_in)
+		return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+	      if ((flags & IS_SUPPRESSED) == 0)
+		{
+		  n = wcrtomb (buf, 0, &state);
+		  if (n > 0 && (flags & IS_ALLOC_USED) != 0
+		      && (str + n) >= (*pstr + str_sz))
+		    {
+		      str_len = (str - *pstr);
+
+		      if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
+			{
+			  if ((flags & USE_POSIX_ALLOC) == 0)
+			    {
+			      (*pstr)[str_len] = 0;
+			      pstr = NULL;
+			      ++rval;
+			    }
+			  return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+			}
+		      *pstr = nstr;
+		      str = nstr + str_len;
+		      str_sz = str_len + n + 1;
+		    }
+
+		  if (n)
+		  {
+		    memcpy (str, buf, n);
+		    str += n;
+		  }
+		  *str++ = 0;
+
+		  optimize_alloc (pstr, str, str_sz);
+		  pstr = NULL;
+		  ++rval;
+		}
+	    }
+	  break;
+
+	default:
+	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+	}
+    }
+
+  if (ignore_ws)
+    {
+      while (iswspace ((c = in_ch (s, &read_in))));
+      back_ch (c, s, &read_in, 0);
+    }
+
+  return cleanup_return (rval, &gcollect, pstr, &wbuf);
+}
+
+int
+__mingw_vfwscanf (FILE *s, const wchar_t *format, va_list argp)
+{
+  _IFP ifp;
+  memset (&ifp, 0, sizeof (_IFP));
+  ifp.fp = s;
+  return __mingw_swformat (&ifp, format, argp);
+}
+
+int
+__mingw_vswscanf (const wchar_t *s, const wchar_t *format, va_list argp)
+{
+  _IFP ifp;
+  memset (&ifp, 0, sizeof (_IFP));
+  ifp.str = s;
+  ifp.is_string = 1;
+  return __mingw_swformat (&ifp, format, argp);
+}
+