mirror of
https://github.com/reactos/reactos.git
synced 2024-06-29 01:12:06 +00:00
[CRT] Rewrite floating point handling for streamout
Fixes some crashes and tests.
This commit is contained in:
parent
2436f57fd5
commit
426e402c54
|
@ -13,6 +13,14 @@
|
|||
#include <strings.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <minmax.h>
|
||||
|
||||
#if DBG && defined(_MSC_VER)
|
||||
#define assert(x) if (!(x)) __int2c()
|
||||
#else
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
# define streamout wstreamout
|
||||
|
@ -64,172 +72,14 @@ enum
|
|||
(flags & FLAG_SHORT) ? (unsigned short)va_arg(argptr, int) : \
|
||||
va_arg(argptr, unsigned int)
|
||||
|
||||
#define va_arg_ffp(argptr, flags) \
|
||||
(flags & FLAG_LONGDOUBLE) ? va_arg(argptr, long double) : \
|
||||
va_arg(argptr, double)
|
||||
|
||||
#define get_exp(f) (int)floor(f == 0 ? 0 : (f >= 0 ? log10(f) : log10(-f)))
|
||||
#define round(x) floor((x) + 0.5)
|
||||
|
||||
#ifndef _USER32_WSPRINTF
|
||||
|
||||
void
|
||||
#ifdef _LIBCNT_
|
||||
/* Due to restrictions in kernel mode regarding the use of floating point,
|
||||
we prevent it from being inlined */
|
||||
__declspec(noinline)
|
||||
#endif
|
||||
format_float(
|
||||
TCHAR chr,
|
||||
unsigned int flags,
|
||||
int precision,
|
||||
TCHAR **string,
|
||||
const TCHAR **prefix,
|
||||
va_list *argptr)
|
||||
{
|
||||
static const TCHAR digits_l[] = _T("0123456789abcdef0x");
|
||||
static const TCHAR digits_u[] = _T("0123456789ABCDEF0X");
|
||||
static const TCHAR _nan[] = _T("#QNAN");
|
||||
static const TCHAR _infinity[] = _T("#INF");
|
||||
const TCHAR *digits = digits_l;
|
||||
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 > 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:
|
||||
/* 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:
|
||||
// http://msdn.microsoft.com/de-de/library/0fatw238%28VS.80%29.aspx
|
||||
num_digits = 3;
|
||||
while (num_digits--)
|
||||
{
|
||||
*--(*string) = digits[val32 % 10];
|
||||
val32 /= 10;
|
||||
}
|
||||
|
||||
/* Sign for the exponent */
|
||||
*--(*string) = exponent >= 0 ? _T('+') : _T('-');
|
||||
|
||||
/* Add 'e' or 'E' separator */
|
||||
*--(*string) = digits[0xe];
|
||||
break;
|
||||
|
||||
case _T('A'):
|
||||
digits = digits_u;
|
||||
case _T('a'):
|
||||
// base = 16;
|
||||
// FIXME: TODO
|
||||
|
||||
case _T('f'):
|
||||
default:
|
||||
/* Shift the decimal point and round */
|
||||
fpval2 = round(sign * fpval * pow(10., precision));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle sign */
|
||||
if (fpval < 0)
|
||||
{
|
||||
*prefix = _T("-");
|
||||
}
|
||||
else if (flags & FLAG_FORCE_SIGN)
|
||||
*prefix = _T("+");
|
||||
else if (flags & FLAG_FORCE_SIGNSP)
|
||||
*prefix = _T(" ");
|
||||
|
||||
/* Handle special cases first */
|
||||
if (_isnan(fpval))
|
||||
{
|
||||
(*string) -= sizeof(_nan) / sizeof(TCHAR) - 1;
|
||||
_tcscpy((*string), _nan);
|
||||
fpval2 = 1;
|
||||
}
|
||||
else if (!_finite(fpval))
|
||||
{
|
||||
(*string) -= sizeof(_infinity) / sizeof(TCHAR) - 1;
|
||||
_tcscpy((*string), _infinity);
|
||||
fpval2 = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Zero padding */
|
||||
while (padding-- > 0) *--(*string) = _T('0');
|
||||
|
||||
/* Digits after the decimal point */
|
||||
num_digits = precision;
|
||||
while (num_digits-- > 0)
|
||||
{
|
||||
*--(*string) = digits[(unsigned __int64)fpval2 % 10];
|
||||
fpval2 /= base;
|
||||
}
|
||||
}
|
||||
|
||||
if (precision > 0 || flags & FLAG_SPECIAL)
|
||||
*--(*string) = _T('.');
|
||||
|
||||
/* Digits before the decimal point */
|
||||
do
|
||||
{
|
||||
*--(*string) = digits[(unsigned __int64)fpval2 % base];
|
||||
fpval2 /= base;
|
||||
}
|
||||
while ((unsigned __int64)fpval2);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
int
|
||||
streamout_char(FILE *stream, int chr)
|
||||
{
|
||||
#if !defined(_USER32_WSPRINTF)
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
return 1;
|
||||
#endif
|
||||
#if defined(_USER32_WSPRINTF) || defined(_LIBCNT_)
|
||||
|
@ -255,8 +105,8 @@ streamout_astring(FILE *stream, const char *string, size_t count)
|
|||
int written = 0;
|
||||
|
||||
#if !defined(_USER32_WSPRINTF)
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
return count;
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
return (int)count;
|
||||
#endif
|
||||
|
||||
while (count--)
|
||||
|
@ -283,8 +133,8 @@ streamout_wstring(FILE *stream, const wchar_t *string, size_t count)
|
|||
int written = 0;
|
||||
|
||||
#if defined(_UNICODE) && !defined(_USER32_WSPRINTF)
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
return count;
|
||||
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
|
||||
return (int)count;
|
||||
#endif
|
||||
|
||||
while (count--)
|
||||
|
@ -315,6 +165,484 @@ streamout_wstring(FILE *stream, const wchar_t *string, size_t count)
|
|||
#define streamout_string streamout_astring
|
||||
#endif
|
||||
|
||||
#ifndef _USER32_WSPRINTF
|
||||
|
||||
// Base 2 exponent divided by 8 is base 16 exponent
|
||||
#define DBL_MAX_16_EXP (DBL_MAX_EXP / 8)
|
||||
|
||||
// A double has 52 fraction bits, which is 14 hex digits
|
||||
#define DBL_DIG_HEX 14
|
||||
|
||||
#define DBL_MAX_DIGITS_10 17
|
||||
#define DBL_MAX_DIGITS_16 14
|
||||
|
||||
static
|
||||
int
|
||||
get_exponent(double fpval, int base)
|
||||
{
|
||||
int exponent;
|
||||
|
||||
if (fpval == 0.)
|
||||
{
|
||||
exponent = 0;
|
||||
}
|
||||
else if (base == 10)
|
||||
{
|
||||
exponent = (int)floor(log10(fpval));
|
||||
assert(exponent <= DBL_MAX_10_EXP);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned __int64 fp_bits = *(unsigned __int64*)&fpval;
|
||||
int exponent2 = (int)((fp_bits >> 52) & 0x7ff);
|
||||
exponent2 -= 1023;
|
||||
exponent = (int)(exponent2 / 8);
|
||||
assert(exponent <= DBL_MAX_16_EXP);
|
||||
}
|
||||
|
||||
return exponent;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
get_dbl_digits(
|
||||
unsigned char digit_buffer[DBL_MAX_DIGITS_10],
|
||||
double fpval,
|
||||
int base,
|
||||
int exponent,
|
||||
int *pnum_digits)
|
||||
{
|
||||
int num_digits = *pnum_digits;
|
||||
|
||||
/* Only base 10 (dec) and 16 (hex) are valid */
|
||||
assert((base == 10) || (base == 16));
|
||||
|
||||
/* fpval must be positive! */
|
||||
assert(fpval >= 0.);
|
||||
|
||||
/* Must fit into the buffer */
|
||||
assert(num_digits <= DBL_MAX_DIGITS_10);
|
||||
|
||||
/* Calculate the maximum divisor */
|
||||
double divisor = pow(10.0, exponent);
|
||||
|
||||
/* Calculate the digits */
|
||||
double remainder = fpval;
|
||||
for (int i = 0; i < num_digits; i++)
|
||||
{
|
||||
int digit = (int)(remainder / divisor);
|
||||
digit_buffer[i] = digit;
|
||||
remainder -= digit * divisor;
|
||||
divisor /= 10.0;
|
||||
}
|
||||
|
||||
/* Round up */
|
||||
int trailing_digit = (int)(remainder / divisor);
|
||||
if (trailing_digit >= 5)
|
||||
{
|
||||
int carry = 1;
|
||||
for (int i = num_digits - 1; i >= 0; i--)
|
||||
{
|
||||
digit_buffer[i] += carry;
|
||||
if (digit_buffer[i] == 10)
|
||||
{
|
||||
digit_buffer[i] = 0;
|
||||
carry = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we carried over the first digit, we need to shift the digits */
|
||||
if (carry)
|
||||
{
|
||||
assert(num_digits < DBL_MAX_DIGITS_10);
|
||||
for (int i = num_digits; i > 0; i--)
|
||||
{
|
||||
digit_buffer[i] = digit_buffer[i - 1];
|
||||
}
|
||||
digit_buffer[0] = 1;
|
||||
exponent++;
|
||||
num_digits++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip trailing zeroes */
|
||||
while ((num_digits > 0) && (digit_buffer[num_digits - 1] == 0))
|
||||
{
|
||||
num_digits--;
|
||||
}
|
||||
|
||||
*pnum_digits = num_digits;
|
||||
|
||||
return exponent;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
stramout_dbl_digits(
|
||||
FILE* stream,
|
||||
const TCHAR* dig_chars,
|
||||
const char * inv_str,
|
||||
unsigned int flags,
|
||||
const unsigned char dig_buffer[DBL_MAX_DIGITS_10],
|
||||
int num_real_digits,
|
||||
int num_int_digits,
|
||||
int num_frac_digits,
|
||||
int first_real_digit,
|
||||
char use_frac_padding)
|
||||
{
|
||||
int current_digit = 0;
|
||||
|
||||
/* Check if we need to insert a virtual 0 */
|
||||
if (first_real_digit > 0)
|
||||
{
|
||||
/* This can only happen when exponent < 0 */
|
||||
assert(num_int_digits == 1);
|
||||
|
||||
/* Output virtual 0 integer digit */
|
||||
streamout_char(stream, dig_chars[0]);
|
||||
current_digit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int num_real_int_digits = min(num_int_digits, num_real_digits);
|
||||
current_digit += num_real_int_digits;
|
||||
for (int i = 0; i < num_real_int_digits; i++)
|
||||
{
|
||||
streamout_char(stream, dig_chars[dig_buffer[i]]);
|
||||
}
|
||||
|
||||
/* Output optional right 0 padding */
|
||||
const int right_padding = num_int_digits - num_real_int_digits;
|
||||
current_digit += max(right_padding, 0);
|
||||
for (int i = 0; i < right_padding; i++)
|
||||
{
|
||||
streamout_char(stream, '0');
|
||||
}
|
||||
}
|
||||
|
||||
/* We print the dot when there are fraction digits or the # flag was used */
|
||||
if ((num_frac_digits > 0) || ((flags & FLAG_SPECIAL) != 0))
|
||||
{
|
||||
streamout_char(stream, '.');
|
||||
}
|
||||
|
||||
/* Only output fraction digits, if precision is > 0 */
|
||||
if (num_frac_digits > 0)
|
||||
{
|
||||
int num_real_frac_digits = num_real_digits - num_int_digits;
|
||||
|
||||
/* Check for invalid numbers */
|
||||
if (inv_str != 0)
|
||||
{
|
||||
const int inv_str_len = (int)strlen(inv_str);
|
||||
num_real_frac_digits = min(inv_str_len, num_frac_digits);
|
||||
for (int i = 0; i < num_real_frac_digits; i++)
|
||||
{
|
||||
streamout_char(stream, inv_str[i]);
|
||||
current_digit++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Output optional 0 chars before real digits begin */
|
||||
const int left_padding = first_real_digit - current_digit;
|
||||
current_digit += max(left_padding, 0);
|
||||
for (int i = 0; i < left_padding; i++)
|
||||
{
|
||||
streamout_char(stream, '0');
|
||||
}
|
||||
|
||||
/* Output remaining real digits */
|
||||
const int start_digit = current_digit - first_real_digit;
|
||||
for (int i = start_digit; i < num_real_digits; i++)
|
||||
{
|
||||
streamout_char(stream, dig_chars[dig_buffer[i]]);
|
||||
current_digit++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pad right with '0' for additional precision */
|
||||
if (use_frac_padding)
|
||||
{
|
||||
const int right_padding = num_frac_digits + num_int_digits - current_digit;
|
||||
for (int i = 0; i < right_padding; i++)
|
||||
{
|
||||
streamout_char(stream, '0');
|
||||
current_digit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of written characters */
|
||||
return current_digit + (num_frac_digits > 0);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
#ifdef _LIBCNT_
|
||||
/* Due to restrictions in kernel mode regarding the use of floating point,
|
||||
we prevent it from being inlined */
|
||||
__declspec(noinline)
|
||||
#endif
|
||||
streamout_double(
|
||||
FILE* stream,
|
||||
char format,
|
||||
unsigned __int64 fp_bits,
|
||||
unsigned int flags,
|
||||
int width,
|
||||
int precision)
|
||||
{
|
||||
const char use_frac_padding = (format != 'g');// || use_exp;
|
||||
static const char _qnan[] = "#QNAN";
|
||||
static const char _snan[] = "#SNAN";
|
||||
static const char _ind[] = "#IND";
|
||||
static const char _infinity[] = "#INF";
|
||||
const char* inv_str = 0;
|
||||
static const TCHAR dig_chars_l[] = _T("0123456789abcdefp0x");
|
||||
static const TCHAR dig_chars_u[] = _T("0123456789ABCDEFP0X");
|
||||
const TCHAR* dig_chars = dig_chars_l;
|
||||
unsigned char dig_buffer[DBL_MAX_DIGITS_10];
|
||||
int base = 10;
|
||||
int use_exp_format = 0;
|
||||
char sign_char = 0;
|
||||
int exponent;
|
||||
int rounded_exponent;
|
||||
int width_exp;
|
||||
int num_int_digits;
|
||||
int num_frac_digits;
|
||||
int first_real_digit;
|
||||
int num_digits;
|
||||
|
||||
/* Convert to an actual double */
|
||||
double fpval = *(double*)&fp_bits;
|
||||
|
||||
/* Check for upper case digits to use */
|
||||
if ((format == 'E') || (format == 'F') || (format == 'G') || (format == 'A'))
|
||||
{
|
||||
dig_chars = dig_chars_u;
|
||||
format = format - 'A' + 'a';
|
||||
}
|
||||
|
||||
/* Check for base 16 (hex) */
|
||||
if (format == 'a')
|
||||
{
|
||||
base = 16;
|
||||
}
|
||||
|
||||
/* Check for default precision */
|
||||
if (precision < 0) precision = 6;
|
||||
|
||||
/* Get sign and normalize fpval to absolute */
|
||||
if (fp_bits & 0x8000000000000000ULL)
|
||||
{
|
||||
sign_char = '-';
|
||||
fpval = -fpval;
|
||||
}
|
||||
else if (flags & FLAG_FORCE_SIGN)
|
||||
{
|
||||
sign_char = '+';
|
||||
}
|
||||
else if (flags & FLAG_FORCE_SIGNSP)
|
||||
{
|
||||
sign_char = ' ';
|
||||
}
|
||||
|
||||
const int width_sign = (sign_char != 0) ? 1 : 0;
|
||||
|
||||
/* Handle NAN / INF */
|
||||
if (_isnan(fpval))
|
||||
{
|
||||
if (fp_bits == 0xFFF8000000000000ULL)
|
||||
{
|
||||
inv_str = _ind;
|
||||
}
|
||||
else if (fp_bits & 0x0008000000000000ULL)
|
||||
{
|
||||
inv_str = _qnan;
|
||||
}
|
||||
else
|
||||
{
|
||||
inv_str = _snan;
|
||||
}
|
||||
fpval = 1.;
|
||||
}
|
||||
else if (!_finite(fpval))
|
||||
{
|
||||
inv_str = _infinity;
|
||||
fpval = 1.;
|
||||
}
|
||||
|
||||
/* Calculate the exponent (i.e. digits before decimal point) */
|
||||
exponent = get_exponent(fpval, base);
|
||||
|
||||
retry:
|
||||
|
||||
/* Check whether to ise the exponent format */
|
||||
if (format == 'g')
|
||||
{
|
||||
use_exp_format = ((exponent < -4) || (exponent >= precision));
|
||||
}
|
||||
else if (format == 'f')
|
||||
{
|
||||
use_exp_format = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_exp_format = 1;
|
||||
}
|
||||
|
||||
/* Check for explicit exponent format */
|
||||
if (use_exp_format)
|
||||
{
|
||||
width_exp = 5;
|
||||
|
||||
/* One digit before the decimal point */
|
||||
num_int_digits = 1;
|
||||
|
||||
/* Precision includes the integer digit */
|
||||
first_real_digit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
width_exp = 0;
|
||||
|
||||
/* Integer digits based on exponent, at least 1 */
|
||||
num_int_digits = max(exponent + 1, 1);
|
||||
|
||||
/* First real digit based on exponent */
|
||||
first_real_digit = max(-exponent, 0);
|
||||
}
|
||||
|
||||
if (format == 'g')
|
||||
{
|
||||
num_frac_digits = max(precision - num_int_digits, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Precision is the number of fractional digits */
|
||||
num_frac_digits = precision;
|
||||
}
|
||||
|
||||
num_digits = num_int_digits + num_frac_digits;
|
||||
|
||||
/* Get max number of actual digits */
|
||||
const int max_real_digits = (base == 16) ? DBL_MAX_DIGITS_16 : DBL_MAX_DIGITS_10;
|
||||
|
||||
/* Calculate the number of real digits to return */
|
||||
int num_real_digits = min(num_digits - first_real_digit, max_real_digits);
|
||||
|
||||
/* Get the digits (0 based) */
|
||||
rounded_exponent = get_dbl_digits(dig_buffer, fpval, base, exponent, &num_real_digits);
|
||||
|
||||
/* If the expoent changed due to rounding, we need to try again */
|
||||
if (rounded_exponent != exponent)
|
||||
{
|
||||
assert(rounded_exponent > exponent);
|
||||
exponent = rounded_exponent;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Special handling for special numbers */
|
||||
if (inv_str != NULL)
|
||||
{
|
||||
num_real_digits = (int)strlen(inv_str) + 1;
|
||||
}
|
||||
|
||||
/* In the g format we need to handle stripped trailing zeroes */
|
||||
if ((format == 'g'))
|
||||
{
|
||||
int max_digits = first_real_digit + num_real_digits;
|
||||
num_frac_digits = max(max_digits - num_int_digits, 0);
|
||||
num_digits = num_int_digits + num_frac_digits;
|
||||
}
|
||||
|
||||
/* Calculate widths */
|
||||
int width_dot = ((num_frac_digits > 0) || (flags & FLAG_SPECIAL)) ? 1 : 0;
|
||||
int width_of_number = width_sign + num_digits + width_dot + width_exp;
|
||||
|
||||
/* Output left space padding */
|
||||
if (((flags & FLAG_ALIGN_LEFT) == 0) &&
|
||||
((flags & FLAG_PAD_ZERO) == 0) &&
|
||||
(width > width_of_number))
|
||||
{
|
||||
const int padding = width - width_of_number;
|
||||
for (int i = 0; i < padding; i++)
|
||||
{
|
||||
streamout_char(stream, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/* Output sign */
|
||||
if (sign_char != 0)
|
||||
{
|
||||
streamout_char(stream, sign_char);
|
||||
}
|
||||
|
||||
/* Output hex prefix */
|
||||
if (format == 'a')
|
||||
{
|
||||
streamout_string(stream, &dig_chars[0x11], 2);
|
||||
}
|
||||
|
||||
/* Output left 0 padding */
|
||||
if (((flags & FLAG_ALIGN_LEFT) == 0) &&
|
||||
((flags & FLAG_PAD_ZERO) != 0) &&
|
||||
(width > width_of_number))
|
||||
{
|
||||
const int padding = width - width_of_number;
|
||||
for (int i = 0; i < padding; i++)
|
||||
{
|
||||
streamout_char(stream, '0');
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the digits */
|
||||
stramout_dbl_digits(
|
||||
stream,
|
||||
dig_chars,
|
||||
inv_str,
|
||||
flags,
|
||||
dig_buffer,
|
||||
num_real_digits,
|
||||
num_int_digits,
|
||||
num_frac_digits,
|
||||
first_real_digit,
|
||||
use_frac_padding);
|
||||
|
||||
/* Output the exponent */
|
||||
if (use_exp_format)
|
||||
{
|
||||
streamout_char(stream, format == 'a' ? dig_chars[0x10] : dig_chars[0xe]);
|
||||
streamout_char(stream, (exponent >= 0) ? '+' : '-');
|
||||
exponent = (exponent < 0) ? -exponent : exponent;
|
||||
assert(exponent < 1000);
|
||||
streamout_char(stream, dig_chars[exponent / 100]);
|
||||
exponent %= 100;
|
||||
streamout_char(stream, dig_chars[exponent / 10]);
|
||||
exponent %= 10;
|
||||
streamout_char(stream, dig_chars[exponent]);
|
||||
}
|
||||
|
||||
/* Output right padding */
|
||||
if (((flags & FLAG_ALIGN_LEFT) != 0) &&
|
||||
(width > width_of_number))
|
||||
{
|
||||
const int padding = width - width_of_number;
|
||||
for (int i = 0; i < padding; i++)
|
||||
{
|
||||
streamout_char(stream, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
return max(width, width_of_number);
|
||||
}
|
||||
|
||||
#endif // _USER32_WSPRINTF
|
||||
|
||||
#ifdef _USER32_WSPRINTF
|
||||
# define USE_MULTISIZE 0
|
||||
#else
|
||||
|
@ -332,7 +660,7 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
|
|||
TCHAR chr, *string;
|
||||
STRING *nt_string;
|
||||
const TCHAR *digits, *prefix;
|
||||
int base, fieldwidth, precision, padding;
|
||||
int base, fieldwidth, precision, padding, rpadding = 0;
|
||||
size_t prefixlen, len;
|
||||
int written = 1, written_all = 0;
|
||||
unsigned int flags;
|
||||
|
@ -558,11 +886,11 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
|
|||
#else
|
||||
flags &= ~FLAG_WIDECHAR;
|
||||
#endif
|
||||
/* Use external function, one for kernel one for user mode */
|
||||
format_float(chr, flags, precision, &string, &prefix, &argptr);
|
||||
len = _tcslen(string);
|
||||
precision = 0;
|
||||
break;
|
||||
/* Capture the double as 64bit int to avoid changing it with the FPU */
|
||||
unsigned __int64 fpval = va_arg(argptr, unsigned __int64);
|
||||
written = streamout_double(stream, chr, fpval, flags, fieldwidth, precision);
|
||||
written_all += written;
|
||||
continue;
|
||||
#endif
|
||||
|
||||
case _T('d'):
|
||||
|
@ -679,15 +1007,13 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
|
|||
if (written == -1) return -1;
|
||||
written_all += written;
|
||||
|
||||
#if 0 && SUPPORT_FLOAT
|
||||
/* Optional right '0' padding */
|
||||
while (precision-- > 0)
|
||||
while (rpadding-- > 0)
|
||||
{
|
||||
if ((written = streamout_char(stream, _T('0'))) == 0) return -1;
|
||||
written_all += written;
|
||||
len++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Optional right padding */
|
||||
if (flags & FLAG_ALIGN_LEFT)
|
||||
|
@ -698,7 +1024,6 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
|
|||
written_all += written;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (written == -1) return -1;
|
||||
|
|
Loading…
Reference in a new issue