Mercurial > vim
diff src/eval.c @ 5747:ddc3f32a4b21 v7.4.218
updated for version 7.4.218
Problem: It's not easy to remove duplicates from a list.
Solution: Add the uniq() function. (LCD)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Tue, 25 Mar 2014 18:24:23 +0100 |
parents | 50dbef5e774a |
children | 839cca5ec18d |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -744,6 +744,7 @@ static void f_trunc __ARGS((typval_T *ar static void f_type __ARGS((typval_T *argvars, typval_T *rettv)); static void f_undofile __ARGS((typval_T *argvars, typval_T *rettv)); static void f_undotree __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_uniq __ARGS((typval_T *argvars, typval_T *rettv)); static void f_values __ARGS((typval_T *argvars, typval_T *rettv)); static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv)); static void f_visualmode __ARGS((typval_T *argvars, typval_T *rettv)); @@ -8150,6 +8151,7 @@ static struct fst {"type", 1, 1, f_type}, {"undofile", 1, 1, f_undofile}, {"undotree", 0, 0, f_undotree}, + {"uniq", 1, 3, f_uniq}, {"values", 1, 1, f_values}, {"virtcol", 1, 1, f_virtcol}, {"visualmode", 0, 1, f_visualmode}, @@ -17023,10 +17025,11 @@ static int item_compare_ic; static char_u *item_compare_func; static dict_T *item_compare_selfdict; static int item_compare_func_err; +static void do_sort_uniq __ARGS((typval_T *argvars, typval_T *rettv, int sort)); #define ITEM_COMPARE_FAIL 999 /* - * Compare functions for f_sort() below. + * Compare functions for f_sort() and f_uniq() below. */ static int #ifdef __BORLANDC__ @@ -17100,9 +17103,10 @@ item_compare2(s1, s2) * "sort({list})" function */ static void -f_sort(argvars, rettv) - typval_T *argvars; - typval_T *rettv; +do_sort_uniq(argvars, rettv, sort) + typval_T *argvars; + typval_T *rettv; + int sort; { list_T *l; listitem_T *li; @@ -17111,12 +17115,12 @@ f_sort(argvars, rettv) long i; if (argvars[0].v_type != VAR_LIST) - EMSG2(_(e_listarg), "sort()"); + EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); else { l = argvars[0].vval.v_list; if (l == NULL || tv_check_lock(l->lv_lock, - (char_u *)_("sort() argument"))) + (char_u *)(sort ? _("sort() argument") : _("uniq() argument")))) return; rettv->vval.v_list = l; rettv->v_type = VAR_LIST; @@ -17163,29 +17167,72 @@ f_sort(argvars, rettv) ptrs = (listitem_T **)alloc((int)(len * sizeof(listitem_T *))); if (ptrs == NULL) return; + i = 0; - for (li = l->lv_first; li != NULL; li = li->li_next) - ptrs[i++] = li; - - item_compare_func_err = FALSE; - /* test the compare function */ - if (item_compare_func != NULL - && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) + if (sort) + { + /* sort(): ptrs will be the list to sort */ + for (li = l->lv_first; li != NULL; li = li->li_next) + ptrs[i++] = li; + + item_compare_func_err = FALSE; + /* test the compare function */ + if (item_compare_func != 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(listitem_T *), + EMSG(_("E702: Sort compare function failed")); + else + { + /* Sort the array with item pointers. */ + qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *), item_compare_func == NULL ? item_compare : item_compare2); + if (!item_compare_func_err) + { + /* Clear the List and append the items in sorted order. */ + l->lv_first = l->lv_last = l->lv_idx_item = NULL; + l->lv_len = 0; + for (i = 0; i < len; ++i) + list_append(l, ptrs[i]); + } + } + } + else + { + int (*item_compare_func_ptr)__ARGS((const void *, const void *)); + + /* f_uniq(): ptrs will be a stack of items to remove */ + item_compare_func_err = FALSE; + item_compare_func_ptr = item_compare_func + ? 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++] = li; + if (item_compare_func_err) + { + EMSG(_("E882: Uniq compare function failed")); + break; + } + } + if (!item_compare_func_err) { - /* Clear the List and append the items in the sorted order. */ - l->lv_first = l->lv_last = l->lv_idx_item = NULL; - l->lv_len = 0; - for (i = 0; i < len; ++i) - list_append(l, ptrs[i]); + while (--i >= 0) + { + li = ptrs[i]->li_next; + ptrs[i]->li_next = li->li_next; + if (li->li_next != NULL) + li->li_next->li_prev = ptrs[i]; + else + l->lv_last = ptrs[i]; + list_fix_watch(l, li); + listitem_free(li); + l->lv_len--; + } } } @@ -17194,6 +17241,28 @@ f_sort(argvars, rettv) } /* + * "sort({list})" function + */ + static void +f_sort(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + do_sort_uniq(argvars, rettv, TRUE); +} + +/* + * "uniq({list})" function + */ + static void +f_uniq(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + do_sort_uniq(argvars, rettv, FALSE); +} + +/* * "soundfold({word})" function */ static void