Annotation of embedaddon/sudo/compat/snprintf.c, revision 1.1.1.2
1.1 misho 1: /*
1.1.1.2 ! misho 2: * Copyright (c) 1999-2005, 2008, 2010-2013
1.1 misho 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:
1.1.1.2 ! misho 44: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_SNPRINTF) || !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF)
! 45:
1.1 misho 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 */
1.1.1.2 ! misho 57: #if defined(HAVE_STDINT_H)
1.1 misho 58: # include <stdint.h>
1.1.1.2 ! misho 59: #elif defined(HAVE_INTTYPES_H)
! 60: # include <inttypes.h>
1.1 misho 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 */
1.1.1.2 ! misho 122: #define LLONGINT 0x020 /* quad integer */
1.1 misho 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':
1.1.1.2 ! misho 436: if (*fmt == 'l') {
! 437: fmt++;
! 438: flags |= LLONGINT;
! 439: } else {
! 440: flags |= LONGINT;
! 441: }
1.1 misho 442: goto rflag;
443: #ifdef HAVE_LONG_LONG_INT
444: case 'q':
1.1.1.2 ! misho 445: flags |= LLONGINT;
1.1 misho 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
1.1.1.2 ! misho 459: if (flags & LLONGINT) {
1.1 misho 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
1.1.1.2 ! misho 479: if (flags & LLONGINT)
1.1 misho 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
1.1.1.2 ! misho 495: if (flags & LLONGINT)
1.1 misho 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";
1.1.1.2 ! misho 513: flags = (flags & ~LLONGINT) | HEXPREFIX;
1.1 misho 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
1.1.1.2 ! misho 542: if (flags & LLONGINT)
1.1 misho 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
1.1.1.2 ! misho 556: if (flags & LLONGINT)
1.1 misho 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
1.1.1.2 ! misho 565: (flags & LLONGINT ? uqval != 0 : ulval != 0))
1.1 misho 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
1.1.1.2 ! misho 588: if (flags & LLONGINT) {
1.1 misho 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 */
1.1.1.2 ! misho 716:
! 717: #endif /* !HAVE_VSNPRINTF || !HAVE_SNPRINTF || !HAVE_VASPRINTF || !HAVE_ASPRINTF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>