mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 19:52:11 +00:00
_ecvt:
- Rewrite the function, getting rid of alloca and unneeded code parts - Relies on working sprintf, especially allows to detect the decimal point position independent of wanted precision - Fixes all msvcrt printf winetests svn path=/trunk/; revision=42383
This commit is contained in:
parent
a08bde0eb5
commit
f9ae6c7786
3 changed files with 102 additions and 114 deletions
|
@ -317,7 +317,6 @@
|
|||
<file>abort.c</file>
|
||||
<file>atexit.c</file>
|
||||
<file>ecvt.c</file>
|
||||
<file>ecvtbuf.c</file>
|
||||
<file>errno.c</file>
|
||||
<file>fcvt.c</file>
|
||||
<file>fcvtbuf.c</file>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
|
||||
#include <precomp.h>
|
||||
/*
|
||||
* PROJECT: ReactOS CRT
|
||||
* LICENSE: See COPYING in the top level directory
|
||||
* PURPOSE: CRT's ecvt
|
||||
* FILE: lib/sdk/crt/stdlib/ecvt.c
|
||||
* PROGRAMERS: Gregor Schneider (parts based on ecvtbuf.c by DJ Delorie)
|
||||
*/
|
||||
|
||||
char *ecvtbuf (double, int, int *, int *, char *);
|
||||
#include <precomp.h>
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
|
@ -9,6 +14,98 @@ char *ecvtbuf (double, int, int *, int *, char *);
|
|||
char *
|
||||
_ecvt (double value, int ndigits, int *decpt, int *sign)
|
||||
{
|
||||
static char ecvt_buf[DBL_MAX_10_EXP + 10];
|
||||
return ecvtbuf (value, ndigits, decpt, sign, ecvt_buf);
|
||||
char *ecvtbuf, *cvtbuf;
|
||||
char *s, *d;
|
||||
|
||||
s = cvtbuf = (char*)malloc(ndigits + 18); /* sign, dot, null, 15 for alignment */
|
||||
d = ecvtbuf = (char*)malloc(DBL_MAX_10_EXP + 10);
|
||||
|
||||
*sign = 0;
|
||||
*decpt = 0;
|
||||
|
||||
if (cvtbuf == NULL || ecvtbuf == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(cvtbuf, "%-+.*E", ndigits, value);
|
||||
/* Treat special values */
|
||||
if (strncmp(s, "NaN", 3) == 0)
|
||||
{
|
||||
memcpy(ecvtbuf, s, 4);
|
||||
}
|
||||
else if (strncmp(s + 1, "Inf", 3) == 0)
|
||||
{
|
||||
memcpy(ecvtbuf, s, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the sign */
|
||||
if (*s && *s == '-')
|
||||
{
|
||||
*sign = 1;
|
||||
}
|
||||
s++;
|
||||
/* Copy the first digit */
|
||||
if (*s && *s != '.')
|
||||
{
|
||||
if (d - ecvtbuf < ndigits)
|
||||
{
|
||||
*d++ = *s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
s++;
|
||||
}
|
||||
}
|
||||
/* Skip the decimal point */
|
||||
if (*s && *s == '.')
|
||||
{
|
||||
s++;
|
||||
}
|
||||
/* Copy fractional digits */
|
||||
while (*s && *s != 'E')
|
||||
{
|
||||
if (d - ecvtbuf < ndigits)
|
||||
{
|
||||
*d++ = *s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
s++;
|
||||
}
|
||||
}
|
||||
/* Skip the exponent */
|
||||
if (*s && *s == 'E')
|
||||
{
|
||||
s++;
|
||||
}
|
||||
/* Set the decimal point to the exponent value plus the one digit we copied */
|
||||
*decpt = atoi(s) + 1;
|
||||
/* Handle special decimal point cases */
|
||||
if (cvtbuf[1] == '0')
|
||||
{
|
||||
*decpt = 0;
|
||||
}
|
||||
if (ndigits < 1)
|
||||
{
|
||||
/* Need enhanced precision*/
|
||||
char* tbuf = (char*)malloc(ndigits + 18);
|
||||
sprintf(tbuf, "%-+.*E", ndigits + 2, value);
|
||||
if (tbuf[1] >= '5')
|
||||
{
|
||||
(*decpt)++;
|
||||
}
|
||||
free(tbuf);
|
||||
}
|
||||
/* Pad with zeroes */
|
||||
while (d - ecvtbuf < ndigits)
|
||||
{
|
||||
*d++ = '0';
|
||||
}
|
||||
/* Terminate */
|
||||
*d = '\0';
|
||||
}
|
||||
free(cvtbuf);
|
||||
return ecvtbuf;
|
||||
}
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
#include <malloc.h>
|
||||
// #include <msvcrt/locale.h>
|
||||
|
||||
void __ecvround (char *, char *, const char *, int *);
|
||||
|
||||
void
|
||||
__ecvround (char *numbuf, char *last_digit, const char *after_last, int *decpt)
|
||||
{
|
||||
char *p;
|
||||
int carry = 0;
|
||||
|
||||
/* Do we have at all to round the last digit? */
|
||||
if (*after_last > '4')
|
||||
{
|
||||
p = last_digit;
|
||||
carry = 1;
|
||||
|
||||
/* Propagate the rounding through trailing '9' digits. */
|
||||
do {
|
||||
int sum = *p + carry;
|
||||
carry = sum > '9';
|
||||
*p-- = sum - carry * 10;
|
||||
} while (carry && p >= numbuf);
|
||||
|
||||
/* We have 9999999... which needs to be rounded to 100000.. */
|
||||
if (carry && p == numbuf)
|
||||
{
|
||||
*p = '1';
|
||||
*decpt += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
ecvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf)
|
||||
{
|
||||
static char INFINITY[] = "Infinity";
|
||||
char decimal = '.' /* localeconv()->decimal_point[0] */;
|
||||
char *cvtbuf = (char *)_alloca (ndigits + 20); /* +3 for sign, dot, null; */
|
||||
/* two extra for rounding */
|
||||
/* 15 extra for alignment */
|
||||
char *s = cvtbuf, *d = buf;
|
||||
|
||||
/* Produce two extra digits, so we could round properly. */
|
||||
sprintf (cvtbuf, "%-+.*E", ndigits + 2, value);
|
||||
*decpt = 0;
|
||||
|
||||
/* The sign. */
|
||||
if (*s++ == '-')
|
||||
*sign = 1;
|
||||
else
|
||||
*sign = 0;
|
||||
|
||||
/* Special values get special treatment. */
|
||||
if (strncmp (s, "Inf", 3) == 0)
|
||||
{
|
||||
/* SunOS docs says we have return "Infinity" for NDIGITS >= 8. */
|
||||
memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3);
|
||||
if (ndigits < 8)
|
||||
buf[3] = '\0';
|
||||
}
|
||||
else if (strcmp (s, "NaN") == 0)
|
||||
memcpy (buf, s, 4);
|
||||
else
|
||||
{
|
||||
char *last_digit, *digit_after_last;
|
||||
|
||||
/* Copy (the single) digit before the decimal. */
|
||||
while (*s && *s != decimal && d - buf < ndigits)
|
||||
*d++ = *s++;
|
||||
|
||||
/* If we don't see any exponent, here's our decimal point. */
|
||||
*decpt = d - buf;
|
||||
if (*s)
|
||||
s++;
|
||||
|
||||
/* Copy the fraction digits. */
|
||||
while (*s && *s != 'E' && d - buf < ndigits)
|
||||
*d++ = *s++;
|
||||
|
||||
/* Remember the last digit copied and the one after it. */
|
||||
last_digit = d > buf ? d - 1 : d;
|
||||
digit_after_last = s;
|
||||
|
||||
/* Get past the E in exponent field. */
|
||||
while (*s && *s++ != 'E')
|
||||
;
|
||||
|
||||
/* Adjust the decimal point by the exponent value. */
|
||||
*decpt += atoi (s);
|
||||
|
||||
/* Pad with zeroes if needed. */
|
||||
while (d - buf < ndigits)
|
||||
*d++ = '0';
|
||||
|
||||
/* Zero-terminate. */
|
||||
*d = '\0';
|
||||
|
||||
/* Round if necessary. */
|
||||
__ecvround (buf, last_digit, digit_after_last, decpt);
|
||||
}
|
||||
return buf;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue