mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.3438: cannot manipulate blobs
Problem: Cannot manipulate blobs.
Solution: Add blob2list() and list2blob(). (Yegappan Lakshmanan,
closes vim/vim#8868)
5dfe467432
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
3f381f4d04
commit
f6b9791212
@ -55,6 +55,7 @@ assert_report({msg}) Number report a test failure
|
|||||||
assert_true({actual} [, {msg}]) Number assert {actual} is true
|
assert_true({actual} [, {msg}]) Number assert {actual} is true
|
||||||
atan({expr}) Float arc tangent of {expr}
|
atan({expr}) Float arc tangent of {expr}
|
||||||
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
|
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
|
||||||
|
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
|
||||||
@ -296,7 +297,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
|
||||||
localtime() Number current time
|
localtime() Number current time
|
||||||
log({expr}) Float natural logarithm (base e) of {expr}
|
log({expr}) Float natural logarithm (base e) of {expr}
|
||||||
log10({expr}) Float logarithm of Float {expr} to base 10
|
log10({expr}) Float logarithm of Float {expr} to base 10
|
||||||
@ -777,6 +779,17 @@ atan2({expr1}, {expr2}) *atan2()*
|
|||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
Compute()->atan2(1)
|
Compute()->atan2(1)
|
||||||
|
|
||||||
|
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")"
|
||||||
@ -4768,6 +4781,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: >
|
||||||
|
@ -721,6 +721,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
|
||||||
@ -1321,6 +1325,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
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ return {
|
|||||||
assert_true={args={1, 2}, base=1},
|
assert_true={args={1, 2}, base=1},
|
||||||
atan={args=1, base=1, float_func="atan"},
|
atan={args=1, base=1, float_func="atan"},
|
||||||
atan2={args=2, base=1},
|
atan2={args=2, base=1},
|
||||||
|
blob2list={args=1, base=1},
|
||||||
browse={args=4},
|
browse={args=4},
|
||||||
browsedir={args=2},
|
browsedir={args=2},
|
||||||
bufadd={args=1, base=1},
|
bufadd={args=1, base=1},
|
||||||
@ -249,6 +250,7 @@ return {
|
|||||||
line={args={1, 2}, base=1},
|
line={args={1, 2}, base=1},
|
||||||
line2byte={args=1, base=1},
|
line2byte={args=1, base=1},
|
||||||
lispindent={args=1, base=1},
|
lispindent={args=1, base=1},
|
||||||
|
list2blob={args=1, base=1},
|
||||||
list2str={args={1, 2}, base=1},
|
list2str={args={1, 2}, base=1},
|
||||||
localtime={},
|
localtime={},
|
||||||
log={args=1, base=1, float_func="log"},
|
log={args=1, base=1, float_func="log"},
|
||||||
|
@ -48,10 +48,16 @@ static char e_dict_required_for_argument_nr[]
|
|||||||
= N_("E1206: Dictionary required for argument %d");
|
= N_("E1206: Dictionary required for argument %d");
|
||||||
static char e_number_required_for_argument_nr[]
|
static char e_number_required_for_argument_nr[]
|
||||||
= N_("E1210: Number required for argument %d");
|
= 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[]
|
static char e_string_or_list_required_for_argument_nr[]
|
||||||
= N_("E1222: String or List required for argument %d");
|
= N_("E1222: String or List required for argument %d");
|
||||||
static char e_list_or_blob_required_for_argument_nr[]
|
static char e_list_or_blob_required_for_argument_nr[]
|
||||||
= N_("E1226: List or Blob required for argument %d");
|
= 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[]
|
static char e_string_or_function_required_for_argument_nr[]
|
||||||
= N_("E1256: String or function required for argument %d");
|
= 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
|
//{{{1 Generic typval operations
|
||||||
//{{{2 Init/alloc/clear
|
//{{{2 Init/alloc/clear
|
||||||
//{{{3 Alloc
|
//{{{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;
|
|| 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.
|
/// 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)
|
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
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
||||||
|
@ -666,6 +666,45 @@ 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(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],
|
||||||
|
\ [[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(v:_null_list))
|
||||||
|
endfunc
|
||||||
|
|
||||||
" The following used to cause an out-of-bounds memory access
|
" The following used to cause an out-of-bounds memory access
|
||||||
func Test_blob2string()
|
func Test_blob2string()
|
||||||
let v = '0z' .. repeat('01010101.', 444)
|
let v = '0z' .. repeat('01010101.', 444)
|
||||||
|
Loading…
Reference in New Issue
Block a user