summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2021-09-14 17:54:30 +0200
committerBram Moolenaar <Bram@vim.org>2021-09-14 17:54:30 +0200
commit5dfe467432638fac2e0156a2f9cd0d9eb569fb39 (patch)
treef26436377c3b39cbbd4881d7c18450e61dc0d3ef /src
parentf5785cf0592626ec17676e814d3ba58f5123bcda (diff)
patch 8.2.3438: cannot manipulate blobsv8.2.3438
Problem: Cannot manipulate blobs. Solution: Add blob2list() and list2blob(). (Yegappan Lakshmanan, closes #8868)
Diffstat (limited to 'src')
-rw-r--r--src/blob.c61
-rw-r--r--src/errors.h4
-rw-r--r--src/evalfunc.c14
-rw-r--r--src/proto/blob.pro2
-rw-r--r--src/proto/typval.pro1
-rw-r--r--src/testdir/test_blob.vim39
-rw-r--r--src/testdir/test_vim9_builtin.vim12
-rw-r--r--src/typval.c17
-rw-r--r--src/version.c2
9 files changed, 152 insertions, 0 deletions
diff --git a/src/blob.c b/src/blob.c
index 2138ac0740..04319f8b1e 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -483,4 +483,65 @@ blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
}
}
+/*
+ * blob2list() function
+ */
+ void
+f_blob2list(typval_T *argvars, typval_T *rettv)
+{
+ blob_T *blob;
+ list_T *l;
+ int i;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ if (check_for_blob_arg(argvars, 0) == FAIL)
+ return;
+
+ blob = argvars->vval.v_blob;
+ l = rettv->vval.v_list;
+ for (i = 0; i < blob_len(blob); i++)
+ list_append_number(l, blob_get(blob, i));
+}
+
+/*
+ * list2blob() function
+ */
+ void
+f_list2blob(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ listitem_T *li;
+ blob_T *blob;
+
+ if (rettv_blob_alloc(rettv) == FAIL)
+ return;
+ blob = rettv->vval.v_blob;
+
+ if (check_for_list_arg(argvars, 0) == FAIL)
+ return;
+
+ l = argvars->vval.v_list;
+ if (l == NULL)
+ return;
+
+ FOR_ALL_LIST_ITEMS(l, li)
+ {
+ int error;
+ varnumber_T n;
+
+ error = FALSE;
+ n = tv_get_number_chk(&li->li_tv, &error);
+ if (error == TRUE || n < 0 || n > 255)
+ {
+ if (!error)
+ semsg(_(e_invalid_value_for_blob_nr), n);
+ ga_clear(&blob->bv_ga);
+ return;
+ }
+ ga_append(&blob->bv_ga, n);
+ }
+}
+
#endif // defined(FEAT_EVAL)
diff --git a/src/errors.h b/src/errors.h
index d4ba7f0ea5..a8ea33d170 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -660,3 +660,7 @@ EXTERN char e_cannot_use_str_itself_it_is_imported_with_star[]
INIT(= N_("E1236: Cannot use %s itself, it is imported with '*'"));
EXTERN char e_no_such_user_defined_command_in_current_buffer_str[]
INIT(= N_("E1237: No such user-defined command in current buffer: %s"));
+EXTERN char e_blob_required_for_argument_nr[]
+ INIT(= N_("E1238: Blob required for argument %d"));
+EXTERN char e_invalid_value_for_blob_nr[]
+ INIT(= N_("E1239: Invalid value for blob: %d"));
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 47290ddeed..16d9be3321 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -289,6 +289,15 @@ arg_string(type_T *type, argcontext_T *context)
}
/*
+ * Check "type" is a blob
+ */
+ static int
+arg_blob(type_T *type, argcontext_T *context)
+{
+ return check_arg_type(&t_blob, type, context);
+}
+
+/*
* Check "type" is a bool or number 0 or 1.
*/
static int
@@ -680,6 +689,7 @@ arg_cursor1(type_T *type, argcontext_T *context)
/*
* Lists of functions that check the argument types of a builtin function.
*/
+static argcheck_T arg1_blob[] = {arg_blob};
static argcheck_T arg1_bool[] = {arg_bool};
static argcheck_T arg1_buffer[] = {arg_buffer};
static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any};
@@ -1169,6 +1179,8 @@ static funcentry_T global_functions[] =
NULL
#endif
},
+ {"blob2list", 1, 1, FEARG_1, arg1_blob,
+ ret_list_number, f_blob2list},
{"browse", 4, 4, 0, arg4_browse,
ret_string, f_browse},
{"browsedir", 2, 2, 0, arg2_string,
@@ -1589,6 +1601,8 @@ static funcentry_T global_functions[] =
ret_number, f_line2byte},
{"lispindent", 1, 1, FEARG_1, arg1_lnum,
ret_number, f_lispindent},
+ {"list2blob", 1, 1, FEARG_1, arg1_list_number,
+ ret_blob, f_list2blob},
{"list2str", 1, 2, FEARG_1, arg2_list_number_bool,
ret_string, f_list2str},
{"listener_add", 1, 2, FEARG_2, arg2_any_buffer,
diff --git a/src/proto/blob.pro b/src/proto/blob.pro
index 5d80463e3d..dbc8d1490c 100644
--- a/src/proto/blob.pro
+++ b/src/proto/blob.pro
@@ -19,4 +19,6 @@ int check_blob_index(long bloblen, varnumber_T n1, int quiet);
int check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet);
int blob_set_range(blob_T *dest, long n1, long n2, typval_T *src);
void blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg);
+void f_blob2list(typval_T *argvars, typval_T *rettv);
+void f_list2blob(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
diff --git a/src/proto/typval.pro b/src/proto/typval.pro
index e509e4d951..d13a1ec711 100644
--- a/src/proto/typval.pro
+++ b/src/proto/typval.pro
@@ -17,6 +17,7 @@ int check_for_opt_number_arg(typval_T *args, int idx);
int check_for_float_or_nr_arg(typval_T *args, int idx);
int check_for_bool_arg(typval_T *args, int idx);
int check_for_opt_bool_arg(typval_T *args, int idx);
+int check_for_blob_arg(typval_T *args, int idx);
int check_for_list_arg(typval_T *args, int idx);
int check_for_opt_list_arg(typval_T *args, int idx);
int check_for_dict_arg(typval_T *args, int idx);
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index d56c4f748a..e722dab559 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -638,4 +638,43 @@ func Test_blob_sort()
call CheckLegacyAndVim9Failure(['call sort([11, 0z11], "N")'], 'E974:')
endfunc
+" Tests for the blob2list() function
+func Test_blob2list()
+ call assert_fails('let v = blob2list(10)', 'E1238: Blob required for argument 1')
+ eval 0zFFFF->blob2list()->assert_equal([255, 255])
+ let tests = [[0z0102, [1, 2]],
+ \ [0z00, [0]],
+ \ [0z, []],
+ \ [0z00000000, [0, 0, 0, 0]],
+ \ [0zAABB.CCDD, [170, 187, 204, 221]]]
+ for t in tests
+ call assert_equal(t[0]->blob2list(), t[1])
+ endfor
+ exe 'let v = 0z' .. repeat('000102030405060708090A0B0C0D0E0F', 64)
+ call assert_equal(1024, blob2list(v)->len())
+ call assert_equal([4, 8, 15], [v[100], v[1000], v[1023]])
+ call assert_equal([], blob2list(test_null_blob()))
+endfunc
+
+" Tests for the list2blob() function
+func Test_list2blob()
+ call assert_fails('let b = list2blob(0z10)', 'E1211: List required for argument 1')
+ let tests = [[[1, 2], 0z0102],
+ \ [[0], 0z00],
+ \ [[], 0z],
+ \ [[0, 0, 0, 0], 0z00000000],
+ \ [[170, 187, 204, 221], 0zAABB.CCDD],
+ \ ]
+ for t in tests
+ call assert_equal(t[0]->list2blob(), t[1])
+ endfor
+ call assert_fails('let b = list2blob([1, []])', 'E745:')
+ call assert_fails('let b = list2blob([-1])', 'E1239:')
+ call assert_fails('let b = list2blob([256])', 'E1239:')
+ let b = range(16)->repeat(64)->list2blob()
+ call assert_equal(1024, b->len())
+ call assert_equal([4, 8, 15], [b[100], b[1000], b[1023]])
+ call assert_equal(0z, list2blob(test_null_list()))
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 5f22b333d6..746d3f8833 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -287,6 +287,10 @@ def Test_balloon_split()
assert_fails('balloon_split(true)', 'E1174:')
enddef
+def Test_blob2list()
+ CheckDefAndScriptFailure2(['blob2list(10)'], 'E1013: Argument 1: type mismatch, expected blob but got number', 'E1238: Blob required for argument 1')
+enddef
+
def Test_browse()
CheckFeature browse
@@ -572,6 +576,7 @@ def Test_char2nr()
assert_equal(97, char2nr('a', 0))
assert_equal(97, char2nr('a', true))
assert_equal(97, char2nr('a', false))
+ char2nr('')->assert_equal(0)
enddef
def Test_charclass()
@@ -786,6 +791,8 @@ def Test_escape()
CheckDefAndScriptFailure2(['escape(true, false)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1')
CheckDefAndScriptFailure2(['escape("a", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2')
assert_equal('a\:b', escape("a:b", ":"))
+ escape('abc', '')->assert_equal('abc')
+ escape('', ':')->assert_equal('')
enddef
def Test_eval()
@@ -1921,6 +1928,11 @@ def Test_lispindent()
assert_equal(0, lispindent(1))
enddef
+def Test_list2blob()
+ CheckDefAndScriptFailure2(['list2blob(10)'], 'E1013: Argument 1: type mismatch, expected list<number> but got number', 'E1211: List required for argument 1')
+ CheckDefFailure(['list2blob([0z10, 0z02])'], 'E1013: Argument 1: type mismatch, expected list<number> but got list<blob>')
+enddef
+
def Test_list2str_str2list_utf8()
var s = "\u3042\u3044"
var l = [0x3042, 0x3044]
diff --git a/src/typval.c b/src/typval.c
index 3a0e2e5d99..c859122ee7 100644
--- a/src/typval.c
+++ b/src/typval.c
@@ -471,6 +471,23 @@ check_for_opt_bool_arg(typval_T *args, int idx)
}
/*
+ * Give an error and return FAIL unless "args[idx]" is a blob.
+ */
+ int
+check_for_blob_arg(typval_T *args, int idx)
+{
+ if (args[idx].v_type != VAR_BLOB)
+ {
+ if (idx >= 0)
+ semsg(_(e_blob_required_for_argument_nr), idx + 1);
+ else
+ emsg(_(e_blob_required));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
* Give an error and return FAIL unless "args[idx]" is a list.
*/
int
diff --git a/src/version.c b/src/version.c
index 11a976c4bc..c803e5bb57 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3438,
+/**/
3437,
/**/
3436,