948ee2c50ce9906ecc83adbddf2db8cc95660c69
[reactos.git] / reactos / lib / sdk / crt / stdlib / ecvt.c
1 /*
2 * PROJECT: ReactOS CRT
3 * LICENSE: See COPYING in the top level directory
4 * PURPOSE: CRT's ecvt
5 * FILE: lib/sdk/crt/stdlib/ecvt.c
6 * PROGRAMERS: Gregor Schneider (parts based on ecvtbuf.c by DJ Delorie)
7 */
8
9 #include <precomp.h>
10 #define NUMBER_EFMT 18 /* sign, dot, null, 15 for alignment */
11
12 /*
13 * @implemented
14 */
15 char *
16 _ecvt (double value, int ndigits, int *decpt, int *sign)
17 {
18 static char ecvtbuf[DBL_MAX_10_EXP + 10];
19 char *cvtbuf, *s, *d;
20
21 s = cvtbuf = (char*)malloc(ndigits + NUMBER_EFMT);
22 d = ecvtbuf;
23
24 *sign = 0;
25 *decpt = 0;
26
27 if (cvtbuf == NULL)
28 {
29 return NULL;
30 }
31
32 sprintf(cvtbuf, "%-+.*E", ndigits, value);
33 /* Treat special values */
34 if (strncmp(s, "NaN", 3) == 0)
35 {
36 memcpy(ecvtbuf, s, 4);
37 }
38 else if (strncmp(s + 1, "Inf", 3) == 0)
39 {
40 memcpy(ecvtbuf, s, 5);
41 }
42 else
43 {
44 /* Set the sign */
45 if (*s && *s == '-')
46 {
47 *sign = 1;
48 }
49 s++;
50 /* Copy the first digit */
51 if (*s && *s != '.')
52 {
53 if (d - ecvtbuf < ndigits)
54 {
55 *d++ = *s++;
56 }
57 else
58 {
59 s++;
60 }
61 }
62 /* Skip the decimal point */
63 if (*s && *s == '.')
64 {
65 s++;
66 }
67 /* Copy fractional digits */
68 while (*s && *s != 'E')
69 {
70 if (d - ecvtbuf < ndigits)
71 {
72 *d++ = *s++;
73 }
74 else
75 {
76 s++;
77 }
78 }
79 /* Skip the exponent */
80 if (*s && *s == 'E')
81 {
82 s++;
83 }
84 /* Set the decimal point to the exponent value plus the one digit we copied */
85 *decpt = atoi(s) + 1;
86 /* Handle special decimal point cases */
87 if (cvtbuf[1] == '0')
88 {
89 *decpt = 0;
90 }
91 if (ndigits < 1)
92 {
93 /* Need enhanced precision*/
94 char* tbuf = (char*)malloc(NUMBER_EFMT);
95 if (tbuf == NULL)
96 {
97 free(cvtbuf);
98 return NULL;
99 }
100 sprintf(tbuf, "%-+.*E", ndigits + 2, value);
101 if (tbuf[1] >= '5')
102 {
103 (*decpt)++;
104 }
105 free(tbuf);
106 }
107 /* Pad with zeroes */
108 while (d - ecvtbuf < ndigits)
109 {
110 *d++ = '0';
111 }
112 /* Terminate */
113 *d = '\0';
114 }
115 free(cvtbuf);
116 return ecvtbuf;
117 }