+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2005-2014 Free Software Foundation Europe e.V.
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+*/
/*
* Copyright Patrick Powell 1995
*
*
* Kern Sibbald, November MMV
*
- * Version $Id$
*/
-/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
- License as published by the Free Software Foundation plus additions
- that are listed in the file LICENSE.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of John Walker.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
-*/
#include "bacula.h"
+#include <wchar.h>
+
#define FP_OUTPUT 1 /* Bacula uses floating point */
+
/* Define the following if you want all the features of
* normal printf, but with all the security problems.
* For Bacula we turn this off, and it silently ignores
* formats that could pose a security problem.
*/
-#undef SECURITY_PROBLEM
+#undef SECURITY_PROBLEM
#ifdef USE_BSNPRINTF
int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
- char *value, int flags, int min, int max);
+ const char *value, int flags, int min, int max);
+static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
+ const wchar_t *value, int flags, int min, int max);
static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
int64_t value, int base, int min, int max, int flags);
#define fmtfp(b, c, m, f, min, max, fl) currlen
#endif
-#define outch(c) {int len=currlen; if (currlen++ < maxlen) { buffer[len] = (c);}}
-
+/*
+ * NOTE!!!! do not use this #define with a construct such
+ * as outch(--place);. It just will NOT work, because the
+ * decrement of place is done ONLY if there is room in the
+ * output buffer.
+ */
+#define outch(c) {int len=currlen; if (currlen < maxlen) \
+ { buffer[len] = (c); currlen++; }}
/* format read states */
#define DP_S_DEFAULT 0
#define DP_F_DOT (1 << 7)
/* Conversion Flags */
-#define DP_C_INT16 1
+#define DP_C_INT16 1
#define DP_C_INT32 2
-#define DP_C_LDOUBLE 3
-#define DP_C_INT64 4
+#define DP_C_LDOUBLE 3
+#define DP_C_INT64 4
+#define DP_C_WCHAR 5 /* wide characters */
+#define DP_C_SIZE_T 6
#define char_to_int(p) ((p)- '0')
#undef MAX
/*
You might ask why does Bacula have it's own printf routine? Well,
There are two reasons: 1. Here (as opposed to library routines), we
- define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
- disable %n for security reasons.
+ define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
+ disable %n for security reasons.
*/
int bsnprintf(char *str, int32_t size, const char *fmt, ...)
char ch;
int64_t value;
char *strvalue;
+ wchar_t *wstrvalue;
int min;
int max;
int state;
*buffer = 0;
while (state != DP_S_DONE) {
- if ((ch == '\0') || (currlen >= maxlen))
+ if ((ch == '\0') || (currlen >= maxlen)) {
state = DP_S_DONE;
-
+ }
switch (state) {
case DP_S_DEFAULT:
if (ch == '%') {
case 'l':
cflags = DP_C_INT32;
ch = *format++;
- if (ch == 'l') { /* It's a long long */
+ if (ch == 's') {
+ cflags = DP_C_WCHAR;
+ } else if (ch == 'l') { /* It's a long long */
cflags = DP_C_INT64;
ch = *format++;
}
break;
+ case 'z':
+ cflags = DP_C_SIZE_T;
+ ch = *format++;
+ break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
value = va_arg(args, int32_t);
} else if (cflags == DP_C_INT64) {
value = va_arg(args, int64_t);
+ } else if (cflags == DP_C_SIZE_T) {
+ value = va_arg(args, ssize_t);
} else {
value = va_arg(args, int);
}
value = va_arg(args, uint32_t);
} else if (cflags == DP_C_INT64) {
value = va_arg(args, uint64_t);
+ } else if (cflags == DP_C_SIZE_T) {
+ value = va_arg(args, size_t);
} else {
value = va_arg(args, unsigned int);
}
currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
break;
case 'c':
- outch(va_arg(args, int));
+ ch = va_arg(args, int);
+ outch(ch);
break;
case 's':
- strvalue = va_arg(args, char *);
- currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
+ if (cflags != DP_C_WCHAR) {
+ strvalue = va_arg(args, char *);
+ if (!strvalue) {
+ strvalue = (char *)"<NULL>";
+ }
+ currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
+ } else {
+ /* %ls means to edit wide characters */
+ wstrvalue = va_arg(args, wchar_t *);
+ if (!wstrvalue) {
+ wstrvalue = (wchar_t *)L"<NULL>";
+ }
+ currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
+ }
break;
case 'p':
flags |= DP_F_UNSIGNED;
- strvalue = va_arg(args, char *);
- currlen = fmtint(buffer, currlen, maxlen, (long)strvalue, 16, min, max, flags);
+ if (sizeof(char *) == 4) {
+ value = va_arg(args, uint32_t);
+ } else if (sizeof(char *) == 8) {
+ value = va_arg(args, uint64_t);
+ } else {
+ value = 0; /* we have a problem */
+ }
+ currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
break;
+
+#ifdef SECURITY_PROBLEM
case 'n':
if (cflags == DP_C_INT16) {
int16_t *num;
num = va_arg(args, int16_t *);
-#ifdef SECURITY_PROBLEM
*num = currlen;
-#endif
} else if (cflags == DP_C_INT32) {
int32_t *num;
num = va_arg(args, int32_t *);
-#ifdef SECURITY_PROBLEM
*num = (int32_t)currlen;
-#endif
} else if (cflags == DP_C_INT64) {
int64_t *num;
num = va_arg(args, int64_t *);
-#ifdef SECURITY_PROBLEM
*num = (int64_t)currlen;
-#endif
} else {
int32_t *num;
num = va_arg(args, int32_t *);
-#ifdef SECURITY_PROBLEM
*num = (int32_t)currlen;
-#endif
}
break;
+#endif
case '%':
outch(ch);
break;
}
static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
- char *value, int flags, int min, int max)
+ const char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
+ char ch;
- if (value == 0) {
- value = "<NULL>";
- }
if (flags & DP_F_DOT && max < 0) { /* Max not specified */
max = 0;
--padlen;
}
while (*value && (cnt < max)) {
- outch(*value++);
+ ch = *value++;
+ outch(ch);
+ ++cnt;
+ }
+ while (padlen < 0) {
+ outch(' ');
+ ++padlen;
+ }
+ return currlen;
+}
+
+static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
+ const wchar_t *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+ char ch;
+
+
+ if (flags & DP_F_DOT && max < 0) { /* Max not specified */
+ max = 0;
+ } else if (max < 0) {
+ max = maxlen;
+ }
+ strln = wcslen(value);
+ if (strln > max) {
+ strln = max; /* truncate to max */
+ }
+ padlen = min - strln;
+ if (padlen < 0) {
+ padlen = 0;
+ }
+ if (flags & DP_F_MINUS) {
+ padlen = -padlen; /* Left Justify */
+ }
+
+ while (padlen > 0) {
+ outch(' ');
+ --padlen;
+ }
+ while (*value && (cnt < max)) {
+
+ ch = (*value++) & 0xff;
+ outch(ch);
++cnt;
}
while (padlen < 0) {
{
int signvalue = 0;
uint64_t uvalue;
- char convert[20];
+ char convert[25];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
+ const char *cvt_string;
if (max < 0) {
max = 0;
caps = 1; /* Should characters be upper case? */
}
+ cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
do {
- convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
- [uvalue % (unsigned)base];
+ convert[place++] = cvt_string[uvalue % (unsigned)base];
uvalue = (uvalue / (unsigned)base);
- } while (uvalue && (place < 20));
- if (place == 20) {
+ } while (uvalue && (place < (int)sizeof(convert)));
+ if (place == (int)sizeof(convert)) {
place--;
}
convert[place] = 0;
}
}
- /* Digits */
+ /* Output digits backward giving correct order */
while (place > 0) {
- outch(convert[--place]);
+ place--;
+ outch(convert[place]);
}
/* Left Justified spaces */
return result;
}
-static long round(LDOUBLE value)
+static int64_t round(LDOUBLE value)
{
- long intpart;
+ int64_t intpart;
- intpart = (long)value;
+ intpart = (int64_t)value;
value = value - intpart;
if (value >= 0.5)
intpart++;
int signvalue = 0;
LDOUBLE ufvalue;
#ifndef HAVE_FCVT
- char iconvert[20];
- char fconvert[20];
+ char iconvert[311];
+ char fconvert[311];
#else
char iconvert[311];
char fconvert[311];
char *result;
+ char dummy[10];
int dec_pt, sig;
int r_length;
extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
- int caps = 0;
int64_t intpart;
int64_t fracpart;
+ const char *cvt_str;
- /*
+ /*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
else if (flags & DP_F_SPACE)
signvalue = ' ';
-#if 0
- if (flags & DP_F_UP)
- caps = 1; /* Should characters be upper case? */
-#endif
-
#ifndef HAVE_FCVT
- intpart = (long)ufvalue;
+ intpart = (int64_t)ufvalue;
- /*
- * Sorry, we only support 9 digits past the decimal because of our
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
* conversion method
*/
if (max > 9)
intpart++;
fracpart -= (int64_t)pow10(max);
}
+
#ifdef DEBUG_SNPRINTF
- printf("fmtfp: %g %d.%d min=%d max=%d\n",
+ printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
(double)fvalue, intpart, fracpart, min, max);
#endif
/* Convert integer part */
+ cvt_str = "0123456789";
do {
- iconvert[iplace++] =
- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
+ iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
intpart = (intpart / 10);
- } while (intpart && (iplace < 20));
- if (iplace == 20)
+ } while (intpart && (iplace < (int)sizeof(iconvert)));
+
+ if (iplace == (int)sizeof(fconvert)) {
iplace--;
+ }
iconvert[iplace] = 0;
/* Convert fractional part */
- do {
- fconvert[fplace++] =
- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
+ cvt_str = "0123456789";
+ for (int fiter = max; fiter > 0; fiter--) {
+ fconvert[fplace++] = cvt_str[fracpart % 10];
fracpart = (fracpart / 10);
- } while (fracpart && (fplace < 20));
- if (fplace == 20)
+ }
+
+ if (fplace == (int)sizeof(fconvert)) {
fplace--;
+ }
fconvert[fplace] = 0;
#else /* use fcvt() */
- if (max > 310)
+ if (max > 310) {
max = 310;
+ }
# ifdef HAVE_FCVTL
result = fcvtl(ufvalue, max, &dec_pt, &sig);
# else
result = fcvt(ufvalue, max, &dec_pt, &sig);
# endif
- r_length = strlen(result);
+ if (!result) {
+ r_length = 0;
+ dummy[0] = 0;
+ result = dummy;
+ } else {
+ r_length = strlen(result);
+ }
/*
* Fix broken fcvt implementation returns..
fplace = 0;
- while (r_length)
+ while (r_length) {
fconvert[fplace++] = result[--r_length];
+ }
while ((dec_pt < 0) && (fplace < max)) {
fconvert[fplace++] = '0';
}
while (iplace > 0) {
- outch(iconvert[--iplace]);
+ iplace--;
+ outch(iconvert[iplace]);
}
if (max > 0) {
outch('.');
while (fplace > 0) {
- outch(fconvert[--fplace]);
+ fplace--;
+ outch(fconvert[fplace]);
}
}
#ifndef LONG_STRING
#define LONG_STRING 1024
#endif
-int main(void)
+
+int main(int argc, char *argv[])
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
#ifdef FP_OUTPUT
- char *fp_fmt[] = {
+ const char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%3.2f",
"%.0f",
"%.1f",
+ "%.2f",
NULL
};
- double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
- 0.9996, 1.996, 4.136, 6442452944.1234, 0
+ double fp_nums[] = { 1.05, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
+ 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
};
#endif
- char *int_fmt[] = {
+ const char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
- char *ll_fmt[] = {
+ const char *ll_fmt[] = {
"%-1.8lld",
"%1.8lld",
"%123.9lld",
};
int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
- char *s_fmt[] = {
+ const char *s_fmt[] = {
"%-1.8s",
"%1.8s",
"%123.9s",
"%3.s",
NULL
};
- char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
-
+ const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
+
+ const char *ls_fmt[] = {
+ "%-1.8ls",
+ "%1.8ls",
+ "%123.9ls",
+ "%5.8ls",
+ "%10.5ls",
+ "% 10.3ls",
+ "%+22.1ls",
+ "%01.3ls",
+ "%ls",
+ "%10ls",
+ "%3ls",
+ "%3.0ls",
+ "%3.ls",
+ NULL
+ };
+ const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
int x, y;
int fail = 0;
}
}
+ for (x = 0; ls_fmt[x] != NULL; x++) {
+ for (y = 0; ls_nums[y] != 0; y++) {
+ int pcount, bcount;
+ bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
+ printf("%s\n", buf1);
+ pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
+ if (bcount != pcount) {
+ printf("bsnprintf count %d doesn't match sprintf count %d\n",
+ bcount, pcount);
+ }
+ if (strcmp(buf1, buf2)) {
+ printf
+ ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
+ ls_fmt[x], buf1, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+
printf("%d tests failed out of %d.\n", fail, num);
+
+ exit(fail > 0);
}
#endif /* TEST_PROGRAM */