print 64-bit integers on 32-bits systems fully
PRIu64/PRIx64 were only printing the lower 32 bits on 32-bit systems. Signed-off-by: Axel Heider <axelheider@gmx.de>
This commit is contained in:
parent
529bd1bc9b
commit
9eca49f9d5
2 changed files with 46 additions and 23 deletions
|
|
@ -23,6 +23,12 @@ typedef signed long long int64_t;
|
||||||
#define INT64_MAX (0x7FFFFFFFFFFFFFFF)
|
#define INT64_MAX (0x7FFFFFFFFFFFFFFF)
|
||||||
#define INT32_MAX (0x7FFFFFFF)
|
#define INT32_MAX (0x7FFFFFFF)
|
||||||
|
|
||||||
|
typedef uint64_t uintmax_t;
|
||||||
|
typedef int64_t intmax_t;
|
||||||
|
|
||||||
|
#define INTMAX_MAX UINT64_MAX
|
||||||
|
#define UINTMAX_MAX INT64_MAX
|
||||||
|
|
||||||
#define PRId64 "lld"
|
#define PRId64 "lld"
|
||||||
#define PRIi64 "lli"
|
#define PRIi64 "lli"
|
||||||
#define PRIu64 "llu"
|
#define PRIu64 "llu"
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,6 @@ static inline bool_t isdigit(char c)
|
||||||
|
|
||||||
#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
|
#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
|
||||||
|
|
||||||
#define INTMAX_MAX INT32_MAX
|
|
||||||
#define INT_MAX 0x7fffffff
|
|
||||||
|
|
||||||
#define ULONG_MAX ((unsigned long)(-1))
|
|
||||||
|
|
||||||
/* State machine to accept length modifiers + conversion specifiers.
|
/* State machine to accept length modifiers + conversion specifiers.
|
||||||
* Result is 0 on failure, or an argument type to pop on success.
|
* Result is 0 on failure, or an argument type to pop on success.
|
||||||
*/
|
*/
|
||||||
|
|
@ -183,7 +178,7 @@ static const unsigned char states[]['z' - 'A' + 1] = {
|
||||||
#define DIGIT(c) (c - '0')
|
#define DIGIT(c) (c - '0')
|
||||||
|
|
||||||
union arg {
|
union arg {
|
||||||
word_t i;
|
uintmax_t i;
|
||||||
long double f;
|
long double f;
|
||||||
void *p;
|
void *p;
|
||||||
};
|
};
|
||||||
|
|
@ -248,7 +243,7 @@ static const char xdigits[16] = {
|
||||||
"0123456789ABCDEF"
|
"0123456789ABCDEF"
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *fmt_x(word_t x, char *s, int lower)
|
static char *fmt_x(uintmax_t x, char *s, int lower)
|
||||||
{
|
{
|
||||||
for (; x; x >>= 4) {
|
for (; x; x >>= 4) {
|
||||||
*--s = xdigits[(x & 15)] | lower;
|
*--s = xdigits[(x & 15)] | lower;
|
||||||
|
|
@ -256,7 +251,7 @@ static char *fmt_x(word_t x, char *s, int lower)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *fmt_o(word_t x, char *s)
|
static char *fmt_o(uintmax_t x, char *s)
|
||||||
{
|
{
|
||||||
for (; x; x >>= 3) {
|
for (; x; x >>= 3) {
|
||||||
*--s = '0' + (x & 7);
|
*--s = '0' + (x & 7);
|
||||||
|
|
@ -264,14 +259,36 @@ static char *fmt_o(word_t x, char *s)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *fmt_u(word_t x, char *s)
|
static char *fmt_u(uintmax_t x, char *s)
|
||||||
{
|
{
|
||||||
unsigned long y;
|
while (0 != x) {
|
||||||
for (; x > ULONG_MAX; x /= 10) {
|
#if defined(CONFIG_ARCH_AARCH32) || defined(CONFIG_ARCH_RISCV32) || defined(CONFIG_ARCH_IA32)
|
||||||
*--s = '0' + x % 10;
|
/* On 32-bit systems, dividing a 64-bit number by 10 makes the compiler
|
||||||
}
|
* call a helper function from a compiler runtime library. The actual
|
||||||
for (y = x; y; y /= 10) {
|
* function differs, currently for x86 it's __udivdi3(), for ARM its
|
||||||
*--s = '0' + y % 10;
|
* __aeabi_uldivmod() and for RISC-V it's __umoddi3(). The kernel is not
|
||||||
|
* supposed to have dependencies on a compiler library, so the algorithm
|
||||||
|
* below (taken from Hacker's Delight) is used to divide by 10 with only
|
||||||
|
* basic operation and avoiding even multiplication.
|
||||||
|
*/
|
||||||
|
uintmax_t q = (x >> 1) + (x >> 2); /* q = x/2 + x/4 = 3x/4 */
|
||||||
|
q += (q >> 4); /* q += (3x/4)/16 = 51x/2^6 */
|
||||||
|
q += (q >> 8); /* q += (51x/2^6)/2^8 = 13107x/2^14 */
|
||||||
|
q += (q >> 16); /* q += (13107x/2^14)/2^16 = 858993458x/2^30 */
|
||||||
|
q += (q >> 32); /* q += (858993458x/2^30)/2^32 = .../2^62 */
|
||||||
|
q >>= 3; /* q is roughly 0.8x, so q/8 is roughly x/10 */
|
||||||
|
unsigned int rem = x - (((q << 2) + q) << 1); // rem = x - 10q */
|
||||||
|
if (rem > 9) { /* handle rounding issues */
|
||||||
|
q += 1;
|
||||||
|
rem = x - (((q << 2) + q) << 1); /* recalculate reminder */
|
||||||
|
assert(rem <= 9); /* there must be no rounding error now */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uintmax_t q = x / 10;
|
||||||
|
unsigned int rem = x % 10;
|
||||||
|
#endif
|
||||||
|
*--s = '0' + rem;
|
||||||
|
x = q;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +304,7 @@ static int getint(char **s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; isdigit(**s); (*s)++) {
|
for (i = 0; isdigit(**s); (*s)++) {
|
||||||
if (i > INT_MAX / 10U || DIGIT(**s) > INT_MAX - 10 * i) {
|
if (i > INTMAX_MAX / 10U || DIGIT(**s) > INTMAX_MAX - 10 * i) {
|
||||||
i = -1;
|
i = -1;
|
||||||
} else {
|
} else {
|
||||||
i = 10 * i + DIGIT(**s);
|
i = 10 * i + DIGIT(**s);
|
||||||
|
|
@ -305,13 +322,12 @@ static int printf_core(out_wrap_t *f, const char *fmt, va_list *ap, union arg *n
|
||||||
int argpos;
|
int argpos;
|
||||||
unsigned st, ps;
|
unsigned st, ps;
|
||||||
int cnt = 0, l = 0;
|
int cnt = 0, l = 0;
|
||||||
word_t i;
|
char buf[sizeof(uintmax_t) * 3 + 3 + LDBL_MANT_DIG / 4];
|
||||||
char buf[sizeof(word_t) * 3 + 3 + LDBL_MANT_DIG / 4];
|
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
int t, pl;
|
int t, pl;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (l > INT_MAX - cnt) {
|
if (l > INTMAX_MAX - cnt) {
|
||||||
/* This error is only specified for snprintf, for other function
|
/* This error is only specified for snprintf, for other function
|
||||||
* from the printf() family the behavior is unspecified. Stopping
|
* from the printf() family the behavior is unspecified. Stopping
|
||||||
* immediately here also seems sane, otherwise %n could produce
|
* immediately here also seems sane, otherwise %n could produce
|
||||||
|
|
@ -329,7 +345,7 @@ static int printf_core(out_wrap_t *f, const char *fmt, va_list *ap, union arg *n
|
||||||
/* Handle literal text and %% format specifiers */
|
/* Handle literal text and %% format specifiers */
|
||||||
for (a = s; *s && *s != '%'; s++);
|
for (a = s; *s && *s != '%'; s++);
|
||||||
for (z = s; s[0] == '%' && s[1] == '%'; z++, s += 2);
|
for (z = s; s[0] == '%' && s[1] == '%'; z++, s += 2);
|
||||||
if (z - a > INT_MAX - cnt) {
|
if (z - a > INTMAX_MAX - cnt) {
|
||||||
return -1; /* overflow */
|
return -1; /* overflow */
|
||||||
}
|
}
|
||||||
l = z - a;
|
l = z - a;
|
||||||
|
|
@ -473,7 +489,7 @@ static int printf_core(out_wrap_t *f, const char *fmt, va_list *ap, union arg *n
|
||||||
fl &= ~ZERO_PAD;
|
fl &= ~ZERO_PAD;
|
||||||
} else if (t == 's') {
|
} else if (t == 's') {
|
||||||
a = arg.p ? arg.p : "(null)";
|
a = arg.p ? arg.p : "(null)";
|
||||||
z = a + strnlen(a, p < 0 ? INT_MAX : p);
|
z = a + strnlen(a, p < 0 ? UINTPTR_MAX : p);
|
||||||
if (p < 0 && *z) {
|
if (p < 0 && *z) {
|
||||||
return -1; /* overflow */
|
return -1; /* overflow */
|
||||||
}
|
}
|
||||||
|
|
@ -531,13 +547,13 @@ static int printf_core(out_wrap_t *f, const char *fmt, va_list *ap, union arg *n
|
||||||
if (p < z - a) {
|
if (p < z - a) {
|
||||||
p = z - a;
|
p = z - a;
|
||||||
}
|
}
|
||||||
if (p > INT_MAX - pl) {
|
if (p > INTMAX_MAX - pl) {
|
||||||
return -1; /* overflow */
|
return -1; /* overflow */
|
||||||
}
|
}
|
||||||
if (w < pl + p) {
|
if (w < pl + p) {
|
||||||
w = pl + p;
|
w = pl + p;
|
||||||
}
|
}
|
||||||
if (w > INT_MAX - cnt) {
|
if (w > INTMAX_MAX - cnt) {
|
||||||
return -1; /* overflow */
|
return -1; /* overflow */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -558,6 +574,7 @@ static int printf_core(out_wrap_t *f, const char *fmt, va_list *ap, union arg *n
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
for (i = 1; i <= NL_ARGMAX && nl_type[i]; i++) {
|
for (i = 1; i <= NL_ARGMAX && nl_type[i]; i++) {
|
||||||
pop_arg(nl_arg + i, nl_type[i], ap);
|
pop_arg(nl_arg + i, nl_type[i], ap);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue