sl@0: /* 
sl@0:  * strtod.c --
sl@0:  *
sl@0:  *	Source code for the "strtod" library procedure.
sl@0:  *
sl@0:  * Copyright (c) 1988-1993 The Regents of the University of California.
sl@0:  * Copyright (c) 1994 Sun Microsystems, Inc.
sl@0:  *
sl@0:  * See the file "license.terms" for information on usage and redistribution
sl@0:  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0:  *
sl@0:  * RCS: @(#) $Id: strtod.c,v 1.6 2002/02/25 14:26:12 dgp Exp $
sl@0:  */
sl@0: 
sl@0: #include "tclInt.h"
sl@0: #include "tclPort.h"
sl@0: #include <ctype.h>
sl@0: 
sl@0: #ifndef TRUE
sl@0: #define TRUE 1
sl@0: #define FALSE 0
sl@0: #endif
sl@0: #ifndef NULL
sl@0: #define NULL 0
sl@0: #endif
sl@0: 
sl@0: static int maxExponent = 511;	/* Largest possible base 10 exponent.  Any
sl@0: 				 * exponent larger than this will already
sl@0: 				 * produce underflow or overflow, so there's
sl@0: 				 * no need to worry about additional digits.
sl@0: 				 */
sl@0: static double powersOf10[] = {	/* Table giving binary powers of 10.  Entry */
sl@0:     10.,			/* is 10^2^i.  Used to convert decimal */
sl@0:     100.,			/* exponents into floating-point numbers. */
sl@0:     1.0e4,
sl@0:     1.0e8,
sl@0:     1.0e16,
sl@0:     1.0e32,
sl@0:     1.0e64,
sl@0:     1.0e128,
sl@0:     1.0e256
sl@0: };
sl@0: 
sl@0: /*
sl@0:  *----------------------------------------------------------------------
sl@0:  *
sl@0:  * strtod --
sl@0:  *
sl@0:  *	This procedure converts a floating-point number from an ASCII
sl@0:  *	decimal representation to internal double-precision format.
sl@0:  *
sl@0:  * Results:
sl@0:  *	The return value is the double-precision floating-point
sl@0:  *	representation of the characters in string.  If endPtr isn't
sl@0:  *	NULL, then *endPtr is filled in with the address of the
sl@0:  *	next character after the last one that was part of the
sl@0:  *	floating-point number.
sl@0:  *
sl@0:  * Side effects:
sl@0:  *	None.
sl@0:  *
sl@0:  *----------------------------------------------------------------------
sl@0:  */
sl@0: 
sl@0: double
sl@0: strtod(string, endPtr)
sl@0:     CONST char *string;		/* A decimal ASCII floating-point number,
sl@0: 				 * optionally preceded by white space.
sl@0: 				 * Must have form "-I.FE-X", where I is the
sl@0: 				 * integer part of the mantissa, F is the
sl@0: 				 * fractional part of the mantissa, and X
sl@0: 				 * is the exponent.  Either of the signs
sl@0: 				 * may be "+", "-", or omitted.  Either I
sl@0: 				 * or F may be omitted, or both.  The decimal
sl@0: 				 * point isn't necessary unless F is present.
sl@0: 				 * The "E" may actually be an "e".  E and X
sl@0: 				 * may both be omitted (but not just one).
sl@0: 				 */
sl@0:     char **endPtr;		/* If non-NULL, store terminating character's
sl@0: 				 * address here. */
sl@0: {
sl@0:     int sign, expSign = FALSE;
sl@0:     double fraction, dblExp, *d;
sl@0:     register CONST char *p;
sl@0:     register int c;
sl@0:     int exp = 0;		/* Exponent read from "EX" field. */
sl@0:     int fracExp = 0;		/* Exponent that derives from the fractional
sl@0: 				 * part.  Under normal circumstatnces, it is
sl@0: 				 * the negative of the number of digits in F.
sl@0: 				 * However, if I is very long, the last digits
sl@0: 				 * of I get dropped (otherwise a long I with a
sl@0: 				 * large negative exponent could cause an
sl@0: 				 * unnecessary overflow on I alone).  In this
sl@0: 				 * case, fracExp is incremented one for each
sl@0: 				 * dropped digit. */
sl@0:     int mantSize;		/* Number of digits in mantissa. */
sl@0:     int decPt;			/* Number of mantissa digits BEFORE decimal
sl@0: 				 * point. */
sl@0:     CONST char *pExp;		/* Temporarily holds location of exponent
sl@0: 				 * in string. */
sl@0: 
sl@0:     /*
sl@0:      * Strip off leading blanks and check for a sign.
sl@0:      */
sl@0: 
sl@0:     p = string;
sl@0:     while (isspace(UCHAR(*p))) {
sl@0: 	p += 1;
sl@0:     }
sl@0:     if (*p == '-') {
sl@0: 	sign = TRUE;
sl@0: 	p += 1;
sl@0:     } else {
sl@0: 	if (*p == '+') {
sl@0: 	    p += 1;
sl@0: 	}
sl@0: 	sign = FALSE;
sl@0:     }
sl@0: 
sl@0:     /*
sl@0:      * Count the number of digits in the mantissa (including the decimal
sl@0:      * point), and also locate the decimal point.
sl@0:      */
sl@0: 
sl@0:     decPt = -1;
sl@0:     for (mantSize = 0; ; mantSize += 1)
sl@0:     {
sl@0: 	c = *p;
sl@0: 	if (!isdigit(c)) {
sl@0: 	    if ((c != '.') || (decPt >= 0)) {
sl@0: 		break;
sl@0: 	    }
sl@0: 	    decPt = mantSize;
sl@0: 	}
sl@0: 	p += 1;
sl@0:     }
sl@0: 
sl@0:     /*
sl@0:      * Now suck up the digits in the mantissa.  Use two integers to
sl@0:      * collect 9 digits each (this is faster than using floating-point).
sl@0:      * If the mantissa has more than 18 digits, ignore the extras, since
sl@0:      * they can't affect the value anyway.
sl@0:      */
sl@0:     
sl@0:     pExp  = p;
sl@0:     p -= mantSize;
sl@0:     if (decPt < 0) {
sl@0: 	decPt = mantSize;
sl@0:     } else {
sl@0: 	mantSize -= 1;			/* One of the digits was the point. */
sl@0:     }
sl@0:     if (mantSize > 18) {
sl@0: 	fracExp = decPt - 18;
sl@0: 	mantSize = 18;
sl@0:     } else {
sl@0: 	fracExp = decPt - mantSize;
sl@0:     }
sl@0:     if (mantSize == 0) {
sl@0: 	fraction = 0.0;
sl@0: 	p = string;
sl@0: 	goto done;
sl@0:     } else {
sl@0: 	int frac1, frac2;
sl@0: 	frac1 = 0;
sl@0: 	for ( ; mantSize > 9; mantSize -= 1)
sl@0: 	{
sl@0: 	    c = *p;
sl@0: 	    p += 1;
sl@0: 	    if (c == '.') {
sl@0: 		c = *p;
sl@0: 		p += 1;
sl@0: 	    }
sl@0: 	    frac1 = 10*frac1 + (c - '0');
sl@0: 	}
sl@0: 	frac2 = 0;
sl@0: 	for (; mantSize > 0; mantSize -= 1)
sl@0: 	{
sl@0: 	    c = *p;
sl@0: 	    p += 1;
sl@0: 	    if (c == '.') {
sl@0: 		c = *p;
sl@0: 		p += 1;
sl@0: 	    }
sl@0: 	    frac2 = 10*frac2 + (c - '0');
sl@0: 	}
sl@0: 	fraction = (1.0e9 * frac1) + frac2;
sl@0:     }
sl@0: 
sl@0:     /*
sl@0:      * Skim off the exponent.
sl@0:      */
sl@0: 
sl@0:     p = pExp;
sl@0:     if ((*p == 'E') || (*p == 'e')) {
sl@0: 	p += 1;
sl@0: 	if (*p == '-') {
sl@0: 	    expSign = TRUE;
sl@0: 	    p += 1;
sl@0: 	} else {
sl@0: 	    if (*p == '+') {
sl@0: 		p += 1;
sl@0: 	    }
sl@0: 	    expSign = FALSE;
sl@0: 	}
sl@0: 	if (!isdigit(UCHAR(*p))) {
sl@0: 	    p = pExp;
sl@0: 	    goto done;
sl@0: 	}
sl@0: 	while (isdigit(UCHAR(*p))) {
sl@0: 	    exp = exp * 10 + (*p - '0');
sl@0: 	    p += 1;
sl@0: 	}
sl@0:     }
sl@0:     if (expSign) {
sl@0: 	exp = fracExp - exp;
sl@0:     } else {
sl@0: 	exp = fracExp + exp;
sl@0:     }
sl@0: 
sl@0:     /*
sl@0:      * Generate a floating-point number that represents the exponent.
sl@0:      * Do this by processing the exponent one bit at a time to combine
sl@0:      * many powers of 2 of 10. Then combine the exponent with the
sl@0:      * fraction.
sl@0:      */
sl@0:     
sl@0:     if (exp < 0) {
sl@0: 	expSign = TRUE;
sl@0: 	exp = -exp;
sl@0:     } else {
sl@0: 	expSign = FALSE;
sl@0:     }
sl@0:     if (exp > maxExponent) {
sl@0: 	exp = maxExponent;
sl@0: 	errno = ERANGE;
sl@0:     }
sl@0:     dblExp = 1.0;
sl@0:     for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
sl@0: 	if (exp & 01) {
sl@0: 	    dblExp *= *d;
sl@0: 	}
sl@0:     }
sl@0:     if (expSign) {
sl@0: 	fraction /= dblExp;
sl@0:     } else {
sl@0: 	fraction *= dblExp;
sl@0:     }
sl@0: 
sl@0: done:
sl@0:     if (endPtr != NULL) {
sl@0: 	*endPtr = (char *) p;
sl@0:     }
sl@0: 
sl@0:     if (sign) {
sl@0: 	return -fraction;
sl@0:     }
sl@0:     return fraction;
sl@0: }