From 9afefd32d3938a50a023355af86ec3293a047130 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Jan 2022 17:37:06 +0800 Subject: [PATCH 1/2] vim-patch:8.2.3630: printf() with %S does not handle multi-byte correctly Problem: Printf() with %S does not handle multi-byte correctly. Solution: Count cells instead of bytes. (closes vim/vim#9169, closes vim/vim#7486) https://github.com/vim/vim/commit/d85fccdfed58108c4e0958d0b17c64690b5f073f --- src/nvim/strings.c | 13 ++++++++----- src/nvim/testdir/test_expr.vim | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index e2a8108c45..efcd40bb75 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1001,10 +1001,9 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, t - str_arg); } if (fmt_spec == 'S') { - if (min_field_width != 0) { - min_field_width += (strlen(str_arg) - - mb_string2cells((char_u *)str_arg)); - } + size_t base_width = min_field_width; + size_t pad_cell = 0; + if (precision) { char_u *p1; size_t i = 0; @@ -1016,7 +1015,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, t break; } } - str_arg_l = (size_t)(p1 - (char_u *)str_arg); + pad_cell = min_field_width - precision; + base_width = str_arg_l = (size_t)(p1 - (char_u *)str_arg); + } + if (min_field_width != 0) { + min_field_width = base_width + pad_cell; } } break; diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 1d7fd3e385..447a519f2c 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -283,6 +283,11 @@ function Test_printf_misc() call assert_equal('🐍', printf('%.2S', '🐍🐍')) call assert_equal('', printf('%.1S', '🐍🐍')) + call assert_equal('[ あいう]', printf('[%10.6S]', 'あいうえお')) + call assert_equal('[ あいうえ]', printf('[%10.8S]', 'あいうえお')) + call assert_equal('[あいうえお]', printf('[%10.10S]', 'あいうえお')) + call assert_equal('[あいうえお]', printf('[%10.12S]', 'あいうえお')) + call assert_equal('1%', printf('%d%%', 1)) endfunc From 658ef9c01ee2e89b5a29f8fb018ac959ae2f4a90 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Jan 2022 17:37:06 +0800 Subject: [PATCH 2/2] vim-patch:8.2.3663: using %S in printf() does not work correctly Problem: Using %S in printf() does not work correctly. Solution: Fix the problem and add more tests. (closes vim/vim#9208) https://github.com/vim/vim/commit/1f2453fec6f8f0f315f00ca7b562a02090cb1e37 --- src/nvim/strings.c | 25 ++++++-------- src/nvim/testdir/test_expr.vim | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index efcd40bb75..291138ef23 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1001,25 +1001,20 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, t - str_arg); } if (fmt_spec == 'S') { - size_t base_width = min_field_width; - size_t pad_cell = 0; + char_u *p1; + size_t i; - if (precision) { - char_u *p1; - size_t i = 0; - - for (p1 = (char_u *)str_arg; *p1; - p1 += utfc_ptr2len(p1)) { - i += (size_t)utf_ptr2cells(p1); - if (i > precision) { - break; - } + for (i = 0, p1 = (char_u *)str_arg; *p1; p1 += utfc_ptr2len(p1)) { + size_t cell = (size_t)utf_ptr2cells(p1); + if (precision_specified && i + cell > precision) { + break; } - pad_cell = min_field_width - precision; - base_width = str_arg_l = (size_t)(p1 - (char_u *)str_arg); + i += cell; } + + str_arg_l = (size_t)(p1 - (char_u *)str_arg); if (min_field_width != 0) { - min_field_width = base_width + pad_cell; + min_field_width += str_arg_l - i; } } break; diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 447a519f2c..5b10e691e5 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -288,6 +288,66 @@ function Test_printf_misc() call assert_equal('[あいうえお]', printf('[%10.10S]', 'あいうえお')) call assert_equal('[あいうえお]', printf('[%10.12S]', 'あいうえお')) + call assert_equal('あいう', printf('%S', 'あいう')) + call assert_equal('あいう', printf('%#S', 'あいう')) + + call assert_equal('あb', printf('%2S', 'あb')) + call assert_equal('あb', printf('%.4S', 'あb')) + call assert_equal('あ', printf('%.2S', 'あb')) + call assert_equal(' あb', printf('%4S', 'あb')) + call assert_equal('0あb', printf('%04S', 'あb')) + call assert_equal('あb ', printf('%-4S', 'あb')) + call assert_equal('あ ', printf('%-4.2S', 'あb')) + + call assert_equal('aい', printf('%2S', 'aい')) + call assert_equal('aい', printf('%.4S', 'aい')) + call assert_equal('a', printf('%.2S', 'aい')) + call assert_equal(' aい', printf('%4S', 'aい')) + call assert_equal('0aい', printf('%04S', 'aい')) + call assert_equal('aい ', printf('%-4S', 'aい')) + call assert_equal('a ', printf('%-4.2S', 'aい')) + + call assert_equal('[あいう]', printf('[%05S]', 'あいう')) + call assert_equal('[あいう]', printf('[%06S]', 'あいう')) + call assert_equal('[0あいう]', printf('[%07S]', 'あいう')) + + call assert_equal('[あiう]', printf('[%05S]', 'あiう')) + call assert_equal('[0あiう]', printf('[%06S]', 'あiう')) + call assert_equal('[00あiう]', printf('[%07S]', 'あiう')) + + call assert_equal('[0あい]', printf('[%05.4S]', 'あいう')) + call assert_equal('[00あい]', printf('[%06.4S]', 'あいう')) + call assert_equal('[000あい]', printf('[%07.4S]', 'あいう')) + + call assert_equal('[00あi]', printf('[%05.4S]', 'あiう')) + call assert_equal('[000あi]', printf('[%06.4S]', 'あiう')) + call assert_equal('[0000あi]', printf('[%07.4S]', 'あiう')) + + call assert_equal('[0あい]', printf('[%05.5S]', 'あいう')) + call assert_equal('[00あい]', printf('[%06.5S]', 'あいう')) + call assert_equal('[000あい]', printf('[%07.5S]', 'あいう')) + + call assert_equal('[あiう]', printf('[%05.5S]', 'あiう')) + call assert_equal('[0あiう]', printf('[%06.5S]', 'あiう')) + call assert_equal('[00あiう]', printf('[%07.5S]', 'あiう')) + + call assert_equal('[0000000000]', printf('[%010.0S]', 'あいう')) + call assert_equal('[0000000000]', printf('[%010.1S]', 'あいう')) + call assert_equal('[00000000あ]', printf('[%010.2S]', 'あいう')) + call assert_equal('[00000000あ]', printf('[%010.3S]', 'あいう')) + call assert_equal('[000000あい]', printf('[%010.4S]', 'あいう')) + call assert_equal('[000000あい]', printf('[%010.5S]', 'あいう')) + call assert_equal('[0000あいう]', printf('[%010.6S]', 'あいう')) + call assert_equal('[0000あいう]', printf('[%010.7S]', 'あいう')) + + call assert_equal('[0000000000]', printf('[%010.1S]', 'あiう')) + call assert_equal('[00000000あ]', printf('[%010.2S]', 'あiう')) + call assert_equal('[0000000あi]', printf('[%010.3S]', 'あiう')) + call assert_equal('[0000000あi]', printf('[%010.4S]', 'あiう')) + call assert_equal('[00000あiう]', printf('[%010.5S]', 'あiう')) + call assert_equal('[00000あiう]', printf('[%010.6S]', 'あiう')) + call assert_equal('[00000あiう]', printf('[%010.7S]', 'あiう')) + call assert_equal('1%', printf('%d%%', 1)) endfunc