reactos/lib/sdk/crt/stdlib/ecvtbuf.c
Art Yerkes c501d8112c Create a branch for network fixes.
svn path=/branches/aicom-network-fixes/; revision=34994
2008-08-01 11:32:26 +00:00

108 lines
2.6 KiB
C

/* 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;
}