[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     ! 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