From 49cf27ab2aa73b1247efb59b325255f4d038e248 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Mon, 24 Sep 2012 08:38:13 +0200 Subject: [PATCH] kernel32: Add line wrapping support to FormatMessage(). --- dlls/kernel32/format_msg.c | 65 +++++++++++++++++---- dlls/kernel32/tests/format_msg.c | 96 ++++++++++++++++---------------- 2 files changed, 101 insertions(+), 60 deletions(-) diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c index 101c2fa92b1..7ce4f0aa365 100644 --- a/dlls/kernel32/format_msg.c +++ b/dlls/kernel32/format_msg.c @@ -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) * diff --git a/dlls/kernel32/tests/format_msg.c b/dlls/kernel32/tests/format_msg.c index cf711f6328e..005e6c4a66c 100644 --- a/dlls/kernel32/tests/format_msg.c +++ b/dlls/kernel32/tests/format_msg.c @@ -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)