#include <float.h>
#ifdef _UNICODE
-#define streamout wstreamout
-#define format_float format_floatw
+# define streamout wstreamout
+# define format_float format_floatw
+# define _flsbuf _flswbuf
+int __cdecl _flswbuf(int ch, FILE *stream);
+#endif
+
+#ifdef _LIBCNT_
+# undef _flsbuf
+# define _flsbuf(chr, stream) _TEOF
#endif
#define MB_CUR_MAX 10
(flags & FLAG_LONGDOUBLE) ? va_arg(argptr, long double) : \
va_arg(argptr, double)
-#ifdef _LIBCNT_
-# define _flsbuf(chr, stream) 0
-#endif
+#define get_exp(f) floor(f == 0 ? 0 : (f >= 0 ? log10(f) : log10(-f)))
+#define round(x) floor((x) + 0.5)
-#define get_exp(f) floor(f > 0 ? log10(f) : log10(-f))
+#ifndef _USER32_WSPRINTF
void
#ifdef _LIBCNT
static const TCHAR _nan[] = _T("#QNAN");
static const TCHAR _infinity[] = _T("#INF");
const TCHAR *digits = digits_l;
- int exponent = 0;
- long double fpval;
- int num_digits, val32, base = 10;
- __int64 val64;
+ int exponent = 0, sign;
+ long double fpval, fpval2;
+ int padding = 0, num_digits, val32, base = 10;
+ /* Normalize the precision */
if (precision < 0) precision = 6;
- else if (precision > 512) precision = 512;
+ else if (precision > 17)
+ {
+ padding = precision - 17;
+ precision = 17;
+ }
+ /* Get the float value and calculate the exponent */
fpval = va_arg_ffp(*argptr, flags);
exponent = get_exp(fpval);
+ sign = fpval < 0 ? -1 : 1;
switch (chr)
{
case _T('G'):
digits = digits_u;
case _T('g'):
+ if (precision > 0) precision--;
if (exponent < -4 || exponent >= precision) goto case_e;
+
+ /* Shift the decimal point and round */
+ fpval2 = round(sign * fpval * pow(10., precision));
+
+ /* Skip trailing zeroes */
+ while (precision && (unsigned __int64)fpval2 % 10 == 0)
+ {
+ precision--;
+ fpval2 /= 10;
+ }
break;
case _T('E'):
digits = digits_u;
case _T('e'):
case_e:
- fpval /= pow(10., exponent);
+ /* Shift the decimal point and round */
+ fpval2 = round(sign * fpval * pow(10., precision - exponent));
+
+ /* Compensate for changed exponent through rounding */
+ if (fpval2 >= (unsigned __int64)pow(10., precision + 1))
+ {
+ exponent++;
+ fpval2 = round(sign * fpval * pow(10., precision - exponent));
+ }
+
val32 = exponent >= 0 ? exponent : -exponent;
// FIXME: handle length of exponent field:
}
/* Sign for the exponent */
- *--(*string) = exponent > 0 ? _T('+') : _T('-');
+ *--(*string) = exponent >= 0 ? _T('+') : _T('-');
/* Add 'e' or 'E' separator */
*--(*string) = digits[0xe];
// FIXME: TODO
case _T('f'):
+ default:
+ /* Shift the decimal point and round */
+ fpval2 = round(sign * fpval * pow(10., precision));
break;
}
- /* CHECKME: Windows seems to handle a max of 17 digits(?) */
- num_digits = precision <= 17 ? precision: 17;
-
/* Handle sign */
if (fpval < 0)
{
- fpval = -fpval;
*prefix = _T("-");
}
else if (flags & FLAG_FORCE_SIGN)
{
(*string) -= sizeof(_nan) / sizeof(TCHAR) - 1;
_tcscpy((*string), _nan);
- val64 = 1;
+ fpval2 = 1;
}
else if (!_finite(fpval))
{
(*string) -= sizeof(_infinity) / sizeof(TCHAR) - 1;
_tcscpy((*string), _infinity);
- val64 = 1;
+ fpval2 = 1;
}
else
{
- fpval *= pow(10., precision);
- val64 = (__int64)(fpval + 0.5);
+ /* Zero padding */
+ while (padding-- > 0) *--(*string) = _T('0');
+ /* Digits after the decimal point */
+ num_digits = precision;
while (num_digits-- > 0)
{
- *--(*string) = digits[val64 % 10];
- val64 /= 10;
+ *--(*string) = digits[(unsigned __int64)fpval2 % 10];
+ fpval2 /= base;
}
}
+ if (precision > 0 || flags & FLAG_SPECIAL)
*--(*string) = _T('.');
/* Digits before the decimal point */
do
{
- *--(*string) = digits[val64 % base];
- val64 /= base;
+ *--(*string) = digits[(unsigned __int64)fpval2 % base];
+ fpval2 /= base;
}
- while (val64);
+ while ((unsigned __int64)fpval2);
}
+#endif
static
int
streamout_char(FILE *stream, int chr)
{
- /* Flush the buffer if neccessary */
+ /* Check if the buffer is full */
if (stream->_cnt < sizeof(TCHAR))
{
- return _flsbuf(chr, stream) != EOF;
+#ifdef _USER32_WSPRINTF
+ return _TEOF;
+#else
+ /* Strings are done now */
+ if (stream->_flag & _IOSTRG) return _TEOF;
+
+ /* Flush buffer for files */
+ return _flsbuf(chr, stream) != _TEOF;
+#endif
}
*(TCHAR*)stream->_ptr = chr;
#define streamout_string streamout_astring
#endif
+#ifdef _USER32_WSPRINTF
+# define USE_MULTISIZE 0
+#else
+# define USE_MULTISIZE 1
+#endif
int
_cdecl
else precision = -1;
/* Handle argument size prefix */
- while (1)
+ do
{
if (chr == _T('h')) flags |= FLAG_SHORT;
else if (chr == _T('w')) flags |= FLAG_WIDECHAR;
else if (chr == _T('L')) flags |= 0; // FIXME: long double
+ else if (chr == _T('F')) flags |= 0; // FIXME: what is that?
else if (chr == _T('l'))
{
- flags |= FLAG_LONG;
-#if SUPPORT_LL
- if (format[0] == _T('l'))
- {
- format++;
- flags |= FLAG_INT64;
+ /* Check if this is the 2nd 'l' in a row */
+ if (format[-2] == 'l') flags |= FLAG_INT64;
+ else flags |= FLAG_LONG;
}
-#endif
- }
else if (chr == _T('I'))
{
if (format[0] == _T('3') && format[1] == _T('2'))
else break;
chr = *format++;
}
+ while (USE_MULTISIZE);
/* Handle the format specifier */
digits = digits_l;
else
len = strlen((char*)string);
if (precision >= 0 && len > precision) len = precision;
+ precision = 0;
break;
+#ifndef _USER32_WSPRINTF
case _T('G'):
case _T('E'):
case _T('A'):
len = _tcslen(string);
precision = 0;
break;
+#endif
case _T('d'):
case _T('i'):
case _T('o'):
base = 8;
- if (flags & FLAG_SPECIAL) prefix = _T("0");
+ if (flags & FLAG_SPECIAL)
+ {
+ prefix = _T("0");
+ if (precision > 0) precision--;
+ }
goto case_unsigned;
- /* Fall through */
case _T('p'):
precision = 2 * sizeof(void*);
if (prefix)
{
written = streamout_string(stream, prefix, prefixlen);
- if (written == -1) return -3;
+ if (written == -1) return -1;
written_all += written;
}
written = streamout_wstring(stream, (wchar_t*)string, len);
else
written = streamout_astring(stream, (char*)string, len);
- if (written == -1) return -5;
+ if (written == -1) return -1;
written_all += written;
#if 0 && SUPPORT_FLOAT
}
- if (written == -1) return -8;
+ if (written == -1) return -1;
return written_all;
}