Annotation of coherent/b/lib/libc/gen/strtod.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.