Lib: Support for 64-bit numbers in bvsnprintf()
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.
This commit is contained in:
parent
cc95b4594a
commit
759b204be3
4 changed files with 50 additions and 35 deletions
65
lib/printf.c
65
lib/printf.c
|
@ -34,13 +34,7 @@ static int skip_atoi(const char **s)
|
||||||
#define SPECIAL 32 /* 0x */
|
#define SPECIAL 32 /* 0x */
|
||||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||||
|
|
||||||
#define do_div(n,base) ({ \
|
static char * number(char * str, u64 num, uint base, int size, int precision,
|
||||||
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,
|
|
||||||
int type, int remains)
|
int type, int remains)
|
||||||
{
|
{
|
||||||
char c,sign,tmp[66];
|
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' : ' ';
|
c = (type & ZEROPAD) ? '0' : ' ';
|
||||||
sign = 0;
|
sign = 0;
|
||||||
if (type & SIGN) {
|
if (type & SIGN) {
|
||||||
if (num < 0) {
|
if (num > (u64) INT64_MAX) {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
num = -num;
|
num = -num;
|
||||||
size--;
|
size--;
|
||||||
|
@ -79,8 +73,11 @@ static char * number(char * str, long num, int base, int size, int precision,
|
||||||
i = 0;
|
i = 0;
|
||||||
if (num == 0)
|
if (num == 0)
|
||||||
tmp[i++]='0';
|
tmp[i++]='0';
|
||||||
else while (num != 0)
|
else while (num != 0) {
|
||||||
tmp[i++] = digits[do_div(num,base)];
|
uint res = num % base;
|
||||||
|
num = num / base;
|
||||||
|
tmp[i++] = digits[res];
|
||||||
|
}
|
||||||
if (i > precision)
|
if (i > precision)
|
||||||
precision = i;
|
precision = i;
|
||||||
size -= precision;
|
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
|
* value printed as eight :-separated octets), |%t| for time values (btime) with
|
||||||
* specified subsecond precision, and |%m| resp. |%M| for error messages (uses
|
* specified subsecond precision, and |%m| resp. |%M| for error messages (uses
|
||||||
* strerror() to translate @errno code to message text). On the other hand, it
|
* 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
|
* Result: number of characters of the output string or -1 if
|
||||||
* the buffer space was insufficient.
|
* the buffer space was insufficient.
|
||||||
*/
|
*/
|
||||||
int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
int len;
|
int len, i;
|
||||||
unsigned long num;
|
u64 num;
|
||||||
int i, base;
|
uint base;
|
||||||
u32 x;
|
u32 x;
|
||||||
u64 X;
|
u64 X;
|
||||||
btime t;
|
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 field_width; /* width of output field */
|
||||||
int precision; /* min. # of digits for integers; max
|
int precision; /* min. # of digits for integers; max
|
||||||
number of chars for from string */
|
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) {
|
for (start=str=buf ; *fmt ; ++fmt, size-=(str-start), start=str) {
|
||||||
if (*fmt != '%') {
|
if (*fmt != '%') {
|
||||||
|
@ -286,16 +284,15 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
field_width = 2*sizeof(void *);
|
field_width = 2*sizeof(void *);
|
||||||
flags |= ZEROPAD;
|
flags |= ZEROPAD;
|
||||||
}
|
}
|
||||||
str = number(str,
|
str = number(str, (uintptr_t) va_arg(args, void *), 16,
|
||||||
(unsigned long) va_arg(args, void *), 16,
|
field_width, precision, flags, size);
|
||||||
field_width, precision, flags, size);
|
|
||||||
if (!str)
|
if (!str)
|
||||||
return -1;
|
return -1;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
if (qualifier == 'l') {
|
if (qualifier == 'l') {
|
||||||
long * ip = va_arg(args, long *);
|
s64 * ip = va_arg(args, s64 *);
|
||||||
*ip = (str - buf);
|
*ip = (str - buf);
|
||||||
} else {
|
} else {
|
||||||
int * ip = va_arg(args, int *);
|
int * ip = va_arg(args, int *);
|
||||||
|
@ -393,7 +390,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
|
|
||||||
/* Print seconds */
|
/* Print seconds */
|
||||||
flags |= SIGN;
|
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)
|
if (!str)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -411,7 +408,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
|
|
||||||
/* Print sub-seconds */
|
/* Print sub-seconds */
|
||||||
*str++ = '.';
|
*str++ = '.';
|
||||||
str = number(str, t2, 10, precision, 0, ZEROPAD, size - 1);
|
str = number(str, (u64) t2, 10, precision, 0, ZEROPAD, size - 1);
|
||||||
if (!str)
|
if (!str)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -446,16 +443,22 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
--fmt;
|
--fmt;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (qualifier == 'l')
|
if (flags & SIGN) {
|
||||||
num = va_arg(args, unsigned long);
|
/* Conversions valid per ISO C99 6.3.1.3 (2) */
|
||||||
else if (qualifier == 'h') {
|
if (qualifier == 'l')
|
||||||
num = (unsigned short) va_arg(args, int);
|
num = (u64) va_arg(args, s64);
|
||||||
if (flags & SIGN)
|
else if (qualifier == 'h')
|
||||||
num = (short) num;
|
num = (u64) (short) va_arg(args, int);
|
||||||
} else if (flags & SIGN)
|
else
|
||||||
num = va_arg(args, int);
|
num = (u64) va_arg(args, int);
|
||||||
else
|
} else {
|
||||||
num = va_arg(args, uint);
|
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);
|
str = number(str, num, base, field_width, precision, flags, size);
|
||||||
if (!str)
|
if (!str)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -45,7 +45,7 @@ t_simple(void)
|
||||||
else
|
else
|
||||||
BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
|
BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
|
||||||
|
|
||||||
long ln = 0;
|
s64 ln = 0;
|
||||||
BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
|
BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
|
||||||
bt_assert_msg(ln == 5, "fmt=\"TeStS%%lntRiNg\", &ln makes ln=%ld, want 5", 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(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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ perf_loop(void *data)
|
||||||
s64 withdrawtime = timediff(&ts_update, &ts_withdraw);
|
s64 withdrawtime = timediff(&ts_update, &ts_withdraw);
|
||||||
|
|
||||||
if (updatetime NS >= p->threshold_min)
|
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);
|
p->exp, gentime, updatetime, withdrawtime);
|
||||||
|
|
||||||
if (updatetime NS < p->threshold_max)
|
if (updatetime NS < p->threshold_max)
|
||||||
|
|
|
@ -533,7 +533,7 @@ write_pid_file(void)
|
||||||
|
|
||||||
/* We don't use PID file for uniqueness, so no need for locking */
|
/* 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)
|
if (pl < 0)
|
||||||
bug("PID buffer too small");
|
bug("PID buffer too small");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue