]> granicus.if.org Git - vim/commitdiff
patch 8.1.1763: evalfunc.c is still too big v8.1.1763
authorBram Moolenaar <Bram@vim.org>
Sat, 27 Jul 2019 21:12:12 +0000 (23:12 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 27 Jul 2019 21:12:12 +0000 (23:12 +0200)
Problem:    Evalfunc.c is still too big.
Solution:   Move dict and list functions to a better place.

src/blob.c
src/dict.c
src/evalfunc.c
src/list.c
src/proto/blob.pro
src/proto/dict.pro
src/proto/list.pro
src/version.c

index fb40a5779970aa6dcca7f53314f0e5caed8e2949..278ced62c8d2a055402d111d80c14b54ed80473e 100644 (file)
@@ -258,4 +258,74 @@ failed:
     return NULL;
 }
 
+/*
+ * "remove({blob})" function
+ */
+    void
+blob_remove(typval_T *argvars, typval_T *rettv)
+{
+    int                error = FALSE;
+    long       idx = (long)tv_get_number_chk(&argvars[1], &error);
+    long       end;
+
+    if (!error)
+    {
+       blob_T  *b = argvars[0].vval.v_blob;
+       int     len = blob_len(b);
+       char_u  *p;
+
+       if (idx < 0)
+           // count from the end
+           idx = len + idx;
+       if (idx < 0 || idx >= len)
+       {
+           semsg(_(e_blobidx), idx);
+           return;
+       }
+       if (argvars[2].v_type == VAR_UNKNOWN)
+       {
+           // Remove one item, return its value.
+           p = (char_u *)b->bv_ga.ga_data;
+           rettv->vval.v_number = (varnumber_T) *(p + idx);
+           mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
+           --b->bv_ga.ga_len;
+       }
+       else
+       {
+           blob_T  *blob;
+
+           // Remove range of items, return list with values.
+           end = (long)tv_get_number_chk(&argvars[2], &error);
+           if (error)
+               return;
+           if (end < 0)
+               // count from the end
+               end = len + end;
+           if (end >= len || idx > end)
+           {
+               semsg(_(e_blobidx), end);
+               return;
+           }
+           blob = blob_alloc();
+           if (blob == NULL)
+               return;
+           blob->bv_ga.ga_len = end - idx + 1;
+           if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
+           {
+               vim_free(blob);
+               return;
+           }
+           p = (char_u *)b->bv_ga.ga_data;
+           mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
+                                                 (size_t)(end - idx + 1));
+           ++blob->bv_refcount;
+           rettv->v_type = VAR_BLOB;
+           rettv->vval.v_blob = blob;
+
+           mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
+           b->bv_ga.ga_len -= end - idx + 1;
+       }
+    }
+}
+
 #endif /* defined(FEAT_EVAL) */
index a80fb352d93e988e48bad7c903f0df8566787664..45aa8246f11877282862c8d849643cb45aa9371b 100644 (file)
@@ -709,7 +709,7 @@ dict2string(typval_T *tv, int copyID, int restore_copyID)
 }
 
 /*
- * Get the key for *{key: val} into "tv" and advance "arg".
+ * Get the key for #{key: val} into "tv" and advance "arg".
  * Return FAIL when there is no valid key.
  */
     static int
@@ -731,7 +731,7 @@ get_literal_key(char_u **arg, typval_T *tv)
 
 /*
  * Allocate a variable for a Dictionary and fill it from "*arg".
- * "literal" is TRUE for *{key: val}
+ * "literal" is TRUE for #{key: val}
  * Return OK or FAIL.  Returns NOTDONE for {expr}.
  */
     int
@@ -1033,6 +1033,33 @@ dict_list(typval_T *argvars, typval_T *rettv, int what)
     }
 }
 
+/*
+ * "items(dict)" function
+ */
+    void
+f_items(typval_T *argvars, typval_T *rettv)
+{
+    dict_list(argvars, rettv, 2);
+}
+
+/*
+ * "keys()" function
+ */
+    void
+f_keys(typval_T *argvars, typval_T *rettv)
+{
+    dict_list(argvars, rettv, 0);
+}
+
+/*
+ * "values(dict)" function
+ */
+    void
+f_values(typval_T *argvars, typval_T *rettv)
+{
+    dict_list(argvars, rettv, 1);
+}
+
 /*
  * Make each item in the dict readonly (not the value of the item).
  */
@@ -1052,4 +1079,54 @@ dict_set_items_ro(dict_T *di)
     }
 }
 
+/*
+ * "has_key()" function
+ */
+    void
+f_has_key(typval_T *argvars, typval_T *rettv)
+{
+    if (argvars[0].v_type != VAR_DICT)
+    {
+       emsg(_(e_dictreq));
+       return;
+    }
+    if (argvars[0].vval.v_dict == NULL)
+       return;
+
+    rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
+                                     tv_get_string(&argvars[1]), -1) != NULL;
+}
+
+/*
+ * "remove({dict})" function
+ */
+    void
+dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
+{
+    dict_T     *d;
+    char_u     *key;
+    dictitem_T *di;
+
+    if (argvars[2].v_type != VAR_UNKNOWN)
+       semsg(_(e_toomanyarg), "remove()");
+    else if ((d = argvars[0].vval.v_dict) != NULL
+           && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
+    {
+       key = tv_get_string_chk(&argvars[1]);
+       if (key != NULL)
+       {
+           di = dict_find(d, key, -1);
+           if (di == NULL)
+               semsg(_(e_dictkey), key);
+           else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
+                       && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
+           {
+               *rettv = di->di_tv;
+               init_tv(&di->di_tv);
+               dictitem_remove(d, di);
+           }
+       }
+    }
+}
+
 #endif /* defined(FEAT_EVAL) */
index c0b6788c292f2da5b01776e44dfdc2381ff8ae85..804dbb47d0381e6af5f6b70eaf80e8dfac332eb0 100644 (file)
@@ -180,7 +180,6 @@ static void f_glob(typval_T *argvars, typval_T *rettv);
 static void f_globpath(typval_T *argvars, typval_T *rettv);
 static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
 static void f_has(typval_T *argvars, typval_T *rettv);
-static void f_has_key(typval_T *argvars, typval_T *rettv);
 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
 static void f_histadd(typval_T *argvars, typval_T *rettv);
@@ -207,9 +206,6 @@ static void f_islocked(typval_T *argvars, typval_T *rettv);
 static void f_isinf(typval_T *argvars, typval_T *rettv);
 static void f_isnan(typval_T *argvars, typval_T *rettv);
 #endif
-static void f_items(typval_T *argvars, typval_T *rettv);
-static void f_join(typval_T *argvars, typval_T *rettv);
-static void f_keys(typval_T *argvars, typval_T *rettv);
 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
 static void f_len(typval_T *argvars, typval_T *rettv);
 static void f_libcall(typval_T *argvars, typval_T *rettv);
@@ -217,7 +213,6 @@ static void f_libcallnr(typval_T *argvars, typval_T *rettv);
 static void f_line(typval_T *argvars, typval_T *rettv);
 static void f_line2byte(typval_T *argvars, typval_T *rettv);
 static void f_lispindent(typval_T *argvars, typval_T *rettv);
-static void f_list2str(typval_T *argvars, typval_T *rettv);
 static void f_localtime(typval_T *argvars, typval_T *rettv);
 #ifdef FEAT_FLOAT
 static void f_log(typval_T *argvars, typval_T *rettv);
@@ -330,7 +325,6 @@ static void f_simplify(typval_T *argvars, typval_T *rettv);
 static void f_sin(typval_T *argvars, typval_T *rettv);
 static void f_sinh(typval_T *argvars, typval_T *rettv);
 #endif
-static void f_sort(typval_T *argvars, typval_T *rettv);
 static void f_soundfold(typval_T *argvars, typval_T *rettv);
 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
@@ -392,8 +386,6 @@ static void f_trunc(typval_T *argvars, typval_T *rettv);
 static void f_type(typval_T *argvars, typval_T *rettv);
 static void f_undofile(typval_T *argvars, typval_T *rettv);
 static void f_undotree(typval_T *argvars, typval_T *rettv);
-static void f_uniq(typval_T *argvars, typval_T *rettv);
-static void f_values(typval_T *argvars, typval_T *rettv);
 static void f_virtcol(typval_T *argvars, typval_T *rettv);
 static void f_visualmode(typval_T *argvars, typval_T *rettv);
 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
@@ -6580,24 +6572,6 @@ f_has(typval_T *argvars, typval_T *rettv)
     rettv->vval.v_number = n;
 }
 
-/*
- * "has_key()" function
- */
-    static void
-f_has_key(typval_T *argvars, typval_T *rettv)
-{
-    if (argvars[0].v_type != VAR_DICT)
-    {
-       emsg(_(e_dictreq));
-       return;
-    }
-    if (argvars[0].vval.v_dict == NULL)
-       return;
-
-    rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
-                                     tv_get_string(&argvars[1]), -1) != NULL;
-}
-
 /*
  * "haslocaldir()" function
  */
@@ -7240,58 +7214,6 @@ f_isnan(typval_T *argvars, typval_T *rettv)
 }
 #endif
 
-/*
- * "items(dict)" function
- */
-    static void
-f_items(typval_T *argvars, typval_T *rettv)
-{
-    dict_list(argvars, rettv, 2);
-}
-
-/*
- * "join()" function
- */
-    static void
-f_join(typval_T *argvars, typval_T *rettv)
-{
-    garray_T   ga;
-    char_u     *sep;
-
-    if (argvars[0].v_type != VAR_LIST)
-    {
-       emsg(_(e_listreq));
-       return;
-    }
-    if (argvars[0].vval.v_list == NULL)
-       return;
-    if (argvars[1].v_type == VAR_UNKNOWN)
-       sep = (char_u *)" ";
-    else
-       sep = tv_get_string_chk(&argvars[1]);
-
-    rettv->v_type = VAR_STRING;
-
-    if (sep != NULL)
-    {
-       ga_init2(&ga, (int)sizeof(char), 80);
-       list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
-       ga_append(&ga, NUL);
-       rettv->vval.v_string = (char_u *)ga.ga_data;
-    }
-    else
-       rettv->vval.v_string = NULL;
-}
-
-/*
- * "keys()" function
- */
-    static void
-f_keys(typval_T *argvars, typval_T *rettv)
-{
-    dict_list(argvars, rettv, 0);
-}
-
 /*
  * "last_buffer_nr()" function.
  */
@@ -7459,61 +7381,6 @@ f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
        rettv->vval.v_number = -1;
 }
 
-/*
- * "list2str()" function
- */
-    static void
-f_list2str(typval_T *argvars, typval_T *rettv)
-{
-    list_T     *l;
-    listitem_T *li;
-    garray_T   ga;
-    int                utf8 = FALSE;
-
-    rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = NULL;
-    if (argvars[0].v_type != VAR_LIST)
-    {
-       emsg(_(e_invarg));
-       return;
-    }
-
-    l = argvars[0].vval.v_list;
-    if (l == NULL)
-       return;  // empty list results in empty string
-
-    if (argvars[1].v_type != VAR_UNKNOWN)
-       utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
-
-    ga_init2(&ga, 1, 80);
-    if (has_mbyte || utf8)
-    {
-       char_u  buf[MB_MAXBYTES + 1];
-       int     (*char2bytes)(int, char_u *);
-
-       if (utf8 || enc_utf8)
-           char2bytes = utf_char2bytes;
-       else
-           char2bytes = mb_char2bytes;
-
-       for (li = l->lv_first; li != NULL; li = li->li_next)
-       {
-           buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
-           ga_concat(&ga, buf);
-       }
-       ga_append(&ga, NUL);
-    }
-    else if (ga_grow(&ga, list_len(l) + 1) == OK)
-    {
-       for (li = l->lv_first; li != NULL; li = li->li_next)
-           ga_append(&ga, tv_get_number(&li->li_tv));
-       ga_append(&ga, NUL);
-    }
-
-    rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = ga.ga_data;
-}
-
 /*
  * "localtime()" function
  */
@@ -9237,158 +9104,16 @@ f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
     static void
 f_remove(typval_T *argvars, typval_T *rettv)
 {
-    list_T     *l;
-    listitem_T *item, *item2;
-    listitem_T *li;
-    long       idx;
-    long       end;
-    char_u     *key;
-    dict_T     *d;
-    dictitem_T *di;
     char_u     *arg_errmsg = (char_u *)N_("remove() argument");
-    int                error = FALSE;
 
     if (argvars[0].v_type == VAR_DICT)
-    {
-       if (argvars[2].v_type != VAR_UNKNOWN)
-           semsg(_(e_toomanyarg), "remove()");
-       else if ((d = argvars[0].vval.v_dict) != NULL
-               && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
-       {
-           key = tv_get_string_chk(&argvars[1]);
-           if (key != NULL)
-           {
-               di = dict_find(d, key, -1);
-               if (di == NULL)
-                   semsg(_(e_dictkey), key);
-               else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
-                           && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
-               {
-                   *rettv = di->di_tv;
-                   init_tv(&di->di_tv);
-                   dictitem_remove(d, di);
-               }
-           }
-       }
-    }
+       dict_remove(argvars, rettv, arg_errmsg);
     else if (argvars[0].v_type == VAR_BLOB)
-    {
-       idx = (long)tv_get_number_chk(&argvars[1], &error);
-       if (!error)
-       {
-           blob_T  *b = argvars[0].vval.v_blob;
-           int     len = blob_len(b);
-           char_u  *p;
-
-           if (idx < 0)
-               // count from the end
-               idx = len + idx;
-           if (idx < 0 || idx >= len)
-           {
-               semsg(_(e_blobidx), idx);
-               return;
-           }
-           if (argvars[2].v_type == VAR_UNKNOWN)
-           {
-               // Remove one item, return its value.
-               p = (char_u *)b->bv_ga.ga_data;
-               rettv->vval.v_number = (varnumber_T) *(p + idx);
-               mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
-               --b->bv_ga.ga_len;
-           }
-           else
-           {
-               blob_T  *blob;
-
-               // Remove range of items, return list with values.
-               end = (long)tv_get_number_chk(&argvars[2], &error);
-               if (error)
-                   return;
-               if (end < 0)
-                   // count from the end
-                   end = len + end;
-               if (end >= len || idx > end)
-               {
-                   semsg(_(e_blobidx), end);
-                   return;
-               }
-               blob = blob_alloc();
-               if (blob == NULL)
-                   return;
-               blob->bv_ga.ga_len = end - idx + 1;
-               if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
-               {
-                   vim_free(blob);
-                   return;
-               }
-               p = (char_u *)b->bv_ga.ga_data;
-               mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
-                                                     (size_t)(end - idx + 1));
-               ++blob->bv_refcount;
-               rettv->v_type = VAR_BLOB;
-               rettv->vval.v_blob = blob;
-
-               mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
-               b->bv_ga.ga_len -= end - idx + 1;
-           }
-       }
-    }
-    else if (argvars[0].v_type != VAR_LIST)
+       blob_remove(argvars, rettv);
+    else if (argvars[0].v_type == VAR_LIST)
+       list_remove(argvars, rettv, arg_errmsg);
+    else
        semsg(_(e_listdictblobarg), "remove()");
-    else if ((l = argvars[0].vval.v_list) != NULL
-                             && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
-    {
-       idx = (long)tv_get_number_chk(&argvars[1], &error);
-       if (error)
-           ;           // type error: do nothing, errmsg already given
-       else if ((item = list_find(l, idx)) == NULL)
-           semsg(_(e_listidx), idx);
-       else
-       {
-           if (argvars[2].v_type == VAR_UNKNOWN)
-           {
-               /* Remove one item, return its value. */
-               vimlist_remove(l, item, item);
-               *rettv = item->li_tv;
-               vim_free(item);
-           }
-           else
-           {
-               // Remove range of items, return list with values.
-               end = (long)tv_get_number_chk(&argvars[2], &error);
-               if (error)
-                   ;           // type error: do nothing
-               else if ((item2 = list_find(l, end)) == NULL)
-                   semsg(_(e_listidx), end);
-               else
-               {
-                   int     cnt = 0;
-
-                   for (li = item; li != NULL; li = li->li_next)
-                   {
-                       ++cnt;
-                       if (li == item2)
-                           break;
-                   }
-                   if (li == NULL)  /* didn't find "item2" after "item" */
-                       emsg(_(e_invrange));
-                   else
-                   {
-                       vimlist_remove(l, item, item2);
-                       if (rettv_list_alloc(rettv) == OK)
-                       {
-                           l = rettv->vval.v_list;
-                           l->lv_first = item;
-                           l->lv_last = item2;
-                           item->li_prev = NULL;
-                           item2->li_next = NULL;
-                           l->lv_len = cnt;
-                       }
-                   }
-               }
-           }
-       }
-    }
 }
 
 /*
@@ -11100,388 +10825,6 @@ f_sinh(typval_T *argvars, typval_T *rettv)
 }
 #endif
 
-static int item_compare(const void *s1, const void *s2);
-static int item_compare2(const void *s1, const void *s2);
-
-/* struct used in the array that's given to qsort() */
-typedef struct
-{
-    listitem_T *item;
-    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;
-    partial_T  *item_compare_partial;
-    dict_T     *item_compare_selfdict;
-    int                item_compare_func_err;
-    int                item_compare_keep_zero;
-} sortinfo_T;
-static sortinfo_T      *sortinfo = NULL;
-#define ITEM_COMPARE_FAIL 999
-
-/*
- * Compare functions for f_sort() and f_uniq() below.
- */
-    static int
-item_compare(const void *s1, const void *s2)
-{
-    sortItem_T  *si1, *si2;
-    typval_T   *tv1, *tv2;
-    char_u     *p1, *p2;
-    char_u     *tofree1 = NULL, *tofree2 = NULL;
-    int                res;
-    char_u     numbuf1[NUMBUFLEN];
-    char_u     numbuf2[NUMBUFLEN];
-
-    si1 = (sortItem_T *)s1;
-    si2 = (sortItem_T *)s2;
-    tv1 = &si1->item->li_tv;
-    tv2 = &si2->item->li_tv;
-
-    if (sortinfo->item_compare_numbers)
-    {
-       varnumber_T     v1 = tv_get_number(tv1);
-       varnumber_T     v2 = tv_get_number(tv2);
-
-       return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
-    }
-
-#ifdef FEAT_FLOAT
-    if (sortinfo->item_compare_float)
-    {
-       float_T v1 = tv_get_float(tv1);
-       float_T v2 = tv_get_float(tv2);
-
-       return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
-    }
-#endif
-
-    /* tv2string() puts quotes around a string and allocates memory.  Don't do
-     * that for string variables. Use a single quote when comparing with a
-     * 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;
-    }
-    else
-       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;
-    }
-    else
-       p2 = tv2string(tv2, &tofree2, numbuf2, 0);
-    if (p1 == NULL)
-       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);
-    }
-    else
-    {
-       double n1, n2;
-       n1 = strtod((char *)p1, (char **)&p1);
-       n2 = strtod((char *)p2, (char **)&p2);
-       res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
-    }
-
-    /* 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);
-    vim_free(tofree2);
-    return res;
-}
-
-    static int
-item_compare2(const void *s1, const void *s2)
-{
-    sortItem_T  *si1, *si2;
-    int                res;
-    typval_T   rettv;
-    typval_T   argv[3];
-    int                dummy;
-    char_u     *func_name;
-    partial_T  *partial = sortinfo->item_compare_partial;
-
-    /* shortcut after failure in previous call; compare all items equal */
-    if (sortinfo->item_compare_func_err)
-       return 0;
-
-    si1 = (sortItem_T *)s1;
-    si2 = (sortItem_T *)s2;
-
-    if (partial == NULL)
-       func_name = sortinfo->item_compare_func;
-    else
-       func_name = partial_name(partial);
-
-    /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
-     * in the copy without changing the original list items. */
-    copy_tv(&si1->item->li_tv, &argv[0]);
-    copy_tv(&si2->item->li_tv, &argv[1]);
-
-    rettv.v_type = VAR_UNKNOWN;                /* clear_tv() uses this */
-    res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
-                                partial, sortinfo->item_compare_selfdict);
-    clear_tv(&argv[0]);
-    clear_tv(&argv[1]);
-
-    if (res == FAIL)
-       res = ITEM_COMPARE_FAIL;
-    else
-       res = (int)tv_get_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;
-}
-
-/*
- * "sort({list})" 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;
-
-    /* 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 || var_check_lock(l->lv_lock,
-            (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
-                                                                       TRUE))
-           goto theend;
-       rettv_list_set(rettv, l);
-
-       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_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;
-
-               i = (long)tv_get_number_chk(&argvars[1], &error);
-               if (error)
-                   goto theend;        /* type error; errmsg already given */
-               if (i == 1)
-                   info.item_compare_ic = TRUE;
-               else if (argvars[1].v_type != VAR_NUMBER)
-                   info.item_compare_func = tv_get_string(&argvars[1]);
-               else if (i != 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;
-                   }
-               }
-           }
-
-           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 (li = l->lv_first; li != NULL; li = li->li_next)
-           {
-               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_last = l->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_last = ptrs[i].item;
-                   list_fix_watch(l, li);
-                   listitem_free(li);
-                   l->lv_len--;
-               }
-           }
-       }
-
-       vim_free(ptrs);
-    }
-theend:
-    sortinfo = old_sortinfo;
-}
-
-/*
- * "sort({list})" function
- */
-    static void
-f_sort(typval_T *argvars, typval_T *rettv)
-{
-    do_sort_uniq(argvars, rettv, TRUE);
-}
-
-/*
- * "uniq({list})" function
- */
-    static void
-f_uniq(typval_T *argvars, typval_T *rettv)
-{
-    do_sort_uniq(argvars, rettv, FALSE);
-}
-
 /*
  * "soundfold({word})" function
  */
@@ -13481,15 +12824,6 @@ f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
     }
 }
 
-/*
- * "values(dict)" function
- */
-    static void
-f_values(typval_T *argvars, typval_T *rettv)
-{
-    dict_list(argvars, rettv, 1);
-}
-
 /*
  * "virtcol(string)" function
  */
index e1aa2d1a00ae83f83986197fc7765208094db1f2..c2bf4909cc72ef1f9f3157dbc3f9f505d00e2194 100644 (file)
@@ -874,6 +874,40 @@ list_join(
     return retval;
 }
 
+/*
+ * "join()" function
+ */
+    void
+f_join(typval_T *argvars, typval_T *rettv)
+{
+    garray_T   ga;
+    char_u     *sep;
+
+    if (argvars[0].v_type != VAR_LIST)
+    {
+       emsg(_(e_listreq));
+       return;
+    }
+    if (argvars[0].vval.v_list == NULL)
+       return;
+    if (argvars[1].v_type == VAR_UNKNOWN)
+       sep = (char_u *)" ";
+    else
+       sep = tv_get_string_chk(&argvars[1]);
+
+    rettv->v_type = VAR_STRING;
+
+    if (sep != NULL)
+    {
+       ga_init2(&ga, (int)sizeof(char), 80);
+       list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
+       ga_append(&ga, NUL);
+       rettv->vval.v_string = (char_u *)ga.ga_data;
+    }
+    else
+       rettv->vval.v_string = NULL;
+}
+
 /*
  * Allocate a variable for a List and fill it from "*arg".
  * Return OK or FAIL.
@@ -1007,4 +1041,507 @@ init_static_list(staticList10_T *sl)
     }
 }
 
+/*
+ * "list2str()" function
+ */
+    void
+f_list2str(typval_T *argvars, typval_T *rettv)
+{
+    list_T     *l;
+    listitem_T *li;
+    garray_T   ga;
+    int                utf8 = FALSE;
+
+    rettv->v_type = VAR_STRING;
+    rettv->vval.v_string = NULL;
+    if (argvars[0].v_type != VAR_LIST)
+    {
+       emsg(_(e_invarg));
+       return;
+    }
+
+    l = argvars[0].vval.v_list;
+    if (l == NULL)
+       return;  // empty list results in empty string
+
+    if (argvars[1].v_type != VAR_UNKNOWN)
+       utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
+
+    ga_init2(&ga, 1, 80);
+    if (has_mbyte || utf8)
+    {
+       char_u  buf[MB_MAXBYTES + 1];
+       int     (*char2bytes)(int, char_u *);
+
+       if (utf8 || enc_utf8)
+           char2bytes = utf_char2bytes;
+       else
+           char2bytes = mb_char2bytes;
+
+       for (li = l->lv_first; li != NULL; li = li->li_next)
+       {
+           buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
+           ga_concat(&ga, buf);
+       }
+       ga_append(&ga, NUL);
+    }
+    else if (ga_grow(&ga, list_len(l) + 1) == OK)
+    {
+       for (li = l->lv_first; li != NULL; li = li->li_next)
+           ga_append(&ga, tv_get_number(&li->li_tv));
+       ga_append(&ga, NUL);
+    }
+
+    rettv->v_type = VAR_STRING;
+    rettv->vval.v_string = ga.ga_data;
+}
+
+    void
+list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
+{
+    list_T     *l;
+    listitem_T *item, *item2;
+    listitem_T *li;
+    int                error = FALSE;
+    int                idx;
+
+    if ((l = argvars[0].vval.v_list) == NULL
+                             || var_check_lock(l->lv_lock, arg_errmsg, TRUE))
+       return;
+
+    idx = (long)tv_get_number_chk(&argvars[1], &error);
+    if (error)
+       ;               // type error: do nothing, errmsg already given
+    else if ((item = list_find(l, idx)) == NULL)
+       semsg(_(e_listidx), idx);
+    else
+    {
+       if (argvars[2].v_type == VAR_UNKNOWN)
+       {
+           /* Remove one item, return its value. */
+           vimlist_remove(l, item, item);
+           *rettv = item->li_tv;
+           vim_free(item);
+       }
+       else
+       {
+           // Remove range of items, return list with values.
+           int end = (long)tv_get_number_chk(&argvars[2], &error);
+
+           if (error)
+               ;               // type error: do nothing
+           else if ((item2 = list_find(l, end)) == NULL)
+               semsg(_(e_listidx), end);
+           else
+           {
+               int         cnt = 0;
+
+               for (li = item; li != NULL; li = li->li_next)
+               {
+                   ++cnt;
+                   if (li == item2)
+                       break;
+               }
+               if (li == NULL)  /* didn't find "item2" after "item" */
+                   emsg(_(e_invrange));
+               else
+               {
+                   vimlist_remove(l, item, item2);
+                   if (rettv_list_alloc(rettv) == OK)
+                   {
+                       l = rettv->vval.v_list;
+                       l->lv_first = item;
+                       l->lv_last = item2;
+                       item->li_prev = NULL;
+                       item2->li_next = NULL;
+                       l->lv_len = cnt;
+                   }
+               }
+           }
+       }
+    }
+}
+
+static int item_compare(const void *s1, const void *s2);
+static int item_compare2(const void *s1, const void *s2);
+
+/* struct used in the array that's given to qsort() */
+typedef struct
+{
+    listitem_T *item;
+    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;
+    partial_T  *item_compare_partial;
+    dict_T     *item_compare_selfdict;
+    int                item_compare_func_err;
+    int                item_compare_keep_zero;
+} sortinfo_T;
+static sortinfo_T      *sortinfo = NULL;
+#define ITEM_COMPARE_FAIL 999
+
+/*
+ * Compare functions for f_sort() and f_uniq() below.
+ */
+    static int
+item_compare(const void *s1, const void *s2)
+{
+    sortItem_T  *si1, *si2;
+    typval_T   *tv1, *tv2;
+    char_u     *p1, *p2;
+    char_u     *tofree1 = NULL, *tofree2 = NULL;
+    int                res;
+    char_u     numbuf1[NUMBUFLEN];
+    char_u     numbuf2[NUMBUFLEN];
+
+    si1 = (sortItem_T *)s1;
+    si2 = (sortItem_T *)s2;
+    tv1 = &si1->item->li_tv;
+    tv2 = &si2->item->li_tv;
+
+    if (sortinfo->item_compare_numbers)
+    {
+       varnumber_T     v1 = tv_get_number(tv1);
+       varnumber_T     v2 = tv_get_number(tv2);
+
+       return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+    }
+
+#ifdef FEAT_FLOAT
+    if (sortinfo->item_compare_float)
+    {
+       float_T v1 = tv_get_float(tv1);
+       float_T v2 = tv_get_float(tv2);
+
+       return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+    }
+#endif
+
+    /* tv2string() puts quotes around a string and allocates memory.  Don't do
+     * that for string variables. Use a single quote when comparing with a
+     * 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;
+    }
+    else
+       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;
+    }
+    else
+       p2 = tv2string(tv2, &tofree2, numbuf2, 0);
+    if (p1 == NULL)
+       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);
+    }
+    else
+    {
+       double n1, n2;
+       n1 = strtod((char *)p1, (char **)&p1);
+       n2 = strtod((char *)p2, (char **)&p2);
+       res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
+    }
+
+    /* 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);
+    vim_free(tofree2);
+    return res;
+}
+
+    static int
+item_compare2(const void *s1, const void *s2)
+{
+    sortItem_T  *si1, *si2;
+    int                res;
+    typval_T   rettv;
+    typval_T   argv[3];
+    int                dummy;
+    char_u     *func_name;
+    partial_T  *partial = sortinfo->item_compare_partial;
+
+    /* shortcut after failure in previous call; compare all items equal */
+    if (sortinfo->item_compare_func_err)
+       return 0;
+
+    si1 = (sortItem_T *)s1;
+    si2 = (sortItem_T *)s2;
+
+    if (partial == NULL)
+       func_name = sortinfo->item_compare_func;
+    else
+       func_name = partial_name(partial);
+
+    /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
+     * in the copy without changing the original list items. */
+    copy_tv(&si1->item->li_tv, &argv[0]);
+    copy_tv(&si2->item->li_tv, &argv[1]);
+
+    rettv.v_type = VAR_UNKNOWN;                /* clear_tv() uses this */
+    res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
+                                partial, sortinfo->item_compare_selfdict);
+    clear_tv(&argv[0]);
+    clear_tv(&argv[1]);
+
+    if (res == FAIL)
+       res = ITEM_COMPARE_FAIL;
+    else
+       res = (int)tv_get_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;
+}
+
+/*
+ * "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;
+
+    /* 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 || var_check_lock(l->lv_lock,
+            (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
+                                                                       TRUE))
+           goto theend;
+       rettv_list_set(rettv, l);
+
+       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_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;
+
+               i = (long)tv_get_number_chk(&argvars[1], &error);
+               if (error)
+                   goto theend;        /* type error; errmsg already given */
+               if (i == 1)
+                   info.item_compare_ic = TRUE;
+               else if (argvars[1].v_type != VAR_NUMBER)
+                   info.item_compare_func = tv_get_string(&argvars[1]);
+               else if (i != 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;
+                   }
+               }
+           }
+
+           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 (li = l->lv_first; li != NULL; li = li->li_next)
+           {
+               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_last = l->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_last = ptrs[i].item;
+                   list_fix_watch(l, li);
+                   listitem_free(li);
+                   l->lv_len--;
+               }
+           }
+       }
+
+       vim_free(ptrs);
+    }
+theend:
+    sortinfo = old_sortinfo;
+}
+
+/*
+ * "sort({list})" function
+ */
+    void
+f_sort(typval_T *argvars, typval_T *rettv)
+{
+    do_sort_uniq(argvars, rettv, TRUE);
+}
+
+/*
+ * "uniq({list})" function
+ */
+    void
+f_uniq(typval_T *argvars, typval_T *rettv)
+{
+    do_sort_uniq(argvars, rettv, FALSE);
+}
+
 #endif /* defined(FEAT_EVAL) */
index 019692dc3b86d827d4a06a951c8a498f56bd8afa..706a83ea061a8fc26e5424294ac77f6a24d20a51 100644 (file)
@@ -13,4 +13,5 @@ int read_blob(FILE *fd, blob_T *blob);
 int write_blob(FILE *fd, blob_T *blob);
 char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf);
 blob_T *string2blob(char_u *str);
+void blob_remove(typval_T *argvars, typval_T *rettv);
 /* vim: set ft=c : */
index c133523731fcc1c7e0a81bd76ed1cd6d15be9eb5..93d61e7f404761ae594ccf11b25933ef4f3c1a50 100644 (file)
@@ -33,5 +33,10 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
 dictitem_T *dict_lookup(hashitem_T *hi);
 int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
 void dict_list(typval_T *argvars, typval_T *rettv, int what);
+void f_items(typval_T *argvars, typval_T *rettv);
+void f_keys(typval_T *argvars, typval_T *rettv);
+void f_values(typval_T *argvars, typval_T *rettv);
 void dict_set_items_ro(dict_T *di);
+void f_has_key(typval_T *argvars, typval_T *rettv);
+void dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg);
 /* vim: set ft=c : */
index 88d902888f4458f0d9308844f6e5c06344e97b10..2f5be0df0e9348a40ce7920a7bc4a730944a96d6 100644 (file)
@@ -34,7 +34,12 @@ list_T *list_copy(list_T *orig, int deep, int copyID);
 void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2);
 char_u *list2string(typval_T *tv, int copyID, int restore_copyID);
 int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int restore_copyID, int copyID);
+void f_join(typval_T *argvars, typval_T *rettv);
 int get_list_tv(char_u **arg, typval_T *rettv, int evaluate);
 int write_list(FILE *fd, list_T *list, int binary);
 void init_static_list(staticList10_T *sl);
+void f_list2str(typval_T *argvars, typval_T *rettv);
+void list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg);
+void f_sort(typval_T *argvars, typval_T *rettv);
+void f_uniq(typval_T *argvars, typval_T *rettv);
 /* vim: set ft=c : */
index 6d2c89c94f993708d6fbdd48bd50a814a314a1b4..da62479b1cc09a904e0160a5fc6c0899ee5c4376 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1763,
 /**/
     1762,
 /**/