Skip to content

Commit 375141e

Browse files
Bakudankunbrammool
authored andcommitted
patch 9.0.0430: cannot use repeat() with a blob
Problem: Cannot use repeat() with a blob. Solution: Implement blob repeat. (closes #11090)
1 parent 0adae2d commit 375141e

File tree

9 files changed

+87
-8
lines changed

9 files changed

+87
-8
lines changed

runtime/doc/builtin.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,8 @@ remove({blob}, {idx} [, {end}]) Number/Blob
471471
remove bytes {idx}-{end} from {blob}
472472
remove({dict}, {key}) any remove entry {key} from {dict}
473473
rename({from}, {to}) Number rename (move) file from {from} to {to}
474-
repeat({expr}, {count}) String repeat {expr} {count} times
474+
repeat({expr}, {count}) List/Blob/String
475+
repeat {expr} {count} times
475476
resolve({filename}) String get filename a shortcut points to
476477
reverse({list}) List reverse {list} in-place
477478
round({expr}) Float round off {expr}
@@ -7294,8 +7295,8 @@ repeat({expr}, {count}) *repeat()*
72947295
result. Example: >
72957296
:let separator = repeat('-', 80)
72967297
< When {count} is zero or negative the result is empty.
7297-
When {expr} is a |List| the result is {expr} concatenated
7298-
{count} times. Example: >
7298+
When {expr} is a |List| or a |Blob| the result is {expr}
7299+
concatenated {count} times. Example: >
72997300
:let longlist = repeat(['a', 'b'], 3)
73007301
< Results in ['a', 'b', 'a', 'b', 'a', 'b'].
73017302

src/errors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,4 +3329,6 @@ EXTERN char e_window_unexpectedly_close_while_searching_for_tags[]
33293329
#ifdef FEAT_EVAL
33303330
EXTERN char e_cannot_use_partial_with_dictionary_for_defer[]
33313331
INIT(= N_("E1300: Cannot use a partial with dictionary for :defer"));
3332+
EXTERN char e_string_number_list_or_blob_required_for_argument_nr[]
3333+
INIT(= N_("E1301: String, Number, List or Blob required for argument %d"));
33323334
#endif

src/evalfunc.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
872872
|| type->tt_type == VAR_UNKNOWN
873873
|| type->tt_type == VAR_STRING
874874
|| type->tt_type == VAR_NUMBER
875+
|| type->tt_type == VAR_BLOB
875876
|| type->tt_type == VAR_LIST)
876877
return OK;
877878

@@ -4400,6 +4401,10 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
44004401
#endif
44014402
}
44024403

4404+
/*
4405+
* "function()" function
4406+
* "funcref()" function
4407+
*/
44034408
static void
44044409
common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
44054410
{
@@ -8399,18 +8404,19 @@ f_rename(typval_T *argvars, typval_T *rettv)
83998404
f_repeat(typval_T *argvars, typval_T *rettv)
84008405
{
84018406
char_u *p;
8402-
int n;
8407+
varnumber_T n;
84038408
int slen;
84048409
int len;
84058410
char_u *r;
84068411
int i;
84078412

84088413
if (in_vim9script()
8409-
&& (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
8414+
&& (check_for_string_or_number_or_list_or_blob_arg(argvars, 0)
8415+
== FAIL
84108416
|| check_for_number_arg(argvars, 1) == FAIL))
84118417
return;
84128418

8413-
n = (int)tv_get_number(&argvars[1]);
8419+
n = tv_get_number(&argvars[1]);
84148420
if (argvars[0].v_type == VAR_LIST)
84158421
{
84168422
if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
@@ -8419,6 +8425,35 @@ f_repeat(typval_T *argvars, typval_T *rettv)
84198425
argvars[0].vval.v_list, NULL) == FAIL)
84208426
break;
84218427
}
8428+
else if (argvars[0].v_type == VAR_BLOB)
8429+
{
8430+
if (rettv_blob_alloc(rettv) == FAIL
8431+
|| argvars[0].vval.v_blob == NULL
8432+
|| n <= 0)
8433+
return;
8434+
8435+
slen = argvars[0].vval.v_blob->bv_ga.ga_len;
8436+
len = (int)slen * n;
8437+
if (len <= 0)
8438+
return;
8439+
8440+
if (ga_grow(&rettv->vval.v_blob->bv_ga, len) == FAIL)
8441+
return;
8442+
8443+
rettv->vval.v_blob->bv_ga.ga_len = len;
8444+
8445+
for (i = 0; i < slen; ++i)
8446+
if (blob_get(argvars[0].vval.v_blob, i) != 0)
8447+
break;
8448+
8449+
if (i == slen)
8450+
// No need to copy since all bytes are already zero
8451+
return;
8452+
8453+
for (i = 0; i < n; ++i)
8454+
blob_set_range(rettv->vval.v_blob,
8455+
(long)i * slen, ((long)i + 1) * slen - 1, argvars);
8456+
}
84228457
else
84238458
{
84248459
p = tv_get_string(&argvars[0]);

src/proto/typval.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ int check_for_opt_string_or_list_arg(typval_T *args, int idx);
4242
int check_for_string_or_dict_arg(typval_T *args, int idx);
4343
int check_for_string_or_number_or_list_arg(typval_T *args, int idx);
4444
int check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx);
45+
int check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx);
4546
int check_for_string_or_list_or_dict_arg(typval_T *args, int idx);
4647
int check_for_string_or_func_arg(typval_T *args, int idx);
4748
int check_for_list_or_blob_arg(typval_T *args, int idx);

src/testdir/test_blob.vim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,18 @@ func Test_blob2string()
725725
call assert_equal(v, string(b))
726726
endfunc
727727

728+
func Test_blob_repeat()
729+
call assert_equal(0z, repeat(0z00, 0))
730+
call assert_equal(0z00, repeat(0z00, 1))
731+
call assert_equal(0z0000, repeat(0z00, 2))
732+
call assert_equal(0z00000000, repeat(0z0000, 2))
733+
734+
call assert_equal(0z, repeat(0z12, 0))
735+
call assert_equal(0z, repeat(0z1234, 0))
736+
call assert_equal(0z1234, repeat(0z1234, 1))
737+
call assert_equal(0z12341234, repeat(0z1234, 2))
738+
endfunc
739+
728740
" Test for blob allocation failure
729741
func Test_blob_alloc_failure()
730742
" blob variable

src/testdir/test_vim9_builtin.vim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,12 +3329,14 @@ def Test_rename()
33293329
enddef
33303330

33313331
def Test_repeat()
3332-
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'])
3333-
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'])
3332+
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'])
3333+
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'])
33343334
var lines =<< trim END
33353335
assert_equal('aaa', repeat('a', 3))
33363336
assert_equal('111', repeat(1, 3))
33373337
assert_equal([1, 1, 1], repeat([1], 3))
3338+
assert_equal(0z000102000102000102, repeat(0z000102, 3))
3339+
assert_equal(0z000000, repeat(0z00, 3))
33383340
var s = '-'
33393341
s ..= repeat(5, 3)
33403342
assert_equal('-555', s)

src/testdir/test_vim9_func.vim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,6 +2533,12 @@ def Test_repeat_return_type()
25332533
endfor
25342534
res->assert_equal(3)
25352535

2536+
res = 0
2537+
for n in repeat(0z01, 3)->blob2list()
2538+
res += n
2539+
endfor
2540+
res->assert_equal(3)
2541+
25362542
res = 0
25372543
for n in add([1, 2], 3)
25382544
res += n

src/typval.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,24 @@ check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx)
791791
|| check_for_string_or_number_or_list_arg(args, idx) != FAIL);
792792
}
793793

794+
/*
795+
* Give an error and return FAIL unless "args[idx]" is a string or a number
796+
* or a list or a blob.
797+
*/
798+
int
799+
check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx)
800+
{
801+
if (args[idx].v_type != VAR_STRING
802+
&& args[idx].v_type != VAR_NUMBER
803+
&& args[idx].v_type != VAR_LIST
804+
&& args[idx].v_type != VAR_BLOB)
805+
{
806+
semsg(_(e_string_number_list_or_blob_required_for_argument_nr), idx + 1);
807+
return FAIL;
808+
}
809+
return OK;
810+
}
811+
794812
/*
795813
* Give an error and return FAIL unless "args[idx]" is a string or a list
796814
* or a dict.

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ static char *(features[]) =
703703

704704
static int included_patches[] =
705705
{ /* Add new patch number below this line */
706+
/**/
707+
430,
706708
/**/
707709
429,
708710
/**/

0 commit comments

Comments
 (0)