]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/print.cpp
added VSS toggling by enable_vss
[bacula/bacula] / bacula / src / win32 / compat / print.cpp
1 /**************************************************************
2  * Original:
3  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
4  * A bombproof version of doprnt(dopr) included.
5  * Sigh.  This sort of thing is always nasty do deal with.  Note that
6  * the version here does not include floating point...
7  *
8  * snprintf() is used instead of sprintf() as it does limit checks
9  * for string length.  This covers a nasty loophole.
10  *
11  * The other functions are there to prevent NULL pointers from
12  * causing nast effects.
13  *
14  * More Recently:
15  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
16  *  This was ugly.  It is still ugly.  I opted out of floating point
17  *  numbers, but the formatter understands just about everything
18  *  from the normal C string format, at least as far as I can tell from
19  *  the Solaris 2.5 printf(3S) man page.
20  *
21  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
22  *    Ok, added some minimal floating point support, which means this
23  *    probably requires libm on most operating systems.  Don't yet
24  *    support the exponent(e, E) and sigfig(g, G).  Also, fmtint()
25  *    was pretty badly broken, it just wasn't being exercised in ways
26  *    which showed it, so that's been fixed.  Also, formated the code
27  *    to mutt conventions, and removed dead code left over from the
28  *    original.  Also, there is now a builtin-test, just compile with:
29  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
30  *    and run snprintf for results.
31  * 
32  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
33  *    The PGP code was using unsigned hexadecimal formats. 
34  *    Unfortunately, unsigned formats simply didn't work.
35  *
36  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
37  *    The original code assumed that both snprintf() and vsnprintf() were
38  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
39  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
40  *
41  *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
42  *    Welcome to the world of %lld and %qd support.  With other
43  *    long long support.  This is needed for sftp-server to work
44  *    right.
45  *
46  *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
47  *    Removed all hint of VARARGS stuff and banished it to the void, 
48  *    and did a bit of KNF style work to make things a bit more
49  *    acceptable.  Consider stealing from mutt or enlightenment.
50  **************************************************************/
51
52 #include "compat.h"
53
54 typedef void (prfun)(char *, size_t *, size_t, int);
55
56 int 
57 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun);
58
59
60 static void 
61 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
62        int min, int max, prfun);
63
64 static void 
65 fmtint(char *buffer, size_t *currlen, size_t maxlen, INT64 value, int base, 
66        int min, int max, int flags, prfun);
67
68 static void 
69 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
70       int min, int max, int flags, prfun);
71
72 static void
73 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c);
74
75 /*
76  * dopr(): poor man's version of doprintf
77  */
78
79 #define MAX(a,b) ((a)>(b)?(a):(b))
80
81 /* format read states */
82 #define DP_S_DEFAULT 0
83 #define DP_S_FLAGS   1
84 #define DP_S_MIN     2
85 #define DP_S_DOT     3
86 #define DP_S_MAX     4
87 #define DP_S_MOD     5
88 #define DP_S_CONV    6
89 #define DP_S_DONE    7
90
91 /* format flags - Bits */
92 #define DP_F_MINUS      (1 << 0)
93 #define DP_F_PLUS       (1 << 1)
94 #define DP_F_SPACE      (1 << 2)
95 #define DP_F_NUM        (1 << 3)
96 #define DP_F_ZERO       (1 << 4)
97 #define DP_F_UP         (1 << 5)
98 #define DP_F_UNSIGNED   (1 << 6)
99
100 /* Conversion Flags */
101 #define DP_C_SHORT     1
102 #define DP_C_LONG      2
103 #define DP_C_LDOUBLE   3
104 #define DP_C_LONG_LONG 4
105
106 #define char_to_int(p)  (p - '0')
107 #define abs_val(p)      (p < 0 ? -p : p)
108
109 static const char digitval[] = "0123456789abcdef0123456789ABCDEF";
110
111 int
112 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun outch)
113 {
114     char *strvalue;
115     char ch;
116     INT64 value;
117     long double fvalue;
118     int min = 0;
119     int max = -1;
120     int state = DP_S_DEFAULT;
121     int flags = 0;
122     int cflags = 0;
123     size_t currlen = 0;
124   
125     ch = *format++;
126
127     while (state != DP_S_DONE)
128     {
129         if ((ch == '\0') || (currlen >= maxlen)) 
130             state = DP_S_DONE;
131
132         switch (state)
133         {
134         case DP_S_DEFAULT:
135             if (ch == '%') 
136                 state = DP_S_FLAGS;
137             else 
138                 outch(buffer, &currlen, maxlen, ch);
139             ch = *format++;
140             break;
141         case DP_S_FLAGS:
142             switch (ch)
143             {
144             case '-':
145                 flags |= DP_F_MINUS;
146                 ch = *format++;
147                 break;
148             case '+':
149                 flags |= DP_F_PLUS;
150                 ch = *format++;
151                 break;
152             case ' ':
153                 flags |= DP_F_SPACE;
154                 ch = *format++;
155                 break;
156             case '#':
157                 flags |= DP_F_NUM;
158                 ch = *format++;
159                 break;
160             case '0':
161                 flags |= DP_F_ZERO;
162                 ch = *format++;
163                 break;
164             default:
165                 state = DP_S_MIN;
166                 break;
167             }
168             break;
169         case DP_S_MIN:
170             if (isdigit((unsigned char)ch))
171             {
172                 min = 10*min + char_to_int(ch);
173                 ch = *format++;
174             }
175             else if (ch == '*')
176             {
177                 min = va_arg(args, int);
178                 ch = *format++;
179                 state = DP_S_DOT;
180             }
181             else 
182                 state = DP_S_DOT;
183             break;
184         case DP_S_DOT:
185             if (ch == '.')
186             {
187                 state = DP_S_MAX;
188                 ch = *format++;
189             }
190             else 
191                 state = DP_S_MOD;
192             break;
193         case DP_S_MAX:
194             if (isdigit((unsigned char)ch))
195             {
196                 if (max < 0)
197                     max = 0;
198                 max = 10*max + char_to_int(ch);
199                 ch = *format++;
200             }
201             else if (ch == '*')
202             {
203                 max = va_arg(args, int);
204                 ch = *format++;
205                 state = DP_S_MOD;
206             }
207             else 
208                 state = DP_S_MOD;
209             break;
210         case DP_S_MOD:
211             switch (ch)
212             {
213             case 'h':
214                 cflags = DP_C_SHORT;
215                 ch = *format++;
216                 break;
217             case 'l':
218                 cflags = DP_C_LONG;
219                 ch = *format++;
220                 if (ch == 'l')
221                 {
222                     cflags = DP_C_LONG_LONG;
223                     ch = *format++;
224                 }
225                 break;
226             case 'q':
227                 cflags = DP_C_LONG_LONG;
228                 ch = *format++;
229                 break;
230             case 'L':
231                 cflags = DP_C_LDOUBLE;
232                 ch = *format++;
233                 break;
234             default:
235                 break;
236             }
237             state = DP_S_CONV;
238             break;
239         case DP_S_CONV:
240             switch (ch)
241             {
242             case 'b':
243                 flags |= DP_F_UNSIGNED;
244                 if (cflags == DP_C_SHORT) 
245                     value = va_arg(args, unsigned int);
246                 else if (cflags == DP_C_LONG)
247                     value = va_arg(args, unsigned long int);
248                 else if (cflags == DP_C_LONG_LONG)
249                     value = va_arg(args, UINT64);
250                 else
251                     value = va_arg(args, unsigned int);
252                 fmtint(buffer, &currlen, maxlen, value, 2, min, max, flags, outch);
253                 break;
254             case 'd':
255             case 'i':
256                 if (cflags == DP_C_SHORT) 
257                     value = va_arg(args, int);
258                 else if (cflags == DP_C_LONG)
259                     value = va_arg(args, long int);
260                 else if (cflags == DP_C_LONG_LONG)
261                     value = va_arg(args, INT64);
262                 else
263                     value = va_arg(args, int);
264                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
265                 break;
266             case 'o':
267                 flags |= DP_F_UNSIGNED;
268                 if (cflags == DP_C_SHORT)
269                     value = va_arg(args, unsigned int);
270                 else if (cflags == DP_C_LONG)
271                     value = va_arg(args, unsigned long int);
272                 else if (cflags == DP_C_LONG_LONG)
273                     value = va_arg(args, UINT64);
274                 else
275                     value = va_arg(args, unsigned int);
276                 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags, outch);
277                 break;
278             case 'u':
279                 flags |= DP_F_UNSIGNED;
280                 if (cflags == DP_C_SHORT)
281                     value = va_arg(args, unsigned int);
282                 else if (cflags == DP_C_LONG)
283                     value = va_arg(args, unsigned long int);
284                 else if (cflags == DP_C_LONG_LONG)
285                     value = va_arg(args, UINT64);
286                 else
287                     value = va_arg(args, unsigned int);
288                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
289                 break;
290             case 'X':
291                 flags |= DP_F_UP;
292             case 'x':
293                 flags |= DP_F_UNSIGNED;
294                 if (cflags == DP_C_SHORT)
295                     value = va_arg(args, unsigned int);
296                 else if (cflags == DP_C_LONG)
297                     value = va_arg(args, unsigned long int);
298                 else if (cflags == DP_C_LONG_LONG)
299                     value = va_arg(args, UINT64);
300                 else
301                     value = va_arg(args, unsigned int);
302                 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags, outch);
303                 break;
304             case 'f':
305                 if (cflags == DP_C_LDOUBLE)
306                     fvalue = va_arg(args, long double);
307                 else
308                     fvalue = va_arg(args, double);
309                 /* um, floating point? */
310                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags, outch);
311                 break;
312             case 'E':
313                 flags |= DP_F_UP;
314             case 'e':
315                 if (cflags == DP_C_LDOUBLE)
316                     fvalue = va_arg(args, long double);
317                 else
318                     fvalue = va_arg(args, double);
319                 break;
320             case 'G':
321                 flags |= DP_F_UP;
322             case 'g':
323                 if (cflags == DP_C_LDOUBLE)
324                     fvalue = va_arg(args, long double);
325                 else
326                     fvalue = va_arg(args, double);
327                 break;
328             case 'c':
329                 outch(buffer, &currlen, maxlen, va_arg(args, int));
330                 break;
331             case 's':
332                 strvalue = va_arg(args, char *);
333                 if (max < 0) 
334                     max = maxlen; /* ie, no max */
335                 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max, outch);
336                 break;
337             case 'p':
338                 strvalue = (char *) va_arg(args, void *);
339                 flags |= DP_F_UNSIGNED;
340                 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max,
341                        flags, outch);
342                 break;
343             case 'n':
344                 if (cflags == DP_C_SHORT)
345                 {
346                     short int *num;
347                     num = va_arg(args, short int *);
348                     *num = currlen;
349                 }
350                 else if (cflags == DP_C_LONG)
351                 {
352                     long int *num;
353                     num = va_arg(args, long int *);
354                     *num = currlen;
355                 }
356                 else if (cflags == DP_C_LONG_LONG)
357                 {
358                     INT64 *num;
359                     num = va_arg(args, INT64 *);
360                     *num = currlen;
361                 }
362                 else
363                 {
364                     int *num;
365                     num = va_arg(args, int *);
366                     *num = currlen;
367                 }
368                 break;
369             case '%':
370                 outch(buffer, &currlen, maxlen, ch);
371                 break;
372             case 'w': /* not supported yet, treat as next char */
373                 ch = *format++;
374                 break;
375             default: /* Unknown, skip */
376                 break;
377             }
378             ch = *format++;
379             state = DP_S_DEFAULT;
380             flags = cflags = min = 0;
381             max = -1;
382             break;
383         case DP_S_DONE:
384             break;
385         default: /* hmm? */
386             break; /* some picky compilers need this */
387         }
388     }
389     outch(buffer, &currlen, maxlen, -1);
390     return currlen;
391 }
392
393 static void
394 fmtstr(char *buffer, size_t *currlen, size_t maxlen, 
395        char *value, int flags, int min, int max, prfun outch)
396 {
397     int padlen, strln;     /* amount to pad */
398     int cnt = 0;
399   
400     if (value == NULL) 
401         value = "<NULL>";
402
403     for (strln = 0; value[strln]; ++strln); /* strlen */
404     padlen = min - strln;
405     if (padlen < 0) 
406         padlen = 0;
407     if (flags & DP_F_MINUS) 
408         padlen = -padlen; /* Left Justify */
409
410     while ((padlen > 0) && (cnt < max))
411     {
412         outch(buffer, currlen, maxlen, ' ');
413         --padlen;
414         ++cnt;
415     }
416     while (*value && (cnt < max))
417     {
418         outch(buffer, currlen, maxlen, *value++);
419         ++cnt;
420     }
421     while ((padlen < 0) && (cnt < max))
422     {
423         outch(buffer, currlen, maxlen, ' ');
424         ++padlen;
425         ++cnt;
426     }
427 }
428
429 /* Have to handle DP_F_NUM(ie 0x and 0 alternates) */
430
431 static void 
432 fmtint(char *buffer, size_t *currlen, size_t maxlen, 
433        INT64 value, int base, int min, int max, int flags, prfun outch)
434 {
435     UINT64 uvalue;
436     char convert[20];
437     int signvalue = 0;
438     int place = 0;
439     int spadlen = 0; /* amount to space pad */
440     int zpadlen = 0; /* amount to zero pad */
441     int caps = 0;
442     
443     if (max < 0)
444         max = 0;
445     
446     uvalue = value;
447
448     if (!(flags & DP_F_UNSIGNED))
449     {
450         if (value < 0)
451         {
452             signvalue = '-';
453             uvalue = -value;
454         }
455         else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
456             signvalue = '+';
457         else if (flags & DP_F_SPACE)
458             signvalue = ' ';
459     }
460   
461     if (flags & DP_F_UP) 
462         caps = 16; /* Should characters be upper case? */
463
464     do
465     {
466         convert[place++] = digitval[(uvalue%base)+caps];
467         uvalue = (uvalue / (unsigned)base);
468     } while (uvalue && (place < 20));
469
470     if (place == 20) 
471         place--;
472
473     convert[place] = 0;
474
475     zpadlen = max - place;
476     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
477
478     if (zpadlen < 0)
479         zpadlen = 0;
480     if (spadlen < 0)
481         spadlen = 0;
482     if (flags & DP_F_ZERO)
483     {
484         zpadlen = MAX(zpadlen, spadlen);
485         spadlen = 0;
486     }
487     if (flags & DP_F_MINUS) 
488         spadlen = -spadlen; /* Left Justifty */
489
490
491     /* Spaces */
492     while (spadlen > 0)
493     {
494         outch(buffer, currlen, maxlen, ' ');
495         --spadlen;
496     }
497
498     /* Sign */
499     if (signvalue) 
500         outch(buffer, currlen, maxlen, signvalue);
501
502     /* Zeros */
503     if (zpadlen > 0)
504     {
505         while (zpadlen > 0)
506         {
507             outch(buffer, currlen, maxlen, '0');
508             --zpadlen;
509         }
510     }
511
512     /* Digits */
513     while (place > 0) 
514         outch(buffer, currlen, maxlen, convert[--place]);
515   
516     /* Left Justified spaces */
517     while (spadlen < 0)
518     {
519         outch(buffer, currlen, maxlen, ' ');
520         ++spadlen;
521     }
522 }
523
524 static long double 
525 pow10(int exp)
526 {
527     long double result = 1;
528
529     while (exp)
530     {
531         result *= 10;
532         exp--;
533     }
534   
535     return result;
536 }
537
538 static long 
539 round(long double value)
540 {
541     long intpart = (long)value;
542
543     value -= intpart;
544     if (value >= 0.5)
545         intpart++;
546
547     return intpart;
548 }
549
550 static void 
551 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
552       int min, int max, int flags, prfun outch)
553 {
554     char iconvert[20];
555     char fconvert[20];
556     int signvalue = 0;
557     int iplace = 0;
558     int fplace = 0;
559     int padlen = 0; /* amount to pad */
560     int zpadlen = 0; 
561     long intpart;
562     long fracpart;
563     long double ufvalue;
564   
565     /* 
566      * AIX manpage says the default is 0, but Solaris says the default
567      * is 6, and sprintf on AIX defaults to 6
568      */
569     if (max < 0)
570         max = 6;
571
572     ufvalue = abs_val(fvalue);
573
574     if (fvalue < 0)
575         signvalue = '-';
576     else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
577         signvalue = '+';
578     else if (flags & DP_F_SPACE)
579         signvalue = ' ';
580
581     intpart = (long)ufvalue;
582
583     /* 
584      * Sorry, we only support 9 digits past the decimal because of our 
585      * conversion method
586      */
587     if (max > 9)
588         max = 9;
589
590     /* We "cheat" by converting the fractional part to integer by
591      * multiplying by a factor of 10
592      */
593     fracpart = round((pow10 (max)) * (ufvalue - intpart));
594
595     if (fracpart >= pow10 (max))
596     {
597         intpart++;
598         fracpart -= (long)pow10 (max);
599     }
600
601     /* Convert integer part */
602     do
603     {
604         iconvert[iplace++] = digitval[intpart % 10];
605         intpart = (intpart / 10);
606     } while (intpart && (iplace < 20));
607
608     if (iplace == 20) 
609         iplace--;
610
611     iconvert[iplace] = 0;
612
613     /* Convert fractional part */
614     do
615     {
616         fconvert[fplace++] = digitval[fracpart % 10];
617         fracpart = (fracpart / 10);
618     } while (fracpart && (fplace < 20));
619
620     if (fplace == 20) 
621         fplace--;
622
623     fconvert[fplace] = 0;
624
625     /* -1 for decimal point, another -1 if we are printing a sign */
626     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
627     zpadlen = max - fplace;
628     if (zpadlen < 0)
629         zpadlen = 0;
630     if (padlen < 0) 
631         padlen = 0;
632     if (flags & DP_F_MINUS) 
633         padlen = -padlen; /* Left Justifty */
634
635     if ((flags & DP_F_ZERO) && (padlen > 0))
636     {
637         if (signvalue)
638         {
639             outch(buffer, currlen, maxlen, signvalue);
640             --padlen;
641             signvalue = 0;
642         }
643         while (padlen > 0)
644         {
645             outch(buffer, currlen, maxlen, '0');
646             --padlen;
647         }
648     }
649
650     while (padlen > 0)
651     {
652         outch(buffer, currlen, maxlen, ' ');
653         --padlen;
654     }
655
656     if (signvalue) 
657         outch(buffer, currlen, maxlen, signvalue);
658
659     while (iplace > 0) 
660         outch(buffer, currlen, maxlen, iconvert[--iplace]);
661
662     /*
663      * Decimal point.  This should probably use locale to find the correct
664      * char to print out.
665      */
666     outch(buffer, currlen, maxlen, '.');
667
668     while (fplace > 0) 
669         outch(buffer, currlen, maxlen, fconvert[--fplace]);
670
671     while (zpadlen > 0)
672     {
673         outch(buffer, currlen, maxlen, '0');
674         --zpadlen;
675     }
676
677     while (padlen < 0)
678     {
679         outch(buffer, currlen, maxlen, ' ');
680         ++padlen;
681     }
682 }
683
684 static void 
685 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
686 {
687     if (c == -1)
688     {
689         if (*currlen < maxlen - 1) 
690             buffer[*currlen] = '\0';
691         else 
692             buffer[maxlen - 1] = '\0';
693     }
694     else if (*currlen < maxlen)
695         buffer[(*currlen)++] = c;
696 }
697
698 int
699 __sprintf(char *str, const char *fmt, ...) 
700 {
701     int rval;
702     va_list ap;
703     va_start(ap, fmt);
704     rval = vsnprintf(str, 128*1024, fmt, ap);
705     va_end(ap);
706     return rval;
707 }
708
709
710 int 
711 __snprintf(char *str, size_t count, const char *fmt, ...)
712 {
713     int rval;
714     va_list ap;
715
716     va_start(ap, fmt);
717     rval = vsnprintf(str, count, fmt, ap);
718     va_end(ap);
719
720     return rval;
721 }
722
723 int
724 __vsprintf(char *s, const char *format, va_list args)
725 {
726     s[0] = 0;
727     return dopr(s, 0xfffff, format, args, dopr_outch);
728 }
729
730 int
731 __vsnprintf(char *s, size_t count, const char *format, va_list args)
732 {
733     s[0] = 0;
734     return dopr(s, count, format, args, dopr_outch);
735 }
736