Annotation of 43BSDReno/lib/libc/stdio/doprnt.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1988 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted provided
        !             6:  * that: (1) source distributions retain this entire copyright notice and
        !             7:  * comment, and (2) distributions including binaries display the following
        !             8:  * acknowledgement:  ``This product includes software developed by the
        !             9:  * University of California, Berkeley and its contributors'' in the
        !            10:  * documentation or other materials provided with the distribution and in
        !            11:  * all advertising materials mentioning features or use of this software.
        !            12:  * Neither the name of the University nor the names of its contributors may
        !            13:  * be used to endorse or promote products derived from this software without
        !            14:  * specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #if defined(LIBC_SCCS) && !defined(lint)
        !            21: static char sccsid[] = "@(#)doprnt.c   5.39 (Berkeley) 6/28/90";
        !            22: #endif /* LIBC_SCCS and not lint */
        !            23: 
        !            24: #include <sys/types.h>
        !            25: #include <varargs.h>
        !            26: #include <stdio.h>
        !            27: #include <ctype.h>
        !            28: 
        !            29: /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
        !            30: #define        MAXEXP          308
        !            31: /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
        !            32: #define        MAXFRACT        39
        !            33: 
        !            34: #define        DEFPREC         6
        !            35: 
        !            36: #define        BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
        !            37: 
        !            38: #define        PUTC(ch)        (void) putc(ch, fp)
        !            39: 
        !            40: #define ARG(basetype) \
        !            41:        _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
        !            42:            flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
        !            43:            va_arg(argp, int)
        !            44: 
        !            45: #define        todigit(c)      ((c) - '0')
        !            46: #define        tochar(n)       ((n) + '0')
        !            47: 
        !            48: /* have to deal with the negative buffer count kludge */
        !            49: #define        NEGATIVE_COUNT_KLUDGE
        !            50: 
        !            51: #define        LONGINT         0x01            /* long integer */
        !            52: #define        LONGDBL         0x02            /* long double; unimplemented */
        !            53: #define        SHORTINT        0x04            /* short integer */
        !            54: #define        ALT             0x08            /* alternate form */
        !            55: #define        LADJUST         0x10            /* left adjustment */
        !            56: #define        ZEROPAD         0x20            /* zero (as opposed to blank) pad */
        !            57: #define        HEXPREFIX       0x40            /* add 0x or 0X prefix */
        !            58: 
        !            59: _doprnt(fmt0, argp, fp)
        !            60:        u_char *fmt0;
        !            61:        va_list argp;
        !            62:        register FILE *fp;
        !            63: {
        !            64:        register u_char *fmt;   /* format string */
        !            65:        register int ch;        /* character from fmt */
        !            66:        register int cnt;       /* return value accumulator */
        !            67:        register int n;         /* random handy integer */
        !            68:        register char *t;       /* buffer pointer */
        !            69:        double _double;         /* double precision arguments %[eEfgG] */
        !            70:        u_long _ulong;          /* integer arguments %[diouxX] */
        !            71:        int base;               /* base for [diouxX] conversion */
        !            72:        int dprec;              /* decimal precision in [diouxX] */
        !            73:        int fieldsz;            /* field size expanded by sign, etc */
        !            74:        int flags;              /* flags as above */
        !            75:        int fpprec;             /* `extra' floating precision in [eEfgG] */
        !            76:        int prec;               /* precision from format (%.3d), or -1 */
        !            77:        int realsz;             /* field size expanded by decimal precision */
        !            78:        int size;               /* size of converted field or string */
        !            79:        int width;              /* width from format (%8d), or 0 */
        !            80:        char sign;              /* sign prefix (' ', '+', '-', or \0) */
        !            81:        char softsign;          /* temporary negative sign for floats */
        !            82:        char *digs;             /* digits for [diouxX] conversion */
        !            83:        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
        !            84: 
        !            85:        if (fp->_flag & _IORW) {
        !            86:                fp->_flag |= _IOWRT;
        !            87:                fp->_flag &= ~(_IOEOF|_IOREAD);
        !            88:        }
        !            89:        if ((fp->_flag & _IOWRT) == 0)
        !            90:                return (EOF);
        !            91: 
        !            92:        fmt = fmt0;
        !            93:        digs = "0123456789abcdef";
        !            94:        for (cnt = 0;; ++fmt) {
        !            95:                n = fp->_cnt;
        !            96:                for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
        !            97:                     ++cnt, ++fmt)
        !            98:                        if (--n < 0
        !            99: #ifdef NEGATIVE_COUNT_KLUDGE
        !           100:                            && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
        !           101: #endif
        !           102:                            || ch == '\n' && fp->_flag & _IOLBF) {
        !           103:                                fp->_cnt = n;
        !           104:                                fp->_ptr = t;
        !           105:                                (void) _flsbuf((u_char)ch, fp);
        !           106:                                n = fp->_cnt;
        !           107:                                t = (char *)fp->_ptr;
        !           108:                        } else
        !           109:                                *t++ = ch;
        !           110:                fp->_cnt = n;
        !           111:                fp->_ptr = t;
        !           112:                if (!ch)
        !           113:                        return (cnt);
        !           114: 
        !           115:                flags = 0; dprec = 0; fpprec = 0; width = 0;
        !           116:                prec = -1;
        !           117:                sign = '\0';
        !           118: 
        !           119: rflag:         switch (*++fmt) {
        !           120:                case ' ':
        !           121:                        /*
        !           122:                         * ``If the space and + flags both appear, the space
        !           123:                         * flag will be ignored.''
        !           124:                         *      -- ANSI X3J11
        !           125:                         */
        !           126:                        if (!sign)
        !           127:                                sign = ' ';
        !           128:                        goto rflag;
        !           129:                case '#':
        !           130:                        flags |= ALT;
        !           131:                        goto rflag;
        !           132:                case '*':
        !           133:                        /*
        !           134:                         * ``A negative field width argument is taken as a
        !           135:                         * - flag followed by a  positive field width.''
        !           136:                         *      -- ANSI X3J11
        !           137:                         * They don't exclude field widths read from args.
        !           138:                         */
        !           139:                        if ((width = va_arg(argp, int)) >= 0)
        !           140:                                goto rflag;
        !           141:                        width = -width;
        !           142:                        /* FALLTHROUGH */
        !           143:                case '-':
        !           144:                        flags |= LADJUST;
        !           145:                        goto rflag;
        !           146:                case '+':
        !           147:                        sign = '+';
        !           148:                        goto rflag;
        !           149:                case '.':
        !           150:                        if (*++fmt == '*')
        !           151:                                n = va_arg(argp, int);
        !           152:                        else {
        !           153:                                n = 0;
        !           154:                                while (isascii(*fmt) && isdigit(*fmt))
        !           155:                                        n = 10 * n + todigit(*fmt++);
        !           156:                                --fmt;
        !           157:                        }
        !           158:                        prec = n < 0 ? -1 : n;
        !           159:                        goto rflag;
        !           160:                case '0':
        !           161:                        /*
        !           162:                         * ``Note that 0 is taken as a flag, not as the
        !           163:                         * beginning of a field width.''
        !           164:                         *      -- ANSI X3J11
        !           165:                         */
        !           166:                        flags |= ZEROPAD;
        !           167:                        goto rflag;
        !           168:                case '1': case '2': case '3': case '4':
        !           169:                case '5': case '6': case '7': case '8': case '9':
        !           170:                        n = 0;
        !           171:                        do {
        !           172:                                n = 10 * n + todigit(*fmt);
        !           173:                        } while (isascii(*++fmt) && isdigit(*fmt));
        !           174:                        width = n;
        !           175:                        --fmt;
        !           176:                        goto rflag;
        !           177:                case 'L':
        !           178:                        flags |= LONGDBL;
        !           179:                        goto rflag;
        !           180:                case 'h':
        !           181:                        flags |= SHORTINT;
        !           182:                        goto rflag;
        !           183:                case 'l':
        !           184:                        flags |= LONGINT;
        !           185:                        goto rflag;
        !           186:                case 'c':
        !           187:                        *(t = buf) = va_arg(argp, int);
        !           188:                        size = 1;
        !           189:                        sign = '\0';
        !           190:                        goto pforw;
        !           191:                case 'D':
        !           192:                        flags |= LONGINT;
        !           193:                        /*FALLTHROUGH*/
        !           194:                case 'd':
        !           195:                case 'i':
        !           196:                        ARG(int);
        !           197:                        if ((long)_ulong < 0) {
        !           198:                                _ulong = -_ulong;
        !           199:                                sign = '-';
        !           200:                        }
        !           201:                        base = 10;
        !           202:                        goto number;
        !           203:                case 'e':
        !           204:                case 'E':
        !           205:                case 'f':
        !           206:                case 'g':
        !           207:                case 'G':
        !           208:                        _double = va_arg(argp, double);
        !           209:                        /*
        !           210:                         * don't do unrealistic precision; just pad it with
        !           211:                         * zeroes later, so buffer size stays rational.
        !           212:                         */
        !           213:                        if (prec > MAXFRACT) {
        !           214:                                if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
        !           215:                                        fpprec = prec - MAXFRACT;
        !           216:                                prec = MAXFRACT;
        !           217:                        }
        !           218:                        else if (prec == -1)
        !           219:                                prec = DEFPREC;
        !           220:                        /*
        !           221:                         * softsign avoids negative 0 if _double is < 0 and
        !           222:                         * no significant digits will be shown
        !           223:                         */
        !           224:                        if (_double < 0) {
        !           225:                                softsign = '-';
        !           226:                                _double = -_double;
        !           227:                        }
        !           228:                        else
        !           229:                                softsign = 0;
        !           230:                        /*
        !           231:                         * cvt may have to round up past the "start" of the
        !           232:                         * buffer, i.e. ``intf("%.2f", (double)9.999);'';
        !           233:                         * if the first char isn't NULL, it did.
        !           234:                         */
        !           235:                        *buf = NULL;
        !           236:                        size = cvt(_double, prec, flags, &softsign, *fmt, buf,
        !           237:                            buf + sizeof(buf));
        !           238:                        if (softsign)
        !           239:                                sign = '-';
        !           240:                        t = *buf ? buf : buf + 1;
        !           241:                        goto pforw;
        !           242:                case 'n':
        !           243:                        if (flags & LONGINT)
        !           244:                                *va_arg(argp, long *) = cnt;
        !           245:                        else if (flags & SHORTINT)
        !           246:                                *va_arg(argp, short *) = cnt;
        !           247:                        else
        !           248:                                *va_arg(argp, int *) = cnt;
        !           249:                        break;
        !           250:                case 'O':
        !           251:                        flags |= LONGINT;
        !           252:                        /*FALLTHROUGH*/
        !           253:                case 'o':
        !           254:                        ARG(unsigned);
        !           255:                        base = 8;
        !           256:                        goto nosign;
        !           257:                case 'p':
        !           258:                        /*
        !           259:                         * ``The argument shall be a pointer to void.  The
        !           260:                         * value of the pointer is converted to a sequence
        !           261:                         * of printable characters, in an implementation-
        !           262:                         * defined manner.''
        !           263:                         *      -- ANSI X3J11
        !           264:                         */
        !           265:                        /* NOSTRICT */
        !           266:                        _ulong = (u_long)va_arg(argp, void *);
        !           267:                        base = 16;
        !           268:                        goto nosign;
        !           269:                case 's':
        !           270:                        if (!(t = va_arg(argp, char *)))
        !           271:                                t = "(null)";
        !           272:                        if (prec >= 0) {
        !           273:                                /*
        !           274:                                 * can't use strlen; can only look for the
        !           275:                                 * NUL in the first `prec' characters, and
        !           276:                                 * strlen() will go further.
        !           277:                                 */
        !           278:                                char *p, *memchr();
        !           279: 
        !           280:                                if (p = memchr(t, 0, prec)) {
        !           281:                                        size = p - t;
        !           282:                                        if (size > prec)
        !           283:                                                size = prec;
        !           284:                                } else
        !           285:                                        size = prec;
        !           286:                        } else
        !           287:                                size = strlen(t);
        !           288:                        sign = '\0';
        !           289:                        goto pforw;
        !           290:                case 'U':
        !           291:                        flags |= LONGINT;
        !           292:                        /*FALLTHROUGH*/
        !           293:                case 'u':
        !           294:                        ARG(unsigned);
        !           295:                        base = 10;
        !           296:                        goto nosign;
        !           297:                case 'X':
        !           298:                        digs = "0123456789ABCDEF";
        !           299:                        /* FALLTHROUGH */
        !           300:                case 'x':
        !           301:                        ARG(unsigned);
        !           302:                        base = 16;
        !           303:                        /* leading 0x/X only if non-zero */
        !           304:                        if (flags & ALT && _ulong != 0)
        !           305:                                flags |= HEXPREFIX;
        !           306: 
        !           307:                        /* unsigned conversions */
        !           308: nosign:                        sign = '\0';
        !           309:                        /*
        !           310:                         * ``... diouXx conversions ... if a precision is
        !           311:                         * specified, the 0 flag will be ignored.''
        !           312:                         *      -- ANSI X3J11
        !           313:                         */
        !           314: number:                        if ((dprec = prec) >= 0)
        !           315:                                flags &= ~ZEROPAD;
        !           316: 
        !           317:                        /*
        !           318:                         * ``The result of converting a zero value with an
        !           319:                         * explicit precision of zero is no characters.''
        !           320:                         *      -- ANSI X3J11
        !           321:                         */
        !           322:                        t = buf + BUF;
        !           323:                        if (_ulong != 0 || prec != 0) {
        !           324:                                do {
        !           325:                                        *--t = digs[_ulong % base];
        !           326:                                        _ulong /= base;
        !           327:                                } while (_ulong);
        !           328:                                digs = "0123456789abcdef";
        !           329:                                if (flags & ALT && base == 8 && *t != '0')
        !           330:                                        *--t = '0'; /* octal leading 0 */
        !           331:                        }
        !           332:                        size = buf + BUF - t;
        !           333: 
        !           334: pforw:
        !           335:                        /*
        !           336:                         * All reasonable formats wind up here.  At this point,
        !           337:                         * `t' points to a string which (if not flags&LADJUST)
        !           338:                         * should be padded out to `width' places.  If
        !           339:                         * flags&ZEROPAD, it should first be prefixed by any
        !           340:                         * sign or other prefix; otherwise, it should be blank
        !           341:                         * padded before the prefix is emitted.  After any
        !           342:                         * left-hand padding and prefixing, emit zeroes
        !           343:                         * required by a decimal [diouxX] precision, then print
        !           344:                         * the string proper, then emit zeroes required by any
        !           345:                         * leftover floating precision; finally, if LADJUST,
        !           346:                         * pad with blanks.
        !           347:                         */
        !           348: 
        !           349:                        /*
        !           350:                         * compute actual size, so we know how much to pad
        !           351:                         * fieldsz excludes decimal prec; realsz includes it
        !           352:                         */
        !           353:                        fieldsz = size + fpprec;
        !           354:                        if (sign)
        !           355:                                fieldsz++;
        !           356:                        if (flags & HEXPREFIX)
        !           357:                                fieldsz += 2;
        !           358:                        realsz = dprec > fieldsz ? dprec : fieldsz;
        !           359: 
        !           360:                        /* right-adjusting blank padding */
        !           361:                        if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
        !           362:                                for (n = realsz; n < width; n++)
        !           363:                                        PUTC(' ');
        !           364:                        /* prefix */
        !           365:                        if (sign)
        !           366:                                PUTC(sign);
        !           367:                        if (flags & HEXPREFIX) {
        !           368:                                PUTC('0');
        !           369:                                PUTC((char)*fmt);
        !           370:                        }
        !           371:                        /* right-adjusting zero padding */
        !           372:                        if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
        !           373:                                for (n = realsz; n < width; n++)
        !           374:                                        PUTC('0');
        !           375:                        /* leading zeroes from decimal precision */
        !           376:                        for (n = fieldsz; n < dprec; n++)
        !           377:                                PUTC('0');
        !           378: 
        !           379:                        /* the string or number proper */
        !           380:                        n = size;
        !           381:                        if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) {
        !           382:                                fp->_cnt -= n;
        !           383:                                bcopy(t, (char *)fp->_ptr, n);
        !           384:                                fp->_ptr += n;
        !           385:                        } else
        !           386:                                while (--n >= 0)
        !           387:                                        PUTC(*t++);
        !           388:                        /* trailing f.p. zeroes */
        !           389:                        while (--fpprec >= 0)
        !           390:                                PUTC('0');
        !           391:                        /* left-adjusting padding (always blank) */
        !           392:                        if (flags & LADJUST)
        !           393:                                for (n = realsz; n < width; n++)
        !           394:                                        PUTC(' ');
        !           395:                        /* finally, adjust cnt */
        !           396:                        cnt += width > realsz ? width : realsz;
        !           397:                        break;
        !           398:                case '\0':      /* "%?" prints ?, unless ? is NULL */
        !           399:                        return (cnt);
        !           400:                default:
        !           401:                        PUTC((char)*fmt);
        !           402:                        cnt++;
        !           403:                }
        !           404:        }
        !           405:        /* NOTREACHED */
        !           406: }
        !           407: 
        !           408: static
        !           409: cvt(number, prec, flags, signp, fmtch, startp, endp)
        !           410:        double number;
        !           411:        register int prec;
        !           412:        int flags;
        !           413:        u_char fmtch;
        !           414:        char *signp, *startp, *endp;
        !           415: {
        !           416:        register char *p, *t;
        !           417:        register double fract;
        !           418:        int dotrim, expcnt, gformat;
        !           419:        double integer, tmp, modf();
        !           420:        char *exponent(), *round();
        !           421: 
        !           422: #ifdef hp300
        !           423:        if (expcnt = isspecial(number, startp, signp))
        !           424:                return(expcnt);
        !           425: #endif
        !           426: 
        !           427:        dotrim = expcnt = gformat = 0;
        !           428:        fract = modf(number, &integer);
        !           429: 
        !           430:        /* get an extra slot for rounding. */
        !           431:        t = ++startp;
        !           432: 
        !           433:        /*
        !           434:         * get integer portion of number; put into the end of the buffer; the
        !           435:         * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
        !           436:         */
        !           437:        for (p = endp - 1; integer; ++expcnt) {
        !           438:                tmp = modf(integer / 10, &integer);
        !           439:                *p-- = tochar((int)((tmp + .01) * 10));
        !           440:        }
        !           441:        switch(fmtch) {
        !           442:        case 'f':
        !           443:                /* reverse integer into beginning of buffer */
        !           444:                if (expcnt)
        !           445:                        for (; ++p < endp; *t++ = *p);
        !           446:                else
        !           447:                        *t++ = '0';
        !           448:                /*
        !           449:                 * if precision required or alternate flag set, add in a
        !           450:                 * decimal point.
        !           451:                 */
        !           452:                if (prec || flags&ALT)
        !           453:                        *t++ = '.';
        !           454:                /* if requires more precision and some fraction left */
        !           455:                if (fract) {
        !           456:                        if (prec)
        !           457:                                do {
        !           458:                                        fract = modf(fract * 10, &tmp);
        !           459:                                        *t++ = tochar((int)tmp);
        !           460:                                } while (--prec && fract);
        !           461:                        if (fract)
        !           462:                                startp = round(fract, (int *)NULL, startp,
        !           463:                                    t - 1, (char)0, signp);
        !           464:                }
        !           465:                for (; prec--; *t++ = '0');
        !           466:                break;
        !           467:        case 'e':
        !           468:        case 'E':
        !           469: eformat:       if (expcnt) {
        !           470:                        *t++ = *++p;
        !           471:                        if (prec || flags&ALT)
        !           472:                                *t++ = '.';
        !           473:                        /* if requires more precision and some integer left */
        !           474:                        for (; prec && ++p < endp; --prec)
        !           475:                                *t++ = *p;
        !           476:                        /*
        !           477:                         * if done precision and more of the integer component,
        !           478:                         * round using it; adjust fract so we don't re-round
        !           479:                         * later.
        !           480:                         */
        !           481:                        if (!prec && ++p < endp) {
        !           482:                                fract = 0;
        !           483:                                startp = round((double)0, &expcnt, startp,
        !           484:                                    t - 1, *p, signp);
        !           485:                        }
        !           486:                        /* adjust expcnt for digit in front of decimal */
        !           487:                        --expcnt;
        !           488:                }
        !           489:                /* until first fractional digit, decrement exponent */
        !           490:                else if (fract) {
        !           491:                        /* adjust expcnt for digit in front of decimal */
        !           492:                        for (expcnt = -1;; --expcnt) {
        !           493:                                fract = modf(fract * 10, &tmp);
        !           494:                                if (tmp)
        !           495:                                        break;
        !           496:                        }
        !           497:                        *t++ = tochar((int)tmp);
        !           498:                        if (prec || flags&ALT)
        !           499:                                *t++ = '.';
        !           500:                }
        !           501:                else {
        !           502:                        *t++ = '0';
        !           503:                        if (prec || flags&ALT)
        !           504:                                *t++ = '.';
        !           505:                }
        !           506:                /* if requires more precision and some fraction left */
        !           507:                if (fract) {
        !           508:                        if (prec)
        !           509:                                do {
        !           510:                                        fract = modf(fract * 10, &tmp);
        !           511:                                        *t++ = tochar((int)tmp);
        !           512:                                } while (--prec && fract);
        !           513:                        if (fract)
        !           514:                                startp = round(fract, &expcnt, startp,
        !           515:                                    t - 1, (char)0, signp);
        !           516:                }
        !           517:                /* if requires more precision */
        !           518:                for (; prec--; *t++ = '0');
        !           519: 
        !           520:                /* unless alternate flag, trim any g/G format trailing 0's */
        !           521:                if (gformat && !(flags&ALT)) {
        !           522:                        while (t > startp && *--t == '0');
        !           523:                        if (*t == '.')
        !           524:                                --t;
        !           525:                        ++t;
        !           526:                }
        !           527:                t = exponent(t, expcnt, fmtch);
        !           528:                break;
        !           529:        case 'g':
        !           530:        case 'G':
        !           531:                /* a precision of 0 is treated as a precision of 1. */
        !           532:                if (!prec)
        !           533:                        ++prec;
        !           534:                /*
        !           535:                 * ``The style used depends on the value converted; style e
        !           536:                 * will be used only if the exponent resulting from the
        !           537:                 * conversion is less than -4 or greater than the precision.''
        !           538:                 *      -- ANSI X3J11
        !           539:                 */
        !           540:                if (expcnt > prec || !expcnt && fract && fract < .0001) {
        !           541:                        /*
        !           542:                         * g/G format counts "significant digits, not digits of
        !           543:                         * precision; for the e/E format, this just causes an
        !           544:                         * off-by-one problem, i.e. g/G considers the digit
        !           545:                         * before the decimal point significant and e/E doesn't
        !           546:                         * count it as precision.
        !           547:                         */
        !           548:                        --prec;
        !           549:                        fmtch -= 2;             /* G->E, g->e */
        !           550:                        gformat = 1;
        !           551:                        goto eformat;
        !           552:                }
        !           553:                /*
        !           554:                 * reverse integer into beginning of buffer,
        !           555:                 * note, decrement precision
        !           556:                 */
        !           557:                if (expcnt)
        !           558:                        for (; ++p < endp; *t++ = *p, --prec);
        !           559:                else
        !           560:                        *t++ = '0';
        !           561:                /*
        !           562:                 * if precision required or alternate flag set, add in a
        !           563:                 * decimal point.  If no digits yet, add in leading 0.
        !           564:                 */
        !           565:                if (prec || flags&ALT) {
        !           566:                        dotrim = 1;
        !           567:                        *t++ = '.';
        !           568:                }
        !           569:                else
        !           570:                        dotrim = 0;
        !           571:                /* if requires more precision and some fraction left */
        !           572:                if (fract) {
        !           573:                        if (prec) {
        !           574:                                do {
        !           575:                                        fract = modf(fract * 10, &tmp);
        !           576:                                        *t++ = tochar((int)tmp);
        !           577:                                } while(!tmp);
        !           578:                                while (--prec && fract) {
        !           579:                                        fract = modf(fract * 10, &tmp);
        !           580:                                        *t++ = tochar((int)tmp);
        !           581:                                }
        !           582:                        }
        !           583:                        if (fract)
        !           584:                                startp = round(fract, (int *)NULL, startp,
        !           585:                                    t - 1, (char)0, signp);
        !           586:                }
        !           587:                /* alternate format, adds 0's for precision, else trim 0's */
        !           588:                if (flags&ALT)
        !           589:                        for (; prec--; *t++ = '0');
        !           590:                else if (dotrim) {
        !           591:                        while (t > startp && *--t == '0');
        !           592:                        if (*t != '.')
        !           593:                                ++t;
        !           594:                }
        !           595:        }
        !           596:        return(t - startp);
        !           597: }
        !           598: 
        !           599: static char *
        !           600: round(fract, exp, start, end, ch, signp)
        !           601:        double fract;
        !           602:        int *exp;
        !           603:        register char *start, *end;
        !           604:        char ch, *signp;
        !           605: {
        !           606:        double tmp;
        !           607: 
        !           608:        if (fract)
        !           609:                (void)modf(fract * 10, &tmp);
        !           610:        else
        !           611:                tmp = todigit(ch);
        !           612:        if (tmp > 4)
        !           613:                for (;; --end) {
        !           614:                        if (*end == '.')
        !           615:                                --end;
        !           616:                        if (++*end <= '9')
        !           617:                                break;
        !           618:                        *end = '0';
        !           619:                        if (end == start) {
        !           620:                                if (exp) {      /* e/E; increment exponent */
        !           621:                                        *end = '1';
        !           622:                                        ++*exp;
        !           623:                                }
        !           624:                                else {          /* f; add extra digit */
        !           625:                                        *--end = '1';
        !           626:                                        --start;
        !           627:                                }
        !           628:                                break;
        !           629:                        }
        !           630:                }
        !           631:        /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
        !           632:        else if (*signp == '-')
        !           633:                for (;; --end) {
        !           634:                        if (*end == '.')
        !           635:                                --end;
        !           636:                        if (*end != '0')
        !           637:                                break;
        !           638:                        if (end == start)
        !           639:                                *signp = 0;
        !           640:                }
        !           641:        return(start);
        !           642: }
        !           643: 
        !           644: static char *
        !           645: exponent(p, exp, fmtch)
        !           646:        register char *p;
        !           647:        register int exp;
        !           648:        u_char fmtch;
        !           649: {
        !           650:        register char *t;
        !           651:        char expbuf[MAXEXP];
        !           652: 
        !           653:        *p++ = fmtch;
        !           654:        if (exp < 0) {
        !           655:                exp = -exp;
        !           656:                *p++ = '-';
        !           657:        }
        !           658:        else
        !           659:                *p++ = '+';
        !           660:        t = expbuf + MAXEXP;
        !           661:        if (exp > 9) {
        !           662:                do {
        !           663:                        *--t = tochar(exp % 10);
        !           664:                } while ((exp /= 10) > 9);
        !           665:                *--t = tochar(exp);
        !           666:                for (; t < expbuf + MAXEXP; *p++ = *t++);
        !           667:        }
        !           668:        else {
        !           669:                *p++ = '0';
        !           670:                *p++ = tochar(exp);
        !           671:        }
        !           672:        return(p);
        !           673: }
        !           674: 
        !           675: #ifdef hp300
        !           676: isspecial(d, bufp, signp)
        !           677:        double d;
        !           678:        char *bufp, *signp;
        !           679: {
        !           680:        register struct IEEEdp {
        !           681:                unsigned sign:1;
        !           682:                unsigned exp:11;
        !           683:                unsigned manh:20;
        !           684:                unsigned manl:32;
        !           685:        } *ip = (struct IEEEdp *)&d;
        !           686: 
        !           687:        if (ip->exp != 0x7ff)
        !           688:                return(0);
        !           689:        if (ip->manh || ip->manl)
        !           690:                (void)strcpy(bufp, "NaN");
        !           691:        else
        !           692:                (void)strcpy(bufp, "Inf");
        !           693:        return(3);
        !           694: }
        !           695: #endif

unix.superglobalmegacorp.com

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