strtod touchups.
[gnulib.git] / lib / strtod.c
1 /* Copyright (C) 1991, 1992, 1997, 1999, 2003, 2006, 2008 Free
2    Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <float.h>
24 #include <math.h>
25 #include <stdbool.h>
26 #include <string.h>
27
28 #include "c-ctype.h"
29
30 /* Convert NPTR to a double.  If ENDPTR is not NULL, a pointer to the
31    character after the last one used in the number is put in *ENDPTR.  */
32 double
33 strtod (const char *nptr, char **endptr)
34 {
35   const unsigned char *s;
36   bool negative = false;
37
38   /* The number so far.  */
39   double num;
40
41   bool got_dot;                 /* Found a decimal point.  */
42   bool got_digit;               /* Seen any digits.  */
43   bool hex = false;             /* Look for hex float exponent.  */
44
45   /* The exponent of the number.  */
46   long int exponent;
47
48   if (nptr == NULL)
49     {
50       errno = EINVAL;
51       goto noconv;
52     }
53
54   /* Use unsigned char for the ctype routines.  */
55   s = (unsigned char *) nptr;
56
57   /* Eat whitespace.  */
58   while (isspace (*s))
59     ++s;
60
61   /* Get the sign.  */
62   negative = *s == '-';
63   if (*s == '-' || *s == '+')
64     ++s;
65
66   num = 0.0;
67   got_dot = false;
68   got_digit = false;
69   exponent = 0;
70
71   /* Check for hex float.  */
72   if (*s == '0' && c_tolower (s[1]) == 'x'
73       && (c_isxdigit (s[2]) || ('.' == s[2] && c_isxdigit (s[3]))))
74     {
75       hex = true;
76       s += 2;
77       for (;; ++s)
78         {
79           if (c_isxdigit (*s))
80             {
81               got_digit = true;
82
83               /* Make sure that multiplication by 16 will not overflow.  */
84               if (num > DBL_MAX / 16)
85                 /* The value of the digit doesn't matter, since we have already
86                    gotten as many digits as can be represented in a `double'.
87                    This doesn't necessarily mean the result will overflow.
88                    The exponent may reduce it to within range.
89
90                    We just need to record that there was another
91                    digit so that we can multiply by 16 later.  */
92                 ++exponent;
93               else
94                 num = ((num * 16.0)
95                        + (c_tolower (*s) - (c_isdigit (*s) ? '0' : 'a' - 10)));
96
97               /* Keep track of the number of digits after the decimal point.
98                  If we just divided by 16 here, we would lose precision.  */
99               if (got_dot)
100                 --exponent;
101             }
102           else if (!got_dot && *s == '.')
103             /* Record that we have found the decimal point.  */
104             got_dot = true;
105           else
106             /* Any other character terminates the number.  */
107             break;
108         }
109     }
110
111   /* Not a hex float.  */
112   else
113     {
114       for (;; ++s)
115         {
116           if (c_isdigit (*s))
117             {
118               got_digit = true;
119
120               /* Make sure that multiplication by 10 will not overflow.  */
121               if (num > DBL_MAX * 0.1)
122                 /* The value of the digit doesn't matter, since we have already
123                    gotten as many digits as can be represented in a `double'.
124                    This doesn't necessarily mean the result will overflow.
125                    The exponent may reduce it to within range.
126
127                    We just need to record that there was another
128                    digit so that we can multiply by 10 later.  */
129                 ++exponent;
130               else
131                 num = (num * 10.0) + (*s - '0');
132
133               /* Keep track of the number of digits after the decimal point.
134                  If we just divided by 10 here, we would lose precision.  */
135               if (got_dot)
136                 --exponent;
137             }
138           else if (!got_dot && *s == '.')
139             /* Record that we have found the decimal point.  */
140             got_dot = true;
141           else
142             /* Any other character terminates the number.  */
143             break;
144         }
145     }
146
147   if (!got_digit)
148     {
149       /* Check for infinities and NaNs.  */
150       if (c_tolower (*s) == 'i'
151           && c_tolower (s[1]) == 'n'
152           && c_tolower (s[2]) == 'f')
153         {
154           s += 3;
155           num = HUGE_VAL;
156           if (c_tolower (*s) == 'i'
157               && c_tolower (s[1]) == 'n'
158               && c_tolower (s[2]) == 'i'
159               && c_tolower (s[3]) == 't'
160               && c_tolower (s[4]) == 'y')
161             s += 5;
162           goto valid;
163         }
164 #ifdef NAN
165       else if (c_tolower (*s) == 'n'
166                && c_tolower (s[1]) == 'a'
167                && c_tolower (s[2]) == 'n')
168         {
169           s += 3;
170           num = NAN;
171           /* Since nan(<n-char-sequence>) is implementation-defined,
172              we define it by ignoring <n-char-sequence>.  A nicer
173              implementation would populate the bits of the NaN
174              according to interpreting n-char-sequence as a
175              hexadecimal number, but the result is still a NaN.  */
176           if (*s == '(')
177             {
178               const unsigned char *p = s + 1;
179               while (c_isalnum (*p))
180                 p++;
181               if (*p == ')')
182                 s = p + 1;
183             }
184           goto valid;
185         }
186 #endif
187       goto noconv;
188     }
189
190   if (c_tolower (*s) == (hex ? 'p' : 'e') && !isspace (s[1]))
191     {
192       /* Get the exponent specified after the `e' or `E'.  */
193       int save = errno;
194       char *end;
195       long int value;
196
197       errno = 0;
198       ++s;
199       value = strtol ((char *) s, &end, 10);
200       if (errno == ERANGE && num)
201         {
202           /* The exponent overflowed a `long int'.  It is probably a safe
203              assumption that an exponent that cannot be represented by
204              a `long int' exceeds the limits of a `double'.  */
205           if (endptr != NULL)
206             *endptr = end;
207           if (value < 0)
208             goto underflow;
209           else
210             goto overflow;
211         }
212       else if (end == (char *) s)
213         /* There was no exponent.  Reset END to point to
214            the 'e' or 'E', so *ENDPTR will be set there.  */
215         end = (char *) s - 1;
216       errno = save;
217       s = (unsigned char *) end;
218       exponent += value;
219     }
220
221   if (num == 0.0)
222     goto valid;
223
224   if (hex)
225     {
226       /* ldexp takes care of range errors.  */
227       num = ldexp (num, exponent);
228       goto valid;
229     }
230
231   /* Multiply NUM by 10 to the EXPONENT power,
232      checking for overflow and underflow.  */
233
234   if (exponent < 0)
235     {
236       if (num < DBL_MIN * pow (10.0, (double) -exponent))
237         goto underflow;
238     }
239   else if (exponent > 0)
240     {
241       if (num > DBL_MAX * pow (10.0, (double) -exponent))
242         goto overflow;
243     }
244
245   num *= pow (10.0, (double) exponent);
246
247  valid:
248   if (endptr != NULL)
249     *endptr = (char *) s;
250   return negative ? -num : num;
251
252  overflow:
253   /* Return an overflow error.  */
254   if (endptr != NULL)
255     *endptr = (char *) s;
256   errno = ERANGE;
257   return negative ? -HUGE_VAL : HUGE_VAL;
258
259  underflow:
260   /* Return an underflow error.  */
261   if (endptr != NULL)
262     *endptr = (char *) s;
263   errno = ERANGE;
264   return negative ? -0.0 : 0.0;
265
266  noconv:
267   /* There was no number.  */
268   if (endptr != NULL)
269     *endptr = (char *) nptr;
270   errno = EINVAL;
271   return 0.0;
272 }