Code

Update to using coreutils 5.2.1 libraries and snprintf.c from samba 3.0.8
[nagiosplug.git] / lib / strtod.c
1 /* Copyright (C) 1991, 1992, 1997, 1999, 2003 Free Software Foundation, Inc.
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.
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.
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.  */
17 #if HAVE_CONFIG_H
18 # include <config.h>
19 #endif
21 #include <errno.h>
22 #ifndef errno
23 extern int errno;
24 #endif
26 #include <ctype.h>
28 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
29 # define IN_CTYPE_DOMAIN(c) 1
30 #else
31 # define IN_CTYPE_DOMAIN(c) isascii(c)
32 #endif
34 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
35 #define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
36 #define TOLOWER(c) (IN_CTYPE_DOMAIN (c) ? tolower(c) : (c))
38 #include <math.h>
40 #include <float.h>
41 #include <stdlib.h>
42 #include <string.h>
44 /* Convert NPTR to a double.  If ENDPTR is not NULL, a pointer to the
45    character after the last one used in the number is put in *ENDPTR.  */
46 double
47 strtod (const char *nptr, char **endptr)
48 {
49   register const char *s;
50   short int sign;
52   /* The number so far.  */
53   double num;
55   int got_dot;                  /* Found a decimal point.  */
56   int got_digit;                /* Seen any digits.  */
58   /* The exponent of the number.  */
59   long int exponent;
61   if (nptr == NULL)
62     {
63       errno = EINVAL;
64       goto noconv;
65     }
67   s = nptr;
69   /* Eat whitespace.  */
70   while (ISSPACE (*s))
71     ++s;
73   /* Get the sign.  */
74   sign = *s == '-' ? -1 : 1;
75   if (*s == '-' || *s == '+')
76     ++s;
78   num = 0.0;
79   got_dot = 0;
80   got_digit = 0;
81   exponent = 0;
82   for (;; ++s)
83     {
84       if (ISDIGIT (*s))
85         {
86           got_digit = 1;
88           /* Make sure that multiplication by 10 will not overflow.  */
89           if (num > DBL_MAX * 0.1)
90             /* The value of the digit doesn't matter, since we have already
91                gotten as many digits as can be represented in a `double'.
92                This doesn't necessarily mean the result will overflow.
93                The exponent may reduce it to within range.
95                We just need to record that there was another
96                digit so that we can multiply by 10 later.  */
97             ++exponent;
98           else
99             num = (num * 10.0) + (*s - '0');
101           /* Keep track of the number of digits after the decimal point.
102              If we just divided by 10 here, we would lose precision.  */
103           if (got_dot)
104             --exponent;
105         }
106       else if (!got_dot && *s == '.')
107         /* Record that we have found the decimal point.  */
108         got_dot = 1;
109       else
110         /* Any other character terminates the number.  */
111         break;
112     }
114   if (!got_digit)
115     goto noconv;
117   if (TOLOWER (*s) == 'e')
118     {
119       /* Get the exponent specified after the `e' or `E'.  */
120       int save = errno;
121       char *end;
122       long int exp;
124       errno = 0;
125       ++s;
126       exp = strtol (s, &end, 10);
127       if (errno == ERANGE)
128         {
129           /* The exponent overflowed a `long int'.  It is probably a safe
130              assumption that an exponent that cannot be represented by
131              a `long int' exceeds the limits of a `double'.  */
132           if (endptr != NULL)
133             *endptr = end;
134           if (exp < 0)
135             goto underflow;
136           else
137             goto overflow;
138         }
139       else if (end == s)
140         /* There was no exponent.  Reset END to point to
141            the 'e' or 'E', so *ENDPTR will be set there.  */
142         end = (char *) s - 1;
143       errno = save;
144       s = end;
145       exponent += exp;
146     }
148   if (endptr != NULL)
149     *endptr = (char *) s;
151   if (num == 0.0)
152     return 0.0;
154   /* Multiply NUM by 10 to the EXPONENT power,
155      checking for overflow and underflow.  */
157   if (exponent < 0)
158     {
159       if (num < DBL_MIN * pow (10.0, (double) -exponent))
160         goto underflow;
161     }
162   else if (exponent > 0)
163     {
164       if (num > DBL_MAX * pow (10.0, (double) -exponent))
165         goto overflow;
166     }
168   num *= pow (10.0, (double) exponent);
170   return num * sign;
172 overflow:
173   /* Return an overflow error.  */
174   errno = ERANGE;
175   return HUGE_VAL * sign;
177 underflow:
178   /* Return an underflow error.  */
179   if (endptr != NULL)
180     *endptr = (char *) nptr;
181   errno = ERANGE;
182   return 0.0;
184 noconv:
185   /* There was no number.  */
186   if (endptr != NULL)
187     *endptr = (char *) nptr;
188   return 0.0;