Annotation of coherent/b/lib/libc/XSTDIO/ndpobj/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 (sdigits != 0 || c != 0)
                     77:                                ++sdigits;      /* significant digits seen */
                     78: #if    __STDC__
                     79:                        if (val > (ULONG_MAX-9) / 10) {
                     80: #else
                     81:                        /* The pre-ANSI compiler gets the test above wrong. */
                     82:                        if (val > 429496728L) {
                     83: #endif
                     84:                                /* Significand too big for val, use d. */
                     85:                                if (flag & BIG)
                     86:                                        d = d * _pow10(vdigits) + val;
                     87:                                else {
                     88:                                        d = val;
                     89:                                        flag |= BIG;
                     90:                                }
                     91:                                vdigits = 1;
                     92:                                val = c;
                     93:                        } else {
                     94:                                ++vdigits;      /* decimal digits in val */
                     95:                                val = val * 10 + c;
                     96:                        }
                     97:                        if (flag & DOT)
                     98:                                --exp;          /* implicit exponent */
                     99:                } else if (c == _decimal_point && (flag & DOT) == 0)
                    100:                        flag |= DOT;
                    101:                else
                    102:                        break;
                    103:        }
                    104: 
                    105:        /* Significand to d. */
                    106:        if (flag & BIG)
                    107:                d = d * _pow10(vdigits) + val;
                    108:        else
                    109:                d = val;
                    110: 
                    111:        /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */
                    112:        if (c == 'e'  ||  c == 'E') {
                    113:                savcp = cp - 1;         /* save in case exponent absent */
                    114: 
                    115:                /* Optional sign. */
                    116:                switch (c = *cp++) {
                    117:                case '-':
                    118:                        flag |= NEGEXP;
                    119:                        /* fall through... */
                    120:                case '+':
                    121:                        c = *cp++;
                    122:                }
                    123: 
                    124:                /* Next character must be decimal digit. */
                    125:                if (!isdigit(c)) {
                    126:                        cp = savcp;             /* restore pre-'E' value */
                    127:                        goto done;
                    128:                }
                    129: 
                    130:                /* Decimal digits. */
                    131:                for (eexp = edigits = 0; isdigit(c); c = *cp++) {
                    132:                        if (edigits != 0 || c != '0')
                    133:                                ++edigits;      /* count exp digits for overflow */
                    134:                        eexp = eexp * 10 + c - '0';
                    135:                }
                    136:                if (edigits > DBL_EXP_10_DIG) {
                    137:                        flag |= ((flag & NEGEXP) ? UNDER : OVER);
                    138:                        --cp;
                    139:                        goto done;
                    140:                }
                    141: 
                    142:                /* Adjust explicit exponent for digits read after '.'. */
                    143:                if (flag & NEGEXP)
                    144:                        exp -= eexp;
                    145:                else
                    146:                        exp += eexp;
                    147:        }
                    148:        --cp;
                    149: 
                    150:        /* Reconcile the significand with the exponent. */
                    151:        if (exp <= DBL_MIN_10_EXP)
                    152:                flag |= UNDER;          /* exponent underflow */
                    153:        else if (exp + sdigits - 1 >= DBL_MAX_10_EXP)
                    154:                flag |= OVER;           /* exponent overflow */
                    155:        else if (exp != 0)
                    156:                d *= _pow10(exp);
                    157: 
                    158: done:
                    159:        if (endptr != (char **)NULL)
                    160:                *endptr = cp;
                    161:        if (flag & UNDER) {
                    162:                errno = ERANGE;
                    163:                return 0.0;
                    164:        }
                    165:        if (flag & OVER) {
                    166:                errno = ERANGE;
                    167:                d = HUGE_VAL;
                    168:        }
                    169:        return ((flag & NEG) ? -d : d);
                    170: }
                    171: 
                    172: /* 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.