mirror of
https://github.com/neovim/neovim.git
synced 2025-10-08 10:56:31 +00:00
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.
08c308aeb5
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "nvim/gettext_defs.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
|
||||
@@ -101,6 +103,7 @@ EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"
|
||||
EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\""));
|
||||
EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
|
||||
EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
|
||||
EXTERN const char e_listblobarg[] INIT(= N_("E899: Argument of %s must be a List or Blob"));
|
||||
EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
|
||||
EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
|
||||
EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
|
||||
@@ -141,6 +144,7 @@ EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive
|
||||
EXTERN const char e_menu_only_exists_in_another_mode[]
|
||||
INIT(= N_("E328: Menu only exists in another mode"));
|
||||
EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
|
||||
EXTERN const char e_list_index_out_of_range_nr[] INIT(= N_("E684: List index out of range: %" PRId64));
|
||||
EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
|
||||
EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
|
||||
EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
|
||||
|
@@ -15,9 +15,6 @@
|
||||
|
||||
#include "eval/executor.c.generated.h"
|
||||
|
||||
char *e_list_index_out_of_range_nr
|
||||
= N_("E684: List index out of range: %" PRId64);
|
||||
|
||||
/// Handle "blob1 += blob2".
|
||||
/// Returns OK or FAIL.
|
||||
static int tv_op_blob(typval_T *tv1, const typval_T *tv2, const char *op)
|
||||
|
@@ -2,6 +2,4 @@
|
||||
|
||||
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
||||
|
||||
extern char *e_list_index_out_of_range_nr;
|
||||
|
||||
#include "eval/executor.h.generated.h"
|
||||
|
@@ -157,10 +157,7 @@ PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
|
||||
PRAGMA_DIAG_POP
|
||||
PRAGMA_DIAG_POP
|
||||
|
||||
static const char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
|
||||
static const char *e_invalwindow = N_("E957: Invalid window number");
|
||||
static const char e_argument_of_str_must_be_list_string_or_dictionary[]
|
||||
= N_("E706: Argument of %s must be a List, String or Dictionary");
|
||||
static const char e_invalid_submatch_number_nr[]
|
||||
= N_("E935: Invalid submatch number: %d");
|
||||
static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
|
||||
@@ -398,34 +395,6 @@ static void f_abs(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "add(list, item)" function
|
||||
static void f_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = 1; // Default: failed.
|
||||
if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (!value_check_lock(tv_list_locked(l), N_("add() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
tv_list_append_tv(l, &argvars[1]);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
if (b != NULL
|
||||
&& !value_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
|
||||
bool error = false;
|
||||
const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
|
||||
|
||||
if (!error) {
|
||||
ga_append(&b->bv_ga, (uint8_t)n);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emsg(_(e_listblobreq));
|
||||
}
|
||||
}
|
||||
|
||||
/// "and(expr, expr)" function
|
||||
static void f_and(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -853,125 +822,6 @@ static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
var_item_copy(NULL, &argvars[0], rettv, false, 0);
|
||||
}
|
||||
|
||||
/// Count the number of times "needle" occurs in string "haystack".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_string(const char *haystack, const char *needle, bool ic)
|
||||
{
|
||||
varnumber_T n = 0;
|
||||
const char *p = haystack;
|
||||
|
||||
if (p == NULL || needle == NULL || *needle == NUL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ic) {
|
||||
const size_t len = strlen(needle);
|
||||
|
||||
while (*p != NUL) {
|
||||
if (mb_strnicmp(p, needle, len) == 0) {
|
||||
n++;
|
||||
p += len;
|
||||
} else {
|
||||
MB_PTR_ADV(p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const char *next;
|
||||
while ((next = strstr(p, needle)) != NULL) {
|
||||
n++;
|
||||
p = next + strlen(needle);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in List "l" starting at index "idx".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic)
|
||||
{
|
||||
if (tv_list_len(l) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
listitem_T *li = tv_list_find(l, (int)idx);
|
||||
if (li == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in Dict "d".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic)
|
||||
{
|
||||
if (d == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
TV_DICT_ITER(d, di, {
|
||||
if (tv_equal(&di->di_tv, needle, ic)) {
|
||||
n++;
|
||||
}
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// "count()" function
|
||||
static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
varnumber_T n = 0;
|
||||
int ic = 0;
|
||||
bool error = false;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
ic = (int)tv_get_number_chk(&argvars[2], &error);
|
||||
}
|
||||
|
||||
if (!error && argvars[0].v_type == VAR_STRING) {
|
||||
n = count_string(argvars[0].vval.v_string, tv_get_string_chk(&argvars[1]), ic);
|
||||
} else if (!error && argvars[0].v_type == VAR_LIST) {
|
||||
int64_t idx = 0;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
idx = (int64_t)tv_get_number_chk(&argvars[3], &error);
|
||||
}
|
||||
if (!error) {
|
||||
n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic);
|
||||
}
|
||||
} else if (!error && argvars[0].v_type == VAR_DICT) {
|
||||
dict_T *d = argvars[0].vval.v_dict;
|
||||
|
||||
if (d != NULL) {
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
emsg(_(e_invarg));
|
||||
} else {
|
||||
n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic);
|
||||
}
|
||||
}
|
||||
} else if (!error) {
|
||||
semsg(_(e_argument_of_str_must_be_list_string_or_dictionary), "count()");
|
||||
}
|
||||
rettv->vval.v_number = n;
|
||||
}
|
||||
|
||||
/// "ctxget([{index}])" function
|
||||
static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -1757,161 +1607,6 @@ static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
flatten_common(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// extend() a List. Append List argvars[1] to List argvars[0] before index
|
||||
/// argvars[3] and return the resulting list in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
list_T *l1 = argvars[0].vval.v_list;
|
||||
list_T *const l2 = argvars[1].vval.v_list;
|
||||
|
||||
if (!is_new && value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_new) {
|
||||
l1 = tv_list_copy(NULL, l1, false, get_copyID());
|
||||
if (l1 == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listitem_T *item;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
int before = (int)tv_get_number_chk(&argvars[2], &error);
|
||||
if (error) {
|
||||
return; // Type error; errmsg already given.
|
||||
}
|
||||
|
||||
if (before == tv_list_len(l1)) {
|
||||
item = NULL;
|
||||
} else {
|
||||
item = tv_list_find(l1, before);
|
||||
if (item == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), (int64_t)before);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item = NULL;
|
||||
}
|
||||
tv_list_extend(l1, l2, item);
|
||||
|
||||
if (is_new) {
|
||||
*rettv = (typval_T){
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
.vval.v_list = l1,
|
||||
};
|
||||
} else {
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
|
||||
/// resulting Dict in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
dict_T *d1 = argvars[0].vval.v_dict;
|
||||
if (d1 == NULL) {
|
||||
const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
|
||||
(void)locked;
|
||||
assert(locked == true);
|
||||
return;
|
||||
}
|
||||
dict_T *const d2 = argvars[1].vval.v_dict;
|
||||
if (d2 == NULL) {
|
||||
// Do nothing
|
||||
tv_copy(&argvars[0], rettv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_new && value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_new) {
|
||||
d1 = tv_dict_copy(NULL, d1, false, get_copyID());
|
||||
if (d1 == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *action = "force";
|
||||
// Check the third argument.
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
const char *const av[] = { "keep", "force", "error" };
|
||||
|
||||
action = tv_get_string_chk(&argvars[2]);
|
||||
if (action == NULL) {
|
||||
if (is_new) {
|
||||
tv_dict_unref(d1);
|
||||
}
|
||||
return; // Type error; error message already given.
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(av); i++) {
|
||||
if (strcmp(action, av[i]) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 3) {
|
||||
if (is_new) {
|
||||
tv_dict_unref(d1);
|
||||
}
|
||||
semsg(_(e_invarg2), action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tv_dict_extend(d1, d2, action);
|
||||
|
||||
if (is_new) {
|
||||
*rettv = (typval_T){
|
||||
.v_type = VAR_DICT,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
.vval.v_dict = d1,
|
||||
};
|
||||
} else {
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// "extend()" or "extendnew()" function.
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
||||
extend_list(argvars, arg_errmsg, is_new, rettv);
|
||||
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) {
|
||||
extend_dict(argvars, arg_errmsg, is_new, rettv);
|
||||
} else {
|
||||
semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
|
||||
}
|
||||
}
|
||||
|
||||
/// "extend(list, list [, idx])" function
|
||||
/// "extend(dict, dict [, action])" function
|
||||
static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char *errmsg = N_("extend() argument");
|
||||
extend(argvars, rettv, errmsg, false);
|
||||
}
|
||||
|
||||
/// "extendnew(list, list [, idx])" function
|
||||
/// "extendnew(dict, dict [, action])" function
|
||||
static void f_extendnew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char *errmsg = N_("extendnew() argument");
|
||||
extend(argvars, rettv, errmsg, true);
|
||||
}
|
||||
|
||||
/// "feedkeys()" function
|
||||
static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -3535,81 +3230,6 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
inputsecret_flag = false;
|
||||
}
|
||||
|
||||
/// "insert()" function
|
||||
static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
|
||||
if (b == NULL
|
||||
|| value_check_lock(b->bv_lock, N_("insert() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int before = 0;
|
||||
const int len = tv_blob_len(b);
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
before = (int)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;
|
||||
}
|
||||
}
|
||||
const int val = (int)tv_get_number_chk(&argvars[1], &error);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
if (val < 0 || val > 255) {
|
||||
semsg(_(e_invarg2), tv_get_string(&argvars[1]));
|
||||
return;
|
||||
}
|
||||
|
||||
ga_grow(&b->bv_ga, 1);
|
||||
uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
|
||||
memmove(p + before + 1, p + before, (size_t)(len - before));
|
||||
*(p + before) = (uint8_t)val;
|
||||
b->bv_ga.ga_len++;
|
||||
|
||||
tv_copy(&argvars[0], rettv);
|
||||
} else if (argvars[0].v_type != VAR_LIST) {
|
||||
semsg(_(e_listblobarg), "insert()");
|
||||
} else {
|
||||
list_T *l = argvars[0].vval.v_list;
|
||||
if (value_check_lock(tv_list_locked(l), N_("insert() argument"), TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t before = 0;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
before = tv_get_number_chk(&argvars[2], &error);
|
||||
}
|
||||
if (error) {
|
||||
// type error; errmsg already given
|
||||
return;
|
||||
}
|
||||
|
||||
listitem_T *item = NULL;
|
||||
if (before != tv_list_len(l)) {
|
||||
item = tv_list_find(l, (int)before);
|
||||
if (item == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), before);
|
||||
l = NULL;
|
||||
}
|
||||
}
|
||||
if (l != NULL) {
|
||||
tv_list_insert_tv(l, &argvars[1], item);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "interrupt()" function
|
||||
static void f_interrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -5656,22 +5276,6 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "remove()" function
|
||||
static void f_remove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const char *const arg_errmsg = N_("remove() argument");
|
||||
|
||||
if (argvars[0].v_type == VAR_DICT) {
|
||||
tv_dict_remove(argvars, rettv, arg_errmsg);
|
||||
} else if (argvars[0].v_type == VAR_BLOB) {
|
||||
tv_blob_remove(argvars, rettv, arg_errmsg);
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
tv_list_remove(argvars, rettv, arg_errmsg);
|
||||
} else {
|
||||
semsg(_(e_listdictblobarg), "remove()");
|
||||
}
|
||||
}
|
||||
|
||||
/// "repeat()" function
|
||||
static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -5740,40 +5344,6 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "reverse({list})" function
|
||||
static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
if (tv_check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
const int len = tv_blob_len(b);
|
||||
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
const uint8_t tmp = tv_blob_get(b, i);
|
||||
tv_blob_set(b, i, tv_blob_get(b, len - i - 1));
|
||||
tv_blob_set(b, len - i - 1, tmp);
|
||||
}
|
||||
tv_blob_set_ret(rettv, b);
|
||||
} else if (argvars[0].v_type == VAR_STRING) {
|
||||
rettv->v_type = VAR_STRING;
|
||||
if (argvars[0].vval.v_string != NULL) {
|
||||
rettv->vval.v_string = reverse_text(argvars[0].vval.v_string);
|
||||
} else {
|
||||
rettv->vval.v_string = NULL;
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
tv_list_reverse(l);
|
||||
tv_list_set_ret(rettv, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of reduce() for list "argvars[0]", using the function "expr"
|
||||
/// starting with the optional initial value argvars[2] and return the result in
|
||||
/// "rettv".
|
||||
|
@@ -1,3 +1,5 @@
|
||||
// eval/list.c: List support and container (List, Dict, Blob) functions.
|
||||
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/list.h"
|
||||
@@ -7,6 +9,7 @@
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/vim_defs.h"
|
||||
|
||||
/// Enum used by filter(), map(), mapnew() and foreach()
|
||||
@@ -19,6 +22,8 @@ typedef enum {
|
||||
|
||||
#include "eval/list.c.generated.h"
|
||||
|
||||
static const char e_argument_of_str_must_be_list_string_or_dictionary[]
|
||||
= N_("E706: Argument of %s must be a List, String or Dictionary");
|
||||
static const char e_argument_of_str_must_be_list_string_dictionary_or_blob[]
|
||||
= N_("E1250: Argument of %s must be a List, String, Dictionary or Blob");
|
||||
|
||||
@@ -417,3 +422,430 @@ void f_foreach(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
filter_map(argvars, rettv, FILTERMAP_FOREACH);
|
||||
}
|
||||
|
||||
/// "add(list, item)" function
|
||||
void f_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = 1; // Default: failed.
|
||||
if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (!value_check_lock(tv_list_locked(l), N_("add() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
tv_list_append_tv(l, &argvars[1]);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
if (b != NULL
|
||||
&& !value_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
|
||||
bool error = false;
|
||||
const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
|
||||
|
||||
if (!error) {
|
||||
ga_append(&b->bv_ga, (uint8_t)n);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emsg(_(e_listblobreq));
|
||||
}
|
||||
}
|
||||
|
||||
/// Count the number of times "needle" occurs in string "haystack".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_string(const char *haystack, const char *needle, bool ic)
|
||||
{
|
||||
varnumber_T n = 0;
|
||||
const char *p = haystack;
|
||||
|
||||
if (p == NULL || needle == NULL || *needle == NUL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ic) {
|
||||
const size_t len = strlen(needle);
|
||||
|
||||
while (*p != NUL) {
|
||||
if (mb_strnicmp(p, needle, len) == 0) {
|
||||
n++;
|
||||
p += len;
|
||||
} else {
|
||||
MB_PTR_ADV(p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const char *next;
|
||||
while ((next = strstr(p, needle)) != NULL) {
|
||||
n++;
|
||||
p = next + strlen(needle);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in List "l" starting at index "idx".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic)
|
||||
{
|
||||
if (tv_list_len(l) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
listitem_T *li = tv_list_find(l, (int)idx);
|
||||
if (li == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in Dict "d".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic)
|
||||
{
|
||||
if (d == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
TV_DICT_ITER(d, di, {
|
||||
if (tv_equal(&di->di_tv, needle, ic)) {
|
||||
n++;
|
||||
}
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// "count()" function
|
||||
void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
varnumber_T n = 0;
|
||||
int ic = 0;
|
||||
bool error = false;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
ic = (int)tv_get_number_chk(&argvars[2], &error);
|
||||
}
|
||||
|
||||
if (!error && argvars[0].v_type == VAR_STRING) {
|
||||
n = count_string(argvars[0].vval.v_string, tv_get_string_chk(&argvars[1]), ic);
|
||||
} else if (!error && argvars[0].v_type == VAR_LIST) {
|
||||
int64_t idx = 0;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
idx = (int64_t)tv_get_number_chk(&argvars[3], &error);
|
||||
}
|
||||
if (!error) {
|
||||
n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic);
|
||||
}
|
||||
} else if (!error && argvars[0].v_type == VAR_DICT) {
|
||||
dict_T *d = argvars[0].vval.v_dict;
|
||||
|
||||
if (d != NULL) {
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
emsg(_(e_invarg));
|
||||
} else {
|
||||
n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic);
|
||||
}
|
||||
}
|
||||
} else if (!error) {
|
||||
semsg(_(e_argument_of_str_must_be_list_string_or_dictionary), "count()");
|
||||
}
|
||||
rettv->vval.v_number = n;
|
||||
}
|
||||
|
||||
/// extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
|
||||
/// resulting Dict in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
dict_T *d1 = argvars[0].vval.v_dict;
|
||||
if (d1 == NULL) {
|
||||
const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
|
||||
(void)locked;
|
||||
assert(locked == true);
|
||||
return;
|
||||
}
|
||||
dict_T *const d2 = argvars[1].vval.v_dict;
|
||||
if (d2 == NULL) {
|
||||
// Do nothing
|
||||
tv_copy(&argvars[0], rettv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_new && value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_new) {
|
||||
d1 = tv_dict_copy(NULL, d1, false, get_copyID());
|
||||
if (d1 == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *action = "force";
|
||||
// Check the third argument.
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
const char *const av[] = { "keep", "force", "error" };
|
||||
|
||||
action = tv_get_string_chk(&argvars[2]);
|
||||
if (action == NULL) {
|
||||
if (is_new) {
|
||||
tv_dict_unref(d1);
|
||||
}
|
||||
return; // Type error; error message already given.
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(av); i++) {
|
||||
if (strcmp(action, av[i]) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 3) {
|
||||
if (is_new) {
|
||||
tv_dict_unref(d1);
|
||||
}
|
||||
semsg(_(e_invarg2), action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tv_dict_extend(d1, d2, action);
|
||||
|
||||
if (is_new) {
|
||||
*rettv = (typval_T){
|
||||
.v_type = VAR_DICT,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
.vval.v_dict = d1,
|
||||
};
|
||||
} else {
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// extend() a List. Append List argvars[1] to List argvars[0] before index
|
||||
/// argvars[3] and return the resulting list in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
list_T *l1 = argvars[0].vval.v_list;
|
||||
list_T *const l2 = argvars[1].vval.v_list;
|
||||
|
||||
if (!is_new && value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_new) {
|
||||
l1 = tv_list_copy(NULL, l1, false, get_copyID());
|
||||
if (l1 == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listitem_T *item;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
int before = (int)tv_get_number_chk(&argvars[2], &error);
|
||||
if (error) {
|
||||
return; // Type error; errmsg already given.
|
||||
}
|
||||
|
||||
if (before == tv_list_len(l1)) {
|
||||
item = NULL;
|
||||
} else {
|
||||
item = tv_list_find(l1, before);
|
||||
if (item == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), (int64_t)before);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item = NULL;
|
||||
}
|
||||
tv_list_extend(l1, l2, item);
|
||||
|
||||
if (is_new) {
|
||||
*rettv = (typval_T){
|
||||
.v_type = VAR_LIST,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
.vval.v_list = l1,
|
||||
};
|
||||
} else {
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// "extend()" or "extendnew()" function.
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
||||
extend_list(argvars, arg_errmsg, is_new, rettv);
|
||||
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) {
|
||||
extend_dict(argvars, arg_errmsg, is_new, rettv);
|
||||
} else {
|
||||
semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
|
||||
}
|
||||
}
|
||||
|
||||
/// "extend(list, list [, idx])" function
|
||||
/// "extend(dict, dict [, action])" function
|
||||
void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char *errmsg = N_("extend() argument");
|
||||
extend(argvars, rettv, errmsg, false);
|
||||
}
|
||||
|
||||
/// "extendnew(list, list [, idx])" function
|
||||
/// "extendnew(dict, dict [, action])" function
|
||||
void f_extendnew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char *errmsg = N_("extendnew() argument");
|
||||
extend(argvars, rettv, errmsg, true);
|
||||
}
|
||||
|
||||
/// "insert()" function
|
||||
void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
|
||||
if (b == NULL
|
||||
|| value_check_lock(b->bv_lock, N_("insert() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int before = 0;
|
||||
const int len = tv_blob_len(b);
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
before = (int)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;
|
||||
}
|
||||
}
|
||||
const int val = (int)tv_get_number_chk(&argvars[1], &error);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
if (val < 0 || val > 255) {
|
||||
semsg(_(e_invarg2), tv_get_string(&argvars[1]));
|
||||
return;
|
||||
}
|
||||
|
||||
ga_grow(&b->bv_ga, 1);
|
||||
uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
|
||||
memmove(p + before + 1, p + before, (size_t)(len - before));
|
||||
*(p + before) = (uint8_t)val;
|
||||
b->bv_ga.ga_len++;
|
||||
|
||||
tv_copy(&argvars[0], rettv);
|
||||
} else if (argvars[0].v_type != VAR_LIST) {
|
||||
semsg(_(e_listblobarg), "insert()");
|
||||
} else {
|
||||
list_T *l = argvars[0].vval.v_list;
|
||||
if (value_check_lock(tv_list_locked(l), N_("insert() argument"), TV_TRANSLATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t before = 0;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
before = tv_get_number_chk(&argvars[2], &error);
|
||||
}
|
||||
if (error) {
|
||||
// type error; errmsg already given
|
||||
return;
|
||||
}
|
||||
|
||||
listitem_T *item = NULL;
|
||||
if (before != tv_list_len(l)) {
|
||||
item = tv_list_find(l, (int)before);
|
||||
if (item == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), before);
|
||||
l = NULL;
|
||||
}
|
||||
}
|
||||
if (l != NULL) {
|
||||
tv_list_insert_tv(l, &argvars[1], item);
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "remove()" function
|
||||
void f_remove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const char *const arg_errmsg = N_("remove() argument");
|
||||
|
||||
if (argvars[0].v_type == VAR_DICT) {
|
||||
tv_dict_remove(argvars, rettv, arg_errmsg);
|
||||
} else if (argvars[0].v_type == VAR_BLOB) {
|
||||
tv_blob_remove(argvars, rettv, arg_errmsg);
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
tv_list_remove(argvars, rettv, arg_errmsg);
|
||||
} else {
|
||||
semsg(_(e_listdictblobarg), "remove()");
|
||||
}
|
||||
}
|
||||
|
||||
/// "reverse({list})" function
|
||||
void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
if (tv_check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[0].v_type == VAR_BLOB) {
|
||||
blob_T *const b = argvars[0].vval.v_blob;
|
||||
const int len = tv_blob_len(b);
|
||||
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
const uint8_t tmp = tv_blob_get(b, i);
|
||||
tv_blob_set(b, i, tv_blob_get(b, len - i - 1));
|
||||
tv_blob_set(b, len - i - 1, tmp);
|
||||
}
|
||||
tv_blob_set_ret(rettv, b);
|
||||
} else if (argvars[0].v_type == VAR_STRING) {
|
||||
rettv->v_type = VAR_STRING;
|
||||
if (argvars[0].vval.v_string != NULL) {
|
||||
rettv->vval.v_string = reverse_text(argvars[0].vval.v_string);
|
||||
} else {
|
||||
rettv->vval.v_string = NULL;
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"),
|
||||
TV_TRANSLATE)) {
|
||||
tv_list_reverse(l);
|
||||
tv_list_set_ret(rettv, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user