summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvimboss <devnull@localhost>2005-01-06 23:28:25 +0000
committervimboss <devnull@localhost>2005-01-06 23:28:25 +0000
commita89d8ae6c623bcd54453e09a41578c0830fe98fa (patch)
treecfb0ed574589c065b6978ee2dd39ad8ca2396df0
parent36645a6ed0c34c121c3b854993886f1856dbced5 (diff)
downloadvim-a89d8ae6c623bcd54453e09a41578c0830fe98fa.tar.gz
updated for version 7.0032v7.0032v7-0032
-rw-r--r--runtime/doc/todo.txt34
-rw-r--r--src/eval.c691
2 files changed, 582 insertions, 143 deletions
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 54213cfc..847418f1 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 05
+*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 06
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -31,26 +31,7 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
-------------------- Known bugs and current work -----------------------
List data type:
-- When removing items from the condition stack may free cs_fors.
-- don't copy the list, use a list-watcher to adjust the item pointer when it's
- deleted.
-- "for a in list"
- Make copy of the list to avoid trouble when it changes. As one big block?
-- "for [a, b] in [[1, 2], [3, 4]]"
-- support list generator: items are obtained with a function by index.
- "range(1, 400, 2)" creates one.
-- == (same value) and "is" (same list)
-- add many functions:
- call(func, list) call function
- keys(list) list of all indexes 0 - (len(list) - 1)
- repeat(list, count) return list concatenated count times
- concat(list1, list2) return list1 and list2 concatenated
- extend(list1, list2) concatenate list2 to list 1
- extend(list1, list2, idx) prepend list2 before idx in list1
- count(list, item) nr of times item appears in list
- index(list, item) lowest index of item in list
- pop(list[, idx]) removes item at idx (default: last)
- pop(list, idx1, idx2) removes items idx1 to idx2, returns them
+- add more functions:
reverse(list) reverses order
sort(list[, func]) sort; func compares items
getval(list, idx[, default]) get value at idx or default
@@ -59,14 +40,14 @@ List data type:
str2list() parse string to list in several ways: white
separated, [] form, etc.
Fix the error numbers E999 in eval.c.
-
-Function reference: Define a nameless (numbered) function and assign
-it to a Funcref variable.
- :function Myfunc = (arg)
- :endfunc
+- Cache the length of a List?
Use 'ignorecase' for ":vimgrep"?
+When allocating a new variable, a search is done for an empty entry. May
+waste a lot of time if there isn't one. Keep an index of available entry,
+none available, or unknown.
+
patch for QuickFixCmdPre and QuickFixCmdPost autocommands. (Ciaran McCreesh,
2005 Jan 1)
@@ -101,7 +82,6 @@ PLANNED FOR VERSION 7.0:
- new DATA TYPES:
- None? (or use empty string?)
- dictionary
- Check old patch from Robert Webb for array support.
Add type checking? See ~/vim/ideas.txt.
- Add SPELLCHECKER, with easy to add support for many languages.
8 Add spell checking. Use "ispell -a" somehow.
diff --git a/src/eval.c b/src/eval.c
index 6ed5c9fa..5a3f70a1 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -320,13 +320,19 @@ static void list_free __ARGS((listvar *l));
static listitem *listitem_alloc __ARGS((void));
static void listitem_free __ARGS((listitem *item));
static long list_len __ARGS((listvar *l));
+static int list_equal __ARGS((listvar *l1, listvar *l2, int ic));
+static int tv_equal __ARGS((typeval *tv1, typeval *tv2, int ic));
static listitem *list_find __ARGS((listvar *l, long n));
+static listitem *list_find_ext __ARGS((listvar *l, long *ip));
static void list_append __ARGS((listvar *l, listitem *item));
static int list_append_tv __ARGS((listvar *l, typeval *tv));
+static int list_insert_tv __ARGS((listvar *l, typeval *tv, listitem *item));
+static int list_extend __ARGS((listvar *l1, listvar *l2, listitem *bef));
+static int list_concat __ARGS((listvar *l1, listvar *l2, typeval *tv));
static listvar *list_copy __ARGS((listvar *orig, int deep));
-static listitem *list_getrem __ARGS((listvar *l, long n));
+static void list_getrem __ARGS((listvar *l, listitem *item, listitem *item2));
static char_u *list2string __ARGS((typeval *tv));
-static char_u *tv2string __ARGS((typeval *tv, char_u **tofree));
+static char_u *tv2string __ARGS((typeval *tv, char_u **tofree, char_u *numbuf));
static int get_env_tv __ARGS((char_u **arg, typeval *rettv, int evaluate));
static int find_internal_func __ARGS((char_u *name));
static char_u *deref_func_name __ARGS((char_u *name, int *lenp));
@@ -348,11 +354,13 @@ static void f_bufnr __ARGS((typeval *argvars, typeval *rettv));
static void f_bufwinnr __ARGS((typeval *argvars, typeval *rettv));
static void f_byte2line __ARGS((typeval *argvars, typeval *rettv));
static void f_byteidx __ARGS((typeval *argvars, typeval *rettv));
+static void f_call __ARGS((typeval *argvars, typeval *rettv));
static void f_char2nr __ARGS((typeval *argvars, typeval *rettv));
static void f_cindent __ARGS((typeval *argvars, typeval *rettv));
static void f_col __ARGS((typeval *argvars, typeval *rettv));
static void f_confirm __ARGS((typeval *argvars, typeval *rettv));
static void f_copy __ARGS((typeval *argvars, typeval *rettv));
+static void f_count __ARGS((typeval *argvars, typeval *rettv));
static void f_cscope_connection __ARGS((typeval *argvars, typeval *rettv));
static void f_cursor __ARGS((typeval *argsvars, typeval *rettv));
static void f_deepcopy __ARGS((typeval *argvars, typeval *rettv));
@@ -365,6 +373,7 @@ static void f_eventhandler __ARGS((typeval *argvars, typeval *rettv));
static void f_executable __ARGS((typeval *argvars, typeval *rettv));
static void f_exists __ARGS((typeval *argvars, typeval *rettv));
static void f_expand __ARGS((typeval *argvars, typeval *rettv));
+static void f_extend __ARGS((typeval *argvars, typeval *rettv));
static void f_filereadable __ARGS((typeval *argvars, typeval *rettv));
static void f_filewritable __ARGS((typeval *argvars, typeval *rettv));
static void f_finddir __ARGS((typeval *argvars, typeval *rettv));
@@ -411,6 +420,7 @@ static void f_iconv __ARGS((typeval *argvars, typeval *rettv));
static void f_indent __ARGS((typeval *argvars, typeval *rettv));
static void f_insert __ARGS((typeval *argvars, typeval *rettv));
static void f_isdirectory __ARGS((typeval *argvars, typeval *rettv));
+static void f_index __ARGS((typeval *argvars, typeval *rettv));
static void f_input __ARGS((typeval *argvars, typeval *rettv));
static void f_inputdialog __ARGS((typeval *argvars, typeval *rettv));
static void f_inputrestore __ARGS((typeval *argvars, typeval *rettv));
@@ -440,6 +450,7 @@ static void f_setcmdpos __ARGS((typeval *argvars, typeval *rettv));
static void f_setwinvar __ARGS((typeval *argvars, typeval *rettv));
static void f_remove __ARGS((typeval *argvars, typeval *rettv));
static void f_rename __ARGS((typeval *argvars, typeval *rettv));
+static void f_repeat __ARGS((typeval *argvars, typeval *rettv));
static void f_resolve __ARGS((typeval *argvars, typeval *rettv));
static void f_search __ARGS((typeval *argvars, typeval *rettv));
static void f_searchpair __ARGS((typeval *argvars, typeval *rettv));
@@ -449,7 +460,6 @@ static void f_remote_foreground __ARGS((typeval *argvars, typeval *rettv));
static void f_remote_peek __ARGS((typeval *argvars, typeval *rettv));
static void f_remote_read __ARGS((typeval *argvars, typeval *rettv));
static void f_remote_send __ARGS((typeval *argvars, typeval *rettv));
-static void f_repeat __ARGS((typeval *argvars, typeval *rettv));
static void f_server2client __ARGS((typeval *argvars, typeval *rettv));
static void f_serverlist __ARGS((typeval *argvars, typeval *rettv));
static void f_setline __ARGS((typeval *argvars, typeval *rettv));
@@ -2448,6 +2458,8 @@ eval3(arg, rettv, evaluate)
* var1 >= var2
* var1 < var2
* var1 <= var2
+ * var1 is var2
+ * var1 isnot var2
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -2464,6 +2476,7 @@ eval4(arg, rettv, evaluate)
char_u *p;
int i;
exptype_T type = TYPE_UNKNOWN;
+ int type_is = FALSE; /* TRUE for "is" and "isnot" */
int len = 2;
long n1, n2;
char_u *s1, *s2;
@@ -2507,6 +2520,17 @@ eval4(arg, rettv, evaluate)
else
type = TYPE_SEQUAL;
break;
+ case 'i': if (p[1] == 's')
+ {
+ if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
+ len = 5;
+ if (!vim_isIDc(p[len]))
+ {
+ type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL;
+ type_is = TRUE;
+ }
+ }
+ break;
}
/*
@@ -2542,11 +2566,73 @@ eval4(arg, rettv, evaluate)
if (evaluate)
{
+ if (type_is && rettv->v_type != var2.v_type)
+ {
+ /* For "is" a different type always means FALSE, for "notis"
+ * it means TRUE. */
+ n1 = (type == TYPE_NEQUAL);
+ }
+ else if (rettv->v_type == VAR_LIST || var2.v_type == VAR_LIST)
+ {
+ if (type_is)
+ {
+ n1 = (rettv->v_type == var2.v_type
+ && rettv->vval.v_list == var2.vval.v_list);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (rettv->v_type != var2.v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (rettv->v_type != var2.v_type)
+ EMSG(_("E999: Can only compare List with List"));
+ else
+ EMSG(_("E999: Invalid operation for Lists"));
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Lists for being equal or unequal. */
+ n1 = list_equal(rettv->vval.v_list, var2.vval.v_list, ic);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
+ else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC)
+ {
+ if (rettv->v_type != var2.v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (rettv->v_type != var2.v_type)
+ EMSG(_("E999: Can only compare Funcref with Funcref"));
+ else
+ EMSG(_("E999: Invalid operation for Funcrefs"));
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Funcrefs for being equal or unequal. */
+ if (rettv->vval.v_string == NULL
+ || var2.vval.v_string == NULL)
+ n1 = FALSE;
+ else
+ n1 = STRCMP(rettv->vval.v_string,
+ var2.vval.v_string) == 0;
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
/*
* If one of the two variables is a number, compare as a number.
* When using "=~" or "!~", always compare as string.
*/
- if ((rettv->v_type == VAR_NUMBER || var2.v_type == VAR_NUMBER)
+ else if ((rettv->v_type == VAR_NUMBER || var2.v_type == VAR_NUMBER)
&& type != TYPE_MATCH && type != TYPE_NOMATCH)
{
n1 = get_tv_number(rettv);
@@ -2631,6 +2717,7 @@ eval5(arg, rettv, evaluate)
int evaluate;
{
typeval var2;
+ typeval var3;
int op;
long n1, n2;
char_u *s1, *s2;
@@ -2682,6 +2769,19 @@ eval5(arg, rettv, evaluate)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = p;
}
+ else if (rettv->v_type == VAR_LIST && var2.v_type == VAR_LIST)
+ {
+ /* concatenate Lists */
+ if (list_concat(rettv->vval.v_list, var2.vval.v_list,
+ &var3) == FAIL)
+ {
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ clear_tv(rettv);
+ *rettv = var3;
+ }
else
{
n1 = get_tv_number(rettv);
@@ -3589,6 +3689,66 @@ list_len(l)
}
/*
+ * Return TRUE when two lists have exactly the same values.
+ */
+ static int
+list_equal(l1, l2, ic)
+ listvar *l1;
+ listvar *l2;
+ int ic; /* ignore case for strings */
+{
+ listitem *item1, *item2;
+
+ for (item1 = l1->lv_first, item2 = l2->lv_first;
+ item1 != NULL && item2 != NULL;
+ item1 = item1->li_next, item2 = item2->li_next)
+ if (!tv_equal(&item1->li_tv, &item2->li_tv, ic))
+ return FALSE;
+ return item1 == NULL && item2 == NULL;
+}
+
+/*
+ * Return TRUE if "tv1" and "tv2" have the same value.
+ * Compares the items just like "==" would compare them.
+ */
+ static int
+tv_equal(tv1, tv2, ic)
+ typeval *tv1;
+ typeval *tv2;
+ int ic; /* ignore case */
+{
+ char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+
+ if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST)
+ {
+ /* recursive! */
+ if (tv1->v_type != tv2->v_type
+ || !list_equal(tv1->vval.v_list, tv2->vval.v_list, ic))
+ return FALSE;
+ }
+ else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC)
+ {
+ if (tv1->v_type != tv2->v_type
+ || tv1->vval.v_string == NULL
+ || tv2->vval.v_string == NULL
+ || STRCMP(tv1->vval.v_string, tv2->vval.v_string) != 0)
+ return FALSE;
+ }
+ else if (tv1->v_type == VAR_NUMBER || tv2->v_type == VAR_NUMBER)
+ {
+ if (get_tv_number(tv1) != get_tv_number(tv2))
+ return FALSE;
+ }
+ else if (!ic && STRCMP(get_tv_string_buf(tv1, buf1),
+ get_tv_string_buf(tv2, buf2)) != 0)
+ return FALSE;
+ else if (ic && STRICMP(get_tv_string_buf(tv1, buf1),
+ get_tv_string_buf(tv2, buf2)) != 0)
+ return FALSE;
+ return TRUE;
+}
+
+/*
* Locate item with index "n" in list "l" and return it.
* A negative index is counted from the end; -1 is the last item.
* Returns NULL when "n" is out of range.
@@ -3621,6 +3781,39 @@ list_find(l, n)
}
/*
+ * Like list_find(), but also find an item just past the end.
+ * "*ip" is the item to find.
+ * When found "*ip" is set to zero, when not found "*ip" is non-zero.
+ * Returns NULL when item not found or item is just past the end.
+ */
+ static listitem *
+list_find_ext(l, ip)
+ listvar *l;
+ long *ip;
+{
+ long n;
+ listitem *item;
+
+ if (*ip < 0)
+ {
+ /* Count from the end: -1 is before last item. */
+ item = l->lv_last;
+ for (n = *ip + 1; n < 0 && item != NULL; ++n)
+ item = item->li_prev;
+ if (item == NULL)
+ n = 1; /* error! */
+ }
+ else
+ {
+ item = l->lv_first;
+ for (n = *ip; n > 0 && item != NULL; --n)
+ item = item->li_next;
+ }
+ *ip = n;
+ return item;
+}
+
+/*
* Append item "item" to the end of list "l".
*/
static void
@@ -3646,6 +3839,7 @@ list_append(l, item)
/*
* Append typeval "tv" to the end of list "l".
+ * Return FAIL when out of memory.
*/
static int
list_append_tv(l, tv)
@@ -3662,6 +3856,81 @@ list_append_tv(l, tv)
}
/*
+ * Insert typeval "tv" in list "l" before "item".
+ * If "item" is NULL append at the end.
+ * Return FAIL when out of memory.
+ */
+ static int
+list_insert_tv(l, tv, item)
+ listvar *l;
+ typeval *tv;
+ listitem *item;
+{
+ listitem *ni = listitem_alloc();
+
+ if (ni == NULL)
+ return FAIL;
+ copy_tv(tv, &ni->li_tv);
+ if (item == NULL)
+ /* Append new item at end of list. */
+ list_append(l, ni);
+ else
+ {
+ /* Insert new item before existing item. */
+ ni->li_prev = item->li_prev;
+ ni->li_next = item;
+ if (item->li_prev == NULL)
+ l->lv_first = ni;
+ else
+ item->li_prev->li_next = ni;
+ item->li_prev = ni;
+ }
+ return OK;
+}
+
+/*
+ * Extend "l1" with "l2".
+ * If "bef" is NULL append at the end, otherwise insert before this item.
+ * Returns FAIL when out of memory.
+ */
+ static int
+list_extend(l1, l2, bef)
+ listvar *l1;
+ listvar *l2;
+ listitem *bef;
+{
+ listitem *item;
+
+ for (item = l2->lv_first; item != NULL; item = item->li_next)
+ if (list_insert_tv(l1, &item->li_tv, bef) == FAIL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Concatenate lists "l1" and "l2" into a new list, stored in "tv".
+ * Return FAIL when out of memory.
+ */
+ static int
+list_concat(l1, l2, tv)
+ listvar *l1;
+ listvar *l2;
+ typeval *tv;
+{
+ listvar *l;
+
+ /* make a copy of the first list. */
+ l = list_copy(l1, FALSE);
+ if (l == NULL)
+ return FAIL;
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = l;
+
+ /* append all items from the second list */
+ return list_extend(l, l2, NULL);
+}
+
+/*
* Make a copy of list "l". Shallow if "deep" is FALSE.
* The refcount of the new list is set to 1.
* Returns NULL when out of memory.
@@ -3716,30 +3985,32 @@ list_copy(orig, deep)
}
/*
- * Remove item with index "n" from list "l" and return it.
- * Returns NULL when "n" is out of range.
+ * Remove items "item" to "item2" from list "l".
*/
- static listitem *
-list_getrem(l, n)
+ static void
+list_getrem(l, item, item2)
listvar *l;
- long n;
-{
listitem *item;
+ listitem *item2;
+{
+ listitem *ip;
- item = list_find(l, n);
- if (item != NULL)
+ /* notify watchers */
+ for (ip = item; ip != NULL; ip = ip->li_next)
{
- list_fix_watch(l, item); /* notify watchers */
- if (item->li_next == NULL)
- l->lv_last = item->li_prev;
- else
- item->li_next->li_prev = item->li_prev;
- if (item->li_prev == NULL)
- l->lv_first = item->li_next;
- else
- item->li_prev->li_next = item->li_next;
+ list_fix_watch(l, ip);
+ if (ip == item2)
+ break;
}
- return item;
+
+ if (item2->li_next == NULL)
+ l->lv_last = item->li_prev;
+ else
+ item2->li_next->li_prev = item->li_prev;
+ if (item->li_prev == NULL)
+ l->lv_first = item2->li_next;
+ else
+ item->li_prev->li_next = item2->li_next;
}
/*
@@ -3755,6 +4026,7 @@ list2string(tv)
int first = TRUE;
char_u *tofree;
char_u *s;
+ char_u numbuf[NUMBUFLEN];
if (tv->vval.v_list == NULL)
return NULL;
@@ -3768,7 +4040,7 @@ list2string(tv)
else
ga_concat(&ga, (char_u *)", ");
- s = tv2string(&item->li_tv, &tofree);
+ s = tv2string(&item->li_tv, &tofree, numbuf);
if (s != NULL)
ga_concat(&ga, s);
vim_free(tofree);
@@ -3782,14 +4054,14 @@ list2string(tv)
/*
* Return a string with the string representation of a variable.
* If the memory is allocated "tofree" is set to it, otherwise NULL.
- * Can only be used once before the value is used, it may call
- * get_var_string().
+ * "numbuf" is used for a number.
* May return NULL;
*/
static char_u *
-tv2string(tv, tofree)
+tv2string(tv, tofree, numbuf)
typeval *tv;
char_u **tofree;
+ char_u *numbuf;
{
switch (tv->v_type)
{
@@ -3806,7 +4078,7 @@ tv2string(tv, tofree)
EMSG2(_(e_intern2), "tv2string()");
}
*tofree = NULL;
- return get_tv_string(tv);
+ return get_tv_string_buf(tv, numbuf);
}
/*
@@ -3888,11 +4160,13 @@ static struct fst
{"bufwinnr", 1, 1, f_bufwinnr},
{"byte2line", 1, 1, f_byte2line},
{"byteidx", 2, 2, f_byteidx},
+ {"call", 2, 2, f_call},
{"char2nr", 1, 1, f_char2nr},
{"cindent", 1, 1, f_cindent},
{"col", 1, 1, f_col},
{"confirm", 1, 4, f_confirm},
{"copy", 1, 1, f_copy},
+ {"count", 2, 3, f_count},
{"cscope_connection",0,3, f_cscope_connection},
{"cursor", 2, 2, f_cursor},
{"deepcopy", 1, 1, f_deepcopy},
@@ -3905,6 +4179,7 @@ static struct fst
{"executable", 1, 1, f_executable},
{"exists", 1, 1, f_exists},
{"expand", 1, 2, f_expand},
+ {"extend", 2, 3, f_extend},
{"file_readable", 1, 1, f_filereadable}, /* obsolete */
{"filereadable", 1, 1, f_filereadable},
{"filewritable", 1, 1, f_filewritable},
@@ -3950,6 +4225,7 @@ static struct fst
{"hostname", 0, 0, f_hostname},
{"iconv", 3, 3, f_iconv},
{"indent", 1, 1, f_indent},
+ {"index", 2, 3, f_index},
{"input", 1, 2, f_input},
{"inputdialog", 1, 3, f_inputdialog},
{"inputrestore", 0, 0, f_inputrestore},
@@ -3979,7 +4255,7 @@ static struct fst
{"remote_peek", 1, 2, f_remote_peek},
{"remote_read", 1, 1, f_remote_read},
{"remote_send", 2, 3, f_remote_send},
- {"remove", 2, 2, f_remove},
+ {"remove", 2, 3, f_remove},
{"rename", 2, 2, f_rename},
{"repeat", 2, 2, f_repeat},
{"resolve", 1, 1, f_resolve},
@@ -4402,13 +4678,17 @@ f_append(argvars, rettv)
typeval *rettv;
{
long lnum;
+ listvar *l;
rettv->vval.v_number = 1; /* Default: Failed */
if (argvars[0].v_type == VAR_LIST)
{
- if (argvars[0].vval.v_list != NULL
- && list_append_tv(argvars[0].vval.v_list, &argvars[1]) == OK)
+ l = argvars[0].vval.v_list;
+ if (l != NULL && list_append_tv(l, &argvars[1]) == OK)
+ {
+ ++l->lv_refcount;
copy_tv(&argvars[0], rettv);
+ }
}
else
{
@@ -4762,6 +5042,55 @@ f_byteidx(argvars, rettv)
}
/*
+ * "call(func, arglist)" function
+ */
+ static void
+f_call(argvars, rettv)
+ typeval *argvars;
+ typeval *rettv;
+{
+ char_u *func;
+ typeval argv[MAX_FUNC_ARGS];
+ int argc = 0;
+ listitem *item;
+ int dummy;
+
+ rettv->vval.v_number = 0;
+ if (argvars[1].v_type != VAR_LIST)
+ {
+ EMSG(_(e_listreq));
+ return;
+ }
+ if (argvars[1].vval.v_list == NULL)
+ return;
+
+ if (argvars[0].v_type == VAR_FUNC)
+ func = argvars[0].vval.v_string;
+ else
+ func = get_tv_string(&argvars[0]);
+
+ for (item = argvars[1].vval.v_list->lv_first; item != NULL;
+ item = item->li_next)
+ {
+ if (argc == MAX_FUNC_ARGS)
+ {
+ EMSG(_("E999: Too many arguments"));
+ break;
+ }
+ /* Make a copy of each argument (is this really needed?) */
+ copy_tv(&item->li_tv, &argv[argc++]);
+ }
+
+ if (item == NULL)
+ (void)call_func(func, STRLEN(func), rettv, argc, argv,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy, TRUE);
+
+ /* Free the arguments. */
+ while (argc > 0)
+ clear_tv(&argv[--argc]);
+}
+
+/*
* "char2nr(string)" function
*/
static void
@@ -4924,6 +5253,33 @@ f_copy(argvars, rettv)
}
/*
+ * "count()" function
+ */
+ static void
+f_count(argvars, rettv)
+ typeval *argvars;
+ typeval *rettv;
+{
+ listitem *li;
+ long n = 0;
+ int ic = FALSE;
+
+ if (argvars[0].v_type != VAR_LIST)
+ EMSG(_(e_listreq));
+ else if (argvars[0].vval.v_list != NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ ic = get_tv_number(&argvars[2]);
+
+ for (li = argvars[0].vval.v_list->lv_first; li != NULL;
+ li = li->li_next)
+ if (tv_equal(&li->li_tv, &argvars[1], ic))
+ ++n;
+ }
+ rettv->vval.v_number = n;
+}
+
+/*
* "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
*
* Checks the existence of a cscope connection.
@@ -5263,6 +5619,48 @@ f_expand(argvars, rettv)
}
/*
+ * "extend(list, list [, idx])" function
+ */
+ static void
+f_extend(argvars, rettv)
+ typeval *argvars;
+ typeval *rettv;
+{
+ long before;
+ long n;
+ listitem *item;
+ listvar *l1, *l2;
+
+ rettv->vval.v_number = 0;
+ if (argvars[0].v_type != VAR_LIST || argvars[1].v_type != VAR_LIST)
+ {
+ EMSG(_(e_listreq));
+ return;
+ }
+ l1 = argvars[0].vval.v_list;
+ l2 = argvars[1].vval.v_list;
+ if (l1 != NULL && l2 != NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ n = before = get_tv_number(&argvars[2]);
+ item = list_find_ext(l1, &n);
+ if (n != 0)
+ {
+ EMSGN(_(e_listidx), before);
+ return;
+ }
+ }
+ else
+ item = NULL;
+ list_extend(l1, l2, item);
+
+ ++l1->lv_refcount;
+ copy_tv(&argvars[0], rettv);
+ }
+}
+
+/*
* "filereadable()" function
*/
static void
@@ -6916,6 +7314,40 @@ f_indent(argvars, rettv)
rettv->vval.v_number = -1;
}
+/*
+ * "index()" function
+ */
+ static void
+f_index(argvars, rettv)
+ typeval *argvars;
+ typeval *rettv;
+{
+ listvar *l;
+ listitem *item;
+ long idx = 0;
+ int ic = FALSE;
+
+ rettv->vval.v_number = -1;
+ if (argvars[0].v_type != VAR_LIST)
+ {
+ EMSG(_(e_listreq));
+ return;
+ }
+ l = argvars[0].vval.v_list;
+ if (l != NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ ic = get_tv_number(&argvars[2]);
+
+ for (item = l->lv_first; item != NULL; item = item->li_next, ++idx)
+ if (tv_equal(&item->li_tv, &argvars[1], ic))
+ {
+ rettv->vval.v_number = idx;
+ break;
+ }
+ }
+}
+
static int inputsecret_flag = 0;
/*
@@ -7093,7 +7525,6 @@ f_insert(argvars, rettv)
long before = 0;
long n;
listitem *item;
- listitem *ni;
listvar *l;
if (argvars[0].v_type != VAR_LIST)
@@ -7103,46 +7534,15 @@ f_insert(argvars, rettv)
if (argvars[2].v_type != VAR_UNKNOWN)
before = get_tv_number(&argvars[2]);
- if (before < 0)
- {
- /* Count from the end: -1 is before last item. */
- item = l->lv_last;
- for (n = before + 1; n < 0 && item != NULL; ++n)
- item = item->li_prev;
- if (item == NULL)
- n = 1; /* report an error, don't append */
- }
- else
- {
- /* Can't use list_find() here, we allow one past the end. */
- item = l->lv_first;
- for (n = before; n > 0 && item != NULL; --n)
- item = item->li_next;
- }
+ n = before;
+ item = list_find_ext(l, &n);
if (n > 0)
EMSGN(_(e_listidx), before);
else
{
- ni = listitem_alloc();
- if (ni != NULL)
- {
- copy_tv(&argvars[1], &ni->li_tv);
- if (item == NULL)
- /* Append new item at end of list. */
- list_append(l, ni);
- else
- {
- /* Insert new item before existing item. */
- ni->li_prev = item->li_prev;
- ni->li_next = item;
- if (item->li_prev == NULL)
- l->lv_first = ni;
- else
- item->li_prev->li_next = ni;
- item->li_prev = ni;
- }
- copy_tv(&argvars[0], rettv);
- }
+ list_insert_tv(l, &argvars[1], item);
+ ++l->lv_refcount;
+ copy_tv(&argvars[0], rettv);
}
}
}
@@ -7595,7 +7995,7 @@ f_nr2char(argvars, rettv)
}
/*
- * "remove({list}, {idx})" function
+ * "remove({list}, {idx} [, {end}])" function
*/
static void
f_remove(argvars, rettv)
@@ -7603,21 +8003,59 @@ f_remove(argvars, rettv)
typeval *rettv;
{
listvar *l;
- listitem *item;
+ listitem *item, *item2;
+ listitem *li;
long idx;
+ long end;
+ rettv->vval.v_number = 0;
if (argvars[0].v_type != VAR_LIST)
EMSG(_("E999: First argument of remove() must be a list"));
else if ((l = argvars[0].vval.v_list) != NULL)
{
idx = get_tv_number(&argvars[1]);
- item = list_getrem(l, idx);
+ item = list_find(l, idx);
if (item == NULL)
EMSGN(_(e_listidx), idx);
else
{
- *rettv = item->li_tv;
- vim_free(item);
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ {
+ /* Remove one item, return its value. */
+ list_getrem(l, item, item);
+ *rettv = item->li_tv;
+ vim_free(item);
+ }
+ else
+ {
+ /* Remove range of items, return list with values. */
+ end = get_tv_number(&argvars[2]);
+ item2 = list_find(l, end);
+ if (item2 == NULL)
+ EMSGN(_(e_listidx), end);
+ else
+ {
+ for (li = item; li != item2 && li != NULL; li = li->li_next)
+ ;
+ if (li == NULL) /* didn't find "item2" after "item" */
+ EMSG(_(e_invrange));
+ else
+ {
+ list_getrem(l, item, item2);
+ l = list_alloc();
+ if (l != NULL)
+ {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = l;
+ l->lv_first = item;
+ l->lv_last = item2;
+ l->lv_refcount = 1;
+ item->li_prev = NULL;
+ item2->li_next = NULL;
+ }
+ }
+ }
+ }
}
}
}
@@ -7640,6 +8078,60 @@ f_rename(argvars, rettv)
}
/*
+ * "repeat()" function
+ */
+/*ARGSUSED*/
+ static void
+f_repeat(argvars, rettv)
+ typeval *argvars;
+ typeval *rettv;
+{
+ char_u *p;
+ int n;
+ int slen;
+ int len;
+ char_u *r;
+ int i;
+ listvar *l;
+
+ n = get_tv_number(&argvars[1]);
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ l = list_alloc();
+ if (l != NULL && argvars[0].vval.v_list != NULL)
+ {
+ l->lv_refcount = 1;
+ while (n-- > 0)
+ if (list_extend(l, argvars[0].vval.v_list, NULL) == FAIL)
+ break;
+ }
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = l;
+ }
+ else
+ {
+ p = get_tv_string(&argvars[0]);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ slen = (int)STRLEN(p);
+ len = slen * n;
+ if (len <= 0)
+ return;
+
+ r = alloc(len + 1);
+ if (r != NULL)
+ {
+ for (i = 0; i < n; i++)
+ mch_memmove(r + i * slen, p, (size_t)slen);
+ r[len] = NUL;
+ }
+
+ rettv->vval.v_string = r;
+ }
+}
+
+/*
* "resolve()" function
*/
static void
@@ -8637,45 +9129,6 @@ f_remote_foreground(argvars, rettv)
#endif
}
-/*
- * "repeat()" function
- */
-/*ARGSUSED*/
- static void
-f_repeat(argvars, rettv)
- typeval *argvars;
- typeval *rettv;
-{
- char_u *p;
- int n;
- int slen;
- int len;
- char_u *r;
- int i;
-
- p = get_tv_string(&argvars[0]);
- n = get_tv_number(&argvars[1]);
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- slen = (int)STRLEN(p);
- len = slen * n;
-
- if (len <= 0)
- return;
-
- r = alloc(len + 1);
- if (r != NULL)
- {
- for (i = 0; i < n; i++)
- mch_memmove(r + i * slen, p, (size_t)slen);
- r[len] = NUL;
- }
-
- rettv->vval.v_string = r;
-}
-
#ifdef HAVE_STRFTIME
/*
* "strftime({format}[, {time}])" function
@@ -8804,9 +9257,10 @@ f_string(argvars, rettv)
typeval *rettv;
{
char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = tv2string(&argvars[0], &tofree);
+ rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf);
if (tofree == NULL)
rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
}
@@ -10475,8 +10929,9 @@ list_one_var(v, prefix)
{
char_u *tofree;
char_u *s;
+ char_u numbuf[NUMBUFLEN];
- s = tv2string(&v->tv, &tofree);
+ s = tv2string(&v->tv, &tofree, numbuf);
list_one_var_a(prefix, v->v_name, v->tv.v_type,
s == NULL ? (char_u *)"" : s);
vim_free(tofree);
@@ -10699,6 +11154,7 @@ ex_echo(eap)
char_u *p;
int needclr = TRUE;
int atstart = TRUE;
+ char_u numbuf[NUMBUFLEN];
if (eap->skip)
++emsg_skip;
@@ -10728,7 +11184,8 @@ ex_echo(eap)
}
else if (eap->cmdidx == CMD_echo)
msg_puts_attr((char_u *)" ", echo_attr);
- for (p = tv2string(&rettv, &tofree); *p != NUL && !got_int; ++p)
+ for (p = tv2string(&rettv, &tofree, numbuf);
+ *p != NUL && !got_int; ++p)
if (*p == '\n' || *p == '\r' || *p == TAB)
{
if (*p != TAB && needclr)
@@ -11938,11 +12395,12 @@ get_return_cmd(rettv)
{
char_u *s;
char_u *tofree = NULL;
+ char_u numbuf[NUMBUFLEN];
if (rettv == NULL)
s = (char_u *)"";
else
- s = tv2string((typeval *)rettv, &tofree);
+ s = tv2string((typeval *)rettv, &tofree, numbuf);
STRCPY(IObuff, ":return ");
STRNCPY(IObuff + 8, s, IOSIZE - 8);
@@ -12112,6 +12570,7 @@ write_viminfo_varlist(fp)
int i;
char *s;
char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
if (find_viminfo_parameter('!') == NULL)
return;
@@ -12130,7 +12589,7 @@ write_viminfo_varlist(fp)
default: continue;
}
fprintf(fp, "!%s\t%s\t", this_var->v_name, s);
- viminfo_writestring(fp, tv2string(&this_var->tv, &tofree));
+ viminfo_writestring(fp, tv2string(&this_var->tv, &tofree, numbuf));
vim_free(tofree);
}
}