]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsnprintf.c
kes Write new subroutine is_volume_purged() that explicitly checks
[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 plus additions
26    that are listed 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             strvalue = va_arg(args, char *);
331             currlen = fmtint(buffer, currlen, maxlen, (long)strvalue, 16, min, max, flags);
332             break;
333          case 'n':
334             if (cflags == DP_C_INT16) {
335                int16_t *num;
336                num = va_arg(args, int16_t *);
337 #ifdef SECURITY_PROBLEM
338                *num = currlen;
339 #endif
340             } else if (cflags == DP_C_INT32) {
341                int32_t *num;
342                num = va_arg(args, int32_t *);
343 #ifdef SECURITY_PROBLEM
344                *num = (int32_t)currlen;
345 #endif
346             } else if (cflags == DP_C_INT64) {
347                int64_t *num;
348                num = va_arg(args, int64_t *);
349 #ifdef SECURITY_PROBLEM
350                *num = (int64_t)currlen;
351 #endif
352             } else {
353                int32_t *num;
354                num = va_arg(args, int32_t *);
355 #ifdef SECURITY_PROBLEM
356                *num = (int32_t)currlen;
357 #endif
358             }
359             break;
360          case '%':
361             outch(ch);
362             break;
363          case 'w':
364             /* not supported yet, treat as next char */
365             ch = *format++;
366             break;
367          default:
368             /* Unknown, skip */
369             break;
370          }
371          ch = *format++;
372          state = DP_S_DEFAULT;
373          flags = cflags = min = 0;
374          max = -1;
375          break;
376       case DP_S_DONE:
377          break;
378       default:
379          /* hmm? */
380          break;                    /* some picky compilers need this */
381       }
382    }
383    if (currlen < maxlen - 1) {
384       buffer[currlen] = '\0';
385    } else {
386       buffer[maxlen - 1] = '\0';
387    }
388    return currlen;
389 }
390
391 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
392                    char *value, int flags, int min, int max)
393 {
394    int padlen, strln;              /* amount to pad */
395    int cnt = 0;
396
397    if (value == 0) {
398       value = "<NULL>";
399    }
400
401    if (flags & DP_F_DOT && max < 0) {   /* Max not specified */
402       max = 0;
403    } else if (max < 0) {
404       max = maxlen;
405    }
406    strln = strlen(value);
407    if (strln > max) {
408       strln = max;                /* truncate to max */
409    }
410    padlen = min - strln;
411    if (padlen < 0) {
412       padlen = 0;
413    }
414    if (flags & DP_F_MINUS) {
415       padlen = -padlen;            /* Left Justify */
416    }
417
418    while (padlen > 0) {
419       outch(' ');
420       --padlen;
421    }
422    while (*value && (cnt < max)) {
423       outch(*value++);
424       ++cnt;
425    }
426    while (padlen < 0) {
427       outch(' ');
428       ++padlen;
429    }
430    return currlen;
431 }
432
433 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
434
435 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
436                    int64_t value, int base, int min, int max, int flags)
437 {
438    int signvalue = 0;
439    uint64_t uvalue;
440    char convert[20];
441    int place = 0;
442    int spadlen = 0;                /* amount to space pad */
443    int zpadlen = 0;                /* amount to zero pad */
444    int caps = 0;
445
446    if (max < 0) {
447       max = 0;
448    }
449
450    uvalue = value;
451
452    if (!(flags & DP_F_UNSIGNED)) {
453       if (value < 0) {
454          signvalue = '-';
455          uvalue = -value;
456       } else if (flags & DP_F_PLUS) {  /* Do a sign (+/i) */
457          signvalue = '+';
458       } else if (flags & DP_F_SPACE) {
459          signvalue = ' ';
460       }
461    }
462
463    if (flags & DP_F_UP) {
464       caps = 1;                    /* Should characters be upper case? */
465    }
466
467    do {
468       convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
469          [uvalue % (unsigned)base];
470       uvalue = (uvalue / (unsigned)base);
471    } while (uvalue && (place < 20));
472    if (place == 20) {
473       place--;
474    }
475    convert[place] = 0;
476
477    zpadlen = max - place;
478    spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
479    if (zpadlen < 0)
480       zpadlen = 0;
481    if (spadlen < 0)
482       spadlen = 0;
483    if (flags & DP_F_ZERO) {
484       zpadlen = MAX(zpadlen, spadlen);
485       spadlen = 0;
486    }
487    if (flags & DP_F_MINUS)
488       spadlen = -spadlen;          /* Left Justifty */
489
490 #ifdef DEBUG_SNPRINTF
491    printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
492           zpadlen, spadlen, min, max, place);
493 #endif
494
495    /* Spaces */
496    while (spadlen > 0) {
497       outch(' ');
498       --spadlen;
499    }
500
501    /* Sign */
502    if (signvalue) {
503       outch(signvalue);
504    }
505
506    /* Zeros */
507    if (zpadlen > 0) {
508       while (zpadlen > 0) {
509          outch('0');
510          --zpadlen;
511       }
512    }
513
514    /* Digits */
515    while (place > 0) {
516       outch(convert[--place]);
517    }
518
519    /* Left Justified spaces */
520    while (spadlen < 0) {
521       outch(' ');
522       ++spadlen;
523    }
524    return currlen;
525 }
526
527 #ifdef FP_OUTPUT
528
529 static LDOUBLE abs_val(LDOUBLE value)
530 {
531    LDOUBLE result = value;
532
533    if (value < 0)
534       result = -value;
535
536    return result;
537 }
538
539 static LDOUBLE pow10(int exp)
540 {
541    LDOUBLE result = 1;
542
543    while (exp) {
544       result *= 10;
545       exp--;
546    }
547
548    return result;
549 }
550
551 static long round(LDOUBLE value)
552 {
553    long intpart;
554
555    intpart = (long)value;
556    value = value - intpart;
557    if (value >= 0.5)
558       intpart++;
559
560    return intpart;
561 }
562
563 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
564                   LDOUBLE fvalue, int min, int max, int flags)
565 {
566    int signvalue = 0;
567    LDOUBLE ufvalue;
568 #ifndef HAVE_FCVT
569    char iconvert[20];
570    char fconvert[20];
571 #else
572    char iconvert[311];
573    char fconvert[311];
574    char *result;
575    int dec_pt, sig;
576    int r_length;
577    extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
578 #endif
579    int iplace = 0;
580    int fplace = 0;
581    int padlen = 0;                 /* amount to pad */
582    int zpadlen = 0;
583    int caps = 0;
584    int64_t intpart;
585    int64_t fracpart;
586
587    /* 
588     * AIX manpage says the default is 0, but Solaris says the default
589     * is 6, and sprintf on AIX defaults to 6
590     */
591    if (max < 0)
592       max = 6;
593
594    ufvalue = abs_val(fvalue);
595
596    if (fvalue < 0)
597       signvalue = '-';
598    else if (flags & DP_F_PLUS)     /* Do a sign (+/i) */
599       signvalue = '+';
600    else if (flags & DP_F_SPACE)
601       signvalue = ' ';
602
603 #if 0
604    if (flags & DP_F_UP)
605       caps = 1;                    /* Should characters be upper case? */
606 #endif
607
608 #ifndef HAVE_FCVT
609    intpart = (long)ufvalue;
610
611    /* 
612     * Sorry, we only support 9 digits past the decimal because of our 
613     * conversion method
614     */
615    if (max > 9)
616       max = 9;
617
618    /* We "cheat" by converting the fractional part to integer by
619     * multiplying by a factor of 10
620     */
621    fracpart = round((pow10(max)) * (ufvalue - intpart));
622
623    if (fracpart >= pow10(max)) {
624       intpart++;
625       fracpart -= (int64_t)pow10(max);
626    }
627 #ifdef DEBUG_SNPRINTF
628    printf("fmtfp: %g %d.%d min=%d max=%d\n",
629           (double)fvalue, intpart, fracpart, min, max);
630 #endif
631
632    /* Convert integer part */
633    do {
634       iconvert[iplace++] =
635          (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
636       intpart = (intpart / 10);
637    } while (intpart && (iplace < 20));
638    if (iplace == 20)
639       iplace--;
640    iconvert[iplace] = 0;
641
642    /* Convert fractional part */
643    do {
644       fconvert[fplace++] =
645          (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
646       fracpart = (fracpart / 10);
647    } while (fracpart && (fplace < 20));
648    if (fplace == 20)
649       fplace--;
650    fconvert[fplace] = 0;
651 #else                              /* use fcvt() */
652    if (max > 310)
653       max = 310;
654 # ifdef HAVE_FCVTL
655    result = fcvtl(ufvalue, max, &dec_pt, &sig);
656 # else
657    result = fcvt(ufvalue, max, &dec_pt, &sig);
658 # endif
659
660    r_length = strlen(result);
661
662    /*
663     * Fix broken fcvt implementation returns..
664     */
665
666    if (r_length == 0) {
667       result[0] = '0';
668       result[1] = '\0';
669       r_length = 1;
670    }
671
672    if (r_length < dec_pt)
673       dec_pt = r_length;
674
675    if (dec_pt <= 0) {
676       iplace = 1;
677       iconvert[0] = '0';
678       iconvert[1] = '\0';
679
680       fplace = 0;
681
682       while (r_length)
683          fconvert[fplace++] = result[--r_length];
684
685       while ((dec_pt < 0) && (fplace < max)) {
686          fconvert[fplace++] = '0';
687          dec_pt++;
688       }
689    } else {
690       int c;
691
692       iplace = 0;
693       for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
694       iconvert[iplace] = '\0';
695
696       result += dec_pt;
697       fplace = 0;
698
699       for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
700    }
701 #endif  /* HAVE_FCVT */
702
703    /* -1 for decimal point, another -1 if we are printing a sign */
704    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
705    zpadlen = max - fplace;
706    if (zpadlen < 0) {
707       zpadlen = 0;
708    }
709    if (padlen < 0) {
710       padlen = 0;
711    }
712    if (flags & DP_F_MINUS) {
713       padlen = -padlen;            /* Left Justifty */
714    }
715
716    if ((flags & DP_F_ZERO) && (padlen > 0)) {
717       if (signvalue) {
718          outch(signvalue);
719          --padlen;
720          signvalue = 0;
721       }
722       while (padlen > 0) {
723          outch('0');
724          --padlen;
725       }
726    }
727    while (padlen > 0) {
728       outch(' ');
729       --padlen;
730    }
731    if (signvalue) {
732       outch(signvalue);
733    }
734
735    while (iplace > 0) {
736       outch(iconvert[--iplace]);
737    }
738
739
740 #ifdef DEBUG_SNPRINTF
741    printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
742 #endif
743
744    /*
745     * Decimal point.  This should probably use locale to find the correct
746     * char to print out.
747     */
748    if (max > 0) {
749       outch('.');
750       while (fplace > 0) {
751          outch(fconvert[--fplace]);
752       }
753    }
754
755    while (zpadlen > 0) {
756       outch('0');
757       --zpadlen;
758    }
759
760    while (padlen < 0) {
761       outch(' ');
762       ++padlen;
763    }
764    return currlen;
765 }
766 #endif  /* FP_OUTPUT */
767
768
769 #ifdef TEST_PROGRAM
770
771 #ifndef LONG_STRING
772 #define LONG_STRING 1024
773 #endif
774 int main(void)
775 {
776    char buf1[LONG_STRING];
777    char buf2[LONG_STRING];
778
779 #ifdef FP_OUTPUT
780    char *fp_fmt[] = {
781       "%-1.5f",
782       "%1.5f",
783       "%123.9f",
784       "%10.5f",
785       "% 10.5f",
786       "%+22.9f",
787       "%+4.9f",
788       "%01.3f",
789       "%4f",
790       "%3.1f",
791       "%3.2f",
792       "%.0f",
793       "%.1f",
794       NULL
795    };
796    double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
797       0.9996, 1.996, 4.136, 6442452944.1234, 0
798    };
799 #endif
800    char *int_fmt[] = {
801       "%-1.5d",
802       "%1.5d",
803       "%123.9d",
804       "%5.5d",
805       "%10.5d",
806       "% 10.5d",
807       "%+22.33d",
808       "%01.3d",
809       "%4d",
810       "%-1.5ld",
811       "%1.5ld",
812       "%123.9ld",
813       "%5.5ld",
814       "%10.5ld",
815       "% 10.5ld",
816       "%+22.33ld",
817       "%01.3ld",
818       "%4ld",
819       NULL
820    };
821    long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
822
823    char *ll_fmt[] = {
824       "%-1.8lld",
825       "%1.8lld",
826       "%123.9lld",
827       "%5.8lld",
828       "%10.5lld",
829       "% 10.8lld",
830       "%+22.33lld",
831       "%01.3lld",
832       "%4lld",
833       NULL
834    };
835    int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
836
837    char *s_fmt[] = {
838       "%-1.8s",
839       "%1.8s",
840       "%123.9s",
841       "%5.8s",
842       "%10.5s",
843       "% 10.3s",
844       "%+22.1s",
845       "%01.3s",
846       "%s",
847       "%10s",
848       "%3s",
849       "%3.0s",
850       "%3.s",
851       NULL
852    };
853    char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
854
855
856    int x, y;
857    int fail = 0;
858    int num = 0;
859
860    printf("Testing snprintf format codes against system sprintf...\n");
861
862 #ifdef FP_OUTPUT
863    for (x = 0; fp_fmt[x] != NULL; x++)
864       for (y = 0; fp_nums[y] != 0; y++) {
865          bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
866          sprintf(buf2, fp_fmt[x], fp_nums[y]);
867          if (strcmp(buf1, buf2)) {
868             printf
869                ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
870                 fp_fmt[x], buf1, buf2);
871             fail++;
872          }
873          num++;
874       }
875 #endif
876
877    for (x = 0; int_fmt[x] != NULL; x++)
878       for (y = 0; int_nums[y] != 0; y++) {
879          int pcount, bcount;
880          bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
881          printf("%s\n", buf1);
882          pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
883          if (bcount != pcount) {
884             printf("bsnprintf count %d doesn't match sprintf count %d\n",
885                bcount, pcount);
886          }
887          if (strcmp(buf1, buf2)) {
888             printf
889                ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
890                 int_fmt[x], buf1, buf2);
891             fail++;
892          }
893          num++;
894       }
895
896    for (x = 0; ll_fmt[x] != NULL; x++) {
897       for (y = 0; ll_nums[y] != 0; y++) {
898          int pcount, bcount;
899          bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
900          printf("%s\n", buf1);
901          pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
902          if (bcount != pcount) {
903             printf("bsnprintf count %d doesn't match sprintf count %d\n",
904                bcount, pcount);
905          }
906          if (strcmp(buf1, buf2)) {
907             printf
908                ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
909                 ll_fmt[x], buf1, buf2);
910             fail++;
911          }
912          num++;
913       }
914    }
915
916    for (x = 0; s_fmt[x] != NULL; x++) {
917       for (y = 0; s_nums[y] != 0; y++) {
918          int pcount, bcount;
919          bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
920          printf("%s\n", buf1);
921          pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
922          if (bcount != pcount) {
923             printf("bsnprintf count %d doesn't match sprintf count %d\n",
924                bcount, pcount);
925          }
926          if (strcmp(buf1, buf2)) {
927             printf
928                ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
929                 s_fmt[x], buf1, buf2);
930             fail++;
931          }
932          num++;
933       }
934    }
935
936
937    printf("%d tests failed out of %d.\n", fail, num);
938 }
939 #endif /* TEST_PROGRAM */
940
941 #endif /* USE_BSNPRINTF */