branch update for HEAD-2003021201
[reactos.git] / lib / crtdll / stdlib / ecvtbuf.c
1 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
2 #include <msvcrt/stdlib.h>
3 #include <msvcrt/stdio.h>
4 #include <msvcrt/string.h>
5 #include <msvcrt/float.h>
6 #include <msvcrt/alloc.h>
7 // #include <msvcrt/locale.h>
8
9 void __ecvround (char *, char *, const char *, int *);
10
11 void
12 __ecvround (char *numbuf, char *last_digit, const char *after_last, int *decpt)
13 {
14   char *p;
15   int carry = 0;
16
17   /* Do we have at all to round the last digit?  */
18   if (*after_last > '4')
19     {
20       p = last_digit;
21       carry = 1;
22
23       /* Propagate the rounding through trailing '9' digits.  */
24       do {
25         int sum = *p + carry;
26         carry = sum > '9';
27         *p-- = sum - carry * 10;
28       } while (carry && p >= numbuf);
29
30       /* We have 9999999... which needs to be rounded to 100000..  */
31       if (carry && p == numbuf)
32         {
33           *p = '1';
34           *decpt += 1;
35         }
36     }
37 }
38
39 char *
40 ecvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf)
41 {
42   static char INFINITY[] = "Infinity";
43   char decimal = '.' /* localeconv()->decimal_point[0] */;
44   char *cvtbuf = (char *)alloca (ndigits + 20); /* +3 for sign, dot, null; */
45                                                 /* two extra for rounding */
46                                                 /* 15 extra for alignment */
47   char *s = cvtbuf, *d = buf;
48
49   /* Produce two extra digits, so we could round properly.  */
50   sprintf (cvtbuf, "%-+.*E", ndigits + 2, value);
51   *decpt = 0;
52
53   /* The sign.  */
54   if (*s++ == '-')
55     *sign = 1;
56   else
57     *sign = 0;
58
59   /* Special values get special treatment.  */
60   if (strncmp (s, "Inf", 3) == 0)
61     {
62       /* SunOS docs says we have return "Infinity" for NDIGITS >= 8.  */
63       memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3);
64       if (ndigits < 8)
65         buf[3] = '\0';
66     }
67   else if (strcmp (s, "NaN") == 0)
68     memcpy (buf, s, 4);
69   else
70     {
71       char *last_digit, *digit_after_last;
72
73       /* Copy (the single) digit before the decimal.  */
74       while (*s && *s != decimal && d - buf < ndigits)
75         *d++ = *s++;
76
77       /* If we don't see any exponent, here's our decimal point.  */
78       *decpt = d - buf;
79       if (*s)
80         s++;
81
82       /* Copy the fraction digits.  */
83       while (*s && *s != 'E' && d - buf < ndigits)
84         *d++ = *s++;
85
86       /* Remember the last digit copied and the one after it.  */
87       last_digit = d > buf ? d - 1 : d;
88       digit_after_last = s;
89
90       /* Get past the E in exponent field.  */
91       while (*s && *s++ != 'E')
92         ;
93
94       /* Adjust the decimal point by the exponent value.  */
95       *decpt += atoi (s);
96
97       /* Pad with zeroes if needed.  */
98       while (d - buf < ndigits)
99         *d++ = '0';
100
101       /* Zero-terminate.  */
102       *d = '\0';
103
104       /* Round if necessary.  */
105       __ecvround (buf, last_digit, digit_after_last, decpt);
106     }
107   return buf;
108 }