Patch 7.4.1394
Problem:    Can't sort inside a sort function.
Solution:   Use a struct to store the sort parameters. (Jacob Niehus)
Files:      src/eval.c, src/testdir/test_sort.vim


*** ../vim-7.4.1393/src/eval.c  2016-02-22 21:48:26.813500402 +0100
--- src/eval.c  2016-02-22 22:48:37.471519676 +0100
***************
*** 18790,18805 ****
      int               idx;
  } sortItem_T;
  
! static int    item_compare_ic;
! static int    item_compare_numeric;
! static int    item_compare_numbers;
  #ifdef FEAT_FLOAT
! static int    item_compare_float;
  #endif
! static char_u *item_compare_func;
! static dict_T *item_compare_selfdict;
! static int    item_compare_func_err;
! static int    item_compare_keep_zero;
  static void   do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
  #define ITEM_COMPARE_FAIL 999
  
--- 18790,18810 ----
      int               idx;
  } sortItem_T;
  
! /* struct storing information about current sort */
! typedef struct
! {
!     int               item_compare_ic;
!     int               item_compare_numeric;
!     int               item_compare_numbers;
  #ifdef FEAT_FLOAT
!     int               item_compare_float;
  #endif
!     char_u    *item_compare_func;
!     dict_T    *item_compare_selfdict;
!     int               item_compare_func_err;
!     int               item_compare_keep_zero;
! } sortinfo_T;
! static sortinfo_T     *sortinfo = NULL;
  static void   do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
  #define ITEM_COMPARE_FAIL 999
  
***************
*** 18825,18831 ****
      tv1 = &si1->item->li_tv;
      tv2 = &si2->item->li_tv;
  
!     if (item_compare_numbers)
      {
        long    v1 = get_tv_number(tv1);
        long    v2 = get_tv_number(tv2);
--- 18830,18836 ----
      tv1 = &si1->item->li_tv;
      tv2 = &si2->item->li_tv;
  
!     if (sortinfo->item_compare_numbers)
      {
        long    v1 = get_tv_number(tv1);
        long    v2 = get_tv_number(tv2);
***************
*** 18834,18840 ****
      }
  
  #ifdef FEAT_FLOAT
!     if (item_compare_float)
      {
        float_T v1 = get_tv_float(tv1);
        float_T v2 = get_tv_float(tv2);
--- 18839,18845 ----
      }
  
  #ifdef FEAT_FLOAT
!     if (sortinfo->item_compare_float)
      {
        float_T v1 = get_tv_float(tv1);
        float_T v2 = get_tv_float(tv2);
***************
*** 18848,18854 ****
       * non-string to do what the docs promise. */
      if (tv1->v_type == VAR_STRING)
      {
!       if (tv2->v_type != VAR_STRING || item_compare_numeric)
            p1 = (char_u *)"'";
        else
            p1 = tv1->vval.v_string;
--- 18853,18859 ----
       * non-string to do what the docs promise. */
      if (tv1->v_type == VAR_STRING)
      {
!       if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
            p1 = (char_u *)"'";
        else
            p1 = tv1->vval.v_string;
***************
*** 18857,18863 ****
        p1 = tv2string(tv1, &tofree1, numbuf1, 0);
      if (tv2->v_type == VAR_STRING)
      {
!       if (tv1->v_type != VAR_STRING || item_compare_numeric)
            p2 = (char_u *)"'";
        else
            p2 = tv2->vval.v_string;
--- 18862,18868 ----
        p1 = tv2string(tv1, &tofree1, numbuf1, 0);
      if (tv2->v_type == VAR_STRING)
      {
!       if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
            p2 = (char_u *)"'";
        else
            p2 = tv2->vval.v_string;
***************
*** 18868,18876 ****
        p1 = (char_u *)"";
      if (p2 == NULL)
        p2 = (char_u *)"";
!     if (!item_compare_numeric)
      {
!       if (item_compare_ic)
            res = STRICMP(p1, p2);
        else
            res = STRCMP(p1, p2);
--- 18873,18881 ----
        p1 = (char_u *)"";
      if (p2 == NULL)
        p2 = (char_u *)"";
!     if (!sortinfo->item_compare_numeric)
      {
!       if (sortinfo->item_compare_ic)
            res = STRICMP(p1, p2);
        else
            res = STRCMP(p1, p2);
***************
*** 18885,18891 ****
  
      /* When the result would be zero, compare the item indexes.  Makes the
       * sort stable. */
!     if (res == 0 && !item_compare_keep_zero)
        res = si1->idx > si2->idx ? 1 : -1;
  
      vim_free(tofree1);
--- 18890,18896 ----
  
      /* When the result would be zero, compare the item indexes.  Makes the
       * sort stable. */
!     if (res == 0 && !sortinfo->item_compare_keep_zero)
        res = si1->idx > si2->idx ? 1 : -1;
  
      vim_free(tofree1);
***************
*** 18906,18912 ****
      int               dummy;
  
      /* shortcut after failure in previous call; compare all items equal */
!     if (item_compare_func_err)
        return 0;
  
      si1 = (sortItem_T *)s1;
--- 18911,18917 ----
      int               dummy;
  
      /* shortcut after failure in previous call; compare all items equal */
!     if (sortinfo->item_compare_func_err)
        return 0;
  
      si1 = (sortItem_T *)s1;
***************
*** 18918,18940 ****
      copy_tv(&si2->item->li_tv, &argv[1]);
  
      rettv.v_type = VAR_UNKNOWN;               /* clear_tv() uses this */
!     res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
                                 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
!                                item_compare_selfdict);
      clear_tv(&argv[0]);
      clear_tv(&argv[1]);
  
      if (res == FAIL)
        res = ITEM_COMPARE_FAIL;
      else
!       res = get_tv_number_chk(&rettv, &item_compare_func_err);
!     if (item_compare_func_err)
        res = ITEM_COMPARE_FAIL;  /* return value has wrong type */
      clear_tv(&rettv);
  
      /* When the result would be zero, compare the pointers themselves.  Makes
       * the sort stable. */
!     if (res == 0 && !item_compare_keep_zero)
        res = si1->idx > si2->idx ? 1 : -1;
  
      return res;
--- 18923,18946 ----
      copy_tv(&si2->item->li_tv, &argv[1]);
  
      rettv.v_type = VAR_UNKNOWN;               /* clear_tv() uses this */
!     res = call_func(sortinfo->item_compare_func,
!                                (int)STRLEN(sortinfo->item_compare_func),
                                 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
!                                sortinfo->item_compare_selfdict);
      clear_tv(&argv[0]);
      clear_tv(&argv[1]);
  
      if (res == FAIL)
        res = ITEM_COMPARE_FAIL;
      else
!       res = get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
!     if (sortinfo->item_compare_func_err)
        res = ITEM_COMPARE_FAIL;  /* return value has wrong type */
      clear_tv(&rettv);
  
      /* When the result would be zero, compare the pointers themselves.  Makes
       * the sort stable. */
!     if (res == 0 && !sortinfo->item_compare_keep_zero)
        res = si1->idx > si2->idx ? 1 : -1;
  
      return res;
***************
*** 18949,18957 ****
--- 18955,18970 ----
      list_T    *l;
      listitem_T        *li;
      sortItem_T        *ptrs;
+     sortinfo_T        *old_sortinfo;
+     sortinfo_T        info;
      long      len;
      long      i;
  
+     /* 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)
        EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
      else
***************
*** 18960,19021 ****
        if (l == NULL || tv_check_lock(l->lv_lock,
             (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
                                                                        TRUE))
!           return;
        rettv->vval.v_list = l;
        rettv->v_type = VAR_LIST;
        ++l->lv_refcount;
  
        len = list_len(l);
        if (len <= 1)
!           return;     /* short list sorts pretty quickly */
  
!       item_compare_ic = FALSE;
!       item_compare_numeric = FALSE;
!       item_compare_numbers = FALSE;
  #ifdef FEAT_FLOAT
!       item_compare_float = FALSE;
  #endif
!       item_compare_func = NULL;
!       item_compare_selfdict = NULL;
        if (argvars[1].v_type != VAR_UNKNOWN)
        {
            /* optional second argument: {func} */
            if (argvars[1].v_type == VAR_FUNC)
!               item_compare_func = argvars[1].vval.v_string;
            else
            {
                int         error = FALSE;
  
                i = get_tv_number_chk(&argvars[1], &error);
                if (error)
!                   return;             /* type error; errmsg already given */
                if (i == 1)
!                   item_compare_ic = TRUE;
                else
!                   item_compare_func = get_tv_string(&argvars[1]);
!               if (item_compare_func != NULL)
                {
!                   if (STRCMP(item_compare_func, "n") == 0)
                    {
!                       item_compare_func = NULL;
!                       item_compare_numeric = TRUE;
                    }
!                   else if (STRCMP(item_compare_func, "N") == 0)
                    {
!                       item_compare_func = NULL;
!                       item_compare_numbers = TRUE;
                    }
  #ifdef FEAT_FLOAT
!                   else if (STRCMP(item_compare_func, "f") == 0)
                    {
!                       item_compare_func = NULL;
!                       item_compare_float = TRUE;
                    }
  #endif
!                   else if (STRCMP(item_compare_func, "i") == 0)
                    {
!                       item_compare_func = NULL;
!                       item_compare_ic = TRUE;
                    }
                }
            }
--- 18973,19034 ----
        if (l == NULL || tv_check_lock(l->lv_lock,
             (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
                                                                        TRUE))
!           goto theend;
        rettv->vval.v_list = l;
        rettv->v_type = VAR_LIST;
        ++l->lv_refcount;
  
        len = list_len(l);
        if (len <= 1)
!           goto theend;        /* short list sorts pretty quickly */
  
!       info.item_compare_ic = 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_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
            {
                int         error = FALSE;
  
                i = get_tv_number_chk(&argvars[1], &error);
                if (error)
!                   goto theend;        /* type error; errmsg already given */
                if (i == 1)
!                   info.item_compare_ic = TRUE;
                else
!                   info.item_compare_func = get_tv_string(&argvars[1]);
!               if (info.item_compare_func != NULL)
                {
!                   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;
                    }
                }
            }
***************
*** 19026,19041 ****
                if (argvars[2].v_type != VAR_DICT)
                {
                    EMSG(_(e_dictreq));
!                   return;
                }
!               item_compare_selfdict = argvars[2].vval.v_dict;
            }
        }
  
        /* Make an array with each entry pointing to an item in the List. */
        ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
        if (ptrs == NULL)
!           return;
  
        i = 0;
        if (sort)
--- 19039,19054 ----
                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 = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
        if (ptrs == NULL)
!           goto theend;
  
        i = 0;
        if (sort)
***************
*** 19048,19057 ****
                ++i;
            }
  
!           item_compare_func_err = FALSE;
!           item_compare_keep_zero = 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"));
--- 19061,19070 ----
                ++i;
            }
  
!           info.item_compare_func_err = FALSE;
!           info.item_compare_keep_zero = FALSE;
            /* test the compare function */
!           if (info.item_compare_func != NULL
                    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
                                                         == ITEM_COMPARE_FAIL)
                EMSG(_("E702: Sort compare function failed"));
***************
*** 19059,19067 ****
            {
                /* Sort the array with item pointers. */
                qsort((void *)ptrs, (size_t)len, sizeof(sortItem_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;
--- 19072,19081 ----
            {
                /* Sort the array with item pointers. */
                qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
!                   info.item_compare_func == 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_last = l->lv_idx_item = NULL;
***************
*** 19076,19084 ****
            int (*item_compare_func_ptr)(const void *, const void *);
  
            /* f_uniq(): ptrs will be a stack of items to remove */
!           item_compare_func_err = FALSE;
!           item_compare_keep_zero = TRUE;
!           item_compare_func_ptr = item_compare_func
                                               ? item_compare2 : item_compare;
  
            for (li = l->lv_first; li != NULL && li->li_next != NULL;
--- 19090,19098 ----
            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
                                               ? item_compare2 : item_compare;
  
            for (li = l->lv_first; li != NULL && li->li_next != NULL;
***************
*** 19087,19100 ****
                if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
                                                                         == 0)
                    ptrs[i++].item = li;
!               if (item_compare_func_err)
                {
                    EMSG(_("E882: Uniq compare function failed"));
                    break;
                }
            }
  
!           if (!item_compare_func_err)
            {
                while (--i >= 0)
                {
--- 19101,19114 ----
                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)
                {
***************
*** 19113,19118 ****
--- 19127,19134 ----
  
        vim_free(ptrs);
      }
+ theend:
+     sortinfo = old_sortinfo;
  }
  
  /*
*** ../vim-7.4.1393/src/testdir/test_sort.vim   2016-01-19 23:35:43.567530384 
+0100
--- src/testdir/test_sort.vim   2016-02-22 22:41:26.036069267 +0100
***************
*** 1,5 ****
--- 1,14 ----
  " Test sort()
  
+ :func Compare1(a, b) abort
+     call sort(range(3), 'Compare2')
+     return a:a ># a:b
+ :endfunc
+ 
+ :func Compare2(a, b) abort
+     return a:a <# a:b
+ :endfunc
+ 
  func Test_sort_strings()
    " numbers compared as strings
    call assert_equal([1, 2, 3], sort([3, 2, 1]))
***************
*** 21,23 ****
--- 30,37 ----
  func Test_sort_float()
    call assert_equal([0.28, 3, 13.5], sort([13.5, 0.28, 3], 'f'))
  endfunc
+ 
+ func Test_sort_nested()
+   " test ability to call sort() from a compare function
+   call assert_equal([1, 3, 5], sort([3, 1, 5], 'Compare1'))
+ endfunc
*** ../vim-7.4.1393/src/version.c       2016-02-22 22:19:18.838058941 +0100
--- src/version.c       2016-02-22 22:42:55.179130994 +0100
***************
*** 750,751 ****
--- 750,753 ----
  {   /* Add new patch number below this line */
+ /**/
+     1394,
  /**/


-- 
Trees moving back and forth is what makes the wind blow.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui