
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include "float.h"
#ifndef errno
extern int errno;
#endif
extern struct {
    double n[308];
    double p[DBL_MAX_10_EXP + 1];
}      dp10_;


double atof(dstr)
    char *dstr;                 /* any correctly working atof() may be used */
{
    int c,                      /* difference from exponent of accumulated
                                   integer to final value */
        exp = 0, neg_val = 0,   /* leading negative sign ? */
        e_exp = 0,              /* number after e/E +/- */
        neg_exp = 0,            /* - after E/e ? */
        fdig = 0;
#ifdef __STDC__
    long double x, retval = 0, r = 0;
#else
    register double x, retval = 0, r = 0;
#endif
    while (isspace(c = *dstr))  /* skip leading  space */
        dstr++;
    switch (c) {                /* optional sign */
      case '-':
        neg_val = 1;
      case '+':         /* fall-through */
        dstr++;
    }

    if (isdigit(c = *dstr++))
    /* add up converted values before dec point */
        do /* changed from while to do while for optimization */
                retval = 10 * retval + (double) (c - '0' while (isdigit(c = *dstr++));
    if (c == '.')
#if LDBL_DIG > DBL_DIG
        while (isdigit(c = *dstr++))   /* and after dec pt */
            retval += (c - '0') * dp10_.p[--fdig];
#else
        if (isdigit(c = *dstr++))
            for (;;) {          /* and after dec pt, order of operations
                                   must be as shown */
                retval = (x = retval) + (r += (c - '0') * dp10_.p[--fdig]);
                if (!isdigit(c = *dstr++))
                    break;
                r += x -= retval;     /* numerical error correction term */
            }
#endif
    if ((c | ' ') == 'e') {     /* found an exponent lead-in */

        switch (*dstr) {        /* sign field */
          case '-':
            neg_exp = 1;
          case '+':        /* fall-through */
          case ' ':             /* many FORTRAN environments generate this! */
            dstr++;
          default:
            ;            /* fall-through */
        }
        if (isdigit(c = *dstr))        /* found  exponent digit */
            do
               e_exp = 10 * e_exp + (int) (c - '0');
            while (isdigit(c = *++dstr));
    }
    if ((exp += neg_exp ? -e_exp : e_exp) >= 0)
        if (exp <= DBL_MAX_10_EXP)
            retval *= dp10_.p[exp];
        else {
            errno = ERANGE;
            retval = HUGE_VAL;
        }
    else if ((exp = -exp) <= DBL_MAX_10_EXP)
        retval /= dp10_.p[exp];
    else if (exp - DBL_MAX_10_EXP / 2 <= DBL_MAX_10_EXP) {
        retval /= dp10_.p[DBL_MAX_10_EXP / 2];
        retval /= dp10_.p[exp - DBL_MAX_10_EXP / 2];
    } else {
        retval = 0;
        errno = ERANGE;
    }
    return (neg_val ? -retval : retval);        /* apply sign */
}
