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