Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Marshall <keithmarshall@@users.sf.net>2008-07-29 03:24:20 +0400
committerKeith Marshall <keithmarshall@@users.sf.net>2008-07-29 03:24:20 +0400
commitf2cb69fd8e2f29eb098fa16d03adef1031ea7728 (patch)
tree8f7a93c6273eb0937c049d538c000971ad8f3e4a /winsup/mingw
parent8c7a3134ddf1f43a283fafc1d96b76cc2327540c (diff)
Replace __mingw_snprintf() with new generic family implementation; likewise, replace __mingw_vsnprintf().
Diffstat (limited to 'winsup/mingw')
-rw-r--r--winsup/mingw/ChangeLog17
-rw-r--r--winsup/mingw/mingwex/Makefile.in32
-rwxr-xr-xwinsup/mingw/mingwex/gdtoa/mingw_snprintf.c1258
-rw-r--r--winsup/mingw/mingwex/stdio/pformat.c2511
-rw-r--r--winsup/mingw/mingwex/stdio/pformat.h90
-rw-r--r--winsup/mingw/mingwex/stdio/snprintf.c44
-rw-r--r--winsup/mingw/mingwex/stdio/vsnprintf.c55
7 files changed, 2739 insertions, 1268 deletions
diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog
index 57369a3c0..0107cdab2 100644
--- a/winsup/mingw/ChangeLog
+++ b/winsup/mingw/ChangeLog
@@ -1,3 +1,20 @@
+2008-07-29 Keith Marshall <keithmarshall@users.sourceforge.net>
+
+ Replace __mingw_snprintf() with new generic family implementation;
+ likewise, replace __mingw_vsnprintf().
+
+ * mingwex/stdio/pformat.c mingwex/stdio/pformat.h: New files.
+ * mingwex/stdio/snprintf.c mingwex/stdio/vsnprintf.c: New files.
+ * mingwex/Makefile.in (STDIO_DISTFILES): Add them.
+ (GDTOA_DISTFILES): Remove mingw_snprintf.c
+ (STDIO_OBJS): Add pformat.o, snprintf.o and vsnprintf.o
+ (GDTOA_OBJS): Remove mingw_snprintf.o
+ (PFORMAT_CFLAGS): New macro; define it, as required by...
+ (pformat.o): ...this new explicit build target.
+ (snprintf.o, vsnprintf.o): Declare prerequisites.
+
+ * mingwex/gdtoa/mingw_snprintf.c: Redundant file; delete it.
+
2008-07-28 Keith Marshall <keithmarshall@users.sourceforge.net>
Lay foundations for new printf() function family implementation.
diff --git a/winsup/mingw/mingwex/Makefile.in b/winsup/mingw/mingwex/Makefile.in
index 9563ad4e7..9142576a4 100644
--- a/winsup/mingw/mingwex/Makefile.in
+++ b/winsup/mingw/mingwex/Makefile.in
@@ -25,7 +25,9 @@ INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
mkinstalldirs = $(SHELL) $(srcdir)/../mkinstalldirs
-DISTFILES = Makefile.in configure configure.in aclocal.m4 \
+
+DISTFILES = \
+ Makefile.in configure configure.in aclocal.m4 \
_Exit.c atoll.c dirent.c feclearexcept.c fegetenv.c \
fegetexceptflag.c fegetround.c feholdexcept.c feraiseexcept.c \
fesetenv.c fesetexceptflag.c fesetround.c fetestexcept.c \
@@ -37,8 +39,7 @@ DISTFILES = Makefile.in configure configure.in aclocal.m4 \
wdirent.c wmemchr.c wmemcmp.c wmemcpy.c wmemmove.c wmemset.c wtoll.c \
wcrtomb.c wctob.c mbrtowc.c btowc.c mb_wc_common.h \
gettimeofday.c isblank.c iswblank.c \
- basename.c dirname.c \
- usleep.c \
+ basename.c dirname.c usleep.c \
tsearch.c twalk.c tdelete.c tfind.c
MATH_DISTFILES = \
@@ -67,12 +68,13 @@ MATH_DISTFILES = \
signbit.c signbitf.c signbitl.c sinf.S sinhf.c sinhl.c sinl.S \
sqrtf.c sqrtl.c tanf.S tanhf.c tanhl.c tanl.S tgamma.c \
tgammaf.c tgammal.c trunc.c truncf.c truncl.c \
- acosh.c acoshf.c acoshl.c asinh.c asinhf.c asinhl.c \
+ acosh.c acoshf.c acoshl.c asinh.c asinhf.c asinhl.c \
atanh.c atanhf.c atanhl.c fastmath.h
STDIO_DISTFILES = \
fopen64.c fseeko64.c ftello64.c lseek64.c \
vfscanf.c vfwscanf.c vscanf.c vsscanf.c vswscanf.c vwscanf.c \
+ pformat.c pformat.h snprintf.c vsnprintf.c \
snwprintf.c vsnwprintf.c
COMPLEX_DISTFILES = \
@@ -90,7 +92,8 @@ GDTOA_DISTFILES = \
arithchk.c dmisc.c dtoa.c g__fmt.c g_dfmt.c g_ffmt.c g_xfmt.c \
gd_arith.h gd_qnan.h gdtoa.c gdtoa.h gdtoaimp.h gethex.c gmisc.c \
hd_init.c hexnan.c misc.c qnan.c README smisc.c strtodg.c strtodnrp.c \
- strtof.c strtopx.c sum.c ulp.c mingw_snprintf.c
+ strtof.c strtopx.c sum.c ulp.c
+
CC = @CC@
# FIXME: Which is it, CC or CC_FOR_TARGET?
CC_FOR_TARGET = $(CC)
@@ -139,7 +142,7 @@ STDLIB_STUB_OBJS = \
STDIO_OBJS = \
fopen64.o fseeko64.o ftello64.o lseek64.o \
vfscanf.o vfwscanf.o vscanf.o vsscanf.o vswscanf.o vwscanf.o \
- snwprintf.o vsnwprintf.o
+ pformat.o snprintf.o vsnprintf.o snwprintf.o vsnwprintf.o
MATH_OBJS = \
acosf.o acosl.o asinf.o asinl.o atan2f.o atan2l.o \
atanf.o atanl.o cbrt.o cbrtf.o cbrtl.o ceilf.o ceill.o \
@@ -175,8 +178,7 @@ FENV_OBJS = fesetround.o fegetround.o \
feclearexcept.o feholdexcept.o fegetexceptflag.o \
feraiseexcept.o fetestexcept.o fesetexceptflag.o
POSIX_OBJS = \
- dirent.o wdirent.o getopt.o ftruncate.o gettimeofday.o \
- usleep.o \
+ dirent.o wdirent.o getopt.o ftruncate.o gettimeofday.o usleep.o \
basename.o dirname.o tsearch.o twalk.o tdelete.o tfind.o
REPLACE_OBJS = \
mingw-aligned-malloc.o mingw-fseek.o
@@ -193,8 +195,7 @@ COMPLEX_OBJS = \
GDTOA_OBJS = \
dmisc.o dtoa.o g__fmt.o g_dfmt.o g_ffmt.o g_xfmt.o gdtoa.o \
gethex.o gmisc.o hd_init.o hexnan.o misc.o smisc.o \
- strtodg.o strtodnrp.o strtof.o strtopx.o sum.o ulp.o \
- mingw_snprintf.o
+ strtodg.o strtodnrp.o strtof.o strtopx.o sum.o ulp.o
LIB_OBJS = $(Q8_OBJS) $(CTYPE_OBJS) $(STDLIB_STUB_OBJS) \
$(STDIO_OBJS) $(MATH_OBJS) $(MATH_ROUND_OBJS) \
@@ -252,6 +253,14 @@ distclean:
.s.o:
$(CC) -c $< -o $@
+# pformat.o needs an explicit build rule; we always build it
+# assuming __MSVCRT_VERSION__ >= 0x0800, relying on ofmt_stub.s
+# (in the parent directory) to maintain forward compatibility
+# for earlier versions of MSVCRT.DLL
+#
+PFORMAT_CFLAGS = $(ALL_CFLAGS) -I $(srcdir)/gdtoa -D__MSVCRT_VERSION__=0x0800
+pformat.o: pformat.c pformat.h
+ $(CC) -c $(PFORMAT_CFLAGS) $(srcdir)/stdio/$*.c -o $@
#
# Dependencies
@@ -267,6 +276,9 @@ $(GDTOA_OBJS): gd_arith.h gdtoa.h gdtoaimp.h gd_qnan.h
$(MATH_ROUND_OBJS) $(MATH_LROUND_OBJS) $(MATH_LLROUND_OBJS): round_internal.h
+snprintf.o: snprintf.c pformat.h
+vsnprintf.o: vsnprintf.c pformat.h
+
dist:
mkdir $(distdir)/mingwex
chmod 755 $(distdir)/mingwex
diff --git a/winsup/mingw/mingwex/gdtoa/mingw_snprintf.c b/winsup/mingw/mingwex/gdtoa/mingw_snprintf.c
deleted file mode 100755
index 26f4573e8..000000000
--- a/winsup/mingw/mingwex/gdtoa/mingw_snprintf.c
+++ /dev/null
@@ -1,1258 +0,0 @@
-/****************************************************************
-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.
-****************************************************************/
-
-/* This implements most of ANSI C's printf, fprintf, and sprintf,
- * with %.0g and %.0G giving the shortest decimal string
- * that rounds to the number being converted, and with negative
- * precisions allowed for %f.
- */
-
-/*
- * Extracted from the AMPL solvers library module
- * http://www.netlib.org/ampl/solvers/printf.c
- * and modified for use in libmingwex.a.
- *
- * libstdc++ amd libgfortran expect an snprintf that can handle host
- * widest float type. This one handle 80 bit long double. Printing
- * to streams using this alternative implementation is not yet
- * supported,
- *
- * Danny Smith <dannysmith@users.sourceforge.net>
- * 2007-06-01
- */
-
-
-#ifdef KR_headers
-#include "varargs.h"
-#else
-#include "stddef.h"
-#include "stdarg.h"
-#include "stdlib.h"
-#endif
-
-#include <stdio.h>
-#include "string.h"
-#include "errno.h"
-
-#ifdef KR_headers
-#define Const /* const */
-#define Voidptr char*
-#ifndef size_t__
-#define size_t int
-#define size_t__
-#endif
-
-#else
-
-#define Const const
-#define Voidptr void*
-
-#endif
-
-
-
-#ifdef USE_FILE_OUTPUT
-#undef MESS
-#ifndef Stderr
-#define Stderr stderr
-#endif
-
-#ifdef _windows_
-#undef PF_BUF
-#define MESS
-#include "mux0.h"
-#define stdout_or_err(f) (f == stdout)
-#else
-#define stdout_or_err(f) (f == Stderr || f == stdout)
-#endif
-
-#endif /* USE_FILE_OUTPUT */
-
-#include <math.h>
-#include <stdint.h>
-#include "gdtoaimp.h"
-#ifdef USE_LOCALE
-#include "locale.h"
-#endif
-
-/*
- * For a MinGW build, we provide the implementation dependent entries
- * `__mingw_snprintf' and `__mingw_vsnprintf', then alias them to provide
- * the C99 conforming implementations of `snprintf()' and `vsnprintf()'.
- */
-# define Snprintf __mingw_snprintf
-# define Vsnprintf __mingw_vsnprintf
-
-int __cdecl __MINGW_NOTHROW
-snprintf(char *, size_t, const char *, ...) __attribute__((alias("__mingw_snprintf")));
-int __cdecl __MINGW_NOTHROW
-vsnprintf (char *, size_t, const char *, __VALIST) __attribute__((alias("__mingw_vsnprintf")));
-
-
-static char* __ldtoa (long double ld, int mode, int ndig, int *decpt,
- int *sign, char **rve)
-{
-
- static FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0 };
- ULong bits[2];
- int ex, kind;
- int fptype = __fpclassifyl (ld);
- union
- {
- unsigned short L[6];
- long double ld;
- } u;
-
- u.ld = ld;
-
- *sign = u.L[4] & 0x8000;
- ex = u.L[4] & 0x7fff;
-
- bits[1] = (u.L[3] << 16) | u.L[2];
- bits[0] = (u.L[1] << 16) | u.L[0];
-
- if (fptype & FP_NAN) /* NaN or Inf */
- {
- if (fptype & FP_NORMAL)
- kind = STRTOG_Infinite;
- else
- kind = STRTOG_NaN;
- }
- else if (fptype & FP_NORMAL) /* Normal or subnormal */
- {
- if (fptype & FP_ZERO)
- {
- kind = STRTOG_Denormal;
- ex = 1;
- }
- else
- kind = STRTOG_Normal;
-
- ex -= 0x3fff + 63;
- }
- else
- kind = STRTOG_Zero;
-
- return __gdtoa (&fpi, ex, bits, &kind, mode, ndig, decpt, rve);
-}
-
-#ifdef USE_ULDIV
-/* This is for avoiding 64-bit divisions on the DEC Alpha, since */
-/* they are not portable among variants of OSF1 (DEC's Unix). */
-
-#define ULDIV(a,b) uldiv_ASL(a,(unsigned long)(b))
-
-#ifndef LLBITS
-#define LLBITS 6
-#endif
-#ifndef ULONG
-#define ULONG unsigned long
-#endif
-
- static int
-klog(ULONG x)
-{
- int k, rv = 0;
-
- if (x > 1L)
- for(k = 1 << LLBITS-1;;) {
- if (x >= (1L << k)) {
- rv |= k;
- x >>= k;
- }
- if (!(k >>= 1))
- break;
- }
- return rv;
- }
-
- ULONG
-uldiv_ASL(ULONG a, ULONG b)
-{
- int ka;
- ULONG c, k;
- static ULONG b0;
- static int kb;
-
- if (a < b)
- return 0;
- if (b != b0) {
- b0 = b;
- kb = klog(b);
- }
- k = 1;
- if ((ka = klog(a) - kb) > 0) {
- k <<= ka;
- b <<= ka;
- }
- c = 0;
- for(;;) {
- if (a >= b) {
- a -= b;
- c |= k;
- }
- if (!(k >>= 1))
- break;
- a <<= 1;
- }
- return c;
- }
-
-#else
-#define ULDIV(a,b) a / b
-#endif /* USE_ULDIV */
-
- typedef struct
-Finfo {
- union {
- #ifdef USE_FILE_OUTPUT
- FILE *cf;
- #endif
- char *sf;
- } u;
- char *ob0, *obe1;
- size_t lastlen;
- } Finfo;
-
- typedef char *(*Putfunc) ANSI((Finfo*, int*));
-
-#ifdef USE_FILE_OUTPUT
-#ifdef PF_BUF
-FILE *stderr_ASL = (FILE*)&stderr_ASL;
-void (*pfbuf_print_ASL) ANSI((char*));
-char *pfbuf_ASL;
-static char *pfbuf_next;
-static size_t pfbuf_len;
-extern Char *mymalloc_ASL ANSI((size_t));
-extern Char *myralloc_ASL ANSI((void *, size_t));
-
-#undef fflush
-#ifdef old_fflush_ASL
-#define fflush old_fflush_ASL
-#endif
-
- void
-fflush_ASL(FILE *f)
-{
- if (f == stderr_ASL) {
- if (pfbuf_ASL && pfbuf_print_ASL) {
- (*pfbuf_print_ASL)(pfbuf_ASL);
- free(pfbuf_ASL);
- pfbuf_ASL = 0;
- }
- }
- else
- fflush(f);
- }
-
- static void
-pf_put(char *buf, int len)
-{
- size_t x, y;
- if (!pfbuf_ASL) {
- x = len + 256;
- if (x < 512)
- x = 512;
- pfbuf_ASL = pfbuf_next = (char*)mymalloc_ASL(pfbuf_len = x);
- }
- else if ((y = (pfbuf_next - pfbuf_ASL) + len) >= pfbuf_len) {
- x = pfbuf_len;
- while((x <<= 1) <= y);
- y = pfbuf_next - pfbuf_ASL;
- pfbuf_ASL = (char*)myralloc_ASL(pfbuf_ASL, x);
- pfbuf_next = pfbuf_ASL + y;
- pfbuf_len = x;
- }
- memcpy(pfbuf_next, buf, len);
- pfbuf_next += len;
- *pfbuf_next = 0;
- }
-
- static char *
-pfput(Finfo *f, int *rvp)
-{
- int n;
- char *ob0 = f->ob0;
- *rvp += n = (int)(f->obe1 - ob0);
- pf_put(ob0, n);
- return ob0;
- }
-#endif /* PF_BUF */
-
- static char *
-Fput
-#ifdef KR_headers
- (f, rvp) register Finfo *f; int *rvp;
-#else
- (register Finfo *f, int *rvp)
-#endif
-{
- register char *ob0 = f->ob0;
-
- *rvp += f->obe1 - ob0;
- *f->obe1 = 0;
- fputs(ob0, f->u.cf);
- return ob0;
- }
-
-
-#ifdef _windows_
-int stdout_fileno_ASL = 1;
-
- static char *
-Wput
-#ifdef KR_headers
- (f, rvp) register Finfo *f; int *rvp;
-#else
- (register Finfo *f, int *rvp)
-#endif
-{
- register char *ob0 = f->ob0;
-
- *rvp += f->obe1 - ob0;
- *f->obe1 = 0;
- mwrite(ob0, f->obe1 - ob0);
- return ob0;
- }
-#endif /*_windows_*/
-#endif /* USE_FILE_OUTPUT */
-
-#ifndef INT_IS_LONG
-#if defined (__SIZEOF_LONG__) && defined (__SIZEOF_INT__) \
- && (__SIZEOF_LONG__) == (__SIZEOF_INT__)
-#define INT_IS_LONG 1
-#endif
-#endif
-
-#define put(x) { *outbuf++ = x; if (outbuf == obe) outbuf = (*fput)(f,&rv); }
-
- static int
-x_sprintf
-#ifdef KR_headers
- (obe, fput, f, fmt, ap)
- char *obe, *fmt; Finfo *f; Putfunc fput; va_list ap;
-#else
- (char *obe, Putfunc fput, Finfo *f, const char *fmt, va_list ap)
-#endif
-{
- char *digits, *ob0, *outbuf, *s, *s0, *se;
- Const char *fmt0;
- char buf[32];
- long long i = 0;
- unsigned long long j;
- unsigned long long u = 0;
-
- double x;
- long double xx;
- int flag_ld = 0;
- int alt, base, c, decpt, dot, conv, i1, lead0, left,
- prec, prec1, psign, rv, sgn, sign, width;
- enum {
- LEN_I,
- LEN_L,
- LEN_S,
- LEN_LL
- } len;
- long long Ltmp;
- intptr_t ip;
- short sh;
- long k;
- unsigned short us;
- unsigned long ui;
- static char hex[] = "0123456789abcdef";
- static char Hex[] = "0123456789ABCDEF";
-
-#ifdef USE_LOCALE
- char decimalpoint = *localeconv()->decimal_point;
-#else
- static const char decimalpoint = '.';
-#endif
-
- ob0 = outbuf = f->ob0;
- rv = 0;
- for(;;) {
- for(;;) {
- switch(c = *fmt++) {
- case 0:
- goto done;
- case '%':
- break;
- default:
- put(c)
- continue;
- }
- break;
- }
- alt=dot=lead0=left=prec=psign=sign=width=0;
- len = LEN_I;
- fmt0 = fmt;
- fmtloop:
- switch(conv = *fmt++) {
- case ' ':
- case '+':
- sign = conv;
- goto fmtloop;
- case '-':
- if (dot)
- psign = 1;
- else
- left = 1;
- goto fmtloop;
- case '#':
- alt = 1;
- goto fmtloop;
- case '0':
- if (!lead0 && !dot) {
- lead0 = 1;
- goto fmtloop;
- }
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- k = conv - '0';
- while((c = *fmt) >= '0' && c <= '9') {
- k = 10*k + c - '0';
- fmt++;
- }
- if (dot)
- prec = psign ? -k : k;
- else
- width = k;
- goto fmtloop;
- case 'h':
- len = LEN_S;
- goto fmtloop;
-#ifndef NO_MSVC_EXTENSIONS
- case 'I':
- if (fmt[0] == '3' && fmt[1] == '2')
- {
- fmt += 2;
- len = LEN_L;
- }
- else if (fmt[0] == '6' && fmt[1] == '4')
- {
- fmt += 2;
- len = LEN_LL;
- }
- else
- len = sizeof (intptr_t) == sizeof (long long)
- ? LEN_LL : LEN_L;
- goto fmtloop;
-#endif
- case 'l':
- if (fmt[0] == 'l')
- {
- fmt++;
- len = LEN_LL;
- }
- else
- len = LEN_L;
- goto fmtloop;
- case 'L':
- flag_ld++;
- goto fmtloop;
- case '.':
- dot = 1;
- lead0 = 0;
- goto fmtloop;
- case '*':
- k = va_arg(ap, int);
- if (dot)
- prec = k;
- else {
- if (k < 0) {
- sign = '-';
- k = -k;
- }
- width = k;
- }
- goto fmtloop;
- case 'c':
-/* %lc (for wctomb conversion) is not implemented. */
- c = va_arg(ap, int);
- put(c)
- continue;
- case '%':
- put(conv)
- continue;
- case 'u':
- switch(len) {
- case LEN_I:
-#if !INT_IS_LONG
- ui = va_arg(ap, int);
- i = ui;
- break;
-#endif
- case LEN_L:
- ui = va_arg(ap, long);
- i = ui;
- break;
- case LEN_S:
- us = va_arg(ap, long);
- i = us;
- break;
- case LEN_LL:
- i = va_arg(ap, long long);
- }
- sign = 0;
- goto have_i;
- case 'i':
- case 'd':
- switch(len) {
- case LEN_I:
-#if !INT_IS_LONG
- k = va_arg(ap, int);
- i = k;
- break;
-#endif
- case LEN_L:
- k = va_arg(ap, long);
- i = k;
- break;
- case LEN_S:
- sh = va_arg(ap, long);
- i = sh;
- break;
- case LEN_LL:
- i = va_arg(ap, long long);
-
- }
- if (i < 0) {
- sign = '-';
- i = -i;
- }
- have_i:
- base = 10;
- u = i;
- digits = hex;
- baseloop:
- s = buf;
- if (!u)
- alt = 0;
- do {
- j = ULDIV(u, base);
- *s++ = digits[u - base * j];
- }
- while((u = j));
- prec -= c = s - buf;
- if (alt && conv == 'o' && prec <= 0)
- prec = 1;
- if ((width -= c) > 0) {
- if (prec > 0)
- width -= prec;
- if (sign)
- width--;
- if (alt == 2)
- width--;
- }
- if (left) {
- if (alt == 2)
- put('0') /* for 0x */
- if (sign)
- put(sign)
- while(--prec >= 0)
- put('0')
- do put(*--s)
- while(s > buf);
- while(--width >= 0)
- put(' ')
- continue;
- }
- if (width > 0) {
- if (lead0) {
- if (alt == 2)
- put('0')
- if (sign)
- put(sign)
- while(--width >= 0)
- put('0')
- goto s_loop;
- }
- else
- while(--width >= 0)
- put(' ')
- }
- if (alt == 2)
- put('0')
- if (sign)
- put(sign)
- s_loop:
- while(--prec >= 0)
- put('0')
- do put(*--s)
- while(s > buf);
- continue;
- case 'n':
- ip = va_arg(ap, intptr_t);
- if (!ip)
- ip = (intptr_t) &Ltmp;
- c = outbuf - ob0 + rv;
- switch(len) {
- case LEN_I:
-#if !INT_IS_LONG
- *(int*)ip = c;
- break;
-#endif
- case LEN_L:
- *(long*)ip = c;
- break;
- case LEN_S:
- *(short*)ip = c;
- break;
- case LEN_LL:
- *(long long*) ip = c;
- break;
- }
- break;
- case 'p':
- alt = 1;
- len = sizeof (intptr_t) == sizeof (long long)
- ? LEN_LL : LEN_L;
- /* no break */
- case 'x':
- digits = hex;
- goto more_x;
- case 'X':
- digits = Hex;
- more_x:
- if (alt) {
- alt = 2;
- sign = conv;
- }
- else
- sign = 0;
- base = 16;
- get_u:
- switch(len) {
- case LEN_I:
-#if !INT_IS_LONG
- ui = va_arg(ap, int);
- u = ui;
- break;
-#endif
- case LEN_L:
- ui = va_arg(ap, long);
- u = ui;
- break;
- case LEN_S:
- us = va_arg(ap, long);
- u = us;
- break;
- case LEN_LL:
- u = va_arg(ap, long long);
- }
- if (!u)
- sign = alt = 0;
- goto baseloop;
- case 'o':
- base = 8;
- digits = hex;
- goto get_u;
- case 's':
-/* %ls (for wctombs conversion) is not implemented. */
- s0 = 0;
- s = va_arg(ap, char*);
- if (!s)
- s = "<NULL>";
- if (prec < 0)
- prec = 0;
- have_s:
- if (dot) {
- for(c = 0; c < prec; c++)
- if (!s[c])
- break;
- prec = c;
- }
- else
- prec = strlen(s);
- width -= prec;
- if (!left)
- while(--width >= 0)
- put(' ')
- while(--prec >= 0)
- put(*s++)
- while(--width >= 0)
- put(' ')
- if (s0)
- __freedtoa(s0);
- continue;
- case 'f':
- if (!dot)
- prec = 6;
- if (flag_ld)
- xx = va_arg(ap, long double);
- else
- {
- x = va_arg(ap, double);
- xx = x;
- }
-
- s = s0 = __ldtoa(xx, 3, prec, &decpt, &sgn, &se);
- if (decpt == -32768) {
- fmt9999:
- dot = prec = alt = 0;
- if (*s == 'N' || *s == 'I')
- goto have_s;
- decpt = strlen(s);
- }
- f_fmt:
- if (sgn && (xx||sign))
- sign = '-';
- if (prec > 0)
- width -= prec;
- if (width > 0) {
- if (sign)
- --width;
- if (decpt <= 0) {
- --width;
- if (prec > 0)
- --width;
- }
- else {
- if (s == se)
- decpt = 1;
- width -= decpt;
- if (prec > 0 || alt)
- --width;
- }
- }
- if (width > 0 && !left) {
- if (lead0) {
- if (sign)
- put(sign)
- sign = 0;
- do put('0')
- while(--width > 0);
- }
- else do put(' ')
- while(--width > 0);
- }
- if (sign)
- put(sign)
- if (decpt <= 0) {
- put('0')
- if (prec > 0 || alt)
- put(decimalpoint)
- while(decpt < 0) {
- put('0')
- prec--;
- decpt++;
- }
- }
- else {
- do {
- if ((c = *s))
- s++;
- else
- c = '0';
- put(c)
- }
- while(--decpt > 0);
- if (prec > 0 || alt)
- put(decimalpoint)
- }
- while(--prec >= 0) {
- if ((c = *s))
- s++;
- else
- c = '0';
- put(c)
- }
- while(--width >= 0)
- put(' ')
- __freedtoa(s0);
- continue;
- case 'G':
- case 'g':
- if (!dot)
- prec = 6;
- if (flag_ld)
- xx = va_arg(ap, long double);
- else
- {
- x = va_arg(ap, double);
- xx = x;
- }
- if (prec < 0)
- prec = 0;
- s = s0 = __ldtoa(xx, prec ? 2 : 0, prec, &decpt,
- &sgn, &se);
- if (decpt == -32768)
- goto fmt9999;
- c = se - s;
- prec1 = prec;
- if (!prec) {
- prec = c;
- prec1 = c + (s[1] || alt ? 5 : 4);
- /* %.0g gives 10 rather than 1e1 */
- }
- if (decpt > -4 && decpt <= prec1) {
- if (alt)
- prec -= decpt;
- else
- prec = c - decpt;
- if (prec < 0)
- prec = 0;
- goto f_fmt;
- }
- conv -= 2;
- if (!alt && prec > c)
- prec = c;
- --prec;
- goto e_fmt;
- case 'e':
- case 'E':
- if (!dot)
- prec = 6;
- if (flag_ld)
- xx = va_arg(ap, long double);
- else
- {
- x = va_arg(ap, double);
- xx = x;
- }
- if (prec < 0)
- prec = 0;
- s = s0 = __ldtoa(xx, 2, prec + 1, &decpt,
- &sgn, &se);
- if (decpt == -32768)
- goto fmt9999;
- e_fmt:
- if (sgn && (xx||sign))
- sign = '-';
- if ((width -= prec + 5) > 0) {
- if (sign)
- --width;
- if (prec || alt)
- --width;
- }
-
- if ((c = --decpt) < 0)
- c = -c;
-
- while(c >= 100) {
- --width;
- c /= 10;
- }
- if (width > 0 && !left) {
- if (lead0) {
- if (sign)
- put(sign)
- sign = 0;
- do put('0')
- while(--width > 0);
- }
- else do put(' ')
- while(--width > 0);
- }
- if (sign)
- put(sign)
- put(*s++)
- if (prec || alt)
- put(decimalpoint)
- while(--prec >= 0) {
- if ((c = *s))
- s++;
- else
- c = '0';
- put(c)
- }
- put(conv)
- if (decpt < 0) {
- put('-')
- decpt = -decpt;
- }
- else
- put('+')
- for(c = 2, k = 10; 10 * k <= decpt; c++, k *= 10);
- for(;;) {
- i1 = decpt / k;
- put(i1 + '0')
- if (--c <= 0)
- break;
- decpt -= i1*k;
- decpt *= 10;
- }
- while(--width >= 0)
- put(' ')
- __freedtoa(s0);
- continue;
- default:
- put('%')
- while(fmt0 < fmt)
- put(*fmt0++)
- continue;
- }
- }
- done:
- *outbuf = 0;
- return (f->lastlen = outbuf - ob0) + rv;
- }
-
-#define Bsize 256
-#ifdef USE_FILE_OUTPUT
- int
-Printf
-#ifdef KR_headers
- (va_alist)
- va_dcl
-{
- char *fmt;
-
- va_list ap;
- int rv;
- Finfo f;
- char buf[Bsize];
-
- va_start(ap);
- fmt = va_arg(ap, char*);
- /*}*/
-#else
- (const char *fmt, ...)
-{
- va_list ap;
- int rv;
- Finfo f;
- char buf[Bsize];
-
- va_start(ap, fmt);
-#endif
- f.u.cf = stdout;
- f.ob0 = buf;
- f.obe1 = buf + Bsize - 1;
-#ifdef _windows_
- if (fileno(stdout) == stdout_fileno_ASL) {
- rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
- mwrite(buf, f.lastlen);
- }
- else
-#endif
-#ifdef PF_BUF
- if (stdout == stderr_ASL) {
- rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
- pf_put(buf, f.lastlen);
- }
- else
-#endif /* PF_BUF */
- {
- rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
- fputs(buf, stdout);
- }
- va_end(ap);
- return rv;
- }
-
- static char *
-Sput
-#ifdef KR_headers
- (f, rvp) Finfo *f; int *rvp;
-#else
- (Finfo *f, int *rvp)
-#endif
-{
- if (Printf("\nBUG! Sput called!\n", f, rvp))
- /* pass vp, rvp and return 0 to shut diagnostics off */
- exit(250);
- return 0;
- }
-
- int
-Sprintf
-#ifdef KR_headers
- (va_alist)
- va_dcl
-{
- char *s, *fmt;
- va_list ap;
- int rv;
- Finfo f;
-
- va_start(ap);
- s = va_arg(ap, char*);
- fmt = va_arg(ap, char*);
- /*}*/
-#else
- (char *s, const char *fmt, ...)
-{
- va_list ap;
- int rv;
- Finfo f;
-
- va_start(ap, fmt);
-#endif
- f.ob0 = s;
- rv = x_sprintf(s, Sput, &f, fmt, ap);
- va_end(ap);
- return rv;
- }
-
-int
-Fprintf
-#ifdef KR_headers
- (va_alist)
- va_dcl
-{
- FILE *F;
- char *s, *fmt;
- va_list ap;
- int rv;
- Finfo f;
- char buf[Bsize];
-
- va_start(ap);
- F = va_arg(ap, FILE*);
- fmt = va_arg(ap, char*);
- /*}*/
-#else
- (FILE *F, const char *fmt, ...)
-{
- va_list ap;
- int rv;
- Finfo f;
- char buf[Bsize];
-
- va_start(ap, fmt);
-#endif
- f.u.cf = F;
- f.ob0 = buf;
- f.obe1 = buf + Bsize - 1;
-#ifdef MESS
- if (stdout_or_err(F)) {
-#ifdef _windows_
- if (fileno(stdout) == stdout_fileno_ASL) {
- rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
- mwrite(buf, f.lastlen);
- }
- else
-#endif
-#ifdef PF_BUF
- if (F == stderr_ASL) {
- rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
- pf_put(buf, f.lastlen);
- }
- else
-#endif
- {
- rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
- fputs(buf, F);
- }
- }
- else
-#endif /*MESS*/
- {
-#ifdef PF_BUF
- if (F == stderr_ASL) {
- rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
- pf_put(buf, f.lastlen);
- }
- else
-#endif
- {
- rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
- fputs(buf, F);
- }
- }
- va_end(ap);
- return rv;
- }
-
- int
-Vsprintf
-#ifdef KR_headers
- (s, fmt, ap) char *s, *fmt; va_list ap;
-#else
- (char *s, const char *fmt, va_list ap)
-#endif
-{
- Finfo f;
- return x_sprintf(f.ob0 = s, Sput, &f, fmt, ap);
- }
-
- int
-Vfprintf
-#ifdef KR_headers
- (F, fmt, ap) FILE *F; char *fmt; va_list ap;
-#else
- (FILE *F, const char *fmt, va_list ap)
-#endif
-{
- char buf[Bsize];
- int rv;
- Finfo f;
-
- f.u.cf = F;
- f.ob0 = buf;
- f.obe1 = buf + Bsize - 1;
-#ifdef MESS
- if (stdout_or_err(F)) {
-#ifdef _windows_
- if (fileno(stdout) == stdout_fileno_ASL) {
- rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
- mwrite(buf, f.lastlen);
- }
- else
-#endif
-#ifdef PF_BUF
- if (F == stderr_ASL) {
- rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
- pf_put(buf, f.lastlen);
- }
- else
-#endif
- {
- rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
- fputs(buf, F);
- }
- }
- else
-#endif /*MESS*/
- {
-#ifdef PF_BUF
- if (F == stderr_ASL) {
- rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
- pf_put(buf, f.lastlen);
- }
- else
-#endif
- {
- rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
- fputs(buf, F);
- }
- }
- va_end(ap);
- return rv;
- }
-
- void
-Perror
-#ifdef KR_headers
- (s) char *s;
-#else
- (const char *s)
-#endif
-{
- if (s && *s)
- fprintf(Stderr, "%s: ", s);
- fprintf(Stderr, "%s\n", strerror(errno));
- }
-#endif /* USE_FILE_OUTPUT */
-
-
- static char *
-Snput
-#ifdef KR_headers
- (f, rvp) Finfo *f; int *rvp;
-#else
- (Finfo *f, int *rvp)
-#endif
-{
- char *s, *s0;
- size_t L;
-
- *rvp += Bsize;
- s0 = f->ob0;
- s = f->u.sf;
- if ((L = f->obe1 - s) > Bsize) {
- L = Bsize;
- goto copy;
- }
- if (L > 0) {
- copy:
- memcpy(s, s0, L);
- f->u.sf = s + L;
- }
- return s0;
- }
-
-
- int
-Vsnprintf
-#ifdef KR_headers
- (s, n, fmt, ap) char *s; size_t n; char *fmt; va_list ap;
-#else
- (char *s, size_t n, const char *fmt, va_list ap)
-#endif
-{
- Finfo f;
- char buf[Bsize];
- int L, rv;
-
- if (n <= 0 || !s) {
- n = 1;
- s = buf;
- }
- f.u.sf = s;
- f.ob0 = buf;
- f.obe1 = s + n - 1;
- rv = x_sprintf(buf + Bsize, Snput, &f, fmt, ap);
- if (f.lastlen > (L = f.obe1 - f.u.sf))
- f.lastlen = L;
- if (f.lastlen > 0) {
- memcpy(f.u.sf, buf, f.lastlen);
- f.u.sf += f.lastlen;
- }
- *f.u.sf = 0;
- return rv;
- }
- int
-Snprintf
-#ifdef KR_headers
- (va_alist)
- va_dcl
-{
- char *s, *fmt;
- int rv;
- size_t n;
- va_list ap;
-
- va_start(ap);
- s = va_arg(ap, char*);
- n = va_arg(ap, size_t);
- fmt = va_arg(ap, char*);
- /*}*/
-#else
- (char *s, size_t n, const char *fmt, ...)
-{
- int rv;
- va_list ap;
-
- va_start(ap, fmt);
-#endif
- rv = Vsnprintf(s, n, fmt, ap);
- va_end(ap);
- return rv;
- }
-
-
-#if (EXPORT_WEAK_SNPRINTF_ALIAS)
-int __cdecl snprintf(char*, size_t, const char* , ...) __attribute__ ((weak, alias ("__mingw_snprintf")));
-int __cdecl vsnprintf (char*, size_t n, const char*, __gnuc_va_list) __attribute__ ((weak, alias ("__mingw_vsnprintf")));
-#endif
-
diff --git a/winsup/mingw/mingwex/stdio/pformat.c b/winsup/mingw/mingwex/stdio/pformat.c
new file mode 100644
index 000000000..82dbcd741
--- /dev/null
+++ b/winsup/mingw/mingwex/stdio/pformat.c
@@ -0,0 +1,2511 @@
+/* FIXME: to be removed one day; for now we explicitly are not
+ * prepared to support the POSIX-XSI additions to the C99 standard.
+ */
+#undef WITH_XSI_FEATURES
+
+/* pformat.c
+ *
+ * $Id$
+ *
+ * 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.
+ ******************************************************************
+ *
+ */
+#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>
+#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 it's use may be considered obsolete; perhaps it
+ * is better to just keep these definitions here.
+ */
+#ifndef _VALUES_H
+/*
+ * values.h
+ *
+ */
+#define _VALUES_H
+
+#include <limits.h>
+
+#define _TYPEBITS(type) (sizeof(type) * CHAR_BIT)
+
+#define LLONGBITS _TYPEBITS(long long)
+
+#endif /* !defined _VALUES_H -- end of file */
+
+#include "pformat.h"
+
+/* Bit-map constants, defining the internal format control
+ * states, which propagate through the flags.
+ */
+#define PFORMAT_HASHED 0x0800
+#define PFORMAT_LJUSTIFY 0x0400
+#define PFORMAT_ZEROFILL 0x0200
+
+#define PFORMAT_JUSTIFY (PFORMAT_LJUSTIFY | PFORMAT_ZEROFILL)
+#define PFORMAT_IGNORE -1
+
+#define PFORMAT_SIGNED 0x01C0
+#define PFORMAT_POSITIVE 0x0100
+#define PFORMAT_NEGATIVE 0x0080
+#define PFORMAT_ADDSPACE 0x0040
+
+#define PFORMAT_XCASE 0x0020
+
+#define PFORMAT_LDOUBLE 0x0004
+
+/* `%o' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_OMASK 0x0007
+#define PFORMAT_OSHIFT 0x0003
+
+/* `%x' and `%X' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_XMASK 0x000F
+#define PFORMAT_XSHIFT 0x0004
+
+/* 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
+
+#ifdef _WIN32
+/*
+ * The Microsoft standard for printing `%e' format exponents is
+ * with a minimum of three digits, unless explicitly set otherwise,
+ * by a prior invocation of the `_set_output_format()' function.
+ *
+ * The following macro allows us to replicate this behaviour.
+ */
+# define PFORMAT_MINEXP __pformat_exponent_digits()
+ /*
+ * However, this feature is unsupported for versions of the
+ * MSVC runtime library prior to msvcr80.dll, and by default,
+ * MinGW uses an earlier version, (equivalent to msvcr60.dll),
+ * for which `_TWO_DIGIT_EXPONENT' will be undefined.
+ */
+# ifndef _TWO_DIGIT_EXPONENT
+ /*
+ * This hack works around the lack of the `_set_output_format()'
+ * feature, when supporting versions of the MSVC runtime library
+ * prior to msvcr80.dll; it simply enforces Microsoft's original
+ * convention, for all cases where the feature is unsupported.
+ */
+# define _get_output_format() 0
+# define _TWO_DIGIT_EXPONENT 1
+# endif
+/*
+ * Irrespective of the MSVCRT version supported, *we* will add
+ * an additional capability, through the following inline function,
+ * which will allow the user to choose his own preferred default
+ * for `PRINTF_EXPONENT_DIGITS', through the simple expedient
+ * of defining it as an environment variable.
+ */
+static __inline__ __attribute__((__always_inline__))
+int __pformat_exponent_digits( void )
+{
+ char *exponent_digits = getenv( "PRINTF_EXPONENT_DIGITS" );
+ return ((exponent_digits != NULL) && ((unsigned)(*exponent_digits - '0') < 3))
+ || (_get_output_format() & _TWO_DIGIT_EXPONENT)
+ ? 2
+ : 3
+ ;
+}
+#else
+/*
+ * When we don't care to mimic Microsoft's standard behaviour,
+ * we adopt the C99/POSIX standard of two digit exponents.
+ */
+# define PFORMAT_MINEXP 2
+#endif
+
+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;
+} __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_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.
+ */
+#define __pformat_arg_length( type ) \
+ 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
+
+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 count;
+ int quota;
+ int expmin;
+} __pformat_t;
+
+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...
+ */
+ ((char *)(stream->dest))[stream->count] = c;
+ }
+ ++stream->count;
+}
+
+static
+void __pformat_putchars( const char *s, int count, __pformat_t *stream )
+{
+ /* 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 );
+}
+
+static __inline__
+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.
+ */
+ __pformat_putchars( s, strlen( s ), stream );
+}
+
+static
+void __pformat_wputchars( const wchar_t *s, int count, __pformat_t *stream )
+{
+ /* 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 );
+}
+
+static __inline__ __attribute__((__always_inline__))
+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.
+ */
+ __pformat_wputchars( s, wcslen( s ), stream );
+}
+
+static __inline__
+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;
+ 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.
+ */
+ char buf[__pformat_int_bufsiz(1, PFORMAT_OSHIFT, stream)];
+ char *p = buf; int precision;
+
+ if( stream->flags & PFORMAT_NEGATIVE )
+ {
+ /* 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;
+ }
+
+ /* Encode the input value for display...
+ */
+ 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.
+ */
+ *p++ = '0' + (unsigned char)(value.__pformat_ullong_t % 10LL);
+ value.__pformat_ullong_t /= 10LL;
+ }
+
+ 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 zeroes.
+ */
+ 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 mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK;
+ int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT;
+ char buf[__pformat_int_bufsiz(2, shift, stream)];
+ char *p = buf;
+
+ 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;
+ }
+
+ 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 zeroes 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 long __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.h"
+
+static
+char *__pformat_cvt( int mode, __pformat_fpreg_t x, 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()'.
+ */
+ unsigned int k, e = 0; char *ep;
+ static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0 };
+
+ /* Classify the argument into an appropriate `__gdtoa()' category...
+ */
+ if( (k = __fpclassifyl( x.__pformat_fpreg_ldouble_t )) & 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 __inline__ __attribute__((__always_inline__))
+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.
+ */
+ __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
+ return __pformat_cvt( 2, z, precision, dp, sign );
+}
+
+static __inline__ __attribute__((__always_inline__))
+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.
+ */
+ __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
+ return __pformat_cvt( 3, z, 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 __inline__
+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 __inline__
+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 __inline__
+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...
+ */
+ 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 );
+ }
+
+ else
+ /* No localisation: just use ASCII '.'...
+ */
+ __pformat_putc( '.', stream );
+}
+
+static __inline__ __attribute__((__always_inline__))
+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
+ /* 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 zeroes
+ * 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--;
+
+ /* 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 zeroes.
+ */
+ while( len-- > 0 )
+ __pformat_putc( *value ? *value++ : '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 );
+ }
+
+ 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 );
+ __pformat_emit_radix_point( stream );
+
+ /* The radix point offset, `len', may be negative; this implies
+ * that additional zeroes must appear, following the radix point,
+ * and preceding the first significant digit. We reduce the
+ * precision, (adding a negative value), to allow for these
+ * additional zeroes, then emit the zeroes as required.
+ */
+ stream->precision += len;
+ while( len++ < 0 )
+ __pformat_putc( '0', stream );
+ }
+
+ /* Now we emit any remaining significant digits, or trailing zeroes,
+ * 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.
+ */
+ 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 );
+}
+
+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 zeroes...
+ */
+ if( ((stream->precision = strlen( value ) - intlen) < 0)
+ /*
+ * This may require a compensating adjustment to the field
+ * width, to accommodate significant trailing zeroes, 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 zeroes
+ * 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 zeroes...
+ */
+ 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], *p = buf;
+ __pformat_intarg_t exponent; short exp_width = 2;
+
+ /* 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).
+ *
+ * However, before we perform the rounding operation, we
+ * normalise the mantissa, shifting it to the left by as many
+ * bit positions may be necessary, until its highest order bit
+ * is set, thus preserving the maximum number of bits in the
+ * rounded result as possible.
+ */
+ while( value.__pformat_fpreg_mantissa < (LLONG_MAX + 1ULL) )
+ value.__pformat_fpreg_mantissa <<= 1;
+
+ /* 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.
+ */
+ value.__pformat_fpreg_exponent++;
+
+ /* 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);
+ }
+
+ /* Encode the significant digits of the mantissa in hexadecimal
+ * ASCII notation, ready for transfer to the output stream...
+ */
+ while( value.__pformat_fpreg_mantissa )
+ {
+ /* taking the rightmost digit in each pass...
+ */
+ int c = value.__pformat_fpreg_mantissa & 0xF;
+ if( c == value.__pformat_fpreg_mantissa )
+ {
+ /* 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++ = '.';
+
+ /* If the most significant hexadecimal digit of the encoded
+ * output value is greater than one, then the indicated value
+ * will appear too large, by an additional binary exponent
+ * corresponding to the number of higher order bit positions
+ * which it occupies...
+ */
+ while( value.__pformat_fpreg_mantissa > 1 )
+ {
+ /* so reduce the exponent value to compensate...
+ */
+ value.__pformat_fpreg_exponent--;
+ value.__pformat_fpreg_mantissa >>= 1;
+ }
+ }
+
+ 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 zeroes, (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 exponent = 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( (exponent = exponent / 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 zeroes 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;
+ exponent.__pformat_llong_t = value.__pformat_fpreg_exponent;
+ __pformat_int( exponent, stream );
+}
+
+static
+void __pformat_xdouble( double x, __pformat_t *stream )
+{
+ /* Handler for `%a' and `%A' format specifiers, (with argument
+ * value specified as `double' type).
+ */
+ unsigned sign_bit = 0;
+ __pformat_fpreg_t z; z.__pformat_fpreg_double_t = 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_bitmap[3] & 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...
+ * first move its exponent into the appropriate field...
+ */
+ z.__pformat_fpreg_bitmap[4] = (z.__pformat_fpreg_bitmap[3] >> 4) & 0x7FF;
+
+ /* Realign the mantissa, leaving space for a
+ * normalised most significant digit...
+ */
+ z.__pformat_fpreg_mantissa <<= 8;
+ z.__pformat_fpreg_bitmap[3] = (z.__pformat_fpreg_bitmap[3] & 0x0FFF);
+
+ /* Check for zero value...
+ */
+ if( z.__pformat_fpreg_exponent || z.__pformat_fpreg_mantissa )
+ {
+ /* and only when the value is non-zero,
+ * eliminate the bias from the exponent...
+ */
+ z.__pformat_fpreg_exponent -= 0x3FF;
+
+ /* Check for a possible denormalised value...
+ */
+ if( z.__pformat_fpreg_exponent > -126 )
+ /*
+ * and normalise when it isn't.
+ */
+ z.__pformat_fpreg_bitmap[3] += 0x1000;
+ }
+
+ /* Finally, hand the adjusted representation off to the generalised
+ * hexadecimal floating point format handler...
+ */
+ __pformat_emit_xfloat( z, 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; z.__pformat_fpreg_ldouble_t = 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 || z.__pformat_fpreg_mantissa )
+ /*
+ * and if the argument value itself is non-zero,
+ * 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 );
+ }
+ }
+}
+
+int __pformat( int flags, void *dest, int max, const char *fmt, va_list argv )
+{
+ int c;
+
+ __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, /* zero output char count */
+ max, /* establish output limit */
+ PFORMAT_MINEXP /* exponent chars preferred */
+ };
+
+ 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;
+
+ /* Restart capture for dynamic field width and precision specs...
+ */
+ int *width_spec = &stream.width;
+
+ /* 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).
+ */
+ __pformat_putc( c, &stream );
+ goto format_scan;
+
+ case 'C':
+ /*
+ * Equivalent to `%lc'; set `length' accordingly,
+ * and simply fall through.
+ */
+ length = PFORMAT_LENGTH_LONG;
+
+ 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)...
+ */
+ argval.__pformat_ullong_t = (wchar_t)(va_arg( argv, int ));
+ __pformat_wputchars( (wchar_t *)(&argval), 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;
+
+ 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 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ /*
+ * Unsigned integer values; octal, decimal or hexadecimal format...
+ */
+ 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( length == PFORMAT_LENGTH_LLONG )
+ /*
+ * The argument is a `long long' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, long long );
+
+ else if( length == PFORMAT_LENGTH_LONG )
+ /*
+ * or here, a `long' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, long );
+
+ else
+ { /* otherwise, it's an `int' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, int );
+ if( length == PFORMAT_LENGTH_SHORT )
+ /*
+ * but it was promoted from a `short' type...
+ */
+ argval.__pformat_llong_t = argval.__pformat_short_t;
+ else if( length == PFORMAT_LENGTH_CHAR )
+ /*
+ * or even from a `char' type...
+ */
+ argval.__pformat_llong_t = argval.__pformat_char_t;
+ }
+
+ /* In any case, all share a common handler...
+ */
+ __pformat_int( argval, &stream );
+ goto format_scan;
+
+ case 'p':
+ /*
+ * Pointer argument; format as hexadecimal, with `0x' prefix...
+ */
+ stream.flags |= PFORMAT_HASHED;
+ argval.__pformat_ullong_t = va_arg( argv, uintptr_t );
+ __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;
+
+ 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...
+ */
+ 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;
+
+ case 'F':
+ /*
+ * Fixed case format using upper case, or lower case on
+ * fall through from above, for `INF' and `NAN'...
+ */
+ 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;
+
+ case 'G':
+ /*
+ * Generalised floating point format, with upper case,
+ * or on fall through from above, with lower case exponent
+ * indicator when required...
+ */
+ 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;
+
+ case 'A':
+ /*
+ * Hexadecimal floating point format; handles radix and
+ * exponent indicators in either upper or lower case...
+ */
+ if( 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...
+ */
+ 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
+
+ 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;
+
+# ifndef _WIN32
+ /*
+ * Microsoft's MSVCRT implementation also uses `l'
+ * as a modifier for `long double'; if we don't want
+ * to support that, we end this case here...
+ */
+ state = PFORMAT_END;
+ break;
+
+ /* otherwise, we simply fall through...
+ */
+# endif
+
+ 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;
+
+# ifdef WITH_XSI_FEATURES
+
+ 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;
+ break;
+
+# endif
+
+ 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 zeroes'
+ * 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;
+ }
+
+ 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; silently reject it, and any
+ * further characters other than argument length modifiers,
+ * until this format specification is completely resolved.
+ */
+ state = PFORMAT_END;
+ }
+ }
+ }
+
+ else
+ /* We just parsed a character which is not included within any format
+ * specification; we simply emit it as a literal.
+ */
+ __pformat_putc( c, &stream );
+ }
+
+ /* When we have fully dispatched the format string, the return value is the
+ * total number of bytes we transferred to the output destination.
+ */
+ return stream.count;
+}
+
+/* $RCSfile$Revision$: end of file */
diff --git a/winsup/mingw/mingwex/stdio/pformat.h b/winsup/mingw/mingwex/stdio/pformat.h
new file mode 100644
index 000000000..a2ace696c
--- /dev/null
+++ b/winsup/mingw/mingwex/stdio/pformat.h
@@ -0,0 +1,90 @@
+#ifndef PFORMAT_H
+/*
+ * pformat.h
+ *
+ * $Id$
+ *
+ * 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
+
+/* This isn't currently defined therein,
+ * but is a potential candidate for inclusion in _mingw.h
+ */
+#ifdef __MINGW32__
+# define __stringify__(NAME) #NAME
+# define __mingw_quoted(NAME) __stringify__(__mingw_##NAME)
+# define __mingw_alias(NAME) __attribute__((alias(__mingw_quoted(NAME)))) NAME
+#else
+# define __mingw_alias(NAME) NAME
+#endif
+
+/* The following are the declarations specific to the `pformat' API...
+ */
+#define PFORMAT_TO_FILE 0x1000
+#define PFORMAT_NOLIMIT 0x2000
+
+#ifdef __MINGW32__
+ /*
+ * Map MinGW specific function names, for use in place of the generic
+ * implementation defined equivalent function names.
+ */
+# define __pformat __mingw_pformat
+
+# 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
+
+int __cdecl __pformat( int, void *, int, const char *, va_list ) __MINGW_NOTHROW;
+
+#endif /* !defined PFORMAT_H: $RCSfile$Revision$: end of file */
diff --git a/winsup/mingw/mingwex/stdio/snprintf.c b/winsup/mingw/mingwex/stdio/snprintf.c
new file mode 100644
index 000000000..4d022e7dc
--- /dev/null
+++ b/winsup/mingw/mingwex/stdio/snprintf.c
@@ -0,0 +1,44 @@
+/* snprintf.c
+ *
+ * $Id$
+ *
+ * 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 "pformat.h"
+
+int __cdecl __snprintf (char *, size_t, const char *fmt, ...) __MINGW_NOTHROW;
+int __cdecl __mingw_alias(snprintf) (char *, size_t, const char *, ...) __MINGW_NOTHROW;
+
+int __cdecl __vsnprintf (char *, size_t, const char *fmt, va_list) __MINGW_NOTHROW;
+
+int __cdecl __snprintf( char *buf, size_t length, const char *fmt, ... )
+{
+ va_list argv; va_start( argv, fmt );
+ register int retval = __vsnprintf( buf, length, fmt, argv );
+ va_end( argv );
+ return retval;
+}
+
+/* $RCSfile$Revision$: end of file */
diff --git a/winsup/mingw/mingwex/stdio/vsnprintf.c b/winsup/mingw/mingwex/stdio/vsnprintf.c
new file mode 100644
index 000000000..a9722c235
--- /dev/null
+++ b/winsup/mingw/mingwex/stdio/vsnprintf.c
@@ -0,0 +1,55 @@
+/* vsnprintf.c
+ *
+ * $Id$
+ *
+ * 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 "pformat.h"
+
+int __cdecl __vsnprintf (char *, size_t, const char *fmt, va_list) __MINGW_NOTHROW;
+int __cdecl __mingw_alias(vsnprintf) (char *, size_t, const char *, va_list) __MINGW_NOTHROW;
+
+int __cdecl __vsnprintf( char *buf, size_t length, const char *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 < length ? retval : length] = '\0';
+
+ return retval;
+}
+
+/* $RCSfile$Revision$: end of file */