Added binary and unicode file i/o support to msvcrt.
[reactos.git] / reactos / 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 }