This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef HAVE_STRTOD
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#include <chartypes.h>
#include <math.h>
#if HAVE_FLOAT_H
# include <float.h>
#else
# define DBL_MAX 1.7976931348623159e+308
# define DBL_MIN 2.2250738585072010e-308
#endif
#include <bashansi.h>
#ifndef NULL
# define NULL 0
#endif
#ifndef HUGE_VAL
# define HUGE_VAL HUGE
#endif
character after the last one used in the number is put in *ENDPTR. */
double
strtod (nptr, endptr)
const char *nptr;
char **endptr;
{
register const char *s;
short sign;
double num;
int got_dot;
int got_digit;
long int exponent;
if (nptr == NULL)
{
errno = EINVAL;
goto noconv;
}
s = nptr;
while (ISSPACE ((unsigned char)*s))
++s;
sign = *s == '-' ? -1 : 1;
if (*s == '-' || *s == '+')
++s;
num = 0.0;
got_dot = 0;
got_digit = 0;
exponent = 0;
for (;; ++s)
{
if (DIGIT (*s))
{
got_digit = 1;
if (num > DBL_MAX * 0.1)
gotten as many digits as can be represented in a `double'.
This doesn't necessarily mean the result will overflow.
The exponent may reduce it to within range.
We just need to record that there was another
digit so that we can multiply by 10 later. */
++exponent;
else
num = (num * 10.0) + (*s - '0');
If we just divided by 10 here, we would lose precision. */
if (got_dot)
--exponent;
}
else if (!got_dot && *s == '.')
got_dot = 1;
else
break;
}
if (!got_digit)
goto noconv;
if (TOLOWER ((unsigned char)*s) == 'e')
{
int save = errno;
char *end;
long int exp;
errno = 0;
++s;
exp = strtol (s, &end, 10);
if (errno == ERANGE)
{
assumption that an exponent that cannot be represented by
a `long int' exceeds the limits of a `double'. */
if (endptr != NULL)
*endptr = end;
if (exp < 0)
goto underflow;
else
goto overflow;
}
else if (end == s)
the 'e' or 'E', so *ENDPTR will be set there. */
end = (char *) s - 1;
errno = save;
s = end;
exponent += exp;
}
if (endptr != NULL)
*endptr = (char *) s;
if (num == 0.0)
return 0.0;
checking for overflow and underflow. */
if (exponent < 0)
{
if (num < DBL_MIN * pow (10.0, (double) -exponent))
goto underflow;
}
else if (exponent > 0)
{
if (num > DBL_MAX * pow (10.0, (double) -exponent))
goto overflow;
}
num *= pow (10.0, (double) exponent);
return num * sign;
overflow:
errno = ERANGE;
return HUGE_VAL * sign;
underflow:
if (endptr != NULL)
*endptr = (char *) nptr;
errno = ERANGE;
return 0.0;
noconv:
if (endptr != NULL)
*endptr = (char *) nptr;
return 0.0;
}
#endif