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
10 Bacula(R) - The Network Backup Solution
12 Copyright (C) 2000-2018 Kern Sibbald
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.
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.
22 This notice must be preserved when any source code is
23 conveyed and/or propagated.
25 Bacula(R) is a registered trademark of Kern Sibbald.
28 * Copyright Patrick Powell 1995
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.
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.
38 * Kern Sibbald, November MMV
41 /**************************************************************
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...
48 * snprintf() is used instead of sprintf() as it does limit checks
49 * for string length. This covers a nasty loophole.
51 * The other functions are there to prevent NULL pointers from
52 * causing nast effects.
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.
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.
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.
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.
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
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 **************************************************************/
95 typedef void (prfun)(char *, size_t *, size_t, int);
98 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun);
102 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
103 int min, int max, prfun);
106 fmtint(char *buffer, size_t *currlen, size_t maxlen, INT64 value, int base,
107 int min, int max, int flags, prfun);
110 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
111 int min, int max, int flags, prfun);
114 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c);
117 * dopr(): poor man's version of doprintf
121 #define MAX(a,b) ((a)>(b)?(a):(b))
124 /* format read states */
125 #define DP_S_DEFAULT 0
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)
143 /* Conversion Flags */
146 #define DP_C_LDOUBLE 3
147 #define DP_C_LONG_LONG 4
149 #define char_to_int(p) (p - '0')
150 #define abs_val(p) (p < 0 ? -p : p)
152 static const char digitval[] = "0123456789abcdef0123456789ABCDEF";
155 dopr(char *buffer, size_t maxlen, const char *format, va_list args, prfun outch)
163 int state = DP_S_DEFAULT;
170 while (state != DP_S_DONE)
172 if ((ch == '\0') || (currlen >= maxlen))
181 outch(buffer, &currlen, maxlen, ch);
213 if (isdigit((unsigned char)ch))
215 min = 10*min + char_to_int(ch);
220 min = va_arg(args, int);
237 if (isdigit((unsigned char)ch))
241 max = 10*max + char_to_int(ch);
246 max = va_arg(args, int);
265 cflags = DP_C_LONG_LONG;
270 cflags = DP_C_LONG_LONG;
274 cflags = DP_C_LDOUBLE;
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);
294 value = va_arg(args, unsigned int);
295 fmtint(buffer, &currlen, maxlen, value, 2, min, max, flags, outch);
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);
306 value = va_arg(args, int);
307 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
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);
318 value = va_arg(args, unsigned int);
319 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags, outch);
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);
330 value = va_arg(args, unsigned int);
331 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags, outch);
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);
344 value = va_arg(args, unsigned int);
345 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags, outch);
348 if (cflags == DP_C_LDOUBLE)
349 fvalue = va_arg(args, long double);
351 fvalue = va_arg(args, double);
352 /* um, floating point? */
353 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags, outch);
358 if (cflags == DP_C_LDOUBLE)
359 fvalue = va_arg(args, long double);
361 fvalue = va_arg(args, double);
366 if (cflags == DP_C_LDOUBLE)
367 fvalue = va_arg(args, long double);
369 fvalue = va_arg(args, double);
372 outch(buffer, &currlen, maxlen, va_arg(args, int));
375 strvalue = va_arg(args, char *);
377 max = maxlen; /* ie, no max */
379 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max, outch);
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);
388 value = 0; /* we have a problem */
390 fmtint(buffer, &currlen, maxlen, value, 16, min, max,
394 if (cflags == DP_C_SHORT)
397 num = va_arg(args, short int *);
400 else if (cflags == DP_C_LONG)
403 num = va_arg(args, long int *);
406 else if (cflags == DP_C_LONG_LONG)
409 num = va_arg(args, INT64 *);
415 num = va_arg(args, int *);
420 outch(buffer, &currlen, maxlen, ch);
422 case 'w': /* not supported yet, treat as next char */
425 default: /* Unknown, skip */
429 state = DP_S_DEFAULT;
430 flags = cflags = min = 0;
436 break; /* some picky compilers need this */
439 outch(buffer, &currlen, maxlen, -1);
444 fmtstr(char *buffer, size_t *currlen, size_t maxlen,
445 char *value, int flags, int min, int max, prfun outch)
447 int padlen, strln; /* amount to pad */
451 value = (char *)"<NULL>";
453 for (strln = 0; value[strln]; ++strln); /* strlen */
454 padlen = min - strln;
457 if (flags & DP_F_MINUS)
458 padlen = -padlen; /* Left Justify */
460 while ((padlen > 0) && (cnt < max)) {
461 outch(buffer, currlen, maxlen, ' ');
465 while (*value && (cnt < max)) {
466 outch(buffer, currlen, maxlen, *value++);
469 while ((padlen < 0) && (cnt < max)) {
470 outch(buffer, currlen, maxlen, ' ');
476 /* Have to handle DP_F_NUM(ie 0x and 0 alternates) */
479 fmtint(char *buffer, size_t *currlen, size_t maxlen,
480 INT64 value, int base, int min, int max, int flags, prfun outch)
486 int spadlen = 0; /* amount to space pad */
487 int zpadlen = 0; /* amount to zero pad */
495 if (!(flags & DP_F_UNSIGNED)) {
500 else if (flags & DP_F_PLUS) /* Do a sign(+/i) */
502 else if (flags & DP_F_SPACE)
507 caps = 16; /* Should characters be upper case? */
510 convert[place++] = digitval[(uvalue%base)+caps];
511 uvalue = (uvalue / (unsigned)base);
512 } while (uvalue && (place < 20));
519 zpadlen = max - place;
520 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
526 if (flags & DP_F_ZERO) {
527 zpadlen = MAX(zpadlen, spadlen);
530 if (flags & DP_F_MINUS)
531 spadlen = -spadlen; /* Left Justifty */
535 while (spadlen > 0) {
536 outch(buffer, currlen, maxlen, ' ');
542 outch(buffer, currlen, maxlen, signvalue);
546 while (zpadlen > 0) {
547 outch(buffer, currlen, maxlen, '0');
554 outch(buffer, currlen, maxlen, convert[--place]);
556 /* Left Justified spaces */
557 while (spadlen < 0) {
558 outch(buffer, currlen, maxlen, ' ');
566 long double result = 1;
578 round(long double value)
580 long intpart = (long)value;
590 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
591 int min, int max, int flags, prfun outch)
598 int padlen = 0; /* amount to pad */
605 * AIX manpage says the default is 0, but Solaris says the default
606 * is 6, and sprintf on AIX defaults to 6
611 ufvalue = abs_val(fvalue);
615 else if (flags & DP_F_PLUS) /* Do a sign(+/i) */
617 else if (flags & DP_F_SPACE)
620 intpart = (long)ufvalue;
623 * Sorry, we only support 9 digits past the decimal because of our
629 /* We "cheat" by converting the fractional part to integer by
630 * multiplying by a factor of 10
632 fracpart = round((pow10 (max)) * (ufvalue - intpart));
634 if (fracpart >= pow10 (max))
637 fracpart -= (long)pow10 (max);
640 /* Convert integer part */
643 iconvert[iplace++] = digitval[intpart % 10];
644 intpart = (intpart / 10);
645 } while (intpart && (iplace < 20));
650 iconvert[iplace] = 0;
652 /* Convert fractional part */
655 fconvert[fplace++] = digitval[fracpart % 10];
656 fracpart = (fracpart / 10);
657 } while (fracpart && (fplace < 20));
662 fconvert[fplace] = 0;
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;
671 if (flags & DP_F_MINUS)
672 padlen = -padlen; /* Left Justifty */
674 if ((flags & DP_F_ZERO) && (padlen > 0))
678 outch(buffer, currlen, maxlen, signvalue);
684 outch(buffer, currlen, maxlen, '0');
691 outch(buffer, currlen, maxlen, ' ');
696 outch(buffer, currlen, maxlen, signvalue);
699 outch(buffer, currlen, maxlen, iconvert[--iplace]);
702 * Decimal point. This should probably use locale to find the correct
705 outch(buffer, currlen, maxlen, '.');
708 outch(buffer, currlen, maxlen, fconvert[--fplace]);
712 outch(buffer, currlen, maxlen, '0');
718 outch(buffer, currlen, maxlen, ' ');
724 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
728 if (*currlen < maxlen - 1)
729 buffer[*currlen] = '\0';
731 buffer[maxlen - 1] = '\0';
733 else if (*currlen < maxlen)
734 buffer[(*currlen)++] = c;
738 __sprintf(char *str, const char *fmt, ...)
743 rval = vsnprintf(str, 128*1024, fmt, ap);
750 __snprintf(char *str, size_t count, const char *fmt, ...)
756 rval = vsnprintf(str, count, fmt, ap);
763 __vsprintf(char *s, const char *format, va_list args)
766 return dopr(s, 0xfffff, format, args, dopr_outch);
770 __vsnprintf(char *s, size_t count, const char *format, va_list args)
773 return dopr(s, count, format, args, dopr_outch);