kernel32: Add line wrapping support to FormatMessage().
This commit is contained in:
parent
8700bb86a2
commit
49cf27ab2a
|
@ -266,14 +266,59 @@ struct _format_message_data
|
|||
LPWSTR formatted;
|
||||
DWORD size;
|
||||
LPWSTR t;
|
||||
LPWSTR space;
|
||||
BOOL inspace;
|
||||
DWORD width, w;
|
||||
};
|
||||
|
||||
static void format_add_char(struct _format_message_data *fmd, WCHAR c)
|
||||
{
|
||||
*fmd->t++ = c;
|
||||
if (fmd->width && fmd->width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
|
||||
{
|
||||
switch (c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
fmd->space = NULL;
|
||||
fmd->inspace = FALSE;
|
||||
fmd->w = 0;
|
||||
break;
|
||||
case ' ':
|
||||
if (!fmd->inspace)
|
||||
fmd->space = fmd->t - 1;
|
||||
fmd->inspace = TRUE;
|
||||
fmd->w++;
|
||||
break;
|
||||
default:
|
||||
fmd->inspace = FALSE;
|
||||
fmd->w++;
|
||||
}
|
||||
if (fmd->w == fmd->width) {
|
||||
LPWSTR notspace;
|
||||
if (fmd->space) {
|
||||
notspace = fmd->space;
|
||||
while (*notspace == ' ' && notspace != fmd->t)
|
||||
notspace++;
|
||||
} else
|
||||
notspace = fmd->space = fmd->t;
|
||||
fmd->w = fmd->t - notspace;
|
||||
memmove(fmd->space+2, notspace, fmd->w * sizeof(*fmd->t));
|
||||
*fmd->space++ = '\r';
|
||||
*fmd->space++ = '\n';
|
||||
fmd->t = fmd->space + fmd->w;
|
||||
fmd->space = NULL;
|
||||
fmd->inspace = FALSE;
|
||||
}
|
||||
}
|
||||
if ((DWORD)(fmd->t - fmd->formatted) == fmd->size) {
|
||||
fmd->formatted = HeapReAlloc(GetProcessHeap(), 0, fmd->formatted, (fmd->size * 2) * sizeof(WCHAR));
|
||||
DWORD_PTR ispace = fmd->space - fmd->formatted;
|
||||
/* Allocate two extra characters so we can insert a '\r\n' in
|
||||
* the middle of a word.
|
||||
*/
|
||||
fmd->formatted = HeapReAlloc(GetProcessHeap(), 0, fmd->formatted, (fmd->size * 2 + 2) * sizeof(WCHAR));
|
||||
fmd->t = fmd->formatted + fmd->size;
|
||||
if (fmd->space)
|
||||
fmd->space = fmd->formatted + ispace;
|
||||
fmd->size *= 2;
|
||||
}
|
||||
}
|
||||
|
@ -286,12 +331,15 @@ static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr
|
|||
{
|
||||
struct _format_message_data fmd;
|
||||
LPCWSTR f;
|
||||
DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
BOOL eos = FALSE;
|
||||
|
||||
fmd.size = 100;
|
||||
fmd.formatted = fmd.t = HeapAlloc( GetProcessHeap(), 0, fmd.size * sizeof(WCHAR) );
|
||||
fmd.formatted = fmd.t = HeapAlloc( GetProcessHeap(), 0, (fmd.size + 2) * sizeof(WCHAR) );
|
||||
|
||||
fmd.width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
fmd.w = 0;
|
||||
fmd.inspace = FALSE;
|
||||
fmd.space = NULL;
|
||||
f = fmtstr;
|
||||
while (*f && !eos) {
|
||||
if (*f=='%') {
|
||||
|
@ -362,7 +410,7 @@ static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr
|
|||
if (ch == '\r') {
|
||||
if (*f == '\n')
|
||||
f++;
|
||||
if(width)
|
||||
if(fmd.width)
|
||||
format_add_char(&fmd, ' ');
|
||||
else
|
||||
{
|
||||
|
@ -372,7 +420,7 @@ static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr
|
|||
} else {
|
||||
if (ch == '\n')
|
||||
{
|
||||
if(width)
|
||||
if(fmd.width)
|
||||
format_add_char(&fmd, ' ');
|
||||
else
|
||||
{
|
||||
|
@ -392,7 +440,6 @@ static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr
|
|||
|
||||
/***********************************************************************
|
||||
* FormatMessageA (KERNEL32.@)
|
||||
* FIXME: missing wrap,
|
||||
*/
|
||||
DWORD WINAPI FormatMessageA(
|
||||
DWORD dwFlags,
|
||||
|
@ -408,7 +455,6 @@ DWORD WINAPI FormatMessageA(
|
|||
LPWSTR target;
|
||||
DWORD destlength;
|
||||
LPWSTR from;
|
||||
DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
|
||||
dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
|
||||
|
@ -437,8 +483,6 @@ DWORD WINAPI FormatMessageA(
|
|||
format_args.last = 0;
|
||||
}
|
||||
|
||||
if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
|
||||
FIXME("line wrapping (%u) not supported.\n", width);
|
||||
from = NULL;
|
||||
if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
|
||||
{
|
||||
|
@ -514,7 +558,6 @@ DWORD WINAPI FormatMessageW(
|
|||
LPWSTR target;
|
||||
DWORD talloced;
|
||||
LPWSTR from;
|
||||
DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
|
||||
dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
|
||||
|
@ -541,8 +584,6 @@ DWORD WINAPI FormatMessageW(
|
|||
format_args.last = 0;
|
||||
}
|
||||
|
||||
if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
|
||||
FIXME("line wrapping not supported.\n");
|
||||
from = NULL;
|
||||
if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
|
||||
from = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpSource) + 1) *
|
||||
|
|
|
@ -1012,42 +1012,42 @@ static void test_message_wrap(void)
|
|||
/* Wrap the last word */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Wrap the very last word */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 20,
|
||||
"short long long line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 21, "Expected FormatMessageW to return 21, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long long\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 21, "Expected FormatMessageW to return 21, got %d\n", ret);
|
||||
ok(!strcmp("short long long\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Strictly less than 10 characters per line! */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10,
|
||||
"short long line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong line", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Handling of duplicate spaces */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 16,
|
||||
"short long line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 16,
|
||||
"short long wordlongerthanaline", 0, 0, out, sizeof(out), NULL);
|
||||
ok(ret == 33, "Expected FormatMessageW to return 33, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\nwordlongerthanal\r\nine", out),"failed out=[%s]\n",out);
|
||||
ok(!strcmp("short long\r\nwordlongerthanal\r\nine", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Breaking in the middle of spaces */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 12,
|
||||
"short long line", 0, 0, out, sizeof(out), NULL);
|
||||
ok(ret == 18, "Expected FormatMessageW to return 18, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\n line", out),"failed out=[%s]\n",out);
|
||||
ok(!strcmp("short long\r\n line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 12,
|
||||
"short long wordlongerthanaline", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 35, "Expected FormatMessageW to return 35, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\n\r\nwordlongerth\r\nanaline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 35, "Expected FormatMessageW to return 35, got %d\n", ret);
|
||||
ok(!strcmp("short long\r\n\r\nwordlongerth\r\nanaline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Handling of start-of-string spaces */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 15,
|
||||
|
@ -1058,55 +1058,55 @@ static void test_message_wrap(void)
|
|||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
" shortlong line", 0, 0, out, sizeof(out), NULL);
|
||||
ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("\r\nshortlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(!strcmp("\r\nshortlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Handling of start-of-line spaces */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"l1%n shortlong line", 0, 0, out, sizeof(out), NULL);
|
||||
ok(ret == 21, "Expected FormatMessageW to return 21, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("l1\r\n\r\nshortlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(!strcmp("l1\r\n\r\nshortlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Pure space wrapping */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 5,
|
||||
" ", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 7, "Expected FormatMessageW to return 7, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("\r\n\r\n\r\n ", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 7, "Expected FormatMessageW to return 7, got %d\n", ret);
|
||||
ok(!strcmp("\r\n\r\n\r\n ", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Handling of trailing spaces */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 5,
|
||||
"l1 ", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("l1\r\n\r\n\r\n ", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret);
|
||||
ok(!strcmp("l1\r\n\r\n\r\n ", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Word that just fills the line */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8,
|
||||
"shortlon", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("shortlon\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret);
|
||||
ok(!strcmp("shortlon\r\n", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Word longer than the line */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8,
|
||||
"shortlongline", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 15, "Expected FormatMessageW to return 15, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("shortlon\r\ngline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 15, "Expected FormatMessageW to return 15, got %d\n", ret);
|
||||
ok(!strcmp("shortlon\r\ngline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Wrap the line multiple times */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 7,
|
||||
"short long line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* '\n's in the source are ignored */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short\nlong line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* Wrap even before a '%n' */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8,
|
||||
"shortlon%n", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 12, "Expected FormatMessageW to return 12, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("shortlon\r\n\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 12, "Expected FormatMessageW to return 12, got %d\n", ret);
|
||||
ok(!strcmp("shortlon\r\n\r\n", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* '%n's count as starting a new line and combine with line wrapping */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10,
|
||||
|
@ -1116,8 +1116,8 @@ static void test_message_wrap(void)
|
|||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8,
|
||||
"short%nlong line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* '%r's also count as starting a new line and all */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10,
|
||||
|
@ -1127,14 +1127,14 @@ static void test_message_wrap(void)
|
|||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8,
|
||||
"short%rlong line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\rlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\rlong\r\nline", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* IGNORE_INSERTS does not prevent line wrapping or disable '%n' */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | 8,
|
||||
"short%nlong line%1", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 19, "Expected FormatMessageW to return 19, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong\r\nline%1", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 19, "Expected FormatMessageW to return 19, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong\r\nline%1", out),"failed out=[%s]\n",out);
|
||||
|
||||
/* MAX_WIDTH_MASK is the same as specifying an infinite line width */
|
||||
strcpy(in, "first line%n");
|
||||
|
@ -1152,38 +1152,38 @@ static void test_message_wrap(void)
|
|||
/* Wrapping and non-space characters */
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long\tline", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong\tline", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong\tline", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long-line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong-line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong-line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long_line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong_line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong_line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long.line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong.line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong.line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long,line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong,line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong,line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long!line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong!line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong!line", out),"failed out=[%s]\n",out);
|
||||
|
||||
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11,
|
||||
"short long?line", 0, 0, out, sizeof(out), NULL);
|
||||
todo_wine ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
todo_wine ok(!strcmp("short\r\nlong?line", out),"failed out=[%s]\n",out);
|
||||
ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret);
|
||||
ok(!strcmp("short\r\nlong?line", out),"failed out=[%s]\n",out);
|
||||
}
|
||||
|
||||
static void test_message_insufficient_buffer(void)
|
||||
|
|
Loading…
Reference in New Issue