[CRT]
[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 if (ndigits < 0) ndigits = 0;
22 s = cvtbuf = (char*)malloc(ndigits + NUMBER_EFMT);
23 d = ecvtbuf;
24
25 *sign = 0;
26 *decpt = 0;
27
28 if (cvtbuf == NULL)
29 {
30 return NULL;
31 }
32
33 sprintf(cvtbuf, "%-+.*E", ndigits, value);
34 /* Treat special values */
35 if (strncmp(s, "NaN", 3) == 0)
36 {
37 memcpy(ecvtbuf, s, 4);
38 }
39 else if (strncmp(s + 1, "Inf", 3) == 0)
40 {
41 memcpy(ecvtbuf, s, 5);
42 }
43 else
44 {
45 /* Set the sign */
46 if (*s && *s == '-')
47 {
48 *sign = 1;
49 }
50 s++;
51 /* Copy the first digit */
52 if (*s && *s != '.')
53 {
54 if (d - ecvtbuf < ndigits)
55 {
56 *d++ = *s++;
57 }
58 else
59 {
60 s++;
61 }
62 }
63 /* Skip the decimal point */
64 if (*s && *s == '.')
65 {
66 s++;
67 }
68 /* Copy fractional digits */
69 while (*s && *s != 'E')
70 {
71 if (d - ecvtbuf < ndigits)
72 {
73 *d++ = *s++;
74 }
75 else
76 {
77 s++;
78 }
79 }
80 /* Skip the exponent */
81 if (*s && *s == 'E')
82 {
83 s++;
84 }
85 /* Set the decimal point to the exponent value plus the one digit we copied */
86 *decpt = atoi(s) + 1;
87 /* Handle special decimal point cases */
88 if (cvtbuf[1] == '0')
89 {
90 *decpt = 0;
91 }
92 if (ndigits < 1)
93 {
94 /* Need enhanced precision*/
95 char* tbuf = (char*)malloc(NUMBER_EFMT);
96 if (tbuf == NULL)
97 {
98 free(cvtbuf);
99 return NULL;
100 }
101 sprintf(tbuf, "%-+.*E", ndigits + 2, value);
102 if (tbuf[1] >= '5')
103 {
104 (*decpt)++;
105 }
106 free(tbuf);
107 }
108 /* Pad with zeroes */
109 while (d - ecvtbuf < ndigits)
110 {
111 *d++ = '0';
112 }
113 /* Terminate */
114 *d = '\0';
115 }
116 free(cvtbuf);
117 return ecvtbuf;
118 }