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