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