| 
									
										
										
										
											2001-07-26 13:41:06 +00:00
										 |  |  | #include "pyconfig.h"
 | 
					
						
							| 
									
										
										
										
											1995-02-19 15:54:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | /* comp.sources.misc strtod(), as posted in comp.lang.tcl,
 | 
					
						
							|  |  |  |    with bugfix for "123000.0" and acceptance of space after 'e' sign nuked. | 
					
						
							| 
									
										
										
										
											1991-04-16 08:45:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  |    ************************************************************ | 
					
						
							|  |  |  |    * YOU MUST EDIT THE MACHINE-DEPENDENT DEFINITIONS BELOW!!! * | 
					
						
							|  |  |  |    ************************************************************ | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											1991-12-31 13:15:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | /*  File   : stdtod.c (Modified version of str2dbl.c)
 | 
					
						
							|  |  |  |     Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc. | 
					
						
							|  |  |  |     Updated: Tuesday August 2nd, 1988 | 
					
						
							|  |  |  |     Defines: double strtod (char *str, char**ptr) | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											1991-04-16 08:45:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | /*  This is an implementation of the strtod() function described in the 
 | 
					
						
							|  |  |  |     System V manuals, with a different name to avoid linker problems. | 
					
						
							|  |  |  |     All that str2dbl() does itself is check that the argument is well-formed | 
					
						
							|  |  |  |     and is in range.  It leaves the work of conversion to atof(), which is | 
					
						
							|  |  |  |     assumed to exist and deliver correct results (if they can be represented). | 
					
						
							| 
									
										
										
										
											1991-12-31 13:15:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  |     There are two reasons why this should be provided to the net: | 
					
						
							|  |  |  |     (a) some UNIX systems do not yet have strtod(), or do not have it | 
					
						
							|  |  |  |         available in the BSD "universe" (but they do have atof()). | 
					
						
							|  |  |  |     (b) some of the UNIX systems that *do* have it get it wrong. | 
					
						
							|  |  |  | 	(some crash with large arguments, some assign the wrong *ptr value). | 
					
						
							|  |  |  |     There is a reason why *we* are providing it: we need a correct version | 
					
						
							|  |  |  |     of strtod(), and if we give this one away maybe someone will look for | 
					
						
							|  |  |  |     mistakes in it and fix them for us (:-). | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | /*  The following constants are machine-specific.  MD{MIN,MAX}EXPT are
 | 
					
						
							|  |  |  |     integers and MD{MIN,MAX}FRAC are strings such that | 
					
						
							|  |  |  | 	0.${MDMAXFRAC}e${MDMAXEXPT} is the largest representable double, | 
					
						
							|  |  |  | 	0.${MDMINFRAC}e${MDMINEXPT} is the smallest representable +ve double | 
					
						
							|  |  |  |     MD{MIN,MAX}FRAC must not have any trailing zeros. | 
					
						
							|  |  |  |     The values here are for IEEE-754 64-bit floats. | 
					
						
							|  |  |  |     It is not perfectly clear to me whether an IEEE infinity should be | 
					
						
							|  |  |  |     returned for overflow, nor what a portable way of writing one is, | 
					
						
							|  |  |  |     so HUGE is just 0.MAXFRAC*10**MAXEXPT (this seems still to be the | 
					
						
							|  |  |  |     UNIX convention). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     I do know about <values.h>, but the whole point of this file is that | 
					
						
							|  |  |  |     we can't always trust that stuff to be there or to be correct. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static	int	MDMINEXPT	= {-323}; | 
					
						
							|  |  |  | static	char	MDMINFRAC[]	= "494065645841246544"; | 
					
						
							|  |  |  | static	double	ZERO		= 0.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static	int	MDMAXEXPT	= { 309}; | 
					
						
							| 
									
										
										
										
											1992-03-27 17:30:32 +00:00
										 |  |  | static	char	MDMAXFRAC[]	= "17976931348623157"; | 
					
						
							|  |  |  | static	double	HUGE		= 1.7976931348623157e308; | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-22 18:47:25 +00:00
										 |  |  | extern	double	atof(const char *);		/* Only called when result known to be ok */ | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-04-07 16:07:23 +00:00
										 |  |  | #ifndef DONT_HAVE_ERRNO_H
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | #include <errno.h>
 | 
					
						
							| 
									
										
										
										
											1999-04-07 16:07:23 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | extern	int	errno; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-22 18:47:25 +00:00
										 |  |  | double strtod(char *str, char **ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | 	int sign, scale, dotseen; | 
					
						
							|  |  |  | 	int esign, expt; | 
					
						
							|  |  |  | 	char *save; | 
					
						
							|  |  |  | 	register char *sp, *dp; | 
					
						
							|  |  |  | 	register int c; | 
					
						
							|  |  |  | 	char *buforg, *buflim; | 
					
						
							| 
									
										
										
										
											2000-07-16 12:04:32 +00:00
										 |  |  | 	char buffer[64];		/* 45-digit significant + */ | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | 					/* 13-digit exponent */ | 
					
						
							|  |  |  | 	sp = str; | 
					
						
							|  |  |  | 	while (*sp == ' ') sp++; | 
					
						
							|  |  |  | 	sign = 1; | 
					
						
							|  |  |  | 	if (*sp == '-') sign -= 2, sp++; | 
					
						
							|  |  |  | 	dotseen = 0, scale = 0; | 
					
						
							|  |  |  | 	dp = buffer;	 | 
					
						
							|  |  |  | 	*dp++ = '0'; *dp++ = '.'; | 
					
						
							|  |  |  | 	buforg = dp, buflim = buffer+48; | 
					
						
							|  |  |  | 	for (save = sp; c = *sp; sp++) | 
					
						
							|  |  |  | 	    if (c == '.') { | 
					
						
							|  |  |  | 		if (dotseen) break; | 
					
						
							|  |  |  | 		dotseen++; | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    if ((unsigned)(c-'0') > (unsigned)('9'-'0')) { | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    if (c == '0') { | 
					
						
							|  |  |  | 		if (dp != buforg) { | 
					
						
							|  |  |  | 		    /* This is not the first digit, so we want to keep it */ | 
					
						
							|  |  |  | 		    if (dp < buflim) *dp++ = c; | 
					
						
							|  |  |  | 		    if (!dotseen) scale++; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 		    /* No non-zero digits seen yet */ | 
					
						
							|  |  |  | 		    /* If a . has been seen, scale must be adjusted */ | 
					
						
							|  |  |  | 		    if (dotseen) scale--; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	    } else { | 
					
						
							|  |  |  | 		/* This is a nonzero digit, so we want to keep it */ | 
					
						
							|  |  |  | 		if (dp < buflim) *dp++ = c; | 
					
						
							|  |  |  | 		/* If it precedes a ., scale must be adjusted */ | 
					
						
							|  |  |  | 		if (!dotseen) scale++; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	if (sp == save) { | 
					
						
							|  |  |  | 	    if (ptr) *ptr = str; | 
					
						
							|  |  |  | 	    errno = EDOM;		/* what should this be? */ | 
					
						
							|  |  |  | 	    return ZERO; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1991-12-31 13:15:19 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											1992-01-14 18:42:23 +00:00
										 |  |  | 	while (dp > buforg && dp[-1] == '0') --dp; | 
					
						
							|  |  |  | 	if (dp == buforg) *dp++ = '0'; | 
					
						
							|  |  |  | 	*dp = '\0'; | 
					
						
							|  |  |  | 	/*  Now the contents of buffer are
 | 
					
						
							|  |  |  | 	    +--+--------+-+--------+ | 
					
						
							|  |  |  | 	    |0.|fraction|\|leftover| | 
					
						
							|  |  |  | 	    +--+--------+-+--------+ | 
					
						
							|  |  |  | 			 ^dp points here | 
					
						
							|  |  |  | 	    where fraction begins with 0 iff it is "0", and has at most | 
					
						
							|  |  |  | 	    45 digits in it, and leftover is at least 16 characters. | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	save = sp, expt = 0, esign = 1; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 	    c = *sp++; | 
					
						
							|  |  |  | 	    if (c != 'e' && c != 'E') break; | 
					
						
							|  |  |  | 	    c = *sp++; | 
					
						
							|  |  |  | 	    if (c == '-') esign -= 2, c = *sp++; else | 
					
						
							|  |  |  | 	    if (c == '+' /* || c == ' ' */ ) c = *sp++; | 
					
						
							|  |  |  | 	    if ((unsigned)(c-'0') > (unsigned)('9'-'0')) break; | 
					
						
							|  |  |  | 	    while (c == '0') c = *sp++; | 
					
						
							|  |  |  | 	    for (; (unsigned)(c-'0') <= (unsigned)('9'-'0'); c = *sp++) | 
					
						
							|  |  |  | 		expt = expt*10 + c-'0';	     | 
					
						
							|  |  |  | 	    if (esign < 0) expt = -expt; | 
					
						
							|  |  |  | 	    save = sp-1; | 
					
						
							|  |  |  | 	} while (0); | 
					
						
							|  |  |  | 	if (ptr) *ptr = save; | 
					
						
							|  |  |  | 	expt += scale; | 
					
						
							|  |  |  | 	/*  Now the number is sign*0.fraction*10**expt  */ | 
					
						
							|  |  |  | 	errno = ERANGE; | 
					
						
							|  |  |  | 	if (expt > MDMAXEXPT) { | 
					
						
							|  |  |  | 	    return HUGE*sign; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 	if (expt == MDMAXEXPT) { | 
					
						
							|  |  |  | 	    if (strcmp(buforg, MDMAXFRAC) > 0) return HUGE*sign; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 	if (expt < MDMINEXPT) { | 
					
						
							|  |  |  | 	    return ZERO*sign; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 	if (expt == MDMINEXPT) { | 
					
						
							|  |  |  | 	    if (strcmp(buforg, MDMINFRAC) < 0) return ZERO*sign; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/*  We have now established that the number can be  */ | 
					
						
							|  |  |  | 	/*  represented without overflow or underflow  */ | 
					
						
							|  |  |  | 	(void) sprintf(dp, "E%d", expt); | 
					
						
							|  |  |  | 	errno = 0; | 
					
						
							|  |  |  | 	return atof(buffer)*sign; | 
					
						
							| 
									
										
										
										
											2000-07-22 18:47:25 +00:00
										 |  |  | } |