Listing 3

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

/* End of File */