]> granicus.if.org Git - vim/commitdiff
patch 9.0.0430: cannot use repeat() with a blob v9.0.0430
authorBakudankun <bakudankun@gmail.com>
Fri, 9 Sep 2022 17:46:47 +0000 (18:46 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 9 Sep 2022 17:46:47 +0000 (18:46 +0100)
Problem:    Cannot use repeat() with a blob.
Solution:   Implement blob repeat. (closes #11090)

runtime/doc/builtin.txt
src/errors.h
src/evalfunc.c
src/proto/typval.pro
src/testdir/test_blob.vim
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_func.vim
src/typval.c
src/version.c

index 12d62a6760a32db139929800da75011d64b3c148..01263402fa24ed8d8883ccc05910e1233c7db26d 100644 (file)
@@ -471,7 +471,8 @@ remove({blob}, {idx} [, {end}])     Number/Blob
                                        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
+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}
@@ -7294,8 +7295,8 @@ repeat({expr}, {count})                                   *repeat()*
                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: >
+               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'].
 
index 2ed62a2afd42a20ceed6c72272abf5db54b5a7ef..45f0d6a66c3be04f6ffc4a2572a07cf1eac6aae5 100644 (file)
@@ -3329,4 +3329,6 @@ EXTERN char e_window_unexpectedly_close_while_searching_for_tags[]
 #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
index 2c041fa6de367c3c32f9a8b0c2560c7c426bd913..bc0e23e9c8e1bf0c576fc17eae7c5e33c5d9324b 100644 (file)
@@ -872,6 +872,7 @@ arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
            || 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,6 +4401,10 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 #endif
 }
 
+/*
+ * "function()" function
+ * "funcref()" function
+ */
     static void
 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
 {
@@ -8399,18 +8404,19 @@ f_rename(typval_T *argvars, typval_T *rettv)
 f_repeat(typval_T *argvars, typval_T *rettv)
 {
     char_u     *p;
-    int                n;
+    varnumber_T        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_string_or_number_or_list_or_blob_arg(argvars, 0)
+                   == FAIL
                || check_for_number_arg(argvars, 1) == FAIL))
        return;
 
-    n = (int)tv_get_number(&argvars[1]);
+    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,6 +8425,35 @@ f_repeat(typval_T *argvars, typval_T *rettv)
                                        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]);
index 7d32a03d94b639ff261ec5050f08573eb966e3f3..b4733fd474946af8d3c49ab14757b34b058674ea 100644 (file)
@@ -42,6 +42,7 @@ int check_for_opt_string_or_list_arg(typval_T *args, int idx);
 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);
index 46370c4749894ce4dde667972f7e7c79055051e1..b0239fd61055c4b4c09a16fcdde4891162ff615c 100644 (file)
@@ -725,6 +725,18 @@ func Test_blob2string()
   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
index b74a8eced299e68921f59c689d53f1722d8c44d2..109cb35af68778b089823287519280f3496504d4 100644 (file)
@@ -3329,12 +3329,14 @@ def Test_rename()
 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'])
+  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)
index c616e1890dd38ee322497a2d5b5a3b46c267b2c3..fce215e47c2e09f42f8324d31380578e18f3fc29 100644 (file)
@@ -2533,6 +2533,12 @@ def Test_repeat_return_type()
   endfor
   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
index 12a741ec220c45ba2c05996c287e40cc8fa7a418..95abe212e3b5d44f9866a943ec6c0e6819929087 100644 (file)
@@ -791,6 +791,24 @@ check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx)
            || check_for_string_or_number_or_list_arg(args, idx) != FAIL);
 }
 
+/*
+ * 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.
index ef5f102cd43f2c1d7ecf5fd7ee29f53093cfb509..3b02a3b111720f47abd1717ceae178bf2cc7e646 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    430,
 /**/
     429,
 /**/