Skip to content

Commit 0a4f9ec

Browse files
jeplerdpgeorge
authored andcommitted
py/mpprint: Rework integer vararg handling.
This adds support for %llx (needed by XINT_FMT for printing cell objects) and incidentally support for capitalized output of %P. It also reduces code size due to the common handling of all integers. Signed-off-by: Jeff Epler <jepler@gmail.com>
1 parent 5e9189d commit 0a4f9ec

File tree

1 file changed

+60
-37
lines changed

1 file changed

+60
-37
lines changed

py/mpprint.c

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -446,16 +446,36 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
446446
}
447447
}
448448

449-
// parse long specifiers (only for LP64 model where they make a difference)
450-
#ifndef __LP64__
451-
const
449+
// parse long and long long specifiers (only where they make a difference)
450+
#if defined(MICROPY_UNIX_COVERAGE) || (LONG_MAX > INT_MAX)
451+
#define SUPPORT_L_FORMAT (1)
452+
#else
453+
#define SUPPORT_L_FORMAT (0)
452454
#endif
455+
#if SUPPORT_L_FORMAT
453456
bool long_arg = false;
457+
#endif
458+
459+
#if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) || defined(MICROPY_UNIX_COVERAGE)
460+
#define SUPPORT_LL_FORMAT (1)
461+
#else
462+
#define SUPPORT_LL_FORMAT (0)
463+
#endif
464+
#if SUPPORT_LL_FORMAT
465+
bool long_long_arg = false;
466+
#endif
467+
454468
if (*fmt == 'l') {
455469
++fmt;
456-
#ifdef __LP64__
470+
#if SUPPORT_L_FORMAT
457471
long_arg = true;
458472
#endif
473+
#if SUPPORT_LL_FORMAT
474+
if (*fmt == 'l') {
475+
++fmt;
476+
long_long_arg = true;
477+
}
478+
#endif
459479
}
460480

461481
if (*fmt == '\0') {
@@ -501,35 +521,50 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
501521
chrs += mp_print_strn(print, str, len, flags, fill, width);
502522
break;
503523
}
504-
case 'd': {
505-
mp_int_t val;
506-
if (long_arg) {
507-
val = va_arg(args, long int);
508-
} else {
509-
val = va_arg(args, int);
510-
}
511-
chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width);
512-
break;
513-
}
524+
case 'd':
525+
case 'p':
526+
case 'P':
514527
case 'u':
515528
case 'x':
516529
case 'X': {
517-
int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16
518-
char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A
530+
char fmt_chr = *fmt;
519531
mp_uint_t val;
520-
if (long_arg) {
521-
val = va_arg(args, unsigned long int);
532+
if (fmt_chr == 'p' || fmt_chr == 'P') {
533+
val = va_arg(args, intptr_t);
534+
}
535+
#if SUPPORT_LL_FORMAT
536+
else if (long_long_arg) {
537+
val = va_arg(args, unsigned long long);
538+
}
539+
#endif
540+
#if SUPPORT_L_FORMAT
541+
else if (long_arg) {
542+
if (sizeof(long) != sizeof(mp_uint_t) && fmt_chr == 'd') {
543+
val = va_arg(args, long);
544+
} else {
545+
val = va_arg(args, unsigned long);
546+
}
547+
}
548+
#endif
549+
else {
550+
if (sizeof(int) != sizeof(mp_uint_t) && fmt_chr == 'd') {
551+
val = va_arg(args, int);
552+
} else {
553+
val = va_arg(args, unsigned);
554+
}
555+
}
556+
int base;
557+
// Map format char x/p/X/P to a/a/A/A for hex letters.
558+
// It doesn't matter what d/u map to.
559+
char fmt_c = (fmt_chr & 0xf0) - 'P' + 'A';
560+
if (fmt_chr == 'd' || fmt_chr == 'u') {
561+
base = 10;
522562
} else {
523-
val = va_arg(args, unsigned int);
563+
base = 16;
524564
}
525-
chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width);
565+
chrs += mp_print_int(print, val, fmt_chr == 'd', base, fmt_c, flags, fill, width);
526566
break;
527567
}
528-
case 'p':
529-
case 'P': // don't bother to handle upcase for 'P'
530-
// Use unsigned long int to work on both ILP32 and LP64 systems
531-
chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);
532-
break;
533568
#if MICROPY_PY_BUILTINS_FLOAT
534569
case 'e':
535570
case 'E':
@@ -545,18 +580,6 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
545580
#endif
546581
break;
547582
}
548-
#endif
549-
// Because 'l' is eaten above, another 'l' means %ll. We need to support
550-
// this length specifier for OBJ_REPR_D (64-bit NaN boxing).
551-
// TODO Either enable this unconditionally, or provide a specific config var.
552-
#if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64)
553-
case 'l': {
554-
unsigned long long int arg_value = va_arg(args, unsigned long long int);
555-
++fmt;
556-
assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
557-
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
558-
break;
559-
}
560583
#endif
561584
default:
562585
// if it's not %% then it's an unsupported format character

0 commit comments

Comments
 (0)