riched20: EM_GETLINE implementation and test, take 3

tkho at ucla.edu tkho at ucla.edu
Wed Apr 26 18:50:18 CDT 2006


Hello,

The following patch implements EM_GETLINE and its conformance test in rich
edit. The test verifies ascii and unicode behavior, but I'm unfamiliar with mbcs
strings and don't address or verify that they work properly.

Regards,

Thomas Kho

2006-04-26 Thomas Kho <tkho at ucla.edu>

	* dlls/riched20/editor.c, dlls/riched20/tests/editor.c:
	riched20: Added EM_GETLINE implementation and test

 editor.c       |   63 ++++++++++++++++++++++++-
 tests/editor.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 204 insertions(+), 2 deletions(-)

Signed-off-by: Thomas Kho <tkho at ucla.edu>
Index: dlls/riched20/editor.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.c,v
retrieving revision 1.105
diff -u -r1.105 editor.c
--- dlls/riched20/editor.c	12 Apr 2006 09:53:22 -0000	1.105
+++ dlls/riched20/editor.c	26 Apr 2006 23:44:38 -0000
@@ -52,7 +52,7 @@
   - EM_GETIMESTATUS
   - EM_GETLANGOPTIONS 2.0
   - EM_GETLIMITTEXT
-  - EM_GETLINE        
+  + EM_GETLINE
   + EM_GETLINECOUNT   returns number of rows, not of paragraphs
   + EM_GETMODIFY
   - EM_GETOLEINTERFACE
@@ -1405,7 +1405,6 @@
   /* UNSUPPORTED_MSG(EM_GETIMESTATUS) missing in Wine headers */
   UNSUPPORTED_MSG(EM_GETLANGOPTIONS)
   UNSUPPORTED_MSG(EM_GETLIMITTEXT)
-  UNSUPPORTED_MSG(EM_GETLINE)
   /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */
   UNSUPPORTED_MSG(EM_GETPASSWORDCHAR)
   UNSUPPORTED_MSG(EM_GETREDONAME)
@@ -2000,6 +1999,66 @@
       return nChars;
     }
   }
+  case EM_GETLINE:
+  {
+    ME_DisplayItem *run;
+    int nBPC = IsWindowUnicode(hWnd) ? sizeof(WCHAR) : 1; /* bytes per char */
+    int nEndChars;
+    int nMaxChars = (int) *(WORD *) lParam;
+    char *dest = (char *) lParam;
+    static const WCHAR szsr[] = { '\r', 0 };
+
+    TRACE("EM_GETLINE: row=%d, nMaxChars=%d (%s)\n", (int) wParam, nMaxChars,
+          IsWindowUnicode(hWnd) ? "Unicode" : "Ansi");
+
+    run = ME_FindRowWithNumber(editor, (int) wParam);
+    if (run == NULL)
+      return 0;
+
+    while ((run = ME_FindItemFwd(run, diRunOrStartRow))
+           && !(run->member.run.nFlags & MERF_ENDPARA)
+           && ((int) dest - (int) lParam) < nMaxChars * nBPC)
+    {
+      int nCopy;
+      ME_String *strText;
+
+      if (run->type != diRun)
+        break;
+
+      strText = run->member.run.strText;
+      nCopy = min(nMaxChars - ((int) dest - (int) lParam)/nBPC, strText->nLen);
+
+      if (IsWindowUnicode(hWnd))
+      {
+        memcpy(dest, strText->szData, nCopy * nBPC);
+        dest += nCopy * nBPC;
+      }
+      else
+      {
+        int nCopied;
+        nCopied = WideCharToMultiByte(CP_ACP, 0, strText->szData,
+                                      nCopy, dest, nCopy, NULL, NULL);
+        if (!nCopied && nCopy) /* can't copy anymore */
+          break; /* FIXME: What's the behavior for real MBCS? */
+        dest += nCopied;
+      }
+    }
+
+    /* append "\r\0", space allowing */
+    nEndChars =  min(nMaxChars - ((int) dest - (int) lParam)/nBPC, 2);
+    if (IsWindowUnicode(hWnd))
+      memcpy(dest, szsr, nEndChars * nBPC);
+    else
+      memcpy(dest, "\r", nEndChars);
+    dest += nEndChars * nBPC;
+
+    TRACE("EM_GETLINE: wrote %d bytes\n", (int) dest - (int) lParam);
+
+    if (nEndChars > 1) /* don't count '\0' */
+      return ((int) dest - (int) lParam - nBPC) / nBPC;
+    else
+      return ((int) dest - (int) lParam) / nBPC;
+  }
   case EM_GETLINECOUNT:
   {
     ME_DisplayItem *item = editor->pBuffer->pFirst->next;
Index: dlls/riched20/tests/editor.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/tests/editor.c,v
retrieving revision 1.12
diff -u -r1.12 editor.c
--- dlls/riched20/tests/editor.c	21 Mar 2006 19:23:02 -0000	1.12
+++ dlls/riched20/tests/editor.c	26 Apr 2006 23:44:38 -0000
@@ -22,9 +22,25 @@
 #include <windows.h>
 #include <richedit.h>
 #include <time.h>
+#include <wchar.h>
 
 static HMODULE hmoduleRichEdit;
 
+static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent) {
+  HWND hwnd;
+  hwnd = CreateWindowW(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
+                      |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
+                      hmoduleRichEdit, NULL);
+  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
+  return hwnd;
+}
+
+static HWND new_richeditW(HWND parent) {
+  static const WCHAR szRichEdit20W[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't',
+    '2', '0', 'W', 0};
+  return new_windowW(szRichEdit20W, ES_MULTILINE, parent);
+}
+
 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
   HWND hwnd;
   hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
@@ -189,6 +205,131 @@
   DestroyWindow(hwndRichEdit);
 }
 
+struct getline_s {
+  int line;
+  size_t buffer_len;
+  char *text;
+} gl[] = {
+  {0, 10, "foo bar\r"},
+  {1, 10, "\r"},
+  {2, 10, "bar\r"},
+  {3, 10, "\r"},
+
+  /* Buffer smaller than line length */
+  {0, 2, "foo bar\r"},
+  {0, 1, "foo bar\r"},
+  {0, 0, "foo bar\r"}
+};
+
+struct getlineW_s {
+  int line;
+  size_t buffer_len;
+  WCHAR text[100];
+} glW[] = {
+  {0, 10, {'f', 'o', 'o', ' ', 'b', 'a', 'r', '\r', 0}},
+  {1, 10, {'\r', 0}},
+  {2, 10, {'b', 'a', 'r', '\r', 0}},
+  {3, 10, {'\r', 0}},
+
+  /* Buffer smaller than line length */
+  {0, 2, {'f', 'o', 'o', ' ', 'b', 'a', 'r', '\r', 0}},
+  {0, 1, {'f', 'o', 'o', ' ', 'b', 'a', 'r', '\r', 0}},
+  {0, 0, {'f', 'o', 'o', ' ', 'b', 'a', 'r', '\r', 0}}
+};
+
+static void test_EM_GETLINE(void)
+{
+  int i;
+  HWND hwndRichEdit = new_richedit(NULL);
+  static const int nBuf = 1024;
+  char dest[1024], origdest[1024];
+  const char text[] = "foo bar\n"
+      "\n"
+      "bar\n";
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
+
+  memset(origdest, 0xBB, nBuf);
+  for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
+  {
+    int nCopied;
+    int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
+    int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
+    memset(dest, 0xBB, nBuf);
+    *(WORD *) dest = gl[i].buffer_len;
+
+    /* EM_GETLINE appends a "\r\0" to the end of the line
+     * nCopied counts up to and including the '\r' */
+    nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
+    ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
+       expected_nCopied);
+    /* two special cases since a parameter is passed via dest */
+    if (gl[i].buffer_len == 0)
+      ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
+         "buffer_len=0\n");
+    else if (gl[i].buffer_len == 1)
+      ok(dest[0] == gl[i].text[0] && !dest[1] &&
+         !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
+    else {
+      ok(!strncmp(dest, gl[i].text, expected_bytes_written),
+         "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
+      ok(!strncmp(dest + expected_bytes_written, origdest
+                  + expected_bytes_written, nBuf - expected_bytes_written),
+         "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
+    }
+  }
+
+  DestroyWindow(hwndRichEdit);
+}
+
+static void test_EM_GETLINEW(void)
+{
+  int i;
+  HWND hwndRichEdit = new_richeditW(NULL);
+  static const int nBuf = 1024;
+  WCHAR dest[1024], origdest[1024];
+  const WCHAR textW[] = { 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\n', '\n',
+    'b', 'a', 'r', '\n', 0 };
+
+  SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) textW);
+
+  memset(origdest, 0xBB, nBuf*sizeof(WCHAR));
+  for (i = 0; i < sizeof(glW)/sizeof(struct getlineW_s); i++)
+  {
+    int nCopied;
+    int expected_nCopied = min(glW[i].buffer_len,
+                               (unsigned int) lstrlenW(glW[i].text));
+    int expected_chars_written = min(glW[i].buffer_len,
+                                     (unsigned int) lstrlenW(glW[i].text));
+    memset(dest, 0xBB, nBuf*sizeof(WCHAR));
+    *(WORD *) dest = glW[i].buffer_len;
+
+    /* EM_GETLINE appends a "\r\0" to the end of the line
+     * nCopied counts up to and including the '\r' */
+    nCopied = SendMessageW(hwndRichEdit, EM_GETLINE, glW[i].line,
+                           (LPARAM) dest);
+    ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
+       expected_nCopied);
+    /* two special cases since a parameter is passed via dest */
+    if (gl[i].buffer_len == 0)
+      ok(!dest[0] && !memcmp(dest+1, origdest+1, (nBuf-1)*sizeof(WCHAR)),
+         "buffer_len=0\n");
+    else if (glW[i].buffer_len == 1)
+      ok(dest[0] == glW[i].text[0] &&
+         !memcmp(dest+1, origdest+1, (nBuf-1)*sizeof(WCHAR)), "buffer_len=1\n");
+    else {
+      ok(!memcmp(dest, glW[i].text, expected_chars_written),
+         "%d: expected_chars_written=%d\n", i, expected_chars_written);
+      ok(!memcmp(dest + expected_chars_written*sizeof(WCHAR),
+                  origdest + expected_chars_written*sizeof(WCHAR),
+                  nBuf - expected_chars_written*sizeof(WCHAR)),
+         "%d: expected_chars_written=%d\n", i, expected_chars_written);
+    }
+  }
+
+  DestroyWindow(hwndRichEdit);
+}
+
 static int get_scroll_pos_y(HWND hwnd)
 {
   POINT p = {-1, -1};
@@ -760,6 +901,8 @@
   hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
   ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
   test_EM_FINDTEXT();
+  test_EM_GETLINE();
+  test_EM_GETLINEW();
   test_EM_SCROLLCARET();
   test_EM_SCROLL();
   test_EM_SETTEXTMODE();



More information about the wine-patches mailing list