Andrew Nguyen : kernel32: Handle some escape sequences with FORMAT_MESSAGE_IGNORE_INSERTS in FormatMessageA /W.

Alexandre Julliard julliard at winehq.org
Wed Apr 28 16:35:47 CDT 2010


Module: wine
Branch: master
Commit: 5505ae978b08ed5facd6bf953c646ab51de6d356
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5505ae978b08ed5facd6bf953c646ab51de6d356

Author: Andrew Nguyen <anguyen at codeweavers.com>
Date:   Wed Apr 28 04:20:35 2010 -0500

kernel32: Handle some escape sequences with FORMAT_MESSAGE_IGNORE_INSERTS in FormatMessageA/W.

---

 dlls/kernel32/format_msg.c       |   37 +++++++++++-
 dlls/kernel32/tests/format_msg.c |  124 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c
index 185c459..a66cb9b 100644
--- a/dlls/kernel32/format_msg.c
+++ b/dlls/kernel32/format_msg.c
@@ -286,8 +286,41 @@ static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr
 
     f = fmtstr;
     if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
-        while (*f && !eos)
-            ADD_TO_T(*f++);
+        while (*f && !eos) {
+            if (*f=='%') {
+                f++;
+                switch (*f)
+                {
+                case '0':
+                    eos = TRUE;
+                    f++;
+                    break;
+                case 'n':
+                    ADD_TO_T('\r');
+                    ADD_TO_T('\n');
+                    f++;
+                    break;
+                case 'r':
+                    ADD_TO_T('\r');
+                    f++;
+                    break;
+                case 't':
+                    ADD_TO_T('\t');
+                    f++;
+                    break;
+                case '\0':
+                    SetLastError(ERROR_INVALID_PARAMETER);
+                    HeapFree(GetProcessHeap(), 0, target);
+                    return NULL;
+                default:
+                    ADD_TO_T('%');
+                    ADD_TO_T(*f++);
+                    break;
+                }
+            }
+            else
+                ADD_TO_T(*f++);
+        }
     }
     else {
         while (*f && !eos) {
diff --git a/dlls/kernel32/tests/format_msg.c b/dlls/kernel32/tests/format_msg.c
index 9021c09..1bf1188 100644
--- a/dlls/kernel32/tests/format_msg.c
+++ b/dlls/kernel32/tests/format_msg.c
@@ -730,6 +730,128 @@ static void test_message_from_string(void)
     ok(r==2,"failed: r=%d\n",r);
 }
 
+static void test_message_ignore_inserts(void)
+{
+    static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'};
+
+    DWORD ret;
+    CHAR out[256];
+
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret);
+    ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out);
+
+    /* The %0 escape sequence is handled. */
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%0", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret);
+    ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out);
+
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%0test", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret);
+    ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out);
+
+    /* While FormatMessageA returns 0 in this case, no last error code is set. */
+    SetLastError(0xdeadbeef);
+    memcpy(out, init_buf, sizeof(init_buf));
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%0test", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 0, "Expected FormatMessageA to return 0, got %d\n", ret);
+    ok(!memcmp(out, init_buf, sizeof(init_buf)) ||
+       broken(!strcmp("", out)), /* Win9x */
+       "Expected the output buffer to be untouched\n");
+    ok(GetLastError() == 0xdeadbeef, "Expected GetLastError() to return 0xdeadbeef, got %u\n", GetLastError());
+
+    /* Insert sequences are ignored. */
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%1%2!*.*s!%99", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 17, "Expected FormatMessageA to return 17, got %d\n", ret);
+    ok(!strcmp("test%1%2!*.*s!%99", out), "Expected output string \"test%%1%%2!*.*s!%%99\", got %s\n", out);
+
+    /* Only the "%n", "%r", and "%t" escape sequences are processed. */
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%%% %.%!", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 8 ||
+       broken(ret == 7) /* Win9x */,
+       "Expected FormatMessageA to return 8, got %d\n", ret);
+    ok(!strcmp("%%% %.%!", out) ||
+       broken(!strcmp("%%% %.!", out)) /* Win9x */,
+       "Expected output string \"%%%%%% %%.%%!\", got %s\n", out);
+
+    ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%n%r%t", 0, 0, out,
+                         sizeof(out)/sizeof(CHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret);
+    ok(!strcmp("\r\n\r\t", out), "Expected output string \"\\r\\n\\r\\t\", got %s\n", out);
+}
+
+static void test_message_ignore_inserts_wide(void)
+{
+    static const WCHAR test[] = {'t','e','s','t',0};
+    static const WCHAR empty[] = {0};
+    static const WCHAR fmt_t0[] = {'t','e','s','t','%','0',0};
+    static const WCHAR fmt_t0t[] = {'t','e','s','t','%','0','t','e','s','t',0};
+    static const WCHAR fmt_0t[] = {'%','0','t','e','s','t',0};
+    static const WCHAR fmt_t12oos99[] = {'t','e','s','t','%','1','%','2','!','*','.','*','s','!','%','9','9',0};
+    static const WCHAR fmt_pctspacedot[] = {'%','%','%',' ','%','.','%','!',0};
+    static const WCHAR fmt_nrt[] = {'%','n','%','r','%','t',0};
+
+    static const WCHAR s_nrt[] = {'\r','\n','\r','\t',0};
+
+    DWORD ret;
+    WCHAR out[256];
+
+    SetLastError(0xdeadbeef);
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, NULL, 0, NULL);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("FormatMessageW is not implemented\n");
+        return;
+    }
+
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, test, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret);
+    ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out));
+
+    /* The %0 escape sequence is handled. */
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t0, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret);
+    ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out));
+
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t0t, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret);
+    ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out));
+
+    /* While FormatMessageA returns 0 in this case, no last error code is set. */
+    SetLastError(0xdeadbeef);
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_0t, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 0, "Expected FormatMessageW to return 0, got %d\n", ret);
+    ok(!lstrcmpW(empty, out), "Expected the output buffer to be the empty string, got %s\n", wine_dbgstr_w(out));
+    ok(GetLastError() == 0xdeadbeef, "Expected GetLastError() to return 0xdeadbeef, got %u\n", GetLastError());
+
+    /* Insert sequences are ignored. */
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t12oos99, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret);
+    ok(!lstrcmpW(fmt_t12oos99, out), "Expected output string \"test%%1%%2!*.*s!%%99\", got %s\n", wine_dbgstr_w(out));
+
+    /* Only the "%n", "%r", and "%t" escape sequences are processed. */
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_pctspacedot, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 8, "Expected FormatMessageW to return 8, got %d\n", ret);
+    ok(!lstrcmpW(fmt_pctspacedot, out), "Expected output string \"%%%%%% %%.%%!\", got %s\n", wine_dbgstr_w(out));
+
+    ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_nrt, 0, 0, out,
+                         sizeof(out)/sizeof(WCHAR), NULL);
+    ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret);
+    ok(!lstrcmpW(s_nrt, out), "Expected output string \"\\r\\n\\r\\t\", got %s\n", wine_dbgstr_w(out));
+}
+
 static void test_message_insufficient_buffer(void)
 {
     static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'};
@@ -1362,6 +1484,8 @@ START_TEST(format_msg)
 {
     test_message_from_string();
     test_message_from_string_wide();
+    test_message_ignore_inserts();
+    test_message_ignore_inserts_wide();
     test_message_insufficient_buffer();
     test_message_insufficient_buffer_wide();
     test_message_null_buffer();




More information about the wine-cvs mailing list