kernel32: Fix handling of width and precision arguments and remove assumptions about va_list implementation in FormatMessage.

This commit is contained in:
Alexandre Julliard 2009-10-29 19:11:28 +01:00
parent 100131d4ca
commit b353401513
2 changed files with 67 additions and 21 deletions

View File

@ -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

View File

@ -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 );
@ -589,6 +594,10 @@ static void test_message_from_string(void)
/* args are not counted the same way with an argument array */
{
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);