xref: /reactos/sdk/lib/crt/stdlib/ecvt.c (revision 34593d93)
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 *
_ecvt(double value,int ndigits,int * decpt,int * sign)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 }
119