File:  [MW Coherent from dump] / coherent / b / lib / libc / XSTDIO / ndpobj / strtod.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * C general utilities library.
 * strtod()
 * ANSI 4.10.1.4.
 * Convert ASCII to double (the System V way).
 * Builds significand in an unsigned long, for efficiency.
 * Does not use any knowledge about floating point representation,
 * except DBL_MIN_10_EXP, DBL_MAX_10_EXP, DBL_EXP_10_DIG.
 */

#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <math.h>

#if	__STDC__
#include <float.h>
#include <locale.h>
#else
#define	_decimal_point	'.'
#define	DBL_MIN_10_EXP	-37		/* DECVAX fp */
#define	DBL_MAX_10_EXP	38
#endif

#define	DBL_EXP_10_DIG	2		/* max dec digits in legal DECVAX exponent */

/* Flag bits. */
#define	NEG	1			/* negative significand */
#define	DOT	2			/* decimal point seen	*/
#define	NEGEXP	4			/* negative exponent	*/
#define	BIG	8			/* significand too big for ulong */
#define	OVER	16			/* overflow		*/
#define	UNDER	32			/* underflow		*/

double
strtod(nptr, endptr) char *nptr; char **endptr;
{
	register char *cp;
	register int c, flag, eexp;
	register unsigned long val;
	int exp, edigits, sdigits, vdigits;
	double d;
	char *savcp;

	cp = nptr;
	val = flag = exp = sdigits = vdigits = 0;
	d = 0.;

	/* Leading white space. */
	while (isspace(c = *cp++))
		;

	/* Optional sign. */
	switch (c) {
	case '-':
		flag |= NEG;
		/* fall through... */
	case '+':
		c = *cp++;
	}

	/* Next character must be decimal digit. */
	if (!isdigit(c)) {
		cp = nptr;
		goto done;
	}

	/*
	 * Significand: sequence of decimal digits with optional '.'.
	 * Compute chunks in val (for efficiency) until it overflows.
	 * d * _pow10(vdigits) + val contains the current significand.
	 */
	for (; ; c = *cp++) {
		if (isdigit(c)) {
			c -= '0';
			if (sdigits != 0 || c != 0)
				++sdigits;	/* significant digits seen */
#if	__STDC__
			if (val > (ULONG_MAX-9) / 10) {
#else
			/* The pre-ANSI compiler gets the test above wrong. */
			if (val > 429496728L) {
#endif
				/* Significand too big for val, use d. */
				if (flag & BIG)
					d = d * _pow10(vdigits) + val;
				else {
					d = val;
					flag |= BIG;
				}
				vdigits = 1;
				val = c;
			} else {
				++vdigits;	/* decimal digits in val */
				val = val * 10 + c;
			}
			if (flag & DOT)
				--exp;		/* implicit exponent */
		} else if (c == _decimal_point && (flag & DOT) == 0)
			flag |= DOT;
		else
			break;
	}

	/* Significand to d. */
	if (flag & BIG)
		d = d * _pow10(vdigits) + val;
	else
		d = val;

	/* Optional exponent: 'E' or 'e', optional sign, decimal digits. */
	if (c == 'e'  ||  c == 'E') {
		savcp = cp - 1;		/* save in case exponent absent */

		/* Optional sign. */
		switch (c = *cp++) {
		case '-':
			flag |= NEGEXP;
			/* fall through... */
		case '+':
			c = *cp++;
		}

		/* Next character must be decimal digit. */
		if (!isdigit(c)) {
			cp = savcp;		/* restore pre-'E' value */
			goto done;
		}

		/* Decimal digits. */
		for (eexp = edigits = 0; isdigit(c); c = *cp++) {
			if (edigits != 0 || c != '0')
				++edigits;	/* count exp digits for overflow */
			eexp = eexp * 10 + c - '0';
		}
		if (edigits > DBL_EXP_10_DIG) {
			flag |= ((flag & NEGEXP) ? UNDER : OVER);
			--cp;
			goto done;
		}

		/* Adjust explicit exponent for digits read after '.'. */
		if (flag & NEGEXP)
			exp -= eexp;
		else
			exp += eexp;
	}
	--cp;

	/* Reconcile the significand with the exponent. */
	if (exp <= DBL_MIN_10_EXP)
		flag |= UNDER;		/* exponent underflow */
	else if (exp + sdigits - 1 >= DBL_MAX_10_EXP)
		flag |= OVER;		/* exponent overflow */
	else if (exp != 0)
		d *= _pow10(exp);

done:
	if (endptr != (char **)NULL)
		*endptr = cp;
	if (flag & UNDER) {
		errno = ERANGE;
		return 0.0;
	}
	if (flag & OVER) {
		errno = ERANGE;
		d = HUGE_VAL;
	}
	return ((flag & NEG) ? -d : d);
}

/* end of strtod.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.