]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/print.cpp
kes Reapply my bat.conf install script in qt-console. I think I
[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                 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max, outch);
339                 break;
340             case 'p':
341                 strvalue = (char *) va_arg(args, void *);
342                 flags |= DP_F_UNSIGNED;
343                 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max,
344                        flags, outch);
345                 break;
346             case 'n':
347                 if (cflags == DP_C_SHORT)
348                 {
349                     short int *num;
350                     num = va_arg(args, short int *);
351                     *num = currlen;
352                 }
353                 else if (cflags == DP_C_LONG)
354                 {
355                     long int *num;
356                     num = va_arg(args, long int *);
357                     *num = currlen;
358                 }
359                 else if (cflags == DP_C_LONG_LONG)
360                 {
361                     INT64 *num;
362                     num = va_arg(args, INT64 *);
363                     *num = currlen;
364                 }
365                 else
366                 {
367                     int *num;
368                     num = va_arg(args, int *);
369                     *num = currlen;
370                 }
371                 break;
372             case '%':
373                 outch(buffer, &currlen, maxlen, ch);
374                 break;
375             case 'w': /* not supported yet, treat as next char */
376                 ch = *format++;
377                 break;
378             default: /* Unknown, skip */
379                 break;
380             }
381             ch = *format++;
382             state = DP_S_DEFAULT;
383             flags = cflags = min = 0;
384             max = -1;
385             break;
386         case DP_S_DONE:
387             break;
388         default: /* hmm? */
389             break; /* some picky compilers need this */
390         }
391     }
392     outch(buffer, &currlen, maxlen, -1);
393     return currlen;
394 }
395
396 static void
397 fmtstr(char *buffer, size_t *currlen, size_t maxlen, 
398        char *value, int flags, int min, int max, prfun outch)
399 {
400     int padlen, strln;     /* amount to pad */
401     int cnt = 0;
402   
403     if (value == NULL) 
404         value = "<NULL>";
405
406     for (strln = 0; value[strln]; ++strln); /* strlen */
407     padlen = min - strln;
408     if (padlen < 0) 
409         padlen = 0;
410     if (flags & DP_F_MINUS) 
411         padlen = -padlen; /* Left Justify */
412
413     while ((padlen > 0) && (cnt < max))
414     {
415         outch(buffer, currlen, maxlen, ' ');
416         --padlen;
417         ++cnt;
418     }
419     while (*value && (cnt < max))
420     {
421         outch(buffer, currlen, maxlen, *value++);
422         ++cnt;
423     }
424     while ((padlen < 0) && (cnt < max))
425     {
426         outch(buffer, currlen, maxlen, ' ');
427         ++padlen;
428         ++cnt;
429     }
430 }
431
432 /* Have to handle DP_F_NUM(ie 0x and 0 alternates) */
433
434 static void 
435 fmtint(char *buffer, size_t *currlen, size_t maxlen, 
436        INT64 value, int base, int min, int max, int flags, prfun outch)
437 {
438     UINT64 uvalue;
439     char convert[20];
440     int signvalue = 0;
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     uvalue = value;
450
451     if (!(flags & DP_F_UNSIGNED))
452     {
453         if (value < 0)
454         {
455             signvalue = '-';
456             uvalue = -value;
457         }
458         else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
459             signvalue = '+';
460         else if (flags & DP_F_SPACE)
461             signvalue = ' ';
462     }
463   
464     if (flags & DP_F_UP) 
465         caps = 16; /* Should characters be upper case? */
466
467     do
468     {
469         convert[place++] = digitval[(uvalue%base)+caps];
470         uvalue = (uvalue / (unsigned)base);
471     } while (uvalue && (place < 20));
472
473     if (place == 20) 
474         place--;
475
476     convert[place] = 0;
477
478     zpadlen = max - place;
479     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
480
481     if (zpadlen < 0)
482         zpadlen = 0;
483     if (spadlen < 0)
484         spadlen = 0;
485     if (flags & DP_F_ZERO)
486     {
487         zpadlen = MAX(zpadlen, spadlen);
488         spadlen = 0;
489     }
490     if (flags & DP_F_MINUS) 
491         spadlen = -spadlen; /* Left Justifty */
492
493
494     /* Spaces */
495     while (spadlen > 0)
496     {
497         outch(buffer, currlen, maxlen, ' ');
498         --spadlen;
499     }
500
501     /* Sign */
502     if (signvalue) 
503         outch(buffer, currlen, maxlen, signvalue);
504
505     /* Zeros */
506     if (zpadlen > 0)
507     {
508         while (zpadlen > 0)
509         {
510             outch(buffer, currlen, maxlen, '0');
511             --zpadlen;
512         }
513     }
514
515     /* Digits */
516     while (place > 0) 
517         outch(buffer, currlen, maxlen, convert[--place]);
518   
519     /* Left Justified spaces */
520     while (spadlen < 0)
521     {
522         outch(buffer, currlen, maxlen, ' ');
523         ++spadlen;
524     }
525 }
526
527 static long double 
528 pow10(int exp)
529 {
530     long double result = 1;
531
532     while (exp)
533     {
534         result *= 10;
535         exp--;
536     }
537   
538     return result;
539 }
540
541 static long 
542 round(long double value)
543 {
544     long intpart = (long)value;
545
546     value -= intpart;
547     if (value >= 0.5)
548         intpart++;
549
550     return intpart;
551 }
552
553 static void 
554 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
555       int min, int max, int flags, prfun outch)
556 {
557     char iconvert[20];
558     char fconvert[20];
559     int signvalue = 0;
560     int iplace = 0;
561     int fplace = 0;
562     int padlen = 0; /* amount to pad */
563     int zpadlen = 0; 
564     long intpart;
565     long fracpart;
566     long double ufvalue;
567   
568     /* 
569      * AIX manpage says the default is 0, but Solaris says the default
570      * is 6, and sprintf on AIX defaults to 6
571      */
572     if (max < 0)
573         max = 6;
574
575     ufvalue = abs_val(fvalue);
576
577     if (fvalue < 0)
578         signvalue = '-';
579     else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
580         signvalue = '+';
581     else if (flags & DP_F_SPACE)
582         signvalue = ' ';
583
584     intpart = (long)ufvalue;
585
586     /* 
587      * Sorry, we only support 9 digits past the decimal because of our 
588      * conversion method
589      */
590     if (max > 9)
591         max = 9;
592
593     /* We "cheat" by converting the fractional part to integer by
594      * multiplying by a factor of 10
595      */
596     fracpart = round((pow10 (max)) * (ufvalue - intpart));
597
598     if (fracpart >= pow10 (max))
599     {
600         intpart++;
601         fracpart -= (long)pow10 (max);
602     }
603
604     /* Convert integer part */
605     do
606     {
607         iconvert[iplace++] = digitval[intpart % 10];
608         intpart = (intpart / 10);
609     } while (intpart && (iplace < 20));
610
611     if (iplace == 20) 
612         iplace--;
613
614     iconvert[iplace] = 0;
615
616     /* Convert fractional part */
617     do
618     {
619         fconvert[fplace++] = digitval[fracpart % 10];
620         fracpart = (fracpart / 10);
621     } while (fracpart && (fplace < 20));
622
623     if (fplace == 20) 
624         fplace--;
625
626     fconvert[fplace] = 0;
627
628     /* -1 for decimal point, another -1 if we are printing a sign */
629     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
630     zpadlen = max - fplace;
631     if (zpadlen < 0)
632         zpadlen = 0;
633     if (padlen < 0) 
634         padlen = 0;
635     if (flags & DP_F_MINUS) 
636         padlen = -padlen; /* Left Justifty */
637
638     if ((flags & DP_F_ZERO) && (padlen > 0))
639     {
640         if (signvalue)
641         {
642             outch(buffer, currlen, maxlen, signvalue);
643             --padlen;
644             signvalue = 0;
645         }
646         while (padlen > 0)
647         {
648             outch(buffer, currlen, maxlen, '0');
649             --padlen;
650         }
651     }
652
653     while (padlen > 0)
654     {
655         outch(buffer, currlen, maxlen, ' ');
656         --padlen;
657     }
658
659     if (signvalue) 
660         outch(buffer, currlen, maxlen, signvalue);
661
662     while (iplace > 0) 
663         outch(buffer, currlen, maxlen, iconvert[--iplace]);
664
665     /*
666      * Decimal point.  This should probably use locale to find the correct
667      * char to print out.
668      */
669     outch(buffer, currlen, maxlen, '.');
670
671     while (fplace > 0) 
672         outch(buffer, currlen, maxlen, fconvert[--fplace]);
673
674     while (zpadlen > 0)
675     {
676         outch(buffer, currlen, maxlen, '0');
677         --zpadlen;
678     }
679
680     while (padlen < 0)
681     {
682         outch(buffer, currlen, maxlen, ' ');
683         ++padlen;
684     }
685 }
686
687 static void 
688 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
689 {
690     if (c == -1)
691     {
692         if (*currlen < maxlen - 1) 
693             buffer[*currlen] = '\0';
694         else 
695             buffer[maxlen - 1] = '\0';
696     }
697     else if (*currlen < maxlen)
698         buffer[(*currlen)++] = c;
699 }
700
701 int
702 __sprintf(char *str, const char *fmt, ...) 
703 {
704     int rval;
705     va_list ap;
706     va_start(ap, fmt);
707     rval = vsnprintf(str, 128*1024, fmt, ap);
708     va_end(ap);
709     return rval;
710 }
711
712
713 int 
714 __snprintf(char *str, size_t count, const char *fmt, ...)
715 {
716     int rval;
717     va_list ap;
718
719     va_start(ap, fmt);
720     rval = vsnprintf(str, count, fmt, ap);
721     va_end(ap);
722
723     return rval;
724 }
725
726 int
727 __vsprintf(char *s, const char *format, va_list args)
728 {
729     s[0] = 0;
730     return dopr(s, 0xfffff, format, args, dopr_outch);
731 }
732
733 int
734 __vsnprintf(char *s, size_t count, const char *format, va_list args)
735 {
736     s[0] = 0;
737     return dopr(s, count, format, args, dopr_outch);
738 }