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>