Annotation of coherent/b/lib/libc/gen/strtod.c, revision 1.1.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.