]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Lib: Support for 64-bit numbers in bvsnprintf()
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 1 Oct 2019 15:01:29 +0000 (17:01 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 9 Oct 2019 15:53:23 +0000 (17:53 +0200)
Use 'l' for s64/u64 instead of for long/ulong, as that is much more
useful. Also make number() correct with regard to signed/unsigned
typecasts.

lib/printf.c
lib/printf_test.c
proto/perf/perf.c
sysdep/unix/main.c

index 8f2cccb30ef47acb40d5e820cbe47b546e38961b..236df427474ffa2bb11f7638367d492efb0809e9 100644 (file)
@@ -34,13 +34,7 @@ static int skip_atoi(const char **s)
 #define SPECIAL        32              /* 0x */
 #define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
-static char * number(char * str, long num, int base, int size, int precision,
+static char * number(char * str, u64 num, uint base, int size, int precision,
        int type, int remains)
 {
        char c,sign,tmp[66];
@@ -58,7 +52,7 @@ static char * number(char * str, long num, int base, int size, int precision,
        c = (type & ZEROPAD) ? '0' : ' ';
        sign = 0;
        if (type & SIGN) {
-               if (num < 0) {
+               if (num > (u64) INT64_MAX) {
                        sign = '-';
                        num = -num;
                        size--;
@@ -79,8 +73,11 @@ static char * number(char * str, long num, int base, int size, int precision,
        i = 0;
        if (num == 0)
                tmp[i++]='0';
-       else while (num != 0)
-               tmp[i++] = digits[do_div(num,base)];
+       else while (num != 0) {
+               uint res = num % base;
+               num = num / base;
+               tmp[i++] = digits[res];
+       }
        if (i > precision)
                precision = i;
        size -= precision;
@@ -128,16 +125,17 @@ static char * number(char * str, long num, int base, int size, int precision,
  * value printed as eight :-separated octets), |%t| for time values (btime) with
  * specified subsecond precision, and |%m| resp. |%M| for error messages (uses
  * strerror() to translate @errno code to message text). On the other hand, it
- * doesn't support floating point numbers.
+ * doesn't support floating point numbers. The bvsnprintf() supports |%h| and
+ * |%l| qualifiers, but |%l| is used for s64/u64 instead of long/ulong.
  *
  * Result: number of characters of the output string or -1 if
  * the buffer space was insufficient.
  */
 int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
 {
-       int len;
-       unsigned long num;
-       int i, base;
+       int len, i;
+       u64 num;
+       uint base;
        u32 x;
        u64 X;
        btime t;
@@ -152,7 +150,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
        int field_width;        /* width of output field */
        int precision;          /* min. # of digits for integers; max
                                   number of chars for from string */
-       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+       int qualifier;          /* 'h' or 'l' for integer fields */
 
        for (start=str=buf ; *fmt ; ++fmt, size-=(str-start), start=str) {
                if (*fmt != '%') {
@@ -286,16 +284,15 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
                                field_width = 2*sizeof(void *);
                                flags |= ZEROPAD;
                        }
-                       str = number(str,
-                               (unsigned long) va_arg(args, void *), 16,
-                               field_width, precision, flags, size);
+                       str = number(str, (uintptr_t) va_arg(args, void *), 16,
+                                    field_width, precision, flags, size);
                        if (!str)
                                return -1;
                        continue;
 
                case 'n':
                        if (qualifier == 'l') {
-                               long * ip = va_arg(args, long *);
+                               s64 * ip = va_arg(args, s64 *);
                                *ip = (str - buf);
                        } else {
                                int * ip = va_arg(args, int *);
@@ -393,7 +390,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
 
                        /* Print seconds */
                        flags |= SIGN;
-                       str = number(str, t1, 10, field_width, 0, flags, size);
+                       str = number(str, (u64) t1, 10, field_width, 0, flags, size);
                        if (!str)
                          return -1;
 
@@ -411,7 +408,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
 
                          /* Print sub-seconds */
                          *str++ = '.';
-                         str = number(str, t2, 10, precision, 0, ZEROPAD, size - 1);
+                         str = number(str, (u64) t2, 10, precision, 0, ZEROPAD, size - 1);
                          if (!str)
                            return -1;
                        }
@@ -446,16 +443,22 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
                                --fmt;
                        continue;
                }
-               if (qualifier == 'l')
-                       num = va_arg(args, unsigned long);
-               else if (qualifier == 'h') {
-                       num = (unsigned short) va_arg(args, int);
-                       if (flags & SIGN)
-                               num = (short) num;
-               } else if (flags & SIGN)
-                       num = va_arg(args, int);
-               else
-                       num = va_arg(args, uint);
+               if (flags & SIGN) {
+                       /* Conversions valid per ISO C99 6.3.1.3 (2) */
+                       if (qualifier == 'l')
+                               num = (u64) va_arg(args, s64);
+                       else if (qualifier == 'h')
+                               num = (u64) (short) va_arg(args, int);
+                       else
+                               num = (u64) va_arg(args, int);
+               } else {
+                       if (qualifier == 'l')
+                               num = va_arg(args, u64);
+                       else if (qualifier == 'h')
+                               num = (unsigned short) va_arg(args, int);
+                       else
+                               num = va_arg(args, uint);
+               }
                str = number(str, num, base, field_width, precision, flags, size);
                if (!str)
                        return -1;
index 341fde9cfbc3efa2e62eb72b0c9776a6d5faf8e7..47ea905d00713ecf46d2147ec57229ab1805c728 100644 (file)
@@ -45,7 +45,7 @@ t_simple(void)
   else
     BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
 
-  long ln = 0;
+  s64 ln = 0;
   BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
   bt_assert_msg(ln == 5, "fmt=\"TeStS%%lntRiNg\", &ln makes ln=%ld, want 5", ln);
 
@@ -54,7 +54,19 @@ t_simple(void)
   BSPRINTF(2, "+1", buf, "%+d", 1);
   BSPRINTF(2, " 1", buf, "% d", 1);
   BSPRINTF(2, "-1", buf, "%d", -1);
-  BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
+  BSPRINTF(11, "-2147483648", buf, "%d", INT32_MIN);
+  BSPRINTF(10,  "2147483647", buf, "%d", INT32_MAX);
+
+  BSPRINTF(1,  "0", buf, "%u", 0x0);
+  BSPRINTF(10, "4294967295", buf, "%u", 0xFFFFFFFF);
+
+  BSPRINTF(4,  "-100", buf, "%ld", (s64) -100);
+  BSPRINTF(3,   "100", buf, "%ld", (s64)  100);
+  BSPRINTF(20, "-9223372036854775808", buf, "%ld", INT64_MIN);
+  BSPRINTF(19,  "9223372036854775807", buf, "%ld", INT64_MAX);
+
+  BSPRINTF(3,  "0 8", buf, "%lu %lu", U64(0), U64(8));
+  BSPRINTF(20, "18446744073709551615", buf, "%lu", UINT64_MAX);
 
   return 1;
 }
index d48ad75170243bda3863fe081c22071159d0269a..dfbd0884c7d261d8b050f50ef385b8d91da51b1d 100644 (file)
@@ -192,7 +192,7 @@ perf_loop(void *data)
   s64 withdrawtime = timediff(&ts_update, &ts_withdraw);
 
   if (updatetime NS >= p->threshold_min)
-    PLOG("exp=%u times: gen=%lu update=%lu withdraw=%lu",
+    PLOG("exp=%u times: gen=%ld update=%ld withdraw=%ld",
        p->exp, gentime, updatetime, withdrawtime);
 
   if (updatetime NS < p->threshold_max)
index a52ae3caf8bd0f5b2b139cd0330d4a79081ed557..282afae220d2cf0a77702dbf60769e108a21b54e 100644 (file)
@@ -533,7 +533,7 @@ write_pid_file(void)
 
   /* We don't use PID file for uniqueness, so no need for locking */
 
-  pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
+  pl = bsnprintf(ps, sizeof(ps), "%ld\n", (s64) getpid());
   if (pl < 0)
     bug("PID buffer too small");