1 //===========================================================================
5 // ISO String to double-precision floating point conversion
7 //===========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //===========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
50 //####DESCRIPTIONEND####
52 //===========================================================================
56 #include <pkgconf/libc_stdlib.h> // Configuration header
59 #if defined(CYGFUN_LIBC_strtod)
63 #include <cyg/infra/cyg_type.h> // Common type definitions and support
64 #include <cyg/infra/cyg_trac.h> // Tracing support
65 #include <cyg/infra/cyg_ass.h> // Assertion support
66 #include <stddef.h> // NULL, wchar_t and size_t from compiler
67 #include <stdlib.h> // Main header for stdlib functions
68 #include <ctype.h> // isspace() and isdigit()
69 #include <float.h> // DBL_MIN_10_EXP and DBL_MAX_10_EXP
70 #include <math.h> // HUGE_VAL
71 #include <errno.h> // errno
75 #define MAXE (DBL_MAX_10_EXP)
76 #define MINE (DBL_MIN_10_EXP)
86 #define Ise(c) ((c == 'e') || (c == 'E'))
87 #define Issign(c) ((c == '-') || (c == '+'))
88 #define Val(c) ((c - '0'))
94 * [atw] multiply 64 bit accumulator by 10 and add digit.
95 * The KA/CA way to do this should be to use
96 * a 64-bit integer internally and use "adjust" to
97 * convert it to float at the end of processing.
100 ten_mul(double *acc, int digit)
102 /* [atw] Crude, but effective (at least on a KB)...
107 return 0; /* no overflow */
112 * compute 10**x by successive squaring.
118 static double powtab[] = {1.0,
124 if (x < (sizeof(powtab)/sizeof(double)))
127 return 10.0 * exp10(x-1);
129 return exp10(x/2) * exp10(x/2);
134 * return (*acc) scaled by 10**dexp.
138 adjust(double *acc, int dexp, int sign)
139 /* *acc the 64 bit accumulator */
140 /* dexp decimal exponent */
148 return (sign) ? -HUGE_VAL : HUGE_VAL;
150 else if (dexp < MINE)
163 return r / exp10(abs(dexp));
165 return r * exp10(dexp);
170 strtod( const char *nptr, char **endptr )
172 const char *start=nptr;
181 CYG_REPORT_FUNCNAMETYPE( "strtod", "returning %f" );
183 CYG_CHECK_DATA_PTR( nptr, "nptr is an invalid pointer!" );
185 // endptr is allowed to be NULL, but if it isn't, we check it
187 CYG_CHECK_DATA_PTR( endptr, "endptr is an invalid pointer!" );
189 while(isspace(*nptr)) nptr++;
191 { /* just leading spaces */
192 if(endptr != NULL) *endptr = (char *)start;
199 if(*nptr == '-') flags = SIGN;
201 { /* "+|-" : should be an error ? */
202 if(endptr != NULL) *endptr = (char *)start;
207 for(; (isdigit(*nptr) || (*nptr == '.')); nptr++)
214 if( ten_mul(&accum, Val(*nptr)) ) texp++;
215 if(flags & DECP) texp--;
222 if(*++nptr != '\0') /* skip e|E */
223 { /* ! ([nptr]xxx[.[yyy]]e) */
225 while(isspace(*nptr)) nptr++; /* Ansi allows spaces after e */
227 { /* ! ([nptr]xxx[.[yyy]]e[space]) */
230 if(*nptr++ == '-') flags |= ESIGN;
233 { /* ! ([nptr]xxx[.[yyy]]e[nptr]) -- error?? */
235 for(; isdigit(*nptr); nptr++)
236 if (e < MAXE) /* prevent from grossly overflowing */
237 e = e*10 + Val(*nptr);
239 /* dont care what comes after this */
250 *endptr = (char *)((conv_done) ? nptr : start);
252 retval = adjust(&accum, (int)texp, (int)(flags & SIGN));
255 CYG_REPORT_RETVAL( retval );
261 #endif // if defined(CYGFUN_LIBC_strtod)