Patch 9.0.0430
Problem:    Cannot use repeat() with a blob.
Solution:   Implement blob repeat. (closes #11090)
Files:      runtime/doc/builtin.txt, src/errors.h, src/evalfunc.c,
            src/typval.c, src/proto/typval.pro, src/testdir/test_blob.vim,
            src/testdir/test_vim9_builtin.vim, src/testdir/test_vim9_func.vim


*** ../vim-9.0.0429/runtime/doc/builtin.txt     2022-09-07 21:30:40.139379052 
+0100
--- runtime/doc/builtin.txt     2022-09-09 18:21:48.346091765 +0100
***************
*** 471,477 ****
                                        remove bytes {idx}-{end} from {blob}
  remove({dict}, {key})         any     remove entry {key} from {dict}
  rename({from}, {to})          Number  rename (move) file from {from} to {to}
! repeat({expr}, {count})               String  repeat {expr} {count} times
  resolve({filename})           String  get filename a shortcut points to
  reverse({list})                       List    reverse {list} in-place
  round({expr})                 Float   round off {expr}
--- 471,478 ----
                                        remove bytes {idx}-{end} from {blob}
  remove({dict}, {key})         any     remove entry {key} from {dict}
  rename({from}, {to})          Number  rename (move) file from {from} to {to}
! repeat({expr}, {count})               List/Blob/String
!                                       repeat {expr} {count} times
  resolve({filename})           String  get filename a shortcut points to
  reverse({list})                       List    reverse {list} in-place
  round({expr})                 Float   round off {expr}
***************
*** 7284,7291 ****
                result.  Example: >
                        :let separator = repeat('-', 80)
  <             When {count} is zero or negative the result is empty.
!               When {expr} is a |List| the result is {expr} concatenated
!               {count} times.  Example: >
                        :let longlist = repeat(['a', 'b'], 3)
  <             Results in ['a', 'b', 'a', 'b', 'a', 'b'].
  
--- 7295,7302 ----
                result.  Example: >
                        :let separator = repeat('-', 80)
  <             When {count} is zero or negative the result is empty.
!               When {expr} is a |List| or a |Blob| the result is {expr}
!               concatenated {count} times.  Example: >
                        :let longlist = repeat(['a', 'b'], 3)
  <             Results in ['a', 'b', 'a', 'b', 'a', 'b'].
  
*** ../vim-9.0.0429/src/errors.h        2022-09-05 21:21:21.135941382 +0100
--- src/errors.h        2022-09-09 18:25:20.473676112 +0100
***************
*** 3329,3332 ****
--- 3329,3334 ----
  #ifdef FEAT_EVAL
  EXTERN char e_cannot_use_partial_with_dictionary_for_defer[]
        INIT(= N_("E1300: Cannot use a partial with dictionary for :defer"));
+ EXTERN char e_string_number_list_or_blob_required_for_argument_nr[]
+       INIT(= N_("E1301: String, Number, List or Blob required for argument 
%d"));
  #endif
*** ../vim-9.0.0429/src/evalfunc.c      2022-09-04 12:29:22.144893115 +0100
--- src/evalfunc.c      2022-09-09 18:29:07.821193375 +0100
***************
*** 872,877 ****
--- 872,878 ----
            || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_NUMBER
+           || type->tt_type == VAR_BLOB
            || type->tt_type == VAR_LIST)
        return OK;
  
***************
*** 4400,4405 ****
--- 4401,4410 ----
  #endif
  }
  
+ /*
+  * "function()" function
+  * "funcref()" function
+  */
      static void
  common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
  {
***************
*** 8399,8416 ****
  f_repeat(typval_T *argvars, typval_T *rettv)
  {
      char_u    *p;
!     int               n;
      int               slen;
      int               len;
      char_u    *r;
      int               i;
  
      if (in_vim9script()
!           && (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
                || check_for_number_arg(argvars, 1) == FAIL))
        return;
  
!     n = (int)tv_get_number(&argvars[1]);
      if (argvars[0].v_type == VAR_LIST)
      {
        if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
--- 8404,8422 ----
  f_repeat(typval_T *argvars, typval_T *rettv)
  {
      char_u    *p;
!     varnumber_T       n;
      int               slen;
      int               len;
      char_u    *r;
      int               i;
  
      if (in_vim9script()
!           && (check_for_string_or_number_or_list_or_blob_arg(argvars, 0)
!                   == FAIL
                || check_for_number_arg(argvars, 1) == FAIL))
        return;
  
!     n = tv_get_number(&argvars[1]);
      if (argvars[0].v_type == VAR_LIST)
      {
        if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
***************
*** 8419,8424 ****
--- 8425,8459 ----
                                        argvars[0].vval.v_list, NULL) == FAIL)
                    break;
      }
+     else if (argvars[0].v_type == VAR_BLOB)
+     {
+       if (rettv_blob_alloc(rettv) == FAIL
+               || argvars[0].vval.v_blob == NULL
+               || n <= 0)
+           return;
+ 
+       slen = argvars[0].vval.v_blob->bv_ga.ga_len;
+       len = (int)slen * n;
+       if (len <= 0)
+           return;
+ 
+       if (ga_grow(&rettv->vval.v_blob->bv_ga, len) == FAIL)
+           return;
+ 
+       rettv->vval.v_blob->bv_ga.ga_len = len;
+ 
+       for (i = 0; i < slen; ++i)
+           if (blob_get(argvars[0].vval.v_blob, i) != 0)
+               break;
+ 
+       if (i == slen)
+           // No need to copy since all bytes are already zero
+           return;
+ 
+       for (i = 0; i < n; ++i)
+           blob_set_range(rettv->vval.v_blob,
+                   (long)i * slen, ((long)i + 1) * slen - 1, argvars);
+     }
      else
      {
        p = tv_get_string(&argvars[0]);
*** ../vim-9.0.0429/src/typval.c        2022-09-01 12:22:19.747659165 +0100
--- src/typval.c        2022-09-09 18:21:48.350091758 +0100
***************
*** 792,797 ****
--- 792,815 ----
  }
  
  /*
+  * Give an error and return FAIL unless "args[idx]" is a string or a number
+  * or a list or a blob.
+  */
+     int
+ check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx)
+ {
+     if (args[idx].v_type != VAR_STRING
+           && args[idx].v_type != VAR_NUMBER
+           && args[idx].v_type != VAR_LIST
+           && args[idx].v_type != VAR_BLOB)
+     {
+       semsg(_(e_string_number_list_or_blob_required_for_argument_nr), idx + 
1);
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+ /*
   * Give an error and return FAIL unless "args[idx]" is a string or a list
   * or a dict.
   */
*** ../vim-9.0.0429/src/proto/typval.pro        2022-09-01 12:22:19.747659165 
+0100
--- src/proto/typval.pro        2022-09-09 18:38:24.503922543 +0100
***************
*** 42,47 ****
--- 42,48 ----
  int check_for_string_or_dict_arg(typval_T *args, int idx);
  int check_for_string_or_number_or_list_arg(typval_T *args, int idx);
  int check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx);
+ int check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx);
  int check_for_string_or_list_or_dict_arg(typval_T *args, int idx);
  int check_for_string_or_func_arg(typval_T *args, int idx);
  int check_for_list_or_blob_arg(typval_T *args, int idx);
*** ../vim-9.0.0429/src/testdir/test_blob.vim   2022-08-14 12:07:06.918862666 
+0100
--- src/testdir/test_blob.vim   2022-09-09 18:43:44.291164347 +0100
***************
*** 725,730 ****
--- 725,742 ----
    call assert_equal(v, string(b))
  endfunc
  
+ func Test_blob_repeat()
+   call assert_equal(0z, repeat(0z00, 0))
+   call assert_equal(0z00, repeat(0z00, 1))
+   call assert_equal(0z0000, repeat(0z00, 2))
+   call assert_equal(0z00000000, repeat(0z0000, 2))
+ 
+   call assert_equal(0z, repeat(0z12, 0))
+   call assert_equal(0z, repeat(0z1234, 0))
+   call assert_equal(0z1234, repeat(0z1234, 1))
+   call assert_equal(0z12341234, repeat(0z1234, 2))
+ endfunc
+ 
  " Test for blob allocation failure
  func Test_blob_alloc_failure()
    " blob variable
*** ../vim-9.0.0429/src/testdir/test_vim9_builtin.vim   2022-09-02 
15:15:11.067569180 +0100
--- src/testdir/test_vim9_builtin.vim   2022-09-09 18:25:49.801615672 +0100
***************
*** 3329,3340 ****
  enddef
  
  def Test_repeat()
!   v9.CheckDefAndScriptFailure(['repeat(1.1, 2)'], ['E1013: Argument 1: type 
mismatch, expected string but got float', 'E1224: String, Number or List 
required for argument 1'])
!   v9.CheckDefAndScriptFailure(['repeat({a: 10}, 2)'], ['E1013: Argument 1: 
type mismatch, expected string but got dict<', 'E1224: String, Number or List 
required for argument 1'])
    var lines =<< trim END
        assert_equal('aaa', repeat('a', 3))
        assert_equal('111', repeat(1, 3))
        assert_equal([1, 1, 1], repeat([1], 3))
        var s = '-'
        s ..= repeat(5, 3)
        assert_equal('-555', s)
--- 3329,3342 ----
  enddef
  
  def Test_repeat()
!   v9.CheckDefAndScriptFailure(['repeat(1.1, 2)'], ['E1013: Argument 1: type 
mismatch, expected string but got float', 'E1301: String, Number, List or Blob 
required for argument 1'])
!   v9.CheckDefAndScriptFailure(['repeat({a: 10}, 2)'], ['E1013: Argument 1: 
type mismatch, expected string but got dict<', 'E1301: String, Number, List or 
Blob required for argument 1'])
    var lines =<< trim END
        assert_equal('aaa', repeat('a', 3))
        assert_equal('111', repeat(1, 3))
        assert_equal([1, 1, 1], repeat([1], 3))
+       assert_equal(0z000102000102000102, repeat(0z000102, 3))
+       assert_equal(0z000000, repeat(0z00, 3))
        var s = '-'
        s ..= repeat(5, 3)
        assert_equal('-555', s)
*** ../vim-9.0.0429/src/testdir/test_vim9_func.vim      2022-09-03 
21:35:50.188158217 +0100
--- src/testdir/test_vim9_func.vim      2022-09-09 18:21:48.350091758 +0100
***************
*** 2534,2539 ****
--- 2534,2545 ----
    res->assert_equal(3)
  
    res = 0
+   for n in repeat(0z01, 3)->blob2list()
+     res += n
+   endfor
+   res->assert_equal(3)
+ 
+   res = 0
    for n in add([1, 2], 3)
      res += n
    endfor
*** ../vim-9.0.0429/src/version.c       2022-09-09 17:38:58.836061268 +0100
--- src/version.c       2022-09-09 18:24:46.401745513 +0100
***************
*** 705,706 ****
--- 705,708 ----
  {   /* Add new patch number below this line */
+ /**/
+     430,
  /**/

-- 
Have you heard about the new Beowulf cluster? It's so fast, it executes
an infinite loop in 6 seconds.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220909174722.2BA971C0CF3%40moolenaar.net.

Raspunde prin e-mail lui