[BACK]Return to vfprintf.c CVS log [TXT][DIR] Up to [local] / prex-old / usr / lib / libc / stdio

Annotation of prex-old/usr/lib/libc/stdio/vfprintf.c, Revision 1.1.1.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 1990, 1993
                      3:  *     The Regents of the University of California.  All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Chris Torek.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the University nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Actual printf innards.
                     35:  *
                     36:  * This code is large and complicated...
                     37:  */
                     38:
                     39: #include <sys/types.h>
                     40:
                     41: #include <limits.h>
                     42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <string.h>
                     45: #include <stdarg.h>
                     46:
                     47: #include "local.h"
                     48: #include "fvwrite.h"
                     49:
                     50: /*
                     51:  * Flush out all the vectors defined by the given uio,
                     52:  * then reset it so that it can be reused.
                     53:  */
                     54: static int
                     55: __sprint(FILE *fp, struct __suio *uio)
                     56: {
                     57:        int err;
                     58:
                     59:        if (uio->uio_resid == 0) {
                     60:                uio->uio_iovcnt = 0;
                     61:                return (0);
                     62:        }
                     63:        err = __sfvwrite(fp, uio);
                     64:        uio->uio_resid = 0;
                     65:        uio->uio_iovcnt = 0;
                     66:        return (err);
                     67: }
                     68:
                     69: /*
                     70:  * Helper function for `fprintf to unbuffered unix file': creates a
                     71:  * temporary buffer.  We only work on write-only files; this avoids
                     72:  * worries about ungetc buffers and so forth.
                     73:  */
                     74: static int
                     75: __sbprintf(FILE *fp, const char *fmt, va_list ap)
                     76: {
                     77:        int ret;
                     78:        FILE fake;
                     79:        unsigned char buf[BUFSIZ];
                     80:
                     81:        /* copy the important variables */
                     82:        fake._flags = fp->_flags & ~__SNBF;
                     83:        fake._file = fp->_file;
                     84:
                     85:        /* set up the buffer */
                     86:        fake._bf._base = fake._p = buf;
                     87:        fake._bf._size = fake._w = sizeof(buf);
                     88:
                     89:        /* do the work, then copy any error status */
                     90:        ret = vfprintf(&fake, fmt, ap);
                     91:        if (ret >= 0 && fflush(&fake))
                     92:                ret = EOF;
                     93:        if (fake._flags & __SERR)
                     94:                fp->_flags |= __SERR;
                     95:        return (ret);
                     96: }
                     97:
                     98: /*
                     99:  * Macros for converting digits to letters and vice versa
                    100:  */
                    101: #define        to_digit(c)     ((c) - '0')
                    102: #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
                    103: #define        to_char(n)      ((n) + '0')
                    104:
                    105: /*
                    106:  * Convert an unsigned long to ASCII for printf purposes, returning
                    107:  * a pointer to the first character of the string representation.
                    108:  * Octal numbers can be forced to have a leading zero; hex numbers
                    109:  * use the given digits.
                    110:  */
                    111: static char *
                    112: __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
                    113: {
                    114:        char *cp = endp;
                    115:        long sval;
                    116:
                    117:        /*
                    118:         * Handle the three cases separately, in the hope of getting
                    119:         * better/faster code.
                    120:         */
                    121:        switch (base) {
                    122:        case 10:
                    123:                if (val < 10) { /* many numbers are 1 digit */
                    124:                        *--cp = to_char(val);
                    125:                        return (cp);
                    126:                }
                    127:                /*
                    128:                 * On many machines, unsigned arithmetic is harder than
                    129:                 * signed arithmetic, so we do at most one unsigned mod and
                    130:                 * divide; this is sufficient to reduce the range of
                    131:                 * the incoming value to where signed arithmetic works.
                    132:                 */
                    133:                if (val > LONG_MAX) {
                    134:                        *--cp = to_char(val % 10);
                    135:                        sval = val / 10;
                    136:                } else
                    137:                        sval = val;
                    138:                do {
                    139:                        *--cp = to_char(sval % 10);
                    140:                        sval /= 10;
                    141:                } while (sval != 0);
                    142:                break;
                    143:
                    144:        case 8:
                    145:                do {
                    146:                        *--cp = to_char(val & 7);
                    147:                        val >>= 3;
                    148:                } while (val);
                    149:                if (octzero && *cp != '0')
                    150:                        *--cp = '0';
                    151:                break;
                    152:
                    153:        case 16:
                    154:                do {
                    155:                        *--cp = xdigs[val & 15];
                    156:                        val >>= 4;
                    157:                } while (val);
                    158:                break;
                    159:
                    160:        default:                        /* oops */
                    161:                abort();
                    162:        }
                    163:        return (cp);
                    164: }
                    165:
                    166:
                    167: #define        BUF             32
                    168:
                    169:
                    170: /*
                    171:  * Flags used during conversion.
                    172:  */
                    173: #define        ALT             0x001           /* alternate form */
                    174: #define        HEXPREFIX       0x002           /* add 0x or 0X prefix */
                    175: #define        LADJUST         0x004           /* left adjustment */
                    176: #define        LONGDBL         0x008           /* long double; unimplemented */
                    177: #define        LONGINT         0x010           /* long integer */
                    178: #define        SHORTINT        0x040           /* short integer */
                    179: #define        ZEROPAD         0x080           /* zero (as opposed to blank) pad */
                    180: int
                    181: vfprintf(fp, fmt0, ap)
                    182:        FILE *fp;
                    183:        const char *fmt0;
                    184:        va_list ap;
                    185: {
                    186:        char *fmt;              /* format string */
                    187:        int ch;                 /* character from fmt */
                    188:        int n;                  /* handy integer (short term usage) */
                    189:        char *cp;               /* handy char pointer (short term usage) */
                    190:        struct __siov *iovp;    /* for PRINT macro */
                    191:        int flags;              /* flags as above */
                    192:        int ret;                /* return value accumulator */
                    193:        int width;              /* width from format (%8d), or 0 */
                    194:        int prec;               /* precision from format (%.3d), or -1 */
                    195:        char sign;              /* sign prefix (' ', '+', '-', or \0) */
                    196:        u_long  ulval;          /* integer arguments %[diouxX] */
                    197:        int base;               /* base for [diouxX] conversion */
                    198:        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
                    199:        int fieldsz;            /* field size expanded by sign, etc */
                    200:        int realsz;             /* field size expanded by dprec */
                    201:        int size;               /* size of converted field or string */
                    202:        char *xdigs = NULL;     /* digits for [xX] conversion */
                    203: #define NIOV 8
                    204:        struct __suio uio;      /* output information: summary */
                    205:        struct __siov iov[NIOV];/* ... and individual io vectors */
                    206:        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
                    207:        char ox[2];             /* space for 0x hex-prefix */
                    208:
                    209:        /*
                    210:         * Choose PADSIZE to trade efficiency vs. size.  If larger printf
                    211:         * fields occur frequently, increase PADSIZE and make the initialisers
                    212:         * below longer.
                    213:         */
                    214: #define        PADSIZE 16              /* pad chunk size */
                    215:        static char blanks[PADSIZE] =
                    216:         {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
                    217:        static char zeroes[PADSIZE] =
                    218:         {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
                    219:
                    220:        /*
                    221:         * BEWARE, these `goto error' on error, and PAD uses `n'.
                    222:         */
                    223: #define        PRINT(ptr, len) { \
                    224:        iovp->iov_base = (ptr); \
                    225:        iovp->iov_len = (len); \
                    226:        uio.uio_resid += (len); \
                    227:        iovp++; \
                    228:        if (++uio.uio_iovcnt >= NIOV) { \
                    229:                if (__sprint(fp, &uio)) \
                    230:                        goto error; \
                    231:                iovp = iov; \
                    232:        } \
                    233: }
                    234: #define        PAD(howmany, with) { \
                    235:        if ((n = (howmany)) > 0) { \
                    236:                while (n > PADSIZE) { \
                    237:                        PRINT(with, PADSIZE); \
                    238:                        n -= PADSIZE; \
                    239:                } \
                    240:                PRINT(with, n); \
                    241:        } \
                    242: }
                    243: #define        FLUSH() { \
                    244:        if (uio.uio_resid && __sprint(fp, &uio)) \
                    245:                goto error; \
                    246:        uio.uio_iovcnt = 0; \
                    247:        iovp = iov; \
                    248: }
                    249:
                    250:        /*
                    251:         * To extend shorts properly, we need both signed and unsigned
                    252:         * argument extraction methods.
                    253:         */
                    254: #define        SARG() \
                    255:        (flags&LONGINT ? va_arg(ap, long) : \
                    256:            flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
                    257:            (long)va_arg(ap, int))
                    258: #define        UARG() \
                    259:        (flags&LONGINT ? va_arg(ap, u_long) : \
                    260:            flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
                    261:            (u_long)va_arg(ap, u_int))
                    262:
                    263:        /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
                    264:        if (cantwrite(fp))
                    265:                return (EOF);
                    266:
                    267:        /* optimise fprintf(stderr) (and other unbuffered Unix files) */
                    268:        if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
                    269:            fp->_file >= 0)
                    270:                return (__sbprintf(fp, fmt0, ap));
                    271:
                    272:        fmt = (char *)fmt0;
                    273:        uio.uio_iov = iovp = iov;
                    274:        uio.uio_resid = 0;
                    275:        uio.uio_iovcnt = 0;
                    276:        ret = 0;
                    277:
                    278:        /*
                    279:         * Scan the format for conversions (`%' character).
                    280:         */
                    281:        for (;;) {
                    282:                for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
                    283:                        /* void */;
                    284:                if ((n = fmt - cp) != 0) {
                    285:                        PRINT(cp, n);
                    286:                        ret += n;
                    287:                }
                    288:                if (ch == '\0')
                    289:                        goto done;
                    290:                fmt++;          /* skip over '%' */
                    291:
                    292:                flags = 0;
                    293:                dprec = 0;
                    294:                width = 0;
                    295:                prec = -1;
                    296:                sign = '\0';
                    297:
                    298: rflag:         ch = *fmt++;
                    299: reswitch:      switch (ch) {
                    300:                case ' ':
                    301:                        /*
                    302:                         * ``If the space and + flags both appear, the space
                    303:                         * flag will be ignored.''
                    304:                         *      -- ANSI X3J11
                    305:                         */
                    306:                        if (!sign)
                    307:                                sign = ' ';
                    308:                        goto rflag;
                    309:                case '#':
                    310:                        flags |= ALT;
                    311:                        goto rflag;
                    312:                case '*':
                    313:                        /*
                    314:                         * ``A negative field width argument is taken as a
                    315:                         * - flag followed by a positive field width.''
                    316:                         *      -- ANSI X3J11
                    317:                         * They don't exclude field widths read from args.
                    318:                         */
                    319:                        if ((width = va_arg(ap, int)) >= 0)
                    320:                                goto rflag;
                    321:                        width = -width;
                    322:                        /* FALLTHROUGH */
                    323:                case '-':
                    324:                        flags |= LADJUST;
                    325:                        goto rflag;
                    326:                case '+':
                    327:                        sign = '+';
                    328:                        goto rflag;
                    329:                case '.':
                    330:                        if ((ch = *fmt++) == '*') {
                    331:                                n = va_arg(ap, int);
                    332:                                prec = n < 0 ? -1 : n;
                    333:                                goto rflag;
                    334:                        }
                    335:                        n = 0;
                    336:                        while (is_digit(ch)) {
                    337:                                n = 10 * n + to_digit(ch);
                    338:                                ch = *fmt++;
                    339:                        }
                    340:                        prec = n < 0 ? -1 : n;
                    341:                        goto reswitch;
                    342:                case '0':
                    343:                        /*
                    344:                         * ``Note that 0 is taken as a flag, not as the
                    345:                         * beginning of a field width.''
                    346:                         *      -- ANSI X3J11
                    347:                         */
                    348:                        flags |= ZEROPAD;
                    349:                        goto rflag;
                    350:                case '1': case '2': case '3': case '4':
                    351:                case '5': case '6': case '7': case '8': case '9':
                    352:                        n = 0;
                    353:                        do {
                    354:                                n = 10 * n + to_digit(ch);
                    355:                                ch = *fmt++;
                    356:                        } while (is_digit(ch));
                    357:                        width = n;
                    358:                        goto reswitch;
                    359:                case 'h':
                    360:                        flags |= SHORTINT;
                    361:                        goto rflag;
                    362:                case 'l':
                    363:                        flags |= LONGINT;
                    364:                        goto rflag;
                    365:                case 'c':
                    366:                        *(cp = buf) = va_arg(ap, int);
                    367:                        size = 1;
                    368:                        sign = '\0';
                    369:                        break;
                    370:                case 'D':
                    371:                        flags |= LONGINT;
                    372:                        /*FALLTHROUGH*/
                    373:                case 'd':
                    374:                case 'i':
                    375:                        ulval = SARG();
                    376:                        if ((long)ulval < 0) {
                    377:                                ulval = -ulval;
                    378:                                sign = '-';
                    379:                        }
                    380:                        base = 10;
                    381:                        goto number;
                    382:                case 'n':
                    383:                        if (flags & LONGINT)
                    384:                                *va_arg(ap, long *) = ret;
                    385:                        else if (flags & SHORTINT)
                    386:                                *va_arg(ap, short *) = ret;
                    387:                        else
                    388:                                *va_arg(ap, int *) = ret;
                    389:                        continue;       /* no output */
                    390:                case 'O':
                    391:                        flags |= LONGINT;
                    392:                        /*FALLTHROUGH*/
                    393:                case 'o':
                    394:                        ulval = UARG();
                    395:                        base = 8;
                    396:                        goto nosign;
                    397:                case 'p':
                    398:                        /*
                    399:                         * ``The argument shall be a pointer to void.  The
                    400:                         * value of the pointer is converted to a sequence
                    401:                         * of printable characters, in an implementation-
                    402:                         * defined manner.''
                    403:                         *      -- ANSI X3J11
                    404:                         */
                    405:                        ulval = (u_long)va_arg(ap, void *);
                    406:                        base = 16;
                    407:                        xdigs = "0123456789abcdef";
                    408:                        flags |= HEXPREFIX;
                    409:                        ch = 'x';
                    410:                        goto nosign;
                    411:                case 's':
                    412:                        if ((cp = va_arg(ap, char *)) == NULL)
                    413:                                cp = "(null)";
                    414:                        if (prec >= 0) {
                    415:                                /*
                    416:                                 * can't use strlen; can only look for the
                    417:                                 * NUL in the first `prec' characters, and
                    418:                                 * strlen() will go further.
                    419:                                 */
                    420:                                char *p = memchr(cp, 0, prec);
                    421:
                    422:                                if (p != NULL) {
                    423:                                        size = p - cp;
                    424:                                        if (size > prec)
                    425:                                                size = prec;
                    426:                                } else
                    427:                                        size = prec;
                    428:                        } else
                    429:                                size = strlen(cp);
                    430:                        sign = '\0';
                    431:                        break;
                    432:                case 'U':
                    433:                        flags |= LONGINT;
                    434:                        /*FALLTHROUGH*/
                    435:                case 'u':
                    436:                        ulval = UARG();
                    437:                        base = 10;
                    438:                        goto nosign;
                    439:                case 'X':
                    440:                        xdigs = "0123456789ABCDEF";
                    441:                        goto hex;
                    442:                case 'x':
                    443:                        xdigs = "0123456789abcdef";
                    444: hex:
                    445:                        ulval = UARG();
                    446:                        base = 16;
                    447:                        /* leading 0x/X only if non-zero */
                    448:                        if (flags & ALT && ulval != 0)
                    449:                                flags |= HEXPREFIX;
                    450:
                    451:                        /* unsigned conversions */
                    452: nosign:                        sign = '\0';
                    453:                        /*
                    454:                         * ``... diouXx conversions ... if a precision is
                    455:                         * specified, the 0 flag will be ignored.''
                    456:                         *      -- ANSI X3J11
                    457:                         */
                    458: number:                        if ((dprec = prec) >= 0)
                    459:                                flags &= ~ZEROPAD;
                    460:
                    461:                        /*
                    462:                         * ``The result of converting a zero value with an
                    463:                         * explicit precision of zero is no characters.''
                    464:                         *      -- ANSI X3J11
                    465:                         */
                    466:                        cp = buf + BUF;
                    467:                        if (ulval != 0 || prec != 0)
                    468:                                cp = __ultoa(ulval, cp, base,
                    469:                                             flags & ALT, xdigs);
                    470:                        size = buf + BUF - cp;
                    471:                        break;
                    472:                default:        /* "%?" prints ?, unless ? is NUL */
                    473:                        if (ch == '\0')
                    474:                                goto done;
                    475:                        /* pretend it was %c with argument ch */
                    476:                        cp = buf;
                    477:                        *cp = ch;
                    478:                        size = 1;
                    479:                        sign = '\0';
                    480:                        break;
                    481:                }
                    482:
                    483:                /*
                    484:                 * All reasonable formats wind up here.  At this point, `cp'
                    485:                 * points to a string which (if not flags&LADJUST) should be
                    486:                 * padded out to `width' places.  If flags&ZEROPAD, it should
                    487:                 * first be prefixed by any sign or other prefix; otherwise,
                    488:                 * it should be blank padded before the prefix is emitted.
                    489:                 * After any left-hand padding and prefixing, emit zeroes
                    490:                 * required by a decimal [diouxX] precision, then print the
                    491:                 * string proper, then emit zeroes required by any leftover
                    492:                 * floating precision; finally, if LADJUST, pad with blanks.
                    493:                 *
                    494:                 * Compute actual size, so we know how much to pad.
                    495:                 * fieldsz excludes decimal prec; realsz includes it.
                    496:                 */
                    497:                fieldsz = size;
                    498:                if (sign)
                    499:                        fieldsz++;
                    500:                else if (flags & HEXPREFIX)
                    501:                        fieldsz += 2;
                    502:                realsz = dprec > fieldsz ? dprec : fieldsz;
                    503:
                    504:                /* right-adjusting blank padding */
                    505:                if ((flags & (LADJUST|ZEROPAD)) == 0)
                    506:                        PAD(width - realsz, blanks);
                    507:
                    508:                /* prefix */
                    509:                if (sign) {
                    510:                        PRINT(&sign, 1);
                    511:                } else if (flags & HEXPREFIX) {
                    512:                        ox[0] = '0';
                    513:                        ox[1] = ch;
                    514:                        PRINT(ox, 2);
                    515:                }
                    516:
                    517:                /* right-adjusting zero padding */
                    518:                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
                    519:                        PAD(width - realsz, zeroes);
                    520:
                    521:                /* leading zeroes from decimal precision */
                    522:                PAD(dprec - fieldsz, zeroes);
                    523:
                    524:                /* the string or number proper */
                    525:                PRINT(cp, size);
                    526:
                    527:                /* left-adjusting padding (always blank) */
                    528:                if (flags & LADJUST)
                    529:                        PAD(width - realsz, blanks);
                    530:
                    531:                /* finally, adjust ret */
                    532:                ret += width > realsz ? width : realsz;
                    533:
                    534:                FLUSH();        /* copy out the I/O vectors */
                    535:        }
                    536: done:
                    537:        FLUSH();
                    538: error:
                    539:        return (__sferror(fp) ? EOF : ret);
                    540:        /* NOTREACHED */
                    541: }

CVSweb