From: Andrew Eikum aeikum@codeweavers.com
This is a replacement for "msvcrt: The '*' character should be interpreted as the beginning of the width specification"[1], which matches the behaviour I see on my machine better.
If a printf format string contains both a '*' (to specify that the field width should be read from a variable), followed by another explicit field width, only the latter field width should be used.
For further details, see [2] and [3].
[1]: https://source.winehq.org/patches/data/218904 [2]: https://www.winehq.org/pipermail/wine-devel/2021-November/200039.html [3]: https://github.com/ValveSoftware/Proton/issues/5258#issuecomment-962423092
Signed-off-by: Andrew Eikum aeikum@codeweavers.com Co-Developed-by: David Gow david@davidgow.net Signed-off-by: David Gow david@davidgow.net ---
Note also that this moves the new tests after the setlocale(LC_ALL, "C"), as I don't think they need to run in a Japanese locale.
--- dlls/msvcrt/printf.h | 8 +++++++- dlls/msvcrt/tests/printf.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h index aeb1290f48f..6d2f02ee85b 100644 --- a/dlls/msvcrt/printf.h +++ b/dlls/msvcrt/printf.h @@ -1050,7 +1050,13 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API flags.LeftAlign = TRUE; flags.FieldLength = -flags.FieldLength; } - } else while (*p >= '0' && *p <= '9') { + + /* Ignore this length if there's another specifier. */ + if (*p >= '0' && *p <= '9') + flags.FieldLength = 0; + } + + while (*p >= '0' && *p <= '9') { flags.FieldLength *= 10; flags.FieldLength += *p++ - '0'; } diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c index 06acf4c8450..cc824f571a6 100644 --- a/dlls/msvcrt/tests/printf.c +++ b/dlls/msvcrt/tests/printf.c @@ -396,6 +396,26 @@ static void test_sprintf( void ) ok(!strcmp(buffer, "string to copy"), "failed: "%s"\n", buffer);
setlocale(LC_ALL, "C"); + + r = p_sprintf(buffer, "%0*02d", 1, 0); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buffer, "00"), "failed: "%s"\n", buffer); + + r = p_sprintf(buffer, "%0*02d", 30, 17); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buffer, "17"), "failed: "%s"\n", buffer); + + r = p_sprintf(buffer, "%*1d", 1, 3); + ok(r==1, "r = %d\n", r); + ok(!strcmp(buffer, "3"), "failed: "%s"\n", buffer); + + r = p_sprintf(buffer, "%0*0d", 1, 2); + ok(r==1, "r = %d\n", r); + ok(!strcmp(buffer, "2"), "failed: "%s"\n", buffer); + + r = p_sprintf(buffer, "% *2d", 0, 7); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buffer, " 7"), "failed: "%s"\n", buffer); }
static void test_swprintf( void )