forked from aniani/vim
patch 8.2.3438: cannot manipulate blobs
Problem: Cannot manipulate blobs. Solution: Add blob2list() and list2blob(). (Yegappan Lakshmanan, closes #8868)
This commit is contained in:
committed by
Bram Moolenaar
parent
f5785cf059
commit
5dfe467432
@@ -2469,6 +2469,7 @@ atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
|
|||||||
balloon_gettext() String current text in the balloon
|
balloon_gettext() String current text in the balloon
|
||||||
balloon_show({expr}) none show {expr} inside the balloon
|
balloon_show({expr}) none show {expr} inside the balloon
|
||||||
balloon_split({msg}) List split {msg} as used for a 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})
|
browse({save}, {title}, {initdir}, {default})
|
||||||
String put up a file requester
|
String put up a file requester
|
||||||
browsedir({title}, {initdir}) String put up a directory requester
|
browsedir({title}, {initdir}) String put up a directory requester
|
||||||
@@ -2721,7 +2722,8 @@ libcallnr({lib}, {func}, {arg}) Number idem, but return a Number
|
|||||||
line({expr} [, {winid}]) Number line nr of cursor, last line or mark
|
line({expr} [, {winid}]) Number line nr of cursor, last line or mark
|
||||||
line2byte({lnum}) Number byte count of line {lnum}
|
line2byte({lnum}) Number byte count of line {lnum}
|
||||||
lispindent({lnum}) Number Lisp indent for line {lnum}
|
lispindent({lnum}) Number Lisp indent for line {lnum}
|
||||||
list2str({list} [, {utf8}]) String turn numbers in {list} into a String
|
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}])
|
listener_add({callback} [, {buf}])
|
||||||
Number add a callback to listen to changes
|
Number add a callback to listen to changes
|
||||||
listener_flush([{buf}]) none invoke listener callbacks
|
listener_flush([{buf}]) none invoke listener callbacks
|
||||||
@@ -3355,6 +3357,17 @@ balloon_split({msg}) *balloon_split()*
|
|||||||
< {only available when compiled with the |+balloon_eval_term|
|
< {only available when compiled with the |+balloon_eval_term|
|
||||||
feature}
|
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()*
|
||||||
browse({save}, {title}, {initdir}, {default})
|
browse({save}, {title}, {initdir}, {default})
|
||||||
Put up a file requester. This only works when "has("browse")"
|
Put up a file requester. This only works when "has("browse")"
|
||||||
@@ -7208,6 +7221,19 @@ lispindent({lnum}) *lispindent()*
|
|||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
GetLnum()->lispindent()
|
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()*
|
list2str({list} [, {utf8}]) *list2str()*
|
||||||
Convert each number in {list} to a character string can
|
Convert each number in {list} to a character string can
|
||||||
concatenate them all. Examples: >
|
concatenate them all. Examples: >
|
||||||
|
@@ -723,6 +723,10 @@ Floating point computation: *float-functions*
|
|||||||
isinf() check for infinity
|
isinf() check for infinity
|
||||||
isnan() check for not a number
|
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*
|
Other computation: *bitwise-function*
|
||||||
and() bitwise AND
|
and() bitwise AND
|
||||||
invert() bitwise invert
|
invert() bitwise invert
|
||||||
@@ -1449,6 +1453,8 @@ is a List with arguments.
|
|||||||
Function references are most useful in combination with a Dictionary, as is
|
Function references are most useful in combination with a Dictionary, as is
|
||||||
explained in the next section.
|
explained in the next section.
|
||||||
|
|
||||||
|
More information about defining your own functions here: |user-functions|.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*41.8* Lists and Dictionaries
|
*41.8* Lists and Dictionaries
|
||||||
|
|
||||||
|
61
src/blob.c
61
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)
|
#endif // defined(FEAT_EVAL)
|
||||||
|
@@ -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 '*'"));
|
INIT(= N_("E1236: Cannot use %s itself, it is imported with '*'"));
|
||||||
EXTERN char e_no_such_user_defined_command_in_current_buffer_str[]
|
EXTERN char e_no_such_user_defined_command_in_current_buffer_str[]
|
||||||
INIT(= N_("E1237: No such user-defined command in current buffer: %s"));
|
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"));
|
||||||
|
@@ -288,6 +288,15 @@ arg_string(type_T *type, argcontext_T *context)
|
|||||||
return check_arg_type(&t_string, type, context);
|
return check_arg_type(&t_string, type, 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.
|
* Check "type" is a bool or number 0 or 1.
|
||||||
*/
|
*/
|
||||||
@@ -680,6 +689,7 @@ arg_cursor1(type_T *type, argcontext_T *context)
|
|||||||
/*
|
/*
|
||||||
* Lists of functions that check the argument types of a builtin function.
|
* 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_bool[] = {arg_bool};
|
||||||
static argcheck_T arg1_buffer[] = {arg_buffer};
|
static argcheck_T arg1_buffer[] = {arg_buffer};
|
||||||
static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any};
|
static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any};
|
||||||
@@ -1169,6 +1179,8 @@ static funcentry_T global_functions[] =
|
|||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
{"blob2list", 1, 1, FEARG_1, arg1_blob,
|
||||||
|
ret_list_number, f_blob2list},
|
||||||
{"browse", 4, 4, 0, arg4_browse,
|
{"browse", 4, 4, 0, arg4_browse,
|
||||||
ret_string, f_browse},
|
ret_string, f_browse},
|
||||||
{"browsedir", 2, 2, 0, arg2_string,
|
{"browsedir", 2, 2, 0, arg2_string,
|
||||||
@@ -1589,6 +1601,8 @@ static funcentry_T global_functions[] =
|
|||||||
ret_number, f_line2byte},
|
ret_number, f_line2byte},
|
||||||
{"lispindent", 1, 1, FEARG_1, arg1_lnum,
|
{"lispindent", 1, 1, FEARG_1, arg1_lnum,
|
||||||
ret_number, f_lispindent},
|
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,
|
{"list2str", 1, 2, FEARG_1, arg2_list_number_bool,
|
||||||
ret_string, f_list2str},
|
ret_string, f_list2str},
|
||||||
{"listener_add", 1, 2, FEARG_2, arg2_any_buffer,
|
{"listener_add", 1, 2, FEARG_2, arg2_any_buffer,
|
||||||
|
@@ -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 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);
|
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 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: set ft=c : */
|
||||||
|
@@ -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_float_or_nr_arg(typval_T *args, int idx);
|
||||||
int check_for_bool_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_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_list_arg(typval_T *args, int idx);
|
||||||
int check_for_opt_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);
|
int check_for_dict_arg(typval_T *args, int idx);
|
||||||
|
@@ -638,4 +638,43 @@ func Test_blob_sort()
|
|||||||
call CheckLegacyAndVim9Failure(['call sort([11, 0z11], "N")'], 'E974:')
|
call CheckLegacyAndVim9Failure(['call sort([11, 0z11], "N")'], 'E974:')
|
||||||
endfunc
|
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: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -287,6 +287,10 @@ def Test_balloon_split()
|
|||||||
assert_fails('balloon_split(true)', 'E1174:')
|
assert_fails('balloon_split(true)', 'E1174:')
|
||||||
enddef
|
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()
|
def Test_browse()
|
||||||
CheckFeature browse
|
CheckFeature browse
|
||||||
|
|
||||||
@@ -572,6 +576,7 @@ def Test_char2nr()
|
|||||||
assert_equal(97, char2nr('a', 0))
|
assert_equal(97, char2nr('a', 0))
|
||||||
assert_equal(97, char2nr('a', true))
|
assert_equal(97, char2nr('a', true))
|
||||||
assert_equal(97, char2nr('a', false))
|
assert_equal(97, char2nr('a', false))
|
||||||
|
char2nr('')->assert_equal(0)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_charclass()
|
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(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')
|
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", ":"))
|
assert_equal('a\:b', escape("a:b", ":"))
|
||||||
|
escape('abc', '')->assert_equal('abc')
|
||||||
|
escape('', ':')->assert_equal('')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_eval()
|
def Test_eval()
|
||||||
@@ -1921,6 +1928,11 @@ def Test_lispindent()
|
|||||||
assert_equal(0, lispindent(1))
|
assert_equal(0, lispindent(1))
|
||||||
enddef
|
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()
|
def Test_list2str_str2list_utf8()
|
||||||
var s = "\u3042\u3044"
|
var s = "\u3042\u3044"
|
||||||
var l = [0x3042, 0x3044]
|
var l = [0x3042, 0x3044]
|
||||||
|
17
src/typval.c
17
src/typval.c
@@ -470,6 +470,23 @@ check_for_opt_bool_arg(typval_T *args, int idx)
|
|||||||
return check_for_bool_arg(args, idx);
|
return check_for_bool_arg(args, 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.
|
* Give an error and return FAIL unless "args[idx]" is a list.
|
||||||
*/
|
*/
|
||||||
|
@@ -755,6 +755,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3438,
|
||||||
/**/
|
/**/
|
||||||
3437,
|
3437,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user