File:  [MW Coherent from dump] / coherent / b / lib / libc / XSTDIO / ndpobj / atof.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.
 * atof()
 * ANSI 4.10.1.1.
 * Convert ASCII to double (the old fashioned way).
 * Builds significand in an unsigned long, for efficiency.
 * Does not use any knowledge about floating point representation.
 */

#if	__STDC__
#include <stdlib.h>
#include <limits.h>
#include <locale.h>
#else
#define	_decimal_point	'.'
extern	double	_pow10();
#endif
#include <ctype.h>

/* 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 */

double
atof(nptr) register char *nptr;
{
	register int		c, flag, eexp;
	register unsigned long	val;
	int			exp, vdigits;
	double			d;

	val = flag = exp = vdigits = 0;

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

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

	/* Number: sequence of decimal digits with optional '.'. */
	for (; ; c = *nptr++) {
		if (isdigit(c)) {
			c -= '0';
#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; */
				val <<= 1;
				val = val + (val << 2) + c;
			}
			if (flag & DOT)
				--exp;
		} else if (c == _decimal_point && (flag & DOT) == 0)
			flag |= DOT;
		else
			break;
	}
	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') {

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

		/* Decimal digits. */
		for (eexp = 0; isdigit(c); c = *nptr++)
			eexp = eexp * 10 + c - '0';

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

	/* Reconcile the significand with the exponent and sign. */
	if (exp != 0)
		d *= _pow10(exp);
	return ((flag & NEG) ? -d : d);
}

unix.superglobalmegacorp.com

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