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