]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/print.cpp
Restore win32 dir from Branch-5.2 and update it
[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 = (char *)"<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         outch(buffer, currlen, maxlen, ' ');
422         --padlen;
423         ++cnt;
424     }
425     while (*value && (cnt < max)) {
426         outch(buffer, currlen, maxlen, *value++);
427         ++cnt;
428     }
429     while ((padlen < 0) && (cnt < max)) {
430         outch(buffer, currlen, maxlen, ' ');
431         ++padlen;
432         ++cnt;
433     }
434 }
435
436 /* Have to handle DP_F_NUM(ie 0x and 0 alternates) */
437
438 static void
439 fmtint(char *buffer, size_t *currlen, size_t maxlen,
440        INT64 value, int base, int min, int max, int flags, prfun outch)
441 {
442     UINT64 uvalue;
443     char convert[20];
444     int signvalue = 0;
445     int place = 0;
446     int spadlen = 0; /* amount to space pad */
447     int zpadlen = 0; /* amount to zero pad */
448     int caps = 0;
449
450     if (max < 0)
451         max = 0;
452
453     uvalue = value;
454
455     if (!(flags & DP_F_UNSIGNED)) {
456         if (value < 0) {
457             signvalue = '-';
458             uvalue = -value;
459         }
460         else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
461             signvalue = '+';
462         else if (flags & DP_F_SPACE)
463             signvalue = ' ';
464     }
465
466     if (flags & DP_F_UP)
467         caps = 16; /* Should characters be upper case? */
468
469     do {
470         convert[place++] = digitval[(uvalue%base)+caps];
471         uvalue = (uvalue / (unsigned)base);
472     } while (uvalue && (place < 20));
473
474     if (place == 20)
475         place--;
476
477     convert[place] = 0;
478
479     zpadlen = max - place;
480     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
481
482     if (zpadlen < 0)
483         zpadlen = 0;
484     if (spadlen < 0)
485         spadlen = 0;
486     if (flags & DP_F_ZERO) {
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         outch(buffer, currlen, maxlen, ' ');
497         --spadlen;
498     }
499
500     /* Sign */
501     if (signvalue)
502         outch(buffer, currlen, maxlen, signvalue);
503
504     /* Zeros */
505     if (zpadlen > 0) {
506         while (zpadlen > 0) {
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         outch(buffer, currlen, maxlen, ' ');
519         ++spadlen;
520     }
521 }
522
523 static long double
524 pow10(int exp)
525 {
526     long double result = 1;
527
528     while (exp)
529     {
530         result *= 10;
531         exp--;
532     }
533
534     return result;
535 }
536
537 static long
538 round(long double value)
539 {
540     long intpart = (long)value;
541
542     value -= intpart;
543     if (value >= 0.5)
544         intpart++;
545
546     return intpart;
547 }
548
549 static void
550 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
551       int min, int max, int flags, prfun outch)
552 {
553     char iconvert[20];
554     char fconvert[20];
555     int signvalue = 0;
556     int iplace = 0;
557     int fplace = 0;
558     int padlen = 0; /* amount to pad */
559     int zpadlen = 0;
560     long intpart;
561     long fracpart;
562     long double ufvalue;
563
564     /*
565      * AIX manpage says the default is 0, but Solaris says the default
566      * is 6, and sprintf on AIX defaults to 6
567      */
568     if (max < 0)
569         max = 6;
570
571     ufvalue = abs_val(fvalue);
572
573     if (fvalue < 0)
574         signvalue = '-';
575     else if (flags & DP_F_PLUS)  /* Do a sign(+/i) */
576         signvalue = '+';
577     else if (flags & DP_F_SPACE)
578         signvalue = ' ';
579
580     intpart = (long)ufvalue;
581
582     /*
583      * Sorry, we only support 9 digits past the decimal because of our
584      * conversion method
585      */
586     if (max > 9)
587         max = 9;
588
589     /* We "cheat" by converting the fractional part to integer by
590      * multiplying by a factor of 10
591      */
592     fracpart = round((pow10 (max)) * (ufvalue - intpart));
593
594     if (fracpart >= pow10 (max))
595     {
596         intpart++;
597         fracpart -= (long)pow10 (max);
598     }
599
600     /* Convert integer part */
601     do
602     {
603         iconvert[iplace++] = digitval[intpart % 10];
604         intpart = (intpart / 10);
605     } while (intpart && (iplace < 20));
606
607     if (iplace == 20)
608         iplace--;
609
610     iconvert[iplace] = 0;
611
612     /* Convert fractional part */
613     do
614     {
615         fconvert[fplace++] = digitval[fracpart % 10];
616         fracpart = (fracpart / 10);
617     } while (fracpart && (fplace < 20));
618
619     if (fplace == 20)
620         fplace--;
621
622     fconvert[fplace] = 0;
623
624     /* -1 for decimal point, another -1 if we are printing a sign */
625     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
626     zpadlen = max - fplace;
627     if (zpadlen < 0)
628         zpadlen = 0;
629     if (padlen < 0)
630         padlen = 0;
631     if (flags & DP_F_MINUS)
632         padlen = -padlen; /* Left Justifty */
633
634     if ((flags & DP_F_ZERO) && (padlen > 0))
635     {
636         if (signvalue)
637         {
638             outch(buffer, currlen, maxlen, signvalue);
639             --padlen;
640             signvalue = 0;
641         }
642         while (padlen > 0)
643         {
644             outch(buffer, currlen, maxlen, '0');
645             --padlen;
646         }
647     }
648
649     while (padlen > 0)
650     {
651         outch(buffer, currlen, maxlen, ' ');
652         --padlen;
653     }
654
655     if (signvalue)
656         outch(buffer, currlen, maxlen, signvalue);
657
658     while (iplace > 0)
659         outch(buffer, currlen, maxlen, iconvert[--iplace]);
660
661     /*
662      * Decimal point.  This should probably use locale to find the correct
663      * char to print out.
664      */
665     outch(buffer, currlen, maxlen, '.');
666
667     while (fplace > 0)
668         outch(buffer, currlen, maxlen, fconvert[--fplace]);
669
670     while (zpadlen > 0)
671     {
672         outch(buffer, currlen, maxlen, '0');
673         --zpadlen;
674     }
675
676     while (padlen < 0)
677     {
678         outch(buffer, currlen, maxlen, ' ');
679         ++padlen;
680     }
681 }
682
683 static void
684 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
685 {
686     if (c == -1)
687     {
688         if (*currlen < maxlen - 1)
689             buffer[*currlen] = '\0';
690         else
691             buffer[maxlen - 1] = '\0';
692     }
693     else if (*currlen < maxlen)
694         buffer[(*currlen)++] = c;
695 }
696
697 int
698 __sprintf(char *str, const char *fmt, ...)
699 {
700     int rval;
701     va_list ap;
702     va_start(ap, fmt);
703     rval = vsnprintf(str, 128*1024, fmt, ap);
704     va_end(ap);
705     return rval;
706 }
707
708
709 int
710 __snprintf(char *str, size_t count, const char *fmt, ...)
711 {
712     int rval;
713     va_list ap;
714
715     va_start(ap, fmt);
716     rval = vsnprintf(str, count, fmt, ap);
717     va_end(ap);
718
719     return rval;
720 }
721
722 int
723 __vsprintf(char *s, const char *format, va_list args)
724 {
725     s[0] = 0;
726     return dopr(s, 0xfffff, format, args, dopr_outch);
727 }
728
729 int
730 __vsnprintf(char *s, size_t count, const char *format, va_list args)
731 {
732     s[0] = 0;
733     return dopr(s, count, format, args, dopr_outch);
734 }