forked from aniani/vim
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.
This commit is contained in:
374
src/list.c
374
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)
|
||||
|
||||
Reference in New Issue
Block a user