]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1598: screenchar() and others are wrong with DBCS 'encoding' v9.0.1598
authorzeertzjq <zeertzjq@outlook.com>
Thu, 1 Jun 2023 19:26:55 +0000 (20:26 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 1 Jun 2023 19:26:55 +0000 (20:26 +0100)
Problem:    screenchar(), screenchars() and screenstring() do not work
            properly when 'encoding' is set to a double-byte encoding.
Solution:   Fix the way the bytes of the characters are obtained.
            (issue #12469)

src/evalfunc.c
src/screen.c
src/testdir/test_functions.vim
src/testdir/test_utf8.vim
src/version.c

index 8f20ebee176414b5ea12e814e7e2d25458ee7233..62e9a40624e4310f774e4c592a8b38365d1c4256 100644 (file)
@@ -8934,7 +8934,6 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
 {
     int                row;
     int                col;
-    int                off;
     int                c;
 
     if (in_vim9script()
@@ -8948,11 +8947,9 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
        c = -1;
     else
     {
-       off = LineOffset[row] + col;
-       if (enc_utf8 && ScreenLinesUC[off] != 0)
-           c = ScreenLinesUC[off];
-       else
-           c = ScreenLines[off];
+       char_u buf[MB_MAXBYTES + 1];
+       screen_getbytes(row, col, buf, NULL);
+       c = (*mb_ptr2char)(buf);
     }
     rettv->vval.v_number = c;
 }
@@ -8965,7 +8962,6 @@ f_screenchars(typval_T *argvars, typval_T *rettv)
 {
     int                row;
     int                col;
-    int                off;
     int                c;
     int                i;
 
@@ -8982,18 +8978,18 @@ f_screenchars(typval_T *argvars, typval_T *rettv)
     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
        return;
 
-    off = LineOffset[row] + col;
-    if (enc_utf8 && ScreenLinesUC[off] != 0)
-       c = ScreenLinesUC[off];
+    char_u buf[MB_MAXBYTES + 1];
+    screen_getbytes(row, col, buf, NULL);
+    int pcc[MAX_MCO];
+    if (enc_utf8)
+       c = utfc_ptr2char(buf, pcc);
     else
-       c = ScreenLines[off];
+       c = (*mb_ptr2char)(buf);
     list_append_number(rettv->vval.v_list, (varnumber_T)c);
 
     if (enc_utf8)
-
-       for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
-           list_append_number(rettv->vval.v_list,
-                                      (varnumber_T)ScreenLinesC[i][off]);
+       for (i = 0; i < Screen_mco && pcc[i] != 0; ++i)
+           list_append_number(rettv->vval.v_list, (varnumber_T)pcc[i]);
 }
 
 /*
@@ -9024,11 +9020,7 @@ f_screenstring(typval_T *argvars, typval_T *rettv)
 {
     int                row;
     int                col;
-    int                off;
-    int                c;
-    int                i;
     char_u     buf[MB_MAXBYTES + 1];
-    int                buflen = 0;
 
     rettv->vval.v_string = NULL;
     rettv->v_type = VAR_STRING;
@@ -9043,18 +9035,7 @@ f_screenstring(typval_T *argvars, typval_T *rettv)
     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
        return;
 
-    off = LineOffset[row] + col;
-    if (enc_utf8 && ScreenLinesUC[off] != 0)
-       c = ScreenLinesUC[off];
-    else
-       c = ScreenLines[off];
-    buflen += mb_char2bytes(c, buf);
-
-    if (enc_utf8 && ScreenLinesUC[off] != 0)
-       for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
-           buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
-
-    buf[buflen] = NUL;
+    screen_getbytes(row, col, buf, NULL);
     rettv->vval.v_string = vim_strsave(buf);
 }
 
@@ -9433,7 +9414,7 @@ f_searchpos(typval_T *argvars, typval_T *rettv)
 
 /*
  * Set the cursor or mark position.
- * If 'charpos' is TRUE, then use the column number as a character offset.
+ * If "charpos" is TRUE, then use the column number as a character offset.
  * Otherwise use the column number as a byte offset.
  */
     static void
index e9bc79267bdb2d156c5ab15374c4407d732a7cbf..7966f3b4d18be4dece61edba98bbf3ee3443ce00 100644 (file)
@@ -1199,8 +1199,9 @@ screen_putchar(int c, int row, int col, int attr)
 }
 
 /*
- * Get a single character directly from ScreenLines into "bytes[]".
- * Also return its attribute in *attrp;
+ * Get a single character directly from ScreenLines into "bytes", which must
+ * have a size of "MB_MAXBYTES + 1".
+ * If "attrp" is not NULL, return the character's attribute in "*attrp".
  */
     void
 screen_getbytes(int row, int col, char_u *bytes, int *attrp)
@@ -1212,7 +1213,8 @@ screen_getbytes(int row, int col, char_u *bytes, int *attrp)
        return;
 
     off = LineOffset[row] + col;
-    *attrp = ScreenAttrs[off];
+    if (attrp != NULL)
+       *attrp = ScreenAttrs[off];
     bytes[0] = ScreenLines[off];
     bytes[1] = NUL;
 
index 17a87d85e04a1761a7e0e5f8c3740446a0dffbb9..715da0b8344111bad8dfc1b948970f86e4e36624 100644 (file)
@@ -3217,6 +3217,31 @@ func Test_screen_functions()
   call assert_equal(-1, screenattr(-1, -1))
   call assert_equal(-1, screenchar(-1, -1))
   call assert_equal([], screenchars(-1, -1))
+
+  " Run this in a separate Vim instance to avoid messing up.
+  let after =<< trim [CODE]
+    scriptencoding utf-8
+    call setline(1, '口')
+    redraw
+    call assert_equal(0, screenattr(1, 1))
+    call assert_equal(char2nr('口'), screenchar(1, 1))
+    call assert_equal([char2nr('口')], screenchars(1, 1))
+    call assert_equal('口', screenstring(1, 1))
+    call writefile(v:errors, 'Xresult')
+    qall!
+  [CODE]
+
+  let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950']
+  if !has('win32')
+    let encodings += ['euc-jp']
+  endif
+  for enc in encodings
+    let msg = 'enc=' .. enc
+    if RunVim([], after, $'--clean --cmd "set encoding={enc}"')
+      call assert_equal([], readfile('Xresult'), msg)
+    endif
+    call delete('Xresult')
+  endfor
 endfunc
 
 " Test for getcurpos() and setpos()
index 610566fd6504d98ccbaa87ed4881333df2c60ddf..3bb7459797634f51f000e15ae8630bf1dbef3f53 100644 (file)
@@ -135,6 +135,19 @@ func Test_screenchar_utf8()
   call assert_equal("B", screenstring(1, 2))
   call assert_equal("C\u0308", screenstring(1, 3))
 
+  " 1-cell, with 6 composing characters
+  set maxcombine=6
+  call setline(1, ["ABC" .. repeat("\u0308", 6)])
+  redraw
+  call assert_equal([0x0041], screenchars(1, 1))
+  call assert_equal([0x0042], 1->screenchars(2))
+  " This should not use uninitialized memory
+  call assert_equal([0x0043] + repeat([0x0308], 6), screenchars(1, 3))
+  call assert_equal("A", screenstring(1, 1))
+  call assert_equal("B", screenstring(1, 2))
+  call assert_equal("C" .. repeat("\u0308", 6), screenstring(1, 3))
+  set maxcombine&
+
   " 2-cells, with composing characters
   let text = "\u3042\u3044\u3046\u3099"
   call setline(1, text)
index 11b962d7e07a1a3406b3d6af36680f64eb40758c..320add580bc71f43fc81e9a95483f09f16f0e61d 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1598,
 /**/
     1597,
 /**/