| Brett Cannon | 0b64be2 | 2010-05-05 20:50:03 +0000 | [diff] [blame] | 1 | #include <stdio.h> | 
|  | 2 | #include <string.h> | 
|  | 3 |  | 
| Martin v. Löwis | 4f1cd8b | 2001-07-26 13:41:06 +0000 | [diff] [blame] | 4 | #include "pyconfig.h" | 
| Guido van Rossum | 2b7e04a | 1995-02-19 15:54:36 +0000 | [diff] [blame] | 5 |  | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 6 | /* comp.sources.misc strtod(), as posted in comp.lang.tcl, | 
|  | 7 | with bugfix for "123000.0" and acceptance of space after 'e' sign nuked. | 
| Guido van Rossum | 753e2bf | 1991-04-16 08:45:40 +0000 | [diff] [blame] | 8 |  | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 9 | ************************************************************ | 
|  | 10 | * YOU MUST EDIT THE MACHINE-DEPENDENT DEFINITIONS BELOW!!! * | 
|  | 11 | ************************************************************ | 
|  | 12 | */ | 
| Guido van Rossum | 5afc747 | 1991-12-31 13:15:19 +0000 | [diff] [blame] | 13 |  | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 14 | /*  File   : stdtod.c (Modified version of str2dbl.c) | 
|  | 15 | Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc. | 
|  | 16 | Updated: Tuesday August 2nd, 1988 | 
|  | 17 | Defines: double strtod (char *str, char**ptr) | 
|  | 18 | */ | 
| Guido van Rossum | 753e2bf | 1991-04-16 08:45:40 +0000 | [diff] [blame] | 19 |  | 
| Brett Cannon | 0b64be2 | 2010-05-05 20:50:03 +0000 | [diff] [blame] | 20 | /*  This is an implementation of the strtod() function described in the | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 21 | System V manuals, with a different name to avoid linker problems. | 
|  | 22 | All that str2dbl() does itself is check that the argument is well-formed | 
|  | 23 | and is in range.  It leaves the work of conversion to atof(), which is | 
|  | 24 | assumed to exist and deliver correct results (if they can be represented). | 
| Guido van Rossum | 5afc747 | 1991-12-31 13:15:19 +0000 | [diff] [blame] | 25 |  | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 26 | There are two reasons why this should be provided to the net: | 
|  | 27 | (a) some UNIX systems do not yet have strtod(), or do not have it | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 28 | available in the BSD "universe" (but they do have atof()). | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 29 | (b) some of the UNIX systems that *do* have it get it wrong. | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 30 | (some crash with large arguments, some assign the wrong *ptr value). | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 31 | There is a reason why *we* are providing it: we need a correct version | 
|  | 32 | of strtod(), and if we give this one away maybe someone will look for | 
|  | 33 | mistakes in it and fix them for us (:-). | 
|  | 34 | */ | 
| Brett Cannon | 0b64be2 | 2010-05-05 20:50:03 +0000 | [diff] [blame] | 35 |  | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 36 | /*  The following constants are machine-specific.  MD{MIN,MAX}EXPT are | 
|  | 37 | integers and MD{MIN,MAX}FRAC are strings such that | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 38 | 0.${MDMAXFRAC}e${MDMAXEXPT} is the largest representable double, | 
|  | 39 | 0.${MDMINFRAC}e${MDMINEXPT} is the smallest representable +ve double | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 40 | MD{MIN,MAX}FRAC must not have any trailing zeros. | 
|  | 41 | The values here are for IEEE-754 64-bit floats. | 
|  | 42 | It is not perfectly clear to me whether an IEEE infinity should be | 
|  | 43 | returned for overflow, nor what a portable way of writing one is, | 
|  | 44 | so HUGE is just 0.MAXFRAC*10**MAXEXPT (this seems still to be the | 
|  | 45 | UNIX convention). | 
|  | 46 |  | 
|  | 47 | I do know about <values.h>, but the whole point of this file is that | 
|  | 48 | we can't always trust that stuff to be there or to be correct. | 
|  | 49 | */ | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 50 | static  int     MDMINEXPT       = -323; | 
|  | 51 | static  char    MDMINFRAC[]     = "494065645841246544"; | 
|  | 52 | static  double  ZERO            = 0.0; | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 53 |  | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 54 | static  int     MDMAXEXPT       = 309; | 
|  | 55 | static  char    MDMAXFRAC[]     = "17976931348623157"; | 
|  | 56 | static  double  HUGE            = 1.7976931348623157e308; | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 57 |  | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 58 | extern  double  atof(const char *);             /* Only called when result known to be ok */ | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 59 |  | 
| Martin v. Löwis | 0e8bd7e | 2006-06-10 12:23:46 +0000 | [diff] [blame] | 60 | #ifdef HAVE_ERRNO_H | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 61 | #include <errno.h> | 
| Guido van Rossum | 2571cc8 | 1999-04-07 16:07:23 +0000 | [diff] [blame] | 62 | #endif | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 63 | extern  int     errno; | 
| Guido van Rossum | 23d5cde | 1992-01-14 18:42:23 +0000 | [diff] [blame] | 64 |  | 
| Thomas Wouters | f70ef4f | 2000-07-22 18:47:25 +0000 | [diff] [blame] | 65 | double strtod(char *str, char **ptr) | 
|  | 66 | { | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 67 | int sign, scale, dotseen; | 
|  | 68 | int esign, expt; | 
|  | 69 | char *save; | 
|  | 70 | register char *sp, *dp; | 
|  | 71 | register int c; | 
|  | 72 | char *buforg, *buflim; | 
|  | 73 | char buffer[64];                    /* 45-digit significant + */ | 
|  | 74 | /* 13-digit exponent */ | 
|  | 75 | sp = str; | 
|  | 76 | while (*sp == ' ') sp++; | 
|  | 77 | sign = 1; | 
|  | 78 | if (*sp == '-') sign -= 2, sp++; | 
|  | 79 | dotseen = 0, scale = 0; | 
|  | 80 | dp = buffer; | 
|  | 81 | *dp++ = '0'; *dp++ = '.'; | 
|  | 82 | buforg = dp, buflim = buffer+48; | 
|  | 83 | for (save = sp; (c = *sp); sp++) | 
|  | 84 | if (c == '.') { | 
|  | 85 | if (dotseen) break; | 
|  | 86 | dotseen++; | 
|  | 87 | } else | 
|  | 88 | if ((unsigned)(c-'0') > (unsigned)('9'-'0')) { | 
|  | 89 | break; | 
|  | 90 | } else | 
|  | 91 | if (c == '0') { | 
|  | 92 | if (dp != buforg) { | 
|  | 93 | /* This is not the first digit, so we want to keep it */ | 
|  | 94 | if (dp < buflim) *dp++ = c; | 
|  | 95 | if (!dotseen) scale++; | 
|  | 96 | } else { | 
|  | 97 | /* No non-zero digits seen yet */ | 
|  | 98 | /* If a . has been seen, scale must be adjusted */ | 
|  | 99 | if (dotseen) scale--; | 
|  | 100 | } | 
|  | 101 | } else { | 
|  | 102 | /* This is a nonzero digit, so we want to keep it */ | 
|  | 103 | if (dp < buflim) *dp++ = c; | 
|  | 104 | /* If it precedes a ., scale must be adjusted */ | 
|  | 105 | if (!dotseen) scale++; | 
|  | 106 | } | 
|  | 107 | if (sp == save) { | 
|  | 108 | if (ptr) *ptr = str; | 
|  | 109 | errno = EDOM;                   /* what should this be? */ | 
|  | 110 | return ZERO; | 
|  | 111 | } | 
| Brett Cannon | 0b64be2 | 2010-05-05 20:50:03 +0000 | [diff] [blame] | 112 |  | 
| Antoine Pitrou | c83ea13 | 2010-05-09 14:46:46 +0000 | [diff] [blame] | 113 | while (dp > buforg && dp[-1] == '0') --dp; | 
|  | 114 | if (dp == buforg) *dp++ = '0'; | 
|  | 115 | *dp = '\0'; | 
|  | 116 | /*  Now the contents of buffer are | 
|  | 117 | +--+--------+-+--------+ | 
|  | 118 | |0.|fraction|\|leftover| | 
|  | 119 | +--+--------+-+--------+ | 
|  | 120 | ^dp points here | 
|  | 121 | where fraction begins with 0 iff it is "0", and has at most | 
|  | 122 | 45 digits in it, and leftover is at least 16 characters. | 
|  | 123 | */ | 
|  | 124 | save = sp, expt = 0, esign = 1; | 
|  | 125 | do { | 
|  | 126 | c = *sp++; | 
|  | 127 | if (c != 'e' && c != 'E') break; | 
|  | 128 | c = *sp++; | 
|  | 129 | if (c == '-') esign -= 2, c = *sp++; else | 
|  | 130 | if (c == '+' /* || c == ' ' */ ) c = *sp++; | 
|  | 131 | if ((unsigned)(c-'0') > (unsigned)('9'-'0')) break; | 
|  | 132 | while (c == '0') c = *sp++; | 
|  | 133 | for (; (unsigned)(c-'0') <= (unsigned)('9'-'0'); c = *sp++) | 
|  | 134 | expt = expt*10 + c-'0'; | 
|  | 135 | if (esign < 0) expt = -expt; | 
|  | 136 | save = sp-1; | 
|  | 137 | } while (0); | 
|  | 138 | if (ptr) *ptr = save; | 
|  | 139 | expt += scale; | 
|  | 140 | /*  Now the number is sign*0.fraction*10**expt  */ | 
|  | 141 | errno = ERANGE; | 
|  | 142 | if (expt > MDMAXEXPT) { | 
|  | 143 | return HUGE*sign; | 
|  | 144 | } else | 
|  | 145 | if (expt == MDMAXEXPT) { | 
|  | 146 | if (strcmp(buforg, MDMAXFRAC) > 0) return HUGE*sign; | 
|  | 147 | } else | 
|  | 148 | if (expt < MDMINEXPT) { | 
|  | 149 | return ZERO*sign; | 
|  | 150 | } else | 
|  | 151 | if (expt == MDMINEXPT) { | 
|  | 152 | if (strcmp(buforg, MDMINFRAC) < 0) return ZERO*sign; | 
|  | 153 | } | 
|  | 154 | /*  We have now established that the number can be  */ | 
|  | 155 | /*  represented without overflow or underflow  */ | 
|  | 156 | (void) sprintf(dp, "E%d", expt); | 
|  | 157 | errno = 0; | 
|  | 158 | return atof(buffer)*sign; | 
| Thomas Wouters | f70ef4f | 2000-07-22 18:47:25 +0000 | [diff] [blame] | 159 | } |