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