Patch 8.2.3867
Problem: Implementation of some list functions too complicated.
Solution: Refactor do_sort_uniq(), f_count() and extend() (Yegappan
Lakshmanan, closes #9378)
Files: src/list.c
*** ../vim-8.2.3866/src/list.c 2021-12-19 10:35:10.700109727 +0000
--- src/list.c 2021-12-21 13:15:24.697233945 +0000
***************
*** 1987,2209 ****
}
/*
! * "sort()" or "uniq()" function
*/
static void
! do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
{
- list_T *l;
- listitem_T *li;
- sortItem_T *ptrs;
- sortinfo_T *old_sortinfo;
- sortinfo_T info;
long len;
! long i;
! if (in_vim9script()
! && (check_for_list_arg(argvars, 0) == FAIL
! || (argvars[1].v_type != VAR_UNKNOWN
! && check_for_opt_dict_arg(argvars, 2) == FAIL)))
! return;
! // Pointer to current info struct used in compare function. Save and
! // restore the current one for nested calls.
! old_sortinfo = sortinfo;
! sortinfo = &info;
! if (argvars[0].v_type != VAR_LIST)
! semsg(_(e_listarg), sort ? "sort()" : "uniq()");
else
{
! l = argvars[0].vval.v_list;
! if (l != NULL && value_check_lock(l->lv_lock,
! (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
! TRUE))
! goto theend;
! rettv_list_set(rettv, l);
! if (l == NULL)
! goto theend;
! CHECK_LIST_MATERIALIZE(l);
! len = list_len(l);
! if (len <= 1)
! goto theend; // short list sorts pretty quickly
!
! info.item_compare_ic = FALSE;
! info.item_compare_lc = FALSE;
! info.item_compare_numeric = FALSE;
! info.item_compare_numbers = FALSE;
! #ifdef FEAT_FLOAT
! info.item_compare_float = FALSE;
! #endif
! info.item_compare_func = NULL;
! info.item_compare_partial = NULL;
! info.item_compare_selfdict = NULL;
! if (argvars[1].v_type != VAR_UNKNOWN)
! {
! // optional second argument: {func}
! if (argvars[1].v_type == VAR_FUNC)
! info.item_compare_func = argvars[1].vval.v_string;
! else if (argvars[1].v_type == VAR_PARTIAL)
! info.item_compare_partial = argvars[1].vval.v_partial;
else
! {
! int error = FALSE;
! int nr = 0;
! if (argvars[1].v_type == VAR_NUMBER)
! {
! nr = tv_get_number_chk(&argvars[1], &error);
! if (error)
! goto theend; // type error; errmsg already given
! if (nr == 1)
! info.item_compare_ic = TRUE;
! }
! if (nr != 1)
! {
! if (argvars[1].v_type != VAR_NUMBER)
! info.item_compare_func = tv_get_string(&argvars[1]);
! else if (nr != 0)
! {
! emsg(_(e_invarg));
! goto theend;
! }
! }
! if (info.item_compare_func != NULL)
! {
! if (*info.item_compare_func == NUL)
! {
! // empty string means default sort
! info.item_compare_func = NULL;
! }
! else if (STRCMP(info.item_compare_func, "n") == 0)
! {
! info.item_compare_func = NULL;
! info.item_compare_numeric = TRUE;
! }
! else if (STRCMP(info.item_compare_func, "N") == 0)
! {
! info.item_compare_func = NULL;
! info.item_compare_numbers = TRUE;
! }
#ifdef FEAT_FLOAT
! else if (STRCMP(info.item_compare_func, "f") == 0)
! {
! info.item_compare_func = NULL;
! info.item_compare_float = TRUE;
! }
#endif
! else if (STRCMP(info.item_compare_func, "i") == 0)
! {
! info.item_compare_func = NULL;
! info.item_compare_ic = TRUE;
! }
! else if (STRCMP(info.item_compare_func, "l") == 0)
! {
! info.item_compare_func = NULL;
! info.item_compare_lc = TRUE;
! }
! }
! }
! if (argvars[2].v_type != VAR_UNKNOWN)
{
! // optional third argument: {dict}
! if (argvars[2].v_type != VAR_DICT)
! {
! emsg(_(e_dictreq));
! goto theend;
! }
! info.item_compare_selfdict = argvars[2].vval.v_dict;
}
}
!
! // Make an array with each entry pointing to an item in the List.
! ptrs = ALLOC_MULT(sortItem_T, len);
! if (ptrs == NULL)
! goto theend;
!
! i = 0;
! if (sort)
{
! // sort(): ptrs will be the list to sort
! FOR_ALL_LIST_ITEMS(l, li)
{
! ptrs[i].item = li;
! ptrs[i].idx = i;
! ++i;
! }
!
! info.item_compare_func_err = FALSE;
! info.item_compare_keep_zero = FALSE;
! // test the compare function
! if ((info.item_compare_func != NULL
! || info.item_compare_partial != NULL)
! && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
! == ITEM_COMPARE_FAIL)
! emsg(_("E702: Sort compare function failed"));
! else
{
! // Sort the array with item pointers.
! qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
! info.item_compare_func == NULL
! && info.item_compare_partial == NULL
! ? item_compare : item_compare2);
!
! if (!info.item_compare_func_err)
! {
! // Clear the List and append the items in sorted order.
! l->lv_first = l->lv_u.mat.lv_last
! = l->lv_u.mat.lv_idx_item = NULL;
! l->lv_len = 0;
! for (i = 0; i < len; ++i)
! list_append(l, ptrs[i].item);
! }
}
! }
! else
! {
! int (*item_compare_func_ptr)(const void *, const void *);
!
! // f_uniq(): ptrs will be a stack of items to remove
! info.item_compare_func_err = FALSE;
! info.item_compare_keep_zero = TRUE;
! item_compare_func_ptr = info.item_compare_func != NULL
! || info.item_compare_partial != NULL
! ? item_compare2 : item_compare;
!
! for (li = l->lv_first; li != NULL && li->li_next != NULL;
! li = li->li_next)
! {
! if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
! == 0)
! ptrs[i++].item = li;
! if (info.item_compare_func_err)
! {
! emsg(_("E882: Uniq compare function failed"));
! break;
! }
}
!
! if (!info.item_compare_func_err)
{
! while (--i >= 0)
! {
! li = ptrs[i].item->li_next;
! ptrs[i].item->li_next = li->li_next;
! if (li->li_next != NULL)
! li->li_next->li_prev = ptrs[i].item;
! else
! l->lv_u.mat.lv_last = ptrs[i].item;
! list_fix_watch(l, li);
! listitem_free(l, li);
! l->lv_len--;
! }
}
}
! vim_free(ptrs);
}
theend:
sortinfo = old_sortinfo;
}
--- 1987,2255 ----
}
/*
! * sort() List "l"
*/
static void
! do_sort(list_T *l, sortinfo_T *info)
{
long len;
! sortItem_T *ptrs;
! long i = 0;
! listitem_T *li;
! len = list_len(l);
! // Make an array with each entry pointing to an item in the List.
! ptrs = ALLOC_MULT(sortItem_T, len);
! if (ptrs == NULL)
! return;
! // sort(): ptrs will be the list to sort
! FOR_ALL_LIST_ITEMS(l, li)
! {
! ptrs[i].item = li;
! ptrs[i].idx = i;
! ++i;
! }
!
! info->item_compare_func_err = FALSE;
! info->item_compare_keep_zero = FALSE;
! // test the compare function
! if ((info->item_compare_func != NULL
! || info->item_compare_partial != NULL)
! && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
! == ITEM_COMPARE_FAIL)
! emsg(_("E702: Sort compare function failed"));
else
{
! // Sort the array with item pointers.
! qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
! info->item_compare_func == NULL
! && info->item_compare_partial == NULL
! ? item_compare : item_compare2);
!
! if (!info->item_compare_func_err)
! {
! // Clear the List and append the items in sorted order.
! l->lv_first = l->lv_u.mat.lv_last
! = l->lv_u.mat.lv_idx_item = NULL;
! l->lv_len = 0;
! for (i = 0; i < len; ++i)
! list_append(l, ptrs[i].item);
! }
! }
! vim_free(ptrs);
! }
!
! /*
! * uniq() List "l"
! */
! static void
! do_uniq(list_T *l, sortinfo_T *info)
! {
! long len;
! sortItem_T *ptrs;
! long i = 0;
! listitem_T *li;
! int (*item_compare_func_ptr)(const void *, const void *);
!
! len = list_len(l);
!
! // Make an array with each entry pointing to an item in the List.
! ptrs = ALLOC_MULT(sortItem_T, len);
! if (ptrs == NULL)
! return;
!
! // f_uniq(): ptrs will be a stack of items to remove
! info->item_compare_func_err = FALSE;
! info->item_compare_keep_zero = TRUE;
! item_compare_func_ptr = info->item_compare_func != NULL
! || info->item_compare_partial != NULL
! ? item_compare2 : item_compare;
!
! for (li = l->lv_first; li != NULL && li->li_next != NULL;
! li = li->li_next)
! {
! if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
! == 0)
! ptrs[i++].item = li;
! if (info->item_compare_func_err)
! {
! emsg(_("E882: Uniq compare function failed"));
! break;
! }
! }
!
! if (!info->item_compare_func_err)
! {
! while (--i >= 0)
! {
! li = ptrs[i].item->li_next;
! ptrs[i].item->li_next = li->li_next;
! if (li->li_next != NULL)
! li->li_next->li_prev = ptrs[i].item;
else
! l->lv_u.mat.lv_last = ptrs[i].item;
! list_fix_watch(l, li);
! listitem_free(l, li);
! l->lv_len--;
! }
! }
! vim_free(ptrs);
! }
!
! /*
! * Parse the optional arguments to sort() and uniq() and return the values in
! * 'info'.
! */
! static int
! parse_sort_uniq_args(typval_T *argvars, sortinfo_T *info)
! {
! info->item_compare_ic = FALSE;
! info->item_compare_lc = FALSE;
! info->item_compare_numeric = FALSE;
! info->item_compare_numbers = FALSE;
#ifdef FEAT_FLOAT
! info->item_compare_float = FALSE;
#endif
! info->item_compare_func = NULL;
! info->item_compare_partial = NULL;
! info->item_compare_selfdict = NULL;
!
! if (argvars[1].v_type == VAR_UNKNOWN)
! return OK;
!
! // optional second argument: {func}
! if (argvars[1].v_type == VAR_FUNC)
! info->item_compare_func = argvars[1].vval.v_string;
! else if (argvars[1].v_type == VAR_PARTIAL)
! info->item_compare_partial = argvars[1].vval.v_partial;
! else
! {
! int error = FALSE;
! int nr = 0;
! if (argvars[1].v_type == VAR_NUMBER)
! {
! nr = tv_get_number_chk(&argvars[1], &error);
! if (error)
! return FAIL;
! if (nr == 1)
! info->item_compare_ic = TRUE;
! }
! if (nr != 1)
! {
! if (argvars[1].v_type != VAR_NUMBER)
! info->item_compare_func = tv_get_string(&argvars[1]);
! else if (nr != 0)
{
! emsg(_(e_invarg));
! return FAIL;
}
}
! if (info->item_compare_func != NULL)
{
! if (*info->item_compare_func == NUL)
{
! // empty string means default sort
! info->item_compare_func = NULL;
! }
! else if (STRCMP(info->item_compare_func, "n") == 0)
{
! info->item_compare_func = NULL;
! info->item_compare_numeric = TRUE;
}
! else if (STRCMP(info->item_compare_func, "N") == 0)
! {
! info->item_compare_func = NULL;
! info->item_compare_numbers = TRUE;
}
! #ifdef FEAT_FLOAT
! else if (STRCMP(info->item_compare_func, "f") == 0)
{
! info->item_compare_func = NULL;
! info->item_compare_float = TRUE;
! }
! #endif
! else if (STRCMP(info->item_compare_func, "i") == 0)
! {
! info->item_compare_func = NULL;
! info->item_compare_ic = TRUE;
! }
! else if (STRCMP(info->item_compare_func, "l") == 0)
! {
! info->item_compare_func = NULL;
! info->item_compare_lc = TRUE;
}
}
+ }
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ // optional third argument: {dict}
+ if (argvars[2].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return FAIL;
+ }
+ info->item_compare_selfdict = argvars[2].vval.v_dict;
+ }
+
+ return OK;
+ }
+
+ /*
+ * "sort()" or "uniq()" function
+ */
+ static void
+ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
+ {
+ list_T *l;
+ sortinfo_T *old_sortinfo;
+ sortinfo_T info;
+ long len;
+
+ if (in_vim9script()
+ && (check_for_list_arg(argvars, 0) == FAIL
+ || (argvars[1].v_type != VAR_UNKNOWN
+ && check_for_opt_dict_arg(argvars, 2) == FAIL)))
+ return;
! if (argvars[0].v_type != VAR_LIST)
! {
! semsg(_(e_listarg), sort ? "sort()" : "uniq()");
! return;
}
+
+ // Pointer to current info struct used in compare function. Save and
+ // restore the current one for nested calls.
+ old_sortinfo = sortinfo;
+ sortinfo = &info;
+
+ l = argvars[0].vval.v_list;
+ if (l != NULL && value_check_lock(l->lv_lock,
+ (char_u *)(sort ? N_("sort() argument") : N_("uniq()
argument")),
+ TRUE))
+ goto theend;
+ rettv_list_set(rettv, l);
+ if (l == NULL)
+ goto theend;
+ CHECK_LIST_MATERIALIZE(l);
+
+ len = list_len(l);
+ if (len <= 1)
+ goto theend; // short list sorts pretty quickly
+
+ if (parse_sort_uniq_args(argvars, &info) == FAIL)
+ goto theend;
+
+ if (sort)
+ do_sort(l, &info);
+ else
+ do_uniq(l, &info);
+
theend:
sortinfo = old_sortinfo;
}
***************
*** 2835,2840 ****
--- 2881,2985 ----
}
/*
+ * Count the number of times "needle" occurs in string "haystack". Case is
+ * ignored if "ic" is TRUE.
+ */
+ static long
+ count_string(char_u *haystack, char_u *needle, int ic)
+ {
+ long n = 0;
+ char_u *p = haystack;
+ char_u *next;
+
+ if (p == NULL || needle == NULL || *needle == NUL)
+ return 0;
+
+ if (ic)
+ {
+ size_t len = STRLEN(needle);
+
+ while (*p != NUL)
+ {
+ if (MB_STRNICMP(p, needle, len) == 0)
+ {
+ ++n;
+ p += len;
+ }
+ else
+ MB_PTR_ADV(p);
+ }
+ }
+ else
+ while ((next = (char_u *)strstr((char *)p, (char *)needle)) != NULL)
+ {
+ ++n;
+ p = next + STRLEN(needle);
+ }
+
+ return n;
+ }
+
+ /*
+ * Count the number of times item "needle" occurs in List "l" starting at
index
+ * "idx". Case is ignored if "ic" is TRUE.
+ */
+ static long
+ count_list(list_T *l, typval_T *needle, long idx, int ic)
+ {
+ long n = 0;
+ listitem_T *li;
+
+ if (l == NULL)
+ return 0;
+
+ CHECK_LIST_MATERIALIZE(l);
+
+ if (list_len(l) == 0)
+ return 0;
+
+ li = list_find(l, idx);
+ if (li == NULL)
+ {
+ semsg(_(e_listidx), idx);
+ return 0;
+ }
+
+ for ( ; li != NULL; li = li->li_next)
+ if (tv_equal(&li->li_tv, needle, ic, FALSE))
+ ++n;
+
+ return n;
+ }
+
+ /*
+ * Count the number of times item "needle" occurs in Dict "d". Case is ignored
+ * if "ic" is TRUE.
+ */
+ static long
+ count_dict(dict_T *d, typval_T *needle, int ic)
+ {
+ int todo;
+ hashitem_T *hi;
+ long n = 0;
+
+ if (d == NULL)
+ return 0;
+
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ if (tv_equal(&HI2DI(hi)->di_tv, needle, ic, FALSE))
+ ++n;
+ }
+ }
+
+ return n;
+ }
+
+ /*
* "count()" function
*/
void
***************
*** 2854,2952 ****
if (argvars[2].v_type != VAR_UNKNOWN)
ic = (int)tv_get_bool_chk(&argvars[2], &error);
! if (argvars[0].v_type == VAR_STRING)
! {
! char_u *expr = tv_get_string_chk(&argvars[1]);
! char_u *p = argvars[0].vval.v_string;
! char_u *next;
!
! if (!error && expr != NULL && *expr != NUL && p != NULL)
! {
! if (ic)
! {
! size_t len = STRLEN(expr);
! while (*p != NUL)
! {
! if (MB_STRNICMP(p, expr, len) == 0)
! {
! ++n;
! p += len;
! }
! else
! MB_PTR_ADV(p);
! }
! }
! else
! while ((next = (char_u *)strstr((char *)p, (char *)expr))
! != NULL)
! {
! ++n;
! p = next + STRLEN(expr);
! }
! }
}
! else if (argvars[0].v_type == VAR_LIST)
{
! listitem_T *li;
! list_T *l;
! long idx;
! if ((l = argvars[0].vval.v_list) != NULL)
{
! CHECK_LIST_MATERIALIZE(l);
! li = l->lv_first;
! if (argvars[2].v_type != VAR_UNKNOWN)
{
! if (argvars[3].v_type != VAR_UNKNOWN)
{
! idx = (long)tv_get_number_chk(&argvars[3], &error);
! if (!error)
! {
! li = list_find(l, idx);
! if (li == NULL)
! semsg(_(e_listidx), idx);
! }
}
- if (error)
- li = NULL;
}
! for ( ; li != NULL; li = li->li_next)
! if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
! ++n;
}
}
! else if (argvars[0].v_type == VAR_DICT)
{
! int todo;
! dict_T *d;
! hashitem_T *hi;
! if ((d = argvars[0].vval.v_dict) != NULL)
{
! if (argvars[2].v_type != VAR_UNKNOWN)
! {
! if (argvars[3].v_type != VAR_UNKNOWN)
! emsg(_(e_invarg));
! }
! todo = error ? 0 : (int)d->dv_hashtab.ht_used;
! for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
{
! if (!HASHITEM_EMPTY(hi))
! {
! --todo;
! if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
! ++n;
! }
}
}
}
- else
- semsg(_(e_listdictarg), "count()");
- rettv->vval.v_number = n;
}
/*
--- 2999,3170 ----
if (argvars[2].v_type != VAR_UNKNOWN)
ic = (int)tv_get_bool_chk(&argvars[2], &error);
! if (!error && argvars[0].v_type == VAR_STRING)
! n = count_string(argvars[0].vval.v_string,
! tv_get_string_chk(&argvars[1]), ic);
! else if (!error && argvars[0].v_type == VAR_LIST)
! {
! long idx = 0;
!
! if (argvars[2].v_type != VAR_UNKNOWN
! && argvars[3].v_type != VAR_UNKNOWN)
! idx = (long)tv_get_number_chk(&argvars[3], &error);
! if (!error)
! n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic);
! }
! else if (!error && argvars[0].v_type == VAR_DICT)
! {
! if (argvars[2].v_type != VAR_UNKNOWN
! && argvars[3].v_type != VAR_UNKNOWN)
! emsg(_(e_invarg));
! else
! n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic);
! }
! else
! semsg(_(e_listdictarg), "count()");
! rettv->vval.v_number = n;
! }
! /*
! * extend() a List. Append List argvars[1] to List argvars[0] before index
! * argvars[3] and return the resulting list in "rettv". "is_new" is TRUE for
! * extendnew().
! */
! static void
! extend_list(
! typval_T *argvars,
! type_T *type,
! char *func_name,
! char_u *arg_errmsg,
! int is_new,
! typval_T *rettv)
! {
! list_T *l1, *l2;
! listitem_T *item;
! long before;
! int error = FALSE;
+ l1 = argvars[0].vval.v_list;
+ if (l1 == NULL)
+ {
+ emsg(_(e_cannot_extend_null_list));
+ return;
}
! l2 = argvars[1].vval.v_list;
! if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE))
! && l2 != NULL)
{
! if (is_new)
! {
! l1 = list_copy(l1, FALSE, get_copyID());
! if (l1 == NULL)
! return;
! }
! if (argvars[2].v_type != VAR_UNKNOWN)
{
! before = (long)tv_get_number_chk(&argvars[2], &error);
! if (error)
! return; // type error; errmsg already given
!
! if (before == l1->lv_len)
! item = NULL;
! else
{
! item = list_find(l1, before);
! if (item == NULL)
{
! semsg(_(e_listidx), before);
! return;
}
}
+ }
+ else
+ item = NULL;
+ if (type != NULL && check_typval_arg_type(
+ type, &argvars[1], func_name, 2) == FAIL)
+ return;
+ list_extend(l1, l2, item);
! if (is_new)
! {
! rettv->v_type = VAR_LIST;
! rettv->vval.v_list = l1;
! rettv->v_lock = FALSE;
}
+ else
+ copy_tv(&argvars[0], rettv);
}
! }
!
! /*
! * extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
! * resulting Dict in "rettv". "is_new" is TRUE for extendnew().
! */
! static void
! extend_dict(
! typval_T *argvars,
! type_T *type,
! char *func_name,
! char_u *arg_errmsg,
! int is_new,
! typval_T *rettv)
! {
! dict_T *d1, *d2;
! char_u *action;
! int i;
!
! d1 = argvars[0].vval.v_dict;
! if (d1 == NULL)
! {
! emsg(_(e_cannot_extend_null_dict));
! return;
! }
! d2 = argvars[1].vval.v_dict;
! if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
! && d2 != NULL)
{
! if (is_new)
! {
! d1 = dict_copy(d1, FALSE, get_copyID());
! if (d1 == NULL)
! return;
! }
! // Check the third argument.
! if (argvars[2].v_type != VAR_UNKNOWN)
{
! static char *(av[]) = {"keep", "force", "error"};
! action = tv_get_string_chk(&argvars[2]);
! if (action == NULL)
! return;
! for (i = 0; i < 3; ++i)
! if (STRCMP(action, av[i]) == 0)
! break;
! if (i == 3)
{
! semsg(_(e_invarg2), action);
! return;
}
}
+ else
+ action = (char_u *)"force";
+
+ if (type != NULL && check_typval_arg_type(type, &argvars[1],
+ func_name, 2) == FAIL)
+ return;
+ dict_extend(d1, d2, action, func_name);
+
+ if (is_new)
+ {
+ rettv->v_type = VAR_DICT;
+ rettv->vval.v_dict = d1;
+ rettv->v_lock = FALSE;
+ }
+ else
+ copy_tv(&argvars[0], rettv);
}
}
/*
***************
*** 2967,3092 ****
}
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
! {
! list_T *l1, *l2;
! listitem_T *item;
! long before;
! int error = FALSE;
!
! l1 = argvars[0].vval.v_list;
! if (l1 == NULL)
! {
! emsg(_(e_cannot_extend_null_list));
! goto theend;
! }
! l2 = argvars[1].vval.v_list;
! if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE))
! && l2 != NULL)
! {
! if (is_new)
! {
! l1 = list_copy(l1, FALSE, get_copyID());
! if (l1 == NULL)
! goto theend;
! }
!
! if (argvars[2].v_type != VAR_UNKNOWN)
! {
! before = (long)tv_get_number_chk(&argvars[2], &error);
! if (error)
! goto theend; // type error; errmsg already given
!
! if (before == l1->lv_len)
! item = NULL;
! else
! {
! item = list_find(l1, before);
! if (item == NULL)
! {
! semsg(_(e_listidx), before);
! goto theend;
! }
! }
! }
! else
! item = NULL;
! if (type != NULL && check_typval_arg_type(
! type, &argvars[1], func_name, 2) == FAIL)
! goto theend;
! list_extend(l1, l2, item);
!
! if (is_new)
! {
! rettv->v_type = VAR_LIST;
! rettv->vval.v_list = l1;
! rettv->v_lock = FALSE;
! }
! else
! copy_tv(&argvars[0], rettv);
! }
! }
else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
! {
! dict_T *d1, *d2;
! char_u *action;
! int i;
!
! d1 = argvars[0].vval.v_dict;
! if (d1 == NULL)
! {
! emsg(_(e_cannot_extend_null_dict));
! goto theend;
! }
! d2 = argvars[1].vval.v_dict;
! if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
! && d2 != NULL)
! {
! if (is_new)
! {
! d1 = dict_copy(d1, FALSE, get_copyID());
! if (d1 == NULL)
! goto theend;
! }
!
! // Check the third argument.
! if (argvars[2].v_type != VAR_UNKNOWN)
! {
! static char *(av[]) = {"keep", "force", "error"};
!
! action = tv_get_string_chk(&argvars[2]);
! if (action == NULL)
! goto theend; // type error; errmsg already given
! for (i = 0; i < 3; ++i)
! if (STRCMP(action, av[i]) == 0)
! break;
! if (i == 3)
! {
! semsg(_(e_invarg2), action);
! goto theend;
! }
! }
! else
! action = (char_u *)"force";
!
! if (type != NULL && check_typval_arg_type(type, &argvars[1],
! func_name, 2) == FAIL)
! goto theend;
! dict_extend(d1, d2, action, func_name);
!
! if (is_new)
! {
! rettv->v_type = VAR_DICT;
! rettv->vval.v_dict = d1;
! rettv->v_lock = FALSE;
! }
! else
! copy_tv(&argvars[0], rettv);
! }
! }
else
semsg(_(e_listdictarg), func_name);
- theend:
if (type != NULL)
clear_type_list(&type_list);
}
--- 3185,3196 ----
}
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
! extend_list(argvars, type, func_name, arg_errmsg, is_new, rettv);
else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
! extend_dict(argvars, type, func_name, arg_errmsg, is_new, rettv);
else
semsg(_(e_listdictarg), func_name);
if (type != NULL)
clear_type_list(&type_list);
}
***************
*** 3308,3314 ****
}
/*
! * reduce() on a List
*/
static void
reduce_list(
--- 3412,3420 ----
}
/*
! * reduce() List argvars[0] using the function 'funcname' with arguments in
! * 'funcexe' starting with the initial value argvars[2] and return the result
! * in 'rettv'.
*/
static void
reduce_list(
***************
*** 3365,3371 ****
}
/*
! * reduce() on a String
*/
static void
reduce_string(
--- 3471,3479 ----
}
/*
! * reduce() String argvars[0] using the function 'funcname' with arguments in
! * 'funcexe' starting with the initial value argvars[2] and return the result
! * in 'rettv'.
*/
static void
reduce_string(
***************
*** 3414,3420 ****
}
/*
! * reduce() on a Blob
*/
static void
reduce_blob(
--- 3522,3530 ----
}
/*
! * reduce() Blob argvars[0] using the function 'funcname' with arguments in
! * 'funcexe' starting with the initial value argvars[2] and return the result
! * in 'rettv'.
*/
static void
reduce_blob(
***************
*** 3470,3475 ****
--- 3580,3587 ----
/*
* "reduce(list, { accumulator, element -> value } [, initial])" function
+ * "reduce(blob, { accumulator, element -> value } [, initial])"
+ * "reduce(string, { accumulator, element -> value } [, initial])"
*/
void
f_reduce(typval_T *argvars, typval_T *rettv)
*** ../vim-8.2.3866/src/version.c 2021-12-21 12:32:13.300529985 +0000
--- src/version.c 2021-12-21 13:10:18.677101619 +0000
***************
*** 751,752 ****
--- 751,754 ----
{ /* Add new patch number below this line */
+ /**/
+ 3867,
/**/
--
How many light bulbs does it take to change a person?
/// 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/20211221132020.EB1211C0DCA%40moolenaar.net.