Commit 9df0177f33
Changed files (31)
lib
libc
mingw
stdio
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);
+}
+