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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202109141555.18EFtLPk1426997%40masaka.moolenaar.net.

Raspunde prin e-mail lui