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