Patch 8.2.3438
Problem: Cannot manipulate blobs.
Solution: Add blob2list() and list2blob(). (Yegappan Lakshmanan,
closes #8868)
Files: runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/blob.c,
src/errors.h, src/evalfunc.c, src/proto/
blob.pro,
src/proto/
typval.pro, src/testdir/test_blob.vim,
src/testdir/test_vim9_builtin.vim, src/typval.c
*** ../vim-8.2.3437/runtime/doc/eval.txt 2021-08-29 12:36:43.301865015 +0200
--- runtime/doc/eval.txt 2021-09-14 17:49:11.560861109 +0200
***************
*** 2452,2469 ****
balloon_gettext() String current text in the balloon
balloon_show({expr}) none show {expr} inside the balloon
balloon_split({msg}) List split {msg} as used for a balloon
browse({save}, {title}, {initdir}, {default})
String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester
bufadd({name}) Number add a buffer to the buffer list
! bufexists({expr}) Number |TRUE| if buffer {expr} exists
! buflisted({expr}) Number |TRUE| if buffer {expr} is listed
! bufload({expr}) Number load buffer {expr} if not loaded yet
! bufloaded({expr}) Number |TRUE| if buffer {expr} is loaded
! bufname([{expr}]) String Name of the buffer {expr}
! bufnr([{expr} [, {create}]]) Number Number of the buffer {expr}
! bufwinid({expr}) Number window ID of buffer {expr}
! bufwinnr({expr}) Number window number of buffer {expr}
byte2line({byte}) Number line number at byte count {byte}
byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr}
byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr}
--- 2469,2487 ----
balloon_gettext() String current text in the balloon
balloon_show({expr}) none show {expr} inside the balloon
balloon_split({msg}) List split {msg} as used for a balloon
+ blob2list({blob}) List convert {blob} into a list of numbers
browse({save}, {title}, {initdir}, {default})
String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester
bufadd({name}) Number add a buffer to the buffer list
! bufexists({buf}) Number |TRUE| if buffer {buf} exists
! buflisted({buf}) Number |TRUE| if buffer {buf} is listed
! bufload({buf}) Number load buffer {buf} if not loaded yet
! bufloaded({buf}) Number |TRUE| if buffer {buf} is loaded
! bufname([{buf}]) String Name of the buffer {buf}
! bufnr([{buf} [, {create}]]) Number Number of the buffer {buf}
! bufwinid({buf}) Number window ID of buffer {buf}
! bufwinnr({buf}) Number window number of buffer {buf}
byte2line({byte}) Number line number at byte count {byte}
byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr}
byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr}
***************
*** 2704,2710 ****
line({expr} [, {winid}]) Number line nr of cursor, last line or mark
line2byte({lnum}) Number byte count of line {lnum}
lispindent({lnum}) Number Lisp indent for line {lnum}
! list2str({list} [, {utf8}]) String turn numbers in {list} into a String
listener_add({callback} [, {buf}])
Number add a callback to listen to changes
listener_flush([{buf}]) none invoke listener callbacks
--- 2722,2729 ----
line({expr} [, {winid}]) Number line nr of cursor, last line or mark
line2byte({lnum}) Number byte count of line {lnum}
lispindent({lnum}) Number Lisp indent for line {lnum}
! list2blob({list}) Blob turn {list} of numbers into a Blob
! list2str({list} [, {utf8}]) String turn {list} of numbers into a String
listener_add({callback} [, {buf}])
Number add a callback to listen to changes
listener_flush([{buf}]) none invoke listener callbacks
***************
*** 3337,3342 ****
--- 3357,3373 ----
< {only available when compiled with the |+balloon_eval_term|
feature}
+ blob2list({blob}) *blob2list()*
+ Return a List containing the number value of each byte in Blob
+ {blob}. Examples: >
+ blob2list(0z0102.0304) returns [1, 2, 3, 4]
+ blob2list(0z) returns []
+ < Returns an empty List on error. |list2blob()| does the
+ opposite.
+
+ Can also be used as a |method|: >
+ GetBlob()->blob2list()
+
*browse()*
browse({save}, {title}, {initdir}, {default})
Put up a file requester. This only works when "has("browse")"
***************
*** 7143,7148 ****
--- 7221,7239 ----
Can also be used as a |method|: >
GetLnum()->lispindent()
+ list2blob({list}) *list2blob()*
+ Return a Blob concatenating all the number values in {list}.
+ Examples: >
+ list2blob([1, 2, 3, 4]) returns 0z01020304
+ list2blob([]) returns 0z
+ < Returns an empty Blob on error. If one of the numbers is
+ negative or more than 255 error *E1239* is given.
+
+ |blob2list()| does the opposite.
+
+ Can also be used as a |method|: >
+ GetList()->list2blob()
+
list2str({list} [, {utf8}]) *list2str()*
Convert each number in {list} to a character string can
concatenate them all. Examples: >
*** ../vim-8.2.3437/runtime/doc/usr_41.txt 2021-08-16 21:38:38.127122597 +0200
--- runtime/doc/usr_41.txt 2021-09-14 17:39:39.273540696 +0200
***************
*** 715,720 ****
--- 723,732 ----
isinf() check for infinity
isnan() check for not a number
+ Blob manipulation: *blob-functions*
+ blob2list() get a list of numbers from a blob
+ list2blob() get a blob from a list of numbers
+
Other computation: *bitwise-function*
and() bitwise AND
invert() bitwise invert
***************
*** 1441,1446 ****
--- 1453,1460 ----
Function references are most useful in combination with a Dictionary, as is
explained in the next section.
+ More information about defining your own functions here: |user-functions|.
+
==============================================================================
*41.8* Lists and Dictionaries
*** ../vim-8.2.3437/src/blob.c 2021-08-04 19:25:50.614808524 +0200
--- src/blob.c 2021-09-14 17:42:01.405372943 +0200
***************
*** 483,486 ****
--- 483,547 ----
}
}
+ /*
+ * 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)
*** ../vim-8.2.3437/src/errors.h 2021-09-12 20:57:56.821929392 +0200
--- src/errors.h 2021-09-14 17:42:39.885327370 +0200
***************
*** 660,662 ****
--- 660,666 ----
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"));
*** ../vim-8.2.3437/src/evalfunc.c 2021-09-08 14:57:38.237188053 +0200
--- src/evalfunc.c 2021-09-14 17:39:39.273540696 +0200
***************
*** 289,294 ****
--- 289,303 ----
}
/*
+ * 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,685 ****
--- 689,695 ----
/*
* 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,1174 ****
--- 1179,1186 ----
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,1594 ****
--- 1601,1608 ----
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,
*** ../vim-8.2.3437/src/proto/
blob.pro 2021-08-04 19:25:50.614808524 +0200
--- src/proto/
blob.pro 2021-09-14 17:39:39.273540696 +0200
***************
*** 19,22 ****
--- 19,24 ----
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 : */
*** ../vim-8.2.3437/src/proto/
typval.pro 2021-07-28 11:51:44.317061732 +0200
--- src/proto/
typval.pro 2021-09-14 17:39:39.273540696 +0200
***************
*** 17,22 ****
--- 17,23 ----
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);
*** ../vim-8.2.3437/src/testdir/test_blob.vim 2021-08-04 19:25:50.618808515 +0200
--- src/testdir/test_blob.vim 2021-09-14 17:46:29.753054129 +0200
***************
*** 638,641 ****
--- 638,680 ----
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
*** ../vim-8.2.3437/src/testdir/test_vim9_builtin.vim 2021-09-11 20:20:34.011127608 +0200
--- src/testdir/test_vim9_builtin.vim 2021-09-14 17:39:39.273540696 +0200
***************
*** 287,292 ****
--- 287,296 ----
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,577 ****
--- 576,582 ----
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,791 ****
--- 791,798 ----
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,1926 ****
--- 1928,1938 ----
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]
*** ../vim-8.2.3437/src/typval.c 2021-09-13 21:36:23.737110573 +0200
--- src/typval.c 2021-09-14 17:39:39.277540692 +0200
***************
*** 471,476 ****
--- 471,493 ----
}
/*
+ * 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
*** ../vim-8.2.3437/src/version.c 2021-09-13 22:17:33.950410680 +0200
--- src/version.c 2021-09-14 17:41:02.257442880 +0200
***************
*** 757,758 ****
--- 757,760 ----
{ /* Add new patch number below this line */
+ /**/
+ 3438,
/**/
--
Q: Why do Norwegians excel at text editing?
A: Their ancestors are Vi-kings
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///