blob: bd09981c896e71be2be16e9a41639105cf34a3b1 [file] [log] [blame]
Jari Aalto31859422009-01-12 13:36:28 +00001/* strtod.c - convert string to double-precision floating-point value. */
2
Jari Aaltocce855b1998-04-17 19:52:44 +00003/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
4
Jari Aalto31859422009-01-12 13:36:28 +00005 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software: you can redistribute it and/or modify
Jari Aaltocce855b1998-04-17 19:52:44 +00008 it under the terms of the GNU General Public License as published by
Jari Aalto31859422009-01-12 13:36:28 +00009 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
Jari Aaltocce855b1998-04-17 19:52:44 +000011
Jari Aalto31859422009-01-12 13:36:28 +000012 Bash is distributed in the hope that it will be useful,
Jari Aaltocce855b1998-04-17 19:52:44 +000013 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
Jari Aalto31859422009-01-12 13:36:28 +000018 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
Jari Aaltocce855b1998-04-17 19:52:44 +000020
21#if HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#ifndef HAVE_STRTOD
26
27#include <errno.h>
28#ifndef errno
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010029#include <errno.h>
Jari Aaltocce855b1998-04-17 19:52:44 +000030#endif
31
Jari Aaltof73dda02001-11-13 17:56:06 +000032#include <chartypes.h>
Jari Aaltocce855b1998-04-17 19:52:44 +000033#include <math.h>
34
35#if HAVE_FLOAT_H
36# include <float.h>
37#else
38# define DBL_MAX 1.7976931348623159e+308
39# define DBL_MIN 2.2250738585072010e-308
40#endif
41
42#include <bashansi.h>
43
44#ifndef NULL
45# define NULL 0
46#endif
47
48#ifndef HUGE_VAL
49# define HUGE_VAL HUGE
50#endif
51
52/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the
53 character after the last one used in the number is put in *ENDPTR. */
54double
55strtod (nptr, endptr)
56 const char *nptr;
57 char **endptr;
58{
59 register const char *s;
60 short sign;
61
62 /* The number so far. */
63 double num;
64
65 int got_dot; /* Found a decimal point. */
66 int got_digit; /* Seen any digits. */
67
68 /* The exponent of the number. */
69 long int exponent;
70
71 if (nptr == NULL)
72 {
73 errno = EINVAL;
74 goto noconv;
75 }
76
77 s = nptr;
78
79 /* Eat whitespace. */
Jari Aaltof73dda02001-11-13 17:56:06 +000080 while (ISSPACE ((unsigned char)*s))
Jari Aaltocce855b1998-04-17 19:52:44 +000081 ++s;
82
83 /* Get the sign. */
84 sign = *s == '-' ? -1 : 1;
85 if (*s == '-' || *s == '+')
86 ++s;
87
88 num = 0.0;
89 got_dot = 0;
90 got_digit = 0;
91 exponent = 0;
92 for (;; ++s)
93 {
Jari Aaltof73dda02001-11-13 17:56:06 +000094 if (DIGIT (*s))
Jari Aaltocce855b1998-04-17 19:52:44 +000095 {
96 got_digit = 1;
97
98 /* Make sure that multiplication by 10 will not overflow. */
99 if (num > DBL_MAX * 0.1)
100 /* The value of the digit doesn't matter, since we have already
101 gotten as many digits as can be represented in a `double'.
102 This doesn't necessarily mean the result will overflow.
103 The exponent may reduce it to within range.
104
105 We just need to record that there was another
106 digit so that we can multiply by 10 later. */
107 ++exponent;
108 else
109 num = (num * 10.0) + (*s - '0');
110
111 /* Keep track of the number of digits after the decimal point.
112 If we just divided by 10 here, we would lose precision. */
113 if (got_dot)
114 --exponent;
115 }
116 else if (!got_dot && *s == '.')
117 /* Record that we have found the decimal point. */
118 got_dot = 1;
119 else
120 /* Any other character terminates the number. */
121 break;
122 }
123
124 if (!got_digit)
125 goto noconv;
126
Jari Aaltof73dda02001-11-13 17:56:06 +0000127 if (TOLOWER ((unsigned char)*s) == 'e')
Jari Aaltocce855b1998-04-17 19:52:44 +0000128 {
129 /* Get the exponent specified after the `e' or `E'. */
130 int save = errno;
131 char *end;
132 long int exp;
133
134 errno = 0;
135 ++s;
136 exp = strtol (s, &end, 10);
137 if (errno == ERANGE)
138 {
139 /* The exponent overflowed a `long int'. It is probably a safe
140 assumption that an exponent that cannot be represented by
141 a `long int' exceeds the limits of a `double'. */
142 if (endptr != NULL)
143 *endptr = end;
144 if (exp < 0)
145 goto underflow;
146 else
147 goto overflow;
148 }
149 else if (end == s)
150 /* There was no exponent. Reset END to point to
151 the 'e' or 'E', so *ENDPTR will be set there. */
152 end = (char *) s - 1;
153 errno = save;
154 s = end;
155 exponent += exp;
156 }
157
158 if (endptr != NULL)
159 *endptr = (char *) s;
160
161 if (num == 0.0)
162 return 0.0;
163
164 /* Multiply NUM by 10 to the EXPONENT power,
165 checking for overflow and underflow. */
166
167 if (exponent < 0)
168 {
169 if (num < DBL_MIN * pow (10.0, (double) -exponent))
170 goto underflow;
171 }
172 else if (exponent > 0)
173 {
174 if (num > DBL_MAX * pow (10.0, (double) -exponent))
175 goto overflow;
176 }
177
178 num *= pow (10.0, (double) exponent);
179
180 return num * sign;
181
182overflow:
183 /* Return an overflow error. */
184 errno = ERANGE;
185 return HUGE_VAL * sign;
186
187underflow:
188 /* Return an underflow error. */
189 if (endptr != NULL)
190 *endptr = (char *) nptr;
191 errno = ERANGE;
192 return 0.0;
193
194noconv:
195 /* There was no number. */
196 if (endptr != NULL)
197 *endptr = (char *) nptr;
198 return 0.0;
199}
200
201#endif /* !HAVE_STRTOD */