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