Annotation of GNUtools/libg++/libio/iovfprintf.c, revision 1.1.1.1

1.1       root        1: /* 
                      2: Copyright (C) 1993 Free Software Foundation
                      3: 
                      4: This file is part of the GNU IO Library.  This library is free
                      5: software; you can redistribute it and/or modify it under the
                      6: terms of the GNU General Public License as published by the
                      7: Free Software Foundation; either version 2, or (at your option)
                      8: any later version.
                      9: 
                     10: This library is distributed in the hope that it will be useful,
                     11: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     13: GNU General Public License for more details.
                     14: 
                     15: You should have received a copy of the GNU General Public License
                     16: along with GNU CC; see the file COPYING.  If not, write to
                     17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     18: 
                     19: As a special exception, if you link this library with files
                     20: compiled with a GNU compiler to produce an executable, this does not cause
                     21: the resulting executable to be covered by the GNU General Public License.
                     22: This exception does not however invalidate any other reasons why
                     23: the executable file might be covered by the GNU General Public License. */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1990 Regents of the University of California.
                     27:  * All rights reserved.
                     28:  *
                     29:  * Redistribution and use in source and binary forms are permitted
                     30:  * provided that the above copyright notice and this paragraph are
                     31:  * duplicated in all such forms and that any documentation,
                     32:  * advertising materials, and other materials related to such
                     33:  * distribution and use acknowledge that the software was developed
                     34:  * by the University of California, Berkeley.  The name of the
                     35:  * University may not be used to endorse or promote products derived
                     36:  * from this software without specific prior written permission.
                     37:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     38:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     39:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     40:  */
                     41: 
                     42: 
                     43: #if defined(LIBC_SCCS) && !defined(lint)
                     44: static char sccsid[] = "%W% (Berkeley) %G%";
                     45: #endif /* LIBC_SCCS and not lint */
                     46: 
                     47: /*
                     48:  * Actual printf innards.
                     49:  *
                     50:  * This code is large and complicated...
                     51:  */
                     52: 
                     53: #include <sys/types.h>
                     54: #include "libioP.h"
                     55: #include <string.h>
                     56: #ifdef __STDC__
                     57: #include <stdarg.h>
                     58: #else
                     59: #include <varargs.h>
                     60: #endif
                     61: 
                     62: /*
                     63:  * Define FLOATING_POINT to get floating point.
                     64:  */
                     65: #ifndef        NO_FLOATING_POINT
                     66: #define        FLOATING_POINT
                     67: #endif
                     68: 
                     69: /* end of configuration stuff */
                     70: 
                     71: 
                     72: /*
                     73:  * Helper "class" for `fprintf to unbuffered': creates a
                     74:  * temporary buffer. */
                     75: 
                     76: struct helper_file
                     77: {
                     78:   struct _IO_FILE_plus _f;
                     79:   _IO_FILE *_put_stream;
                     80: };
                     81: 
                     82: static int
                     83: _IO_helper_overflow (fp, c)
                     84:      _IO_FILE *fp;
                     85:      int c;
                     86: {
                     87:   _IO_FILE *target = ((struct helper_file*)fp)->_put_stream;
                     88:   int used = fp->_IO_write_ptr - fp->_IO_write_base;
                     89:   if (used)
                     90:     {
                     91:       _IO_sputn(target, fp->_IO_write_base, used);
                     92:       fp->_IO_write_ptr -= used;
                     93:     }
                     94:   return _IO_putc (c, fp);
                     95: }
                     96: 
                     97: static struct _IO_jump_t _IO_helper_jumps = {
                     98:   _IO_helper_overflow,
                     99:   _IO_default_underflow,
                    100:   _IO_default_xsputn,
                    101:   _IO_default_xsgetn,
                    102:   _IO_default_read,
                    103:   _IO_default_write,
                    104:   _IO_default_doallocate,
                    105:   _IO_default_pbackfail,
                    106:   _IO_default_setbuf,
                    107:   _IO_default_sync,
                    108:   _IO_default_finish,
                    109:   _IO_default_close,
                    110:   _IO_default_stat,
                    111:   _IO_default_seek,
                    112:   _IO_default_seekoff,
                    113:   _IO_default_seekpos,
                    114: };
                    115: 
                    116: static int
                    117: helper_vfprintf(fp, fmt0, ap)
                    118:      register _IO_FILE* fp;
                    119:      char const *fmt0;
                    120:      _IO_va_list ap;
                    121: {
                    122:   char buf[_IO_BUFSIZ];
                    123:   struct helper_file helper;
                    124:   register _IO_FILE *hp = (_IO_FILE*)&helper;
                    125:   int result, to_flush;
                    126: 
                    127:   /* initialize helper */
                    128:   helper._put_stream = fp;
                    129:   hp->_IO_write_base = buf;
                    130:   hp->_IO_write_ptr = buf;
                    131:   hp->_IO_write_end = buf+_IO_BUFSIZ;
                    132:   hp->_jumps = &_IO_helper_jumps;
                    133:   
                    134:   /* Now print to helper instead. */
                    135:   result = _IO_vfprintf(hp, fmt0, ap);
                    136: 
                    137:   /* Now flush anything from the helper to the fp. */
                    138:   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
                    139:     {
                    140:       if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush)
                    141:        return EOF;
                    142:     }
                    143:   return result;
                    144: }
                    145: 
                    146: #ifdef FLOATING_POINT
                    147: 
                    148: #include "floatio.h"
                    149: #define        BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
                    150: #define        DEFPREC         6
                    151: extern double modf _PARAMS((double, double*));
                    152: 
                    153: #else /* no FLOATING_POINT */
                    154: 
                    155: #define        BUF             40
                    156: 
                    157: #endif /* FLOATING_POINT */
                    158: 
                    159: 
                    160: /*
                    161:  * Macros for converting digits to letters and vice versa
                    162:  */
                    163: #define        to_digit(c)     ((c) - '0')
                    164: #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
                    165: #define        to_char(n)      ((n) + '0')
                    166: 
                    167: /*
                    168:  * Flags used during conversion.
                    169:  */
                    170: #define        LONGINT         0x01            /* long integer */
                    171: #define        LONGDBL         0x02            /* long double; unimplemented */
                    172: #define        SHORTINT        0x04            /* short integer */
                    173: #define        ALT             0x08            /* alternate form */
                    174: #define        LADJUST         0x10            /* left adjustment */
                    175: #define        ZEROPAD         0x20            /* zero (as opposed to blank) pad */
                    176: #define        HEXPREFIX       0x40            /* add 0x or 0X prefix */
                    177: 
                    178: int
                    179: _IO_vfprintf(fp, fmt0, ap)
                    180:      register _IO_FILE* fp;
                    181:      char const *fmt0;
                    182:      _IO_va_list ap;
                    183: {
                    184:        register const char *fmt; /* format string */
                    185:        register int ch;        /* character from fmt */
                    186:        register int n;         /* handy integer (short term usage) */
                    187:        register char *cp;      /* handy char pointer (short term usage) */
                    188:        const char *fmark;      /* for remembering a place in fmt */
                    189:        register int flags;     /* flags as above */
                    190:        int ret;                /* return value accumulator */
                    191:        int width;              /* width from format (%8d), or 0 */
                    192:        int prec;               /* precision from format (%.3d), or -1 */
                    193:        char sign;              /* sign prefix (' ', '+', '-', or \0) */
                    194: #ifdef FLOATING_POINT
                    195:        int softsign;           /* temporary negative sign for floats */
                    196:        double _double;         /* double precision arguments %[eEfgG] */
                    197: #ifndef USE_DTOA
                    198:        int fpprec;             /* `extra' floating precision in [eEfgG] */
                    199: #endif
                    200: #endif
                    201:        unsigned long _ulong;   /* integer arguments %[diouxX] */
                    202:        enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
                    203:        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
                    204:        int dpad;               /* extra 0 padding needed for integers */
                    205:        int fieldsz;            /* field size expanded by sign, dpad etc */
                    206:        /* The initialization of 'size' is to suppress a warning that
                    207:           'size' might be used unitialized.  It seems gcc can't
                    208:           quite grok this spaghetti code ... */
                    209:        int size = 0;           /* size of converted field or string */
                    210:        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
                    211:        char ox[2];             /* space for 0x hex-prefix */
                    212: 
                    213:        /*
                    214:         * BEWARE, these `goto error' on error, and PAD uses `n'.
                    215:         */
                    216: #define        PRINT(ptr, len) \
                    217:   do { if (_IO_sputn(fp,ptr, len) != len) goto error; } while (0)
                    218: #define PAD_SP(howmany) if (_IO_padn(fp, ' ', howmany) < (howmany)) goto error;
                    219: #define PAD_0(howmany) if (_IO_padn(fp, '0', howmany) < (howmany)) goto error;
                    220: 
                    221:        /*
                    222:         * To extend shorts properly, we need both signed and unsigned
                    223:         * argument extraction methods.
                    224:         */
                    225: #define        SARG() \
                    226:        (flags&LONGINT ? va_arg(ap, long) : \
                    227:            flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
                    228:            (long)va_arg(ap, int))
                    229: #define        UARG() \
                    230:        (flags&LONGINT ? va_arg(ap, unsigned long) : \
                    231:            flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
                    232:            (unsigned long)va_arg(ap, unsigned int))
                    233: 
                    234:        /* optimise stderr (and other unbuffered Unix files) */
                    235:        if (fp->_IO_file_flags & _IO_UNBUFFERED)
                    236:            return helper_vfprintf(fp, fmt0, ap);
                    237: 
                    238:        fmt = fmt0;
                    239:        ret = 0;
                    240: 
                    241:        /*
                    242:         * Scan the format for conversions (`%' character).
                    243:         */
                    244:        for (;;) {
                    245:                for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
                    246:                        /* void */;
                    247:                if ((n = fmt - fmark) != 0) {
                    248:                        PRINT(fmark, n);
                    249:                        ret += n;
                    250:                }
                    251:                if (ch == '\0')
                    252:                        goto done;
                    253:                fmt++;          /* skip over '%' */
                    254: 
                    255:                flags = 0;
                    256:                dprec = 0;
                    257: #if defined(FLOATING_POINT) && !defined (USE_DTOA)
                    258:                fpprec = 0;
                    259: #endif
                    260:                width = 0;
                    261:                prec = -1;
                    262:                sign = '\0';
                    263: 
                    264: rflag:         ch = *fmt++;
                    265: reswitch:      switch (ch) {
                    266:                case ' ':
                    267:                        /*
                    268:                         * ``If the space and + flags both appear, the space
                    269:                         * flag will be ignored.''
                    270:                         *      -- ANSI X3J11
                    271:                         */
                    272:                        if (!sign)
                    273:                                sign = ' ';
                    274:                        goto rflag;
                    275:                case '#':
                    276:                        flags |= ALT;
                    277:                        goto rflag;
                    278:                case '*':
                    279:                        /*
                    280:                         * ``A negative field width argument is taken as a
                    281:                         * - flag followed by a positive field width.''
                    282:                         *      -- ANSI X3J11
                    283:                         * They don't exclude field widths read from args.
                    284:                         */
                    285:                        if ((width = va_arg(ap, int)) >= 0)
                    286:                                goto rflag;
                    287:                        width = -width;
                    288:                        /* FALLTHROUGH */
                    289:                case '-':
                    290:                        flags |= LADJUST;
                    291:                        flags &= ~ZEROPAD; /* '-' disables '0' */
                    292:                        goto rflag;
                    293:                case '+':
                    294:                        sign = '+';
                    295:                        goto rflag;
                    296:                case '.':
                    297:                        if ((ch = *fmt++) == '*') {
                    298:                                n = va_arg(ap, int);
                    299:                                prec = n < 0 ? -1 : n;
                    300:                                goto rflag;
                    301:                        }
                    302:                        n = 0;
                    303:                        while (is_digit(ch)) {
                    304:                                n = 10 * n + to_digit(ch);
                    305:                                ch = *fmt++;
                    306:                        }
                    307:                        prec = n < 0 ? -1 : n;
                    308:                        goto reswitch;
                    309:                case '0':
                    310:                        /*
                    311:                         * ``Note that 0 is taken as a flag, not as the
                    312:                         * beginning of a field width.''
                    313:                         *      -- ANSI X3J11
                    314:                         */
                    315:                        if (!(flags & LADJUST))
                    316:                            flags |= ZEROPAD; /* '-' disables '0' */
                    317:                        goto rflag;
                    318:                case '1': case '2': case '3': case '4':
                    319:                case '5': case '6': case '7': case '8': case '9':
                    320:                        n = 0;
                    321:                        do {
                    322:                                n = 10 * n + to_digit(ch);
                    323:                                ch = *fmt++;
                    324:                        } while (is_digit(ch));
                    325:                        width = n;
                    326:                        goto reswitch;
                    327: #ifdef FLOATING_POINT
                    328:                case 'L':
                    329:                        flags |= LONGDBL;
                    330:                        goto rflag;
                    331: #endif
                    332:                case 'h':
                    333:                        flags |= SHORTINT;
                    334:                        goto rflag;
                    335:                case 'l':
                    336:                        flags |= LONGINT;
                    337:                        goto rflag;
                    338:                case 'c':
                    339:                        *(cp = buf) = va_arg(ap, int);
                    340:                        size = 1;
                    341:                        sign = '\0';
                    342:                        break;
                    343:                case 'D':
                    344:                        flags |= LONGINT;
                    345:                        /*FALLTHROUGH*/
                    346:                case 'd':
                    347:                case 'i':
                    348:                        _ulong = SARG();
                    349:                        if ((long)_ulong < 0) {
                    350:                                _ulong = -_ulong;
                    351:                                sign = '-';
                    352:                        }
                    353:                        base = DEC;
                    354:                        goto number;
                    355: #ifdef FLOATING_POINT
                    356:                case 'e':
                    357:                case 'E':
                    358:                case 'f':
                    359:                case 'F':
                    360:                case 'g':
                    361:                case 'G':
                    362:                        _double = va_arg(ap, double);
                    363: #ifdef USE_DTOA
                    364:                        {
                    365:                            int fmt_flags = 0;
                    366:                            int fill = ' ';
                    367:                            if (flags & ALT)
                    368:                                fmt_flags |= _IO_SHOWPOINT;
                    369:                            if (flags & LADJUST)
                    370:                                fmt_flags |= _IO_LEFT;
                    371:                            else if (flags & ZEROPAD)
                    372:                                fmt_flags |= _IO_INTERNAL, fill = '0';
                    373:                            n = _IO_outfloat(_double, fp, ch, width,
                    374:                                             prec < 0 ? DEFPREC : prec,
                    375:                                             fmt_flags, sign, fill);
                    376:                            if (n < 0)
                    377:                                goto error;
                    378:                            ret += n;
                    379:                        }
                    380:                        /* CHECK ERROR! */
                    381:                        continue;
                    382: #else
                    383:                        /*
                    384:                         * don't do unrealistic precision; just pad it with
                    385:                         * zeroes later, so buffer size stays rational.
                    386:                         */
                    387:                        if (prec > MAXFRACT) {
                    388:                                if ((ch != 'g' && ch != 'G') || (flags&ALT))
                    389:                                        fpprec = prec - MAXFRACT;
                    390:                                prec = MAXFRACT;
                    391:                        } else if (prec == -1)
                    392:                                prec = DEFPREC;
                    393:                        /* __cvt_double may have to round up before the
                    394:                           "start" of its buffer, i.e.
                    395:                           ``intf("%.2f", (double)9.999);'';
                    396:                           if the first character is still NUL, it did.
                    397:                           softsign avoids negative 0 if _double < 0 but
                    398:                           no significant digits will be shown. */
                    399:                        cp = buf;
                    400:                        *cp = '\0';
                    401:                        size = __cvt_double(_double, prec, flags, &softsign,
                    402:                                            ch, cp, buf + sizeof(buf));
                    403:                        if (softsign)
                    404:                                sign = '-';
                    405:                        if (*cp == '\0')
                    406:                                cp++;
                    407:                        break;
                    408: #endif
                    409: #endif /* FLOATING_POINT */
                    410:                case 'n':
                    411:                        if (flags & LONGINT)
                    412:                                *va_arg(ap, long *) = ret;
                    413:                        else if (flags & SHORTINT)
                    414:                                *va_arg(ap, short *) = ret;
                    415:                        else
                    416:                                *va_arg(ap, int *) = ret;
                    417:                        continue;       /* no output */
                    418:                case 'O':
                    419:                        flags |= LONGINT;
                    420:                        /*FALLTHROUGH*/
                    421:                case 'o':
                    422:                        _ulong = UARG();
                    423:                        base = OCT;
                    424:                        goto nosign;
                    425:                case 'p':
                    426:                        /*
                    427:                         * ``The argument shall be a pointer to void.  The
                    428:                         * value of the pointer is converted to a sequence
                    429:                         * of printable characters, in an implementation-
                    430:                         * defined manner.''
                    431:                         *      -- ANSI X3J11
                    432:                         */
                    433:                        /* NOSTRICT */
                    434:                        _ulong = (unsigned long)va_arg(ap, void *);
                    435:                        base = HEX;
                    436:                        flags |= HEXPREFIX;
                    437:                        ch = 'x';
                    438:                        goto nosign;
                    439:                case 's':
                    440:                        if ((cp = va_arg(ap, char *)) == NULL)
                    441:                                cp = "(null)";
                    442:                        if (prec >= 0) {
                    443:                                /*
                    444:                                 * can't use strlen; can only look for the
                    445:                                 * NUL in the first `prec' characters, and
                    446:                                 * strlen() will go further.
                    447:                                 */
                    448:                                char *p = (char*)memchr(cp, 0, prec);
                    449: 
                    450:                                if (p != NULL) {
                    451:                                        size = p - cp;
                    452:                                        if (size > prec)
                    453:                                                size = prec;
                    454:                                } else
                    455:                                        size = prec;
                    456:                        } else
                    457:                                size = strlen(cp);
                    458:                        sign = '\0';
                    459:                        break;
                    460:                case 'U':
                    461:                        flags |= LONGINT;
                    462:                        /*FALLTHROUGH*/
                    463:                case 'u':
                    464:                        _ulong = UARG();
                    465:                        base = DEC;
                    466:                        goto nosign;
                    467:                case 'X':
                    468:                case 'x':
                    469:                        _ulong = UARG();
                    470:                        base = HEX;
                    471:                        /* leading 0x/X only if non-zero */
                    472:                        if (flags & ALT && _ulong != 0)
                    473:                                flags |= HEXPREFIX;
                    474: 
                    475:                        /* unsigned conversions */
                    476: nosign:                        sign = '\0';
                    477:                        /*
                    478:                         * ``... diouXx conversions ... if a precision is
                    479:                         * specified, the 0 flag will be ignored.''
                    480:                         *      -- ANSI X3J11
                    481:                         */
                    482: number:                        if ((dprec = prec) >= 0)
                    483:                                flags &= ~ZEROPAD;
                    484: 
                    485:                        /*
                    486:                         * ``The result of converting a zero value with an
                    487:                         * explicit precision of zero is no characters.''
                    488:                         *      -- ANSI X3J11
                    489:                         */
                    490:                        cp = buf + BUF;
                    491:                        if (_ulong != 0 || prec != 0) {
                    492:                                char *xdigs; /* digits for [xX] conversion */
                    493:                                /*
                    494:                                 * unsigned mod is hard, and unsigned mod
                    495:                                 * by a constant is easier than that by
                    496:                                 * a variable; hence this switch.
                    497:                                 */
                    498:                                switch (base) {
                    499:                                case OCT:
                    500:                                        do {
                    501:                                                *--cp = to_char(_ulong & 7);
                    502:                                                _ulong >>= 3;
                    503:                                        } while (_ulong);
                    504:                                        /* handle octal leading 0 */
                    505:                                        if (flags & ALT && *cp != '0')
                    506:                                                *--cp = '0';
                    507:                                        break;
                    508: 
                    509:                                case DEC:
                    510:                                        /* many numbers are 1 digit */
                    511:                                        while (_ulong >= 10) {
                    512:                                                *--cp = to_char(_ulong % 10);
                    513:                                                _ulong /= 10;
                    514:                                        }
                    515:                                        *--cp = to_char(_ulong);
                    516:                                        break;
                    517: 
                    518:                                case HEX:
                    519:                                        if (ch == 'X')
                    520:                                            xdigs = "0123456789ABCDEF";
                    521:                                        else /* ch == 'x' || ch == 'p' */
                    522:                                            xdigs = "0123456789abcdef";
                    523:                                        do {
                    524:                                                *--cp = xdigs[_ulong & 15];
                    525:                                                _ulong >>= 4;
                    526:                                        } while (_ulong);
                    527:                                        break;
                    528: 
                    529:                                default:
                    530:                                        cp = "bug in vform: bad base";
                    531:                                        goto skipsize;
                    532:                                }
                    533:                        }
                    534:                        size = buf + BUF - cp;
                    535:                skipsize:
                    536:                        break;
                    537:                default:        /* "%?" prints ?, unless ? is NUL */
                    538:                        if (ch == '\0')
                    539:                                goto done;
                    540:                        /* pretend it was %c with argument ch */
                    541:                        cp = buf;
                    542:                        *cp = ch;
                    543:                        size = 1;
                    544:                        sign = '\0';
                    545:                        break;
                    546:                }
                    547: 
                    548:                /*
                    549:                 * All reasonable formats wind up here.  At this point,
                    550:                 * `cp' points to a string which (if not flags&LADJUST)
                    551:                 * should be padded out to `width' places.  If
                    552:                 * flags&ZEROPAD, it should first be prefixed by any
                    553:                 * sign or other prefix; otherwise, it should be blank
                    554:                 * padded before the prefix is emitted.  After any
                    555:                 * left-hand padding and prefixing, emit zeroes
                    556:                 * required by a decimal [diouxX] precision, then print
                    557:                 * the string proper, then emit zeroes required by any
                    558:                 * leftover floating precision; finally, if LADJUST,
                    559:                 * pad with blanks.
                    560:                 */
                    561: 
                    562:                /*
                    563:                 * compute actual size, so we know how much to pad.
                    564:                 */
                    565: #if defined(FLOATING_POINT) && !defined (USE_DTOA)
                    566:                fieldsz = size + fpprec;
                    567: #else
                    568:                fieldsz = size;
                    569: #endif
                    570:                dpad = dprec - size;
                    571:                if (dpad < 0)
                    572:                    dpad = 0;
                    573: 
                    574:                if (sign)
                    575:                        fieldsz++;
                    576:                else if (flags & HEXPREFIX)
                    577:                        fieldsz += 2;
                    578:                fieldsz += dpad;
                    579: 
                    580:                /* right-adjusting blank padding */
                    581:                if ((flags & (LADJUST|ZEROPAD)) == 0)
                    582:                        PAD_SP(width - fieldsz);
                    583: 
                    584:                /* prefix */
                    585:                if (sign) {
                    586:                        PRINT(&sign, 1);
                    587:                } else if (flags & HEXPREFIX) {
                    588:                        ox[0] = '0';
                    589:                        ox[1] = ch;
                    590:                        PRINT(ox, 2);
                    591:                }
                    592: 
                    593:                /* right-adjusting zero padding */
                    594:                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
                    595:                        PAD_0(width - fieldsz);
                    596: 
                    597:                /* leading zeroes from decimal precision */
                    598:                PAD_0(dpad);
                    599: 
                    600:                /* the string or number proper */
                    601:                PRINT(cp, size);
                    602: 
                    603: #if defined(FLOATING_POINT) && !defined (USE_DTOA)
                    604:                /* trailing f.p. zeroes */
                    605:                PAD_0(fpprec);
                    606: #endif
                    607: 
                    608:                /* left-adjusting padding (always blank) */
                    609:                if (flags & LADJUST)
                    610:                        PAD_SP(width - fieldsz);
                    611: 
                    612:                /* finally, adjust ret */
                    613:                ret += width > fieldsz ? width : fieldsz;
                    614: 
                    615:        }
                    616: done:
                    617:        return ret;
                    618: error:
                    619:        return EOF;
                    620:        /* NOTREACHED */
                    621: }
                    622: 
                    623: #if defined(FLOATING_POINT) && !defined(USE_DTOA)
                    624: 
                    625: static char *exponent(register char *p, register int exp, int fmtch)
                    626: {
                    627:        register char *t;
                    628:        char expbuf[MAXEXP];
                    629: 
                    630:        *p++ = fmtch;
                    631:        if (exp < 0) {
                    632:                exp = -exp;
                    633:                *p++ = '-';
                    634:        }
                    635:        else
                    636:                *p++ = '+';
                    637:        t = expbuf + MAXEXP;
                    638:        if (exp > 9) {
                    639:                do {
                    640:                        *--t = to_char(exp % 10);
                    641:                } while ((exp /= 10) > 9);
                    642:                *--t = to_char(exp);
                    643:                for (; t < expbuf + MAXEXP; *p++ = *t++);
                    644:        }
                    645:        else {
                    646:                *p++ = '0';
                    647:                *p++ = to_char(exp);
                    648:        }
                    649:        return (p);
                    650: }
                    651: 
                    652: static char * round(double fract, int *exp,
                    653:                    register char *start, register char *end,
                    654:                    char ch, int *signp)
                    655: {
                    656:        double tmp;
                    657: 
                    658:        if (fract)
                    659:        (void)modf(fract * 10, &tmp);
                    660:        else
                    661:                tmp = to_digit(ch);
                    662:        if (tmp > 4)
                    663:                for (;; --end) {
                    664:                        if (*end == '.')
                    665:                                --end;
                    666:                        if (++*end <= '9')
                    667:                                break;
                    668:                        *end = '0';
                    669:                        if (end == start) {
                    670:                                if (exp) {      /* e/E; increment exponent */
                    671:                                        *end = '1';
                    672:                                        ++*exp;
                    673:                                }
                    674:                                else {          /* f; add extra digit */
                    675:                                *--end = '1';
                    676:                                --start;
                    677:                                }
                    678:                                break;
                    679:                        }
                    680:                }
                    681:        /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
                    682:        else if (*signp == '-')
                    683:                for (;; --end) {
                    684:                        if (*end == '.')
                    685:                                --end;
                    686:                        if (*end != '0')
                    687:                                break;
                    688:                        if (end == start)
                    689:                                *signp = 0;
                    690:                }
                    691:        return (start);
                    692: }
                    693: 
                    694: int __cvt_double(double number, register int prec, int flags, int *signp,
                    695:                 int fmtch, char *startp, char *endp)
                    696: {
                    697:        register char *p, *t;
                    698:        register double fract;
                    699:        int dotrim = 0, expcnt, gformat = 0;
                    700:        double integer, tmp;
                    701: 
                    702:        expcnt = 0;
                    703:        if (number < 0) {
                    704:                number = -number;
                    705:                *signp = '-';
                    706:        } else
                    707:                *signp = 0;
                    708: 
                    709:        fract = modf(number, &integer);
                    710: 
                    711:        /* get an extra slot for rounding. */
                    712:        t = ++startp;
                    713: 
                    714:        /*
                    715:         * get integer portion of number; put into the end of the buffer; the
                    716:         * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
                    717:         */
                    718:        for (p = endp - 1; integer; ++expcnt) {
                    719:                tmp = modf(integer / 10, &integer);
                    720:                *p-- = to_char((int)((tmp + .01) * 10));
                    721:        }
                    722:        switch (fmtch) {
                    723:        case 'f':
                    724:        case 'F':
                    725:                /* reverse integer into beginning of buffer */
                    726:                if (expcnt)
                    727:                        for (; ++p < endp; *t++ = *p);
                    728:                else
                    729:                        *t++ = '0';
                    730:                /*
                    731:                 * if precision required or alternate flag set, add in a
                    732:                 * decimal point.
                    733:                 */
                    734:                if (prec || flags&ALT)
                    735:                        *t++ = '.';
                    736:                /* if requires more precision and some fraction left */
                    737:                if (fract) {
                    738:                        if (prec)
                    739:                                do {
                    740:                                        fract = modf(fract * 10, &tmp);
                    741:                                        *t++ = to_char((int)tmp);
                    742:                                } while (--prec && fract);
                    743:                        if (fract)
                    744:                                startp = round(fract, (int *)NULL, startp,
                    745:                                    t - 1, (char)0, signp);
                    746:                }
                    747:                for (; prec--; *t++ = '0');
                    748:                break;
                    749:        case 'e':
                    750:        case 'E':
                    751: eformat:       if (expcnt) {
                    752:                        *t++ = *++p;
                    753:                        if (prec || flags&ALT)
                    754:                                *t++ = '.';
                    755:                        /* if requires more precision and some integer left */
                    756:                        for (; prec && ++p < endp; --prec)
                    757:                                *t++ = *p;
                    758:                        /*
                    759:                         * if done precision and more of the integer component,
                    760:                         * round using it; adjust fract so we don't re-round
                    761:                         * later.
                    762:                         */
                    763:                        if (!prec && ++p < endp) {
                    764:                                fract = 0;
                    765:                                startp = round((double)0, &expcnt, startp,
                    766:                                    t - 1, *p, signp);
                    767:                        }
                    768:                        /* adjust expcnt for digit in front of decimal */
                    769:                        --expcnt;
                    770:                }
                    771:                /* until first fractional digit, decrement exponent */
                    772:                else if (fract) {
                    773:                        /* adjust expcnt for digit in front of decimal */
                    774:                        for (expcnt = -1;; --expcnt) {
                    775:                                fract = modf(fract * 10, &tmp);
                    776:                                if (tmp)
                    777:                                        break;
                    778:                        }
                    779:                        *t++ = to_char((int)tmp);
                    780:                        if (prec || flags&ALT)
                    781:                                *t++ = '.';
                    782:                }
                    783:                else {
                    784:                        *t++ = '0';
                    785:                        if (prec || flags&ALT)
                    786:                                *t++ = '.';
                    787:                }
                    788:                /* if requires more precision and some fraction left */
                    789:                if (fract) {
                    790:                        if (prec)
                    791:                                do {
                    792:                                        fract = modf(fract * 10, &tmp);
                    793:                                        *t++ = to_char((int)tmp);
                    794:                                } while (--prec && fract);
                    795:                        if (fract)
                    796:                                startp = round(fract, &expcnt, startp,
                    797:                                    t - 1, (char)0, signp);
                    798:                }
                    799:                /* if requires more precision */
                    800:                for (; prec--; *t++ = '0');
                    801: 
                    802:                /* unless alternate flag, trim any g/G format trailing 0's */
                    803:                if (gformat && !(flags&ALT)) {
                    804:                        while (t > startp && *--t == '0');
                    805:                        if (*t == '.')
                    806:                                --t;
                    807:                        ++t;
                    808:                }
                    809:                t = exponent(t, expcnt, fmtch);
                    810:                break;
                    811:        case 'g':
                    812:        case 'G':
                    813:                /* a precision of 0 is treated as a precision of 1. */
                    814:                if (!prec)
                    815:                        ++prec;
                    816:                /*
                    817:                 * ``The style used depends on the value converted; style e
                    818:                 * will be used only if the exponent resulting from the
                    819:                 * conversion is less than -4 or greater than the precision.''
                    820:                 *      -- ANSI X3J11
                    821:                 */
                    822:                if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
                    823:                        /*
                    824:                         * g/G format counts "significant digits, not digits of
                    825:                         * precision; for the e/E format, this just causes an
                    826:                         * off-by-one problem, i.e. g/G considers the digit
                    827:                         * before the decimal point significant and e/E doesn't
                    828:                         * count it as precision.
                    829:                         */
                    830:                        --prec;
                    831:                        fmtch -= 2;             /* G->E, g->e */
                    832:                        gformat = 1;
                    833:                        goto eformat;
                    834:                }
                    835:                /*
                    836:                 * reverse integer into beginning of buffer,
                    837:                 * note, decrement precision
                    838:                 */
                    839:                if (expcnt)
                    840:                        for (; ++p < endp; *t++ = *p, --prec);
                    841:                else
                    842:                        *t++ = '0';
                    843:                /*
                    844:                 * if precision required or alternate flag set, add in a
                    845:                 * decimal point.  If no digits yet, add in leading 0.
                    846:                 */
                    847:                if (prec || flags&ALT) {
                    848:                        dotrim = 1;
                    849:                        *t++ = '.';
                    850:                }
                    851:                else
                    852:                        dotrim = 0;
                    853:                /* if requires more precision and some fraction left */
                    854:                if (fract) {
                    855:                        if (prec) {
                    856:                                /* If no integer part, don't count initial
                    857:                                 * zeros as significant digits. */
                    858:                                do {
                    859:                                        fract = modf(fract * 10, &tmp);
                    860:                                        *t++ = to_char((int)tmp);
                    861:                                } while(!tmp && !expcnt);
                    862:                                while (--prec && fract) {
                    863:                                        fract = modf(fract * 10, &tmp);
                    864:                                        *t++ = to_char((int)tmp);
                    865:                                }
                    866:                        }
                    867:                        if (fract)
                    868:                                startp = round(fract, (int *)NULL, startp,
                    869:                                    t - 1, (char)0, signp);
                    870:                }
                    871:                /* alternate format, adds 0's for precision, else trim 0's */
                    872:                if (flags&ALT)
                    873:                        for (; prec--; *t++ = '0');
                    874:                else if (dotrim) {
                    875:                        while (t > startp && *--t == '0');
                    876:                        if (*t != '.')
                    877:                                ++t;
                    878:                }
                    879:        }
                    880:        return (t - startp);
                    881: }
                    882: 
                    883: #endif /* defined(FLOATING_POINT) && !defined(USE_DTOA) */

unix.superglobalmegacorp.com

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