2 * Copyright Patrick Powell 1995
4 * This code is based on code written by Patrick Powell
5 * (papowell@astart.com) It may be used for any purpose as long
6 * as this notice remains intact on all source code distributions.
8 * Adapted for Bacula -- note there were lots of bugs in
9 * the original code: %lld and %s were seriously broken, and
10 * with FP turned off %f seg faulted.
12 * Kern Sibbald, November MMV
17 Bacula® - The Network Backup Solution
19 Copyright (C) 2005-2008 Free Software Foundation Europe e.V.
21 The main author of Bacula is Kern Sibbald, with contributions from
22 many others, a complete list can be found in the file AUTHORS.
23 This program is Free Software; you can redistribute it and/or
24 modify it under the terms of version two of the GNU General Public
25 License as published by the Free Software Foundation and included
28 This program is distributed in the hope that it will be useful, but
29 WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31 General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program; if not, write to the Free Software
35 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
38 Bacula® is a registered trademark of Kern Sibbald.
39 The licensor of Bacula is the Free Software Foundation Europe
40 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
41 Switzerland, email:ftf@fsfeurope.org.
47 #define FP_OUTPUT 1 /* Bacula uses floating point */
49 /* Define the following if you want all the features of
50 * normal printf, but with all the security problems.
51 * For Bacula we turn this off, and it silently ignores
52 * formats that could pose a security problem.
54 #undef SECURITY_PROBLEM
58 #ifdef HAVE_LONG_DOUBLE
59 #define LDOUBLE long double
61 #define LDOUBLE double
64 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
65 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
66 const char *value, int flags, int min, int max);
67 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
68 int64_t value, int base, int min, int max, int flags);
74 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
75 LDOUBLE fvalue, int min, int max, int flags);
77 #define fmtfp(b, c, m, f, min, max, fl) currlen
81 * NOTE!!!! do not use this #define with a construct such
82 * as outch(--place);. It just will NOT work, because the
83 * decrement of place is done ONLY if there is room in the
86 #define outch(c) {int len=currlen; if (currlen < maxlen) \
87 { buffer[len] = (c); currlen++; }}
89 /* format read states */
90 #define DP_S_DEFAULT 0
99 /* format flags - Bits */
100 #define DP_F_MINUS (1 << 0)
101 #define DP_F_PLUS (1 << 1)
102 #define DP_F_SPACE (1 << 2)
103 #define DP_F_NUM (1 << 3)
104 #define DP_F_ZERO (1 << 4)
105 #define DP_F_UP (1 << 5)
106 #define DP_F_UNSIGNED (1 << 6)
107 #define DP_F_DOT (1 << 7)
109 /* Conversion Flags */
112 #define DP_C_LDOUBLE 3
115 #define char_to_int(p) ((p)- '0')
117 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
120 You might ask why does Bacula have it's own printf routine? Well,
121 There are two reasons: 1. Here (as opposed to library routines), we
122 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
123 disable %n for security reasons.
126 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
131 va_start(arg_ptr, fmt);
132 len = bvsnprintf(str, size, fmt, arg_ptr);
138 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
154 state = DP_S_DEFAULT;
155 currlen = flags = cflags = min = 0;
160 while (state != DP_S_DONE) {
161 if ((ch == '\0') || (currlen >= maxlen)) {
201 if (isdigit((unsigned char)ch)) {
202 min = 10 * min + char_to_int(ch);
204 } else if (ch == '*') {
205 min = va_arg(args, int);
220 if (isdigit((unsigned char)ch)) {
223 max = 10 * max + char_to_int(ch);
225 } else if (ch == '*') {
226 max = va_arg(args, int);
241 if (ch == 'l') { /* It's a long long */
247 cflags = DP_C_LDOUBLE;
250 case 'q': /* same as long long */
263 if (cflags == DP_C_INT16) {
264 value = va_arg(args, int32_t);
265 } else if (cflags == DP_C_INT32) {
266 value = va_arg(args, int32_t);
267 } else if (cflags == DP_C_INT64) {
268 value = va_arg(args, int64_t);
270 value = va_arg(args, int);
272 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
280 } else if (ch == 'x') {
282 } else if (ch == 'X') {
288 flags |= DP_F_UNSIGNED;
289 if (cflags == DP_C_INT16) {
290 value = va_arg(args, uint32_t);
291 } else if (cflags == DP_C_INT32) {
292 value = va_arg(args, uint32_t);
293 } else if (cflags == DP_C_INT64) {
294 value = va_arg(args, uint64_t);
296 value = va_arg(args, unsigned int);
298 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
301 if (cflags == DP_C_LDOUBLE) {
302 fvalue = va_arg(args, LDOUBLE);
304 fvalue = va_arg(args, double);
306 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
311 if (cflags == DP_C_LDOUBLE) {
312 fvalue = va_arg(args, LDOUBLE);
314 fvalue = va_arg(args, double);
316 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
321 if (cflags == DP_C_LDOUBLE) {
322 fvalue = va_arg(args, LDOUBLE);
324 fvalue = va_arg(args, double);
326 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
329 ch = va_arg(args, int);
333 strvalue = va_arg(args, char *);
334 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
337 flags |= DP_F_UNSIGNED;
338 if (sizeof(char *) == 4) {
339 value = va_arg(args, uint32_t);
340 } else if (sizeof(char *) == 8) {
341 value = va_arg(args, uint64_t);
343 value = 0; /* we have a problem */
345 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
348 if (cflags == DP_C_INT16) {
350 num = va_arg(args, int16_t *);
351 #ifdef SECURITY_PROBLEM
354 } else if (cflags == DP_C_INT32) {
356 num = va_arg(args, int32_t *);
357 #ifdef SECURITY_PROBLEM
358 *num = (int32_t)currlen;
360 } else if (cflags == DP_C_INT64) {
362 num = va_arg(args, int64_t *);
363 #ifdef SECURITY_PROBLEM
364 *num = (int64_t)currlen;
368 num = va_arg(args, int32_t *);
369 #ifdef SECURITY_PROBLEM
370 *num = (int32_t)currlen;
378 /* not supported yet, treat as next char */
386 state = DP_S_DEFAULT;
387 flags = cflags = min = 0;
394 break; /* some picky compilers need this */
397 if (currlen < maxlen - 1) {
398 buffer[currlen] = '\0';
400 buffer[maxlen - 1] = '\0';
405 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
406 const char *value, int flags, int min, int max)
408 int padlen, strln; /* amount to pad */
413 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
415 } else if (max < 0) {
421 strln = strlen(value);
423 strln = max; /* truncate to max */
425 padlen = min - strln;
429 if (flags & DP_F_MINUS) {
430 padlen = -padlen; /* Left Justify */
437 while (*value && (cnt < max)) {
449 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
451 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
452 int64_t value, int base, int min, int max, int flags)
458 int spadlen = 0; /* amount to space pad */
459 int zpadlen = 0; /* amount to zero pad */
461 const char *cvt_string;
469 if (!(flags & DP_F_UNSIGNED)) {
473 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
475 } else if (flags & DP_F_SPACE) {
480 if (flags & DP_F_UP) {
481 caps = 1; /* Should characters be upper case? */
484 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
486 convert[place++] = cvt_string[uvalue % (unsigned)base];
487 uvalue = (uvalue / (unsigned)base);
488 } while (uvalue && (place < (int)sizeof(convert)));
489 if (place == (int)sizeof(convert)) {
494 zpadlen = max - place;
495 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
500 if (flags & DP_F_ZERO) {
501 zpadlen = MAX(zpadlen, spadlen);
504 if (flags & DP_F_MINUS)
505 spadlen = -spadlen; /* Left Justifty */
507 #ifdef DEBUG_SNPRINTF
508 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
509 zpadlen, spadlen, min, max, place);
513 while (spadlen > 0) {
525 while (zpadlen > 0) {
531 /* Output digits backward giving correct order */
534 outch(convert[place]);
537 /* Left Justified spaces */
538 while (spadlen < 0) {
547 static LDOUBLE abs_val(LDOUBLE value)
549 LDOUBLE result = value;
557 static LDOUBLE pow10(int exp)
569 static int64_t round(LDOUBLE value)
573 intpart = (int64_t)value;
574 value = value - intpart;
581 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
582 LDOUBLE fvalue, int min, int max, int flags)
596 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
600 int padlen = 0; /* amount to pad */
608 * AIX manpage says the default is 0, but Solaris says the default
609 * is 6, and sprintf on AIX defaults to 6
614 ufvalue = abs_val(fvalue);
618 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
620 else if (flags & DP_F_SPACE)
625 caps = 1; /* Should characters be upper case? */
629 intpart = (int64_t)ufvalue;
632 * Sorry, we only support 9 digits past the decimal because of our
638 /* We "cheat" by converting the fractional part to integer by
639 * multiplying by a factor of 10
641 fracpart = round((pow10(max)) * (ufvalue - intpart));
643 if (fracpart >= pow10(max)) {
645 fracpart -= (int64_t)pow10(max);
648 #ifdef DEBUG_SNPRINTF
649 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
650 (double)fvalue, intpart, fracpart, min, max);
653 /* Convert integer part */
654 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
656 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
657 intpart = (intpart / 10);
658 } while (intpart && (iplace < (int)sizeof(iconvert)));
660 if (iplace == (int)sizeof(fconvert)) {
663 iconvert[iplace] = 0;
665 /* Convert fractional part */
666 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
668 fconvert[fplace++] = cvt_str[fracpart % 10];
669 fracpart = (fracpart / 10);
670 } while (fracpart && (fplace < (int)sizeof(fconvert)));
672 if (fplace == (int)sizeof(fconvert)) {
675 fconvert[fplace] = 0;
676 #else /* use fcvt() */
681 result = fcvtl(ufvalue, max, &dec_pt, &sig);
683 result = fcvt(ufvalue, max, &dec_pt, &sig);
690 r_length = strlen(result);
694 * Fix broken fcvt implementation returns..
703 if (r_length < dec_pt)
714 fconvert[fplace++] = result[--r_length];
717 while ((dec_pt < 0) && (fplace < max)) {
718 fconvert[fplace++] = '0';
725 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
726 iconvert[iplace] = '\0';
731 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
733 #endif /* HAVE_FCVT */
735 /* -1 for decimal point, another -1 if we are printing a sign */
736 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
737 zpadlen = max - fplace;
744 if (flags & DP_F_MINUS) {
745 padlen = -padlen; /* Left Justifty */
748 if ((flags & DP_F_ZERO) && (padlen > 0)) {
769 outch(iconvert[iplace]);
773 #ifdef DEBUG_SNPRINTF
774 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
778 * Decimal point. This should probably use locale to find the correct
785 outch(fconvert[fplace]);
789 while (zpadlen > 0) {
800 #endif /* FP_OUTPUT */
806 #define LONG_STRING 1024
810 char buf1[LONG_STRING];
811 char buf2[LONG_STRING];
830 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
831 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
855 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
869 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
887 char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
894 printf("Testing snprintf format codes against system sprintf...\n");
897 for (x = 0; fp_fmt[x] != NULL; x++)
898 for (y = 0; fp_nums[y] != 0; y++) {
899 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
900 sprintf(buf2, fp_fmt[x], fp_nums[y]);
901 if (strcmp(buf1, buf2)) {
903 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
904 fp_fmt[x], buf1, buf2);
911 for (x = 0; int_fmt[x] != NULL; x++)
912 for (y = 0; int_nums[y] != 0; y++) {
914 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
915 printf("%s\n", buf1);
916 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
917 if (bcount != pcount) {
918 printf("bsnprintf count %d doesn't match sprintf count %d\n",
921 if (strcmp(buf1, buf2)) {
923 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
924 int_fmt[x], buf1, buf2);
930 for (x = 0; ll_fmt[x] != NULL; x++) {
931 for (y = 0; ll_nums[y] != 0; y++) {
933 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
934 printf("%s\n", buf1);
935 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
936 if (bcount != pcount) {
937 printf("bsnprintf count %d doesn't match sprintf count %d\n",
940 if (strcmp(buf1, buf2)) {
942 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
943 ll_fmt[x], buf1, buf2);
950 for (x = 0; s_fmt[x] != NULL; x++) {
951 for (y = 0; s_nums[y] != 0; y++) {
953 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
954 printf("%s\n", buf1);
955 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
956 if (bcount != pcount) {
957 printf("bsnprintf count %d doesn't match sprintf count %d\n",
960 if (strcmp(buf1, buf2)) {
962 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
963 s_fmt[x], buf1, buf2);
971 printf("%d tests failed out of %d.\n", fail, num);
973 #endif /* TEST_PROGRAM */
975 #endif /* USE_BSNPRINTF */