From: Alex Henrie Subject: [PATCH v2] kernel32: Implement FormatMessage variable prefixes I, I32, and I64 Message-Id: <20181120074934.336-1-alexhenrie24@gmail.com> Date: Tue, 20 Nov 2018 00:49:34 -0700 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=33392 Signed-off-by: Alex Henrie --- v2: Drop I64 tests that fail on Windows --- dlls/kernel32/format_msg.c | 26 +++++++++++++++++++- dlls/kernel32/tests/format_msg.c | 42 ++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c index 5741713d81..bd4b2df110 100644 --- a/dlls/kernel32/format_msg.c +++ b/dlls/kernel32/format_msg.c @@ -249,7 +249,31 @@ static LPCWSTR format_insert( BOOL unicode_caller, int insert, LPCWSTR format, { *p++ = 'c'; } - /* FIXME: handle I64 etc. */ + /* check for 32-bit integer format */ + else if (format[0] == 'I' && format[1] == '3' && format[2] == '2' && + (format[3] == 'd' || format[3] == 'i' || format[3] == 'u' || + format[3] == 'o' || format[3] == 'x' || format[3] == 'X')) + { + *p++ = format[3]; + } + /* check for 64-bit integer format */ + else if (format[0] == 'I' && format[1] == '6' && format[2] == '4' && + (format[3] == 'd' || format[3] == 'i' || format[3] == 'u' || + format[3] == 'o' || format[3] == 'x' || format[3] == 'X')) + { + *p++ = 'l'; + *p++ = format[3]; + } + /* check for pointer-size integer format */ + else if (format[0] == 'I' && + (format[1] == 'd' || format[1] == 'i' || format[1] == 'u' || + format[1] == 'o' || format[1] == 'x' || format[1] == 'x')) + { +#ifdef _WIN64 + *p++ = 'l'; +#endif + *p++ = format[1]; + } else while (*format && *format != '!') *p++ = *format++; *p = 0; diff --git a/dlls/kernel32/tests/format_msg.c b/dlls/kernel32/tests/format_msg.c index 57ee78af9e..58d51104f7 100644 --- a/dlls/kernel32/tests/format_msg.c +++ b/dlls/kernel32/tests/format_msg.c @@ -26,6 +26,8 @@ #define ULL(a,b) (((ULONG64)(a) << 32) | (b)) +static const BOOL is_32bit = (sizeof(void *) == sizeof(int)); + static DWORD WINAPIV doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, LPSTR out, DWORD outsize, ... ) { @@ -98,6 +100,8 @@ static void test_message_from_string_wide(void) static const WCHAR fmt_1oou1oou[] = {'%','1','!','*','.','*','u','!',',','%','1','!','*','.','*','u','!',0}; static const WCHAR fmt_1oou3oou[] = {'%','1','!','*','.','*','u','!',',','%','3','!','*','.','*','u','!',0}; static const WCHAR fmt_1oou4oou[] = {'%','1','!','*','.','*','u','!',',','%','4','!','*','.','*','u','!',0}; + static const WCHAR fmt_1I32d[] = {'%','1','!','I','3','2','d','!',0}; + static const WCHAR fmt_1Id[] = {'%','1','!','I','d','!',0}; static const WCHAR s_123d[] = {'1','2','3',0}; static const WCHAR s_14d[] = {' ',' ',' ','1',0}; @@ -390,6 +394,16 @@ static void test_message_from_string_wide(void) ok(r==12,"failed: r=%d\n",r); } + /* prefixes not shared with standard printf */ + + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1I32d, 0, 0, out, ARRAY_SIZE(out), 123); + ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%d\n", r); + + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1Id, 0, 0, out, ARRAY_SIZE(out), 123); + ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%d\n", r); + /* change of pace... test the low byte of dwflags */ /* line feed */ @@ -688,6 +702,16 @@ static void test_message_from_string(void) } } + /* prefixes not shared with standard printf */ + + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I32d!", 0, 0, out, ARRAY_SIZE(out), 123); + ok(!strcmp("123", out),"failed out=[%s]\n",out); + ok(r==3,"failed: r=%d\n",r); + + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!Id!", 0, 0, out, ARRAY_SIZE(out), 123); + ok(!strcmp("123", out),"failed out=[%s]\n",out); + ok(r==3,"failed: r=%d\n",r); + /* change of pace... test the low byte of dwflags */ /* line feed */ @@ -1718,26 +1742,28 @@ static void test_message_from_64bit_number(void) UINT64 number; const char expected[32]; int len; + BOOL todo32; } unsigned_tests[] = { { 0, "0", 1 }, { 1234567890, "1234567890", 10}, - { ULL(0xFFFFFFFF,0xFFFFFFFF), "18446744073709551615", 20 }, - { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 }, + { ULL(0xFFFFFFFF,0xFFFFFFFF), "18446744073709551615", 20, TRUE }, + { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19, TRUE }, }; static const struct { INT64 number; const char expected[32]; int len; + BOOL todo32; } signed_tests[] = { { 0, "0" , 1}, { 1234567890, "1234567890", 10 }, { -1, "-1", 2}, { ULL(0xFFFFFFFF,0xFFFFFFFF), "-1", 2}, - { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 }, - { -ULL(0x7FFFFFFF,0xFFFFFFFF), "-9223372036854775807", 20}, + { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19, TRUE }, + { -ULL(0x7FFFFFFF,0xFFFFFFFF), "-9223372036854775807", 20, TRUE }, }; int i; @@ -1746,14 +1772,12 @@ static void test_message_from_64bit_number(void) r = doitW(FORMAT_MESSAGE_FROM_STRING, I64u, 0, 0, outW, ARRAY_SIZE(outW), unsigned_tests[i].number); MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); -todo_wine { +todo_wine_if(is_32bit && unsigned_tests[i].todo32) { ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i, unsigned_tests[i].expected, wine_dbgstr_w(outW)); ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); -} r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!", 0, 0, outA, sizeof(outA), unsigned_tests[i].number); -todo_wine { ok(!strcmp(outA, unsigned_tests[i].expected),"[%d] failed, expected %s, got %s\n", i, unsigned_tests[i].expected, outA); ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); @@ -1765,14 +1789,12 @@ todo_wine { r = doitW(FORMAT_MESSAGE_FROM_STRING, I64d, 0, 0, outW, ARRAY_SIZE(outW), signed_tests[i].number); MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); -todo_wine { +todo_wine_if(is_32bit && signed_tests[i].todo32) { ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i, signed_tests[i].expected, wine_dbgstr_w(outW)); ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); -} r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!", 0, 0, outA, sizeof(outA), signed_tests[i].number); -todo_wine { ok(!strcmp(outA, signed_tests[i].expected),"[%d] failed, expected %s, got %s\n", i, signed_tests[i].expected, outA); ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); -- 2.19.1