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