]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/print.cpp
ebl typo fix
[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 "bacula.h"
53 #include "compat.h"
54
55 typedef void (prfun)(char *, size_t *, size_t, int);
56
57 int 
58 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun);
59
60
61 static void 
62 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
63        int min, int max, prfun);
64
65 static void 
66 fmtint(char *buffer, size_t *currlen, size_t maxlen, INT64 value, int base, 
67        int min, int max, int flags, prfun);
68
69 static void 
70 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
71       int min, int max, int flags, prfun);
72
73 static void
74 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c);
75
76 /*
77  * dopr(): poor man's version of doprintf
78  */
79
80 #ifndef MAX
81 #define MAX(a,b) ((a)>(b)?(a):(b))
82 #endif
83
84 /* format read states */
85 #define DP_S_DEFAULT 0
86 #define DP_S_FLAGS   1
87 #define DP_S_MIN     2
88 #define DP_S_DOT     3
89 #define DP_S_MAX     4
90 #define DP_S_MOD     5
91 #define DP_S_CONV    6
92 #define DP_S_DONE    7
93
94 /* format flags - Bits */
95 #define DP_F_MINUS      (1 << 0)
96 #define DP_F_PLUS       (1 << 1)
97 #define DP_F_SPACE      (1 << 2)
98 #define DP_F_NUM        (1 << 3)
99 #define DP_F_ZERO       (1 << 4)
100 #define DP_F_UP         (1 << 5)
101 #define DP_F_UNSIGNED   (1 << 6)
102
103 /* Conversion Flags */
104 #define DP_C_SHORT     1
105 #define DP_C_LONG      2
106 #define DP_C_LDOUBLE   3
107 #define DP_C_LONG_LONG 4
108
109 #define char_to_int(p)  (p - '0')
110 #define abs_val(p)      (p < 0 ? -p : p)
111
112 static const char digitval[] = "0123456789abcdef0123456789ABCDEF";
113
114 int
115 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun outch)
116 {
117     char *strvalue;
118     char ch;
119     INT64 value;
120     long double fvalue;
121     int min = 0;
122     int max = -1;
123     int state = DP_S_DEFAULT;
124     int flags = 0;
125     int cflags = 0;
126     size_t currlen = 0;
127   
128     ch = *format++;
129
130     while (state != DP_S_DONE)
131     {
132         if ((ch == '\0') || (currlen >= maxlen)) 
133             state = DP_S_DONE;
134
135         switch (state)
136         {
137         case DP_S_DEFAULT:
138             if (ch == '%') 
139                 state = DP_S_FLAGS;
140             else 
141                 outch(buffer, &currlen, maxlen, ch);
142             ch = *format++;
143             break;
144         case DP_S_FLAGS:
145             switch (ch)
146             {
147             case '-':
148                 flags |= DP_F_MINUS;
149                 ch = *format++;
150                 break;
151             case '+':
152                 flags |= DP_F_PLUS;
153                 ch = *format++;
154                 break;
155             case ' ':
156                 flags |= DP_F_SPACE;
157                 ch = *format++;
158                 break;
159             case '#':
160                 flags |= DP_F_NUM;
161                 ch = *format++;
162                 break;
163             case '0':
164                 flags |= DP_F_ZERO;
165                 ch = *format++;
166                 break;
167             default:
168                 state = DP_S_MIN;
169                 break;
170             }
171             break;
172         case DP_S_MIN:
173             if (isdigit((unsigned char)ch))
174             {
175                 min = 10*min + char_to_int(ch);
176                 ch = *format++;
177             }
178             else if (ch == '*')
179             {
180                 min = va_arg(args, int);
181                 ch = *format++;
182                 state = DP_S_DOT;
183             }
184             else 
185                 state = DP_S_DOT;
186             break;
187         case DP_S_DOT:
188             if (ch == '.')
189             {
190                 state = DP_S_MAX;
191                 ch = *format++;
192             }
193             else 
194                 state = DP_S_MOD;
195             break;
196         case DP_S_MAX:
197             if (isdigit((unsigned char)ch))
198             {
199                 if (max < 0)
200                     max = 0;
201                 max = 10*max + char_to_int(ch);
202                 ch = *format++;
203             }
204             else if (ch == '*')
205             {
206                 max = va_arg(args, int);
207                 ch = *format++;
208                 state = DP_S_MOD;
209             }
210             else 
211                 state = DP_S_MOD;
212             break;
213         case DP_S_MOD:
214             switch (ch)
215             {
216             case 'h':
217                 cflags = DP_C_SHORT;
218                 ch = *format++;
219                 break;
220             case 'l':
221                 cflags = DP_C_LONG;
222                 ch = *format++;
223                 if (ch == 'l')
224                 {
225                     cflags = DP_C_LONG_LONG;
226                     ch = *format++;
227                 }
228                 break;
229             case 'q':
230                 cflags = DP_C_LONG_LONG;
231                 ch = *format++;
232                 break;
233             case 'L':
234                 cflags = DP_C_LDOUBLE;
235                 ch = *format++;
236                 break;
237             default:
238                 break;
239             }
240             state = DP_S_CONV;
241             break;
242         case DP_S_CONV:
243             switch (ch)
244             {
245             case 'b':
246                 flags |= DP_F_UNSIGNED;
247                 if (cflags == DP_C_SHORT) 
248                     value = va_arg(args, unsigned int);
249                 else if (cflags == DP_C_LONG)
250                     value = va_arg(args, unsigned long int);
251                 else if (cflags == DP_C_LONG_LONG)
252                     value = va_arg(args, UINT64);
253                 else
254                     value = va_arg(args, unsigned int);
255                 fmtint(buffer, &currlen, maxlen, value, 2, min, max, flags, outch);
256                 break;
257             case 'd':
258             case 'i':
259                 if (cflags == DP_C_SHORT) 
260                     value = va_arg(args, int);
261                 else if (cflags == DP_C_LONG)
262                     value = va_arg(args, long int);
263                 else if (cflags == DP_C_LONG_LONG)
264                     value = va_arg(args, INT64);
265                 else
266                     value = va_arg(args, int);
267                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
268                 break;
269             case 'o':
270                 flags |= DP_F_UNSIGNED;
271                 if (cflags == DP_C_SHORT)
272                     value = va_arg(args, unsigned int);
273                 else if (cflags == DP_C_LONG)
274                     value = va_arg(args, unsigned long int);
275                 else if (cflags == DP_C_LONG_LONG)
276                     value = va_arg(args, UINT64);
277                 else
278                     value = va_arg(args, unsigned int);
279                 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags, outch);
280                 break;
281             case 'u':
282                 flags |= DP_F_UNSIGNED;
283                 if (cflags == DP_C_SHORT)
284                     value = va_arg(args, unsigned int);
285                 else if (cflags == DP_C_LONG)
286                     value = va_arg(args, unsigned long int);
287                 else if (cflags == DP_C_LONG_LONG)
288                     value = va_arg(args, UINT64);
289                 else
290                     value = va_arg(args, unsigned int);
291                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
292                 break;
293             case 'X':
294                 flags |= DP_F_UP;
295             case 'x':
296                 flags |= DP_F_UNSIGNED;
297                 if (cflags == DP_C_SHORT)
298                     value = va_arg(args, unsigned int);
299                 else if (cflags == DP_C_LONG)
300                     value = va_arg(args, unsigned long int);
301                 else if (cflags == DP_C_LONG_LONG)
302                     value = va_arg(args, UINT64);
303                 else
304                     value = va_arg(args, unsigned int);
305                 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags, outch);
306                 break;
307             case 'f':
308                 if (cflags == DP_C_LDOUBLE)
309                     fvalue = va_arg(args, long double);
310                 else
311                     fvalue = va_arg(args, double);
312                 /* um, floating point? */
313                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags, outch);
314                 break;
315             case 'E':
316                 flags |= DP_F_UP;
317             case 'e':
318                 if (cflags == DP_C_LDOUBLE)
319                     fvalue = va_arg(args, long double);
320                 else
321                     fvalue = va_arg(args, double);
322                 break;
323             case 'G':
324                 flags |= DP_F_UP;
325             case 'g':
326                 if (cflags == DP_C_LDOUBLE)
327                     fvalue = va_arg(args, long double);
328                 else
329                     fvalue = va_arg(args, double);
330                 break;
331             case 'c':
332                 outch(buffer, &currlen, maxlen, va_arg(args, int));
333                 break;
334             case 's':
335                 strvalue = va_arg(args, char *);
336                 if (max < 0) {
337                     max = maxlen; /* ie, no max */
338                 }
339                 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max, outch);
340                 break;
341             case 'p':
342                 flags |= DP_F_UNSIGNED;
343                 if (sizeof(char *) == 4) {
344                    value = va_arg(args, uint32_t);
345                 } else if (sizeof(char *) == 8) {
346                    value = va_arg(args, uint64_t);
347                 } else {
348                    value = 0;             /* we have a problem */
349                 }
350                 fmtint(buffer, &currlen, maxlen, value, 16, min, max,
351                        flags, outch);
352                 break;
353             case 'n':
354                 if (cflags == DP_C_SHORT)
355                 {
356                     short int *num;
357                     num = va_arg(args, short int *);
358                     *num = currlen;
359                 }
360                 else if (cflags == DP_C_LONG)
361                 {
362                     long int *num;
363                     num = va_arg(args, long int *);
364                     *num = currlen;
365                 }
366                 else if (cflags == DP_C_LONG_LONG)
367                 {
368                     INT64 *num;
369                     num = va_arg(args, INT64 *);
370                     *num = currlen;
371                 }
372                 else
373                 {
374                     int *num;
375                     num = va_arg(args, int *);
376                     *num = currlen;
377                 }
378                 break;
379             case '%':
380                 outch(buffer, &currlen, maxlen, ch);
381                 break;
382             case 'w': /* not supported yet, treat as next char */
383                 ch = *format++;
384                 break;
385             default: /* Unknown, skip */
386                 break;
387             }
388             ch = *format++;
389             state = DP_S_DEFAULT;
390             flags = cflags = min = 0;
391             max = -1;
392             break;
393         case DP_S_DONE:
394             break;
395         default: /* hmm? */
396             break; /* some picky compilers need this */
397         }
398     }
399     outch(buffer, &currlen, maxlen, -1);
400     return currlen;
401 }
402
403 static void
404 fmtstr(char *buffer, size_t *currlen, size_t maxlen, 
405        char *value, int flags, int min, int max, prfun outch)
406 {
407     int padlen, strln;     /* amount to pad */
408     int cnt = 0;
409   
410     if (value == NULL) 
411         value = "<NULL>";
412
413     for (strln = 0; value[strln]; ++strln); /* strlen */
414     padlen = min - strln;
415     if (padlen < 0) 
416         padlen = 0;
417     if (flags & DP_F_MINUS) 
418         padlen = -padlen; /* Left Justify */
419
420     while ((padlen > 0) && (cnt < max))
421     {
422         outch(buffer, currlen, maxlen, ' ');
423         --padlen;
424         ++cnt;
425     }
426     while (*value && (cnt < max))
427     {
428         outch(buffer, currlen, maxlen, *value++);
429         ++cnt;
430     }
431     while ((padlen < 0) && (cnt < max))
432     {
433         outch(buffer, currlen, maxlen, ' ');
434         ++padlen;
435         ++cnt;
436     }
437 }
438
439 /* Have to handle DP_F_NUM(ie 0x and 0 alternates) */
440
441 static void 
442 fmtint(char *buffer, size_t *currlen, size_t maxlen, 
443        INT64 value, int base, int min, int max, int flags, prfun outch)
444 {
445     UINT64 uvalue;
446     char convert[20];
447     int signvalue = 0;
448     int place = 0;
449     int spadlen = 0; /* amount to space pad */
450     int zpadlen = 0; /* amount to zero pad */
451     int caps = 0;
452     
453     if (max < 0)
454         max = 0;
455     
456     uvalue = value;
457
458     if (!(flags & DP_F_UNSIGNED))
459     {
460         if (value < 0)
461         {
462             signvalue = '-';
463             uvalue = -value;
464         }
465         else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
466             signvalue = '+';
467         else if (flags & DP_F_SPACE)
468             signvalue = ' ';
469     }
470   
471     if (flags & DP_F_UP) 
472         caps = 16; /* Should characters be upper case? */
473
474     do
475     {
476         convert[place++] = digitval[(uvalue%base)+caps];
477         uvalue = (uvalue / (unsigned)base);
478     } while (uvalue && (place < 20));
479
480     if (place == 20) 
481         place--;
482
483     convert[place] = 0;
484
485     zpadlen = max - place;
486     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
487
488     if (zpadlen < 0)
489         zpadlen = 0;
490     if (spadlen < 0)
491         spadlen = 0;
492     if (flags & DP_F_ZERO)
493     {
494         zpadlen = MAX(zpadlen, spadlen);
495         spadlen = 0;
496     }
497     if (flags & DP_F_MINUS) 
498         spadlen = -spadlen; /* Left Justifty */
499
500
501     /* Spaces */
502     while (spadlen > 0)
503     {
504         outch(buffer, currlen, maxlen, ' ');
505         --spadlen;
506     }
507
508     /* Sign */
509     if (signvalue) 
510         outch(buffer, currlen, maxlen, signvalue);
511
512     /* Zeros */
513     if (zpadlen > 0)
514     {
515         while (zpadlen > 0)
516         {
517             outch(buffer, currlen, maxlen, '0');
518             --zpadlen;
519         }
520     }
521
522     /* Digits */
523     while (place > 0) 
524         outch(buffer, currlen, maxlen, convert[--place]);
525   
526     /* Left Justified spaces */
527     while (spadlen < 0)
528     {
529         outch(buffer, currlen, maxlen, ' ');
530         ++spadlen;
531     }
532 }
533
534 static long double 
535 pow10(int exp)
536 {
537     long double result = 1;
538
539     while (exp)
540     {
541         result *= 10;
542         exp--;
543     }
544   
545     return result;
546 }
547
548 static long 
549 round(long double value)
550 {
551     long intpart = (long)value;
552
553     value -= intpart;
554     if (value >= 0.5)
555         intpart++;
556
557     return intpart;
558 }
559
560 static void 
561 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
562       int min, int max, int flags, prfun outch)
563 {
564     char iconvert[20];
565     char fconvert[20];
566     int signvalue = 0;
567     int iplace = 0;
568     int fplace = 0;
569     int padlen = 0; /* amount to pad */
570     int zpadlen = 0; 
571     long intpart;
572     long fracpart;
573     long double ufvalue;
574   
575     /* 
576      * AIX manpage says the default is 0, but Solaris says the default
577      * is 6, and sprintf on AIX defaults to 6
578      */
579     if (max < 0)
580         max = 6;
581
582     ufvalue = abs_val(fvalue);
583
584     if (fvalue < 0)
585         signvalue = '-';
586     else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
587         signvalue = '+';
588     else if (flags & DP_F_SPACE)
589         signvalue = ' ';
590
591     intpart = (long)ufvalue;
592
593     /* 
594      * Sorry, we only support 9 digits past the decimal because of our 
595      * conversion method
596      */
597     if (max > 9)
598         max = 9;
599
600     /* We "cheat" by converting the fractional part to integer by
601      * multiplying by a factor of 10
602      */
603     fracpart = round((pow10 (max)) * (ufvalue - intpart));
604
605     if (fracpart >= pow10 (max))
606     {
607         intpart++;
608         fracpart -= (long)pow10 (max);
609     }
610
611     /* Convert integer part */
612     do
613     {
614         iconvert[iplace++] = digitval[intpart % 10];
615         intpart = (intpart / 10);
616     } while (intpart && (iplace < 20));
617
618     if (iplace == 20) 
619         iplace--;
620
621     iconvert[iplace] = 0;
622
623     /* Convert fractional part */
624     do
625     {
626         fconvert[fplace++] = digitval[fracpart % 10];
627         fracpart = (fracpart / 10);
628     } while (fracpart && (fplace < 20));
629
630     if (fplace == 20) 
631         fplace--;
632
633     fconvert[fplace] = 0;
634
635     /* -1 for decimal point, another -1 if we are printing a sign */
636     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
637     zpadlen = max - fplace;
638     if (zpadlen < 0)
639         zpadlen = 0;
640     if (padlen < 0) 
641         padlen = 0;
642     if (flags & DP_F_MINUS) 
643         padlen = -padlen; /* Left Justifty */
644
645     if ((flags & DP_F_ZERO) && (padlen > 0))
646     {
647         if (signvalue)
648         {
649             outch(buffer, currlen, maxlen, signvalue);
650             --padlen;
651             signvalue = 0;
652         }
653         while (padlen > 0)
654         {
655             outch(buffer, currlen, maxlen, '0');
656             --padlen;
657         }
658     }
659
660     while (padlen > 0)
661     {
662         outch(buffer, currlen, maxlen, ' ');
663         --padlen;
664     }
665
666     if (signvalue) 
667         outch(buffer, currlen, maxlen, signvalue);
668
669     while (iplace > 0) 
670         outch(buffer, currlen, maxlen, iconvert[--iplace]);
671
672     /*
673      * Decimal point.  This should probably use locale to find the correct
674      * char to print out.
675      */
676     outch(buffer, currlen, maxlen, '.');
677
678     while (fplace > 0) 
679         outch(buffer, currlen, maxlen, fconvert[--fplace]);
680
681     while (zpadlen > 0)
682     {
683         outch(buffer, currlen, maxlen, '0');
684         --zpadlen;
685     }
686
687     while (padlen < 0)
688     {
689         outch(buffer, currlen, maxlen, ' ');
690         ++padlen;
691     }
692 }
693
694 static void 
695 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
696 {
697     if (c == -1)
698     {
699         if (*currlen < maxlen - 1) 
700             buffer[*currlen] = '\0';
701         else 
702             buffer[maxlen - 1] = '\0';
703     }
704     else if (*currlen < maxlen)
705         buffer[(*currlen)++] = c;
706 }
707
708 int
709 __sprintf(char *str, const char *fmt, ...) 
710 {
711     int rval;
712     va_list ap;
713     va_start(ap, fmt);
714     rval = vsnprintf(str, 128*1024, fmt, ap);
715     va_end(ap);
716     return rval;
717 }
718
719
720 int 
721 __snprintf(char *str, size_t count, const char *fmt, ...)
722 {
723     int rval;
724     va_list ap;
725
726     va_start(ap, fmt);
727     rval = vsnprintf(str, count, fmt, ap);
728     va_end(ap);
729
730     return rval;
731 }
732
733 int
734 __vsprintf(char *s, const char *format, va_list args)
735 {
736     s[0] = 0;
737     return dopr(s, 0xfffff, format, args, dopr_outch);
738 }
739
740 int
741 __vsnprintf(char *s, size_t count, const char *format, va_list args)
742 {
743     s[0] = 0;
744     return dopr(s, count, format, args, dopr_outch);
745 }