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