/* $Header$ */
#ifndef NOFLOAT
#include <ctype.h>

extern double ldexp();

#define MAX	(0x7fffffffL/10)

double
strtod(p, pp)
	register char *p;
	char **pp;
{
	register int c;
	int exp = 0, sign = 1, expsign = 0;
	double fl;
	long lowl = 0, highl = 0, pos = 1;
	int dotseen = 0;
	int digit_seen = 0;

	if (pp) *pp = p;
	while (isspace(*p)) p++;
	c = *p;

	switch (c) {
	case '-':
		sign = -1;
	case '+': 
		p++;
	}

	while (isdigit(c = *p++) || (c == '.' && ! dotseen++)) {
		if (c == '.') continue;
		digit_seen = 1;
		if (highl < MAX) {
			highl = (highl << 3) + (highl << 1) + (c - '0');
		}
		else if (pos < MAX) {
			pos = (pos << 3) + (pos << 1);
			lowl = (lowl << 3) + (lowl << 1) + (c - '0');
		}
		else exp++;
		if (dotseen) exp--;
	}
	if (! digit_seen) return 0.0;
	fl = highl;
	if (pos > 1) {
		fl = pos * fl + lowl;
	}

	if (pp) *pp = p-1;

	if (c == 'E' || c == 'e') {
		int exp1 = 0;
		int sign = 1;

		switch (*p) {
		case '-':
			sign = -1;
		case '+':
			p++;
		}
		if (isdigit(c = *p)) {
			do {
				exp1 = 10 * exp1 + c - '0';
			} while (isdigit(c = *++p));
			if (pp) *pp = p;
		}
		exp += sign * exp1;
	}

	if (fl == 0.0) return 0.0;

	if (exp < 0) {
		expsign = 1;
		exp = -exp;
	}

	if (exp != 0) {
                int oldexp = exp;
                double exp5 = 5.0;
                double correction = 1.0;
 
                while (exp) {
                        if (exp % 2) correction *= exp5;
                        exp /= 2;
                        if (exp != 0) exp5 *= exp5;
                }
                if (expsign) fl = fl / correction;
                else    fl = fl * correction;
 
                fl = ldexp(fl, expsign ? -oldexp : oldexp);
	}

	return sign * fl;
}
#endif
