Annotation of embedaddon/sudo/compat/snprintf.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1999-2005, 2008, 2010-2011
        !             3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
        !             4:  * Copyright (c) 1990, 1993
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to Berkeley by
        !             8:  * Chris Torek.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. Neither the name of the University nor the names of its contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            32:  * SUCH DAMAGE.
        !            33:  *
        !            34:  * From: @(#)vfprintf.c        8.1 (Berkeley) 6/4/93
        !            35:  */
        !            36: 
        !            37: /*
        !            38:  * v?snprintf/v?asprintf based on 4.4BSD stdio.
        !            39:  * NOTE: does not support floating point.
        !            40:  */
        !            41: 
        !            42: #include <config.h>
        !            43: 
        !            44: #include <sys/types.h>
        !            45: #include <sys/param.h>
        !            46: 
        !            47: #include <stdio.h>
        !            48: #ifdef STDC_HEADERS
        !            49: # include <stdlib.h>
        !            50: # include <stddef.h>
        !            51: #else
        !            52: # ifdef HAVE_STDLIB_H
        !            53: #  include <stdlib.h>
        !            54: # endif
        !            55: #endif /* STDC_HEADERS */
        !            56: #ifdef HAVE_STDINT_H
        !            57: # include <stdint.h>
        !            58: #endif
        !            59: #ifdef HAVE_STRING_H
        !            60: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
        !            61: #  include <memory.h>
        !            62: # endif
        !            63: # include <string.h>
        !            64: #endif /* HAVE_STRING_H */
        !            65: #ifdef HAVE_STRINGS_H
        !            66: # include <strings.h>
        !            67: #endif /* HAVE_STRINGS_H */
        !            68: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
        !            69: # include <malloc.h>
        !            70: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
        !            71: #include <limits.h>
        !            72: #include <stdarg.h>
        !            73: 
        !            74: #include "missing.h"
        !            75: 
        !            76: static int xxxprintf(char **, size_t, int, const char *, va_list);
        !            77: 
        !            78: /*
        !            79:  * Some systems may not have these defined in <limits.h>
        !            80:  */
        !            81: #ifndef ULONG_MAX
        !            82: # define ULONG_MAX     ((unsigned long)-1)
        !            83: #endif
        !            84: #ifndef LONG_MAX
        !            85: # define LONG_MAX      (ULONG_MAX / 2)
        !            86: #endif
        !            87: #ifdef HAVE_LONG_LONG_INT
        !            88: # ifndef ULLONG_MAX
        !            89: #  ifdef UQUAD_MAX
        !            90: #   define ULLONG_MAX  UQUAD_MAX
        !            91: #  else
        !            92: #   define ULLONG_MAX  ((unsigned long long)-1)
        !            93: #  endif
        !            94: # endif
        !            95: # ifndef LLONG_MAX
        !            96: #  ifdef QUAD_MAX
        !            97: #   define LLONG_MAX   QUAD_MAX
        !            98: #  else
        !            99: #   define LLONG_MAX   (ULLONG_MAX / 2)
        !           100: #  endif
        !           101: # endif
        !           102: #endif /* HAVE_LONG_LONG_INT */
        !           103: 
        !           104: /*
        !           105:  * Macros for converting digits to letters and vice versa
        !           106:  */
        !           107: #define        to_digit(c)     ((c) - '0')
        !           108: #define is_digit(c)    ((unsigned int)to_digit(c) <= 9)
        !           109: #define        to_char(n)      ((n) + '0')
        !           110: 
        !           111: /*
        !           112:  * Flags used during conversion.
        !           113:  */
        !           114: #define        ALT             0x001           /* alternate form */
        !           115: #define        HEXPREFIX       0x002           /* add 0x or 0X prefix */
        !           116: #define        LADJUST         0x004           /* left adjustment */
        !           117: #define        LONGDBL         0x008           /* long double; unimplemented */
        !           118: #define        LONGINT         0x010           /* long integer */
        !           119: #define        QUADINT         0x020           /* quad integer */
        !           120: #define        SHORTINT        0x040           /* short integer */
        !           121: #define        ZEROPAD         0x080           /* zero (as opposed to blank) pad */
        !           122: 
        !           123: #define BUF            68
        !           124: 
        !           125: /*
        !           126:  * Convert an unsigned long to ASCII for printf purposes, returning
        !           127:  * a pointer to the first character of the string representation.
        !           128:  * Octal numbers can be forced to have a leading zero; hex numbers
        !           129:  * use the given digits.
        !           130:  */
        !           131: static char *
        !           132: __ultoa(unsigned long val, char *endp, int base, int octzero, char *xdigs)
        !           133: {
        !           134:        char *cp = endp;
        !           135:        long sval;
        !           136: 
        !           137:        /*
        !           138:         * Handle the three cases separately, in the hope of getting
        !           139:         * better/faster code.
        !           140:         */
        !           141:        switch (base) {
        !           142:        case 10:
        !           143:                if (val < 10) { /* many numbers are 1 digit */
        !           144:                        *--cp = to_char(val);
        !           145:                        return cp;
        !           146:                }
        !           147:                /*
        !           148:                 * On many machines, unsigned arithmetic is harder than
        !           149:                 * signed arithmetic, so we do at most one unsigned mod and
        !           150:                 * divide; this is sufficient to reduce the range of
        !           151:                 * the incoming value to where signed arithmetic works.
        !           152:                 */
        !           153:                if (val > LONG_MAX) {
        !           154:                        *--cp = to_char(val % 10);
        !           155:                        sval = val / 10;
        !           156:                } else
        !           157:                        sval = val;
        !           158:                do {
        !           159:                        *--cp = to_char(sval % 10);
        !           160:                        sval /= 10;
        !           161:                } while (sval != 0);
        !           162:                break;
        !           163: 
        !           164:        case 8:
        !           165:                do {
        !           166:                        *--cp = to_char(val & 7);
        !           167:                        val >>= 3;
        !           168:                } while (val);
        !           169:                if (octzero && *cp != '0')
        !           170:                        *--cp = '0';
        !           171:                break;
        !           172: 
        !           173:        case 16:
        !           174:                do {
        !           175:                        *--cp = xdigs[val & 15];
        !           176:                        val >>= 4;
        !           177:                } while (val);
        !           178:                break;
        !           179: 
        !           180:        default:                        /* oops */
        !           181:                abort();
        !           182:        }
        !           183:        return cp;
        !           184: }
        !           185: 
        !           186: /* Identical to __ultoa, but for quads. */
        !           187: #ifdef HAVE_LONG_LONG_INT
        !           188: # if SIZEOF_LONG_INT == 8
        !           189: #  define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x))
        !           190: # else
        !           191: static char *
        !           192: __uqtoa(unsigned long long val, char *endp, int base, int octzero, char *xdigs)
        !           193: {
        !           194:        char *cp = endp;
        !           195:        long long sval;
        !           196: 
        !           197:        /* quick test for small values; __ultoa is typically much faster */
        !           198:        /* (perhaps instead we should run until small, then call __ultoa?) */
        !           199:        if (val <= (unsigned long long)ULONG_MAX)
        !           200:                return __ultoa((unsigned long)val, endp, base, octzero, xdigs);
        !           201:        switch (base) {
        !           202:        case 10:
        !           203:                if (val < 10) {
        !           204:                        *--cp = to_char(val % 10);
        !           205:                        return cp;
        !           206:                }
        !           207:                if (val > LLONG_MAX) {
        !           208:                        *--cp = to_char(val % 10);
        !           209:                        sval = val / 10;
        !           210:                } else
        !           211:                        sval = val;
        !           212:                do {
        !           213:                        *--cp = to_char(sval % 10);
        !           214:                        sval /= 10;
        !           215:                } while (sval != 0);
        !           216:                break;
        !           217: 
        !           218:        case 8:
        !           219:                do {
        !           220:                        *--cp = to_char(val & 7);
        !           221:                        val >>= 3;
        !           222:                } while (val);
        !           223:                if (octzero && *cp != '0')
        !           224:                        *--cp = '0';
        !           225:                break;
        !           226: 
        !           227:        case 16:
        !           228:                do {
        !           229:                        *--cp = xdigs[val & 15];
        !           230:                        val >>= 4;
        !           231:                } while (val);
        !           232:                break;
        !           233: 
        !           234:        default:                        /* oops */
        !           235:                abort();
        !           236:        }
        !           237:        return cp;
        !           238: }
        !           239: # endif /* !SIZEOF_LONG_INT */
        !           240: #endif /* HAVE_LONG_LONG_INT */
        !           241: 
        !           242: /*
        !           243:  * Actual printf innards.
        !           244:  */
        !           245: static int
        !           246: xxxprintf(char **strp, size_t strsize, int alloc, const char *fmt0, va_list ap)
        !           247: {
        !           248:        char *fmt;              /* format string */
        !           249:        int ch;                 /* character from fmt */
        !           250:        int n;                  /* handy integer (short term usage) */
        !           251:        char *cp;               /* handy char pointer (short term usage) */
        !           252:        int flags;              /* flags as above */
        !           253:        int ret;                /* return value accumulator */
        !           254:        int width;              /* width from format (%8d), or 0 */
        !           255:        int prec;               /* precision from format (%.3d), or -1 */
        !           256:        char sign;              /* sign prefix (' ', '+', '-', or \0) */
        !           257:        unsigned long ulval = 0; /* integer arguments %[diouxX] */
        !           258: #ifdef HAVE_LONG_LONG_INT
        !           259:        unsigned long long uqval = 0; /* %q (quad) integers */
        !           260: #endif
        !           261:        int base;               /* base for [diouxX] conversion */
        !           262:        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
        !           263:        int fieldsz;            /* field size expanded by sign, etc */
        !           264:        int realsz;             /* field size expanded by dprec */
        !           265:        int size;               /* size of converted field or string */
        !           266:        char *xdigs = "";       /* digits for [xX] conversion */
        !           267:        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
        !           268:        char ox[2];             /* space for 0x hex-prefix */
        !           269:        char *str;              /* pointer to string to fill */
        !           270:        char *estr;             /* pointer to last char in str */
        !           271: 
        !           272:        /*
        !           273:         * Choose PADSIZE to trade efficiency vs. size.  If larger printf
        !           274:         * fields occur frequently, increase PADSIZE and make the initialisers
        !           275:         * below longer.
        !           276:         */
        !           277: #define        PADSIZE 16              /* pad chunk size */
        !           278:        static char blanks[PADSIZE] =
        !           279:         {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
        !           280:        static char zeroes[PADSIZE] =
        !           281:         {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
        !           282: 
        !           283:        /* Print chars to "str", (allocate as needed if alloc is set). */
        !           284: #define        PRINT(ptr, len) do { \
        !           285:        const char *p = ptr; \
        !           286:        const char *endp = ptr + len; \
        !           287:        while (p < endp && (str < estr || alloc)) { \
        !           288:                if (alloc && str >= estr) { \
        !           289:                        char *t; \
        !           290:                        strsize = (strsize << 1) + 1; \
        !           291:                        if (!(t = (char *)realloc(*strp, strsize))) { \
        !           292:                                free(str); \
        !           293:                                *strp = NULL; \
        !           294:                                ret = -1; \
        !           295:                                goto done; \
        !           296:                        } \
        !           297:                        str = t + (str - *strp); \
        !           298:                        estr = t + strsize - 1; \
        !           299:                        *strp = t; \
        !           300:                } \
        !           301:                *str++ = *p++; \
        !           302:        } \
        !           303: } while (0)
        !           304: 
        !           305:        /* BEWARE, PAD uses `n'. */
        !           306: #define        PAD(plen, pstr) do { \
        !           307:        if ((n = (plen)) > 0) { \
        !           308:                while (n > PADSIZE) { \
        !           309:                        PRINT(pstr, PADSIZE); \
        !           310:                        n -= PADSIZE; \
        !           311:                } \
        !           312:                PRINT(pstr, n); \
        !           313:        } \
        !           314: } while (0)
        !           315: 
        !           316:        /*
        !           317:         * To extend shorts properly, we need both signed and unsigned
        !           318:         * argument extraction methods.
        !           319:         */
        !           320: #define        SARG() \
        !           321:        (flags&LONGINT ? va_arg(ap, long) : \
        !           322:            flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
        !           323:            (long)va_arg(ap, int))
        !           324: #define        UARG() \
        !           325:        (flags&LONGINT ? va_arg(ap, unsigned long) : \
        !           326:            flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
        !           327:            (unsigned long)va_arg(ap, unsigned int))
        !           328: 
        !           329:        fmt = (char *)fmt0;
        !           330:        ret = 0;
        !           331: 
        !           332:        if (alloc) {
        !           333:                strsize = 128;
        !           334:                *strp = str = (char *)malloc(strsize);
        !           335:                if (str == NULL) {
        !           336:                        ret = -1;
        !           337:                        goto done;
        !           338:                }
        !           339:                estr = str + 127;
        !           340:        } else {
        !           341:                str = *strp;
        !           342:                if (strsize)
        !           343:                        estr = str + strsize - 1;
        !           344:                else
        !           345:                        estr = NULL;
        !           346:        }
        !           347: 
        !           348:        /*
        !           349:         * Scan the format for conversions (`%' character).
        !           350:         */
        !           351:        for (;;) {
        !           352:                for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
        !           353:                        /* void */;
        !           354:                if ((n = fmt - cp) != 0) {
        !           355:                        PRINT(cp, n);
        !           356:                        ret += n;
        !           357:                }
        !           358:                if (ch == '\0')
        !           359:                        goto done;
        !           360:                fmt++;          /* skip over '%' */
        !           361: 
        !           362:                flags = 0;
        !           363:                dprec = 0;
        !           364:                width = 0;
        !           365:                prec = -1;
        !           366:                sign = '\0';
        !           367: 
        !           368: rflag:         ch = *fmt++;
        !           369: reswitch:      switch (ch) {
        !           370:                case ' ':
        !           371:                        /*
        !           372:                         * ``If the space and + flags both appear, the space
        !           373:                         * flag will be ignored.''
        !           374:                         *      -- ANSI X3J11
        !           375:                         */
        !           376:                        if (!sign)
        !           377:                                sign = ' ';
        !           378:                        goto rflag;
        !           379:                case '#':
        !           380:                        flags |= ALT;
        !           381:                        goto rflag;
        !           382:                case '*':
        !           383:                        /*
        !           384:                         * ``A negative field width argument is taken as a
        !           385:                         * - flag followed by a positive field width.''
        !           386:                         *      -- ANSI X3J11
        !           387:                         * They don't exclude field widths read from args.
        !           388:                         */
        !           389:                        if ((width = va_arg(ap, int)) >= 0)
        !           390:                                goto rflag;
        !           391:                        width = -width;
        !           392:                        /* FALLTHROUGH */
        !           393:                case '-':
        !           394:                        flags |= LADJUST;
        !           395:                        goto rflag;
        !           396:                case '+':
        !           397:                        sign = '+';
        !           398:                        goto rflag;
        !           399:                case '.':
        !           400:                        if ((ch = *fmt++) == '*') {
        !           401:                                n = va_arg(ap, int);
        !           402:                                prec = n < 0 ? -1 : n;
        !           403:                                goto rflag;
        !           404:                        }
        !           405:                        n = 0;
        !           406:                        while (is_digit(ch)) {
        !           407:                                n = 10 * n + to_digit(ch);
        !           408:                                ch = *fmt++;
        !           409:                        }
        !           410:                        prec = n < 0 ? -1 : n;
        !           411:                        goto reswitch;
        !           412:                case '0':
        !           413:                        /*
        !           414:                         * ``Note that 0 is taken as a flag, not as the
        !           415:                         * beginning of a field width.''
        !           416:                         *      -- ANSI X3J11
        !           417:                         */
        !           418:                        flags |= ZEROPAD;
        !           419:                        goto rflag;
        !           420:                case '1': case '2': case '3': case '4':
        !           421:                case '5': case '6': case '7': case '8': case '9':
        !           422:                        n = 0;
        !           423:                        do {
        !           424:                                n = 10 * n + to_digit(ch);
        !           425:                                ch = *fmt++;
        !           426:                        } while (is_digit(ch));
        !           427:                        width = n;
        !           428:                        goto reswitch;
        !           429:                case 'h':
        !           430:                        flags |= SHORTINT;
        !           431:                        goto rflag;
        !           432:                case 'l':
        !           433:                        flags |= LONGINT;
        !           434:                        goto rflag;
        !           435: #ifdef HAVE_LONG_LONG_INT
        !           436:                case 'q':
        !           437:                        flags |= QUADINT;
        !           438:                        goto rflag;
        !           439: #endif /* HAVE_LONG_LONG_INT */
        !           440:                case 'c':
        !           441:                        *(cp = buf) = va_arg(ap, int);
        !           442:                        size = 1;
        !           443:                        sign = '\0';
        !           444:                        break;
        !           445:                case 'D':
        !           446:                        flags |= LONGINT;
        !           447:                        /*FALLTHROUGH*/
        !           448:                case 'd':
        !           449:                case 'i':
        !           450: #ifdef HAVE_LONG_LONG_INT
        !           451:                        if (flags & QUADINT) {
        !           452:                                uqval = va_arg(ap, long long);
        !           453:                                if ((long long)uqval < 0) {
        !           454:                                        uqval = -uqval;
        !           455:                                        sign = '-';
        !           456:                                }
        !           457:                        }
        !           458:                        else
        !           459: #endif /* HAVE_LONG_LONG_INT */
        !           460:                        {
        !           461:                                ulval = SARG();
        !           462:                                if ((long)ulval < 0) {
        !           463:                                        ulval = -ulval;
        !           464:                                        sign = '-';
        !           465:                                }
        !           466:                        }
        !           467:                        base = 10;
        !           468:                        goto number;
        !           469:                case 'n':
        !           470: #ifdef HAVE_LONG_LONG_INT
        !           471:                        if (flags & QUADINT)
        !           472:                                *va_arg(ap, long long *) = ret;
        !           473:                        else
        !           474: #endif /* HAVE_LONG_LONG_INT */
        !           475:                        if (flags & LONGINT)
        !           476:                                *va_arg(ap, long *) = ret;
        !           477:                        else if (flags & SHORTINT)
        !           478:                                *va_arg(ap, short *) = ret;
        !           479:                        else
        !           480:                                *va_arg(ap, int *) = ret;
        !           481:                        continue;       /* no output */
        !           482:                case 'O':
        !           483:                        flags |= LONGINT;
        !           484:                        /*FALLTHROUGH*/
        !           485:                case 'o':
        !           486: #ifdef HAVE_LONG_LONG_INT
        !           487:                        if (flags & QUADINT)
        !           488:                                uqval = va_arg(ap, unsigned long long);
        !           489:                        else
        !           490: #endif /* HAVE_LONG_LONG_INT */
        !           491:                                ulval = UARG();
        !           492:                        base = 8;
        !           493:                        goto nosign;
        !           494:                case 'p':
        !           495:                        /*
        !           496:                         * ``The argument shall be a pointer to void.  The
        !           497:                         * value of the pointer is converted to a sequence
        !           498:                         * of printable characters, in an implementation-
        !           499:                         * defined manner.''
        !           500:                         *      -- ANSI X3J11
        !           501:                         */
        !           502:                        ulval = (unsigned long)va_arg(ap, void *);
        !           503:                        base = 16;
        !           504:                        xdigs = "0123456789abcdef";
        !           505:                        flags = (flags & ~QUADINT) | HEXPREFIX;
        !           506:                        ch = 'x';
        !           507:                        goto nosign;
        !           508:                case 's':
        !           509:                        if ((cp = va_arg(ap, char *)) == NULL)
        !           510:                                cp = "(null)";
        !           511:                        if (prec >= 0) {
        !           512:                                /*
        !           513:                                 * can't use strlen; can only look for the
        !           514:                                 * NUL in the first `prec' characters, and
        !           515:                                 * strlen() will go further.
        !           516:                                 */
        !           517:                                char *p = memchr(cp, 0, prec);
        !           518: 
        !           519:                                if (p != NULL) {
        !           520:                                        size = p - cp;
        !           521:                                        if (size > prec)
        !           522:                                                size = prec;
        !           523:                                } else
        !           524:                                        size = prec;
        !           525:                        } else
        !           526:                                size = strlen(cp);
        !           527:                        sign = '\0';
        !           528:                        break;
        !           529:                case 'U':
        !           530:                        flags |= LONGINT;
        !           531:                        /*FALLTHROUGH*/
        !           532:                case 'u':
        !           533: #ifdef HAVE_LONG_LONG_INT
        !           534:                        if (flags & QUADINT)
        !           535:                                uqval = va_arg(ap, unsigned long long);
        !           536:                        else
        !           537: #endif /* HAVE_LONG_LONG_INT */
        !           538:                                ulval = UARG();
        !           539:                        base = 10;
        !           540:                        goto nosign;
        !           541:                case 'X':
        !           542:                        xdigs = "0123456789ABCDEF";
        !           543:                        goto hex;
        !           544:                case 'x':
        !           545:                        xdigs = "0123456789abcdef";
        !           546: hex:
        !           547: #ifdef HAVE_LONG_LONG_INT
        !           548:                        if (flags & QUADINT)
        !           549:                                uqval = va_arg(ap, unsigned long long);
        !           550:                        else
        !           551: #endif /* HAVE_LONG_LONG_INT */
        !           552:                                ulval = UARG();
        !           553:                        base = 16;
        !           554:                        /* leading 0x/X only if non-zero */
        !           555:                        if (flags & ALT &&
        !           556: #ifdef HAVE_LONG_LONG_INT
        !           557:                            (flags & QUADINT ? uqval != 0 : ulval != 0))
        !           558: #else
        !           559:                            ulval != 0)
        !           560: #endif /* HAVE_LONG_LONG_INT */
        !           561:                                flags |= HEXPREFIX;
        !           562: 
        !           563:                        /* unsigned conversions */
        !           564: nosign:                        sign = '\0';
        !           565:                        /*
        !           566:                         * ``... diouXx conversions ... if a precision is
        !           567:                         * specified, the 0 flag will be ignored.''
        !           568:                         *      -- ANSI X3J11
        !           569:                         */
        !           570: number:                        if ((dprec = prec) >= 0)
        !           571:                                flags &= ~ZEROPAD;
        !           572: 
        !           573:                        /*
        !           574:                         * ``The result of converting a zero value with an
        !           575:                         * explicit precision of zero is no characters.''
        !           576:                         *      -- ANSI X3J11
        !           577:                         */
        !           578:                        cp = buf + BUF;
        !           579: #ifdef HAVE_LONG_LONG_INT
        !           580:                        if (flags & QUADINT) {
        !           581:                                if (uqval != 0 || prec != 0)
        !           582:                                        cp = __uqtoa(uqval, cp, base,
        !           583:                                            flags & ALT, xdigs);
        !           584:                        }
        !           585:                        else
        !           586: #endif /* HAVE_LONG_LONG_INT */
        !           587:                        {
        !           588:                                if (ulval != 0 || prec != 0)
        !           589:                                        cp = __ultoa(ulval, cp, base,
        !           590:                                            flags & ALT, xdigs);
        !           591:                        }
        !           592:                        size = buf + BUF - cp;
        !           593:                        break;
        !           594:                default:        /* "%?" prints ?, unless ? is NUL */
        !           595:                        if (ch == '\0')
        !           596:                                goto done;
        !           597:                        /* pretend it was %c with argument ch */
        !           598:                        cp = buf;
        !           599:                        *cp = ch;
        !           600:                        size = 1;
        !           601:                        sign = '\0';
        !           602:                        break;
        !           603:                }
        !           604: 
        !           605:                /*
        !           606:                 * All reasonable formats wind up here.  At this point, `cp'
        !           607:                 * points to a string which (if not flags&LADJUST) should be
        !           608:                 * padded out to `width' places.  If flags&ZEROPAD, it should
        !           609:                 * first be prefixed by any sign or other prefix; otherwise,
        !           610:                 * it should be blank padded before the prefix is emitted.
        !           611:                 * After any left-hand padding and prefixing, emit zeroes
        !           612:                 * required by a decimal [diouxX] precision, then print the
        !           613:                 * string proper, then emit zeroes required by any leftover
        !           614:                 * floating precision; finally, if LADJUST, pad with blanks.
        !           615:                 *
        !           616:                 * Compute actual size, so we know how much to pad.
        !           617:                 * fieldsz excludes decimal prec; realsz includes it.
        !           618:                 */
        !           619:                fieldsz = size;
        !           620:                if (sign)
        !           621:                        fieldsz++;
        !           622:                else if (flags & HEXPREFIX)
        !           623:                        fieldsz += 2;
        !           624:                realsz = dprec > fieldsz ? dprec : fieldsz;
        !           625: 
        !           626:                /* right-adjusting blank padding */
        !           627:                if ((flags & (LADJUST|ZEROPAD)) == 0)
        !           628:                        PAD(width - realsz, blanks);
        !           629: 
        !           630:                /* prefix */
        !           631:                if (sign) {
        !           632:                        PRINT(&sign, 1);
        !           633:                } else if (flags & HEXPREFIX) {
        !           634:                        ox[0] = '0';
        !           635:                        ox[1] = ch;
        !           636:                        PRINT(ox, 2);
        !           637:                }
        !           638: 
        !           639:                /* right-adjusting zero padding */
        !           640:                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
        !           641:                        PAD(width - realsz, zeroes);
        !           642: 
        !           643:                /* leading zeroes from decimal precision */
        !           644:                PAD(dprec - fieldsz, zeroes);
        !           645: 
        !           646:                /* the string or number proper */
        !           647:                PRINT(cp, size);
        !           648: 
        !           649:                /* left-adjusting padding (always blank) */
        !           650:                if (flags & LADJUST)
        !           651:                        PAD(width - realsz, blanks);
        !           652: 
        !           653:                /* finally, adjust ret */
        !           654:                ret += width > realsz ? width : realsz;
        !           655:        }
        !           656: done:
        !           657:        if (strsize)
        !           658:                *str = '\0';
        !           659:        return ret;
        !           660:        /* NOTREACHED */
        !           661: }
        !           662: 
        !           663: #ifndef HAVE_VSNPRINTF
        !           664: int
        !           665: vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
        !           666: {
        !           667: 
        !           668:        return xxxprintf(&str, n, 0, fmt, ap);
        !           669: }
        !           670: #endif /* HAVE_VSNPRINTF */
        !           671: 
        !           672: #ifndef HAVE_SNPRINTF
        !           673: int
        !           674: snprintf(char *str, size_t n, char const *fmt, ...)
        !           675: {
        !           676:        int ret;
        !           677:        va_list ap;
        !           678: 
        !           679:        va_start(ap, fmt);
        !           680:        ret = xxxprintf(&str, n, 0, fmt, ap);
        !           681:        va_end(ap);
        !           682:        return ret;
        !           683: }
        !           684: #endif /* HAVE_SNPRINTF */
        !           685: 
        !           686: #ifndef HAVE_VASPRINTF
        !           687: int
        !           688: vasprintf(char **str, const char *fmt, va_list ap)
        !           689: {
        !           690: 
        !           691:        return xxxprintf(str, 0, 1, fmt, ap);
        !           692: }
        !           693: #endif /* HAVE_VASPRINTF */
        !           694: 
        !           695: #ifndef HAVE_ASPRINTF
        !           696: int
        !           697: asprintf(char **str, char const *fmt, ...)
        !           698: {
        !           699:        int ret;
        !           700:        va_list ap;
        !           701: 
        !           702:        va_start(ap, fmt);
        !           703:        ret = xxxprintf(str, 0, 1, fmt, ap);
        !           704:        va_end(ap);
        !           705:        return ret;
        !           706: }
        !           707: #endif /* HAVE_ASPRINTF */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>