From b3534015135a3b3622c5f3c7d4aefefb04e8d36d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 29 Oct 2009 19:11:28 +0100 Subject: [PATCH] kernel32: Fix handling of width and precision arguments and remove assumptions about va_list implementation in FormatMessage. --- dlls/kernel32/format_msg.c | 75 ++++++++++++++++++++++++++++++---------- dlls/kernel32/tests/format_msg.c | 13 +++++-- 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c index 46f65a1378a..ce4e52fc1f8 100644 --- a/dlls/kernel32/format_msg.c +++ b/dlls/kernel32/format_msg.c @@ -39,6 +39,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(resource); +struct format_args +{ + ULONG_PTR *args; + __ms_va_list *list; + int last; +}; /* Messages used by FormatMessage * @@ -138,17 +144,25 @@ static LPSTR load_messageA( HMODULE module, UINT id, WORD lang ) /********************************************************************** * get_arg (internal) */ -static ULONG_PTR get_arg( int nr, DWORD flags, __ms_va_list *args ) +static ULONG_PTR get_arg( int nr, DWORD flags, struct format_args *args ) { - if (flags & FORMAT_MESSAGE_ARGUMENT_ARRAY) return ((ULONG_PTR *)args)[nr - 1]; - return (*(ULONG_PTR **)args)[nr - 1]; /* FIXME */ + if (nr == -1) nr = args->last + 1; + if (args->list) + { + if (!args->args) args->args = HeapAlloc( GetProcessHeap(), 0, 99 * sizeof(ULONG_PTR) ); + while (nr > args->last) + args->args[args->last++] = va_arg( *args->list, ULONG_PTR ); + } + if (nr > args->last) args->last = nr; + return args->args[nr - 1]; } /********************************************************************** * format_insertA (internal) */ -static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, __ms_va_list *args, LPSTR *result ) +static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, + struct format_args *args, LPSTR *result ) { char *astring = NULL, *p, fmt[256]; ULONG_PTR arg; @@ -176,7 +190,7 @@ static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, __ms_va_li if (*format == '*') { p += sprintf( p, "%lu", get_arg( insert, flags, args )); - insert++; + insert = -1; format++; } else *p++ = *format++; @@ -189,7 +203,7 @@ static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, __ms_va_li if (*format == '*') { p += sprintf( p, "%lu", get_arg( insert, flags, args )); - insert++; + insert = -1; format++; } else @@ -269,7 +283,8 @@ static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, __ms_va_li /********************************************************************** * format_insertW (internal) */ -static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, __ms_va_list *args, LPWSTR *result) +static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, + struct format_args *args, LPWSTR *result ) { static const WCHAR fmt_lu[] = {'%','l','u',0}; WCHAR *wstring = NULL, *p, fmt[256]; @@ -298,7 +313,7 @@ static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, __ms_va_ if (*format == '*') { p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); - insert++; + insert = -1; format++; } else *p++ = *format++; @@ -311,7 +326,7 @@ static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, __ms_va_ if (*format == '*') { p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); - insert++; + insert = -1; format++; } else @@ -399,9 +414,8 @@ DWORD WINAPI FormatMessageA( DWORD nSize, __ms_va_list* args ) { + struct format_args format_args; DWORD ret = 0; -#if defined(__i386__) || defined(__sparc__) -/* This implementation is completely dependent on the format of the va_list on x86 CPUs */ LPSTR target,t; DWORD talloced; LPSTR from; @@ -422,6 +436,19 @@ DWORD WINAPI FormatMessageA( return 0; } + if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) + { + format_args.args = (ULONG_PTR *)args; + format_args.list = NULL; + format_args.last = 0; + } + else + { + format_args.args = NULL; + format_args.list = args; + format_args.last = 0; + } + if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) FIXME("line wrapping (%u) not supported.\n", width); from = NULL; @@ -484,7 +511,7 @@ DWORD WINAPI FormatMessageA( f++; break; } - f = format_insertA( insertnr, f, dwFlags, args, &str ); + f = format_insertA( insertnr, f, dwFlags, &format_args, &str ); for (x = str; *x; x++) ADD_TO_T(*x); HeapFree( GetProcessHeap(), 0, str ); break; @@ -546,8 +573,8 @@ DWORD WINAPI FormatMessageA( } HeapFree(GetProcessHeap(),0,target); HeapFree(GetProcessHeap(),0,from); + if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); ret = (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer) : strlen(lpBuffer); -#endif /* __i386__ */ TRACE("-- returning %d\n", ret); return ret; } @@ -566,8 +593,7 @@ DWORD WINAPI FormatMessageW( DWORD nSize, __ms_va_list* args ) { -#if defined(__i386__) || defined(__sparc__) -/* This implementation is completely dependent on the format of the va_list on x86 CPUs */ + struct format_args format_args; LPWSTR target,t; DWORD talloced; LPWSTR from; @@ -588,6 +614,19 @@ DWORD WINAPI FormatMessageW( return 0; } + if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) + { + format_args.args = (ULONG_PTR *)args; + format_args.list = NULL; + format_args.last = 0; + } + else + { + format_args.args = NULL; + format_args.list = args; + format_args.last = 0; + } + if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) FIXME("line wrapping not supported.\n"); from = NULL; @@ -651,7 +690,7 @@ DWORD WINAPI FormatMessageW( f++; break; } - f = format_insertW( insertnr, f, dwFlags, args, &str ); + f = format_insertW( insertnr, f, dwFlags, &format_args, &str ); for (x = str; *x; x++) ADD_TO_T(*x); HeapFree( GetProcessHeap(), 0, str ); break; @@ -713,13 +752,11 @@ DWORD WINAPI FormatMessageW( HeapFree(GetProcessHeap(),0,target); HeapFree(GetProcessHeap(),0,from); + if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); TRACE("ret=%s\n", wine_dbgstr_w((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? *(LPWSTR*)lpBuffer : lpBuffer)); return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlenW(*(LPWSTR*)lpBuffer): strlenW(lpBuffer); -#else - return 0; -#endif /* __i386__ */ } #undef ADD_TO_T diff --git a/dlls/kernel32/tests/format_msg.c b/dlls/kernel32/tests/format_msg.c index 15064b2bf37..4b4192ef24e 100644 --- a/dlls/kernel32/tests/format_msg.c +++ b/dlls/kernel32/tests/format_msg.c @@ -120,6 +120,7 @@ static void test_message_from_string_wide(void) static const WCHAR s_sp001002[] = {' ',' ','0','0','1',',',' ','0','0','0','2',0}; static const WCHAR s_sp001sp002[] = {' ',' ','0','0','1',',',' ',' ','0','0','0','2',0}; static const WCHAR s_sp002sp001[] = {' ',' ','0','0','0','2',',',' ',' ','0','0','1',0}; + static const WCHAR s_sp002sp003[] = {' ',' ','0','0','0','2',',',' ','0','0','0','0','3',0}; WCHAR out[0x100] = {0}; DWORD r, error; @@ -332,7 +333,7 @@ static void test_message_from_string_wide(void) ok(r==5,"failed: r=%d\n",r); r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou1oou, 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 4, 2 ); - todo_wine ok(!lstrcmpW( s_sp001002, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(!lstrcmpW( s_sp001002, out),"failed out=[%s]\n", wine_dbgstr_w(out)); ok(r==11,"failed: r=%d\n",r); r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou3oou, 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 6, 4, 2 ); @@ -341,6 +342,10 @@ static void test_message_from_string_wide(void) /* args are not counted the same way with an argument array */ { ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou1oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), (va_list *)args ); + ok(!lstrcmpW(s_sp002sp003, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==13,"failed: r=%d\n",r); r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou4oou, 0, 0, out, sizeof(out)/sizeof(WCHAR), (va_list *)args ); ok(!lstrcmpW(s_sp002sp001, out),"failed out=[%s]\n", wine_dbgstr_w(out)); @@ -580,7 +585,7 @@ static void test_message_from_string(void) ok(r==5,"failed: r=%d\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), 5, 3, 1, 4, 2 ); - todo_wine ok(!strcmp( " 001, 0002", out),"failed out=[%s]\n",out); + ok(!strcmp( " 001, 0002", out),"failed out=[%s]\n",out); ok(r==11,"failed: r=%d\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%3!*.*u!", 0, 0, out, sizeof(out), 5, 3, 1, 6, 4, 2 ); @@ -590,6 +595,10 @@ static void test_message_from_string(void) { ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, + "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), (va_list *)args ); + ok(!strcmp(" 0002, 00003", out),"failed out=[%s]\n",out); + ok(r==13,"failed: r=%d\n",r); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, "%1!*.*u!,%4!*.*u!", 0, 0, out, sizeof(out), (va_list *)args ); ok(!strcmp(" 0002, 001", out),"failed out=[%s]\n",out); ok(r==12,"failed: r=%d\n",r); -- 2.11.4.GIT