Annotation of coherent/b/bin/as/strtod.c, revision 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.