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