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