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-2006 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 plus additions
26 that are listed in the file LICENSE.
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 John Walker.
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 */
48 /* Define the following if you want all the features of
49 * normal printf, but with all the security problems.
50 * For Bacula we turn this off, and it silently ignores
51 * formats that could pose a security problem.
53 #undef SECURITY_PROBLEM
57 #ifdef HAVE_LONG_DOUBLE
58 #define LDOUBLE long double
60 #define LDOUBLE double
63 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
64 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
65 char *value, int flags, int min, int max);
66 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
67 int64_t value, int base, int min, int max, int flags);
73 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
74 LDOUBLE fvalue, int min, int max, int flags);
76 #define fmtfp(b, c, m, f, min, max, fl) currlen
79 #define outch(c) {int len=currlen; if (currlen++ < maxlen) { buffer[len] = (c);}}
82 /* format read states */
83 #define DP_S_DEFAULT 0
92 /* format flags - Bits */
93 #define DP_F_MINUS (1 << 0)
94 #define DP_F_PLUS (1 << 1)
95 #define DP_F_SPACE (1 << 2)
96 #define DP_F_NUM (1 << 3)
97 #define DP_F_ZERO (1 << 4)
98 #define DP_F_UP (1 << 5)
99 #define DP_F_UNSIGNED (1 << 6)
100 #define DP_F_DOT (1 << 7)
102 /* Conversion Flags */
105 #define DP_C_LDOUBLE 3
108 #define char_to_int(p) ((p)- '0')
110 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
113 You might ask why does Bacula have it's own printf routine? Well,
114 There are two reasons: 1. Here (as opposed to library routines), we
115 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
116 disable %n for security reasons.
119 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
124 va_start(arg_ptr, fmt);
125 len = bvsnprintf(str, size, fmt, arg_ptr);
131 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
147 state = DP_S_DEFAULT;
148 currlen = flags = cflags = min = 0;
153 while (state != DP_S_DONE) {
154 if ((ch == '\0') || (currlen >= maxlen))
194 if (isdigit((unsigned char)ch)) {
195 min = 10 * min + char_to_int(ch);
197 } else if (ch == '*') {
198 min = va_arg(args, int);
213 if (isdigit((unsigned char)ch)) {
216 max = 10 * max + char_to_int(ch);
218 } else if (ch == '*') {
219 max = va_arg(args, int);
234 if (ch == 'l') { /* It's a long long */
240 cflags = DP_C_LDOUBLE;
243 case 'q': /* same as long long */
256 if (cflags == DP_C_INT16) {
257 value = va_arg(args, int32_t);
258 } else if (cflags == DP_C_INT32) {
259 value = va_arg(args, int32_t);
260 } else if (cflags == DP_C_INT64) {
261 value = va_arg(args, int64_t);
263 value = va_arg(args, int);
265 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
273 } else if (ch == 'x') {
275 } else if (ch == 'X') {
281 flags |= DP_F_UNSIGNED;
282 if (cflags == DP_C_INT16) {
283 value = va_arg(args, uint32_t);
284 } else if (cflags == DP_C_INT32) {
285 value = va_arg(args, uint32_t);
286 } else if (cflags == DP_C_INT64) {
287 value = va_arg(args, uint64_t);
289 value = va_arg(args, unsigned int);
291 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
294 if (cflags == DP_C_LDOUBLE) {
295 fvalue = va_arg(args, LDOUBLE);
297 fvalue = va_arg(args, double);
299 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
304 if (cflags == DP_C_LDOUBLE) {
305 fvalue = va_arg(args, LDOUBLE);
307 fvalue = va_arg(args, double);
309 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
314 if (cflags == DP_C_LDOUBLE) {
315 fvalue = va_arg(args, LDOUBLE);
317 fvalue = va_arg(args, double);
319 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
322 outch(va_arg(args, int));
325 strvalue = va_arg(args, char *);
326 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
329 flags |= DP_F_UNSIGNED;
330 if (sizeof(char *) == 4) {
331 value = va_arg(args, uint32_t);
332 } else if (sizeof(char *) == 8) {
333 value = va_arg(args, uint64_t);
335 value = (uint64_t)va_arg(args, char *);
337 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
340 if (cflags == DP_C_INT16) {
342 num = va_arg(args, int16_t *);
343 #ifdef SECURITY_PROBLEM
346 } else if (cflags == DP_C_INT32) {
348 num = va_arg(args, int32_t *);
349 #ifdef SECURITY_PROBLEM
350 *num = (int32_t)currlen;
352 } else if (cflags == DP_C_INT64) {
354 num = va_arg(args, int64_t *);
355 #ifdef SECURITY_PROBLEM
356 *num = (int64_t)currlen;
360 num = va_arg(args, int32_t *);
361 #ifdef SECURITY_PROBLEM
362 *num = (int32_t)currlen;
370 /* not supported yet, treat as next char */
378 state = DP_S_DEFAULT;
379 flags = cflags = min = 0;
386 break; /* some picky compilers need this */
389 if (currlen < maxlen - 1) {
390 buffer[currlen] = '\0';
392 buffer[maxlen - 1] = '\0';
397 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
398 char *value, int flags, int min, int max)
400 int padlen, strln; /* amount to pad */
407 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
409 } else if (max < 0) {
412 strln = strlen(value);
414 strln = max; /* truncate to max */
416 padlen = min - strln;
420 if (flags & DP_F_MINUS) {
421 padlen = -padlen; /* Left Justify */
428 while (*value && (cnt < max)) {
439 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
441 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
442 int64_t value, int base, int min, int max, int flags)
448 int spadlen = 0; /* amount to space pad */
449 int zpadlen = 0; /* amount to zero pad */
458 if (!(flags & DP_F_UNSIGNED)) {
462 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
464 } else if (flags & DP_F_SPACE) {
469 if (flags & DP_F_UP) {
470 caps = 1; /* Should characters be upper case? */
474 convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
475 [uvalue % (unsigned)base];
476 uvalue = (uvalue / (unsigned)base);
477 } while (uvalue && (place < 20));
483 zpadlen = max - place;
484 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
489 if (flags & DP_F_ZERO) {
490 zpadlen = MAX(zpadlen, spadlen);
493 if (flags & DP_F_MINUS)
494 spadlen = -spadlen; /* Left Justifty */
496 #ifdef DEBUG_SNPRINTF
497 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
498 zpadlen, spadlen, min, max, place);
502 while (spadlen > 0) {
514 while (zpadlen > 0) {
522 outch(convert[--place]);
525 /* Left Justified spaces */
526 while (spadlen < 0) {
535 static LDOUBLE abs_val(LDOUBLE value)
537 LDOUBLE result = value;
545 static LDOUBLE pow10(int exp)
557 static long round(LDOUBLE value)
561 intpart = (long)value;
562 value = value - intpart;
569 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
570 LDOUBLE fvalue, int min, int max, int flags)
583 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
587 int padlen = 0; /* amount to pad */
594 * AIX manpage says the default is 0, but Solaris says the default
595 * is 6, and sprintf on AIX defaults to 6
600 ufvalue = abs_val(fvalue);
604 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
606 else if (flags & DP_F_SPACE)
611 caps = 1; /* Should characters be upper case? */
615 intpart = (long)ufvalue;
618 * Sorry, we only support 9 digits past the decimal because of our
624 /* We "cheat" by converting the fractional part to integer by
625 * multiplying by a factor of 10
627 fracpart = round((pow10(max)) * (ufvalue - intpart));
629 if (fracpart >= pow10(max)) {
631 fracpart -= (int64_t)pow10(max);
633 #ifdef DEBUG_SNPRINTF
634 printf("fmtfp: %g %d.%d min=%d max=%d\n",
635 (double)fvalue, intpart, fracpart, min, max);
638 /* Convert integer part */
641 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
642 intpart = (intpart / 10);
643 } while (intpart && (iplace < 20));
646 iconvert[iplace] = 0;
648 /* Convert fractional part */
651 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
652 fracpart = (fracpart / 10);
653 } while (fracpart && (fplace < 20));
656 fconvert[fplace] = 0;
657 #else /* use fcvt() */
661 result = fcvtl(ufvalue, max, &dec_pt, &sig);
663 result = fcvt(ufvalue, max, &dec_pt, &sig);
666 r_length = strlen(result);
669 * Fix broken fcvt implementation returns..
678 if (r_length < dec_pt)
689 fconvert[fplace++] = result[--r_length];
691 while ((dec_pt < 0) && (fplace < max)) {
692 fconvert[fplace++] = '0';
699 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
700 iconvert[iplace] = '\0';
705 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
707 #endif /* HAVE_FCVT */
709 /* -1 for decimal point, another -1 if we are printing a sign */
710 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
711 zpadlen = max - fplace;
718 if (flags & DP_F_MINUS) {
719 padlen = -padlen; /* Left Justifty */
722 if ((flags & DP_F_ZERO) && (padlen > 0)) {
742 outch(iconvert[--iplace]);
746 #ifdef DEBUG_SNPRINTF
747 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
751 * Decimal point. This should probably use locale to find the correct
757 outch(fconvert[--fplace]);
761 while (zpadlen > 0) {
772 #endif /* FP_OUTPUT */
778 #define LONG_STRING 1024
782 char buf1[LONG_STRING];
783 char buf2[LONG_STRING];
802 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
803 0.9996, 1.996, 4.136, 6442452944.1234, 0
827 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
841 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
859 char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
866 printf("Testing snprintf format codes against system sprintf...\n");
869 for (x = 0; fp_fmt[x] != NULL; x++)
870 for (y = 0; fp_nums[y] != 0; y++) {
871 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
872 sprintf(buf2, fp_fmt[x], fp_nums[y]);
873 if (strcmp(buf1, buf2)) {
875 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
876 fp_fmt[x], buf1, buf2);
883 for (x = 0; int_fmt[x] != NULL; x++)
884 for (y = 0; int_nums[y] != 0; y++) {
886 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
887 printf("%s\n", buf1);
888 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
889 if (bcount != pcount) {
890 printf("bsnprintf count %d doesn't match sprintf count %d\n",
893 if (strcmp(buf1, buf2)) {
895 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
896 int_fmt[x], buf1, buf2);
902 for (x = 0; ll_fmt[x] != NULL; x++) {
903 for (y = 0; ll_nums[y] != 0; y++) {
905 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
906 printf("%s\n", buf1);
907 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
908 if (bcount != pcount) {
909 printf("bsnprintf count %d doesn't match sprintf count %d\n",
912 if (strcmp(buf1, buf2)) {
914 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
915 ll_fmt[x], buf1, buf2);
922 for (x = 0; s_fmt[x] != NULL; x++) {
923 for (y = 0; s_nums[y] != 0; y++) {
925 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
926 printf("%s\n", buf1);
927 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
928 if (bcount != pcount) {
929 printf("bsnprintf count %d doesn't match sprintf count %d\n",
932 if (strcmp(buf1, buf2)) {
934 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
935 s_fmt[x], buf1, buf2);
943 printf("%d tests failed out of %d.\n", fail, num);
945 #endif /* TEST_PROGRAM */
947 #endif /* USE_BSNPRINTF */