aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.lua2
-rw-r--r--src/nvim/eval/typval.c73
-rw-r--r--src/nvim/testdir/test_blob.vim40
3 files changed, 115 insertions, 0 deletions
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 24263d9aee..ae10a7e035 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -49,6 +49,7 @@ return {
assert_true={args={1, 2}, base=1},
atan={args=1, base=1, float_func="atan"},
atan2={args=2, base=1},
+ blob2list={args=1, base=1},
browse={args=4},
browsedir={args=2},
bufadd={args=1, base=1},
@@ -249,6 +250,7 @@ return {
line={args={1, 2}, base=1},
line2byte={args=1, base=1},
lispindent={args=1, base=1},
+ list2blob={args=1, base=1},
list2str={args={1, 2}, base=1},
localtime={},
log={args=1, base=1, float_func="log"},
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index d56efe30da..6037536548 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -48,10 +48,16 @@ static char e_dict_required_for_argument_nr[]
= N_("E1206: Dictionary required for argument %d");
static char e_number_required_for_argument_nr[]
= N_("E1210: Number required for argument %d");
+static char e_list_required_for_argument_nr[]
+ = N_("E1211: List required for argument %d");
static char e_string_or_list_required_for_argument_nr[]
= N_("E1222: String or List required for argument %d");
static char e_list_or_blob_required_for_argument_nr[]
= N_("E1226: List or Blob required for argument %d");
+static char e_blob_required_for_argument_nr[]
+ = N_("E1238: Blob required for argument %d");
+static char e_invalid_value_for_blob_nr[]
+ = N_("E1239: Invalid value for blob: %d");
static char e_string_or_function_required_for_argument_nr[]
= N_("E1256: String or function required for argument %d");
@@ -2826,6 +2832,51 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
}
}
+/// blob2list() function
+void f_blob2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ if (tv_check_for_blob_arg(argvars, 0) == FAIL) {
+ return;
+ }
+
+ blob_T *const blob = argvars->vval.v_blob;
+ list_T *const l = rettv->vval.v_list;
+ for (int i = 0; i < tv_blob_len(blob); i++) {
+ tv_list_append_number(l, tv_blob_get(blob, i));
+ }
+}
+
+/// list2blob() function
+void f_list2blob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_blob_alloc_ret(rettv);
+ blob_T *const blob = rettv->vval.v_blob;
+
+ if (tv_check_for_list_arg(argvars, 0) == FAIL) {
+ return;
+ }
+
+ list_T *const l = argvars->vval.v_list;
+ if (l == NULL) {
+ return;
+ }
+
+ TV_LIST_ITER_CONST(l, li, {
+ bool error = false;
+ varnumber_T n = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
+ if (error || 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, (uint8_t)n);
+ });
+}
+
//{{{1 Generic typval operations
//{{{2 Init/alloc/clear
//{{{3 Alloc
@@ -3968,6 +4019,28 @@ int tv_check_for_opt_number_arg(const typval_T *const args, const int idx)
|| tv_check_for_number_arg(args, idx) != FAIL) ? OK : FAIL;
}
+/// Give an error and return FAIL unless "args[idx]" is a blob.
+int tv_check_for_blob_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (args[idx].v_type != VAR_BLOB) {
+ semsg(_(e_blob_required_for_argument_nr), idx + 1);
+ return FAIL;
+ }
+ return OK;
+}
+
+/// Give an error and return FAIL unless "args[idx]" is a list.
+int tv_check_for_list_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (args[idx].v_type != VAR_LIST) {
+ semsg(_(e_list_required_for_argument_nr), idx + 1);
+ return FAIL;
+ }
+ return OK;
+}
+
/// Give an error and return FAIL unless "args[idx]" is a dict.
int tv_check_for_dict_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index b01d9309fa..f889da987a 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -666,6 +666,46 @@ 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(v:_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],
+ \ [[255, 255], 0zFFFF],
+ \ [[170, 187, 204, 221], 0zAABB.CCDD],
+ \ ]
+ for t in tests
+ call assert_equal(t[1], t[0]->list2blob())
+ 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(v:_null_list))
+endfunc
+
" The following used to cause an out-of-bounds memory access
func Test_blob2string()
let v = '0z' .. repeat('01010101.', 444)