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-2007 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 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 */
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
80 #define outch(c) {if (currlen < maxlen) { buffer[currlen++] = (c);}}
83 /* format read states */
84 #define DP_S_DEFAULT 0
93 /* format flags - Bits */
94 #define DP_F_MINUS (1 << 0)
95 #define DP_F_PLUS (1 << 1)
96 #define DP_F_SPACE (1 << 2)
97 #define DP_F_NUM (1 << 3)
98 #define DP_F_ZERO (1 << 4)
99 #define DP_F_UP (1 << 5)
100 #define DP_F_UNSIGNED (1 << 6)
101 #define DP_F_DOT (1 << 7)
103 /* Conversion Flags */
106 #define DP_C_LDOUBLE 3
109 #define char_to_int(p) ((p)- '0')
111 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
114 You might ask why does Bacula have it's own printf routine? Well,
115 There are two reasons: 1. Here (as opposed to library routines), we
116 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
117 disable %n for security reasons.
120 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
125 va_start(arg_ptr, fmt);
126 len = bvsnprintf(str, size, fmt, arg_ptr);
132 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
148 state = DP_S_DEFAULT;
149 currlen = flags = cflags = min = 0;
154 while (state != DP_S_DONE) {
155 if ((ch == '\0') || (currlen >= maxlen)) {
195 if (isdigit((unsigned char)ch)) {
196 min = 10 * min + char_to_int(ch);
198 } else if (ch == '*') {
199 min = va_arg(args, int);
214 if (isdigit((unsigned char)ch)) {
217 max = 10 * max + char_to_int(ch);
219 } else if (ch == '*') {
220 max = va_arg(args, int);
235 if (ch == 'l') { /* It's a long long */
241 cflags = DP_C_LDOUBLE;
244 case 'q': /* same as long long */
257 if (cflags == DP_C_INT16) {
258 value = va_arg(args, int32_t);
259 } else if (cflags == DP_C_INT32) {
260 value = va_arg(args, int32_t);
261 } else if (cflags == DP_C_INT64) {
262 value = va_arg(args, int64_t);
264 value = va_arg(args, int);
266 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
274 } else if (ch == 'x') {
276 } else if (ch == 'X') {
282 flags |= DP_F_UNSIGNED;
283 if (cflags == DP_C_INT16) {
284 value = va_arg(args, uint32_t);
285 } else if (cflags == DP_C_INT32) {
286 value = va_arg(args, uint32_t);
287 } else if (cflags == DP_C_INT64) {
288 value = va_arg(args, uint64_t);
290 value = va_arg(args, unsigned int);
292 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
295 if (cflags == DP_C_LDOUBLE) {
296 fvalue = va_arg(args, LDOUBLE);
298 fvalue = va_arg(args, double);
300 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
305 if (cflags == DP_C_LDOUBLE) {
306 fvalue = va_arg(args, LDOUBLE);
308 fvalue = va_arg(args, double);
310 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
315 if (cflags == DP_C_LDOUBLE) {
316 fvalue = va_arg(args, LDOUBLE);
318 fvalue = va_arg(args, double);
320 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
323 outch(va_arg(args, int));
326 strvalue = va_arg(args, char *);
327 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
330 flags |= DP_F_UNSIGNED;
331 if (sizeof(char *) == 4) {
332 value = va_arg(args, uint32_t);
333 } else if (sizeof(char *) == 8) {
334 value = va_arg(args, uint64_t);
336 value = 0; /* we have a problem */
338 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
341 if (cflags == DP_C_INT16) {
343 num = va_arg(args, int16_t *);
344 #ifdef SECURITY_PROBLEM
347 } else if (cflags == DP_C_INT32) {
349 num = va_arg(args, int32_t *);
350 #ifdef SECURITY_PROBLEM
351 *num = (int32_t)currlen;
353 } else if (cflags == DP_C_INT64) {
355 num = va_arg(args, int64_t *);
356 #ifdef SECURITY_PROBLEM
357 *num = (int64_t)currlen;
361 num = va_arg(args, int32_t *);
362 #ifdef SECURITY_PROBLEM
363 *num = (int32_t)currlen;
371 /* not supported yet, treat as next char */
379 state = DP_S_DEFAULT;
380 flags = cflags = min = 0;
387 break; /* some picky compilers need this */
390 if (currlen < maxlen - 1) {
391 buffer[currlen] = '\0';
393 buffer[maxlen - 1] = '\0';
398 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
399 const char *value, int flags, int min, int max)
401 int padlen, strln; /* amount to pad */
405 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
407 } else if (max < 0) {
413 strln = strlen(value);
415 strln = max; /* truncate to max */
417 padlen = min - strln;
421 if (flags & DP_F_MINUS) {
422 padlen = -padlen; /* Left Justify */
429 while (*value && (cnt < max)) {
440 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
442 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
443 int64_t value, int base, int min, int max, int flags)
449 int spadlen = 0; /* amount to space pad */
450 int zpadlen = 0; /* amount to zero pad */
452 const char *cvt_string;
460 if (!(flags & DP_F_UNSIGNED)) {
464 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
466 } else if (flags & DP_F_SPACE) {
471 if (flags & DP_F_UP) {
472 caps = 1; /* Should characters be upper case? */
475 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
477 convert[place++] = cvt_string[uvalue % (unsigned)base];
478 uvalue = (uvalue / (unsigned)base);
479 } while (uvalue && (place < (int)sizeof(convert)));
480 if (place == (int)sizeof(convert)) {
485 zpadlen = max - place;
486 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
491 if (flags & DP_F_ZERO) {
492 zpadlen = MAX(zpadlen, spadlen);
495 if (flags & DP_F_MINUS)
496 spadlen = -spadlen; /* Left Justifty */
498 #ifdef DEBUG_SNPRINTF
499 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
500 zpadlen, spadlen, min, max, place);
504 while (spadlen > 0) {
516 while (zpadlen > 0) {
524 outch(convert[--place]);
527 /* Left Justified spaces */
528 while (spadlen < 0) {
537 static LDOUBLE abs_val(LDOUBLE value)
539 LDOUBLE result = value;
547 static LDOUBLE pow10(int exp)
559 static long round(LDOUBLE value)
563 intpart = (long)value;
564 value = value - intpart;
571 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
572 LDOUBLE fvalue, int min, int max, int flags)
586 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
590 int padlen = 0; /* amount to pad */
597 * AIX manpage says the default is 0, but Solaris says the default
598 * is 6, and sprintf on AIX defaults to 6
603 ufvalue = abs_val(fvalue);
607 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
609 else if (flags & DP_F_SPACE)
614 caps = 1; /* Should characters be upper case? */
618 intpart = (long)ufvalue;
621 * Sorry, we only support 9 digits past the decimal because of our
627 /* We "cheat" by converting the fractional part to integer by
628 * multiplying by a factor of 10
630 fracpart = round((pow10(max)) * (ufvalue - intpart));
632 if (fracpart >= pow10(max)) {
634 fracpart -= (int64_t)pow10(max);
637 #ifdef DEBUG_SNPRINTF
638 printf("fmtfp: %g %d.%d min=%d max=%d\n",
639 (double)fvalue, intpart, fracpart, min, max);
642 /* Convert integer part */
645 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
646 intpart = (intpart / 10);
647 } while (intpart && (iplace < 20));
650 iconvert[iplace] = 0;
652 /* Convert fractional part */
655 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
656 fracpart = (fracpart / 10);
657 } while (fracpart && (fplace < 20));
660 fconvert[fplace] = 0;
661 #else /* use fcvt() */
665 result = fcvtl(ufvalue, max, &dec_pt, &sig);
667 result = fcvt(ufvalue, max, &dec_pt, &sig);
674 r_length = strlen(result);
678 * Fix broken fcvt implementation returns..
687 if (r_length < dec_pt)
698 fconvert[fplace++] = result[--r_length];
701 while ((dec_pt < 0) && (fplace < max)) {
702 fconvert[fplace++] = '0';
709 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
710 iconvert[iplace] = '\0';
715 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
717 #endif /* HAVE_FCVT */
719 /* -1 for decimal point, another -1 if we are printing a sign */
720 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
721 zpadlen = max - fplace;
728 if (flags & DP_F_MINUS) {
729 padlen = -padlen; /* Left Justifty */
732 if ((flags & DP_F_ZERO) && (padlen > 0)) {
752 outch(iconvert[--iplace]);
756 #ifdef DEBUG_SNPRINTF
757 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
761 * Decimal point. This should probably use locale to find the correct
767 outch(fconvert[--fplace]);
771 while (zpadlen > 0) {
782 #endif /* FP_OUTPUT */
788 #define LONG_STRING 1024
792 char buf1[LONG_STRING];
793 char buf2[LONG_STRING];
812 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
813 0.9996, 1.996, 4.136, 6442452944.1234, 0
837 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
851 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
869 char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
876 printf("Testing snprintf format codes against system sprintf...\n");
879 for (x = 0; fp_fmt[x] != NULL; x++)
880 for (y = 0; fp_nums[y] != 0; y++) {
881 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
882 sprintf(buf2, fp_fmt[x], fp_nums[y]);
883 if (strcmp(buf1, buf2)) {
885 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
886 fp_fmt[x], buf1, buf2);
893 for (x = 0; int_fmt[x] != NULL; x++)
894 for (y = 0; int_nums[y] != 0; y++) {
896 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
897 printf("%s\n", buf1);
898 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
899 if (bcount != pcount) {
900 printf("bsnprintf count %d doesn't match sprintf count %d\n",
903 if (strcmp(buf1, buf2)) {
905 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
906 int_fmt[x], buf1, buf2);
912 for (x = 0; ll_fmt[x] != NULL; x++) {
913 for (y = 0; ll_nums[y] != 0; y++) {
915 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
916 printf("%s\n", buf1);
917 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
918 if (bcount != pcount) {
919 printf("bsnprintf count %d doesn't match sprintf count %d\n",
922 if (strcmp(buf1, buf2)) {
924 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
925 ll_fmt[x], buf1, buf2);
932 for (x = 0; s_fmt[x] != NULL; x++) {
933 for (y = 0; s_nums[y] != 0; y++) {
935 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
936 printf("%s\n", buf1);
937 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
938 if (bcount != pcount) {
939 printf("bsnprintf count %d doesn't match sprintf count %d\n",
942 if (strcmp(buf1, buf2)) {
944 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
945 s_fmt[x], buf1, buf2);
953 printf("%d tests failed out of %d.\n", fail, num);
955 #endif /* TEST_PROGRAM */
957 #endif /* USE_BSNPRINTF */