Skip to content

mpprint: Rework integer vararg handling. #17618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions ports/unix/coverage.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,20 @@ static mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign
mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding
mp_printf(&mp_plat_print, "%ld\n", 123); // long
mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex
mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex
mp_printf(&mp_plat_print, "%lx\n", 0x123fl); // long hex
mp_printf(&mp_plat_print, "%lX\n", 0x123fl); // capital long hex
if (sizeof(mp_int_t) == 8) {
mp_printf(&mp_plat_print, "%llx\n", LLONG_MAX); // long long hex
mp_printf(&mp_plat_print, "%llX\n", LLONG_MAX); // capital long long hex
mp_printf(&mp_plat_print, "%llu\n", ULLONG_MAX); // unsigned long long
} else {
// fake for platforms without narrower mp_int_t
mp_printf(&mp_plat_print, "7fffffffffffffff\n", LLONG_MAX);
mp_printf(&mp_plat_print, "7FFFFFFFFFFFFFFF\n", LLONG_MAX);
mp_printf(&mp_plat_print, "18446744073709551615\n", ULLONG_MAX);
}
mp_printf(&mp_plat_print, "%p\n", (void *)0x789f); // pointer
mp_printf(&mp_plat_print, "%P\n", (void *)0x789f); // pointer uppercase
mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision
mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision
mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools
Expand All @@ -216,11 +228,31 @@ static mp_obj_t extra_coverage(void) {
#endif
mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed
mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned
mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned
mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned
mp_printf(&mp_plat_print, "%x\n", 0x8000000f); // should print unsigned
mp_printf(&mp_plat_print, "%X\n", 0x8000000f); // should print unsigned
mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier
mp_printf(&mp_plat_print, "%%\n"); // literal % character
mp_printf(&mp_plat_print, ".%-3s.\n", "a"); // left adjust

// Check that all kinds of mp_printf arguments are parsed out
// correctly, by having a char argument before and after each main type
// of value that can be formatted.
mp_printf(&mp_plat_print, "%c%%%c\n", '<', '>');
mp_printf(&mp_plat_print, "%c%p%c\n", '<', (void *)0xaaaa, '>');
mp_printf(&mp_plat_print, "%c%b%c\n", '<', true, '>');
mp_printf(&mp_plat_print, "%c%d%c\n", '<', 0xaaaa, '>');
mp_printf(&mp_plat_print, "%c%ld%c\n", '<', 0xaaaal, '>');
mp_printf(&mp_plat_print, "%c" INT_FMT "%c\n", '<', (mp_int_t)0xaaaa, '>');
mp_printf(&mp_plat_print, "%c%s%c\n", '<', "test", '>');
mp_printf(&mp_plat_print, "%c%f%c\n", '<', MICROPY_FLOAT_CONST(1000.), '>');
mp_printf(&mp_plat_print, "%c%q%c\n", '<', (qstr)MP_QSTR_True, '>');
if (sizeof(mp_int_t) == 8) {
mp_printf(&mp_plat_print, "%c%lld%c\n", '<', LLONG_MAX, '>');
} else {
mp_printf(&mp_plat_print, "<9223372036854775807>\n");
}


}

// GC
Expand Down
97 changes: 60 additions & 37 deletions py/mpprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,16 +446,36 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
}
}

// parse long specifiers (only for LP64 model where they make a difference)
#ifndef __LP64__
const
// parse long and long long specifiers (only where they make a difference)
#if defined(MICROPY_UNIX_COVERAGE) || (LONG_MAX > INT_MAX)
#define SUPPORT_L_FORMAT (1)
#else
#define SUPPORT_L_FORMAT (0)
#endif
#if SUPPORT_L_FORMAT
bool long_arg = false;
#endif

#if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) || defined(MICROPY_UNIX_COVERAGE)
#define SUPPORT_LL_FORMAT (1)
#else
#define SUPPORT_LL_FORMAT (0)
#endif
#if SUPPORT_LL_FORMAT
bool long_long_arg = false;
#endif

if (*fmt == 'l') {
++fmt;
#ifdef __LP64__
#if SUPPORT_L_FORMAT
long_arg = true;
#endif
#if SUPPORT_LL_FORMAT
if (*fmt == 'l') {
++fmt;
long_long_arg = true;
}
#endif
}

if (*fmt == '\0') {
Expand Down Expand Up @@ -501,35 +521,50 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
chrs += mp_print_strn(print, str, len, flags, fill, width);
break;
}
case 'd': {
mp_int_t val;
if (long_arg) {
val = va_arg(args, long int);
} else {
val = va_arg(args, int);
}
chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width);
break;
}
case 'd':
case 'p':
case 'P':
case 'u':
case 'x':
case 'X': {
int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16
char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A
char fmt_chr = *fmt;
mp_uint_t val;
if (long_arg) {
val = va_arg(args, unsigned long int);
if (fmt_chr == 'p' || fmt_chr == 'P') {
val = va_arg(args, intptr_t);
}
#if SUPPORT_LL_FORMAT
else if (long_long_arg) {
val = va_arg(args, unsigned long long);
}
#endif
#if SUPPORT_L_FORMAT
else if (long_arg) {
if (sizeof(long) != sizeof(mp_uint_t) && fmt_chr == 'd') {
val = va_arg(args, long);
} else {
val = va_arg(args, unsigned long);
}
}
#endif
else {
if (sizeof(int) != sizeof(mp_uint_t) && fmt_chr == 'd') {
val = va_arg(args, int);
} else {
val = va_arg(args, unsigned);
}
}
int base;
// Map format char x/p/X/P to a/a/A/A for hex letters.
// It doesn't matter what d/u map to.
char fmt_c = (fmt_chr & 0xf0) - 'P' + 'A';
if (fmt_chr == 'd' || fmt_chr == 'u') {
base = 10;
} else {
val = va_arg(args, unsigned int);
base = 16;
}
chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width);
chrs += mp_print_int(print, val, fmt_chr == 'd', base, fmt_c, flags, fill, width);
break;
}
case 'p':
case 'P': // don't bother to handle upcase for 'P'
// Use unsigned long int to work on both ILP32 and LP64 systems
chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
Expand All @@ -545,18 +580,6 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
#endif
break;
}
#endif
// Because 'l' is eaten above, another 'l' means %ll. We need to support
// this length specifier for OBJ_REPR_D (64-bit NaN boxing).
// TODO Either enable this unconditionally, or provide a specific config var.
#if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64)
case 'l': {
unsigned long long int arg_value = va_arg(args, unsigned long long int);
++fmt;
assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
break;
}
#endif
default:
// if it's not %% then it's an unsupported format character
Expand Down
23 changes: 19 additions & 4 deletions tests/ports/unix/extra_coverage.py.exp
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,34 @@
-123 +123 123
-0123
123
123
1ABCDEF
123f
123F
7fffffffffffffff
7FFFFFFFFFFFFFFF
18446744073709551615
789f
789F
ab abc ' abc' ' True' 'Tru'

false true
(null)
-2147483648
2147483648
80000000
80000000
8000000f
8000000F
abc
%
.a .
<%>
<aaaa>
<true>
<43690>
<43690>
<43690>
<test>
<1000.000000>
<True>
<9223372036854775807>
# GC
0
0
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy