Annotation of coherent/b/bin/as/strtod.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * C general utilities library.
                      3:  * strtod()
                      4:  * ANSI 4.10.1.4.
                      5:  * Convert ASCII to double (the System V way).
                      6:  * Builds significand in an unsigned long, for efficiency.
                      7:  * Does not use any knowledge about floating point representation,
                      8:  * except DBL_MIN_10_EXP, DBL_MAX_10_EXP, DBL_EXP_10_DIG.
                      9:  */
                     10: 
                     11: #include <stdlib.h>
                     12: #include <ctype.h>
                     13: #include <errno.h>
                     14: #include <math.h>
                     15: 
                     16: #if    __STDC__
                     17: #include <float.h>
                     18: #include <locale.h>
                     19: #else
                     20: #define        _decimal_point  '.'
                     21: #define        DBL_MIN_10_EXP  -37             /* DECVAX fp */
                     22: #define        DBL_MAX_10_EXP  38
                     23: #endif
                     24: 
                     25: #define        DBL_EXP_10_DIG  2               /* max dec digits in legal DECVAX exponent */
                     26: 
                     27: /* Flag bits. */
                     28: #define        NEG     1                       /* negative significand */
                     29: #define        DOT     2                       /* decimal point seen   */
                     30: #define        NEGEXP  4                       /* negative exponent    */
                     31: #define        BIG     8                       /* significand too big for ulong */
                     32: #define        OVER    16                      /* overflow             */
                     33: #define        UNDER   32                      /* underflow            */
                     34: 
                     35: double
                     36: strtod(nptr, endptr) char *nptr; char **endptr;
                     37: {
                     38:        register char *cp;
                     39:        register int c, flag, eexp;
                     40:        register unsigned long val;
                     41:        int exp, edigits, sdigits, vdigits;
                     42:        double d;
                     43:        char *savcp;
                     44: 
                     45:        cp = nptr;
                     46:        val = flag = exp = sdigits = vdigits = 0;
                     47:        d = 0.;
                     48: 
                     49:        /* Leading white space. */
                     50:        while (isspace(c = *cp++))
                     51:                ;
                     52: 
                     53:        /* Optional sign. */
                     54:        switch (c) {
                     55:        case '-':
                     56:                flag |= NEG;
                     57:                /* fall through... */
                     58:        case '+':
                     59:                c = *cp++;
                     60:        }
                     61: 
                     62:        /* Next character must be decimal digit. */
                     63:        if (!isdigit(c)) {
                     64:                cp = nptr;
                     65:                goto done;
                     66:        }
                     67: 
                     68:        /*
                     69:         * Significand: sequence of decimal digits with optional '.'.
                     70:         * Compute chunks in val (for efficiency) until it overflows.
                     71:         * d * _pow10(vdigits) + val contains the current significand.
                     72:         */
                     73:        for (; ; c = *cp++) {
                     74:                if (isdigit(c)) {
                     75:                        c -= '0';
                     76:                        if (c == 0 && (flag & DOT)) {
                     77:                                /* Check for trailing zeros, to avoid imprecision.  */
                     78:                                char *look, d;
                     79: 
                     80:                                for (look = cp; (d = *look++) == '0';)
                     81:                                        ;
                     82:                                if (!isdigit(d)) {
                     83:                                        cp = look;
                     84:                                        c = d;
                     85:                                        break;
                     86:                                }
                     87:                        }
                     88:                        if (sdigits != 0 || c != 0)
                     89:                                ++sdigits;      /* significant digits seen */
                     90: #if    __STDC__
                     91:                        if (val > (ULONG_MAX-9) / 10) {
                     92: #else
                     93:                        /* The pre-ANSI compiler gets the test above wrong. */
                     94:                        if (val > 429496728L) {
                     95: #endif
                     96:                                /* Significand too big for val, use d. */
                     97:                                if (flag & BIG)
                     98:                                        d = d * _pow10(vdigits) + val;
                     99:                                else {
                    100:                                        d = val;
                    101:                                        flag |= BIG;
                    102:                                }
                    103:                                vdigits = 1;
                    104:                                val = c;
                    105:                        } else {
                    106:                                ++vdigits;      /* decimal digits in val */
                    107:                                val = val * 10 + c;
                    108:                        }
                    109:                        if (flag & DOT)
                    110:                                --exp;          /* implicit exponent */
                    111:                } else if (c == _decimal_point && (flag & DOT) == 0)
                    112:                        flag |= DOT;
                    113:                else
                    114:                        break;
                    115:        }
                    116: 
                    117:        /* Significand to d. */
                    118:        if (flag & BIG)
                    119:                d = d * _pow10(vdigits) + val;
                    120:        else
                    121:                d = val;
                    122: 
                    123:        /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */
                    124:        if (c == 'e'  ||  c == 'E') {
                    125:                savcp = cp - 1;         /* save in case exponent absent */
                    126: 
                    127:                /* Optional sign. */
                    128:                switch (c = *cp++) {
                    129:                case '-':
                    130:                        flag |= NEGEXP;
                    131:                        /* fall through... */
                    132:                case '+':
                    133:                        c = *cp++;
                    134:                }
                    135: 
                    136:                /* Next character must be decimal digit. */
                    137:                if (!isdigit(c)) {
                    138:                        cp = savcp;             /* restore pre-'E' value */
                    139:                        goto done;
                    140:                }
                    141: 
                    142:                /* Decimal digits. */
                    143:                for (eexp = edigits = 0; isdigit(c); c = *cp++) {
                    144:                        if (edigits != 0 || c != '0')
                    145:                                ++edigits;      /* count exp digits for overflow */
                    146:                        eexp = eexp * 10 + c - '0';
                    147:                }
                    148:                if (edigits > DBL_EXP_10_DIG) {
                    149:                        flag |= ((flag & NEGEXP) ? UNDER : OVER);
                    150:                        --cp;
                    151:                        goto done;
                    152:                }
                    153: 
                    154:                /* Adjust explicit exponent for digits read after '.'. */
                    155:                if (flag & NEGEXP)
                    156:                        exp -= eexp;
                    157:                else
                    158:                        exp += eexp;
                    159:        }
                    160:        --cp;
                    161: 
                    162:        /* Reconcile the significand with the exponent. */
                    163:        if (exp <= DBL_MIN_10_EXP)
                    164:                flag |= UNDER;          /* exponent underflow */
                    165:        else if (exp + sdigits - 1 >= DBL_MAX_10_EXP)
                    166:                flag |= OVER;           /* exponent overflow */
                    167:        else if (exp != 0)
                    168:                d *= _pow10(exp);
                    169: 
                    170: done:
                    171:        if (endptr != (char **)NULL)
                    172:                *endptr = cp;
                    173:        if (flag & UNDER) {
                    174:                errno = ERANGE;
                    175:                return 0.0;
                    176:        }
                    177:        if (flag & OVER) {
                    178:                errno = ERANGE;
                    179:                d = HUGE_VAL;
                    180:        }
                    181:        return ((flag & NEG) ? -d : d);
                    182: }
                    183: 
                    184: /* 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.