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