1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Copyright Patrick Powell 1995
21 *
22 * This code is based on code written by Patrick Powell
23 * (papowell@astart.com) It may be used for any purpose as long
24 * as this notice remains intact on all source code distributions.
25 *
26 * Adapted for Bacula -- note there were lots of bugs in
27 * the original code: %lld and %s were seriously broken, and
28 * with FP turned off %f seg faulted.
29 *
30 * Kern Sibbald, November MMV
31 *
32 */
33
34
35
36 #include "bacula.h"
37 #include <wchar.h>
38
39 #define FP_OUTPUT 1 /* Bacula uses floating point */
40
41 /* Define the following if you want all the features of
42 * normal printf, but with all the security problems.
43 * For Bacula we turn this off, and it silently ignores
44 * formats that could pose a security problem.
45 */
46 #undef SECURITY_PROBLEM
47
48 #ifdef USE_BSNPRINTF
49
50 #ifdef HAVE_LONG_DOUBLE
51 #define LDOUBLE long double
52 #else
53 #define LDOUBLE double
54 #endif
55
56 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
57 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
58 const char *value, int flags, int min, int max);
59 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
60 const wchar_t *value, int flags, int min, int max);
61 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
62 int64_t value, int base, int min, int max, int flags);
63
64 #ifdef FP_OUTPUT
65 # ifdef HAVE_FCVTL
66 # define fcvt fcvtl
67 # endif
68 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
69 LDOUBLE fvalue, int min, int max, int flags);
70 #else
71 #define fmtfp(b, c, m, f, min, max, fl) currlen
72 #endif
73
74 /*
75 * NOTE!!!! do not use this #define with a construct such
76 * as outch(--place);. It just will NOT work, because the
77 * decrement of place is done ONLY if there is room in the
78 * output buffer.
79 */
80 #define outch(c) {int len=currlen; if (currlen < maxlen) \
81 { buffer[len] = (c); currlen++; }}
82
83 /* format read states */
84 #define DP_S_DEFAULT 0
85 #define DP_S_FLAGS 1
86 #define DP_S_MIN 2
87 #define DP_S_DOT 3
88 #define DP_S_MAX 4
89 #define DP_S_MOD 5
90 #define DP_S_CONV 6
91 #define DP_S_DONE 7
92
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)
102
103 /* Conversion Flags */
104 #define DP_C_INT16 1
105 #define DP_C_INT32 2
106 #define DP_C_LDOUBLE 3
107 #define DP_C_INT64 4
108 #define DP_C_WCHAR 5 /* wide characters */
109 #define DP_C_SIZE_T 6
110
111 #define char_to_int(p) ((p)- '0')
112 #undef MAX
113 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
114
115 /*
116 You might ask why does Bacula have it's own printf routine? Well,
117 There are two reasons: 1. Here (as opposed to library routines), we
118 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
119 disable %n for security reasons.
120 */
121
bsnprintf(char * str,int32_t size,const char * fmt,...)122 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
123 {
124 va_list arg_ptr;
125 int len;
126
127 va_start(arg_ptr, fmt);
128 len = bvsnprintf(str, size, fmt, arg_ptr);
129 va_end(arg_ptr);
130 return len;
131 }
132
133
bvsnprintf(char * buffer,int32_t maxlen,const char * format,va_list args)134 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
135 {
136 char ch;
137 int64_t value;
138 char *strvalue;
139 wchar_t *wstrvalue;
140 int min;
141 int max;
142 int state;
143 int flags;
144 int cflags;
145 int32_t currlen;
146 int base;
147 #ifdef FP_OUTPUT
148 LDOUBLE fvalue;
149 #endif
150
151 state = DP_S_DEFAULT;
152 currlen = flags = cflags = min = 0;
153 max = -1;
154 ch = *format++;
155 *buffer = 0;
156
157 while (state != DP_S_DONE) {
158 if ((ch == '\0') || (currlen >= maxlen)) {
159 state = DP_S_DONE;
160 }
161 switch (state) {
162 case DP_S_DEFAULT:
163 if (ch == '%') {
164 state = DP_S_FLAGS;
165 } else {
166 outch(ch);
167 }
168 ch = *format++;
169 break;
170 case DP_S_FLAGS:
171 switch (ch) {
172 case '-':
173 flags |= DP_F_MINUS;
174 ch = *format++;
175 break;
176 case '+':
177 flags |= DP_F_PLUS;
178 ch = *format++;
179 break;
180 case ' ':
181 flags |= DP_F_SPACE;
182 ch = *format++;
183 break;
184 case '#':
185 flags |= DP_F_NUM;
186 ch = *format++;
187 break;
188 case '0':
189 flags |= DP_F_ZERO;
190 ch = *format++;
191 break;
192 default:
193 state = DP_S_MIN;
194 break;
195 }
196 break;
197 case DP_S_MIN:
198 if (isdigit((unsigned char)ch)) {
199 min = 10 * min + char_to_int(ch);
200 ch = *format++;
201 } else if (ch == '*') {
202 min = va_arg(args, int);
203 ch = *format++;
204 state = DP_S_DOT;
205 } else
206 state = DP_S_DOT;
207 break;
208 case DP_S_DOT:
209 if (ch == '.') {
210 state = DP_S_MAX;
211 flags |= DP_F_DOT;
212 ch = *format++;
213 } else
214 state = DP_S_MOD;
215 break;
216 case DP_S_MAX:
217 if (isdigit((unsigned char)ch)) {
218 if (max < 0)
219 max = 0;
220 max = 10 * max + char_to_int(ch);
221 ch = *format++;
222 } else if (ch == '*') {
223 max = va_arg(args, int);
224 ch = *format++;
225 state = DP_S_MOD;
226 } else
227 state = DP_S_MOD;
228 break;
229 case DP_S_MOD:
230 switch (ch) {
231 case 'h':
232 cflags = DP_C_INT16;
233 ch = *format++;
234 break;
235 case 'l':
236 cflags = DP_C_INT32;
237 ch = *format++;
238 if (ch == 's') {
239 cflags = DP_C_WCHAR;
240 } else if (ch == 'l') { /* It's a long long */
241 cflags = DP_C_INT64;
242 ch = *format++;
243 }
244 break;
245 case 'z':
246 cflags = DP_C_SIZE_T;
247 ch = *format++;
248 break;
249 case 'L':
250 cflags = DP_C_LDOUBLE;
251 ch = *format++;
252 break;
253 case 'q': /* same as long long */
254 cflags = DP_C_INT64;
255 ch = *format++;
256 break;
257 default:
258 break;
259 }
260 state = DP_S_CONV;
261 break;
262 case DP_S_CONV:
263 switch (ch) {
264 case 'd':
265 case 'i':
266 if (cflags == DP_C_INT16) {
267 value = va_arg(args, int32_t);
268 } else if (cflags == DP_C_INT32) {
269 value = va_arg(args, int32_t);
270 } else if (cflags == DP_C_INT64) {
271 value = va_arg(args, int64_t);
272 } else if (cflags == DP_C_SIZE_T) {
273 value = va_arg(args, ssize_t);
274 } else {
275 value = va_arg(args, int);
276 }
277 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
278 break;
279 case 'X':
280 case 'x':
281 case 'o':
282 case 'u':
283 if (ch == 'o') {
284 base = 8;
285 } else if (ch == 'x') {
286 base = 16;
287 } else if (ch == 'X') {
288 base = 16;
289 flags |= DP_F_UP;
290 } else {
291 base = 10;
292 }
293 flags |= DP_F_UNSIGNED;
294 if (cflags == DP_C_INT16) {
295 value = va_arg(args, uint32_t);
296 } else if (cflags == DP_C_INT32) {
297 value = va_arg(args, uint32_t);
298 } else if (cflags == DP_C_INT64) {
299 value = va_arg(args, uint64_t);
300 } else if (cflags == DP_C_SIZE_T) {
301 value = va_arg(args, size_t);
302 } else {
303 value = va_arg(args, unsigned int);
304 }
305 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
306 break;
307 case 'f':
308 if (cflags == DP_C_LDOUBLE) {
309 fvalue = va_arg(args, LDOUBLE);
310 } else {
311 fvalue = va_arg(args, double);
312 }
313 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
314 break;
315 case 'E':
316 flags |= DP_F_UP;
317 case 'e':
318 if (cflags == DP_C_LDOUBLE) {
319 fvalue = va_arg(args, LDOUBLE);
320 } else {
321 fvalue = va_arg(args, double);
322 }
323 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
324 break;
325 case 'G':
326 flags |= DP_F_UP;
327 case 'g':
328 if (cflags == DP_C_LDOUBLE) {
329 fvalue = va_arg(args, LDOUBLE);
330 } else {
331 fvalue = va_arg(args, double);
332 }
333 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
334 break;
335 case 'c':
336 ch = va_arg(args, int);
337 outch(ch);
338 break;
339 case 's':
340 if (cflags != DP_C_WCHAR) {
341 strvalue = va_arg(args, char *);
342 if (!strvalue) {
343 strvalue = (char *)"<NULL>";
344 }
345 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
346 } else {
347 /* %ls means to edit wide characters */
348 wstrvalue = va_arg(args, wchar_t *);
349 if (!wstrvalue) {
350 wstrvalue = (wchar_t *)L"<NULL>";
351 }
352 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
353 }
354 break;
355 case 'p':
356 flags |= DP_F_UNSIGNED;
357 if (sizeof(char *) == 4) {
358 value = va_arg(args, uint32_t);
359 } else if (sizeof(char *) == 8) {
360 value = va_arg(args, uint64_t);
361 } else {
362 value = 0; /* we have a problem */
363 }
364 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
365 break;
366
367 #ifdef SECURITY_PROBLEM
368 case 'n':
369 if (cflags == DP_C_INT16) {
370 int16_t *num;
371 num = va_arg(args, int16_t *);
372 *num = currlen;
373 } else if (cflags == DP_C_INT32) {
374 int32_t *num;
375 num = va_arg(args, int32_t *);
376 *num = (int32_t)currlen;
377 } else if (cflags == DP_C_INT64) {
378 int64_t *num;
379 num = va_arg(args, int64_t *);
380 *num = (int64_t)currlen;
381 } else {
382 int32_t *num;
383 num = va_arg(args, int32_t *);
384 *num = (int32_t)currlen;
385 }
386 break;
387 #endif
388 case '%':
389 outch(ch);
390 break;
391 case 'w':
392 /* not supported yet, treat as next char */
393 ch = *format++;
394 break;
395 default:
396 /* Unknown, skip */
397 break;
398 }
399 ch = *format++;
400 state = DP_S_DEFAULT;
401 flags = cflags = min = 0;
402 max = -1;
403 break;
404 case DP_S_DONE:
405 break;
406 default:
407 /* hmm? */
408 break; /* some picky compilers need this */
409 }
410 }
411 if (currlen < maxlen - 1) {
412 buffer[currlen] = '\0';
413 } else {
414 buffer[maxlen - 1] = '\0';
415 }
416 return currlen;
417 }
418
fmtstr(char * buffer,int32_t currlen,int32_t maxlen,const char * value,int flags,int min,int max)419 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
420 const char *value, int flags, int min, int max)
421 {
422 int padlen, strln; /* amount to pad */
423 int cnt = 0;
424 char ch;
425
426
427 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
428 max = 0;
429 } else if (max < 0) {
430 max = maxlen;
431 }
432 strln = strlen(value);
433 if (strln > max) {
434 strln = max; /* truncate to max */
435 }
436 padlen = min - strln;
437 if (padlen < 0) {
438 padlen = 0;
439 }
440 if (flags & DP_F_MINUS) {
441 padlen = -padlen; /* Left Justify */
442 }
443
444 while (padlen > 0) {
445 outch(' ');
446 --padlen;
447 }
448 while (*value && (cnt < max)) {
449 ch = *value++;
450 outch(ch);
451 ++cnt;
452 }
453 while (padlen < 0) {
454 outch(' ');
455 ++padlen;
456 }
457 return currlen;
458 }
459
fmtwstr(char * buffer,int32_t currlen,int32_t maxlen,const wchar_t * value,int flags,int min,int max)460 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
461 const wchar_t *value, int flags, int min, int max)
462 {
463 int padlen, strln; /* amount to pad */
464 int cnt = 0;
465 char ch;
466
467
468 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
469 max = 0;
470 } else if (max < 0) {
471 max = maxlen;
472 }
473 strln = wcslen(value);
474 if (strln > max) {
475 strln = max; /* truncate to max */
476 }
477 padlen = min - strln;
478 if (padlen < 0) {
479 padlen = 0;
480 }
481 if (flags & DP_F_MINUS) {
482 padlen = -padlen; /* Left Justify */
483 }
484
485 while (padlen > 0) {
486 outch(' ');
487 --padlen;
488 }
489 while (*value && (cnt < max)) {
490
491 ch = (*value++) & 0xff;
492 outch(ch);
493 ++cnt;
494 }
495 while (padlen < 0) {
496 outch(' ');
497 ++padlen;
498 }
499 return currlen;
500 }
501
502 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
503
fmtint(char * buffer,int32_t currlen,int32_t maxlen,int64_t value,int base,int min,int max,int flags)504 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
505 int64_t value, int base, int min, int max, int flags)
506 {
507 int signvalue = 0;
508 uint64_t uvalue;
509 char convert[25];
510 int place = 0;
511 int spadlen = 0; /* amount to space pad */
512 int zpadlen = 0; /* amount to zero pad */
513 int caps = 0;
514 const char *cvt_string;
515
516 if (max < 0) {
517 max = 0;
518 }
519
520 uvalue = value;
521
522 if (!(flags & DP_F_UNSIGNED)) {
523 if (value < 0) {
524 signvalue = '-';
525 uvalue = -value;
526 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
527 signvalue = '+';
528 } else if (flags & DP_F_SPACE) {
529 signvalue = ' ';
530 }
531 }
532
533 if (flags & DP_F_UP) {
534 caps = 1; /* Should characters be upper case? */
535 }
536
537 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
538 do {
539 convert[place++] = cvt_string[uvalue % (unsigned)base];
540 uvalue = (uvalue / (unsigned)base);
541 } while (uvalue && (place < (int)sizeof(convert)));
542 if (place == (int)sizeof(convert)) {
543 place--;
544 }
545 convert[place] = 0;
546
547 zpadlen = max - place;
548 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
549 if (zpadlen < 0)
550 zpadlen = 0;
551 if (spadlen < 0)
552 spadlen = 0;
553 if (flags & DP_F_ZERO) {
554 zpadlen = MAX(zpadlen, spadlen);
555 spadlen = 0;
556 }
557 if (flags & DP_F_MINUS)
558 spadlen = -spadlen; /* Left Justifty */
559
560 #ifdef DEBUG_SNPRINTF
561 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
562 zpadlen, spadlen, min, max, place);
563 #endif
564
565 /* Spaces */
566 while (spadlen > 0) {
567 outch(' ');
568 --spadlen;
569 }
570
571 /* Sign */
572 if (signvalue) {
573 outch(signvalue);
574 }
575
576 /* Zeros */
577 if (zpadlen > 0) {
578 while (zpadlen > 0) {
579 outch('0');
580 --zpadlen;
581 }
582 }
583
584 /* Output digits backward giving correct order */
585 while (place > 0) {
586 place--;
587 outch(convert[place]);
588 }
589
590 /* Left Justified spaces */
591 while (spadlen < 0) {
592 outch(' ');
593 ++spadlen;
594 }
595 return currlen;
596 }
597
598 #ifdef FP_OUTPUT
599
abs_val(LDOUBLE value)600 static LDOUBLE abs_val(LDOUBLE value)
601 {
602 LDOUBLE result = value;
603
604 if (value < 0)
605 result = -value;
606
607 return result;
608 }
609
pow10(int exp)610 static LDOUBLE pow10(int exp)
611 {
612 LDOUBLE result = 1;
613
614 while (exp) {
615 result *= 10;
616 exp--;
617 }
618
619 return result;
620 }
621
bround(LDOUBLE value)622 static int64_t bround(LDOUBLE value)
623 {
624 int64_t intpart;
625
626 intpart = (int64_t)value;
627 value = value - intpart;
628 if (value >= 0.5)
629 intpart++;
630
631 return intpart;
632 }
633
fmtfp(char * buffer,int32_t currlen,int32_t maxlen,LDOUBLE fvalue,int min,int max,int flags)634 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
635 LDOUBLE fvalue, int min, int max, int flags)
636 {
637 int signvalue = 0;
638 LDOUBLE ufvalue;
639 #ifndef HAVE_FCVT
640 char iconvert[311];
641 char fconvert[311];
642 #else
643 char iconvert[311];
644 char fconvert[311];
645 char *result;
646 char dummy[10];
647 int dec_pt, sig;
648 int r_length;
649 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
650 #endif
651 int iplace = 0;
652 int fplace = 0;
653 int padlen = 0; /* amount to pad */
654 int zpadlen = 0;
655 int64_t intpart;
656 int64_t fracpart;
657 const char *cvt_str;
658
659 /*
660 * AIX manpage says the default is 0, but Solaris says the default
661 * is 6, and sprintf on AIX defaults to 6
662 */
663 if (max < 0)
664 max = 6;
665
666 ufvalue = abs_val(fvalue);
667
668 if (fvalue < 0)
669 signvalue = '-';
670 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
671 signvalue = '+';
672 else if (flags & DP_F_SPACE)
673 signvalue = ' ';
674
675 #ifndef HAVE_FCVT
676 intpart = (int64_t)ufvalue;
677
678 /*
679 * Sorry, we only support 9 digits past the decimal because of our
680 * conversion method
681 */
682 if (max > 9)
683 max = 9;
684
685 /* We "cheat" by converting the fractional part to integer by
686 * multiplying by a factor of 10
687 */
688 fracpart = bround((pow10(max)) * (ufvalue - intpart));
689
690 if (fracpart >= pow10(max)) {
691 intpart++;
692 fracpart -= (int64_t)pow10(max);
693 }
694
695 #ifdef DEBUG_SNPRINTF
696 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
697 (double)fvalue, intpart, fracpart, min, max);
698 #endif
699
700 /* Convert integer part */
701 cvt_str = "0123456789";
702 do {
703 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
704 intpart = (intpart / 10);
705 } while (intpart && (iplace < (int)sizeof(iconvert)));
706
707 if (iplace == (int)sizeof(fconvert)) {
708 iplace--;
709 }
710 iconvert[iplace] = 0;
711
712 /* Convert fractional part */
713 cvt_str = "0123456789";
714 for (int fiter = max; fiter > 0; fiter--) {
715 fconvert[fplace++] = cvt_str[fracpart % 10];
716 fracpart = (fracpart / 10);
717 }
718
719 if (fplace == (int)sizeof(fconvert)) {
720 fplace--;
721 }
722 fconvert[fplace] = 0;
723 #else /* use fcvt() */
724 if (max > 310) {
725 max = 310;
726 }
727 # ifdef HAVE_FCVTL
728 result = fcvtl(ufvalue, max, &dec_pt, &sig);
729 # else
730 result = fcvt(ufvalue, max, &dec_pt, &sig);
731 # endif
732
733 if (!result) {
734 r_length = 0;
735 dummy[0] = 0;
736 result = dummy;
737 } else {
738 r_length = strlen(result);
739 }
740
741 /*
742 * Fix broken fcvt implementation returns..
743 */
744
745 if (r_length == 0) {
746 result[0] = '0';
747 result[1] = '\0';
748 r_length = 1;
749 }
750
751 if (r_length < dec_pt)
752 dec_pt = r_length;
753
754 if (dec_pt <= 0) {
755 iplace = 1;
756 iconvert[0] = '0';
757 iconvert[1] = '\0';
758
759 fplace = 0;
760
761 while (r_length) {
762 fconvert[fplace++] = result[--r_length];
763 }
764
765 while ((dec_pt < 0) && (fplace < max)) {
766 fconvert[fplace++] = '0';
767 dec_pt++;
768 }
769 } else {
770 int c;
771
772 iplace = 0;
773 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
774 iconvert[iplace] = '\0';
775
776 result += dec_pt;
777 fplace = 0;
778
779 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
780 }
781 #endif /* HAVE_FCVT */
782
783 /* -1 for decimal point, another -1 if we are printing a sign */
784 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
785 zpadlen = max - fplace;
786 if (zpadlen < 0) {
787 zpadlen = 0;
788 }
789 if (padlen < 0) {
790 padlen = 0;
791 }
792 if (flags & DP_F_MINUS) {
793 padlen = -padlen; /* Left Justifty */
794 }
795
796 if ((flags & DP_F_ZERO) && (padlen > 0)) {
797 if (signvalue) {
798 outch(signvalue);
799 --padlen;
800 signvalue = 0;
801 }
802 while (padlen > 0) {
803 outch('0');
804 --padlen;
805 }
806 }
807 while (padlen > 0) {
808 outch(' ');
809 --padlen;
810 }
811 if (signvalue) {
812 outch(signvalue);
813 }
814
815 while (iplace > 0) {
816 iplace--;
817 outch(iconvert[iplace]);
818 }
819
820
821 #ifdef DEBUG_SNPRINTF
822 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
823 #endif
824
825 /*
826 * Decimal point. This should probably use locale to find the correct
827 * char to print out.
828 */
829 if (max > 0) {
830 outch('.');
831 while (fplace > 0) {
832 fplace--;
833 outch(fconvert[fplace]);
834 }
835 }
836
837 while (zpadlen > 0) {
838 outch('0');
839 --zpadlen;
840 }
841
842 while (padlen < 0) {
843 outch(' ');
844 ++padlen;
845 }
846 return currlen;
847 }
848 #endif /* FP_OUTPUT */
849
850 #ifdef TEST_PROGRAM
851 #include "unittests.h"
852
853 #ifndef LONG_STRING
854 #define LONG_STRING 1024
855 #endif
856 #define MSGLEN 80
857
main(int argc,char * argv[])858 int main(int argc, char *argv[])
859 {
860 Unittests bsnprintf_test("bsnprintf_test");
861 char buf1[LONG_STRING];
862 char buf2[LONG_STRING];
863 char msg[MSGLEN];
864 bool check_cont, check_nr;
865 int pcount, bcount;
866
867 #ifdef FP_OUTPUT
868 const char *fp_fmt[] = {
869 "%-1.5f",
870 "%1.5f",
871 "%123.9f",
872 "%10.5f",
873 "% 10.5f",
874 "%+22.9f",
875 "%+4.9f",
876 "%01.3f",
877 "%4f",
878 "%3.1f",
879 "%3.2f",
880 "%.0f",
881 "%.1f",
882 "%.2f",
883 NULL
884 };
885 double fp_nums[] = { 1.05, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
886 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
887 };
888 #endif
889 const char *int_fmt[] = {
890 "%-1.5d",
891 "%1.5d",
892 "%123.9d",
893 "%5.5d",
894 "%10.5d",
895 "% 10.5d",
896 "%+22.33d",
897 "%01.3d",
898 "%4d",
899 "%-1.5ld",
900 "%1.5ld",
901 "%123.9ld",
902 "%5.5ld",
903 "%10.5ld",
904 "% 10.5ld",
905 "%+22.33ld",
906 "%01.3ld",
907 "%4ld",
908 NULL
909 };
910 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
911
912 const char *ll_fmt[] = {
913 "%-1.8lld",
914 "%1.8lld",
915 "%123.9lld",
916 "%5.8lld",
917 "%10.5lld",
918 "% 10.8lld",
919 "%+22.33lld",
920 "%01.3lld",
921 "%4lld",
922 NULL
923 };
924 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
925
926 const char *s_fmt[] = {
927 "%-1.8s",
928 "%1.8s",
929 "%123.9s",
930 "%5.8s",
931 "%10.5s",
932 "% 10.3s",
933 "%+22.1s",
934 "%01.3s",
935 "%s",
936 "%10s",
937 "%3s",
938 "%3.0s",
939 "%3.s",
940 NULL
941 };
942 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
943
944 const char *ls_fmt[] = {
945 "%-1.8ls",
946 "%1.8ls",
947 "%123.9ls",
948 "%5.8ls",
949 "%10.5ls",
950 "% 10.3ls",
951 "%+22.1ls",
952 "%01.3ls",
953 "%ls",
954 "%10ls",
955 "%3ls",
956 "%3.0ls",
957 "%3.ls",
958 NULL
959 };
960 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
961
962 int x, y;
963
964 printf("\n\tTesting bsnprintf against system sprintf...\n\n");
965 #ifdef FP_OUTPUT
966 printf("Testing bsnprintf float format codes\n");
967 for (x = 0; fp_fmt[x] != NULL; x++){
968 check_cont = true;
969 check_nr = true;
970 for (y = 0; fp_nums[y] != 0; y++) {
971 bcount = bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
972 pcount = sprintf(buf2, fp_fmt[x], fp_nums[y]);
973 if (bcount != pcount) {
974 check_nr = false;
975 }
976 if (strcmp(buf1, buf2) != 0){
977 check_cont = false;
978 }
979 }
980 snprintf(msg, MSGLEN, "Checking return length for format %s", fp_fmt[x]);
981 ok(check_nr, msg);
982 snprintf(msg, MSGLEN, "Checking format %s", fp_fmt[x]);
983 ok(check_cont, msg);
984 }
985 #endif
986
987 printf("Testing bsnprintf int format codes\n");
988 for (x = 0; int_fmt[x] != NULL; x++){
989 check_cont = true;
990 check_nr = true;
991 for (y = 0; int_nums[y] != 0; y++) {
992 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
993 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
994 if (bcount != pcount) {
995 check_nr = false;
996 }
997 if (strcmp(buf1, buf2) != 0) {
998 check_cont = false;
999 }
1000 }
1001 snprintf(msg, MSGLEN, "Checking return length for format %s", int_fmt[x]);
1002 ok(check_nr, msg);
1003 snprintf(msg, MSGLEN, "Checking format %s", int_fmt[x]);
1004 ok(check_cont, msg);
1005 }
1006
1007 printf("Testing bsnprintf long format codes\n");
1008 for (x = 0; ll_fmt[x] != NULL; x++) {
1009 check_cont = true;
1010 check_nr = true;
1011 for (y = 0; ll_nums[y] != 0; y++) {
1012 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1013 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
1014 if (bcount != pcount) {
1015 check_nr = false;
1016 }
1017 if (strcmp(buf1, buf2) != 0) {
1018 check_cont = false;
1019 }
1020 }
1021 snprintf(msg, MSGLEN, "Checking return length for format %s", ll_fmt[x]);
1022 ok(check_nr, msg);
1023 snprintf(msg, MSGLEN, "Checking format %s", ll_fmt[x]);
1024 ok(check_cont, msg);
1025 }
1026
1027 printf("Testing bsnprintf str format codes\n");
1028 for (x = 0; s_fmt[x] != NULL; x++) {
1029 check_cont = true;
1030 check_nr = true;
1031 for (y = 0; s_nums[y] != 0; y++) {
1032 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1033 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
1034 if (bcount != pcount) {
1035 check_nr = false;
1036 }
1037 if (strcmp(buf1, buf2) != 0) {
1038 check_cont = false;
1039 }
1040 }
1041 snprintf(msg, MSGLEN, "Checking return length for format %s", s_fmt[x]);
1042 ok(check_nr, msg);
1043 snprintf(msg, MSGLEN, "Checking format %s", s_fmt[x]);
1044 ok(check_cont, msg);
1045 }
1046
1047 printf("Testing bsnprintf long str format codes\n");
1048 for (x = 0; ls_fmt[x] != NULL; x++) {
1049 check_cont = true;
1050 check_nr = true;
1051 for (y = 0; ls_nums[y] != 0; y++) {
1052 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1053 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1054 if (bcount != pcount) {
1055 check_nr = false;
1056 }
1057 if (strcmp(buf1, buf2) != 0) {
1058 check_cont = false;
1059 }
1060 }
1061 snprintf(msg, MSGLEN, "Checking return length for format %s", ls_fmt[x]);
1062 ok(check_nr, msg);
1063 snprintf(msg, MSGLEN, "Checking format %s", ls_fmt[x]);
1064 ok(check_cont, msg);
1065 }
1066
1067 return report();
1068 }
1069 #endif /* TEST_PROGRAM */
1070
1071 #endif /* USE_BSNPRINTF */
1072