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