| /* |
| * Copyright (c) 1999-2005, 2008, 2010 |
| * Todd C. Miller <Todd.Miller@courtesan.com> |
| * Copyright (c) 1990, 1993 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * This code is derived from software contributed to Berkeley by |
| * Chris Torek. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the University nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * |
| * From: @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 |
| */ |
| |
| /* |
| * v?snprintf/v?asprintf based on 4.4BSD stdio. |
| * NOTE: does not support floating point. |
| */ |
| |
| #include <config.h> |
| |
| #include <sys/types.h> |
| #include <sys/param.h> |
| |
| #include <stdio.h> |
| #ifdef STDC_HEADERS |
| # include <stdlib.h> |
| # include <stddef.h> |
| #else |
| # ifdef HAVE_STDLIB_H |
| # include <stdlib.h> |
| # endif |
| #endif /* STDC_HEADERS */ |
| #ifdef HAVE_STDINT_H |
| # include <stdint.h> |
| #endif |
| #ifdef HAVE_STRING_H |
| # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) |
| # include <memory.h> |
| # endif |
| # include <string.h> |
| #endif /* HAVE_STRING_H */ |
| #ifdef HAVE_STRINGS_H |
| # include <strings.h> |
| #endif /* HAVE_STRINGS_H */ |
| #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) |
| # include <malloc.h> |
| #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ |
| #include <limits.h> |
| |
| #ifdef __STDC__ |
| # include <stdarg.h> |
| #else |
| # include <varargs.h> |
| #endif |
| |
| #include <compat.h> |
| |
| static int xxxprintf __P((char **, size_t, int, const char *, va_list)); |
| |
| /* |
| * Some systems may not have these defined in <limits.h> |
| */ |
| #ifndef ULONG_MAX |
| # define ULONG_MAX ((unsigned long)-1) |
| #endif |
| #ifndef LONG_MAX |
| # define LONG_MAX (ULONG_MAX / 2) |
| #endif |
| #ifdef HAVE_LONG_LONG_INT |
| # ifndef ULLONG_MAX |
| # ifdef UQUAD_MAX |
| # define ULLONG_MAX UQUAD_MAX |
| # else |
| # define ULLONG_MAX ((unsigned long long)-1) |
| # endif |
| # endif |
| # ifndef LLONG_MAX |
| # ifdef QUAD_MAX |
| # define LLONG_MAX QUAD_MAX |
| # else |
| # define LLONG_MAX (ULLONG_MAX / 2) |
| # endif |
| # endif |
| #endif /* HAVE_LONG_LONG_INT */ |
| |
| /* |
| * Macros for converting digits to letters and vice versa |
| */ |
| #define to_digit(c) ((c) - '0') |
| #define is_digit(c) ((unsigned int)to_digit(c) <= 9) |
| #define to_char(n) ((n) + '0') |
| |
| /* |
| * Flags used during conversion. |
| */ |
| #define ALT 0x001 /* alternate form */ |
| #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ |
| #define LADJUST 0x004 /* left adjustment */ |
| #define LONGDBL 0x008 /* long double; unimplemented */ |
| #define LONGINT 0x010 /* long integer */ |
| #define QUADINT 0x020 /* quad integer */ |
| #define SHORTINT 0x040 /* short integer */ |
| #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ |
| |
| #define BUF 68 |
| |
| #ifndef HAVE_MEMCHR |
| void * |
| memchr(s, c, n) |
| const void *s; |
| unsigned char c; |
| size_t n; |
| { |
| if (n != 0) { |
| const unsigned char *p = s; |
| |
| do { |
| if (*p++ == c) |
| return ((void *)(p - 1)); |
| } while (--n != 0); |
| } |
| return (NULL); |
| } |
| #endif /* !HAVE_MEMCHR */ |
| |
| /* |
| * Convert an unsigned long to ASCII for printf purposes, returning |
| * a pointer to the first character of the string representation. |
| * Octal numbers can be forced to have a leading zero; hex numbers |
| * use the given digits. |
| */ |
| static char * |
| __ultoa(val, endp, base, octzero, xdigs) |
| unsigned long val; |
| char *endp; |
| int base, octzero; |
| char *xdigs; |
| { |
| char *cp = endp; |
| long sval; |
| |
| /* |
| * Handle the three cases separately, in the hope of getting |
| * better/faster code. |
| */ |
| switch (base) { |
| case 10: |
| if (val < 10) { /* many numbers are 1 digit */ |
| *--cp = to_char(val); |
| return (cp); |
| } |
| /* |
| * On many machines, unsigned arithmetic is harder than |
| * signed arithmetic, so we do at most one unsigned mod and |
| * divide; this is sufficient to reduce the range of |
| * the incoming value to where signed arithmetic works. |
| */ |
| if (val > LONG_MAX) { |
| *--cp = to_char(val % 10); |
| sval = val / 10; |
| } else |
| sval = val; |
| do { |
| *--cp = to_char(sval % 10); |
| sval /= 10; |
| } while (sval != 0); |
| break; |
| |
| case 8: |
| do { |
| *--cp = to_char(val & 7); |
| val >>= 3; |
| } while (val); |
| if (octzero && *cp != '0') |
| *--cp = '0'; |
| break; |
| |
| case 16: |
| do { |
| *--cp = xdigs[val & 15]; |
| val >>= 4; |
| } while (val); |
| break; |
| |
| default: /* oops */ |
| abort(); |
| } |
| return (cp); |
| } |
| |
| /* Identical to __ultoa, but for quads. */ |
| #ifdef HAVE_LONG_LONG_INT |
| # if SIZEOF_LONG_INT == 8 |
| # define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x)) |
| # else |
| static char * |
| __uqtoa(val, endp, base, octzero, xdigs) |
| unsigned long long val; |
| char *endp; |
| int base, octzero; |
| char *xdigs; |
| { |
| char *cp = endp; |
| long long sval; |
| |
| /* quick test for small values; __ultoa is typically much faster */ |
| /* (perhaps instead we should run until small, then call __ultoa?) */ |
| if (val <= (unsigned long long)ULONG_MAX) |
| return (__ultoa((unsigned long)val, endp, base, octzero, xdigs)); |
| switch (base) { |
| case 10: |
| if (val < 10) { |
| *--cp = to_char(val % 10); |
| return (cp); |
| } |
| if (val > LLONG_MAX) { |
| *--cp = to_char(val % 10); |
| sval = val / 10; |
| } else |
| sval = val; |
| do { |
| *--cp = to_char(sval % 10); |
| sval /= 10; |
| } while (sval != 0); |
| break; |
| |
| case 8: |
| do { |
| *--cp = to_char(val & 7); |
| val >>= 3; |
| } while (val); |
| if (octzero && *cp != '0') |
| *--cp = '0'; |
| break; |
| |
| case 16: |
| do { |
| *--cp = xdigs[val & 15]; |
| val >>= 4; |
| } while (val); |
| break; |
| |
| default: /* oops */ |
| abort(); |
| } |
| return (cp); |
| } |
| # endif /* !SIZEOF_LONG_INT */ |
| #endif /* HAVE_LONG_LONG_INT */ |
| |
| /* |
| * Actual printf innards. |
| */ |
| static int |
| xxxprintf(strp, strsize, alloc, fmt0, ap) |
| char **strp; |
| size_t strsize; |
| int alloc; |
| const char *fmt0; |
| va_list ap; |
| { |
| char *fmt; /* format string */ |
| int ch; /* character from fmt */ |
| int n; /* handy integer (short term usage) */ |
| char *cp; /* handy char pointer (short term usage) */ |
| int flags; /* flags as above */ |
| int ret; /* return value accumulator */ |
| int width; /* width from format (%8d), or 0 */ |
| int prec; /* precision from format (%.3d), or -1 */ |
| char sign; /* sign prefix (' ', '+', '-', or \0) */ |
| unsigned long ulval; /* integer arguments %[diouxX] */ |
| #ifdef HAVE_LONG_LONG_INT |
| unsigned long long uqval; /* %q (quad) integers */ |
| #endif |
| int base; /* base for [diouxX] conversion */ |
| int dprec; /* a copy of prec if [diouxX], 0 otherwise */ |
| int fieldsz; /* field size expanded by sign, etc */ |
| int realsz; /* field size expanded by dprec */ |
| int size; /* size of converted field or string */ |
| char *xdigs; /* digits for [xX] conversion */ |
| char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ |
| char ox[2]; /* space for 0x hex-prefix */ |
| char *str; /* pointer to string to fill */ |
| char *estr; /* pointer to last char in str */ |
| |
| /* |
| * Choose PADSIZE to trade efficiency vs. size. If larger printf |
| * fields occur frequently, increase PADSIZE and make the initialisers |
| * below longer. |
| */ |
| #define PADSIZE 16 /* pad chunk size */ |
| static char blanks[PADSIZE] = |
| {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; |
| static char zeroes[PADSIZE] = |
| {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; |
| |
| /* Print chars to "str", (allocate as needed if alloc is set). */ |
| #define PRINT(ptr, len) do { \ |
| const char *p = ptr; \ |
| const char *endp = ptr + len; \ |
| while (p < endp && (str < estr || alloc)) { \ |
| if (alloc && str >= estr) { \ |
| char *t; \ |
| strsize = (strsize << 1) + 1; \ |
| if (!(t = (char *)realloc(*strp, strsize))) { \ |
| free(str); \ |
| *strp = NULL; \ |
| ret = -1; \ |
| goto done; \ |
| } \ |
| str = t + (str - *strp); \ |
| estr = t + strsize - 1; \ |
| *strp = t; \ |
| } \ |
| *str++ = *p++; \ |
| } \ |
| } while (0) |
| |
| /* BEWARE, PAD uses `n'. */ |
| #define PAD(howmany, with) do { \ |
| if ((n = (howmany)) > 0) { \ |
| while (n > PADSIZE) { \ |
| PRINT(with, PADSIZE); \ |
| n -= PADSIZE; \ |
| } \ |
| PRINT(with, n); \ |
| } \ |
| } while (0) |
| |
| /* |
| * To extend shorts properly, we need both signed and unsigned |
| * argument extraction methods. |
| */ |
| #define SARG() \ |
| (flags&LONGINT ? va_arg(ap, long) : \ |
| flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ |
| (long)va_arg(ap, int)) |
| #define UARG() \ |
| (flags&LONGINT ? va_arg(ap, unsigned long) : \ |
| flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ |
| (unsigned long)va_arg(ap, unsigned int)) |
| |
| fmt = (char *)fmt0; |
| ret = 0; |
| |
| if (alloc) { |
| strsize = 128; |
| *strp = str = (char *)malloc(strsize); |
| if (str == NULL) { |
| ret = -1; |
| goto done; |
| } |
| estr = str + 127; |
| } else { |
| str = *strp; |
| if (strsize) |
| estr = str + strsize - 1; |
| else |
| estr = NULL; |
| } |
| |
| /* |
| * Scan the format for conversions (`%' character). |
| */ |
| for (;;) { |
| for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) |
| /* void */; |
| if ((n = fmt - cp) != 0) { |
| PRINT(cp, n); |
| ret += n; |
| } |
| if (ch == '\0') |
| goto done; |
| fmt++; /* skip over '%' */ |
| |
| flags = 0; |
| dprec = 0; |
| width = 0; |
| prec = -1; |
| sign = '\0'; |
| |
| rflag: ch = *fmt++; |
| reswitch: switch (ch) { |
| case ' ': |
| /* |
| * ``If the space and + flags both appear, the space |
| * flag will be ignored.'' |
| * -- ANSI X3J11 |
| */ |
| if (!sign) |
| sign = ' '; |
| goto rflag; |
| case '#': |
| flags |= ALT; |
| goto rflag; |
| case '*': |
| /* |
| * ``A negative field width argument is taken as a |
| * - flag followed by a positive field width.'' |
| * -- ANSI X3J11 |
| * They don't exclude field widths read from args. |
| */ |
| if ((width = va_arg(ap, int)) >= 0) |
| goto rflag; |
| width = -width; |
| /* FALLTHROUGH */ |
| case '-': |
| flags |= LADJUST; |
| goto rflag; |
| case '+': |
| sign = '+'; |
| goto rflag; |
| case '.': |
| if ((ch = *fmt++) == '*') { |
| n = va_arg(ap, int); |
| prec = n < 0 ? -1 : n; |
| goto rflag; |
| } |
| n = 0; |
| while (is_digit(ch)) { |
| n = 10 * n + to_digit(ch); |
| ch = *fmt++; |
| } |
| prec = n < 0 ? -1 : n; |
| goto reswitch; |
| case '0': |
| /* |
| * ``Note that 0 is taken as a flag, not as the |
| * beginning of a field width.'' |
| * -- ANSI X3J11 |
| */ |
| flags |= ZEROPAD; |
| goto rflag; |
| case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| n = 0; |
| do { |
| n = 10 * n + to_digit(ch); |
| ch = *fmt++; |
| } while (is_digit(ch)); |
| width = n; |
| goto reswitch; |
| case 'h': |
| flags |= SHORTINT; |
| goto rflag; |
| case 'l': |
| flags |= LONGINT; |
| goto rflag; |
| #ifdef HAVE_LONG_LONG_INT |
| case 'q': |
| flags |= QUADINT; |
| goto rflag; |
| #endif /* HAVE_LONG_LONG_INT */ |
| case 'c': |
| *(cp = buf) = va_arg(ap, int); |
| size = 1; |
| sign = '\0'; |
| break; |
| case 'D': |
| flags |= LONGINT; |
| /*FALLTHROUGH*/ |
| case 'd': |
| case 'i': |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) { |
| uqval = va_arg(ap, long long); |
| if ((long long)uqval < 0) { |
| uqval = -uqval; |
| sign = '-'; |
| } |
| } |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| { |
| ulval = SARG(); |
| if ((long)ulval < 0) { |
| ulval = -ulval; |
| sign = '-'; |
| } |
| } |
| base = 10; |
| goto number; |
| case 'n': |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) |
| *va_arg(ap, long long *) = ret; |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| if (flags & LONGINT) |
| *va_arg(ap, long *) = ret; |
| else if (flags & SHORTINT) |
| *va_arg(ap, short *) = ret; |
| else |
| *va_arg(ap, int *) = ret; |
| continue; /* no output */ |
| case 'O': |
| flags |= LONGINT; |
| /*FALLTHROUGH*/ |
| case 'o': |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) |
| uqval = va_arg(ap, unsigned long long); |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| ulval = UARG(); |
| base = 8; |
| goto nosign; |
| case 'p': |
| /* |
| * ``The argument shall be a pointer to void. The |
| * value of the pointer is converted to a sequence |
| * of printable characters, in an implementation- |
| * defined manner.'' |
| * -- ANSI X3J11 |
| */ |
| ulval = (unsigned long)va_arg(ap, void *); |
| base = 16; |
| xdigs = "0123456789abcdef"; |
| flags = (flags & ~QUADINT) | HEXPREFIX; |
| ch = 'x'; |
| goto nosign; |
| case 's': |
| if ((cp = va_arg(ap, char *)) == NULL) |
| cp = "(null)"; |
| if (prec >= 0) { |
| /* |
| * can't use strlen; can only look for the |
| * NUL in the first `prec' characters, and |
| * strlen() will go further. |
| */ |
| char *p = memchr(cp, 0, prec); |
| |
| if (p != NULL) { |
| size = p - cp; |
| if (size > prec) |
| size = prec; |
| } else |
| size = prec; |
| } else |
| size = strlen(cp); |
| sign = '\0'; |
| break; |
| case 'U': |
| flags |= LONGINT; |
| /*FALLTHROUGH*/ |
| case 'u': |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) |
| uqval = va_arg(ap, unsigned long long); |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| ulval = UARG(); |
| base = 10; |
| goto nosign; |
| case 'X': |
| xdigs = "0123456789ABCDEF"; |
| goto hex; |
| case 'x': |
| xdigs = "0123456789abcdef"; |
| hex: |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) |
| uqval = va_arg(ap, unsigned long long); |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| ulval = UARG(); |
| base = 16; |
| /* leading 0x/X only if non-zero */ |
| if (flags & ALT && |
| #ifdef HAVE_LONG_LONG_INT |
| (flags & QUADINT ? uqval != 0 : ulval != 0)) |
| #else |
| ulval != 0) |
| #endif /* HAVE_LONG_LONG_INT */ |
| flags |= HEXPREFIX; |
| |
| /* unsigned conversions */ |
| nosign: sign = '\0'; |
| /* |
| * ``... diouXx conversions ... if a precision is |
| * specified, the 0 flag will be ignored.'' |
| * -- ANSI X3J11 |
| */ |
| number: if ((dprec = prec) >= 0) |
| flags &= ~ZEROPAD; |
| |
| /* |
| * ``The result of converting a zero value with an |
| * explicit precision of zero is no characters.'' |
| * -- ANSI X3J11 |
| */ |
| cp = buf + BUF; |
| #ifdef HAVE_LONG_LONG_INT |
| if (flags & QUADINT) { |
| if (uqval != 0 || prec != 0) |
| cp = __uqtoa(uqval, cp, base, |
| flags & ALT, xdigs); |
| } |
| else |
| #endif /* HAVE_LONG_LONG_INT */ |
| { |
| if (ulval != 0 || prec != 0) |
| cp = __ultoa(ulval, cp, base, |
| flags & ALT, xdigs); |
| } |
| size = buf + BUF - cp; |
| break; |
| default: /* "%?" prints ?, unless ? is NUL */ |
| if (ch == '\0') |
| goto done; |
| /* pretend it was %c with argument ch */ |
| cp = buf; |
| *cp = ch; |
| size = 1; |
| sign = '\0'; |
| break; |
| } |
| |
| /* |
| * All reasonable formats wind up here. At this point, `cp' |
| * points to a string which (if not flags&LADJUST) should be |
| * padded out to `width' places. If flags&ZEROPAD, it should |
| * first be prefixed by any sign or other prefix; otherwise, |
| * it should be blank padded before the prefix is emitted. |
| * After any left-hand padding and prefixing, emit zeroes |
| * required by a decimal [diouxX] precision, then print the |
| * string proper, then emit zeroes required by any leftover |
| * floating precision; finally, if LADJUST, pad with blanks. |
| * |
| * Compute actual size, so we know how much to pad. |
| * fieldsz excludes decimal prec; realsz includes it. |
| */ |
| fieldsz = size; |
| if (sign) |
| fieldsz++; |
| else if (flags & HEXPREFIX) |
| fieldsz += 2; |
| realsz = dprec > fieldsz ? dprec : fieldsz; |
| |
| /* right-adjusting blank padding */ |
| if ((flags & (LADJUST|ZEROPAD)) == 0) |
| PAD(width - realsz, blanks); |
| |
| /* prefix */ |
| if (sign) { |
| PRINT(&sign, 1); |
| } else if (flags & HEXPREFIX) { |
| ox[0] = '0'; |
| ox[1] = ch; |
| PRINT(ox, 2); |
| } |
| |
| /* right-adjusting zero padding */ |
| if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) |
| PAD(width - realsz, zeroes); |
| |
| /* leading zeroes from decimal precision */ |
| PAD(dprec - fieldsz, zeroes); |
| |
| /* the string or number proper */ |
| PRINT(cp, size); |
| |
| /* left-adjusting padding (always blank) */ |
| if (flags & LADJUST) |
| PAD(width - realsz, blanks); |
| |
| /* finally, adjust ret */ |
| ret += width > realsz ? width : realsz; |
| } |
| done: |
| if (strsize) |
| *str = '\0'; |
| return (ret); |
| /* NOTREACHED */ |
| } |
| |
| #ifndef HAVE_VSNPRINTF |
| int |
| vsnprintf(str, n, fmt, ap) |
| char *str; |
| size_t n; |
| const char *fmt; |
| va_list ap; |
| { |
| |
| return (xxxprintf(&str, n, 0, fmt, ap)); |
| } |
| #endif /* HAVE_VSNPRINTF */ |
| |
| #ifndef HAVE_SNPRINTF |
| int |
| #ifdef __STDC__ |
| snprintf(char *str, size_t n, char const *fmt, ...) |
| #else |
| snprintf(str, n, fmt, va_alist) |
| char *str; |
| size_t n; |
| char const *fmt; |
| va_dcl |
| #endif |
| { |
| int ret; |
| va_list ap; |
| |
| #ifdef __STDC__ |
| va_start(ap, fmt); |
| #else |
| va_start(ap); |
| #endif |
| ret = xxxprintf(&str, n, 0, fmt, ap); |
| va_end(ap); |
| return (ret); |
| } |
| #endif /* HAVE_SNPRINTF */ |
| |
| #ifndef HAVE_VASPRINTF |
| int |
| vasprintf(str, fmt, ap) |
| char **str; |
| const char *fmt; |
| va_list ap; |
| { |
| |
| return (xxxprintf(str, 0, 1, fmt, ap)); |
| } |
| #endif /* HAVE_VASPRINTF */ |
| |
| #ifndef HAVE_ASPRINTF |
| int |
| #ifdef __STDC__ |
| asprintf(char **str, char const *fmt, ...) |
| #else |
| asprintf(str, fmt, va_alist) |
| char **str; |
| char const *fmt; |
| va_dcl |
| #endif |
| { |
| int ret; |
| va_list ap; |
| |
| #ifdef __STDC__ |
| va_start(ap, fmt); |
| #else |
| va_start(ap); |
| #endif |
| ret = xxxprintf(str, 0, 1, fmt, ap); |
| va_end(ap); |
| return (ret); |
| } |
| #endif /* HAVE_ASPRINTF */ |