mirror of
https://github.com/reactos/reactos.git
synced 2025-06-25 01:09:42 +00:00
- Added support for floating point and exponential formats to *printf functions
- Based on the tools/ssprintf.cpp implementation, ported to C with changes made to comply with msvcrt behaviour - Reduces msvcrt winetest printf failure from 13 down to 1 - same failure as WinXP - Related bugs: bug #1533, bug #3727, bug #3878 svn path=/trunk/; revision=37734
This commit is contained in:
parent
9c90984e71
commit
6c677fe4e5
1 changed files with 222 additions and 97 deletions
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* PROGRAMMERS: David Welch
|
||||
* PROGRAMMERS:
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Gregor Schneider
|
||||
*
|
||||
* TODO:
|
||||
* - Verify the implementation of '%Z'.
|
||||
|
@ -23,13 +25,14 @@
|
|||
#include <tchar.h>
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define SIGN 2 /* unsigned/signed */
|
||||
#define PLUS 4 /* show plus */
|
||||
#define SPACE 8 /* space if plus */
|
||||
#define LEFT 16 /* left justified */
|
||||
#define SPECIAL 32 /* 0x */
|
||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||
#define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
|
||||
#define ZEROTRUNC 128 /* truncate zero's */
|
||||
#define REMOVEHEX 256 /* remove 0x from BASE 16 */
|
||||
|
||||
static
|
||||
__inline
|
||||
|
@ -146,105 +149,229 @@ number(char * buf, char * end, long long num, int base, int size, int precision,
|
|||
return buf;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned int mantissal:32;
|
||||
unsigned int mantissah:20;
|
||||
unsigned int exponent:11;
|
||||
unsigned int sign:1;
|
||||
} ieee_double_t;
|
||||
|
||||
static char *
|
||||
numberf(char * buf, char * end, double num, int base, int size, int precision, int type)
|
||||
numberf(char * buf, char * end, double num, char exp_sign, int size, int precision, int type)
|
||||
{
|
||||
char c,sign,tmp[66];
|
||||
const char *digits;
|
||||
const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
int i;
|
||||
long long x;
|
||||
double exponent = 0.0;
|
||||
double e;
|
||||
long ie;
|
||||
|
||||
/* FIXME
|
||||
the float version of number is direcly copy of number
|
||||
*/
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int ro = 0;
|
||||
|
||||
digits = (type & LARGE) ? large_digits : small_digits;
|
||||
if (type & LEFT)
|
||||
type &= ~ZEROPAD;
|
||||
if (base < 2 || base > 36)
|
||||
return 0;
|
||||
c = (type & ZEROPAD) ? '0' : ' ';
|
||||
sign = 0;
|
||||
if (num < 0) {
|
||||
sign = '-';
|
||||
num = -num;
|
||||
size--;
|
||||
} else if (type & PLUS) {
|
||||
sign = '+';
|
||||
size--;
|
||||
} else if (type & SPACE) {
|
||||
sign = ' ';
|
||||
size--;
|
||||
double frac, intr;
|
||||
double p;
|
||||
|
||||
char c, sign, digits[66];
|
||||
char *tmp;
|
||||
|
||||
union
|
||||
{
|
||||
double* __n;
|
||||
ieee_double_t* n;
|
||||
} n;
|
||||
|
||||
n.__n = #
|
||||
|
||||
if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' )
|
||||
{
|
||||
ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
|
||||
exponent = ie/3.321928;
|
||||
}
|
||||
if (type & SPECIAL) {
|
||||
if (base == 16)
|
||||
size -= 2;
|
||||
else if (base == 8)
|
||||
|
||||
if ( exp_sign == 'g' || exp_sign == 'G' )
|
||||
{
|
||||
type |= ZEROTRUNC;
|
||||
if ( exponent < -4 || fabs(exponent) >= precision )
|
||||
exp_sign -= 2; // g -> e and G -> E
|
||||
else
|
||||
exp_sign = 'f';
|
||||
}
|
||||
|
||||
if ( exp_sign == 'e' || exp_sign == 'E' )
|
||||
{
|
||||
frac = modf(exponent,&e);
|
||||
/* FIXME: this exponent over-/underflow scheme doesn't comply with the wanted behaviour
|
||||
* needed at all or completely different in original? */
|
||||
#if 0
|
||||
if ( frac > 0.5 )
|
||||
e++;
|
||||
else if ( frac < -0.5 )
|
||||
e--;
|
||||
#endif
|
||||
|
||||
/* size-5 because "e+abc" is going to follow */
|
||||
buf = numberf(buf, end, num/pow(10.0L,(long double)e), 'f', size-5, precision, type);
|
||||
if (buf <= end)
|
||||
*buf = exp_sign;
|
||||
++buf;
|
||||
size--;
|
||||
|
||||
ie = (long)e;
|
||||
type = LEFT | SIGN | PLUS;
|
||||
buf = number(buf, end, ie, 10, 3, 3, type);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if ( exp_sign == 'f' )
|
||||
{
|
||||
if (type & LEFT)
|
||||
type &= ~ZEROPAD;
|
||||
|
||||
c = (type & ZEROPAD) ? '0' : ' ';
|
||||
sign = 0;
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
sign = '-';
|
||||
num = fabs(num);
|
||||
size--;
|
||||
}
|
||||
i = 0;
|
||||
if (num == 0)
|
||||
tmp[i++] = '0';
|
||||
else while (num != 0)
|
||||
{
|
||||
x = num;
|
||||
tmp[i++] = digits[do_div(&x,base)];
|
||||
num=x;
|
||||
}
|
||||
if (i > precision)
|
||||
precision = i;
|
||||
size -= precision;
|
||||
if (!(type&(ZEROPAD+LEFT))) {
|
||||
while(size-->0) {
|
||||
}
|
||||
else if (type & PLUS)
|
||||
{
|
||||
sign = '+';
|
||||
size--;
|
||||
}
|
||||
else if (type & SPACE)
|
||||
{
|
||||
sign = ' ';
|
||||
size--;
|
||||
}
|
||||
|
||||
frac = modf(num,&intr);
|
||||
|
||||
// # flags forces a . and prevents truncation of trailing zero's
|
||||
if ( precision > 0 )
|
||||
{
|
||||
i = precision-1;
|
||||
while ( i >= 0 )
|
||||
{
|
||||
frac*=10.0L;
|
||||
frac = modf(frac, &p);
|
||||
digits[i] = (int)p + '0';
|
||||
i--;
|
||||
}
|
||||
i = precision;
|
||||
size -= precision;
|
||||
|
||||
if ( precision >= 1 || type & SPECIAL)
|
||||
{
|
||||
digits[i++] = '.';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
ro = 0;
|
||||
if ( frac > 0.5 )
|
||||
{
|
||||
ro = 1;
|
||||
}
|
||||
|
||||
if ( intr == 0.0 )
|
||||
{
|
||||
digits[i++] = '0';
|
||||
size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( intr > 0.0 )
|
||||
{
|
||||
p = intr;
|
||||
intr/=10.0L;
|
||||
modf(intr, &intr);
|
||||
|
||||
p -= 10.0*intr;
|
||||
|
||||
digits[i++] = (int)p + '0';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
j = 0;
|
||||
while ( j < i && ro == 1)
|
||||
{
|
||||
if ( digits[j] >= '0' && digits[j] <= '8' )
|
||||
{
|
||||
digits[j]++;
|
||||
ro = 0;
|
||||
}
|
||||
else if ( digits[j] == '9' )
|
||||
{
|
||||
digits[j] = '0';
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if ( ro == 1 )
|
||||
digits[i++] = '1';
|
||||
|
||||
digits[i] = 0;
|
||||
|
||||
if (!(type & (ZEROPAD+LEFT)))
|
||||
{
|
||||
while(size-->0)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
if (sign)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = sign;
|
||||
++buf;
|
||||
}
|
||||
|
||||
if (!(type & (ZEROPAD+LEFT)))
|
||||
{
|
||||
while(size-->0)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(type & LEFT))
|
||||
{
|
||||
while (size-- > 0)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = c;
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = digits;
|
||||
if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
|
||||
{
|
||||
j = 0;
|
||||
while ( j < i && ( *tmp == '0' || *tmp == '.' ))
|
||||
{
|
||||
tmp++;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
while (i-- > 0)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = tmp[i];
|
||||
++buf;
|
||||
}
|
||||
while (size-- > 0)
|
||||
{
|
||||
if (buf <= end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
if (sign) {
|
||||
if (buf <= end)
|
||||
*buf = sign;
|
||||
++buf;
|
||||
}
|
||||
if (type & SPECIAL) {
|
||||
if (base==8) {
|
||||
if (buf <= end)
|
||||
*buf = '0';
|
||||
++buf;
|
||||
} else if (base==16) {
|
||||
if (buf <= end)
|
||||
*buf = '0';
|
||||
++buf;
|
||||
if (buf <= end)
|
||||
*buf = digits[33];
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
if (!(type & LEFT)) {
|
||||
while (size-- > 0) {
|
||||
if (buf <= end)
|
||||
*buf = c;
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
if (type & ZEROPAD) {
|
||||
while (i < precision--) {
|
||||
if (buf <= end)
|
||||
*buf = '0';
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
while (i-- > 0) {
|
||||
if (buf <= end)
|
||||
*buf = tmp[i];
|
||||
++buf;
|
||||
}
|
||||
while (size-- > 0) {
|
||||
if (buf <= end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
@ -368,8 +495,6 @@ int __cdecl lnx_vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
|
|||
number of chars for from string */
|
||||
int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
|
||||
|
||||
/* clear the string buffer with zero so we do not need NULL terment it at end */
|
||||
|
||||
str = buf;
|
||||
end = buf + cnt - 1;
|
||||
if (end < buf - 1) {
|
||||
|
@ -596,7 +721,7 @@ int __cdecl lnx_vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
|
|||
} else {
|
||||
if ( precision == -1 )
|
||||
precision = 6;
|
||||
str = numberf(str, end, _double, base, field_width, precision, flags);
|
||||
str = numberf(str, end, _double, *fmt, field_width, precision, flags);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue