diff options
author | rbtnn <naru123456789@gmail.com> | 2021-12-18 18:33:46 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-12-18 18:33:46 +0000 |
commit | 0ccb5842f5fb103763d106c7aa364d758343c35a (patch) | |
tree | 76ea36f2abf5035e3695132e0cc5b59e2e9a325c /src/list.c | |
parent | 605ec91e5a7330d61be313637e495fa02a6dc264 (diff) | |
download | vim-git-0ccb5842f5fb103763d106c7aa364d758343c35a.tar.gz |
patch 8.2.3848: cannot use reduce() for a stringv8.2.3848
Problem: Cannot use reduce() for a string.
Solution: Make reduce() work with a string. (Naruhiko Nishino, closes #9366)
Diffstat (limited to 'src/list.c')
-rw-r--r-- | src/list.c | 88 |
1 files changed, 71 insertions, 17 deletions
diff --git a/src/list.c b/src/list.c index fafe4655a..484be8331 100644 --- a/src/list.c +++ b/src/list.c @@ -314,6 +314,28 @@ listitem_alloc(void) } /* + * Make a typval_T of the first character of "input" and store it in "output". + * Return OK or FAIL. + */ + static int +tv_get_first_char(char_u *input, typval_T *output) +{ + char_u buf[MB_MAXBYTES + 1]; + int len; + + if (input == NULL || output == NULL) + return FAIL; + + len = has_mbyte ? mb_ptr2len(input) : 1; + STRNCPY(buf, input, len); + buf[len] = NUL; + output->v_type = VAR_STRING; + output->vval.v_string = vim_strsave(buf); + + return output->vval.v_string == NULL ? FAIL : OK; +} + +/* * Free a list item, unless it was allocated together with the list itself. * Does not clear the value. Does not notify watchers. */ @@ -2492,7 +2514,6 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap) char_u *p; typval_T tv; garray_T ga; - char_u buf[MB_MAXBYTES + 1]; int len; // set_vim_var_nr() doesn't set the type @@ -2503,16 +2524,9 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap) { typval_T newtv; - if (has_mbyte) - len = mb_ptr2len(p); - else - len = 1; - - STRNCPY(buf, p, len); - buf[len] = NUL; - - tv.v_type = VAR_STRING; - tv.vval.v_string = vim_strsave(buf); + if (tv_get_first_char(p, &tv) == FAIL) + break; + len = STRLEN(tv.vval.v_string); set_vim_var_nr(VV_KEY, idx); if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL @@ -3248,12 +3262,17 @@ f_reduce(typval_T *argvars, typval_T *rettv) partial_T *partial = NULL; funcexe_T funcexe; typval_T argv[3]; + int r; + int called_emsg_start = called_emsg; - if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) - { - emsg(_(e_listblobreq)); + if (in_vim9script() + && check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL) return; - } + + if (argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_LIST + && argvars[0].v_type != VAR_BLOB) + semsg(_(e_string_list_or_blob_required), "reduce()"); if (argvars[1].v_type == VAR_FUNC) func_name = argvars[1].vval.v_string; @@ -3278,8 +3297,6 @@ f_reduce(typval_T *argvars, typval_T *rettv) { list_T *l = argvars[0].vval.v_list; listitem_T *li = NULL; - int r; - int called_emsg_start = called_emsg; if (l != NULL) CHECK_LIST_MATERIALIZE(l); @@ -3319,6 +3336,43 @@ f_reduce(typval_T *argvars, typval_T *rettv) l->lv_lock = prev_locked; } } + else if (argvars[0].v_type == VAR_STRING) + { + char_u *p = tv_get_string(&argvars[0]); + int len; + + if (argvars[2].v_type == VAR_UNKNOWN) + { + if (*p == NUL) + { + semsg(_(e_reduceempty), "String"); + return; + } + if (tv_get_first_char(p, rettv) == FAIL) + return; + p += STRLEN(rettv->vval.v_string); + } + else if (argvars[2].v_type != VAR_STRING) + { + semsg(_(e_string_expected_for_argument_nr), 3); + return; + } + else + copy_tv(&argvars[2], rettv); + + for ( ; *p != NUL; p += len) + { + argv[0] = *rettv; + if (tv_get_first_char(p, &argv[1]) == FAIL) + break; + len = STRLEN(argv[1].vval.v_string); + r = call_func(func_name, -1, rettv, 2, argv, &funcexe); + clear_tv(&argv[0]); + clear_tv(&argv[1]); + if (r == FAIL || called_emsg != called_emsg_start) + break; + } + } else { blob_T *b = argvars[0].vval.v_blob; |