diff src/list.c @ 17970:684a15da9929 v8.1.1981

patch 8.1.1981: the evalfunc.c file is too big Commit: https://github.com/vim/vim/commit/08c308aeb5e7dfa18fa61f261b0bff79517a4883 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 4 17:48:15 2019 +0200 patch 8.1.1981: the evalfunc.c file is too big Problem: The evalfunc.c file is too big. Solution: Move undo functions to undo.c. Move cmdline functions to ex_getln.c. Move some container functions to list.c.
author Bram Moolenaar <Bram@vim.org>
date Wed, 04 Sep 2019 18:00:03 +0200
parents 6d4d3bce365d
children f41b55f9357c
line wrap: on
line diff
--- a/src/list.c
+++ b/src/list.c
@@ -8,13 +8,15 @@
  */
 
 /*
- * list.c: List support
+ * list.c: List support and container (List, Dict, Blob) functions.
  */
 
 #include "vim.h"
 
 #if defined(FEAT_EVAL) || defined(PROTO)
 
+static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
+
 /* List heads for garbage collection. */
 static list_T		*first_list = NULL;	/* list of all lists */
 
@@ -1763,4 +1765,374 @@ f_map(typval_T *argvars, typval_T *rettv
     filter_map(argvars, rettv, TRUE);
 }
 
+/*
+ * "add(list, item)" function
+ */
+    void
+f_add(typval_T *argvars, typval_T *rettv)
+{
+    list_T	*l;
+    blob_T	*b;
+
+    rettv->vval.v_number = 1; /* Default: Failed */
+    if (argvars[0].v_type == VAR_LIST)
+    {
+	if ((l = argvars[0].vval.v_list) != NULL
+		&& !var_check_lock(l->lv_lock,
+					 (char_u *)N_("add() argument"), TRUE)
+		&& list_append_tv(l, &argvars[1]) == OK)
+	    copy_tv(&argvars[0], rettv);
+    }
+    else if (argvars[0].v_type == VAR_BLOB)
+    {
+	if ((b = argvars[0].vval.v_blob) != NULL
+		&& !var_check_lock(b->bv_lock,
+					 (char_u *)N_("add() argument"), TRUE))
+	{
+	    int		error = FALSE;
+	    varnumber_T n = tv_get_number_chk(&argvars[1], &error);
+
+	    if (!error)
+	    {
+		ga_append(&b->bv_ga, (int)n);
+		copy_tv(&argvars[0], rettv);
+	    }
+	}
+    }
+    else
+	emsg(_(e_listblobreq));
+}
+
+/*
+ * "count()" function
+ */
+    void
+f_count(typval_T *argvars, typval_T *rettv)
+{
+    long	n = 0;
+    int		ic = FALSE;
+    int		error = FALSE;
+
+    if (argvars[2].v_type != VAR_UNKNOWN)
+	ic = (int)tv_get_number_chk(&argvars[2], &error);
+
+    if (argvars[0].v_type == VAR_STRING)
+    {
+	char_u *expr = tv_get_string_chk(&argvars[1]);
+	char_u *p = argvars[0].vval.v_string;
+	char_u *next;
+
+	if (!error && expr != NULL && *expr != NUL && p != NULL)
+	{
+	    if (ic)
+	    {
+		size_t len = STRLEN(expr);
+
+		while (*p != NUL)
+		{
+		    if (MB_STRNICMP(p, expr, len) == 0)
+		    {
+			++n;
+			p += len;
+		    }
+		    else
+			MB_PTR_ADV(p);
+		}
+	    }
+	    else
+		while ((next = (char_u *)strstr((char *)p, (char *)expr))
+								       != NULL)
+		{
+		    ++n;
+		    p = next + STRLEN(expr);
+		}
+	}
+
+    }
+    else if (argvars[0].v_type == VAR_LIST)
+    {
+	listitem_T	*li;
+	list_T		*l;
+	long		idx;
+
+	if ((l = argvars[0].vval.v_list) != NULL)
+	{
+	    li = l->lv_first;
+	    if (argvars[2].v_type != VAR_UNKNOWN)
+	    {
+		if (argvars[3].v_type != VAR_UNKNOWN)
+		{
+		    idx = (long)tv_get_number_chk(&argvars[3], &error);
+		    if (!error)
+		    {
+			li = list_find(l, idx);
+			if (li == NULL)
+			    semsg(_(e_listidx), idx);
+		    }
+		}
+		if (error)
+		    li = NULL;
+	    }
+
+	    for ( ; li != NULL; li = li->li_next)
+		if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
+		    ++n;
+	}
+    }
+    else if (argvars[0].v_type == VAR_DICT)
+    {
+	int		todo;
+	dict_T		*d;
+	hashitem_T	*hi;
+
+	if ((d = argvars[0].vval.v_dict) != NULL)
+	{
+	    if (argvars[2].v_type != VAR_UNKNOWN)
+	    {
+		if (argvars[3].v_type != VAR_UNKNOWN)
+		    emsg(_(e_invarg));
+	    }
+
+	    todo = error ? 0 : (int)d->dv_hashtab.ht_used;
+	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+	    {
+		if (!HASHITEM_EMPTY(hi))
+		{
+		    --todo;
+		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
+			++n;
+		}
+	    }
+	}
+    }
+    else
+	semsg(_(e_listdictarg), "count()");
+    rettv->vval.v_number = n;
+}
+
+/*
+ * "extend(list, list [, idx])" function
+ * "extend(dict, dict [, action])" function
+ */
+    void
+f_extend(typval_T *argvars, typval_T *rettv)
+{
+    char_u      *arg_errmsg = (char_u *)N_("extend() argument");
+
+    if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
+    {
+	list_T		*l1, *l2;
+	listitem_T	*item;
+	long		before;
+	int		error = FALSE;
+
+	l1 = argvars[0].vval.v_list;
+	l2 = argvars[1].vval.v_list;
+	if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
+		&& l2 != NULL)
+	{
+	    if (argvars[2].v_type != VAR_UNKNOWN)
+	    {
+		before = (long)tv_get_number_chk(&argvars[2], &error);
+		if (error)
+		    return;		/* type error; errmsg already given */
+
+		if (before == l1->lv_len)
+		    item = NULL;
+		else
+		{
+		    item = list_find(l1, before);
+		    if (item == NULL)
+		    {
+			semsg(_(e_listidx), before);
+			return;
+		    }
+		}
+	    }
+	    else
+		item = NULL;
+	    list_extend(l1, l2, item);
+
+	    copy_tv(&argvars[0], rettv);
+	}
+    }
+    else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
+    {
+	dict_T	*d1, *d2;
+	char_u	*action;
+	int	i;
+
+	d1 = argvars[0].vval.v_dict;
+	d2 = argvars[1].vval.v_dict;
+	if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
+		&& d2 != NULL)
+	{
+	    /* Check the third argument. */
+	    if (argvars[2].v_type != VAR_UNKNOWN)
+	    {
+		static char *(av[]) = {"keep", "force", "error"};
+
+		action = tv_get_string_chk(&argvars[2]);
+		if (action == NULL)
+		    return;		/* type error; errmsg already given */
+		for (i = 0; i < 3; ++i)
+		    if (STRCMP(action, av[i]) == 0)
+			break;
+		if (i == 3)
+		{
+		    semsg(_(e_invarg2), action);
+		    return;
+		}
+	    }
+	    else
+		action = (char_u *)"force";
+
+	    dict_extend(d1, d2, action);
+
+	    copy_tv(&argvars[0], rettv);
+	}
+    }
+    else
+	semsg(_(e_listdictarg), "extend()");
+}
+
+/*
+ * "insert()" function
+ */
+    void
+f_insert(typval_T *argvars, typval_T *rettv)
+{
+    long	before = 0;
+    listitem_T	*item;
+    list_T	*l;
+    int		error = FALSE;
+
+    if (argvars[0].v_type == VAR_BLOB)
+    {
+	int	    val, len;
+	char_u	    *p;
+
+	len = blob_len(argvars[0].vval.v_blob);
+	if (argvars[2].v_type != VAR_UNKNOWN)
+	{
+	    before = (long)tv_get_number_chk(&argvars[2], &error);
+	    if (error)
+		return;		// type error; errmsg already given
+	    if (before < 0 || before > len)
+	    {
+		semsg(_(e_invarg2), tv_get_string(&argvars[2]));
+		return;
+	    }
+	}
+	val = tv_get_number_chk(&argvars[1], &error);
+	if (error)
+	    return;
+	if (val < 0 || val > 255)
+	{
+	    semsg(_(e_invarg2), tv_get_string(&argvars[1]));
+	    return;
+	}
+
+	if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
+	    return;
+	p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
+	mch_memmove(p + before + 1, p + before, (size_t)len - before);
+	*(p + before) = val;
+	++argvars[0].vval.v_blob->bv_ga.ga_len;
+
+	copy_tv(&argvars[0], rettv);
+    }
+    else if (argvars[0].v_type != VAR_LIST)
+	semsg(_(e_listblobarg), "insert()");
+    else if ((l = argvars[0].vval.v_list) != NULL
+	    && !var_check_lock(l->lv_lock,
+				     (char_u *)N_("insert() argument"), TRUE))
+    {
+	if (argvars[2].v_type != VAR_UNKNOWN)
+	    before = (long)tv_get_number_chk(&argvars[2], &error);
+	if (error)
+	    return;		/* type error; errmsg already given */
+
+	if (before == l->lv_len)
+	    item = NULL;
+	else
+	{
+	    item = list_find(l, before);
+	    if (item == NULL)
+	    {
+		semsg(_(e_listidx), before);
+		l = NULL;
+	    }
+	}
+	if (l != NULL)
+	{
+	    list_insert_tv(l, &argvars[1], item);
+	    copy_tv(&argvars[0], rettv);
+	}
+    }
+}
+
+/*
+ * "remove()" function
+ */
+    void
+f_remove(typval_T *argvars, typval_T *rettv)
+{
+    char_u	*arg_errmsg = (char_u *)N_("remove() argument");
+
+    if (argvars[0].v_type == VAR_DICT)
+	dict_remove(argvars, rettv, arg_errmsg);
+    else if (argvars[0].v_type == VAR_BLOB)
+	blob_remove(argvars, rettv);
+    else if (argvars[0].v_type == VAR_LIST)
+	list_remove(argvars, rettv, arg_errmsg);
+    else
+	semsg(_(e_listdictblobarg), "remove()");
+}
+
+/*
+ * "reverse({list})" function
+ */
+    void
+f_reverse(typval_T *argvars, typval_T *rettv)
+{
+    list_T	*l;
+    listitem_T	*li, *ni;
+
+    if (argvars[0].v_type == VAR_BLOB)
+    {
+	blob_T	*b = argvars[0].vval.v_blob;
+	int	i, len = blob_len(b);
+
+	for (i = 0; i < len / 2; i++)
+	{
+	    int tmp = blob_get(b, i);
+
+	    blob_set(b, i, blob_get(b, len - i - 1));
+	    blob_set(b, len - i - 1, tmp);
+	}
+	rettv_blob_set(rettv, b);
+	return;
+    }
+
+    if (argvars[0].v_type != VAR_LIST)
+	semsg(_(e_listblobarg), "reverse()");
+    else if ((l = argvars[0].vval.v_list) != NULL
+	    && !var_check_lock(l->lv_lock,
+				    (char_u *)N_("reverse() argument"), TRUE))
+    {
+	li = l->lv_last;
+	l->lv_first = l->lv_last = NULL;
+	l->lv_len = 0;
+	while (li != NULL)
+	{
+	    ni = li->li_prev;
+	    list_append(l, li);
+	    li = ni;
+	}
+	rettv_list_set(rettv, l);
+	l->lv_idx = l->lv_len - l->lv_idx - 1;
+    }
+}
+
 #endif // defined(FEAT_EVAL)