aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/buffer.c734
-rw-r--r--src/nvim/eval/buffer.h10
-rw-r--r--src/nvim/eval/decode.c76
-rw-r--r--src/nvim/eval/encode.c59
-rw-r--r--src/nvim/eval/encode.h16
-rw-r--r--src/nvim/eval/executor.c21
-rw-r--r--src/nvim/eval/funcs.c2710
-rw-r--r--src/nvim/eval/funcs.h22
-rw-r--r--src/nvim/eval/gc.c5
-rw-r--r--src/nvim/eval/gc.h1
-rw-r--r--src/nvim/eval/typval.c289
-rw-r--r--src/nvim/eval/typval.h469
-rw-r--r--src/nvim/eval/typval_defs.h399
-rw-r--r--src/nvim/eval/typval_encode.c.h32
-rw-r--r--src/nvim/eval/typval_encode.h4
-rw-r--r--src/nvim/eval/userfunc.c1043
-rw-r--r--src/nvim/eval/userfunc.h85
-rw-r--r--src/nvim/eval/vars.c346
-rw-r--r--src/nvim/eval/vars.h2
-rw-r--r--src/nvim/eval/window.c954
-rw-r--r--src/nvim/eval/window.h78
21 files changed, 4259 insertions, 3096 deletions
diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c
new file mode 100644
index 0000000000..2f37d1ba2e
--- /dev/null
+++ b/src/nvim/eval/buffer.c
@@ -0,0 +1,734 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// eval/buffer.c: Buffer related builtin functions
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/change.h"
+#include "nvim/cursor.h"
+#include "nvim/eval.h"
+#include "nvim/eval/buffer.h"
+#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/globals.h"
+#include "nvim/macros.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/move.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
+#include "nvim/sign.h"
+#include "nvim/types.h"
+#include "nvim/undo.h"
+#include "nvim/vim.h"
+
+typedef struct {
+ win_T *cob_curwin_save;
+ aco_save_T cob_aco;
+ int cob_using_aco;
+ int cob_save_VIsual_active;
+} cob_T;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/buffer.c.generated.h"
+#endif
+
+/// Find a buffer by number or exact name.
+buf_T *find_buffer(typval_T *avar)
+{
+ buf_T *buf = NULL;
+
+ if (avar->v_type == VAR_NUMBER) {
+ buf = buflist_findnr((int)avar->vval.v_number);
+ } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
+ buf = buflist_findname_exp(avar->vval.v_string);
+ if (buf == NULL) {
+ // No full path name match, try a match with a URL or a "nofile"
+ // buffer, these don't use the full path.
+ FOR_ALL_BUFFERS(bp) {
+ if (bp->b_fname != NULL
+ && (path_with_url(bp->b_fname) || bt_nofilename(bp))
+ && strcmp(bp->b_fname, avar->vval.v_string) == 0) {
+ buf = bp;
+ break;
+ }
+ }
+ }
+ }
+ return buf;
+}
+
+/// If there is a window for "curbuf", make it the current window.
+static void find_win_for_curbuf(void)
+{
+ wininfo_T *wip;
+
+ // The b_wininfo list should have the windows that recently contained the
+ // buffer, going over this is faster than going over all the windows.
+ // Do check the buffer is still there.
+ FOR_ALL_BUF_WININFO(curbuf, wip) {
+ if (wip->wi_win != NULL && wip->wi_win->w_buffer == curbuf) {
+ curwin = wip->wi_win;
+ break;
+ }
+ }
+}
+
+/// Used before making a change in "buf", which is not the current one: Make
+/// "buf" the current buffer and find a window for this buffer, so that side
+/// effects are done correctly (e.g., adjusting marks).
+///
+/// Information is saved in "cob" and MUST be restored by calling
+/// change_other_buffer_restore().
+static void change_other_buffer_prepare(cob_T *cob, buf_T *buf)
+{
+ CLEAR_POINTER(cob);
+
+ // Set "curbuf" to the buffer being changed. Then make sure there is a
+ // window for it to handle any side effects.
+ cob->cob_save_VIsual_active = VIsual_active;
+ VIsual_active = false;
+ cob->cob_curwin_save = curwin;
+ curbuf = buf;
+ find_win_for_curbuf(); // simplest: find existing window for "buf"
+
+ if (curwin->w_buffer != buf) {
+ // No existing window for this buffer. It is dangerous to have
+ // curwin->w_buffer differ from "curbuf", use the autocmd window.
+ curbuf = curwin->w_buffer;
+ aucmd_prepbuf(&cob->cob_aco, buf);
+ cob->cob_using_aco = true;
+ }
+}
+
+static void change_other_buffer_restore(cob_T *cob)
+{
+ if (cob->cob_using_aco) {
+ aucmd_restbuf(&cob->cob_aco);
+ } else {
+ curwin = cob->cob_curwin_save;
+ curbuf = curwin->w_buffer;
+ }
+ VIsual_active = cob->cob_save_VIsual_active;
+}
+
+/// Set line or list of lines in buffer "buf" to "lines".
+/// Any type is allowed and converted to a string.
+static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_T *lines,
+ typval_T *rettv)
+ FUNC_ATTR_NONNULL_ARG(4, 5)
+{
+ linenr_T lnum = lnum_arg + (append ? 1 : 0);
+ long added = 0;
+
+ // When using the current buffer ml_mfp will be set if needed. Useful when
+ // setline() is used on startup. For other buffers the buffer must be
+ // loaded.
+ const bool is_curbuf = buf == curbuf;
+ if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
+ rettv->vval.v_number = 1; // FAIL
+ return;
+ }
+
+ // After this don't use "return", goto "cleanup"!
+ cob_T cob;
+ if (!is_curbuf) {
+ // set "curbuf" to "buf" and find a window for this buffer
+ change_other_buffer_prepare(&cob, buf);
+ }
+
+ linenr_T append_lnum;
+ if (append) {
+ // appendbufline() uses the line number below which we insert
+ append_lnum = lnum - 1;
+ } else {
+ // setbufline() uses the line number above which we insert, we only
+ // append if it's below the last line
+ append_lnum = curbuf->b_ml.ml_line_count;
+ }
+
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ char *line = NULL;
+ if (lines->v_type == VAR_LIST) {
+ l = lines->vval.v_list;
+ if (l == NULL || tv_list_len(l) == 0) {
+ // set proper return code
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ rettv->vval.v_number = 1; // FAIL
+ }
+ goto cleanup;
+ }
+ li = tv_list_first(l);
+ } else {
+ line = typval_tostring(lines, false);
+ }
+
+ // Default result is zero == OK.
+ for (;;) {
+ if (lines->v_type == VAR_LIST) {
+ // List argument, get next string.
+ if (li == NULL) {
+ break;
+ }
+ xfree(line);
+ line = typval_tostring(TV_LIST_ITEM_TV(li), false);
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+
+ rettv->vval.v_number = 1; // FAIL
+ if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
+ break;
+ }
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (!append && lnum <= curbuf->b_ml.ml_line_count) {
+ // Existing line, replace it.
+ int old_len = (int)strlen(ml_get(lnum));
+ if (u_savesub(lnum) == OK
+ && ml_replace(lnum, line, true) == OK) {
+ inserted_bytes(lnum, 0, old_len, (int)strlen(line));
+ if (is_curbuf && lnum == curwin->w_cursor.lnum) {
+ check_cursor_col();
+ }
+ rettv->vval.v_number = 0; // OK
+ }
+ } else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
+ // append the line.
+ added++;
+ if (ml_append(lnum - 1, line, 0, false) == OK) {
+ rettv->vval.v_number = 0; // OK
+ }
+ }
+
+ if (l == NULL) { // only one string argument
+ break;
+ }
+ lnum++;
+ }
+ xfree(line);
+
+ if (added > 0) {
+ appended_lines_mark(append_lnum, added);
+
+ // Only adjust the cursor for buffers other than the current, unless it
+ // is the current window. For curbuf and other windows it has been done
+ // in mark_adjust_internal().
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf
+ && (wp->w_buffer != curbuf || wp == curwin)
+ && wp->w_cursor.lnum > append_lnum) {
+ wp->w_cursor.lnum += (linenr_T)added;
+ }
+ }
+ check_cursor_col();
+ update_topline(curwin);
+ }
+
+cleanup:
+ if (!is_curbuf) {
+ change_other_buffer_restore(&cob);
+ }
+}
+
+/// "append(lnum, string/list)" function
+void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ const linenr_T lnum = tv_get_lnum(&argvars[0]);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
+ }
+}
+
+/// Set or append lines to a buffer.
+static void buf_set_append_line(typval_T *argvars, typval_T *rettv, bool append)
+{
+ const int did_emsg_before = did_emsg;
+ buf_T *const buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ rettv->vval.v_number = 1; // FAIL
+ } else {
+ const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(buf, lnum, append, &argvars[2], rettv);
+ }
+ }
+}
+
+/// "appendbufline(buf, lnum, string/list)" function
+void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_set_append_line(argvars, rettv, true);
+}
+
+/// "bufadd(expr)" function
+void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ char *name = (char *)tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
+}
+
+/// "bufexists(expr)" function
+void f_bufexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
+}
+
+/// "buflisted(expr)" function
+void f_buflisted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
+}
+
+/// "bufload(expr)" function
+void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
+{
+ buf_T *buf = get_buf_arg(&argvars[0]);
+
+ if (buf != NULL) {
+ buffer_ensure_loaded(buf);
+ }
+}
+
+/// "bufloaded(expr)" function
+void f_bufloaded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
+}
+
+/// "bufname(expr)" function
+void f_bufname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const buf_T *buf;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ buf = curbuf;
+ } else {
+ buf = tv_get_buf_from_arg(&argvars[0]);
+ }
+ if (buf != NULL && buf->b_fname != NULL) {
+ rettv->vval.v_string = xstrdup(buf->b_fname);
+ }
+}
+
+/// "bufnr(expr)" function
+void f_bufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const buf_T *buf;
+ bool error = false;
+
+ rettv->vval.v_number = -1;
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ buf = curbuf;
+ } else {
+ // Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
+ // and the second argument isn't zero, but we want to return early if the
+ // first argument isn't a string or number so only one error is shown.
+ if (!tv_check_str_or_nr(&argvars[0])) {
+ return;
+ }
+ emsg_off++;
+ buf = tv_get_buf(&argvars[0], false);
+ emsg_off--;
+ }
+
+ // If the buffer isn't found and the second argument is not zero create a
+ // new buffer.
+ const char *name;
+ if (buf == NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[1], &error) != 0
+ && !error
+ && (name = tv_get_string_chk(&argvars[0])) != NULL) {
+ buf = buflist_new((char *)name, NULL, 1, 0);
+ }
+
+ if (buf != NULL) {
+ rettv->vval.v_number = buf->b_fnum;
+ }
+}
+
+static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
+{
+ const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
+ if (buf == NULL) { // no need to search if invalid arg or buffer not found
+ rettv->vval.v_number = -1;
+ return;
+ }
+
+ int winnr = 0;
+ int winid;
+ bool found_buf = false;
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ winnr++;
+ if (wp->w_buffer == buf) {
+ found_buf = true;
+ winid = wp->handle;
+ break;
+ }
+ }
+ rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
+}
+
+/// "bufwinid(nr)" function
+void f_bufwinid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_win_common(argvars, rettv, false);
+}
+
+/// "bufwinnr(nr)" function
+void f_bufwinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_win_common(argvars, rettv, true);
+}
+
+/// "deletebufline()" function
+void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ rettv->vval.v_number = 1; // FAIL by default
+ buf_T *const buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
+
+ linenr_T last;
+ const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ last = tv_get_lnum_buf(&argvars[2], buf);
+ } else {
+ last = first;
+ }
+
+ if (buf->b_ml.ml_mfp == NULL || first < 1
+ || first > buf->b_ml.ml_line_count || last < first) {
+ return;
+ }
+
+ // After this don't use "return", goto "cleanup"!
+ const bool is_curbuf = buf == curbuf;
+ cob_T cob;
+ if (!is_curbuf) {
+ // set "curbuf" to "buf" and find a window for this buffer
+ change_other_buffer_prepare(&cob, buf);
+ }
+
+ if (last > curbuf->b_ml.ml_line_count) {
+ last = curbuf->b_ml.ml_line_count;
+ }
+ const long count = last - first + 1;
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (u_save(first - 1, last + 1) == FAIL) {
+ goto cleanup;
+ }
+
+ for (linenr_T lnum = first; lnum <= last; lnum++) {
+ ml_delete(first, true);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ if (wp->w_cursor.lnum > last) {
+ wp->w_cursor.lnum -= (linenr_T)count;
+ } else if (wp->w_cursor.lnum > first) {
+ wp->w_cursor.lnum = first;
+ }
+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
+ wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
+ }
+ }
+ }
+ check_cursor_col();
+ deleted_lines_mark(first, count);
+ rettv->vval.v_number = 0; // OK
+
+cleanup:
+ if (!is_curbuf) {
+ change_other_buffer_restore(&cob);
+ }
+}
+
+/// @return buffer options, variables and other attributes in a dictionary.
+static dict_T *get_buffer_info(buf_T *buf)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
+ tv_dict_add_str(dict, S_LEN("name"),
+ buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
+ tv_dict_add_nr(dict, S_LEN("lnum"),
+ buf == curbuf ? curwin->w_cursor.lnum : buflist_findlnum(buf));
+ tv_dict_add_nr(dict, S_LEN("linecount"), buf->b_ml.ml_line_count);
+ tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
+ tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
+ tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
+ tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
+ tv_dict_add_nr(dict, S_LEN("hidden"),
+ buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
+
+ // Get a reference to buffer variables
+ tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
+
+ // List of windows displaying this buffer
+ list_T *const windows = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ tv_list_append_number(windows, (varnumber_T)wp->handle);
+ }
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), windows);
+
+ if (buf->b_signlist != NULL) {
+ // List of signs placed in this buffer
+ tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
+ }
+
+ tv_dict_add_nr(dict, S_LEN("lastused"), buf->b_last_used);
+
+ return dict;
+}
+
+/// "getbufinfo()" function
+void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *argbuf = NULL;
+ bool filtered = false;
+ bool sel_buflisted = false;
+ bool sel_bufloaded = false;
+ bool sel_bufmodified = false;
+
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ // List of all the buffers or selected buffers
+ if (argvars[0].v_type == VAR_DICT) {
+ dict_T *sel_d = argvars[0].vval.v_dict;
+
+ if (sel_d != NULL) {
+ dictitem_T *di;
+
+ filtered = true;
+
+ di = tv_dict_find(sel_d, S_LEN("buflisted"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_buflisted = true;
+ }
+
+ di = tv_dict_find(sel_d, S_LEN("bufloaded"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_bufloaded = true;
+ }
+ di = tv_dict_find(sel_d, S_LEN("bufmodified"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_bufmodified = true;
+ }
+ }
+ } else if (argvars[0].v_type != VAR_UNKNOWN) {
+ // Information about one buffer. Argument specifies the buffer
+ argbuf = tv_get_buf_from_arg(&argvars[0]);
+ if (argbuf == NULL) {
+ return;
+ }
+ }
+
+ // Return information about all the buffers or a specified buffer
+ FOR_ALL_BUFFERS(buf) {
+ if (argbuf != NULL && argbuf != buf) {
+ continue;
+ }
+ if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
+ || (sel_buflisted && !buf->b_p_bl)
+ || (sel_bufmodified && !buf->b_changed))) {
+ continue;
+ }
+
+ dict_T *const d = get_buffer_info(buf);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (argbuf != NULL) {
+ return;
+ }
+ }
+}
+
+/// Get line or list of lines from buffer "buf" into "rettv".
+///
+/// @param retlist if true, then the lines are returned as a Vim List.
+///
+/// @return range (from start to end) of lines in rettv from the specified
+/// buffer.
+static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
+{
+ rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
+ rettv->vval.v_string = NULL;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
+ if (retlist) {
+ tv_list_alloc_ret(rettv, 0);
+ }
+ return;
+ }
+
+ if (retlist) {
+ if (start < 1) {
+ start = 1;
+ }
+ if (end > buf->b_ml.ml_line_count) {
+ end = buf->b_ml.ml_line_count;
+ }
+ tv_list_alloc_ret(rettv, end - start + 1);
+ while (start <= end) {
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)ml_get_buf(buf, start++, false), -1);
+ }
+ } else {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count)
+ ? xstrdup(ml_get_buf(buf, start, false)) : NULL);
+ }
+}
+
+/// @param retlist true: "getbufline()" function
+/// false: "getbufoneline()" function
+static void getbufline(typval_T *argvars, typval_T *rettv, bool retlist)
+{
+ const int did_emsg_before = did_emsg;
+ buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
+ const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
+ ? lnum
+ : tv_get_lnum_buf(&argvars[2], buf));
+
+ get_buffer_lines(buf, lnum, end, retlist, rettv);
+}
+
+/// "getbufline()" function
+void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ getbufline(argvars, rettv, true);
+}
+
+/// "getbufoneline()" function
+void f_getbufoneline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ getbufline(argvars, rettv, false);
+}
+
+/// "getline(lnum, [end])" function
+void f_getline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ linenr_T end;
+ bool retlist;
+
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ end = lnum;
+ retlist = false;
+ } else {
+ end = tv_get_lnum(&argvars[1]);
+ retlist = true;
+ }
+
+ get_buffer_lines(curbuf, lnum, end, retlist, rettv);
+}
+
+/// "setbufline()" function
+void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_set_append_line(argvars, rettv, false);
+}
+
+/// "setline()" function
+void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ linenr_T lnum = tv_get_lnum(&argvars[0]);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
+ }
+}
+
+/// Make "buf" the current buffer.
+///
+/// restore_buffer() MUST be called to undo.
+/// No autocommands will be executed. Use aucmd_prepbuf() if there are any.
+void switch_buffer(bufref_T *save_curbuf, buf_T *buf)
+{
+ block_autocmds();
+ set_bufref(save_curbuf, curbuf);
+ curbuf->b_nwindows--;
+ curbuf = buf;
+ curwin->w_buffer = buf;
+ curbuf->b_nwindows++;
+}
+
+/// Restore the current buffer after using switch_buffer().
+void restore_buffer(bufref_T *save_curbuf)
+{
+ unblock_autocmds();
+ // Check for valid buffer, just in case.
+ if (bufref_valid(save_curbuf)) {
+ curbuf->b_nwindows--;
+ curwin->w_buffer = save_curbuf->br_buf;
+ curbuf = save_curbuf->br_buf;
+ curbuf->b_nwindows++;
+ }
+}
+
+/// Find a window for buffer "buf".
+/// If found true is returned and "wp" and "tp" are set to
+/// the window and tabpage.
+/// If not found, false is returned.
+///
+/// @param buf buffer to find a window for
+/// @param[out] wp stores the found window
+/// @param[out] tp stores the found tabpage
+///
+/// @return true if a window was found for the buffer.
+bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
+{
+ *wp = NULL;
+ *tp = NULL;
+ FOR_ALL_TAB_WINDOWS(tp2, wp2) {
+ if (wp2->w_buffer == buf) {
+ *tp = tp2;
+ *wp = wp2;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/nvim/eval/buffer.h b/src/nvim/eval/buffer.h
new file mode 100644
index 0000000000..4a2f8f9e94
--- /dev/null
+++ b/src/nvim/eval/buffer.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_EVAL_BUFFER_H
+#define NVIM_EVAL_BUFFER_H
+
+#include "nvim/buffer_defs.h"
+#include "nvim/eval/typval_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/buffer.h.generated.h"
+#endif
+#endif // NVIM_EVAL_BUFFER_H
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 7b975ce775..cd1479f150 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -1,20 +1,31 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include <msgpack.h>
+#include <assert.h>
+#include <msgpack/object.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "klib/kvec.h"
#include "nvim/ascii.h"
-#include "nvim/charset.h" // vim_str2nr
+#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
-#include "nvim/globals.h"
-#include "nvim/lib/kvec.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/hashtab.h"
#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/vim.h" // OK, FAIL
+#include "nvim/types.h"
+#include "nvim/vim.h"
/// Helper structure for container_struct
typedef struct {
@@ -271,11 +282,9 @@ typval_T decode_string(const char *const s, const size_t len, const TriState has
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_ref(list);
create_special_dict(&tv, kMPString,
- ((typval_T){
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
+ (typval_T){ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list } });
const int elw_ret = encode_list_write((void *)list, s, len);
if (s_allocated) {
xfree((void *)s);
@@ -286,13 +295,12 @@ typval_T decode_string(const char *const s, const size_t len, const TriState has
}
}
return tv;
- } else {
- return (typval_T) {
- .v_type = VAR_STRING,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_string = ((s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
- };
}
+ return (typval_T) {
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_string = ((s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
+ };
}
/// Parse JSON double-quoted string
@@ -368,7 +376,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
goto parse_json_string_fail;
}
} else {
- uint8_t p_byte = (uint8_t)*p;
+ uint8_t p_byte = (uint8_t)(*p);
// unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
if (p_byte < 0x20) {
semsg(_("E474: ASCII control characters cannot be present "
@@ -430,7 +438,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
const char ubuf[] = { t[1], t[2], t[3], t[4] };
t += 4;
uvarnumber_T ch;
- vim_str2nr((char_u *)ubuf, NULL, NULL,
+ vim_str2nr(ubuf, NULL, NULL,
STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true);
if (ch == 0) {
hasnul = true;
@@ -469,7 +477,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
['r'] = CAR,
['f'] = FF,
};
- *str_end++ = escapes[(int)*t];
+ *str_end++ = escapes[(int)(*t)];
break;
}
default:
@@ -600,7 +608,7 @@ parse_json_number_check:
// Convert integer
varnumber_T nr;
int num_len;
- vim_str2nr((char_u *)s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true);
+ vim_str2nr(s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true);
if ((int)exp_num_len != num_len) {
semsg(_("E685: internal error: while converting number \"%.*s\" "
"to integer vim_str2nr consumed %i bytes in place of %zu"),
@@ -838,12 +846,10 @@ json_decode_string_cycle_start:
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
};
- kv_push(container_stack, ((ContainerStackItem) {
- .stack_index = kv_size(stack),
- .s = p,
- .container = tv,
- .special_val = NULL,
- }));
+ kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = NULL }));
kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
@@ -862,12 +868,10 @@ json_decode_string_cycle_start:
.vval = { .v_dict = dict },
};
}
- kv_push(container_stack, ((ContainerStackItem) {
- .stack_index = kv_size(stack),
- .s = p,
- .container = tv,
- .special_val = val_list,
- }));
+ kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = val_list }));
kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
@@ -1089,11 +1093,9 @@ msgpack_to_vim_generic_map: {}
tv_list_append_number(list, mobj.via.ext.type);
list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
tv_list_append_list(list, ext_val_list);
- create_special_dict(rettv, kMPExt, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
+ create_special_dict(rettv, kMPExt, ((typval_T) { .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list } }));
if (encode_list_write((void *)ext_val_list, mobj.via.ext.ptr,
mobj.via.ext.size) == -1) {
return FAIL;
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index bb514fba47..c2f1eae8af 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -10,23 +10,28 @@
#include <assert.h>
#include <inttypes.h>
#include <math.h>
-#include <msgpack.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "klib/kvec.h"
+#include "msgpack/pack.h"
#include "nvim/ascii.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/charset.h" // vim_isprintc()
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/garray.h"
-#include "nvim/lib/kvec.h"
+#include "nvim/gettext.h"
+#include "nvim/hashtab.h"
#include "nvim/macros.h"
#include "nvim/math.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/vim.h" // For _()
const char *const encode_bool_var_names[] = {
@@ -131,35 +136,35 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
typval_T key_tv = {
.v_type = VAR_STRING,
.vval = { .v_string =
- (char *)(v.data.d.hi ==
- NULL ? v.data.d.dict->dv_hashtab.ht_array : (v.data.d.hi -
- 1))->hi_key },
+ (v.data.d.hi ==
+ NULL ? v.data.d.dict->dv_hashtab.ht_array : (v.data.d.hi -
+ 1))->hi_key },
};
char *const key = encode_tv2string(&key_tv, NULL);
- vim_snprintf((char *)IObuff, IOSIZE, key_msg, key);
+ vim_snprintf(IObuff, IOSIZE, key_msg, key);
xfree(key);
- ga_concat(&msg_ga, (char *)IObuff);
+ ga_concat(&msg_ga, IObuff);
break;
}
case kMPConvPairs:
case kMPConvList: {
const int idx = (v.data.l.li == tv_list_first(v.data.l.list)
- ? 0
- : (v.data.l.li == NULL
- ? tv_list_len(v.data.l.list) - 1
- : (int)tv_list_idx_of_item(v.data.l.list,
- TV_LIST_ITEM_PREV(v.data.l.list,
- v.data.l.li))));
+ ? 0
+ : (v.data.l.li == NULL
+ ? tv_list_len(v.data.l.list) - 1
+ : (int)tv_list_idx_of_item(v.data.l.list,
+ TV_LIST_ITEM_PREV(v.data.l.list,
+ v.data.l.li))));
const listitem_T *const li = (v.data.l.li == NULL
- ? tv_list_last(v.data.l.list)
- : TV_LIST_ITEM_PREV(v.data.l.list,
- v.data.l.li));
+ ? tv_list_last(v.data.l.list)
+ : TV_LIST_ITEM_PREV(v.data.l.list,
+ v.data.l.li));
if (v.type == kMPConvList
|| li == NULL
|| (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
&& tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
- vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
- ga_concat(&msg_ga, (char *)IObuff);
+ vim_snprintf(IObuff, IOSIZE, idx_msg, idx);
+ ga_concat(&msg_ga, IObuff);
} else {
assert(li != NULL);
listitem_T *const first_item =
@@ -167,9 +172,9 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
assert(first_item != NULL);
typval_T key_tv = *TV_LIST_ITEM_TV(first_item);
char *const key = encode_tv2echo(&key_tv, NULL);
- vim_snprintf((char *)IObuff, IOSIZE, key_pair_msg, key, idx);
+ vim_snprintf(IObuff, IOSIZE, key_pair_msg, key, idx);
xfree(key);
- ga_concat(&msg_ga, (char *)IObuff);
+ ga_concat(&msg_ga, IObuff);
}
break;
}
@@ -188,8 +193,8 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
break;
case kMPConvPartialList: {
const int idx = (int)(v.data.a.arg - v.data.a.argv) - 1;
- vim_snprintf((char *)IObuff, IOSIZE, partial_arg_i_msg, idx);
- ga_concat(&msg_ga, (char *)IObuff);
+ vim_snprintf(IObuff, IOSIZE, partial_arg_i_msg, idx);
+ ga_concat(&msg_ga, IObuff);
break;
}
}
@@ -219,7 +224,7 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, cha
}
len++;
if (TV_LIST_ITEM_TV(li)->vval.v_string != NULL) {
- len += STRLEN(TV_LIST_ITEM_TV(li)->vval.v_string);
+ len += strlen(TV_LIST_ITEM_TV(li)->vval.v_string);
}
});
if (len) {
@@ -281,7 +286,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
state->offset = 0;
state->li_length = (TV_LIST_ITEM_TV(state->li)->vval.v_string == NULL
? 0
- : STRLEN(TV_LIST_ITEM_TV(state->li)->vval.v_string));
+ : strlen(TV_LIST_ITEM_TV(state->li)->vval.v_string));
}
}
*read_bytes = nbuf;
@@ -304,7 +309,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
if (buf_[i_] == '\'') { \
ga_append(gap, '\''); \
} \
- ga_append(gap, buf_[i_]); \
+ ga_append(gap, (uint8_t)buf_[i_]); \
} \
ga_append(gap, '\''); \
} \
diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h
index 8755ff48ac..41e7614fc0 100644
--- a/src/nvim/eval/encode.h
+++ b/src/nvim/eval/encode.h
@@ -2,11 +2,15 @@
#define NVIM_EVAL_ENCODE_H
#include <msgpack.h>
+#include <msgpack/pack.h>
#include <stddef.h>
+#include <string.h>
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/garray.h"
-#include "nvim/vim.h" // For STRLEN
+#include "nvim/vim.h"
/// Convert VimL value to msgpack string
///
@@ -15,9 +19,7 @@
/// @param[in] objname Object name, used for error message.
///
/// @return OK in case of success, FAIL otherwise.
-int encode_vim_to_msgpack(msgpack_packer *const packer,
- typval_T *const tv,
- const char *const objname);
+int encode_vim_to_msgpack(msgpack_packer *packer, typval_T *tv, const char *objname);
/// Convert VimL value to :echo output
///
@@ -26,9 +28,7 @@ int encode_vim_to_msgpack(msgpack_packer *const packer,
/// @param[in] objname Object name, used for error message.
///
/// @return OK in case of success, FAIL otherwise.
-int encode_vim_to_echo(garray_T *const packer,
- typval_T *const tv,
- const char *const objname);
+int encode_vim_to_echo(garray_T *packer, typval_T *tv, const char *objname);
/// Structure defining state for read_from_list()
typedef struct {
@@ -48,7 +48,7 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list)
.offset = 0,
.li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
? 0
- : STRLEN(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
+ : strlen(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
};
}
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index b461456a3a..9caea2fef1 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -1,15 +1,23 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <inttypes.h>
+#include <stdlib.h>
+
#include "nvim/eval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/message.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/executor.c.generated.h"
+# include "eval/executor.c.generated.h" // IWYU pragma: export
#endif
char *e_listidx = N_("E684: list index out of range: %" PRId64);
@@ -43,7 +51,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
blob_T *const b1 = tv1->vval.v_blob;
blob_T *const b2 = tv2->vval.v_blob;
for (int i = 0; i < tv_blob_len(b2); i++) {
- ga_append(&b1->bv_ga, (char)tv_blob_get(b2, i));
+ ga_append(&b1->bv_ga, tv_blob_get(b2, i));
}
}
return OK;
@@ -61,7 +69,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
if (tv2->v_type == VAR_LIST) {
break;
}
- if (vim_strchr("+-*/%", *op) != NULL) {
+ if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
// nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
@@ -108,8 +116,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
const char *tvs = tv_get_string(tv1);
char numbuf[NUMBUFLEN];
char *const s =
- (char *)concat_str((const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
- numbuf));
+ concat_str(tvs, tv_get_string_buf(tv2, numbuf));
tv_clear(tv1);
tv1->v_type = VAR_STRING;
tv1->vval.v_string = s;
@@ -123,8 +130,8 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
break;
}
const float_T f = (tv2->v_type == VAR_FLOAT
- ? tv2->vval.v_float
- : (float_T)tv_get_number(tv2));
+ ? tv2->vval.v_float
+ : (float_T)tv_get_number(tv2));
switch (*op) {
case '+':
tv1->vval.v_float += f; break;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 9f851653eb..a6dc41d0f3 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1,27 +1,44 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <assert.h>
+#include <fcntl.h>
#include <float.h>
+#include <inttypes.h>
+#include <limits.h>
#include <math.h>
-
+#include <msgpack/object.h>
+#include <msgpack/pack.h>
+#include <msgpack/unpack.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <uv.h>
+
+#include "auto/config.h"
#include "nvim/api/private/converter.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
-#include "nvim/arglist.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
-#include "nvim/change.h"
+#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
-#include "nvim/cmdhist.h"
#include "nvim/context.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
-#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/buffer.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -29,55 +46,72 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
+#include "nvim/event/process.h"
+#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/file_search.h"
#include "nvim/fileio.h"
-#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
+#include "nvim/hashtab.h"
+#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
-#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/input.h"
-#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
-#include "nvim/mapping.h"
+#include "nvim/main.h"
#include "nvim/mark.h"
-#include "nvim/match.h"
#include "nvim/math.h"
+#include "nvim/mbyte.h"
+#include "nvim/memfile_defs.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/menu.h"
+#include "nvim/message.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/msgpack_rpc/server.h"
+#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
#include "nvim/os/dl.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/fs_defs.h"
+#include "nvim/os/os.h"
+#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
+#include "nvim/os/stdpaths_defs.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/plines.h"
#include "nvim/popupmenu.h"
+#include "nvim/pos.h"
#include "nvim/profile.h"
-#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sha256.h"
-#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/spellsuggest.h"
#include "nvim/state.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/testing.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/version.h"
@@ -106,6 +140,7 @@ typedef enum {
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
# include "funcs.generated.h"
+
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
#endif
@@ -113,6 +148,8 @@ PRAGMA_DIAG_POP
static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number");
static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
+static char e_using_number_as_bool_nr[]
+ = N_("E1023: Using a Number as a Bool: %d");
/// Dummy va_list for passing to vim_snprintf
///
@@ -132,13 +169,13 @@ char *get_function_name(expand_T *xp, int idx)
intidx = -1;
}
if (intidx < 0) {
- char_u *name = (char_u *)get_user_func_name(xp, idx);
+ char *name = get_user_func_name(xp, idx);
if (name != NULL) {
if (*name != NUL && *name != '<'
- && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
- return cat_prefix_varname('g', (char *)name);
+ && strncmp("g:", xp->xp_pattern, 2) == 0) {
+ return cat_prefix_varname('g', name);
}
- return (char *)name;
+ return name;
}
}
@@ -155,7 +192,7 @@ char *get_function_name(expand_T *xp, int idx)
} else {
IObuff[key_len + 1] = NUL;
}
- return (char *)IObuff;
+ return IObuff;
}
/// Function given to ExpandGeneric() to obtain the list of internal or
@@ -168,9 +205,9 @@ char *get_expr_name(expand_T *xp, int idx)
intidx = -1;
}
if (intidx < 0) {
- char_u *name = (char_u *)get_function_name(xp, idx);
+ char *name = get_function_name(xp, idx);
if (name != NULL) {
- return (char *)name;
+ return name;
}
}
return get_user_var_name(xp, ++intidx);
@@ -189,37 +226,37 @@ const EvalFuncDef *find_internal_func(const char *const name)
return index >= 0 ? &functions[index] : NULL;
}
-int call_internal_func(const char_u *const fname, const int argcount, typval_T *const argvars,
+int call_internal_func(const char *const fname, const int argcount, typval_T *const argvars,
typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL
{
- const EvalFuncDef *const fdef = find_internal_func((const char *)fname);
+ const EvalFuncDef *const fdef = find_internal_func(fname);
if (fdef == NULL) {
- return ERROR_UNKNOWN;
+ return FCERR_UNKNOWN;
} else if (argcount < fdef->min_argc) {
- return ERROR_TOOFEW;
+ return FCERR_TOOFEW;
} else if (argcount > fdef->max_argc) {
- return ERROR_TOOMANY;
+ return FCERR_TOOMANY;
}
argvars[argcount].v_type = VAR_UNKNOWN;
fdef->func(argvars, rettv, fdef->data);
- return ERROR_NONE;
+ return FCERR_NONE;
}
/// Invoke a method for base->method().
-int call_internal_method(const char_u *const fname, const int argcount, typval_T *const argvars,
+int call_internal_method(const char *const fname, const int argcount, typval_T *const argvars,
typval_T *const rettv, typval_T *const basetv)
FUNC_ATTR_NONNULL_ALL
{
- const EvalFuncDef *const fdef = find_internal_func((const char *)fname);
+ const EvalFuncDef *const fdef = find_internal_func(fname);
if (fdef == NULL) {
- return ERROR_UNKNOWN;
+ return FCERR_UNKNOWN;
} else if (fdef->base_arg == BASE_NONE) {
- return ERROR_NOTMETHOD;
+ return FCERR_NOTMETHOD;
} else if (argcount + 1 < fdef->min_argc) {
- return ERROR_TOOFEW;
+ return FCERR_TOOFEW;
} else if (argcount + 1 > fdef->max_argc) {
- return ERROR_TOOMANY;
+ return FCERR_TOOMANY;
}
typval_T argv[MAX_FUNC_ARGS + 1];
@@ -231,10 +268,10 @@ int call_internal_method(const char_u *const fname, const int argcount, typval_T
argv[argcount + 1].v_type = VAR_UNKNOWN;
fdef->func(argv, rettv, fdef->data);
- return ERROR_NONE;
+ return FCERR_NONE;
}
-/// @return TRUE for a non-zero Number and a non-empty String.
+/// @return true for a non-zero Number and a non-empty String.
static int non_zero_arg(typval_T *argvars)
{
return ((argvars[0].v_type == VAR_NUMBER
@@ -251,26 +288,25 @@ static int non_zero_arg(typval_T *argvars)
/// Some versions of glibc on i386 have an optimization that makes it harder to
/// call math functions indirectly from inside an inlined function, causing
/// compile-time errors. Avoid `inline` in that case. #3072
-static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void float_op_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T f;
- float_T (*function)(float_T) = (float_T (*)(float_T)) fptr;
rettv->v_type = VAR_FLOAT;
if (tv_get_float_chk(argvars, &f)) {
- rettv->vval.v_float = function(f);
+ rettv->vval.v_float = fptr.float_func(f);
} else {
rettv->vval.v_float = 0.0;
}
}
-static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
}
- ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr;
+ MsgpackRpcRequestHandler handler = *fptr.api_handler;
Array args = ARRAY_DICT_INIT;
@@ -279,7 +315,8 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
Error err = ERROR_INIT;
- Object result = fn(VIML_INTERNAL_CALL, args, &err);
+ Arena res_arena = ARENA_EMPTY;
+ Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err);
if (ERROR_SET(&err)) {
semsg_multiline((const char *)e_api_error, err.msg);
@@ -292,15 +329,19 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
end:
api_free_array(args);
- api_free_object(result);
+ if (handler.arena_return) {
+ arena_mem_free(arena_finish(&res_arena));
+ } else {
+ api_free_object(result);
+ }
api_clear_error(&err);
}
/// "abs(expr)" function
-static void f_abs(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_abs(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type == VAR_FLOAT) {
- float_op_wrapper(argvars, rettv, (FunPtr)&fabs);
+ float_op_wrapper(argvars, rettv, (EvalFuncData){ .float_func = &fabs });
} else {
bool error = false;
@@ -316,25 +357,25 @@ static void f_abs(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "add(list, item)" function
-static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+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 (!var_check_lock(tv_list_locked(l), N_("add() argument"),
- TV_TRANSLATE)) {
+ 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
- && !var_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
+ && !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, (char)n);
+ ga_append(&b->bv_ga, (uint8_t)n);
tv_copy(&argvars[0], rettv);
}
}
@@ -344,42 +385,21 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "and(expr, expr)" function
-static void f_and(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_and(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
& tv_get_number_chk(&argvars[1], NULL);
}
/// "api_info()" function
-static void f_api_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
Dictionary metadata = api_metadata();
(void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
- api_free_dictionary(metadata);
-}
-
-/// "append(lnum, string/list)" function
-static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- const linenr_T lnum = tv_get_lnum(&argvars[0]);
-
- set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
-}
-
-/// "appendbufline(buf, lnum, string/list)" function
-static void f_appendbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_T *const buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, true, &argvars[2], rettv);
- }
}
/// "atan2()" function
-static void f_atan2(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_atan2(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T fx;
float_T fy;
@@ -393,176 +413,16 @@ static void f_atan2(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "browse(save, title, initdir, default)" function
-static void f_browse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_browse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
}
/// "browsedir(title, initdir)" function
-static void f_browsedir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- f_browse(argvars, rettv, NULL);
-}
-
-/// Find a buffer by number or exact name.
-static buf_T *find_buffer(typval_T *avar)
-{
- buf_T *buf = NULL;
-
- if (avar->v_type == VAR_NUMBER) {
- buf = buflist_findnr((int)avar->vval.v_number);
- } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
- buf = buflist_findname_exp(avar->vval.v_string);
- if (buf == NULL) {
- // No full path name match, try a match with a URL or a "nofile"
- // buffer, these don't use the full path.
- FOR_ALL_BUFFERS(bp) {
- if (bp->b_fname != NULL
- && (path_with_url(bp->b_fname) || bt_nofilename(bp))
- && STRCMP(bp->b_fname, avar->vval.v_string) == 0) {
- buf = bp;
- break;
- }
- }
- }
- }
- return buf;
-}
-
-/// "bufadd(expr)" function
-static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- char_u *name = (char_u *)tv_get_string(&argvars[0]);
-
- rettv->vval.v_number = buflist_add(*name == NUL ? NULL : (char *)name, 0);
-}
-
-/// "bufexists(expr)" function
-static void f_bufexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
-}
-
-/// "buflisted(expr)" function
-static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_T *buf;
-
- buf = find_buffer(&argvars[0]);
- rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
-}
-
-/// "bufload(expr)" function
-static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
-{
- buf_T *buf = get_buf_arg(&argvars[0]);
-
- if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
- aco_save_T aco;
-
- aucmd_prepbuf(&aco, buf);
- swap_exists_action = SEA_NONE;
- open_buffer(false, NULL, 0);
- aucmd_restbuf(&aco);
- }
-}
-
-/// "bufloaded(expr)" function
-static void f_bufloaded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_browsedir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- buf_T *buf;
-
- buf = find_buffer(&argvars[0]);
- rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
-}
-
-/// "bufname(expr)" function
-static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- const buf_T *buf;
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- if (argvars[0].v_type == VAR_UNKNOWN) {
- buf = curbuf;
- } else {
- buf = tv_get_buf_from_arg(&argvars[0]);
- }
- if (buf != NULL && buf->b_fname != NULL) {
- rettv->vval.v_string = xstrdup(buf->b_fname);
- }
-}
-
-/// "bufnr(expr)" function
-static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- const buf_T *buf;
- bool error = false;
-
- rettv->vval.v_number = -1;
-
- if (argvars[0].v_type == VAR_UNKNOWN) {
- buf = curbuf;
- } else {
- // Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
- // and the second argument isn't zero, but we want to return early if the
- // first argument isn't a string or number so only one error is shown.
- if (!tv_check_str_or_nr(&argvars[0])) {
- return;
- }
- emsg_off++;
- buf = tv_get_buf(&argvars[0], false);
- emsg_off--;
- }
-
- // If the buffer isn't found and the second argument is not zero create a
- // new buffer.
- const char *name;
- if (buf == NULL
- && argvars[1].v_type != VAR_UNKNOWN
- && tv_get_number_chk(&argvars[1], &error) != 0
- && !error
- && (name = tv_get_string_chk(&argvars[0])) != NULL) {
- buf = buflist_new((char *)name, NULL, 1, 0);
- }
-
- if (buf != NULL) {
- rettv->vval.v_number = buf->b_fnum;
- }
-}
-
-static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
-{
- const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
- if (buf == NULL) { // no need to search if invalid arg or buffer not found
- rettv->vval.v_number = -1;
- return;
- }
-
- int winnr = 0;
- int winid;
- bool found_buf = false;
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- winnr++;
- if (wp->w_buffer == buf) {
- found_buf = true;
- winid = wp->handle;
- break;
- }
- }
- rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
-}
-
-/// "bufwinid(nr)" function
-static void f_bufwinid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_win_common(argvars, rettv, false);
-}
-
-/// "bufwinnr(nr)" function
-static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_win_common(argvars, rettv, true);
+ f_browse(argvars, rettv, fptr);
}
/// Get buffer by number or pattern.
@@ -575,7 +435,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
return NULL;
}
- char_u *name = (char_u *)tv->vval.v_string;
+ char *name = tv->vval.v_string;
if (name == NULL || *name == NUL) {
return curbuf;
@@ -588,9 +448,9 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
int save_magic = p_magic;
p_magic = true;
char *save_cpo = p_cpo;
- p_cpo = "";
+ p_cpo = empty_option;
- buf_T *buf = buflist_findnr(buflist_findpat((char *)name, (char *)name + STRLEN(name),
+ buf_T *buf = buflist_findnr(buflist_findpat(name, name + strlen(name),
true, false, curtab_only));
p_magic = save_magic;
@@ -630,7 +490,7 @@ buf_T *get_buf_arg(typval_T *arg)
}
/// "byte2line(byte)" function
-static void f_byte2line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
long boff = tv_get_number(&argvars[0]) - 1;
if (boff < 0) {
@@ -665,19 +525,19 @@ static void byteidx(typval_T *argvars, typval_T *rettv, int comp)
}
/// "byteidx()" function
-static void f_byteidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_byteidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
byteidx(argvars, rettv, false);
}
/// "byteidxcomp()" function
-static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
byteidx(argvars, rettv, true);
}
/// "call(func, arglist [, dict])" function
-static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[1].v_type != VAR_LIST) {
emsg(_(e_listreq));
@@ -688,19 +548,19 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
bool owned = false;
- char_u *func;
+ char *func;
partial_T *partial = NULL;
if (argvars[0].v_type == VAR_FUNC) {
- func = (char_u *)argvars[0].vval.v_string;
+ func = argvars[0].vval.v_string;
} else if (argvars[0].v_type == VAR_PARTIAL) {
partial = argvars[0].vval.v_partial;
- func = (char_u *)partial_name(partial);
+ func = partial_name(partial);
} else if (nlua_is_table_from_lua(&argvars[0])) {
// TODO(tjdevries): UnifiedCallback
func = nlua_register_table_as_callable(&argvars[0]);
owned = true;
} else {
- func = (char_u *)tv_get_string(&argvars[0]);
+ func = (char *)tv_get_string(&argvars[0]);
}
if (*func == NUL) {
@@ -726,13 +586,13 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "changenr()" function
-static void f_changenr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_changenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = curbuf->b_u_seq_cur;
}
/// "chanclose(id[, stream])" function
-static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_chanclose(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -771,7 +631,7 @@ static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "chansend(id, data)" function
-static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -788,6 +648,14 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ptrdiff_t input_len = 0;
char *input = NULL;
+ uint64_t id = (uint64_t)argvars[0].vval.v_number;
+#ifdef UNIX
+ bool crlf = false;
+#else
+ Channel *chan = find_channel(id);
+ bool crlf = (chan != NULL && chan->term) ? true: false;
+#endif
+
if (argvars[1].v_type == VAR_BLOB) {
const blob_T *const b = argvars[1].vval.v_blob;
input_len = tv_blob_len(b);
@@ -795,7 +663,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
input = xmemdup(b->bv_ga.ga_data, (size_t)input_len);
}
} else {
- input = save_tv_as_string(&argvars[1], &input_len, false);
+ input = save_tv_as_string(&argvars[1], &input_len, false, crlf);
}
if (!input) {
@@ -803,7 +671,6 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// or there is no input to send.
return;
}
- uint64_t id = (uint64_t)argvars[0].vval.v_number;
const char *error = NULL;
rettv->vval.v_number = (varnumber_T)channel_send(id, input, (size_t)input_len, true, &error);
if (error) {
@@ -812,7 +679,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "char2nr(string)" function
-static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_char2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[1].v_type != VAR_UNKNOWN) {
if (!tv_check_num(&argvars[1])) {
@@ -829,15 +696,38 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// otherwise the byte index of the column.
static void get_col(typval_T *argvars, typval_T *rettv, bool charcol)
{
+ if (tv_check_for_string_or_list_arg(argvars, 0) == FAIL
+ || tv_check_for_opt_number_arg(argvars, 1) == FAIL) {
+ return;
+ }
+
+ switchwin_T switchwin;
+ bool winchanged = false;
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ // use the window specified in the second argument
+ tabpage_T *tp;
+ win_T *wp = win_id2wp_tp((int)tv_get_number(&argvars[1]), &tp);
+ if (wp == NULL || tp == NULL) {
+ return;
+ }
+
+ if (switch_win_noblock(&switchwin, wp, tp, true) != OK) {
+ return;
+ }
+
+ check_cursor();
+ winchanged = true;
+ }
+
colnr_T col = 0;
int fnum = curbuf->b_fnum;
-
pos_T *fp = var2fpos(&argvars[0], false, &fnum, charcol);
if (fp != NULL && fnum == curbuf->b_fnum) {
if (fp->col == MAXCOL) {
// '> can be MAXCOL, get the length of the line then
if (fp->lnum <= curbuf->b_ml.ml_line_count) {
- col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
+ col = (colnr_T)strlen(ml_get(fp->lnum)) + 1;
} else {
col = MAXCOL;
}
@@ -846,11 +736,12 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol)
// col(".") when the cursor is on the NUL at the end of the line
// because of "coladd" can be seen as an extra column.
if (virtual_active() && fp == &curwin->w_cursor) {
- char_u *p = get_cursor_pos_ptr();
+ char *p = get_cursor_pos_ptr();
if (curwin->w_cursor.coladd >=
- (colnr_T)win_chartabsize(curwin, p, curwin->w_virtcol - curwin->w_cursor.coladd)) {
+ (colnr_T)win_chartabsize(curwin, p,
+ curwin->w_virtcol - curwin->w_cursor.coladd)) {
int l;
- if (*p != NUL && p[(l = utfc_ptr2len((char *)p))] == NUL) {
+ if (*p != NUL && p[(l = utfc_ptr2len(p))] == NUL) {
col += l;
}
}
@@ -858,23 +749,28 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol)
}
}
rettv->vval.v_number = col;
+
+ if (winchanged) {
+ restore_win_noblock(&switchwin, true);
+ }
}
/// "charcol()" function
-static void f_charcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_col(argvars, rettv, true);
}
/// "charidx()" function
-static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_STRING
|| argvars[1].v_type != VAR_NUMBER
|| (argvars[2].v_type != VAR_UNKNOWN
- && argvars[2].v_type != VAR_NUMBER)) {
+ && argvars[2].v_type != VAR_NUMBER
+ && argvars[2].v_type != VAR_BOOL)) {
emsg(_(e_invarg));
return;
}
@@ -889,7 +785,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
countcc = (int)tv_get_number(&argvars[2]);
}
if (countcc < 0 || countcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), countcc);
return;
}
@@ -913,7 +809,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "chdir(dir)" function
-static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -925,12 +821,12 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// Return the current directory
- char_u *cwd = xmalloc(MAXPATHL);
+ char *cwd = xmalloc(MAXPATHL);
if (os_dirname(cwd, MAXPATHL) != FAIL) {
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(cwd);
#endif
- rettv->vval.v_string = (char *)vim_strsave(cwd);
+ rettv->vval.v_string = xstrdup(cwd);
}
xfree(cwd);
@@ -948,7 +844,7 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "cindent(lnum)" function
-static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
pos_T pos = curwin->w_cursor;
linenr_T lnum = tv_get_lnum(argvars);
@@ -963,26 +859,26 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
win_T *get_optional_window(typval_T *argvars, int idx)
{
- win_T *win = curwin;
+ if (argvars[idx].v_type == VAR_UNKNOWN) {
+ return curwin;
+ }
- if (argvars[idx].v_type != VAR_UNKNOWN) {
- win = find_win_by_nr_or_id(&argvars[idx]);
- if (win == NULL) {
- emsg(_(e_invalwindow));
- return NULL;
- }
+ win_T *win = find_win_by_nr_or_id(&argvars[idx]);
+ if (win == NULL) {
+ emsg(_(e_invalwindow));
+ return NULL;
}
return win;
}
/// "col(string)" function
-static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_col(argvars, rettv, false);
}
/// "confirm(message, buttons[, default [, type]])" function
-static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_confirm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[NUMBUFLEN];
char buf2[NUMBUFLEN];
@@ -1029,19 +925,19 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!error) {
- rettv->vval.v_number = do_dialog(type, NULL, (char_u *)message, (char_u *)buttons, def, NULL,
+ rettv->vval.v_number = do_dialog(type, NULL, (char *)message, (char *)buttons, def, NULL,
false);
}
}
/// "copy()" function
-static void f_copy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
var_item_copy(NULL, &argvars[0], rettv, false, 0);
}
/// "count()" function
-static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
long n = 0;
int ic = 0;
@@ -1052,15 +948,15 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[0].v_type == VAR_STRING) {
- const char_u *expr = (char_u *)tv_get_string_chk(&argvars[1]);
- const char_u *p = (char_u *)argvars[0].vval.v_string;
+ const char *expr = tv_get_string_chk(&argvars[1]);
+ const char *p = argvars[0].vval.v_string;
if (!error && expr != NULL && *expr != NUL && p != NULL) {
if (ic) {
- const size_t len = STRLEN(expr);
+ const size_t len = strlen(expr);
while (*p != NUL) {
- if (mb_strnicmp(p, expr, len) == 0) {
+ if (mb_strnicmp((char *)p, (char *)expr, len) == 0) {
n++;
p += len;
} else {
@@ -1068,10 +964,10 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
} else {
- char_u *next;
- while ((next = (char_u *)strstr((char *)p, (char *)expr)) != NULL) {
+ char *next;
+ while ((next = strstr((char *)p, (char *)expr)) != NULL) {
n++;
- p = next + STRLEN(expr);
+ p = next + strlen(expr);
}
}
}
@@ -1127,31 +1023,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = n;
}
-/// "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
-///
-/// Checks the existence of a cscope connection.
-static void f_cscope_connection(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- int num = 0;
- const char *dbpath = NULL;
- const char *prepend = NULL;
- char buf[NUMBUFLEN];
-
- if (argvars[0].v_type != VAR_UNKNOWN
- && argvars[1].v_type != VAR_UNKNOWN) {
- num = (int)tv_get_number(&argvars[0]);
- dbpath = tv_get_string(&argvars[1]);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- prepend = tv_get_string_buf(&argvars[2], buf);
- }
- }
-
- rettv->vval.v_number = cs_connection(num, (char_u *)dbpath,
- (char_u *)prepend);
-}
-
/// "ctxget([{index}])" function
-static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
size_t index = 0;
if (argvars[0].v_type == VAR_NUMBER) {
@@ -1175,7 +1048,7 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "ctxpop()" function
-static void f_ctxpop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_ctxpop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (!ctx_restore(NULL, kCtxAll)) {
emsg(_("Context stack is empty"));
@@ -1183,7 +1056,7 @@ static void f_ctxpop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "ctxpush([{types}])" function
-static void f_ctxpush(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_ctxpush(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int types = kCtxAll;
if (argvars[0].v_type == VAR_LIST) {
@@ -1214,7 +1087,7 @@ static void f_ctxpush(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "ctxset({context}[, {index}])" function
-static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_DICT) {
semsg(_(e_invarg2), "expected dictionary as first argument");
@@ -1254,7 +1127,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "ctxsize()" function
-static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_ctxsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = (varnumber_T)ctx_size();
@@ -1265,7 +1138,7 @@ static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Otherwise use the column number as a byte offset.
static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
{
- long line, col;
+ long lnum, col;
long coladd = 0;
bool set_curswant = true;
@@ -1279,7 +1152,7 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
return;
}
- line = pos.lnum;
+ lnum = pos.lnum;
col = pos.col;
coladd = pos.coladd;
if (curswant >= 0) {
@@ -1288,10 +1161,15 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
}
} else if ((argvars[0].v_type == VAR_NUMBER || argvars[0].v_type == VAR_STRING)
&& (argvars[1].v_type == VAR_NUMBER || argvars[1].v_type == VAR_STRING)) {
- line = tv_get_lnum(argvars);
+ lnum = tv_get_lnum(argvars);
+ if (lnum < 0) {
+ semsg(_(e_invarg2), tv_get_string(&argvars[0]));
+ } else if (lnum == 0) {
+ lnum = curwin->w_cursor.lnum;
+ }
col = (long)tv_get_number_chk(&argvars[1], NULL);
if (charcol) {
- col = buf_charidx_to_byteidx(curbuf, (linenr_T)line, (int)col) + 1;
+ col = buf_charidx_to_byteidx(curbuf, (linenr_T)lnum, (int)col) + 1;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
coladd = (long)tv_get_number_chk(&argvars[2], NULL);
@@ -1300,11 +1178,11 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
emsg(_(e_invarg));
return;
}
- if (line < 0 || col < 0 || coladd < 0) {
+ if (lnum < 0 || col < 0 || coladd < 0) {
return; // type error; errmsg already given
}
- if (line > 0) {
- curwin->w_cursor.lnum = (linenr_T)line;
+ if (lnum > 0) {
+ curwin->w_cursor.lnum = (linenr_T)lnum;
}
if (col > 0) {
curwin->w_cursor.col = (colnr_T)col - 1;
@@ -1326,43 +1204,45 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
/// Moves the cursor to the specified line and column.
///
/// @return 0 when the position could be set, -1 otherwise.
-static void f_cursor(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_cursor(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
set_cursorpos(argvars, rettv, false);
}
/// "debugbreak()" function
-static void f_debugbreak(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_debugbreak(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = FAIL;
int pid = (int)tv_get_number(&argvars[0]);
if (pid == 0) {
emsg(_(e_invarg));
- } else {
-#ifdef WIN32
- HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ return;
+ }
- if (hProcess != NULL) {
- DebugBreakProcess(hProcess);
- CloseHandle(hProcess);
- rettv->vval.v_number = OK;
- }
+#ifdef MSWIN
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ if (hProcess == NULL) {
+ return;
+ }
+
+ DebugBreakProcess(hProcess);
+ CloseHandle(hProcess);
+ rettv->vval.v_number = OK;
#else
- uv_kill(pid, SIGINT);
+ uv_kill(pid, SIGINT);
#endif
- }
}
/// "deepcopy()" function
-static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int noref = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- noref = (int)tv_get_number_chk(&argvars[1], NULL);
+ noref = (int)tv_get_bool_chk(&argvars[1], NULL);
}
if (noref < 0 || noref > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), noref);
} else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID()
@@ -1371,7 +1251,7 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "delete()" function
-static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_delete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = -1;
if (check_secure()) {
@@ -1407,7 +1287,7 @@ static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// dictwatcheradd(dict, key, funcref) function
-static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
@@ -1445,7 +1325,7 @@ static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// dictwatcherdel(dict, key, funcref) function
-static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
@@ -1479,96 +1359,20 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
callback_free(&callback);
}
-/// "deletebufline()" function
-static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_T *const buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- return;
- }
- const bool is_curbuf = buf == curbuf;
- const bool save_VIsual_active = VIsual_active;
-
- linenr_T last;
- const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- last = tv_get_lnum_buf(&argvars[2], buf);
- } else {
- last = first;
- }
-
- if (buf->b_ml.ml_mfp == NULL || first < 1
- || first > buf->b_ml.ml_line_count || last < first) {
- rettv->vval.v_number = 1; // FAIL
- return;
- }
-
- buf_T *curbuf_save = NULL;
- win_T *curwin_save = NULL;
- if (!is_curbuf) {
- VIsual_active = false;
- curbuf_save = curbuf;
- curwin_save = curwin;
- curbuf = buf;
- find_win_for_curbuf();
- }
- if (last > curbuf->b_ml.ml_line_count) {
- last = curbuf->b_ml.ml_line_count;
- }
- const long count = last - first + 1;
-
- // When coming here from Insert mode, sync undo, so that this can be
- // undone separately from what was previously inserted.
- if (u_sync_once == 2) {
- u_sync_once = 1; // notify that u_sync() was called
- u_sync(true);
- }
-
- if (u_save(first - 1, last + 1) == FAIL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- for (linenr_T lnum = first; lnum <= last; lnum++) {
- ml_delete(first, true);
- }
-
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp->w_buffer == buf) {
- if (wp->w_cursor.lnum > last) {
- wp->w_cursor.lnum -= (linenr_T)count;
- } else if (wp->w_cursor.lnum > first) {
- wp->w_cursor.lnum = first;
- }
- if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
- wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
- }
- }
- }
- check_cursor_col();
- deleted_lines_mark(first, count);
- }
-
- if (!is_curbuf) {
- curbuf = curbuf_save;
- curwin = curwin_save;
- VIsual_active = save_VIsual_active;
- }
-}
-
/// "did_filetype()" function
-static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_did_filetype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = did_filetype;
}
/// "diff_filler()" function
-static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_diff_filler(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = MAX(0, diff_check(curwin, tv_get_lnum(argvars)));
}
/// "diff_hlID()" function
-static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
linenr_T lnum = tv_get_lnum(argvars);
static linenr_T prev_lnum = 0;
@@ -1585,9 +1389,10 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|| changedtick != buf_get_changedtick(curbuf)
|| fnum != curbuf->b_fnum) {
// New line, buffer, change: need to get the values.
- int filler_lines = diff_check(curwin, lnum);
- if (filler_lines < 0) {
- if (filler_lines == -1) {
+ int linestatus = 0;
+ int filler_lines = diff_check_with_linestatus(curwin, lnum, &linestatus);
+ if (filler_lines < 0 || linestatus < 0) {
+ if (filler_lines == -1 || linestatus == -1) {
change_start = MAXCOL;
change_end = -1;
if (diff_find_change(curwin, lnum, &change_start, &change_end)) {
@@ -1614,11 +1419,11 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
hlID = HLF_CHD; // Changed line.
}
}
- rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)(hlID + 1);
+ rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (hlID + 1);
}
/// "empty({expr})" function
-static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_empty(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
bool n = true;
@@ -1668,7 +1473,7 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "environ()" function
-static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_environ(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
@@ -1690,7 +1495,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char c = env[i][len];
env[i][len] = NUL;
-#ifdef WIN32
+#ifdef MSWIN
// Upper-case all the keys for Windows so we can detect duplicates
char *const key = strcase_save(str, true);
#else
@@ -1713,32 +1518,31 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "escape({string}, {chars})" function
-static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_escape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[NUMBUFLEN];
- rettv->vval.v_string = (char *)vim_strsave_escaped((const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1],
- buf));
+ rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
+ tv_get_string_buf(&argvars[1], buf));
rettv->v_type = VAR_STRING;
}
/// "getenv()" function
-static void f_getenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u *p = (char_u *)vim_getenv(tv_get_string(&argvars[0]));
+ char *p = vim_getenv(tv_get_string(&argvars[0]));
if (p == NULL) {
rettv->v_type = VAR_SPECIAL;
rettv->vval.v_special = kSpecialVarNull;
return;
}
- rettv->vval.v_string = (char *)p;
+ rettv->vval.v_string = p;
rettv->v_type = VAR_STRING;
}
/// "eval()" function
-static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *s = tv_get_string_chk(&argvars[0]);
if (s != NULL) {
@@ -1759,15 +1563,15 @@ static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "eventhandler()" function
-static void f_eventhandler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_eventhandler(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = vgetc_busy;
}
/// "executable()" function
-static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_executable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- if (tv_check_for_string(&argvars[0]) == FAIL) {
+ if (tv_check_for_string_arg(argvars, 0) == FAIL) {
return;
}
@@ -1794,7 +1598,7 @@ static char *get_list_line(int c, void *cookie, int indent, bool do_concat)
return s == NULL ? NULL : xstrdup(s);
}
-static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int arg_off)
+void execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
{
const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_silent;
@@ -1873,30 +1677,15 @@ static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int
}
/// "execute(command)" function
-static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- execute_common(argvars, rettv, fptr, 0);
-}
-
-/// "win_execute(win_id, command)" function
-static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- // Return an empty string if something fails.
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- int id = (int)tv_get_number(argvars);
- tabpage_T *tp;
- win_T *wp = win_id2wp_tp(id, &tp);
- if (wp != NULL && tp != NULL) {
- WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, fptr, 1));
- }
+ execute_common(argvars, rettv, 0);
}
/// "exepath()" function
-static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- if (tv_check_for_nonempty_string(&argvars[0]) == FAIL) {
+ if (tv_check_for_nonempty_string_arg(argvars, 0) == FAIL) {
return;
}
@@ -1906,7 +1695,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
#ifdef BACKSLASH_IN_FILENAME
if (path != NULL) {
- slash_adjust((char_u *)path);
+ slash_adjust(path);
}
#endif
@@ -1915,7 +1704,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "exists()" function
-static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int n = false;
@@ -1955,13 +1744,12 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "expand()" function
-static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char *errormsg;
int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
bool error = false;
#ifdef BACKSLASH_IN_FILENAME
- char_u *p_csl_save = p_csl;
+ char *p_csl_save = p_csl;
// avoid using 'completeslash' here
p_csl = empty_option;
@@ -1977,10 +1765,17 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *s = tv_get_string(&argvars[0]);
if (*s == '%' || *s == '#' || *s == '<') {
- emsg_off++;
+ if (p_verbose == 0) {
+ emsg_off++;
+ }
size_t len;
- char_u *result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL);
- emsg_off--;
+ char *errormsg = NULL;
+ char *result = eval_vars((char *)s, s, &len, NULL, &errormsg, NULL, false);
+ if (p_verbose == 0) {
+ emsg_off--;
+ } else if (errormsg != NULL) {
+ emsg(errormsg);
+ }
if (rettv->v_type == VAR_LIST) {
tv_list_alloc_ret(rettv, (result != NULL));
if (result != NULL) {
@@ -1988,7 +1783,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
XFREE_CLEAR(result);
} else {
- rettv->vval.v_string = (char *)result;
+ rettv->vval.v_string = result;
}
} else {
// When the optional second argument is non-zero, don't remove matches
@@ -2005,10 +1800,9 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
options += WILD_ICASE;
}
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = (char *)ExpandOne(&xpc, (char_u *)s, NULL, options,
- WILD_ALL);
+ rettv->vval.v_string = ExpandOne(&xpc, (char *)s, NULL, options, WILD_ALL);
} else {
- ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL_KEEP);
+ ExpandOne(&xpc, (char *)s, NULL, options, WILD_ALL_KEEP);
tv_list_alloc_ret(rettv, xpc.xp_numfiles);
for (int i = 0; i < xpc.xp_numfiles; i++) {
tv_list_append_string(rettv->vval.v_list,
@@ -2026,7 +1820,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "menu_get(path [, modes])" function
-static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenMayKnow);
int modes = MENU_ALL_MODES;
@@ -2039,9 +1833,15 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "expandcmd()" function
/// Expand all the special characters in a command string.
-static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *errormsg = NULL;
+ bool emsgoff = true;
+
+ if (argvars[1].v_type == VAR_DICT
+ && tv_dict_get_bool(argvars[1].vval.v_dict, "errmsg", kBoolVarFalse)) {
+ emsgoff = false;
+ }
rettv->v_type = VAR_STRING;
char *cmdstr = xstrdup(tv_get_string(&argvars[0]));
@@ -2055,15 +1855,23 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
};
eap.argt |= EX_NOSPC;
- emsg_off++;
- expand_filename(&eap, &cmdstr, &errormsg);
- emsg_off--;
+ if (emsgoff) {
+ emsg_off++;
+ }
+ if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL) {
+ if (!emsgoff && errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
+ }
+ if (emsgoff) {
+ emsg_off--;
+ }
rettv->vval.v_string = cmdstr;
}
/// "flatten(list[, {maxdepth}])" function
-static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
bool error = false;
@@ -2088,9 +1896,9 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *list = argvars[0].vval.v_list;
if (list != NULL
- && !var_check_lock(tv_list_locked(list),
- N_("flatten() argument"),
- TV_TRANSLATE)
+ && !value_check_lock(tv_list_locked(list),
+ N_("flatten() argument"),
+ TV_TRANSLATE)
&& tv_list_flatten(list, maxdepth) == OK) {
tv_copy(&argvars[0], rettv);
}
@@ -2098,7 +1906,7 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "extend(list, list [, idx])" function
/// "extend(dict, dict [, action])" function
-static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const arg_errmsg = N_("extend() argument");
@@ -2107,7 +1915,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *const l1 = argvars[0].vval.v_list;
list_T *const l2 = argvars[1].vval.v_list;
- if (!var_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
+ if (!value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
listitem_T *item;
if (argvars[2].v_type != VAR_UNKNOWN) {
long before = (long)tv_get_number_chk(&argvars[2], &error);
@@ -2136,13 +1944,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dict_T *const d1 = argvars[0].vval.v_dict;
dict_T *const d2 = argvars[1].vval.v_dict;
if (d1 == NULL) {
- const bool locked = var_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
+ const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
(void)locked;
assert(locked == true);
} else if (d2 == NULL) {
// Do nothing
tv_copy(&argvars[0], rettv);
- } else if (!var_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ } else if (!value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *action = "force";
// Check the third argument.
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -2174,7 +1982,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "feedkeys()" function
-static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// This is not allowed in the sandbox. If the commands would still be
// executed in the sandbox it would be OK, but it probably happens later,
@@ -2195,17 +2003,17 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "filereadable()" function
-static void f_filereadable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_filereadable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const p = tv_get_string(&argvars[0]);
rettv->vval.v_number =
- (*p && !os_isdir((const char_u *)p) && os_file_is_readable(p));
+ (*p && !os_isdir(p) && os_file_is_readable(p));
}
/// @return 0 for not writable
/// 1 for writable file
/// 2 for a dir which we have rights to write into.
-static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *filename = tv_get_string(&argvars[0]);
rettv->vval.v_number = os_file_is_writable(filename);
@@ -2213,8 +2021,8 @@ static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
{
- char_u *fresult = NULL;
- char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
+ char *fresult = NULL;
+ char *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
int count = 1;
bool first = true;
bool error = false;
@@ -2231,7 +2039,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
error = true;
} else {
if (*p != NUL) {
- path = (char_u *)p;
+ path = (char *)p;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -2249,12 +2057,12 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) {
xfree(fresult);
}
- fresult = find_file_in_path_option(first ? (char_u *)fname : NULL,
+ fresult = find_file_in_path_option(first ? (char *)fname : NULL,
first ? strlen(fname) : 0,
0, first, path,
- find_what, (char_u *)curbuf->b_ffname,
+ find_what, curbuf->b_ffname,
(find_what == FINDFILE_DIR
- ? (char_u *)""
+ ? ""
: curbuf->b_p_sua));
first = false;
@@ -2265,46 +2073,48 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
}
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = (char *)fresult;
+ rettv->vval.v_string = fresult;
}
}
/// "filter()" function
-static void f_filter(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_filter(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
filter_map(argvars, rettv, false);
}
/// "finddir({fname}[, {path}[, {count}]])" function
-static void f_finddir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_finddir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
findfilendir(argvars, rettv, FINDFILE_DIR);
}
/// "findfile({fname}[, {path}[, {count}]])" function
-static void f_findfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_findfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
findfilendir(argvars, rettv, FINDFILE_FILE);
}
/// "float2nr({float})" function
-static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T f;
- if (tv_get_float_chk(argvars, &f)) {
- if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
- rettv->vval.v_number = -VARNUMBER_MAX;
- } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
- rettv->vval.v_number = VARNUMBER_MAX;
- } else {
- rettv->vval.v_number = (varnumber_T)f;
- }
+ if (!tv_get_float_chk(argvars, &f)) {
+ return;
+ }
+
+ if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
+ rettv->vval.v_number = -VARNUMBER_MAX;
+ } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
+ rettv->vval.v_number = VARNUMBER_MAX;
+ } else {
+ rettv->vval.v_number = (varnumber_T)f;
}
}
/// "fmod()" function
-static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_fmod(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T fx;
float_T fy;
@@ -2318,16 +2128,16 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "fnameescape({string})" function
-static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_fnameescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_string = vim_strsave_fnameescape(tv_get_string(&argvars[0]), VSE_NONE);
rettv->v_type = VAR_STRING;
}
/// "fnamemodify({fname}, {mods})" function
-static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u *fbuf = NULL;
+ char *fbuf = NULL;
size_t len = 0;
char buf[NUMBUFLEN];
const char *fname = tv_get_string_chk(&argvars[0]);
@@ -2339,7 +2149,7 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (*mods != NUL) {
size_t usedlen = 0;
(void)modify_fname((char *)mods, false, &usedlen,
- (char **)&fname, (char **)&fbuf, &len);
+ (char **)&fname, &fbuf, &len);
}
}
@@ -2353,21 +2163,21 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "foreground()" function
-static void f_foreground(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_foreground(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{}
-static void f_funcref(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_funcref(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- common_function(argvars, rettv, true, fptr);
+ common_function(argvars, rettv, true);
}
-static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_function(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- common_function(argvars, rettv, false, fptr);
+ common_function(argvars, rettv, false);
}
/// "garbagecollect()" function
-static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_garbagecollect(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// This is postponed until we are back at the toplevel, because we may be
// using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
@@ -2379,7 +2189,7 @@ static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "get()" function
-static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
typval_T *tv = NULL;
bool what_is_dict = false;
@@ -2426,7 +2236,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
pt = argvars[0].vval.v_partial;
} else {
CLEAR_FIELD(fref_pt);
- fref_pt.pt_name = (char_u *)argvars[0].vval.v_string;
+ fref_pt.pt_name = argvars[0].vval.v_string;
pt = &fref_pt;
}
@@ -2434,13 +2244,17 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const what = tv_get_string(&argvars[1]);
if (strcmp(what, "func") == 0 || strcmp(what, "name") == 0) {
+ const char *name = partial_name(pt);
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
- const char *const n = (const char *)partial_name(pt);
- assert(n != NULL);
- rettv->vval.v_string = xstrdup(n);
+ assert(name != NULL);
if (rettv->v_type == VAR_FUNC) {
- func_ref((char_u *)rettv->vval.v_string);
+ func_ref((char *)name);
+ }
+ if (*what == 'n' && pt->pt_name == NULL && pt->pt_func != NULL) {
+ // use <SNR> instead of the byte code
+ name = printable_func_name(pt->pt_func);
}
+ rettv->vval.v_string = xstrdup(name);
} else if (strcmp(what, "dict") == 0) {
what_is_dict = true;
if (pt->pt_dict != NULL) {
@@ -2475,120 +2289,8 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "getbufinfo()" function
-static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_T *argbuf = NULL;
- bool filtered = false;
- bool sel_buflisted = false;
- bool sel_bufloaded = false;
- bool sel_bufmodified = false;
-
- tv_list_alloc_ret(rettv, kListLenMayKnow);
-
- // List of all the buffers or selected buffers
- if (argvars[0].v_type == VAR_DICT) {
- dict_T *sel_d = argvars[0].vval.v_dict;
-
- if (sel_d != NULL) {
- dictitem_T *di;
-
- filtered = true;
-
- di = tv_dict_find(sel_d, S_LEN("buflisted"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_buflisted = true;
- }
-
- di = tv_dict_find(sel_d, S_LEN("bufloaded"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_bufloaded = true;
- }
- di = tv_dict_find(sel_d, S_LEN("bufmodified"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_bufmodified = true;
- }
- }
- } else if (argvars[0].v_type != VAR_UNKNOWN) {
- // Information about one buffer. Argument specifies the buffer
- argbuf = tv_get_buf_from_arg(&argvars[0]);
- if (argbuf == NULL) {
- return;
- }
- }
-
- // Return information about all the buffers or a specified buffer
- FOR_ALL_BUFFERS(buf) {
- if (argbuf != NULL && argbuf != buf) {
- continue;
- }
- if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
- || (sel_buflisted && !buf->b_p_bl)
- || (sel_bufmodified && !buf->b_changed))) {
- continue;
- }
-
- dict_T *const d = get_buffer_info(buf);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (argbuf != NULL) {
- return;
- }
- }
-}
-
-/// Get line or list of lines from buffer "buf" into "rettv".
-///
-/// @param retlist if TRUE, then the lines are returned as a Vim List.
-///
-/// @return range (from start to end) of lines in rettv from the specified
-/// buffer.
-static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
-{
- rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
- rettv->vval.v_string = NULL;
-
- if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
- if (retlist) {
- tv_list_alloc_ret(rettv, 0);
- }
- return;
- }
-
- if (retlist) {
- if (start < 1) {
- start = 1;
- }
- if (end > buf->b_ml.ml_line_count) {
- end = buf->b_ml.ml_line_count;
- }
- tv_list_alloc_ret(rettv, end - start + 1);
- while (start <= end) {
- tv_list_append_string(rettv->vval.v_list,
- (const char *)ml_get_buf(buf, start++, false), -1);
- }
- } else {
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string =
- (char *)((start >= 1 && start <= buf->b_ml.ml_line_count)
- ? vim_strsave(ml_get_buf(buf, start, false)) : NULL);
- }
-}
-
-/// "getbufline()" function
-static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
-
- const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
- const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
- ? lnum
- : tv_get_lnum_buf(&argvars[2], buf));
-
- get_buffer_lines(buf, lnum, end, true, rettv);
-}
-
/// "getchangelist()" function
-static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getchangelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, 2);
@@ -2693,13 +2395,13 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos, bool
}
/// "getcharpos()" function
-static void f_getcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getpos_both(argvars, rettv, false, true);
}
/// "getcharsearch()" function
-static void f_getcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
@@ -2710,49 +2412,6 @@ static void f_getcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_nr(dict, S_LEN("until"), last_csearch_until());
}
-/// "getcmdcompltype()" function
-static void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char *)get_cmdline_completion();
-}
-
-/// "getcmdline()" function
-static void f_getcmdline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char *)get_cmdline_str();
-}
-
-/// "getcmdpos()" function
-static void f_getcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = get_cmdline_pos() + 1;
-}
-
-/// "getcmdscreenpos()" function
-static void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = get_cmdline_screen_pos() + 1;
-}
-
-/// "getcmdtype()" function
-static void f_getcmdtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xmallocz(1);
- rettv->vval.v_string[0] = (char)get_cmdline_type();
-}
-
-/// "getcmdwintype()" function
-static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- rettv->vval.v_string = xmallocz(1);
- rettv->vval.v_string[0] = (char)cmdwin_type;
-}
-
/// `getcwd([{win}[, {tab}]])` function
///
/// Every scope not specified implies the currently selected scope object.
@@ -2762,7 +2421,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// @pre An argument may not be -1 if preceding arguments are not all -1.
///
/// @post The return value will be a string.
-static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// Possible scope of working directory to return.
CdScope scope = kCdScopeInvalid;
@@ -2857,13 +2516,13 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
FALLTHROUGH; // In global directory, just need to get OS CWD.
case kCdScopeInvalid: // If called without any arguments, get OS CWD.
- if (os_dirname((char_u *)cwd, MAXPATHL) == FAIL) {
+ if (os_dirname(cwd, MAXPATHL) == FAIL) {
from = ""; // Return empty string on failure.
}
}
if (from) {
- STRLCPY(cwd, from, MAXPATHL);
+ xstrlcpy(cwd, from, MAXPATHL);
}
rettv->vval.v_string = xstrdup(cwd);
@@ -2875,17 +2534,17 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getfontname()" function
-static void f_getfontname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getfontname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
}
/// "getfperm({fname})" function
-static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *perm = NULL;
- char_u flags[] = "rwx";
+ char flags[] = "rwx";
const char *filename = tv_get_string(&argvars[0]);
int32_t file_perm = os_getperm(filename);
@@ -2893,7 +2552,7 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
perm = xstrdup("---------");
for (int i = 0; i < 9; i++) {
if (file_perm & (1 << (8 - i))) {
- perm[i] = (char)flags[i % 3];
+ perm[i] = flags[i % 3];
}
}
}
@@ -2902,7 +2561,7 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getfsize({fname})" function
-static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getfsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *fname = tv_get_string(&argvars[0]);
@@ -2911,7 +2570,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FileInfo file_info;
if (os_fileinfo(fname, &file_info)) {
uint64_t filesize = os_fileinfo_size(&file_info);
- if (os_isdir((const char_u *)fname)) {
+ if (os_isdir(fname)) {
rettv->vval.v_number = 0;
} else {
rettv->vval.v_number = (varnumber_T)filesize;
@@ -2927,7 +2586,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getftime({fname})" function
-static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *fname = tv_get_string(&argvars[0]);
@@ -2940,9 +2599,9 @@ static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getftype({fname})" function
-static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getftype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u *type = NULL;
+ char *type = NULL;
char *t;
const char *fname = tv_get_string(&argvars[0]);
@@ -2968,13 +2627,13 @@ static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
t = "other";
}
- type = vim_strsave((char_u *)t);
+ type = xstrdup(t);
}
- rettv->vval.v_string = (char *)type;
+ rettv->vval.v_string = type;
}
/// "getjumplist()" function
-static void f_getjumplist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getjumplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenMayKnow);
win_T *const wp = find_tabwin(&argvars[0], &argvars[1]);
@@ -3004,26 +2663,8 @@ static void f_getjumplist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "getline(lnum, [end])" function
-static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- linenr_T end;
- bool retlist;
-
- const linenr_T lnum = tv_get_lnum(argvars);
- if (argvars[1].v_type == VAR_UNKNOWN) {
- end = lnum;
- retlist = false;
- } else {
- end = tv_get_lnum(&argvars[1]);
- retlist = true;
- }
-
- get_buffer_lines(curbuf, lnum, end, retlist, rettv);
-}
-
/// "getmarklist()" function
-static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getmarklist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenMayKnow);
@@ -3041,7 +2682,7 @@ static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getmousepos()" function
-static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getmousepos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int row = mouse_row;
int col = mouse_col;
@@ -3082,24 +2723,24 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getpid()" function
-static void f_getpid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = os_get_pid();
}
/// "getcurpos(string)" function
-static void f_getcurpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getcurpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getpos_both(argvars, rettv, true, false);
}
-static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getpos_both(argvars, rettv, true, true);
}
/// "getpos(string)" function
-static void f_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getpos_both(argvars, rettv, false, false);
}
@@ -3109,23 +2750,23 @@ static void f_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Returns zero on error.
static int getreg_get_regname(typval_T *argvars)
{
- const char_u *strregname;
+ const char *strregname;
if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = (const char_u *)tv_get_string_chk(&argvars[0]);
+ strregname = tv_get_string_chk(&argvars[0]);
if (strregname == NULL) { // type error; errmsg already given
return 0;
}
} else {
// Default to v:register
- strregname = (char_u *)get_vim_var_str(VV_REG);
+ strregname = get_vim_var_str(VV_REG);
}
- return *strregname == 0 ? '"' : *strregname;
+ return *strregname == 0 ? '"' : (uint8_t)(*strregname);
}
/// "getreg()" function
-static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getreg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int arg2 = false;
bool return_list = false;
@@ -3161,7 +2802,7 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "getregtype()" function
-static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getregtype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// on error return an empty string
rettv->v_type = VAR_STRING;
@@ -3180,40 +2821,8 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = xstrdup(buf);
}
-/// "gettabinfo()" function
-static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tabpage_T *tparg = NULL;
-
- tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
- ? 1
- : kListLenMayKnow));
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- // Information about one tab page
- tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- if (tparg == NULL) {
- return;
- }
- }
-
- // Get information about a specific tab page or all tab pages
- int tpnr = 0;
- FOR_ALL_TABS(tp) {
- tpnr++;
- if (tparg != NULL && tp != tparg) {
- continue;
- }
- dict_T *const d = get_tabpage_info(tp, tpnr);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (tparg != NULL) {
- return;
- }
- }
-}
-
/// "gettagstack()" function
-static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_gettagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
win_T *wp = curwin; // default is current window
@@ -3229,41 +2838,6 @@ static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
get_tagstack(wp, rettv->vval.v_dict);
}
-/// "getwininfo()" function
-static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wparg = NULL;
-
- tv_list_alloc_ret(rettv, kListLenMayKnow);
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wparg = win_id2wp((int)tv_get_number(&argvars[0]));
- if (wparg == NULL) {
- return;
- }
- }
-
- // Collect information about either all the windows across all the tab
- // pages or one particular window.
- int16_t tabnr = 0;
- FOR_ALL_TABS(tp) {
- tabnr++;
- int16_t winnr = 0;
- FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
- winnr++;
- if (wparg != NULL && wp != wparg) {
- continue;
- }
- dict_T *const d = get_win_info(wp, tabnr, winnr);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (wparg != NULL) {
- // found information about a specific window
- return;
- }
- }
- }
-}
-
/// Dummy timer callback. Used by f_wait().
static void dummy_timer_due_cb(TimeWatcher *tw, void *data)
{}
@@ -3275,7 +2849,7 @@ static void dummy_timer_close_cb(TimeWatcher *tw, void *data)
}
/// "wait(timeout, condition[, interval])" function
-static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
@@ -3328,113 +2902,8 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
time_watcher_close(tw, dummy_timer_close_cb);
}
-/// "win_screenpos()" function
-static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_list_alloc_ret(rettv, 2);
- const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
- tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
- tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
-}
-
-/// Move the window wp into a new split of targetwin in a given direction
-static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
-{
- int height = wp->w_height;
- win_T *oldwin = curwin;
-
- if (wp == targetwin || wp == aucmd_win) {
- return;
- }
-
- // Jump to the target window
- if (curwin != targetwin) {
- win_goto(targetwin);
- }
-
- // Remove the old window and frame from the tree of frames
- int dir;
- (void)winframe_remove(wp, &dir, NULL);
- win_remove(wp, NULL);
- last_status(false); // may need to remove last status line
- (void)win_comp_pos(); // recompute window positions
-
- // Split a window on the desired side and put the old window there
- (void)win_split_ins(size, flags, wp, dir);
-
- // If splitting horizontally, try to preserve height
- if (size == 0 && !(flags & WSP_VERT)) {
- win_setheight_win(height, wp);
- if (p_ea) {
- win_equal(wp, true, 'v');
- }
- }
-
- if (oldwin != curwin) {
- win_goto(oldwin);
- }
-}
-
-/// "win_splitmove()" function
-static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- win_T *targetwin = find_win_by_nr_or_id(&argvars[1]);
-
- if (wp == NULL || targetwin == NULL || wp == targetwin
- || !win_valid(wp) || !win_valid(targetwin)
- || win_valid_floating(wp) || win_valid_floating(targetwin)) {
- emsg(_(e_invalwindow));
- rettv->vval.v_number = -1;
- return;
- }
-
- int flags = 0, size = 0;
-
- if (argvars[2].v_type != VAR_UNKNOWN) {
- dict_T *d;
- dictitem_T *di;
-
- if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
- emsg(_(e_invarg));
- return;
- }
-
- d = argvars[2].vval.v_dict;
- if (tv_dict_get_number(d, "vertical")) {
- flags |= WSP_VERT;
- }
- if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
- flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
- }
- size = (int)tv_dict_get_number(d, "size");
- }
-
- win_move_into_split(wp, targetwin, size, flags);
-}
-
-/// "getwinpos({timeout})" function
-static void f_getwinpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_list_alloc_ret(rettv, 2);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
-}
-
-/// "getwinposx()" function
-static void f_getwinposx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = -1;
-}
-
-/// "getwinposy()" function
-static void f_getwinposy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = -1;
-}
-
/// "glob()" function
-static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int options = WILD_SILENT|WILD_USE_NL;
expand_T xpc;
@@ -3464,11 +2933,11 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
options += WILD_ICASE;
}
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = (char *)ExpandOne(&xpc, (char_u *)
- tv_get_string(&argvars[0]), NULL, options,
- WILD_ALL);
+ rettv->vval.v_string = ExpandOne(&xpc, (char *)
+ tv_get_string(&argvars[0]), NULL, options,
+ WILD_ALL);
} else {
- ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
+ ExpandOne(&xpc, (char *)tv_get_string(&argvars[0]), NULL, options,
WILD_ALL_KEEP);
tv_list_alloc_ret(rettv, xpc.xp_numfiles);
for (int i = 0; i < xpc.xp_numfiles; i++) {
@@ -3483,7 +2952,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "globpath()" function
-static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath.
bool error = false;
@@ -3513,8 +2982,8 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const file = tv_get_string_buf_chk(&argvars[1], buf1);
if (file != NULL && !error) {
garray_T ga;
- ga_init(&ga, (int)sizeof(char_u *), 10);
- globpath((char *)tv_get_string(&argvars[0]), (char_u *)file, &ga, flags);
+ ga_init(&ga, (int)sizeof(char *), 10);
+ globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags);
if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n");
@@ -3533,7 +3002,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "glob2regpat()" function
-static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const pat = tv_get_string_chk(&argvars[0]); // NULL on type error
@@ -3541,8 +3010,21 @@ static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = (pat == NULL) ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, false);
}
+/// "gettext()" function
+static void f_gettext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ if (argvars[0].v_type != VAR_STRING
+ || argvars[0].vval.v_string == NULL
+ || *argvars[0].vval.v_string == NUL) {
+ semsg(_(e_invarg2), tv_get_string(&argvars[0]));
+ } else {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = xstrdup(_(argvars[0].vval.v_string));
+ }
+}
+
/// "has()" function
-static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
static const char *const has_list[] = {
#if defined(BSD) && !defined(__APPLE__)
@@ -3557,7 +3039,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
#ifdef UNIX
"unix",
#endif
-#if defined(WIN32)
+#ifdef MSWIN
"win32",
#endif
#ifdef _WIN64
@@ -3580,7 +3062,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"cmdwin",
"comments",
"conceal",
- "cscope",
"cursorbind",
"cursorshape",
#ifdef DEBUG
@@ -3601,9 +3082,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"fork",
#endif
"gettext",
-#if defined(HAVE_ICONV)
"iconv",
-#endif
"insert_expand",
"jumplist",
"keymap",
@@ -3631,8 +3110,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"packages",
"path_extra",
"persistent_undo",
- "postscript",
- "printer",
"profile",
"pythonx",
"reltime",
@@ -3649,7 +3126,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"spell",
"syntax",
#if !defined(UNIX)
- "system", // TODO(SplinterOfChaos): This IS defined for UNIX!
+ "system",
#endif
"tablineat",
"tag_binary",
@@ -3765,7 +3242,7 @@ static bool has_wsl(void)
/// @pre An argument may not be -1 if preceding arguments are not all -1.
///
/// @post The return value will be either the number `1` or `0`.
-static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_haslocaldir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// Possible scope of working directory to return.
CdScope scope = kCdScopeInvalid;
@@ -3855,29 +3332,29 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "highlightID(name)" function
-static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
}
/// "highlight_exists()" function
-static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_hlexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
}
/// "hostname()" function
-static void f_hostname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_hostname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char hostname[256];
os_get_hostname(hostname, 256);
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char *)vim_strsave((char_u *)hostname);
+ rettv->vval.v_string = xstrdup(hostname);
}
/// iconv() function
-static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_iconv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
vimconv_T vimconv;
@@ -3886,9 +3363,9 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const str = tv_get_string(&argvars[0]);
char buf1[NUMBUFLEN];
- char_u *const from = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[1], buf1)));
+ char *const from = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[1], buf1)));
char buf2[NUMBUFLEN];
- char_u *const to = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[2], buf2)));
+ char *const to = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
convert_setup(&vimconv, from, to);
@@ -3896,7 +3373,7 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (vimconv.vc_type == CONV_NONE) {
rettv->vval.v_string = xstrdup(str);
} else {
- rettv->vval.v_string = (char *)string_convert(&vimconv, (char_u *)str, NULL);
+ rettv->vval.v_string = string_convert(&vimconv, (char *)str, NULL);
}
convert_setup(&vimconv, NULL, NULL);
@@ -3905,7 +3382,7 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "indent()" function
-static void f_indent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const linenr_T lnum = tv_get_lnum(argvars);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
@@ -3916,7 +3393,7 @@ static void f_indent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "index()" function
-static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
long idx = 0;
bool ic = false;
@@ -3956,33 +3433,36 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_(e_listblobreq));
return;
}
+
list_T *const l = argvars[0].vval.v_list;
- if (l != NULL) {
- listitem_T *item = tv_list_first(l);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- bool error = false;
+ if (l == NULL) {
+ return;
+ }
- // Start at specified item.
- idx = tv_list_uidx(l, (int)tv_get_number_chk(&argvars[2], &error));
- if (error || idx == -1) {
+ listitem_T *item = tv_list_first(l);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+
+ // Start at specified item.
+ idx = tv_list_uidx(l, (int)tv_get_number_chk(&argvars[2], &error));
+ if (error || idx == -1) {
+ item = NULL;
+ } else {
+ item = tv_list_find(l, (int)idx);
+ assert(item != NULL);
+ }
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ ic = !!tv_get_number_chk(&argvars[3], &error);
+ if (error) {
item = NULL;
- } else {
- item = tv_list_find(l, (int)idx);
- assert(item != NULL);
- }
- if (argvars[3].v_type != VAR_UNKNOWN) {
- ic = !!tv_get_number_chk(&argvars[3], &error);
- if (error) {
- item = NULL;
- }
}
}
+ }
- for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) {
- if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) {
- rettv->vval.v_number = idx;
- break;
- }
+ for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) {
+ if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) {
+ rettv->vval.v_number = idx;
+ break;
}
}
}
@@ -3991,19 +3471,19 @@ static bool inputsecret_flag = false;
/// "input()" function
/// Also handles inputsecret() when inputsecret is set.
-static void f_input(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_input(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_user_input(argvars, rettv, false, inputsecret_flag);
}
/// "inputdialog()" function
-static void f_inputdialog(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_inputdialog(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_user_input(argvars, rettv, true, inputsecret_flag);
}
/// "inputlist()" function
-static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_inputlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_LIST) {
semsg(_(e_listarg), "inputlist()");
@@ -4034,7 +3514,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static garray_T ga_userinput = { 0, 0, sizeof(tasave_T), 4, NULL };
/// "inputrestore()" function
-static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_inputrestore(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (!GA_EMPTY(&ga_userinput)) {
ga_userinput.ga_len--;
@@ -4048,7 +3528,7 @@ static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "inputsave()" function
-static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_inputsave(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// Add an entry to the stack of typeahead storage.
tasave_T *p = GA_APPEND_VIA_PTR(tasave_T, &ga_userinput);
@@ -4056,17 +3536,17 @@ static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "inputsecret()" function
-static void f_inputsecret(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_inputsecret(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
cmdline_star++;
inputsecret_flag = true;
- f_input(argvars, rettv, NULL);
+ f_input(argvars, rettv, fptr);
cmdline_star--;
inputsecret_flag = false;
}
/// "insert()" function
-static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
list_T *l;
bool error = false;
@@ -4075,8 +3555,8 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
blob_T *const b = argvars[0].vval.v_blob;
if (b == NULL
- || var_check_lock(b->bv_lock, N_("insert() argument"),
- TV_TRANSLATE)) {
+ || value_check_lock(b->bv_lock, N_("insert() argument"),
+ TV_TRANSLATE)) {
return;
}
@@ -4103,16 +3583,16 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ga_grow(&b->bv_ga, 1);
- char_u *const p = (char_u *)b->bv_ga.ga_data;
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
memmove(p + before + 1, p + before, (size_t)(len - before));
- *(p + before) = (char_u)val;
+ *(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 if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("insert() argument"), TV_TRANSLATE)) {
+ } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ N_("insert() argument"), TV_TRANSLATE)) {
long before = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
before = tv_get_number_chk(&argvars[2], &error);
@@ -4139,34 +3619,34 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "interrupt()" function
static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, typval_T *rettv FUNC_ATTR_UNUSED,
- FunPtr fptr FUNC_ATTR_UNUSED)
+ EvalFuncData fptr FUNC_ATTR_UNUSED)
{
got_int = true;
}
/// "invert(expr)" function
-static void f_invert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_invert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
}
/// "isdirectory()" function
-static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_isdirectory(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- rettv->vval.v_number = os_isdir((const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = os_isdir(tv_get_string(&argvars[0]));
}
/// "islocked()" function
-static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_islocked(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
lval_T lv;
rettv->vval.v_number = -1;
- const char_u *const end = (char_u *)get_lval((char *)tv_get_string(&argvars[0]),
- NULL,
- &lv, false, false,
- GLV_NO_AUTOLOAD|GLV_READ_ONLY,
- FNE_CHECK_START);
+ const char *const end = get_lval((char *)tv_get_string(&argvars[0]),
+ NULL,
+ &lv, false, false,
+ GLV_NO_AUTOLOAD|GLV_READ_ONLY,
+ FNE_CHECK_START);
if (end != NULL && lv.ll_name != NULL) {
if (*end != NUL) {
semsg(_(e_trailing_arg), end);
@@ -4199,7 +3679,7 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "isinf()" function
-static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_isinf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type == VAR_FLOAT
&& xisinf(argvars[0].vval.v_float)) {
@@ -4208,14 +3688,14 @@ static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "isnan()" function
-static void f_isnan(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_isnan(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
&& xisnan(argvars[0].vval.v_float);
}
/// "id()" function
-static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_id(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
const int len = vim_vsnprintf_typval(NULL, 0, "%p", dummy_ap, argvars);
@@ -4225,7 +3705,7 @@ static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "jobpid(id)" function
-static void f_jobpid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_jobpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4249,7 +3729,7 @@ static void f_jobpid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "jobresize(job, width, height)" function
-static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4281,7 +3761,7 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
static const char *ignored_env_vars[] = {
-#ifndef WIN32
+#ifndef MSWIN
"COLUMNS",
"LINES",
"TERMCAP",
@@ -4293,7 +3773,7 @@ static const char *ignored_env_vars[] = {
/// According to comments in src/win/process.c of libuv, Windows has a few
/// "essential" environment variables.
static const char *required_env_vars[] = {
-#ifdef WIN32
+#ifdef MSWIN
"HOMEDRIVE",
"HOMEPATH",
"LOGONSERVER",
@@ -4316,7 +3796,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
if (!clear_env) {
typval_T temp_env = TV_INITIAL_VALUE;
- f_environ(NULL, &temp_env, NULL);
+ f_environ(NULL, &temp_env, (EvalFuncData){ .nullptr = NULL });
tv_dict_extend(env, temp_env.vval.v_dict, "force");
tv_dict_free(temp_env.vval.v_dict);
@@ -4332,7 +3812,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
tv_dict_item_remove(env, dv);
}
}
-#ifndef WIN32
+#ifndef MSWIN
// Set COLORTERM to "truecolor" if termguicolors is set and 256
// otherwise, but only if it was set in the parent terminal at all
dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM"));
@@ -4367,7 +3847,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
}
if (job_env) {
-#ifdef WIN32
+#ifdef MSWIN
TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, {
// Always use upper-case keys for Windows so we detect duplicate keys
char *const key = strcase_save((const char *)var->di_key, true);
@@ -4405,7 +3885,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
}
/// "jobstart()" function
-static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4467,7 +3947,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
-#ifdef WIN32
+#ifdef MSWIN
if (pty && overlapped) {
semsg(_(e_invarg2),
"job cannot have both 'pty' and 'overlapped' options set");
@@ -4480,7 +3960,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
- if (!os_isdir((const char_u *)cwd)) {
+ if (!os_isdir(cwd)) {
semsg(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
@@ -4525,7 +4005,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "jobstop()" function
-static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_jobstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4558,7 +4038,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "jobwait(ids[, timeout])" function
-static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4657,7 +4137,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// json_decode() function
-static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_json_decode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char numbuf[NUMBUFLEN];
const char *s = NULL;
@@ -4691,14 +4171,28 @@ static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// json_encode() function
-static void f_json_encode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_json_encode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = encode_tv2json(&argvars[0], NULL);
}
+/// "keytrans()" function
+static void f_keytrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->v_type = VAR_STRING;
+ if (tv_check_for_string_arg(argvars, 0) == FAIL
+ || argvars[0].vval.v_string == NULL) {
+ return;
+ }
+ // Need to escape K_SPECIAL for mb_unescape().
+ char *escaped = vim_strsave_escape_ks(argvars[0].vval.v_string);
+ rettv->vval.v_string = str2special_save(escaped, true, true);
+ xfree(escaped);
+}
+
/// "last_buffer_nr()" function.
-static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int n = 0;
@@ -4712,7 +4206,7 @@ static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "len()" function
-static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_len(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
switch (argvars[0].v_type) {
case VAR_STRING:
@@ -4783,19 +4277,19 @@ static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
}
/// "libcall()" function
-static void f_libcall(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_libcall(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
libcall_common(argvars, rettv, VAR_STRING);
}
/// "libcallnr()" function
-static void f_libcallnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_libcallnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
libcall_common(argvars, rettv, VAR_NUMBER);
}
/// "line(string, [winid])" function
-static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
linenr_T lnum = 0;
pos_T *fp = NULL;
@@ -4826,7 +4320,7 @@ static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "line2byte(lnum)" function
-static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_line2byte(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const linenr_T lnum = tv_get_lnum(argvars);
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) {
@@ -4840,7 +4334,7 @@ static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "lispindent(lnum)" function
-static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const pos_T pos = curwin->w_cursor;
const linenr_T lnum = tv_get_lnum(argvars);
@@ -4854,13 +4348,13 @@ static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "localtime()" function
-static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_localtime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = (varnumber_T)time(NULL);
}
/// luaeval() function implementation
-static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_luaeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
const char *const str = tv_get_string_chk(&argvars[0]);
@@ -4872,7 +4366,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "map()" function
-static void f_map(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_map(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
filter_map(argvars, rettv, true);
}
@@ -4880,9 +4374,9 @@ static void f_map(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
- char_u *str = NULL;
+ char *str = NULL;
long len = 0;
- char_u *expr = NULL;
+ char *expr = NULL;
regmatch_T regmatch;
long start = 0;
long nth = 1;
@@ -4890,11 +4384,11 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
bool match = false;
list_T *l = NULL;
long idx = 0;
- char_u *tofree = NULL;
+ char *tofree = NULL;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
- p_cpo = "";
+ p_cpo = empty_option;
rettv->vval.v_number = -1;
switch (type) {
@@ -4927,8 +4421,8 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
}
li = tv_list_first(l);
} else {
- expr = str = (char_u *)tv_get_string(&argvars[0]);
- len = (long)STRLEN(str);
+ expr = str = (char *)tv_get_string(&argvars[0]);
+ len = (long)strlen(str);
}
char patbuf[NUMBUFLEN];
@@ -4987,8 +4481,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
break;
}
xfree(tofree);
- tofree = expr = str = (char_u *)encode_tv2echo(TV_LIST_ITEM_TV(li),
- NULL);
+ tofree = expr = str = encode_tv2echo(TV_LIST_ITEM_TV(li), NULL);
if (str == NULL) {
break;
}
@@ -5009,7 +4502,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
idx++;
} else {
startcol = (colnr_T)(regmatch.startp[0]
- + utfc_ptr2len((char *)regmatch.startp[0]) - str);
+ + utfc_ptr2len(regmatch.startp[0]) - str);
if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) {
match = false;
break;
@@ -5028,7 +4521,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
- TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz((const char *)regmatch.startp[0], rd);
+ TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz(regmatch.startp[0], rd);
TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(regmatch.startp[0] - expr);
TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(regmatch.endp[0] - expr);
if (l != NULL) {
@@ -5064,11 +4557,9 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
rettv->vval.v_number = idx;
} else {
if (type == kSomeMatch) {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.startp[0] - str);
+ rettv->vval.v_number = (varnumber_T)(regmatch.startp[0] - str);
} else {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.endp[0] - str);
+ rettv->vval.v_number = (varnumber_T)(regmatch.endp[0] - str);
}
rettv->vval.v_number += (varnumber_T)(str - expr);
}
@@ -5090,31 +4581,31 @@ theend:
}
/// "match()" function
-static void f_match(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_match(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
find_some_match(argvars, rettv, kSomeMatch);
}
/// "matchend()" function
-static void f_matchend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_matchend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
find_some_match(argvars, rettv, kSomeMatchEnd);
}
/// "matchlist()" function
-static void f_matchlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_matchlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
find_some_match(argvars, rettv, kSomeMatchList);
}
/// "matchstr()" function
-static void f_matchstr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_matchstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
find_some_match(argvars, rettv, kSomeMatchStr);
}
/// "matchstrpos()" function
-static void f_matchstrpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_matchstrpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
find_some_match(argvars, rettv, kSomeMatchStrPos);
}
@@ -5142,7 +4633,7 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
TV_LIST_ITER_CONST(tv->vval.v_list, li, {
const varnumber_T i = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
if (error) {
- return;
+ return; // type error; errmsg already given
}
if (domax ? i > n : i < n) {
n = i;
@@ -5155,7 +4646,7 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
TV_DICT_ITER(tv->vval.v_dict, di, {
const varnumber_T i = tv_get_number_chk(&di->di_tv, &error);
if (error) {
- return;
+ return; // type error; errmsg already given
}
if (domax ? i > n : i < n) {
n = i;
@@ -5165,23 +4656,24 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
semsg(_(e_listdictarg), domax ? "max()" : "min()");
return;
}
+
rettv->vval.v_number = n;
}
/// "max()" function
-static void f_max(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_max(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
max_min(argvars, rettv, true);
}
/// "min()" function
-static void f_min(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_min(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
max_min(argvars, rettv, false);
}
/// "mkdir()" function
-static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int prot = 0755; // -V536
@@ -5216,17 +4708,16 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
xfree(failed_dir);
rettv->vval.v_number = FAIL;
return;
- } else {
- rettv->vval.v_number = OK;
- return;
}
+ rettv->vval.v_number = OK;
+ return;
}
}
rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
}
/// "mode()" function
-static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_mode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[MODE_MAX_LENGTH];
@@ -5243,7 +4734,7 @@ static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "msgpackdump()" function
-static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
if (argvars[0].v_type != VAR_LIST) {
@@ -5382,7 +4873,7 @@ static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret
}
/// "msgpackparse" function
-static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_msgpackparse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
@@ -5398,7 +4889,7 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "nextnonblank()" function
-static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_nextnonblank(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
linenr_T lnum;
@@ -5407,7 +4898,7 @@ static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
lnum = 0;
break;
}
- if (*skipwhite((char *)ml_get(lnum)) != NUL) {
+ if (*skipwhite(ml_get(lnum)) != NUL) {
break;
}
}
@@ -5415,7 +4906,7 @@ static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "nr2char()" function
-static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_nr2char(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[1].v_type != VAR_UNKNOWN) {
if (!tv_check_num(&argvars[1])) {
@@ -5446,14 +4937,14 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "or(expr, expr)" function
-static void f_or(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_or(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
| tv_get_number_chk(&argvars[1], NULL);
}
/// "pathshorten()" function
-static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_pathshorten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int trim_len = 1;
@@ -5465,17 +4956,17 @@ static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
rettv->v_type = VAR_STRING;
- const char_u *p = (char_u *)tv_get_string_chk(&argvars[0]);
+ const char *p = tv_get_string_chk(&argvars[0]);
if (p == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = (char *)vim_strsave(p);
- shorten_dir_len((char_u *)rettv->vval.v_string, trim_len);
+ rettv->vval.v_string = xstrdup(p);
+ shorten_dir_len(rettv->vval.v_string, trim_len);
}
}
/// "pow()" function
-static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_pow(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T fx;
float_T fy;
@@ -5489,13 +4980,13 @@ static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "prevnonblank()" function
-static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_prevnonblank(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
linenr_T lnum = tv_get_lnum(argvars);
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
lnum = 0;
} else {
- while (lnum >= 1 && *skipwhite((char *)ml_get(lnum)) == NUL) {
+ while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) {
lnum--;
}
}
@@ -5503,7 +4994,7 @@ static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "printf()" function
-static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_printf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -5525,7 +5016,7 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "prompt_setcallback({buffer}, {callback})" function
-static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
Callback prompt_callback = { .type = kCallbackNone };
@@ -5548,7 +5039,7 @@ static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr
}
/// "prompt_setinterrupt({buffer}, {callback})" function
-static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
Callback interrupt_callback = { .type = kCallbackNone };
@@ -5571,7 +5062,7 @@ static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fpt
}
/// "prompt_getprompt({buffer})" function
-static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
// return an empty string by default, e.g. it's not a prompt buffer
@@ -5587,11 +5078,11 @@ static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_string = (char *)vim_strsave(buf_prompt_text(buf));
+ rettv->vval.v_string = xstrdup(buf_prompt_text(buf));
}
/// "prompt_setprompt({buffer}, {text})" function
-static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
@@ -5607,14 +5098,14 @@ static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "pum_getpos()" function
-static void f_pum_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_pum_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
pum_set_event_info(rettv->vval.v_dict);
}
/// "pumvisible()" function
-static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_pumvisible(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (pum_visible()) {
rettv->vval.v_number = 1;
@@ -5622,7 +5113,7 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "py3eval()" and "pyxeval()" functions (always python3)
-static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_py3eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
script_host_eval("python3", argvars, rettv);
}
@@ -5657,10 +5148,11 @@ static void init_srand(uint32_t *const x)
}
}
if (dev_urandom_state != OK) {
- // Reading /dev/urandom doesn't work, fall back to time().
+ // Reading /dev/urandom doesn't work, fall back to os_hrtime() XOR with process ID
#endif
// uncrustify:off
- *x = (uint32_t)time(NULL);
+ *x = (uint32_t)os_hrtime();
+ *x ^= (uint32_t)os_get_pid();
#ifndef MSWIN
}
#endif
@@ -5694,7 +5186,7 @@ static inline uint32_t shuffle_xoshiro128starstar(uint32_t *const x, uint32_t *c
}
/// "rand()" function
-static void f_rand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
uint32_t result;
@@ -5705,7 +5197,7 @@ static void f_rand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// When no argument is given use the global seed list.
if (!initialized) {
// Initialize the global seed list.
- uint32_t x;
+ uint32_t x = 0;
init_srand(&x);
gx = splitmix32(&x);
@@ -5764,7 +5256,7 @@ theend:
}
/// "srand()" function
-static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_srand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
uint32_t x = 0;
@@ -5786,19 +5278,19 @@ static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "perleval()" function
-static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_perleval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
script_host_eval("perl", argvars, rettv);
}
/// "rubyeval()" function
-static void f_rubyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rubyeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
script_host_eval("ruby", argvars, rettv);
}
/// "range()" function
-static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_range(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
varnumber_T end;
varnumber_T stride = 1;
@@ -5820,13 +5312,16 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (stride == 0) {
emsg(_("E726: Stride is zero"));
- } else if (stride > 0 ? end + 1 < start : end - 1 > start) {
+ return;
+ }
+ if (stride > 0 ? end + 1 < start : end - 1 > start) {
emsg(_("E727: Start past end"));
- } else {
- tv_list_alloc_ret(rettv, (end - start) / stride);
- for (varnumber_T i = start; stride > 0 ? i <= end : i >= end; i += stride) {
- tv_list_append_number(rettv->vval.v_list, i);
- }
+ return;
+ }
+
+ tv_list_alloc_ret(rettv, (end - start) / stride);
+ for (varnumber_T i = start; stride > 0 ? i <= end : i >= end; i += stride) {
+ tv_list_append_number(rettv->vval.v_list, i);
}
}
@@ -5868,7 +5363,7 @@ theend:
}
/// "readdir()" function
-static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_readdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenUnknown);
@@ -5885,17 +5380,17 @@ static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ga_clear_strings(&ga);
}
-/// "readfile()" function
-static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+/// "readfile()" or "readblob()" function
+static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_blob)
{
bool binary = false;
- bool blob = false;
+ bool blob = always_blob;
FILE *fd;
- char_u buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1
+ char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1
int io_size = sizeof(buf);
- char_u *prev = NULL; // previously read bytes, if any
- long prevlen = 0; // length of data in prev
- long prevsize = 0; // size of prev buffer
+ char *prev = NULL; // previously read bytes, if any
+ ptrdiff_t prevlen = 0; // length of data in prev
+ ptrdiff_t prevsize = 0; // size of prev buffer
long maxline = MAXLNUM;
if (argvars[1].v_type != VAR_UNKNOWN) {
@@ -5913,7 +5408,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// their own about CR-LF conversion.
const char *const fname = tv_get_string(&argvars[0]);
- if (os_isdir((const char_u *)fname)) {
+ if (os_isdir(fname)) {
semsg(_(e_isadir2), fname);
return;
}
@@ -5944,13 +5439,13 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// - an incomplete line gets written
// - a "binary" file gets an empty line at the end if it ends in a
// newline.
- char_u *p; // Position in buf.
- char_u *start; // Start of current line.
+ char *p; // Position in buf.
+ char *start; // Start of current line.
for (p = buf, start = buf;
p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
p++) {
- if (*p == '\n' || readlen <= 0) {
- char_u *s = NULL;
+ if (readlen <= 0 || *p == '\n') {
+ char *s = NULL;
size_t len = (size_t)(p - start);
// Finished a line. Remove CRs before NL.
@@ -5967,7 +5462,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (prevlen == 0) {
assert(len < INT_MAX);
- s = vim_strnsave(start, len);
+ s = xstrnsave(start, len);
} else {
// Change "prev" buffer to be the right size. This way
// the bytes are only copied once, and very long lines are
@@ -5982,7 +5477,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_owned_tv(l, (typval_T) {
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
- .vval.v_string = (char *)s,
+ .vval.v_string = s,
});
start = p + 1; // Step over newline.
@@ -6002,18 +5497,18 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*p = '\n';
// Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
// when finding the BF and check the previous two bytes.
- } else if (*p == 0xbf && !binary) {
+ } else if ((uint8_t)(*p) == 0xbf && !binary) {
// Find the two bytes before the 0xbf. If p is at buf, or buf + 1,
// these may be in the "prev" string.
- char_u back1 = p >= buf + 1 ? p[-1]
+ char back1 = p >= buf + 1 ? p[-1]
: prevlen >= 1 ? prev[prevlen - 1] : NUL;
- char_u back2 = p >= buf + 2 ? p[-2]
+ char back2 = p >= buf + 2 ? p[-2]
: p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
: prevlen >=
- 2 ? prev[prevlen - 2] : NUL;
+ 2 ? prev[prevlen - 2] : NUL;
- if (back2 == 0xef && back1 == 0xbb) {
- char_u *dest = p - 2;
+ if ((uint8_t)back2 == 0xef && (uint8_t)back1 == 0xbb) {
+ char *dest = p - 2;
// Usually a BOM is at the beginning of a file, and so at
// the beginning of a line; then we can just step over it.
@@ -6024,8 +5519,8 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int adjust_prevlen = 0;
if (dest < buf) { // -V782
- adjust_prevlen = (int)(buf - dest); // -V782
// adjust_prevlen must be 1 or 2.
+ adjust_prevlen = (int)(buf - dest); // -V782
dest = buf;
}
if (readlen > p - buf + 1) {
@@ -6050,17 +5545,17 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// small, to avoid repeatedly 'allocing' large and
// 'reallocing' small.
if (prevsize == 0) {
- prevsize = (long)(p - start);
+ prevsize = p - start;
} else {
- long grow50pc = (prevsize * 3) / 2;
- long growmin = (long)((p - start) * 2 + prevlen);
+ ptrdiff_t grow50pc = (prevsize * 3) / 2;
+ ptrdiff_t growmin = (p - start) * 2 + prevlen;
prevsize = grow50pc > growmin ? grow50pc : growmin;
}
prev = xrealloc(prev, (size_t)prevsize);
}
// Add the line part to end of "prev".
memmove(prev + prevlen, start, (size_t)(p - start));
- prevlen += (long)(p - start);
+ prevlen += p - start;
}
} // while
@@ -6068,8 +5563,20 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
fclose(fd);
}
+/// "readblob()" function
+static void f_readblob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ read_file_or_blob(argvars, rettv, true);
+}
+
+/// "readfile()" function
+static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ read_file_or_blob(argvars, rettv, false);
+}
+
/// "getreginfo()" function
-static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int regname = getreg_get_regname(argvars);
if (regname == 0) {
@@ -6119,18 +5626,18 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "reg_executing()" function
-static void f_reg_executing(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reg_executing(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
return_register(reg_executing, rettv);
}
/// "reg_recording()" function
-static void f_reg_recording(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reg_recording(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
return_register(reg_recording, rettv);
}
-static void f_reg_recorded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reg_recorded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
return_register(reg_recorded, rettv);
}
@@ -6172,7 +5679,7 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL
/// one argument it returns the time passed since the argument.
/// With two arguments it returns the time passed between
/// the two arguments.
-static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reltime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
proftime_T res;
proftime_T start;
@@ -6214,7 +5721,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "reltimestr()" function
-static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reltimestr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
proftime_T tm;
@@ -6227,7 +5734,7 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "remove()" function
-static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_remove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const arg_errmsg = N_("remove() argument");
@@ -6243,19 +5750,19 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "rename({from}, {to})" function
-static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rename(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
rettv->vval.v_number = -1;
} else {
char buf[NUMBUFLEN];
- rettv->vval.v_number = vim_rename((const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
+ tv_get_string_buf(&argvars[1], buf));
}
}
/// "repeat()" function
-static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
varnumber_T n = tv_get_number(&argvars[1]);
if (argvars[0].v_type == VAR_LIST) {
@@ -6292,18 +5799,18 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "resolve()" function
-static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
const char *fname = tv_get_string(&argvars[0]);
-#ifdef WIN32
+#ifdef MSWIN
char *v = os_resolve_shortcut(fname);
if (v == NULL) {
if (os_is_reparse_point_include(fname)) {
v = os_realpath(fname, v);
}
}
- rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v);
+ rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v);
#else
# ifdef HAVE_READLINK
{
@@ -6365,7 +5872,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (*q != NUL) {
cpy = remain;
remain = (remain
- ? (char *)concat_str((char_u *)q - 1, (char_u *)remain)
+ ? concat_str(q - 1, remain)
: xstrdup(q - 1));
xfree(cpy);
q[-1] = NUL;
@@ -6377,7 +5884,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
q[-1] = NUL;
q = path_tail(p);
}
- if (q > p && !path_is_absolute((const char_u *)buf)) {
+ if (q > p && !path_is_absolute(buf)) {
// Symlink is relative to directory of argument. Replace the
// symlink with the resolved name in the same directory.
const size_t p_len = strlen(p);
@@ -6424,7 +5931,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
&& (p[2] == NUL
|| vim_ispathsep(p[2])))))) {
// Prepend "./".
- cpy = (char *)concat_str((const char_u *)"./", (const char_u *)p);
+ cpy = concat_str("./", p);
xfree(p);
p = cpy;
} else if (!is_relative_to_current) {
@@ -6457,18 +5964,18 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
# endif
#endif
- simplify_filename((char_u *)rettv->vval.v_string);
+ simplify_filename(rettv->vval.v_string);
}
/// "reverse({list})" function
-static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
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 char_u tmp = tv_blob_get(b, 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);
}
@@ -6477,8 +5984,8 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
semsg(_(e_listblobarg), "reverse()");
} else {
list_T *const l = argvars[0].vval.v_list;
- if (!var_check_lock(tv_list_locked(l), N_("reverse() argument"),
- TV_TRANSLATE)) {
+ if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"),
+ TV_TRANSLATE)) {
tv_list_reverse(l);
tv_list_set_ret(rettv, l);
}
@@ -6486,7 +5993,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "reduce(list, { accumulator, element -> value } [, initial])" function
-static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
emsg(_(e_listblobreq));
@@ -6508,8 +6015,8 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.evaluate = true;
- funcexe.partial = partial;
+ funcexe.fe_evaluate = true;
+ funcexe.fe_partial = partial;
typval_T initial;
typval_T argv[3];
@@ -6598,55 +6105,57 @@ static int get_search_arg(typval_T *varp, int *flagsp)
{
int dir = FORWARD;
- if (varp->v_type != VAR_UNKNOWN) {
- char nbuf[NUMBUFLEN];
- const char *flags = tv_get_string_buf_chk(varp, nbuf);
- if (flags == NULL) {
- return 0; // Type error; errmsg already given.
- }
- int mask;
- while (*flags != NUL) {
- switch (*flags) {
- case 'b':
- dir = BACKWARD; break;
- case 'w':
- p_ws = true; break;
- case 'W':
- p_ws = false; break;
- default:
- mask = 0;
- if (flagsp != NULL) {
- switch (*flags) {
- case 'c':
- mask = SP_START; break;
- case 'e':
- mask = SP_END; break;
- case 'm':
- mask = SP_RETCOUNT; break;
- case 'n':
- mask = SP_NOMOVE; break;
- case 'p':
- mask = SP_SUBPAT; break;
- case 'r':
- mask = SP_REPEAT; break;
- case 's':
- mask = SP_SETPCMARK; break;
- case 'z':
- mask = SP_COLUMN; break;
- }
- }
- if (mask == 0) {
- semsg(_(e_invarg2), flags);
- dir = 0;
- } else {
- *flagsp |= mask;
+ if (varp->v_type == VAR_UNKNOWN) {
+ return FORWARD;
+ }
+
+ char nbuf[NUMBUFLEN];
+ const char *flags = tv_get_string_buf_chk(varp, nbuf);
+ if (flags == NULL) {
+ return 0; // Type error; errmsg already given.
+ }
+ int mask;
+ while (*flags != NUL) {
+ switch (*flags) {
+ case 'b':
+ dir = BACKWARD; break;
+ case 'w':
+ p_ws = true; break;
+ case 'W':
+ p_ws = false; break;
+ default:
+ mask = 0;
+ if (flagsp != NULL) {
+ switch (*flags) {
+ case 'c':
+ mask = SP_START; break;
+ case 'e':
+ mask = SP_END; break;
+ case 'm':
+ mask = SP_RETCOUNT; break;
+ case 'n':
+ mask = SP_NOMOVE; break;
+ case 'p':
+ mask = SP_SUBPAT; break;
+ case 'r':
+ mask = SP_REPEAT; break;
+ case 's':
+ mask = SP_SETPCMARK; break;
+ case 'z':
+ mask = SP_COLUMN; break;
}
}
- if (dir == 0) {
- break;
+ if (mask == 0) {
+ semsg(_(e_invarg2), flags);
+ dir = 0;
+ } else {
+ *flagsp |= mask;
}
- flags++;
}
+ if (dir == 0) {
+ break;
+ }
+ flags++;
}
return dir;
}
@@ -6718,7 +6227,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
// Repeat until {skip} returns false.
for (;;) {
subpatnum
- = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1, options, RE_SEARCH, &sia);
+ = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia);
// finding the first match again means there is no match where {skip}
// evaluates to zero.
if (firstpos.lnum != 0 && equalpos(pos, firstpos)) {
@@ -6729,7 +6238,9 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
// didn't find it or no skip argument
break;
}
- firstpos = pos;
+ if (firstpos.lnum == 0) {
+ firstpos = pos;
+ }
// If the skip expression matches, ignore this match.
{
@@ -6786,7 +6297,7 @@ theend:
}
/// "rpcnotify()" function
-static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -6811,17 +6322,20 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ADD(args, vim_to_object(tv));
}
- if (!rpc_send_event((uint64_t)argvars[0].vval.v_number,
- tv_get_string(&argvars[1]), args)) {
+ bool ok = rpc_send_event((uint64_t)argvars[0].vval.v_number,
+ tv_get_string(&argvars[1]), args);
+
+ api_free_array(args);
+
+ if (!ok) {
semsg(_(e_invarg2), "Channel doesn't exist");
return;
}
-
rettv->vval.v_number = 1;
}
/// "rpcrequest()" function
-static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -6910,12 +6424,12 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
end:
- arena_mem_free(res_mem, NULL);
+ arena_mem_free(res_mem);
api_clear_error(&err);
}
/// "rpcstart()" function (DEPRECATED)
-static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -6955,7 +6469,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Allocate extra memory for the argument vector and the NULL pointer
int argvl = argsl + 2;
- char **argv = xmalloc(sizeof(char_u *) * (size_t)argvl);
+ char **argv = xmalloc(sizeof(char *) * (size_t)argvl);
// Copy program name
argv[0] = xstrdup(argvars[0].vval.v_string);
@@ -6982,7 +6496,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "rpcstop()" function
-static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_rpcstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -7000,7 +6514,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// if called with a job, stop it, else closes the channel
uint64_t id = (uint64_t)argvars[0].vval.v_number;
if (find_job(id, false)) {
- f_jobstop(argvars, rettv, NULL);
+ f_jobstop(argvars, rettv, fptr);
} else {
const char *error;
rettv->vval.v_number =
@@ -7012,7 +6526,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "screenattr()" function
-static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screenattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
@@ -7030,7 +6544,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "screenchar()" function
-static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
@@ -7048,7 +6562,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "screenchars()" function
-static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
@@ -7061,7 +6575,7 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
int pcc[MAX_MCO];
- int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + (size_t)col], pcc);
+ int c = utfc_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col], pcc);
int composing_len = 0;
while (pcc[composing_len] != 0) {
composing_len++;
@@ -7076,45 +6590,19 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "screencol()" function
///
/// First column is 1 to be consistent with virtcol().
-static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screencol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = ui_current_col() + 1;
}
-/// "screenpos({winid}, {lnum}, {col})" function
-static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_dict_alloc_ret(rettv);
- dict_T *dict = rettv->vval.v_dict;
-
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- return;
- }
-
- pos_T pos = {
- .lnum = (linenr_T)tv_get_number(&argvars[1]),
- .col = (colnr_T)tv_get_number(&argvars[2]) - 1,
- .coladd = 0
- };
- int row = 0;
- int scol = 0, ccol = 0, ecol = 0;
- textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol, false);
-
- tv_dict_add_nr(dict, S_LEN("row"), row);
- tv_dict_add_nr(dict, S_LEN("col"), scol);
- tv_dict_add_nr(dict, S_LEN("curscol"), ccol);
- tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
-}
-
/// "screenrow()" function
-static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screenrow(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = ui_current_row() + 1;
}
/// "screenstring()" function
-static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
@@ -7129,11 +6617,11 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_string = (char *)vim_strsave(grid->chars[grid->line_offset[row] + (size_t)col]);
+ rettv->vval.v_string = xstrdup((char *)grid->chars[grid->line_offset[row] + (size_t)col]);
}
/// "search()" function
-static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_search(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int flags = 0;
@@ -7141,7 +6629,7 @@ static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "searchdecl()" function
-static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_searchdecl(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int locally = 1;
int thisblock = 0;
@@ -7157,7 +6645,7 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
if (!error && name != NULL) {
- rettv->vval.v_number = find_decl((char_u *)name, strlen(name), locally,
+ rettv->vval.v_number = find_decl((char *)name, strlen(name), locally,
thisblock, SEARCH_KEEP) == FAIL;
}
}
@@ -7236,13 +6724,13 @@ theend:
}
/// "searchpair()" function
-static void f_searchpair(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_searchpair(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = searchpair_cmn(argvars, NULL);
}
/// "searchpairpos()" function
-static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_searchpairpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
pos_T match_pos;
int lnum = 0;
@@ -7284,7 +6772,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
- p_cpo = (char *)empty_option;
+ p_cpo = empty_option;
// Set the time limit, if there is one.
proftime_T tm = profile_setlimit(time_limit);
@@ -7292,14 +6780,14 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
- char_u *pat2 = xmalloc(pat2_len);
+ char *pat2 = xmalloc(pat2_len);
const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
- char_u *pat3 = xmalloc(pat3_len);
- snprintf((char *)pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
+ char *pat3 = xmalloc(pat3_len);
+ snprintf(pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
if (*mpat == NUL) {
STRCPY(pat3, pat2);
} else {
- snprintf((char *)pat3, pat3_len,
+ snprintf(pat3, pat3_len,
"\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat);
}
if (flags & SP_START) {
@@ -7316,7 +6804,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
clearpos(&firstpos);
pos_T foundpos;
clearpos(&foundpos);
- char_u *pat = pat3;
+ char *pat = pat3;
for (;;) {
searchit_arg_T sia = {
.sa_stop_lnum = lnum_stop,
@@ -7410,18 +6898,23 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
xfree(pat2);
xfree(pat3);
- if ((char_u *)p_cpo == empty_option) {
+ if (p_cpo == empty_option) {
p_cpo = save_cpo;
} else {
// Darn, evaluating the {skip} expression changed the value.
- free_string_option((char_u *)save_cpo);
+ // If it's still empty it was changed and restored, need to restore in
+ // the complicated way.
+ if (*p_cpo == NUL) {
+ set_option_value_give_err("cpo", 0L, save_cpo, 0);
+ }
+ free_string_option(save_cpo);
}
return retval;
}
/// "searchpos()" function
-static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_searchpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
pos_T match_pos;
int flags = 0;
@@ -7441,7 +6934,7 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "serverlist()" function
-static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_serverlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
size_t n;
char **addrs = server_address_list(&n);
@@ -7455,7 +6948,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "serverstart()" function
-static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_serverstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL; // Address of the new server
@@ -7470,9 +6963,8 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type != VAR_STRING) {
emsg(_(e_invarg));
return;
- } else {
- address = xstrdup(tv_get_string(argvars));
}
+ address = xstrdup(tv_get_string(argvars));
} else {
address = server_address_new(NULL);
}
@@ -7500,7 +6992,7 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "serverstop()" function
-static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
@@ -7519,23 +7011,8 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "setbufline()" function
-static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- linenr_T lnum;
- buf_T *buf;
-
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
- }
-}
-
/// Set the cursor or mark position.
-/// If 'charpos' is TRUE, then use the column number as a character offset.
+/// If 'charpos' is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
@@ -7543,41 +7020,45 @@ static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
rettv->vval.v_number = -1;
const char *const name = tv_get_string_chk(argvars);
- if (name != NULL) {
- pos_T pos;
- int fnum;
- if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK) {
- if (pos.col != MAXCOL && --pos.col < 0) {
- pos.col = 0;
- }
- if (name[0] == '.' && name[1] == NUL) {
- // set cursor; "fnum" is ignored
- curwin->w_cursor = pos;
- if (curswant >= 0) {
- curwin->w_curswant = curswant - 1;
- curwin->w_set_curswant = false;
- }
- check_cursor();
- rettv->vval.v_number = 0;
- } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
- // set mark
- if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
- rettv->vval.v_number = 0;
- }
- } else {
- emsg(_(e_invarg));
- }
+ if (name == NULL) {
+ return;
+ }
+
+ pos_T pos;
+ int fnum;
+ if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) != OK) {
+ return;
+ }
+
+ if (pos.col != MAXCOL && --pos.col < 0) {
+ pos.col = 0;
+ }
+ if (name[0] == '.' && name[1] == NUL) {
+ // set cursor; "fnum" is ignored
+ curwin->w_cursor = pos;
+ if (curswant >= 0) {
+ curwin->w_curswant = curswant - 1;
+ curwin->w_set_curswant = false;
+ }
+ check_cursor();
+ rettv->vval.v_number = 0;
+ } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
+ // set mark
+ if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
+ rettv->vval.v_number = 0;
}
+ } else {
+ emsg(_(e_invarg));
}
}
/// "setcharpos()" function
-static void f_setcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
set_position(argvars, rettv, true);
}
-static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_DICT) {
emsg(_(e_dictreq));
@@ -7585,44 +7066,36 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
dict_T *d = argvars[0].vval.v_dict;
- if (d != NULL) {
- char_u *const csearch = (char_u *)tv_dict_get_string(d, "char", false);
- if (csearch != NULL) {
- int pcc[MAX_MCO];
- const int c = utfc_ptr2char(csearch, pcc);
- set_last_csearch(c, csearch, utfc_ptr2len((char *)csearch));
- }
-
- dictitem_T *di = tv_dict_find(d, S_LEN("forward"));
- if (di != NULL) {
- set_csearch_direction(tv_get_number(&di->di_tv) ? FORWARD : BACKWARD);
- }
+ if (d == NULL) {
+ return;
+ }
- di = tv_dict_find(d, S_LEN("until"));
- if (di != NULL) {
- set_csearch_until(!!tv_get_number(&di->di_tv));
- }
+ char *const csearch = tv_dict_get_string(d, "char", false);
+ if (csearch != NULL) {
+ int pcc[MAX_MCO];
+ const int c = utfc_ptr2char(csearch, pcc);
+ set_last_csearch(c, csearch, utfc_ptr2len(csearch));
}
-}
-/// "setcmdpos()" function
-static void f_setcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- const int pos = (int)tv_get_number(&argvars[0]) - 1;
+ dictitem_T *di = tv_dict_find(d, S_LEN("forward"));
+ if (di != NULL) {
+ set_csearch_direction(tv_get_number(&di->di_tv) ? FORWARD : BACKWARD);
+ }
- if (pos >= 0) {
- rettv->vval.v_number = set_cmdline_pos(pos);
+ di = tv_dict_find(d, S_LEN("until"));
+ if (di != NULL) {
+ set_csearch_until(!!tv_get_number(&di->di_tv));
}
}
/// "setcursorcharpos" function
-static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
set_cursorpos(argvars, rettv, true);
}
/// "setenv()" function
-static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char namebuf[NUMBUFLEN];
char valbuf[NUMBUFLEN];
@@ -7637,7 +7110,7 @@ static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "setfperm({fname}, {mode})" function
-static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = 0;
@@ -7667,15 +7140,8 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = os_setperm(fname, mode) == OK;
}
-/// "setline()" function
-static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- linenr_T lnum = tv_get_lnum(&argvars[0]);
- set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
-}
-
/// "setpos()" function
-static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
set_position(argvars, rettv, false);
}
@@ -7711,7 +7177,7 @@ static int get_yank_type(char **const pp, MotionType *const yank_type, long *con
}
/// "setreg()" function
-static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_setreg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
bool append = false;
@@ -7837,7 +7303,7 @@ free_lstval:
if (strval == NULL) {
return;
}
- write_reg_contents_ex(regname, (const char_u *)strval, (ssize_t)STRLEN(strval),
+ write_reg_contents_ex(regname, strval, (ssize_t)strlen(strval),
append, yank_type, (colnr_T)block_len);
}
if (pointreg != 0) {
@@ -7852,7 +7318,7 @@ free_lstval:
}
/// "settagstack()" function
-static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
static char *e_invact2 = N_("E962: Invalid action: '%s'");
char action = 'r';
@@ -7903,7 +7369,7 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// f_sha256 - sha256({string}) function
-static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_sha256(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *p = tv_get_string(&argvars[0]);
const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0);
@@ -7914,18 +7380,17 @@ static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "shellescape({string})" function
-static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_shellescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const bool do_special = non_zero_arg(&argvars[1]);
rettv->vval.v_string =
- (char *)vim_strsave_shellescape((const char_u *)tv_get_string(&argvars[0]), do_special,
- do_special);
+ vim_strsave_shellescape(tv_get_string(&argvars[0]), do_special, do_special);
rettv->v_type = VAR_STRING;
}
/// shiftwidth() function
-static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = 0;
@@ -7941,16 +7406,16 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "simplify()" function
-static void f_simplify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_simplify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const p = tv_get_string(&argvars[0]);
rettv->vval.v_string = xstrdup(p);
- simplify_filename((char_u *)rettv->vval.v_string); // Simplify in place.
+ simplify_filename(rettv->vval.v_string); // Simplify in place.
rettv->v_type = VAR_STRING;
}
/// "sockconnect()" function
-static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_sockconnect(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) {
emsg(_(e_invarg));
@@ -8002,7 +7467,7 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "stdioopen()" function
-static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_stdioopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_DICT) {
emsg(_(e_invarg));
@@ -8036,7 +7501,7 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "reltimefloat()" function
-static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_reltimefloat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
FUNC_ATTR_NONNULL_ALL
{
proftime_T tm;
@@ -8049,7 +7514,7 @@ static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "soundfold({word})" function
-static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_soundfold(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
const char *const s = tv_get_string(&argvars[0]);
@@ -8057,7 +7522,7 @@ static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "spellbadword()" function
-static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const int wo_spell_save = curwin->w_p_spell;
@@ -8079,7 +7544,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Find the start and length of the badly spelled word.
len = spell_move_to(curwin, FORWARD, true, true, &attr);
if (len != 0) {
- word = (char *)get_cursor_pos_ptr();
+ word = get_cursor_pos_ptr();
curwin->w_set_curswant = true;
}
} else if (*curbuf->b_s.b_p_spl != NUL) {
@@ -8089,7 +7554,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (str != NULL) {
// Check the argument for spelling.
while (*str != NUL) {
- len = spell_check(curwin, (char_u *)str, &attr, &capcol, false);
+ len = spell_check(curwin, (char *)str, &attr, &capcol, false);
if (attr != HLF_COUNT) {
word = str;
break;
@@ -8113,7 +7578,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "spellsuggest()" function
-static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
garray_T ga = GA_EMPTY_INIT_VALUE;
const int wo_spell_save = curwin->w_p_spell;
@@ -8148,7 +7613,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
maxcount = 25;
}
- spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false);
+ spell_suggest_list(&ga, (char *)str, maxcount, need_capital, false);
f_spellsuggest_return:
tv_list_alloc_ret(rettv, (ptrdiff_t)ga.ga_len);
@@ -8160,7 +7625,7 @@ f_spellsuggest_return:
curwin->w_p_spell = wo_spell_save;
}
-static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
colnr_T col = 0;
bool keepempty = false;
@@ -8168,7 +7633,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
- p_cpo = "";
+ p_cpo = empty_option;
const char *str = tv_get_string(&argvars[0]);
const char *pat = NULL;
@@ -8179,7 +7644,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
typeerr = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- keepempty = (bool)tv_get_number_chk(&argvars[2], &typeerr);
+ keepempty = (bool)tv_get_bool_chk(&argvars[2], &typeerr);
}
}
if (pat == NULL || *pat == NUL) {
@@ -8204,7 +7669,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (*str == NUL) {
match = false; // Empty item at the end.
} else {
- match = vim_regexec_nl(&regmatch, (char_u *)str, col);
+ match = vim_regexec_nl(&regmatch, (char *)str, col);
}
const char *end;
if (match) {
@@ -8222,11 +7687,11 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
}
// Advance to just after the match.
- if (regmatch.endp[0] > (char_u *)str) {
+ if (regmatch.endp[0] > str) {
col = 0;
} else {
// Don't get stuck at the same match.
- col = utfc_ptr2len((char *)regmatch.endp[0]);
+ col = utfc_ptr2len(regmatch.endp[0]);
}
str = (const char *)regmatch.endp[0];
}
@@ -8239,7 +7704,7 @@ theend:
}
/// "stdpath(type)" function
-static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_stdpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -8271,7 +7736,7 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "str2float()" function
-static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_str2float(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *p = skipwhite(tv_get_string(&argvars[0]));
bool isneg = (*p == '-');
@@ -8287,18 +7752,18 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "str2list()" function
-static void f_str2list(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_str2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenUnknown);
- const char_u *p = (const char_u *)tv_get_string(&argvars[0]);
+ const char *p = tv_get_string(&argvars[0]);
- for (; *p != NUL; p += utf_ptr2len((char *)p)) {
- tv_list_append_number(rettv->vval.v_list, utf_ptr2char((char *)p));
+ for (; *p != NUL; p += utf_ptr2len(p)) {
+ tv_list_append_number(rettv->vval.v_list, utf_ptr2char(p));
}
}
/// "str2nr()" function
-static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int base = 10;
int what = 0;
@@ -8309,15 +7774,15 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_(e_invarg));
return;
}
- if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) {
+ if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2])) {
what |= STR2NR_QUOTE;
}
}
- char_u *p = (char_u *)skipwhite(tv_get_string(&argvars[0]));
+ char *p = skipwhite(tv_get_string(&argvars[0]));
bool isneg = (*p == '-');
if (*p == '+' || *p == '-') {
- p = (char_u *)skipwhite((char *)p + 1);
+ p = skipwhite(p + 1);
}
switch (base) {
case 2:
@@ -8341,7 +7806,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strftime({format}[, {time}])" function
-static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
time_t seconds;
@@ -8361,18 +7826,15 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = xstrdup(_("(Invalid)"));
} else {
vimconv_T conv;
- char_u *enc;
conv.vc_type = CONV_NONE;
- enc = enc_locale();
+ char *enc = enc_locale();
convert_setup(&conv, p_enc, enc);
if (conv.vc_type != CONV_NONE) {
- p = (char *)string_convert(&conv, (char_u *)p, NULL);
+ p = string_convert(&conv, p, NULL);
}
char result_buf[256];
- if (p != NULL) {
- (void)strftime(result_buf, sizeof(result_buf), p, curtime_ptr);
- } else {
+ if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
result_buf[0] = NUL;
}
@@ -8381,7 +7843,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
convert_setup(&conv, enc, p_enc);
if (conv.vc_type != CONV_NONE) {
- rettv->vval.v_string = (char *)string_convert(&conv, (char_u *)result_buf, NULL);
+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
} else {
rettv->vval.v_string = xstrdup(result_buf);
}
@@ -8393,7 +7855,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strgetchar()" function
-static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strgetchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = -1;
@@ -8407,7 +7869,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- const size_t len = STRLEN(str);
+ const size_t len = strlen(str);
size_t byteidx = 0;
while (charidx >= 0 && byteidx < len) {
@@ -8421,7 +7883,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "stridx()" function
-static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_stridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = -1;
@@ -8453,43 +7915,55 @@ static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "string()" function
-static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_string(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = encode_tv2string(&argvars[0], NULL);
}
/// "strlen()" function
-static void f_strlen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
}
-/// "strchars()" function
-static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc)
{
const char *s = tv_get_string(&argvars[0]);
- int skipcc = 0;
varnumber_T len = 0;
- int (*func_mb_ptr2char_adv)(const char_u **pp);
+ int (*func_mb_ptr2char_adv)(const char **pp);
+
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL) {
+ func_mb_ptr2char_adv(&s);
+ len++;
+ }
+ rettv->vval.v_number = len;
+}
+
+/// "strcharlen()" function
+static void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ strchar_common(argvars, rettv, true);
+}
+
+/// "strchars()" function
+static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int skipcc = false;
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
+ skipcc = (int)tv_get_bool(&argvars[1]);
}
if (skipcc < 0 || skipcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), skipcc);
} else {
- func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
- while (*s != NUL) {
- func_mb_ptr2char_adv((const char_u **)&s);
- len++;
- }
- rettv->vval.v_number = len;
+ strchar_common(argvars, rettv, skipcc);
}
}
/// "strdisplaywidth()" function
-static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const s = tv_get_string(&argvars[0]);
int col = 0;
@@ -8498,11 +7972,11 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
col = (int)tv_get_number(&argvars[1]);
}
- rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char_u *)s) - col);
+ rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char *)s) - col);
}
/// "strwidth()" function
-static void f_strwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const s = tv_get_string(&argvars[0]);
@@ -8510,10 +7984,10 @@ static void f_strwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strcharpart()" function
-static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strcharpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const p = tv_get_string(&argvars[0]);
- const size_t slen = STRLEN(p);
+ const size_t slen = strlen(p);
int nbyte = 0;
bool error = false;
@@ -8564,7 +8038,7 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strpart()" function
-static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
bool error = false;
@@ -8610,7 +8084,7 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strptime({format}, {timestring})" function
-static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char fmt_buf[NUMBUFLEN];
char str_buf[NUMBUFLEN];
@@ -8624,10 +8098,10 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
vimconv_T conv = {
.vc_type = CONV_NONE,
};
- char_u *enc = enc_locale();
+ char *enc = enc_locale();
convert_setup(&conv, p_enc, enc);
if (conv.vc_type != CONV_NONE) {
- fmt = (char *)string_convert(&conv, (char_u *)fmt, NULL);
+ fmt = string_convert(&conv, fmt, NULL);
}
if (fmt == NULL
|| os_strptime(str, fmt, &tmval) == NULL
@@ -8642,7 +8116,7 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strridx()" function
-static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[NUMBUFLEN];
const char *const needle = tv_get_string_chk(&argvars[1]);
@@ -8653,7 +8127,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return; // Type error; errmsg already given.
}
- const size_t haystack_len = STRLEN(haystack);
+ const size_t haystack_len = strlen(haystack);
ptrdiff_t end_idx;
if (argvars[2].v_type != VAR_UNKNOWN) {
// Third argument: upper limit for index.
@@ -8685,14 +8159,14 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "strtrans()" function
-static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_strtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = transstr(tv_get_string(&argvars[0]), true);
}
/// "submatch()" function
-static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_submatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
bool error = false;
int no = (int)tv_get_number_chk(&argvars[0], &error);
@@ -8715,7 +8189,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (retList == 0) {
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char *)reg_submatch(no);
+ rettv->vval.v_string = reg_submatch(no);
} else {
rettv->v_type = VAR_LIST;
rettv->vval.v_list = reg_submatch_list(no);
@@ -8723,7 +8197,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "substitute()" function
-static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char patbuf[NUMBUFLEN];
char subbuf[NUMBUFLEN];
@@ -8752,14 +8226,14 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "swapinfo(swap_filename)" function
-static void f_swapinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_swapinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
}
/// "swapname(expr)" function
-static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_swapname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
buf_T *buf = tv_get_buf(&argvars[0], false);
@@ -8768,12 +8242,12 @@ static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|| buf->b_ml.ml_mfp->mf_fname == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = (char *)vim_strsave(buf->b_ml.ml_mfp->mf_fname);
+ rettv->vval.v_string = xstrdup(buf->b_ml.ml_mfp->mf_fname);
}
}
/// "synID(lnum, col, trans)" function
-static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_synID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
// -1 on type error (both)
const linenr_T lnum = tv_get_lnum(argvars);
@@ -8784,7 +8258,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int id = 0;
if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
- && col >= 0 && (size_t)col < STRLEN(ml_get(lnum))) {
+ && col >= 0 && (size_t)col < strlen(ml_get(lnum))) {
id = syn_get_id(curwin, lnum, col, trans, NULL, false);
}
@@ -8792,7 +8266,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "synIDattr(id, what [, mode])" function
-static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_synIDattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const int id = (int)tv_get_number(&argvars[0]);
const char *const what = tv_get_string(&argvars[1]);
@@ -8850,7 +8324,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
break;
case 'u':
- if (STRLEN(what) >= 9) {
+ if (strlen(what) >= 9) {
if (TOLOWER_ASC(what[5]) == 'l') {
// underline
p = highlight_has_attr(id, HL_UNDERLINE, modec);
@@ -8879,7 +8353,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "synIDtrans(id)" function
-static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_synIDtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int id = (int)tv_get_number(&argvars[0]);
@@ -8893,12 +8367,12 @@ static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "synconcealed(lnum, col)" function
-static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int syntax_flags = 0;
int cchar;
int matchid = 0;
- char_u str[NUMBUFLEN];
+ char str[NUMBUFLEN];
tv_list_set_ret(rettv, NULL);
@@ -8909,7 +8383,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
CLEAR_FIELD(str);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0
- && (size_t)col <= STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) {
+ && (size_t)col <= strlen(ml_get(lnum)) && curwin->w_p_cole > 0) {
(void)syn_get_id(curwin, lnum, col, false, NULL, false);
syntax_flags = get_syntax_info(&matchid);
@@ -8922,7 +8396,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
: curwin->w_p_lcs_chars.conceal;
}
if (cchar != NUL) {
- utf_char2bytes(cchar, (char *)str);
+ utf_char2bytes(cchar, str);
}
}
}
@@ -8930,12 +8404,12 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_alloc_ret(rettv, 3);
tv_list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0);
// -1 to auto-determine strlen
- tv_list_append_string(rettv->vval.v_list, (const char *)str, -1);
+ tv_list_append_string(rettv->vval.v_list, str, -1);
tv_list_append_number(rettv->vval.v_list, matchid);
}
/// "synstack(lnum, col)" function
-static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_set_ret(rettv, NULL);
@@ -8946,7 +8420,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (lnum >= 1
&& lnum <= curbuf->b_ml.ml_line_count
&& col >= 0
- && (size_t)col <= STRLEN(ml_get(lnum))) {
+ && (size_t)col <= strlen(ml_get(lnum))) {
tv_list_alloc_ret(rettv, kListLenMayKnow);
(void)syn_get_id(curwin, lnum, col, false, NULL, true);
@@ -8959,18 +8433,18 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// f_system - the VimL system() function
-static void f_system(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_system(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_system_output_as_rettv(argvars, rettv, false);
}
-static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_systemlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
get_system_output_as_rettv(argvars, rettv, true);
}
/// "tabpagebuflist()" function
-static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
win_T *wp = NULL;
@@ -8991,114 +8465,15 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "tabpagenr()" function
-static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- int nr = 1;
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- const char *const arg = tv_get_string_chk(&argvars[0]);
- nr = 0;
- if (arg != NULL) {
- if (strcmp(arg, "$") == 0) {
- nr = tabpage_index(NULL) - 1;
- } else if (strcmp(arg, "#") == 0) {
- nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0;
- } else {
- semsg(_(e_invexpr2), arg);
- }
- }
- } else {
- nr = tabpage_index(curtab);
- }
- rettv->vval.v_number = nr;
-}
-
-/// Common code for tabpagewinnr() and winnr().
-static int get_winnr(tabpage_T *tp, typval_T *argvar)
-{
- int nr = 1;
-
- win_T *twin = (tp == curtab) ? curwin : tp->tp_curwin;
- if (argvar->v_type != VAR_UNKNOWN) {
- bool invalid_arg = false;
- const char *const arg = tv_get_string_chk(argvar);
- if (arg == NULL) {
- nr = 0; // Type error; errmsg already given.
- } else if (strcmp(arg, "$") == 0) {
- twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
- } else if (strcmp(arg, "#") == 0) {
- twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
- if (twin == NULL) {
- nr = 0;
- }
- } else {
- // Extract the window count (if specified). e.g. winnr('3j')
- char *endp;
- long count = strtol((char *)arg, &endp, 10);
- if (count <= 0) {
- // if count is not specified, default to 1
- count = 1;
- }
- if (endp != NULL && *endp != '\0') {
- if (strequal(endp, "j")) {
- twin = win_vert_neighbor(tp, twin, false, count);
- } else if (strequal(endp, "k")) {
- twin = win_vert_neighbor(tp, twin, true, count);
- } else if (strequal(endp, "h")) {
- twin = win_horz_neighbor(tp, twin, true, count);
- } else if (strequal(endp, "l")) {
- twin = win_horz_neighbor(tp, twin, false, count);
- } else {
- invalid_arg = true;
- }
- } else {
- invalid_arg = true;
- }
- }
-
- if (invalid_arg) {
- semsg(_(e_invexpr2), arg);
- nr = 0;
- }
- }
-
- if (nr > 0) {
- for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
- wp != twin; wp = wp->w_next) {
- if (wp == NULL) {
- // didn't find it in this tabpage
- nr = 0;
- break;
- }
- nr++;
- }
- }
- return nr;
-}
-
-/// "tabpagewinnr()" function
-static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- int nr = 1;
- tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
- if (tp == NULL) {
- nr = 0;
- } else {
- nr = get_winnr(tp, &argvars[1]);
- }
- rettv->vval.v_number = nr;
-}
-
/// "tagfiles()" function
-static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_tagfiles(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenUnknown);
char *fname = xmalloc(MAXPATHL);
bool first = true;
tagname_T tn;
- while (get_tagfname(&tn, first, (char_u *)fname) == OK) {
+ while (get_tagfname(&tn, first, fname) == OK) {
tv_list_append_string(rettv->vval.v_list, fname, -1);
first = false;
}
@@ -9108,7 +8483,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "taglist()" function
-static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const tag_pattern = tv_get_string(&argvars[0]);
@@ -9122,18 +8497,18 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
fname = tv_get_string(&argvars[1]);
}
(void)get_tags(tv_list_alloc_ret(rettv, kListLenUnknown),
- (char_u *)tag_pattern, (char_u *)fname);
+ (char *)tag_pattern, (char *)fname);
}
/// "tempname()" function
-static void f_tempname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_tempname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char *)vim_tempname();
+ rettv->vval.v_string = vim_tempname();
}
/// "termopen(cmd[, cwd])" function
-static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
@@ -9176,7 +8551,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
- if (!os_isdir((const char_u *)cwd)) {
+ if (!os_isdir(cwd)) {
semsg(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
@@ -9216,9 +8591,9 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int pid = chan->stream.pty.process.pid;
// "./…" => "/home/foo/…"
- vim_FullName(cwd, (char *)NameBuff, sizeof(NameBuff), false);
+ vim_FullName(cwd, NameBuff, sizeof(NameBuff), false);
// "/home/foo/…" => "~/…"
- size_t len = home_replace(NULL, (char *)NameBuff, (char *)IObuff, sizeof(IObuff), true);
+ size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = '\0';
@@ -9231,14 +8606,14 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// Terminal URI: "term://$CWD//$PID:$CMD"
- snprintf((char *)NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
- (char *)IObuff, pid, cmd);
+ snprintf(NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
+ IObuff, pid, cmd);
// at this point the buffer has no terminal instance associated yet, so unset
// the 'swapfile' option to ensure no swap file will be created
curbuf->b_p_swf = false;
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
- (void)setfname(curbuf, (char *)NameBuff, NULL, true);
+ (void)setfname(curbuf, NameBuff, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
// Save the job id and pid in b:terminal_job_{id,pid}
@@ -9256,7 +8631,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "timer_info([timer])" function
-static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_UNKNOWN) {
if (argvars[0].v_type != VAR_NUMBER) {
@@ -9274,7 +8649,7 @@ static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "timer_pause(timer, paused)" function
-static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr)
+static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_NUMBER) {
emsg(_(e_number_exp));
@@ -9294,7 +8669,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr)
}
/// "timer_start(timeout, callback, opts)" function
-static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int repeat = 1;
@@ -9326,7 +8701,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "timer_stop(timerid)" function
-static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_timer_stop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_NUMBER) {
emsg(_(e_number_exp));
@@ -9341,27 +8716,27 @@ static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
timer_stop(timer);
}
-static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr)
+static void f_timer_stopall(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
{
timer_stop_all();
}
/// "tolower(string)" function
-static void f_tolower(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_tolower(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), false);
}
/// "toupper(string)" function
-static void f_toupper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_toupper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), true);
}
/// "tr(string, fromstr, tostr)" function
-static void f_tr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[NUMBUFLEN];
char buf2[NUMBUFLEN];
@@ -9389,7 +8764,7 @@ static void f_tr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int fromlen;
for (const char *p = fromstr; *p != NUL; p += fromlen) {
fromlen = utfc_ptr2len(p);
- if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) {
+ if (fromlen == inlen && strncmp(in_str, p, (size_t)inlen) == 0) {
int tolen;
for (p = tostr; *p != NUL; p += tolen) {
tolen = utfc_ptr2len(p);
@@ -9440,14 +8815,14 @@ error:
}
/// "trim({expr})" function
-static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf1[NUMBUFLEN];
char buf2[NUMBUFLEN];
- const char_u *head = (const char_u *)tv_get_string_buf_chk(&argvars[0], buf1);
- const char_u *mask = NULL;
- const char_u *prev;
- const char_u *p;
+ const char *head = tv_get_string_buf_chk(&argvars[0], buf1);
+ const char *mask = NULL;
+ const char *prev;
+ const char *p;
int dir = 0;
rettv->v_type = VAR_STRING;
@@ -9456,8 +8831,13 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
+ if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_STRING) {
+ semsg(_(e_invarg2), tv_get_string(&argvars[1]));
+ return;
+ }
+
if (argvars[1].v_type == VAR_STRING) {
- mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2);
+ mask = tv_get_string_buf_chk(&argvars[1], buf2);
if (argvars[2].v_type != VAR_UNKNOWN) {
bool error = false;
// leading or trailing characters to trim
@@ -9495,7 +8875,7 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- const char_u *tail = head + STRLEN(head);
+ const char *tail = head + strlen(head);
if (dir == 0 || dir == 2) {
// Trim trailing characters
for (; tail > head; tail = prev) {
@@ -9518,11 +8898,11 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- rettv->vval.v_string = (char *)vim_strnsave(head, (size_t)(tail - head));
+ rettv->vval.v_string = xstrnsave(head, (size_t)(tail - head));
}
/// "type(expr)" function
-static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_type(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int n = -1;
@@ -9554,7 +8934,7 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "undofile(name)" function
-static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_undofile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
const char *const fname = tv_get_string(&argvars[0]);
@@ -9573,7 +8953,7 @@ static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "undotree()" function
-static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_undotree(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
@@ -9591,7 +8971,7 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "virtcol(string)" function
-static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
colnr_T vcol = 0;
int fnum = curbuf->b_fnum;
@@ -9603,7 +8983,7 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (fp->col < 0) {
fp->col = 0;
} else {
- const size_t len = STRLEN(ml_get(fp->lnum));
+ const size_t len = strlen(ml_get(fp->lnum));
if (fp->col > (colnr_T)len) {
fp->col = (colnr_T)len;
}
@@ -9616,14 +8996,14 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "visualmode()" function
-static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_visualmode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u str[2];
+ char str[2];
rettv->v_type = VAR_STRING;
- str[0] = (char_u)curbuf->b_visual_mode_eval;
+ str[0] = (char)curbuf->b_visual_mode_eval;
str[1] = NUL;
- rettv->vval.v_string = (char *)vim_strsave(str);
+ rettv->vval.v_string = xstrdup(str);
// A non-zero number or non-empty string argument: reset mode.
if (non_zero_arg(&argvars[0])) {
@@ -9632,287 +9012,29 @@ static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "wildmenumode()" function
-static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_wildmenumode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (wild_menu_showing || ((State & MODE_CMDLINE) && cmdline_pum_active())) {
rettv->vval.v_number = 1;
}
}
-/// "win_findbuf()" function
-static void f_win_findbuf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_list_alloc_ret(rettv, kListLenMayKnow);
- win_findbuf(argvars, rettv->vval.v_list);
-}
-
-/// "win_getid()" function
-static void f_win_getid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = win_getid(argvars);
-}
-
-/// "win_gettype(nr)" function
-static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp = curwin;
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_string = (char *)vim_strsave((char_u *)"unknown");
- return;
- }
- }
- if (wp == aucmd_win) {
- rettv->vval.v_string = xstrdup("autocmd");
- } else if (wp->w_p_pvw) {
- rettv->vval.v_string = xstrdup("preview");
- } else if (wp->w_floating) {
- rettv->vval.v_string = xstrdup("popup");
- } else if (wp == curwin && cmdwin_type != 0) {
- rettv->vval.v_string = xstrdup("command");
- } else if (bt_quickfix(wp->w_buffer)) {
- rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
- }
-}
-
-/// "win_gotoid()" function
-static void f_win_gotoid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = win_gotoid(argvars);
-}
-
-/// "win_id2tabwin()" function
-static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_id2tabwin(argvars, rettv);
-}
-
-/// "win_id2win()" function
-static void f_win_id2win(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = win_id2win(argvars);
-}
-
-/// "win_move_separator()" function
-static void f_win_move_separator(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = false;
-
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL || wp->w_floating) {
- return;
- }
-
- int offset = (int)tv_get_number(&argvars[1]);
- win_drag_vsep_line(wp, offset);
- rettv->vval.v_number = true;
-}
-
-/// "win_move_statusline()" function
-static void f_win_move_statusline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp;
- int offset;
-
- rettv->vval.v_number = false;
-
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL || wp->w_floating) {
- return;
- }
-
- offset = (int)tv_get_number(&argvars[1]);
- win_drag_status_line(wp, offset);
- rettv->vval.v_number = true;
-}
-
-/// "winbufnr(nr)" function
-static void f_winbufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_buffer->b_fnum;
- }
-}
-
-/// "wincol()" function
-static void f_wincol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- validate_cursor();
- rettv->vval.v_number = curwin->w_wcol + 1;
-}
-
-/// "winheight(nr)" function
-static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_height;
- }
-}
-
-/// "winlayout()" function
-static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tabpage_T *tp;
-
- tv_list_alloc_ret(rettv, 2);
-
- if (argvars[0].v_type == VAR_UNKNOWN) {
- tp = curtab;
- } else {
- tp = find_tabpage((int)tv_get_number(&argvars[0]));
- if (tp == NULL) {
- return;
- }
- }
-
- get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
-}
-
-/// "winline()" function
-static void f_winline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- validate_cursor();
- rettv->vval.v_number = curwin->w_wrow + 1;
-}
-
-/// "winnr()" function
-static void f_winnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = get_winnr(curtab, &argvars[0]);
-}
-
-/// "winrestcmd()" function
-static void f_winrestcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- char_u buf[50];
-
- garray_T ga;
- ga_init(&ga, (int)sizeof(char), 70);
-
- // Do this twice to handle some window layouts properly.
- for (int i = 0; i < 2; i++) {
- int winnr = 1;
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- snprintf((char *)buf, sizeof(buf), "%dresize %d|", winnr,
- wp->w_height);
- ga_concat(&ga, (char *)buf);
- snprintf((char *)buf, sizeof(buf), "vert %dresize %d|", winnr,
- wp->w_width);
- ga_concat(&ga, (char *)buf);
- winnr++;
- }
- }
- ga_append(&ga, NUL);
-
- rettv->vval.v_string = ga.ga_data;
- rettv->v_type = VAR_STRING;
-}
-
-/// "winrestview()" function
-static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- dict_T *dict = argvars[0].vval.v_dict;
-
- if (argvars[0].v_type != VAR_DICT || dict == NULL) {
- emsg(_(e_invarg));
- } else {
- dictitem_T *di;
- if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
- curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
- curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
- curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
- curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
- curwin->w_set_curswant = false;
- }
- if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
- set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
- }
- if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
- curwin->w_topfill = (int)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
- curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
- curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
- }
-
- check_cursor();
- win_new_height(curwin, curwin->w_height);
- win_new_width(curwin, curwin->w_width);
- changed_window_setting();
-
- if (curwin->w_topline <= 0) {
- curwin->w_topline = 1;
- }
- if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
- curwin->w_topline = curbuf->b_ml.ml_line_count;
- }
- check_topfill(curwin, true);
- }
-}
-
-/// "winsaveview()" function
-static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_dict_alloc_ret(rettv);
- dict_T *dict = rettv->vval.v_dict;
-
- tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
- tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
- tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
- update_curswant();
- tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
-
- tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
- tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
- tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
- tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
-}
-
-/// "winwidth(nr)" function
-static void f_winwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_width;
- }
-}
-
/// "windowsversion()" function
-static void f_windowsversion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_windowsversion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = xstrdup(windowsVersion);
}
/// "wordcount()" function
-static void f_wordcount(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_wordcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_alloc_ret(rettv);
cursor_pos_info(rettv->vval.v_dict);
}
/// "writefile()" function
-static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = -1;
@@ -9935,6 +9057,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool binary = false;
bool append = false;
bool do_fsync = !!p_fs;
+ bool mkdir_p = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
const char *const flags = tv_get_string_chk(&argvars[2]);
if (flags == NULL) {
@@ -9950,6 +9073,8 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
do_fsync = true; break;
case 'S':
do_fsync = false; break;
+ case 'p':
+ mkdir_p = true; break;
default:
// Using %s, p and not %c, *p to preserve multibyte characters
semsg(_("E5060: Unknown flag: %s"), p);
@@ -9969,6 +9094,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_("E482: Can't open file with an empty name"));
} else if ((error = file_open(&fp, fname,
((append ? kFileAppend : kFileTruncate)
+ | (mkdir_p ? kFileMkDir : kFileCreate)
| kFileCreate), 0666)) != 0) {
semsg(_("E482: Can't open file %s for writing: %s"),
fname, os_strerror(error));
@@ -9990,7 +9116,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "xor(expr, expr)" function
-static void f_xor(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static void f_xor(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
^ tv_get_number_chk(&argvars[1], NULL);
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index 583ee0e75e..1ae031a952 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -1,11 +1,17 @@
#ifndef NVIM_EVAL_FUNCS_H
#define NVIM_EVAL_FUNCS_H
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "nvim/api/private/dispatch.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/types.h"
/// Prototype of C function that implements VimL function
-typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
+typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, EvalFuncData data);
/// Special flags for base_arg @see EvalFuncDef
#define BASE_NONE 0 ///< Not a method (no base argument).
@@ -13,13 +19,13 @@ typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
/// Structure holding VimL function definition
typedef struct {
- char *name; ///< Name of the function.
- uint8_t min_argc; ///< Minimal number of arguments.
- uint8_t max_argc; ///< Maximal number of arguments.
- uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
- bool fast; ///< Can be run in |api-fast| events
- VimLFunc func; ///< Function implementation.
- FunPtr data; ///< Userdata for function implementation.
+ char *name; ///< Name of the function.
+ uint8_t min_argc; ///< Minimal number of arguments.
+ uint8_t max_argc; ///< Maximal number of arguments.
+ uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
+ bool fast; ///< Can be run in |api-fast| events
+ VimLFunc func; ///< Function implementation.
+ EvalFuncData data; ///< Userdata for function implementation.
} EvalFuncDef;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/eval/gc.c b/src/nvim/eval/gc.c
index 633e6abacf..6a54c4ddc1 100644
--- a/src/nvim/eval/gc.c
+++ b/src/nvim/eval/gc.c
@@ -1,11 +1,12 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <stddef.h>
+
#include "nvim/eval/gc.h"
-#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/gc.c.generated.h"
+# include "eval/gc.c.generated.h" // IWYU pragma: export
#endif
/// Head of list of all dictionaries
diff --git a/src/nvim/eval/gc.h b/src/nvim/eval/gc.h
index c2e862e469..3185750c3b 100644
--- a/src/nvim/eval/gc.h
+++ b/src/nvim/eval/gc.h
@@ -2,6 +2,7 @@
#define NVIM_EVAL_GC_H
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
extern dict_T *gc_first_dict;
extern list_T *gc_first_list;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 8822bb0491..05b4737206 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -28,9 +28,9 @@
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/mbyte.h"
+#include "nvim/mbyte_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/os/fileio.h"
#include "nvim/os/input.h"
#include "nvim/pos.h"
#include "nvim/types.h"
@@ -40,6 +40,15 @@
# include "eval/typval.c.generated.h"
#endif
+static char e_string_required_for_argument_nr[]
+ = N_("E1174: String required for argument %d");
+static char e_non_empty_string_required_for_argument_nr[]
+ = N_("E1175: Non-empty string required for argument %d");
+static char e_number_required_for_argument_nr[]
+ = N_("E1210: Number required for argument %d");
+static char e_string_or_list_required_for_argument_nr[]
+ = N_("E1222: String or List required for argument %d");
+
bool tv_in_free_unref_items = false;
// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
@@ -317,10 +326,12 @@ void tv_list_free_list(list_T *const l)
void tv_list_free(list_T *const l)
FUNC_ATTR_NONNULL_ALL
{
- if (!tv_in_free_unref_items) {
- tv_list_free_contents(l);
- tv_list_free_list(l);
+ if (tv_in_free_unref_items) {
+ return;
}
+
+ tv_list_free_contents(l);
+ tv_list_free_list(l);
}
/// Unreference a list
@@ -831,7 +842,7 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
}
/// "join()" function
-void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_join(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_LIST) {
emsg(_(e_listreq));
@@ -855,7 +866,7 @@ void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "list2str()" function
-void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_list2str(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
garray_T ga;
@@ -889,8 +900,8 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
list_T *l;
bool error = false;
- if (var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- arg_errmsg, TV_TRANSLATE)) {
+ if (value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ arg_errmsg, TV_TRANSLATE)) {
return;
}
@@ -1016,7 +1027,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
if (sortinfo->item_compare_lc) {
res = strcoll(p1, p2);
} else {
- res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);
+ res = sortinfo->item_compare_ic ? STRICMP(p1, p2): strcmp(p1, p2);
}
} else {
double n1, n2;
@@ -1079,15 +1090,17 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.evaluate = true;
- funcexe.partial = partial;
- funcexe.selfdict = sortinfo->item_compare_selfdict;
+ funcexe.fe_evaluate = true;
+ funcexe.fe_partial = partial;
+ funcexe.fe_selfdict = sortinfo->item_compare_selfdict;
res = call_func(func_name, -1, &rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
tv_clear(&argv[1]);
if (res == FAIL) {
+ // XXX: ITEM_COMPARE_FAIL is unused
res = ITEM_COMPARE_FAIL;
+ sortinfo->item_compare_func_err = true;
} else {
res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
if (res > 0) {
@@ -1143,7 +1156,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
semsg(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
list_T *const l = argvars[0].vval.v_list;
- if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
+ if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
goto theend;
}
tv_list_set_ret(rettv, l);
@@ -1242,20 +1255,18 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
item_compare_func_ptr = item_compare_keeping_zero;
}
- int idx = 0;
for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l))
; li != NULL;) {
listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li);
if (item_compare_func_ptr(&prev_li, &li) == 0) {
- if (info.item_compare_func_err) { // -V547
- emsg(_("E882: Uniq compare function failed"));
- break;
- }
li = tv_list_item_remove(l, li);
} else {
- idx++;
li = TV_LIST_ITEM_NEXT(l, li);
}
+ if (info.item_compare_func_err) {
+ emsg(_("E882: Uniq compare function failed"));
+ break;
+ }
}
}
@@ -1267,13 +1278,13 @@ theend:
}
/// "sort"({list})" function
-void f_sort(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_sort(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
do_sort_uniq(argvars, rettv, true);
}
/// "uniq({list})" function
-void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
do_sort_uniq(argvars, rettv, false);
}
@@ -1356,7 +1367,7 @@ void tv_list_reverse(list_T *const l)
/// true list will not be modified. Must be initialized to false
/// by the caller.
void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
- const ListSorter item_compare_func, bool *errp)
+ const ListSorter item_compare_func, const bool *errp)
FUNC_ATTR_NONNULL_ARG(3, 4)
{
const int len = tv_list_len(l);
@@ -1568,7 +1579,7 @@ bool tv_callback_equal(const Callback *cb1, const Callback *cb2)
}
switch (cb1->type) {
case kCallbackFuncref:
- return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
+ return strcmp(cb1->data.funcref, cb2->data.funcref) == 0;
case kCallbackPartial:
// FIXME: this is inconsistent with tv_equal but is needed for precision
// maybe change dictwatcheradd to return a watcher id instead?
@@ -1588,7 +1599,7 @@ void callback_free(Callback *callback)
{
switch (callback->type) {
case kCallbackFuncref:
- func_unref((char_u *)callback->data.funcref);
+ func_unref(callback->data.funcref);
xfree(callback->data.funcref);
break;
case kCallbackPartial:
@@ -1617,7 +1628,7 @@ void callback_put(Callback *cb, typval_T *tv)
case kCallbackFuncref:
tv->v_type = VAR_FUNC;
tv->vval.v_string = xstrdup(cb->data.funcref);
- func_ref((char_u *)cb->data.funcref);
+ func_ref(cb->data.funcref);
break;
case kCallbackLua:
// TODO(tjdevries): Unified Callback.
@@ -1643,7 +1654,7 @@ void callback_copy(Callback *dest, Callback *src)
break;
case kCallbackFuncref:
dest->data.funcref = xstrdup(src->data.funcref);
- func_ref((char_u *)src->data.funcref);
+ func_ref(src->data.funcref);
break;
case kCallbackLua:
dest->data.luaref = api_new_luaref(src->data.luaref);
@@ -1740,9 +1751,8 @@ static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key)
const size_t len = watcher->key_pattern_len;
if (len && watcher->key_pattern[len - 1] == '*') {
return strncmp(key, watcher->key_pattern, len - 1) == 0;
- } else {
- return strcmp(key, watcher->key_pattern) == 0;
}
+ return strcmp(key, watcher->key_pattern) == 0;
}
/// Send a change notification to all dictionary watchers that match given key
@@ -1774,7 +1784,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T
tv_dict_add(argv[2].vval.v_dict, v);
}
- if (oldtv) {
+ if (oldtv && oldtv->v_type != VAR_UNKNOWN) {
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
tv_copy(oldtv, &v->di_tv);
tv_dict_add(argv[2].vval.v_dict, v);
@@ -1834,6 +1844,7 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
di->di_key[key_len] = NUL;
di->di_flags = DI_FLAGS_ALLOC;
di->di_tv.v_lock = VAR_UNLOCKED;
+ di->di_tv.v_type = VAR_UNKNOWN;
return di;
}
@@ -2053,9 +2064,24 @@ int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
+ return tv_dict_get_number_def(d, key, 0);
+}
+
+/// Get a number item from a dictionary.
+///
+/// Returns "def" if the entry doesn't exist.
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Key to find in dictionary.
+/// @param[in] def Default value.
+///
+/// @return Dictionary item.
+varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key, const int def)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
dictitem_T *const di = tv_dict_find(d, key, -1);
if (di == NULL) {
- return 0;
+ return def;
}
return tv_get_number(&di->di_tv);
}
@@ -2074,7 +2100,7 @@ char **tv_dict_to_env(dict_T *denv)
TV_DICT_ITER(denv, var, {
const char *str = tv_get_string(&var->di_tv);
assert(str);
- size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1;
+ size_t len = strlen((char *)var->di_key) + strlen(str) + strlen("=") + 1;
env[i] = xmalloc(len);
snprintf(env[i], len, "%s=%s", (char *)var->di_key, str);
i++;
@@ -2183,6 +2209,15 @@ bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_
return res;
}
+/// Check for adding a function to g: or l:.
+/// If the name is wrong give an error message and return true.
+int tv_dict_wrong_func_name(dict_T *d, typval_T *tv, const char *name)
+{
+ return (d == &globvardict || &d->dv_hashtab == get_funccal_local_ht())
+ && tv_is_func(*tv)
+ && var_wrong_func_name(name, true);
+}
+
//{{{2 dict_add*
/// Add item to dictionary
@@ -2194,7 +2229,10 @@ bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_
int tv_dict_add(dict_T *const d, dictitem_T *const item)
FUNC_ATTR_NONNULL_ALL
{
- return hash_add(&d->dv_hashtab, item->di_key);
+ if (tv_dict_wrong_func_name(d, &item->di_tv, (const char *)item->di_key)) {
+ return FAIL;
+ }
+ return hash_add(&d->dv_hashtab, (char *)item->di_key);
}
/// Add a list entry to dictionary
@@ -2410,10 +2448,10 @@ void tv_dict_clear(dict_T *const d)
///
/// @param d1 Dictionary to extend.
/// @param[in] d2 Dictionary to extend with.
-/// @param[in] action "error", "force", "keep":
-///
+/// @param[in] action "error", "force", "move", "keep":
/// e*, including "error": duplicate key gives an error.
/// f*, including "force": duplicate d2 keys override d1.
+/// m*, including "move": move items instead of copying.
/// other, including "keep": duplicate d2 keys ignored.
void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action)
FUNC_ATTR_NONNULL_ALL
@@ -2422,27 +2460,33 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
const char *const arg_errmsg = _("extend() argument");
const size_t arg_errmsg_len = strlen(arg_errmsg);
- TV_DICT_ITER(d2, di2, {
+ if (*action == 'm') {
+ hash_lock(&d2->dv_hashtab); // don't rehash on hash_remove()
+ }
+
+ HASHTAB_ITER(&d2->dv_hashtab, hi2, {
+ dictitem_T *const di2 = TV_DICT_HI2DI(hi2);
dictitem_T *const di1 = tv_dict_find(d1, (const char *)di2->di_key, -1);
- if (d1->dv_scope != VAR_NO_SCOPE) {
- // Disallow replacing a builtin function in l: and g:.
- // Check the key to be valid when adding to any scope.
- if (d1->dv_scope == VAR_DEF_SCOPE
- && tv_is_func(di2->di_tv)
- && !var_check_func_name((const char *)di2->di_key, di1 == NULL)) {
- break;
- }
- if (!valid_varname((const char *)di2->di_key)) {
- break;
- }
+ // Check the key to be valid when adding to any scope.
+ if (d1->dv_scope != VAR_NO_SCOPE && !valid_varname((const char *)di2->di_key)) {
+ break;
}
if (di1 == NULL) {
- dictitem_T *const new_di = tv_dict_item_copy(di2);
- if (tv_dict_add(d1, new_di) == FAIL) {
- tv_dict_item_free(new_di);
- } else if (watched) {
- tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv,
- NULL);
+ if (*action == 'm') {
+ // Cheap way to move a dict item from "d2" to "d1".
+ // If dict_add() fails then "d2" won't be empty.
+ dictitem_T *const new_di = di2;
+ if (tv_dict_add(d1, new_di) == OK) {
+ hash_remove(&d2->dv_hashtab, hi2);
+ tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv, NULL);
+ }
+ } else {
+ dictitem_T *const new_di = tv_dict_item_copy(di2);
+ if (tv_dict_add(d1, new_di) == FAIL) {
+ tv_dict_item_free(new_di);
+ } else if (watched) {
+ tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv, NULL);
+ }
}
} else if (*action == 'e') {
semsg(_("E737: Key already exists: %s"), di2->di_key);
@@ -2450,10 +2494,14 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
} else if (*action == 'f' && di2 != di1) {
typval_T oldtv;
- if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
+ if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
|| var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
break;
}
+ // Disallow replacing a builtin function.
+ if (tv_dict_wrong_func_name(d1, &di2->di_tv, (const char *)di2->di_key)) {
+ break;
+ }
if (watched) {
tv_copy(&di1->di_tv, &oldtv);
@@ -2469,6 +2517,10 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
}
}
});
+
+ if (*action == 'm') {
+ hash_unlock(&d2->dv_hashtab);
+ }
}
/// Compare two dictionaries
@@ -2483,10 +2535,14 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool
if (d1 == d2) {
return true;
}
- if (d1 == NULL || d2 == NULL) {
+ if (tv_dict_len(d1) != tv_dict_len(d2)) {
return false;
}
- if (tv_dict_len(d1) != tv_dict_len(d2)) {
+ if (tv_dict_len(d1) == 0) {
+ // empty and NULL dicts are considered equal
+ return true;
+ }
+ if (d1 == NULL || d2 == NULL) {
return false;
}
@@ -2532,8 +2588,8 @@ dict_T *tv_dict_copy(const vimconv_T *const conv, dict_T *const orig, const bool
if (conv == NULL || conv->vc_type == CONV_NONE) {
new_di = tv_dict_item_alloc((const char *)di->di_key);
} else {
- size_t len = STRLEN(di->di_key);
- char *const key = (char *)string_convert(conv, di->di_key, &len);
+ size_t len = strlen((char *)di->di_key);
+ char *const key = (char *)string_convert(conv, (char *)di->di_key, &len);
if (key == NULL) {
new_di = tv_dict_item_alloc_len((const char *)di->di_key, len);
} else {
@@ -2654,7 +2710,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
{
blob_T *const b = argvars[0].vval.v_blob;
- if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
+ if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
return;
}
@@ -2674,7 +2730,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
}
if (argvars[2].v_type == VAR_UNKNOWN) {
// Remove one item, return its value.
- char_u *const p = (char_u *)b->bv_ga.ga_data;
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
rettv->vval.v_number = (varnumber_T)(*(p + idx));
memmove(p + idx, p + idx + 1, (size_t)(len - idx - 1));
b->bv_ga.ga_len--;
@@ -2696,9 +2752,8 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
blob->bv_ga.ga_len = (int)(end - idx + 1);
ga_grow(&blob->bv_ga, (int)(end - idx + 1));
- char_u *const p = (char_u *)b->bv_ga.ga_data;
- memmove((char_u *)blob->bv_ga.ga_data, p + idx,
- (size_t)(end - idx + 1));
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
+ memmove(blob->bv_ga.ga_data, p + idx, (size_t)(end - idx + 1));
tv_blob_set_ret(rettv, blob);
if (len - end - 1 > 0) {
@@ -2777,7 +2832,7 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi
switch (what) {
case kDictListKeys:
tv_item.v_type = VAR_STRING;
- tv_item.vval.v_string = (char *)vim_strsave(di->di_key);
+ tv_item.vval.v_string = xstrdup((char *)di->di_key);
break;
case kDictListValues:
tv_copy(&di->di_tv, &tv_item);
@@ -2806,25 +2861,25 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi
}
/// "items(dict)" function
-void f_items(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_list(argvars, rettv, 2);
}
/// "keys()" function
-void f_keys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_keys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_list(argvars, rettv, 0);
}
/// "values(dict)" function
-void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_values(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_dict_list(argvars, rettv, 1);
}
/// "has_key()" function
-void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_has_key(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (argvars[0].v_type != VAR_DICT) {
emsg(_(e_dictreq));
@@ -2846,7 +2901,7 @@ void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
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, TV_TRANSLATE)) {
+ && !value_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *key = tv_get_string_chk(&argvars[1]);
if (key != NULL) {
dictitem_T *di = tv_dict_find(d, key, -1);
@@ -2951,7 +3006,7 @@ void tv_blob_copy(typval_T *const from, typval_T *const to)
(tv)->v_lock = VAR_UNLOCKED; \
} while (0)
-static inline int _nothing_conv_func_start(typval_T *const tv, char_u *const fun)
+static inline int _nothing_conv_func_start(typval_T *const tv, char *const fun)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
{
tv->v_lock = VAR_UNLOCKED;
@@ -3114,6 +3169,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic
#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
#include "nvim/eval/typval_encode.c.h"
+
#undef TYPVAL_ENCODE_SCOPE
#undef TYPVAL_ENCODE_NAME
#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
@@ -3178,7 +3234,7 @@ void tv_free(typval_T *tv)
partial_unref(tv->vval.v_partial);
break;
case VAR_FUNC:
- func_unref((char_u *)tv->vval.v_string);
+ func_unref(tv->vval.v_string);
FALLTHROUGH;
case VAR_STRING:
xfree(tv->vval.v_string);
@@ -3231,7 +3287,7 @@ void tv_copy(const typval_T *const from, typval_T *const to)
if (from->vval.v_string != NULL) {
to->vval.v_string = xstrdup(from->vval.v_string);
if (from->v_type == VAR_FUNC) {
- func_ref((char_u *)to->vval.v_string);
+ func_ref(to->vval.v_string);
}
}
break;
@@ -3403,12 +3459,12 @@ bool tv_check_lock(const typval_T *tv, const char *name, size_t name_len)
default:
break;
}
- return var_check_lock(tv->v_lock, name, name_len)
- || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len));
+ return value_check_lock(tv->v_lock, name, name_len)
+ || (lock != VAR_UNLOCKED && value_check_lock(lock, name, name_len));
}
-/// @return true if variable "name" is locked (immutable)
-bool var_check_lock(VarLockStatus lock, const char *name, size_t name_len)
+/// @return true if variable "name" has a locked (immutable) value
+bool value_check_lock(VarLockStatus lock, const char *name, size_t name_len)
{
const char *error_message = NULL;
switch (lock) {
@@ -3583,13 +3639,13 @@ bool tv_check_str_or_nr(const typval_T *const tv)
#define FUNC_ERROR "E703: Using a Funcref as a Number"
static const char *const num_errors[] = {
- [VAR_PARTIAL]=N_(FUNC_ERROR),
- [VAR_FUNC]=N_(FUNC_ERROR),
- [VAR_LIST]=N_("E745: Using a List as a Number"),
- [VAR_DICT]=N_("E728: Using a Dictionary as a Number"),
- [VAR_FLOAT]=N_("E805: Using a Float as a Number"),
- [VAR_BLOB]=N_("E974: Using a Blob as a Number"),
- [VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
+ [VAR_PARTIAL]= N_(FUNC_ERROR),
+ [VAR_FUNC]= N_(FUNC_ERROR),
+ [VAR_LIST]= N_("E745: Using a List as a Number"),
+ [VAR_DICT]= N_("E728: Using a Dictionary as a Number"),
+ [VAR_FLOAT]= N_("E805: Using a Float as a Number"),
+ [VAR_BLOB]= N_("E974: Using a Blob as a Number"),
+ [VAR_UNKNOWN]= N_("E685: using an invalid value as a Number"),
};
#undef FUNC_ERROR
@@ -3628,13 +3684,13 @@ bool tv_check_num(const typval_T *const tv)
#define FUNC_ERROR "E729: using Funcref as a String"
static const char *const str_errors[] = {
- [VAR_PARTIAL]=N_(FUNC_ERROR),
- [VAR_FUNC]=N_(FUNC_ERROR),
- [VAR_LIST]=N_("E730: using List as a String"),
- [VAR_DICT]=N_("E731: using Dictionary as a String"),
- [VAR_FLOAT]=((const char *)e_float_as_string),
- [VAR_BLOB]=N_("E976: using Blob as a String"),
- [VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
+ [VAR_PARTIAL]= N_(FUNC_ERROR),
+ [VAR_FUNC]= N_(FUNC_ERROR),
+ [VAR_LIST]= N_("E730: using List as a String"),
+ [VAR_DICT]= N_("E731: using Dictionary as a String"),
+ [VAR_FLOAT]= ((const char *)e_float_as_string),
+ [VAR_BLOB]= N_("E976: using Blob as a String"),
+ [VAR_UNKNOWN]= N_("E908: using an invalid value as a String"),
};
#undef FUNC_ERROR
@@ -3717,8 +3773,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
case VAR_STRING: {
varnumber_T n = 0;
if (tv->vval.v_string != NULL) {
- vim_str2nr((char_u *)tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0,
- false);
+ vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0, false);
}
return n;
}
@@ -3746,9 +3801,11 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
linenr_T tv_get_lnum(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
+ const int did_emsg_before = did_emsg;
linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL);
- if (lnum == 0) { // No valid number, try using same function as line() does.
+ if (lnum <= 0 && did_emsg_before == did_emsg && tv->v_type != VAR_NUMBER) {
int fnum;
+ // No valid number, try using same function as line() does.
pos_T *const fp = var2fpos(tv, true, &fnum, false);
if (fp != NULL) {
lnum = fp->lnum;
@@ -3801,26 +3858,56 @@ float_T tv_get_float(const typval_T *const tv)
return 0;
}
-// Give an error and return FAIL unless "tv" is a string.
-int tv_check_for_string(const typval_T *const tv)
+/// Give an error and return FAIL unless "args[idx]" is a string.
+int tv_check_for_string_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (args[idx].v_type != VAR_STRING) {
+ semsg(_(e_string_required_for_argument_nr), idx + 1);
+ return FAIL;
+ }
+ return OK;
+}
+
+/// Give an error and return FAIL unless "args[idx]" is a non-empty string.
+int tv_check_for_nonempty_string_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
- if (tv->v_type != VAR_STRING) {
- emsg(_(e_stringreq));
+ if (tv_check_for_string_arg(args, idx) == FAIL) {
+ return FAIL;
+ }
+ if (args[idx].vval.v_string == NULL || *args[idx].vval.v_string == NUL) {
+ semsg(_(e_non_empty_string_required_for_argument_nr), idx + 1);
return FAIL;
}
return OK;
}
-// Give an error and return FAIL unless "tv" is a non-empty string.
-int tv_check_for_nonempty_string(const typval_T *const tv)
+/// Give an error and return FAIL unless "args[idx]" is a number.
+int tv_check_for_number_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
- if (tv_check_for_string(tv) == FAIL) {
+ if (args[idx].v_type != VAR_NUMBER) {
+ semsg(_(e_number_required_for_argument_nr), idx + 1);
return FAIL;
}
- if (tv->vval.v_string == NULL || *tv->vval.v_string == NUL) {
- emsg(_(e_non_empty_string_required));
+ return OK;
+}
+
+/// Check for an optional number argument at "idx"
+int tv_check_for_opt_number_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ return (args[idx].v_type == VAR_UNKNOWN
+ || tv_check_for_number_arg(args, idx) != FAIL) ? OK : FAIL;
+}
+
+/// Give an error and return FAIL unless "args[idx]" is a string or a list.
+int tv_check_for_string_or_list_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_LIST) {
+ semsg(_(e_string_or_list_required_for_argument_nr), idx + 1);
return FAIL;
}
return OK;
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index c4bc9f603b..3f59cd3547 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -2,11 +2,12 @@
#define NVIM_EVAL_TYPVAL_H
#include <assert.h>
-#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
+#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/gettext.h"
@@ -15,405 +16,10 @@
#include "nvim/macros.h"
#include "nvim/mbyte_defs.h"
#include "nvim/message.h"
-#include "nvim/pos.h" // for linenr_T
#include "nvim/types.h"
-#ifdef LOG_LIST_ACTIONS
-# include "nvim/memory.h"
-#endif
-
-/// Type used for VimL VAR_NUMBER values
-typedef int64_t varnumber_T;
-typedef uint64_t uvarnumber_T;
-
-/// Type used for VimL VAR_FLOAT values
-typedef double float_T;
-
-/// Refcount for dict or list that should not be freed
-enum { DO_NOT_FREE_CNT = (INT_MAX / 2), };
-
-/// Additional values for tv_list_alloc() len argument
-enum ListLenSpecials {
- /// List length is not known in advance
- ///
- /// To be used when there is neither a way to know how many elements will be
- /// needed nor are any educated guesses.
- kListLenUnknown = -1,
- /// List length *should* be known, but is actually not
- ///
- /// All occurrences of this value should be eventually removed. This is for
- /// the case when the only reason why list length is not known is that it
- /// would be hard to code without refactoring, but refactoring is needed.
- kListLenShouldKnow = -2,
- /// List length may be known in advance, but it requires too much effort
- ///
- /// To be used when it looks impractical to determine list length.
- kListLenMayKnow = -3,
-};
-
-/// Maximal possible value of varnumber_T variable
-#define VARNUMBER_MAX INT64_MAX
-#define UVARNUMBER_MAX UINT64_MAX
-
-/// Minimal possible value of varnumber_T variable
-#define VARNUMBER_MIN INT64_MIN
-
-/// %d printf format specifier for varnumber_T
-#define PRIdVARNUMBER PRId64
-
-typedef struct listvar_S list_T;
-typedef struct dictvar_S dict_T;
-typedef struct partial_S partial_T;
-typedef struct blobvar_S blob_T;
-
-typedef struct ufunc ufunc_T;
-
-typedef enum {
- kCallbackNone = 0,
- kCallbackFuncref,
- kCallbackPartial,
- kCallbackLua,
-} CallbackType;
-
-typedef struct {
- union {
- char *funcref;
- partial_T *partial;
- LuaRef luaref;
- } data;
- CallbackType type;
-} Callback;
-
-#define CALLBACK_INIT { .type = kCallbackNone }
-#define CALLBACK_NONE ((Callback)CALLBACK_INIT)
-
-/// Structure holding dictionary watcher
-typedef struct dict_watcher {
- Callback callback;
- char *key_pattern;
- size_t key_pattern_len;
- QUEUE node;
- bool busy; // prevent recursion if the dict is changed in the callback
- bool needs_free;
-} DictWatcher;
-
-/// Bool variable values
-typedef enum {
- kBoolVarFalse, ///< v:false
- kBoolVarTrue, ///< v:true
-} BoolVarValue;
-
-/// Special variable values
-typedef enum {
- kSpecialVarNull, ///< v:null
-} SpecialVarValue;
-
-/// Variable lock status for typval_T.v_lock
-typedef enum {
- VAR_UNLOCKED = 0, ///< Not locked.
- VAR_LOCKED = 1, ///< User lock, can be unlocked.
- VAR_FIXED = 2, ///< Locked forever.
-} VarLockStatus;
-
-/// VimL variable types, for use in typval_T.v_type
-typedef enum {
- VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
- VAR_NUMBER, ///< Number, .v_number is used.
- VAR_STRING, ///< String, .v_string is used.
- VAR_FUNC, ///< Function reference, .v_string is used as function name.
- VAR_LIST, ///< List, .v_list is used.
- VAR_DICT, ///< Dictionary, .v_dict is used.
- VAR_FLOAT, ///< Floating-point value, .v_float is used.
- VAR_BOOL, ///< true, false
- VAR_SPECIAL, ///< Special value (null), .v_special
- ///< is used.
- VAR_PARTIAL, ///< Partial, .v_partial is used.
- VAR_BLOB, ///< Blob, .v_blob is used.
-} VarType;
-
-/// Structure that holds an internal variable value
-typedef struct {
- VarType v_type; ///< Variable type.
- VarLockStatus v_lock; ///< Variable lock status.
- union typval_vval_union {
- varnumber_T v_number; ///< Number, for VAR_NUMBER.
- BoolVarValue v_bool; ///< Bool value, for VAR_BOOL
- SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
- float_T v_float; ///< Floating-point number, for VAR_FLOAT.
- char *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
- list_T *v_list; ///< List for VAR_LIST, can be NULL.
- dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
- partial_T *v_partial; ///< Closure: function with args.
- blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL.
- } vval; ///< Actual value.
-} typval_T;
-
-/// Values for (struct dictvar_S).dv_scope
-typedef enum {
- VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
- VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
- VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
- ///< (l:, g:).
-} ScopeType;
-
-/// Structure to hold an item of a list
-typedef struct listitem_S listitem_T;
-
-struct listitem_S {
- listitem_T *li_next; ///< Next item in list.
- listitem_T *li_prev; ///< Previous item in list.
- typval_T li_tv; ///< Item value.
-};
-
-/// Structure used by those that are using an item in a list
-typedef struct listwatch_S listwatch_T;
-
-struct listwatch_S {
- listitem_T *lw_item; ///< Item being watched.
- listwatch_T *lw_next; ///< Next watcher.
-};
-
-/// Structure to hold info about a list
-/// Order of members is optimized to reduce padding.
-struct listvar_S {
- listitem_T *lv_first; ///< First item, NULL if none.
- listitem_T *lv_last; ///< Last item, NULL if none.
- listwatch_T *lv_watch; ///< First watcher, NULL if none.
- listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
- list_T *lv_copylist; ///< Copied list used by deepcopy().
- list_T *lv_used_next; ///< next list in used lists list.
- list_T *lv_used_prev; ///< Previous list in used lists list.
- int lv_refcount; ///< Reference count.
- int lv_len; ///< Number of items.
- int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
- int lv_copyID; ///< ID used by deepcopy().
- VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
-
- LuaRef lua_table_ref;
-};
-
-// Static list with 10 items. Use tv_list_init_static10() to initialize.
-typedef struct {
- list_T sl_list; // must be first
- listitem_T sl_items[10];
-} staticList10_T;
-
-#define TV_LIST_STATIC10_INIT { \
- .sl_list = { \
- .lv_first = NULL, \
- .lv_last = NULL, \
- .lv_refcount = 0, \
- .lv_len = 0, \
- .lv_watch = NULL, \
- .lv_idx_item = NULL, \
- .lv_lock = VAR_FIXED, \
- .lv_used_next = NULL, \
- .lv_used_prev = NULL, \
- }, \
-}
-
-#define TV_DICTITEM_STRUCT(...) \
- struct { \
- typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
- uint8_t di_flags; /* Flags. */ \
- char_u di_key[__VA_ARGS__]; /* Key value. */ \
- }
-
-/// Structure to hold a scope dictionary
-///
-/// @warning Must be compatible with dictitem_T.
-///
-/// For use in find_var_in_ht to pretend that it found dictionary item when it
-/// finds scope dictionary.
-typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
-
-/// Structure to hold an item of a Dictionary
-///
-/// @warning Must be compatible with ScopeDictDictItem.
-///
-/// Also used for a variable.
-typedef TV_DICTITEM_STRUCT() dictitem_T;
-
-/// Flags for dictitem_T.di_flags
-typedef enum {
- DI_FLAGS_RO = 1, ///< Read-only value
- DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
- DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
- DI_FLAGS_LOCK = 8, ///< Locked value.
- DI_FLAGS_ALLOC = 16, ///< Separately allocated.
-} DictItemFlags;
-
-/// Structure representing a Dictionary
-struct dictvar_S {
- VarLockStatus dv_lock; ///< Whole dictionary lock status.
- ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
- ///< dictionary represents a scope (i.e. g:, l: …).
- int dv_refcount; ///< Reference count.
- int dv_copyID; ///< ID used when recursivery traversing a value.
- hashtab_T dv_hashtab; ///< Hashtab containing all items.
- dict_T *dv_copydict; ///< Copied dict used by deepcopy().
- dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
- dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
- QUEUE watchers; ///< Dictionary key watchers set by user code.
-
- LuaRef lua_table_ref;
-};
-
-/// Structure to hold info about a Blob
-struct blobvar_S {
- garray_T bv_ga; ///< Growarray with the data.
- int bv_refcount; ///< Reference count.
- VarLockStatus bv_lock; ///< VAR_UNLOCKED, VAR_LOCKED, VAR_FIXED.
-};
-
-/// Type used for script ID
-typedef int scid_T;
-/// Format argument for scid_T
-#define PRIdSCID "d"
-
-// SCript ConteXt (SCTX): identifies a script line.
-// When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current
-// line number. When executing a user function "sc_lnum" is the line where the
-// function was defined, "sourcing_lnum" is the line number inside the
-// function. When stored with a function, mapping, option, etc. "sc_lnum" is
-// the line number in the script "sc_sid".
-typedef struct {
- scid_T sc_sid; // script ID
- int sc_seq; // sourcing sequence number
- linenr_T sc_lnum; // line number
-} sctx_T;
-
-/// Maximum number of function arguments
-#define MAX_FUNC_ARGS 20
-/// Short variable name length
-#define VAR_SHORT_LEN 20
-/// Number of fixed variables used for arguments
-#define FIXVAR_CNT 12
-
-/// Callback interface for C function reference>
-/// Used for managing functions that were registered with |register_cfunc|
-typedef int (*cfunc_T)(int argcount, typval_T *argvars, typval_T *rettv, void *state); // NOLINT
-/// Callback to clear cfunc_T and any associated state.
-typedef void (*cfunc_free_T)(void *state);
-
-// Structure to hold info for a function that is currently being executed.
-typedef struct funccall_S funccall_T;
-
-struct funccall_S {
- ufunc_T *func; ///< Function being called.
- int linenr; ///< Next line to be executed.
- int returned; ///< ":return" used.
- /// Fixed variables for arguments.
- TV_DICTITEM_STRUCT(VAR_SHORT_LEN + 1) fixvar[FIXVAR_CNT];
- dict_T l_vars; ///< l: local function variables.
- ScopeDictDictItem l_vars_var; ///< Variable for l: scope.
- dict_T l_avars; ///< a: argument variables.
- ScopeDictDictItem l_avars_var; ///< Variable for a: scope.
- list_T l_varlist; ///< List for a:000.
- listitem_T l_listitems[MAX_FUNC_ARGS]; ///< List items for a:000.
- typval_T *rettv; ///< Return value.
- linenr_T breakpoint; ///< Next line with breakpoint or zero.
- int dbg_tick; ///< Debug_tick when breakpoint was set.
- int level; ///< Top nesting level of executed function.
- proftime_T prof_child; ///< Time spent in a child.
- funccall_T *caller; ///< Calling function or NULL; or next funccal in
- ///< list pointed to by previous_funccal.
- int fc_refcount; ///< Number of user functions that reference this funccall.
- int fc_copyID; ///< CopyID used for garbage collection.
- garray_T fc_funcs; ///< List of ufunc_T* which keep a reference to "func".
-};
-
-/// Structure to hold info for a user function.
-struct ufunc {
- int uf_varargs; ///< variable nr of arguments
- int uf_flags;
- int uf_calls; ///< nr of active calls
- bool uf_cleared; ///< func_clear() was already called
- garray_T uf_args; ///< arguments
- garray_T uf_def_args; ///< default argument expressions
- garray_T uf_lines; ///< function lines
- int uf_profiling; ///< true when func is being profiled
- int uf_prof_initialized;
- // Managing cfuncs
- cfunc_T uf_cb; ///< C function extension callback
- cfunc_free_T uf_cb_free; ///< C function extension free callback
- void *uf_cb_state; ///< State of C function extension.
- // Profiling the function as a whole.
- int uf_tm_count; ///< nr of calls
- proftime_T uf_tm_total; ///< time spent in function + children
- proftime_T uf_tm_self; ///< time spent in function itself
- proftime_T uf_tm_children; ///< time spent in children this call
- // Profiling the function per line.
- int *uf_tml_count; ///< nr of times line was executed
- proftime_T *uf_tml_total; ///< time spent in a line + children
- proftime_T *uf_tml_self; ///< time spent in a line itself
- proftime_T uf_tml_start; ///< start time for current line
- proftime_T uf_tml_children; ///< time spent in children for this line
- proftime_T uf_tml_wait; ///< start wait time for current line
- int uf_tml_idx; ///< index of line being timed; -1 if none
- int uf_tml_execed; ///< line being timed was executed
- sctx_T uf_script_ctx; ///< SCTX where function was defined,
- ///< used for s: variables
- int uf_refcount; ///< reference count, see func_name_refcount()
- funccall_T *uf_scoped; ///< l: local variables for closure
- char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with
- ///< "<SNR>" as a string, otherwise NULL
- char_u uf_name[]; ///< Name of function (actual size equals name);
- ///< can start with <SNR>123_
- ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
-};
-
-struct partial_S {
- int pt_refcount; ///< Reference count.
- char_u *pt_name; ///< Function name; when NULL use pt_func->name.
- ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with
- ///< pt_name.
- bool pt_auto; ///< When true the partial was created by using dict.member
- ///< in handle_subscript().
- int pt_argc; ///< Number of arguments.
- typval_T *pt_argv; ///< Arguments in allocated array.
- dict_T *pt_dict; ///< Dict for "self".
-};
-
-/// Structure used for explicit stack while garbage collecting hash tables
-typedef struct ht_stack_S {
- hashtab_T *ht;
- struct ht_stack_S *prev;
-} ht_stack_T;
-
-/// Structure used for explicit stack while garbage collecting lists
-typedef struct list_stack_S {
- list_T *list;
- struct list_stack_S *prev;
-} list_stack_T;
-
-/// Structure representing one list item, used for sort array.
-typedef struct {
- listitem_T *item; ///< Sorted list item.
- int idx; ///< Sorted list item index.
-} ListSortItem;
-
-typedef int (*ListSorter)(const void *, const void *);
#ifdef LOG_LIST_ACTIONS
-
-/// List actions log entry
-typedef struct {
- uintptr_t l; ///< List log entry belongs to.
- uintptr_t li1; ///< First list item log entry belongs to, if applicable.
- uintptr_t li2; ///< Second list item log entry belongs to, if applicable.
- int len; ///< List length when log entry was created.
- const char *action; ///< Logged action.
-} ListLogEntry;
-
-typedef struct list_log ListLog;
-
-/// List actions log
-struct list_log {
- ListLog *next; ///< Next chunk or NULL.
- size_t capacity; ///< Number of entries in current chunk.
- size_t size; ///< Current chunk size.
- ListLogEntry entries[]; ///< Actual log entries.
-};
+# include "nvim/memory.h"
extern ListLog *list_log_first; ///< First list log chunk, NULL if missing
extern ListLog *list_log_last; ///< Last list log chunk
@@ -442,10 +48,8 @@ static inline ListLog *list_log_new(const size_t size)
return ret;
}
-static inline void list_log(const list_T *const l,
- const listitem_T *const li1,
- const listitem_T *const li2,
- const char *const action)
+static inline void list_log(const list_T *const l, const listitem_T *const li1,
+ const listitem_T *const li2, const char *const action)
REAL_FATTR_ALWAYS_INLINE;
/// Add new entry to log
@@ -489,7 +93,7 @@ static inline void list_log(const list_T *const l, const listitem_T *const li1,
#define TV_DICT_HI2DI(hi) \
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
-static inline void tv_list_ref(list_T *const l)
+static inline void tv_list_ref(list_T *l)
REAL_FATTR_ALWAYS_INLINE;
/// Increase reference count for a given list
@@ -505,7 +109,7 @@ static inline void tv_list_ref(list_T *const l)
l->lv_refcount++;
}
-static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
+static inline void tv_list_set_ret(typval_T *tv, list_T *l)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a list as the return value. Increments the reference count.
@@ -519,7 +123,7 @@ static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
tv_list_ref(l);
}
-static inline VarLockStatus tv_list_locked(const list_T *const l)
+static inline VarLockStatus tv_list_locked(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get list lock status
@@ -562,7 +166,7 @@ static inline void tv_list_set_copyid(list_T *const l, const int copyid)
l->lv_copyID = copyid;
}
-static inline int tv_list_len(const list_T *const l)
+static inline int tv_list_len(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a list
@@ -577,7 +181,7 @@ static inline int tv_list_len(const list_T *const l)
return l->lv_len;
}
-static inline int tv_list_copyid(const list_T *const l)
+static inline int tv_list_copyid(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
/// Get list copyID
@@ -590,7 +194,7 @@ static inline int tv_list_copyid(const list_T *const l)
return l->lv_copyID;
}
-static inline list_T *tv_list_latest_copy(const list_T *const l)
+static inline list_T *tv_list_latest_copy(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
/// Get latest list copy
@@ -605,7 +209,7 @@ static inline list_T *tv_list_latest_copy(const list_T *const l)
return l->lv_copylist;
}
-static inline int tv_list_uidx(const list_T *const l, int n)
+static inline int tv_list_uidx(const list_T *l, int n)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Normalize index: that is, return either -1 or non-negative index
@@ -628,7 +232,7 @@ static inline int tv_list_uidx(const list_T *const l, int n)
return n;
}
-static inline bool tv_list_has_watchers(const list_T *const l)
+static inline bool tv_list_has_watchers(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check whether list has watchers
@@ -643,7 +247,7 @@ static inline bool tv_list_has_watchers(const list_T *const l)
return l && l->lv_watch;
}
-static inline listitem_T *tv_list_first(const list_T *const l)
+static inline listitem_T *tv_list_first(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get first list item
@@ -661,7 +265,7 @@ static inline listitem_T *tv_list_first(const list_T *const l)
return l->lv_first;
}
-static inline listitem_T *tv_list_last(const list_T *const l)
+static inline listitem_T *tv_list_last(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get last list item
@@ -679,7 +283,7 @@ static inline listitem_T *tv_list_last(const list_T *const l)
return l->lv_last;
}
-static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
+static inline void tv_dict_set_ret(typval_T *tv, dict_T *d)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a dictionary as the return value
@@ -695,7 +299,7 @@ static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
}
}
-static inline long tv_dict_len(const dict_T *const d)
+static inline long tv_dict_len(const dict_T *d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a Dictionary
@@ -709,7 +313,7 @@ static inline long tv_dict_len(const dict_T *const d)
return (long)d->dv_hashtab.ht_used;
}
-static inline bool tv_dict_is_watched(const dict_T *const d)
+static inline bool tv_dict_is_watched(const dict_T *d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check if dictionary is watched
@@ -722,7 +326,7 @@ static inline bool tv_dict_is_watched(const dict_T *const d)
return d && !QUEUE_EMPTY(&d->watchers);
}
-static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
+static inline void tv_blob_set_ret(typval_T *tv, blob_T *b)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a blob as the return value.
@@ -740,7 +344,7 @@ static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
}
}
-static inline int tv_blob_len(const blob_T *const b)
+static inline int tv_blob_len(const blob_T *b)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the length of the data in the blob, in bytes.
@@ -754,7 +358,7 @@ static inline int tv_blob_len(const blob_T *const b)
return b->bv_ga.ga_len;
}
-static inline char_u tv_blob_get(const blob_T *const b, int idx)
+static inline uint8_t tv_blob_get(const blob_T *b, int idx)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the byte at index `idx` in the blob.
@@ -763,12 +367,12 @@ static inline char_u tv_blob_get(const blob_T *const b, int idx)
/// @param[in] idx Index in a blob. Must be valid.
///
/// @return Byte value at the given index.
-static inline char_u tv_blob_get(const blob_T *const b, int idx)
+static inline uint8_t tv_blob_get(const blob_T *const b, int idx)
{
- return ((char_u *)b->bv_ga.ga_data)[idx];
+ return ((uint8_t *)b->bv_ga.ga_data)[idx];
}
-static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+static inline void tv_blob_set(blob_T *b, int idx, uint8_t c)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
/// Store the byte `c` at index `idx` in the blob.
@@ -776,9 +380,9 @@ static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
/// @param[in] b Blob to index. Cannot be NULL.
/// @param[in] idx Index in a blob. Must be valid.
/// @param[in] c Value to store.
-static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+static inline void tv_blob_set(blob_T *const b, int idx, uint8_t c)
{
- ((char_u *)b->bv_ga.ga_data)[idx] = c;
+ ((uint8_t *)b->bv_ga.ga_data)[idx] = c;
}
/// Initialize VimL object
@@ -793,12 +397,6 @@ static inline void tv_init(typval_T *const tv)
}
}
-#define TV_INITIAL_VALUE \
- ((typval_T) { \
- .v_type = VAR_UNKNOWN, \
- .v_lock = VAR_UNLOCKED, \
- })
-
/// Empty string
///
/// Needed for hack which allows not allocating empty string and still not
@@ -836,7 +434,7 @@ extern bool tv_in_free_unref_items;
/// @param li Name of the variable with current listitem_T entry.
/// @param code Cycle body.
#define TV_LIST_ITER(l, li, code) \
- _TV_LIST_ITER_MOD( , l, li, code)
+ _TV_LIST_ITER_MOD( , l, li, code) // NOLINT(whitespace/parens)
/// Iterate over a list
///
@@ -893,13 +491,9 @@ extern bool tv_in_free_unref_items;
} \
})
-static inline bool tv_get_float_chk(const typval_T *const tv,
- float_T *const ret_f)
+static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
-// FIXME circular dependency, cannot import message.h.
-bool semsg(const char *const fmt, ...);
-
/// Get the float value
///
/// Raises an error if object is not number or floating-point.
@@ -935,7 +529,7 @@ static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
return QUEUE_DATA(q, DictWatcher, node);
}
-static inline bool tv_is_func(const typval_T tv)
+static inline bool tv_is_func(typval_T tv)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
/// Check whether given typval_T contains a function
@@ -970,4 +564,9 @@ EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h"
#endif
+
+#define tv_get_bool tv_get_number
+#define tv_get_bool_chk tv_get_number_chk
+#define tv_dict_get_bool tv_dict_get_number_def
+
#endif // NVIM_EVAL_TYPVAL_H
diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h
new file mode 100644
index 0000000000..4615198441
--- /dev/null
+++ b/src/nvim/eval/typval_defs.h
@@ -0,0 +1,399 @@
+#ifndef NVIM_EVAL_TYPVAL_DEFS_H
+#define NVIM_EVAL_TYPVAL_DEFS_H
+
+#include <inttypes.h>
+#include <limits.h>
+
+#include "nvim/garray.h"
+#include "nvim/hashtab.h"
+#include "nvim/lib/queue.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+
+/// Type used for VimL VAR_NUMBER values
+typedef int64_t varnumber_T;
+typedef uint64_t uvarnumber_T;
+
+/// Refcount for dict or list that should not be freed
+enum { DO_NOT_FREE_CNT = (INT_MAX / 2), };
+
+/// Additional values for tv_list_alloc() len argument
+enum ListLenSpecials {
+ /// List length is not known in advance
+ ///
+ /// To be used when there is neither a way to know how many elements will be
+ /// needed nor are any educated guesses.
+ kListLenUnknown = -1,
+ /// List length *should* be known, but is actually not
+ ///
+ /// All occurrences of this value should be eventually removed. This is for
+ /// the case when the only reason why list length is not known is that it
+ /// would be hard to code without refactoring, but refactoring is needed.
+ kListLenShouldKnow = -2,
+ /// List length may be known in advance, but it requires too much effort
+ ///
+ /// To be used when it looks impractical to determine list length.
+ kListLenMayKnow = -3,
+};
+
+/// Maximal possible value of varnumber_T variable
+#define VARNUMBER_MAX INT64_MAX
+#define UVARNUMBER_MAX UINT64_MAX
+
+/// Minimal possible value of varnumber_T variable
+#define VARNUMBER_MIN INT64_MIN
+
+/// %d printf format specifier for varnumber_T
+#define PRIdVARNUMBER PRId64
+
+typedef struct listvar_S list_T;
+typedef struct dictvar_S dict_T;
+typedef struct partial_S partial_T;
+typedef struct blobvar_S blob_T;
+
+typedef struct ufunc ufunc_T;
+
+typedef enum {
+ kCallbackNone = 0,
+ kCallbackFuncref,
+ kCallbackPartial,
+ kCallbackLua,
+} CallbackType;
+
+typedef struct {
+ union {
+ char *funcref;
+ partial_T *partial;
+ LuaRef luaref;
+ } data;
+ CallbackType type;
+} Callback;
+
+#define CALLBACK_INIT { .type = kCallbackNone }
+#define CALLBACK_NONE ((Callback)CALLBACK_INIT)
+
+/// Structure holding dictionary watcher
+typedef struct dict_watcher {
+ Callback callback;
+ char *key_pattern;
+ size_t key_pattern_len;
+ QUEUE node;
+ bool busy; // prevent recursion if the dict is changed in the callback
+ bool needs_free;
+} DictWatcher;
+
+/// Bool variable values
+typedef enum {
+ kBoolVarFalse, ///< v:false
+ kBoolVarTrue, ///< v:true
+} BoolVarValue;
+
+/// Special variable values
+typedef enum {
+ kSpecialVarNull, ///< v:null
+} SpecialVarValue;
+
+/// Variable lock status for typval_T.v_lock
+typedef enum {
+ VAR_UNLOCKED = 0, ///< Not locked.
+ VAR_LOCKED = 1, ///< User lock, can be unlocked.
+ VAR_FIXED = 2, ///< Locked forever.
+} VarLockStatus;
+
+/// VimL variable types, for use in typval_T.v_type
+typedef enum {
+ VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
+ VAR_NUMBER, ///< Number, .v_number is used.
+ VAR_STRING, ///< String, .v_string is used.
+ VAR_FUNC, ///< Function reference, .v_string is used as function name.
+ VAR_LIST, ///< List, .v_list is used.
+ VAR_DICT, ///< Dictionary, .v_dict is used.
+ VAR_FLOAT, ///< Floating-point value, .v_float is used.
+ VAR_BOOL, ///< true, false
+ VAR_SPECIAL, ///< Special value (null), .v_special is used.
+ VAR_PARTIAL, ///< Partial, .v_partial is used.
+ VAR_BLOB, ///< Blob, .v_blob is used.
+} VarType;
+
+/// Structure that holds an internal variable value
+typedef struct {
+ VarType v_type; ///< Variable type.
+ VarLockStatus v_lock; ///< Variable lock status.
+ union typval_vval_union {
+ varnumber_T v_number; ///< Number, for VAR_NUMBER.
+ BoolVarValue v_bool; ///< Bool value, for VAR_BOOL
+ SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
+ float_T v_float; ///< Floating-point number, for VAR_FLOAT.
+ char *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
+ list_T *v_list; ///< List for VAR_LIST, can be NULL.
+ dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
+ partial_T *v_partial; ///< Closure: function with args.
+ blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL.
+ } vval; ///< Actual value.
+} typval_T;
+
+#define TV_INITIAL_VALUE \
+ ((typval_T) { \
+ .v_type = VAR_UNKNOWN, \
+ .v_lock = VAR_UNLOCKED, \
+ })
+
+/// Values for (struct dictvar_S).dv_scope
+typedef enum {
+ VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
+ VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
+ VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
+ ///< (l:, g:).
+} ScopeType;
+
+/// Structure to hold an item of a list
+typedef struct listitem_S listitem_T;
+
+struct listitem_S {
+ listitem_T *li_next; ///< Next item in list.
+ listitem_T *li_prev; ///< Previous item in list.
+ typval_T li_tv; ///< Item value.
+};
+
+/// Structure used by those that are using an item in a list
+typedef struct listwatch_S listwatch_T;
+
+struct listwatch_S {
+ listitem_T *lw_item; ///< Item being watched.
+ listwatch_T *lw_next; ///< Next watcher.
+};
+
+/// Structure to hold info about a list
+/// Order of members is optimized to reduce padding.
+struct listvar_S {
+ listitem_T *lv_first; ///< First item, NULL if none.
+ listitem_T *lv_last; ///< Last item, NULL if none.
+ listwatch_T *lv_watch; ///< First watcher, NULL if none.
+ listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
+ list_T *lv_copylist; ///< Copied list used by deepcopy().
+ list_T *lv_used_next; ///< next list in used lists list.
+ list_T *lv_used_prev; ///< Previous list in used lists list.
+ int lv_refcount; ///< Reference count.
+ int lv_len; ///< Number of items.
+ int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
+ int lv_copyID; ///< ID used by deepcopy().
+ VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
+
+ LuaRef lua_table_ref;
+};
+
+/// Static list with 10 items. Use tv_list_init_static10() to initialize.
+typedef struct {
+ list_T sl_list; // must be first
+ listitem_T sl_items[10];
+} staticList10_T;
+
+#define TV_LIST_STATIC10_INIT { \
+ .sl_list = { \
+ .lv_first = NULL, \
+ .lv_last = NULL, \
+ .lv_refcount = 0, \
+ .lv_len = 0, \
+ .lv_watch = NULL, \
+ .lv_idx_item = NULL, \
+ .lv_lock = VAR_FIXED, \
+ .lv_used_next = NULL, \
+ .lv_used_prev = NULL, \
+ }, \
+}
+
+#define TV_DICTITEM_STRUCT(...) \
+ struct { \
+ typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
+ uint8_t di_flags; /* Flags. */ \
+ char_u di_key[__VA_ARGS__]; /* Key value. */ /* NOLINT(runtime/arrays)*/ \
+ }
+
+/// Structure to hold a scope dictionary
+///
+/// @warning Must be compatible with dictitem_T.
+///
+/// For use in find_var_in_ht to pretend that it found dictionary item when it
+/// finds scope dictionary.
+typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
+
+/// Structure to hold an item of a Dictionary
+///
+/// @warning Must be compatible with ScopeDictDictItem.
+///
+/// Also used for a variable.
+typedef TV_DICTITEM_STRUCT() dictitem_T;
+
+/// Flags for dictitem_T.di_flags
+typedef enum {
+ DI_FLAGS_RO = 1, ///< Read-only value
+ DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
+ DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
+ DI_FLAGS_LOCK = 8, ///< Locked value.
+ DI_FLAGS_ALLOC = 16, ///< Separately allocated.
+} DictItemFlags;
+
+/// Structure representing a Dictionary
+struct dictvar_S {
+ VarLockStatus dv_lock; ///< Whole dictionary lock status.
+ ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
+ ///< dictionary represents a scope (i.e. g:, l: …).
+ int dv_refcount; ///< Reference count.
+ int dv_copyID; ///< ID used when recursivery traversing a value.
+ hashtab_T dv_hashtab; ///< Hashtab containing all items.
+ dict_T *dv_copydict; ///< Copied dict used by deepcopy().
+ dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
+ dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
+ QUEUE watchers; ///< Dictionary key watchers set by user code.
+
+ LuaRef lua_table_ref;
+};
+
+/// Structure to hold info about a Blob
+struct blobvar_S {
+ garray_T bv_ga; ///< Growarray with the data.
+ int bv_refcount; ///< Reference count.
+ VarLockStatus bv_lock; ///< VAR_UNLOCKED, VAR_LOCKED, VAR_FIXED.
+};
+
+/// Type used for script ID
+typedef int scid_T;
+/// Format argument for scid_T
+#define PRIdSCID "d"
+
+/// SCript ConteXt (SCTX): identifies a script line.
+/// When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current
+/// line number. When executing a user function "sc_lnum" is the line where the
+/// function was defined, "sourcing_lnum" is the line number inside the
+/// function. When stored with a function, mapping, option, etc. "sc_lnum" is
+/// the line number in the script "sc_sid".
+typedef struct {
+ scid_T sc_sid; ///< script ID
+ int sc_seq; ///< sourcing sequence number
+ linenr_T sc_lnum; ///< line number
+} sctx_T;
+
+/// Maximum number of function arguments
+enum { MAX_FUNC_ARGS = 20, };
+/// Short variable name length
+enum { VAR_SHORT_LEN = 20, };
+/// Number of fixed variables used for arguments
+enum { FIXVAR_CNT = 12, };
+
+/// Structure to hold info for a function that is currently being executed.
+typedef struct funccall_S funccall_T;
+
+struct funccall_S {
+ ufunc_T *func; ///< Function being called.
+ int linenr; ///< Next line to be executed.
+ int returned; ///< ":return" used.
+ /// Fixed variables for arguments.
+ TV_DICTITEM_STRUCT(VAR_SHORT_LEN + 1) fixvar[FIXVAR_CNT];
+ dict_T l_vars; ///< l: local function variables.
+ ScopeDictDictItem l_vars_var; ///< Variable for l: scope.
+ dict_T l_avars; ///< a: argument variables.
+ ScopeDictDictItem l_avars_var; ///< Variable for a: scope.
+ list_T l_varlist; ///< List for a:000.
+ listitem_T l_listitems[MAX_FUNC_ARGS]; ///< List items for a:000.
+ typval_T *rettv; ///< Return value.
+ linenr_T breakpoint; ///< Next line with breakpoint or zero.
+ int dbg_tick; ///< debug_tick when breakpoint was set.
+ int level; ///< Top nesting level of executed function.
+ proftime_T prof_child; ///< Time spent in a child.
+ funccall_T *caller; ///< Calling function or NULL; or next funccal in
+ ///< list pointed to by previous_funccal.
+ int fc_refcount; ///< Number of user functions that reference this funccall.
+ int fc_copyID; ///< CopyID used for garbage collection.
+ garray_T fc_funcs; ///< List of ufunc_T* which keep a reference to "func".
+};
+
+/// Structure to hold info for a user function.
+struct ufunc {
+ int uf_varargs; ///< variable nr of arguments
+ int uf_flags;
+ int uf_calls; ///< nr of active calls
+ bool uf_cleared; ///< func_clear() was already called
+ garray_T uf_args; ///< arguments
+ garray_T uf_def_args; ///< default argument expressions
+ garray_T uf_lines; ///< function lines
+ int uf_profiling; ///< true when func is being profiled
+ int uf_prof_initialized;
+ LuaRef uf_luaref; ///< lua callback, used if (uf_flags & FC_LUAREF)
+ // Profiling the function as a whole.
+ int uf_tm_count; ///< nr of calls
+ proftime_T uf_tm_total; ///< time spent in function + children
+ proftime_T uf_tm_self; ///< time spent in function itself
+ proftime_T uf_tm_children; ///< time spent in children this call
+ // Profiling the function per line.
+ int *uf_tml_count; ///< nr of times line was executed
+ proftime_T *uf_tml_total; ///< time spent in a line + children
+ proftime_T *uf_tml_self; ///< time spent in a line itself
+ proftime_T uf_tml_start; ///< start time for current line
+ proftime_T uf_tml_children; ///< time spent in children for this line
+ proftime_T uf_tml_wait; ///< start wait time for current line
+ int uf_tml_idx; ///< index of line being timed; -1 if none
+ int uf_tml_execed; ///< line being timed was executed
+ sctx_T uf_script_ctx; ///< SCTX where function was defined,
+ ///< used for s: variables
+ int uf_refcount; ///< reference count, see func_name_refcount()
+ funccall_T *uf_scoped; ///< l: local variables for closure
+ char *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with
+ ///< "<SNR>" as a string, otherwise NULL
+ char uf_name[]; ///< Name of function (actual size equals name);
+ ///< can start with <SNR>123_
+ ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
+};
+
+struct partial_S {
+ int pt_refcount; ///< Reference count.
+ char *pt_name; ///< Function name; when NULL use pt_func->name.
+ ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with pt_name.
+ bool pt_auto; ///< When true the partial was created by using dict.member
+ ///< in handle_subscript().
+ int pt_argc; ///< Number of arguments.
+ typval_T *pt_argv; ///< Arguments in allocated array.
+ dict_T *pt_dict; ///< Dict for "self".
+};
+
+/// Structure used for explicit stack while garbage collecting hash tables
+typedef struct ht_stack_S {
+ hashtab_T *ht;
+ struct ht_stack_S *prev;
+} ht_stack_T;
+
+/// Structure used for explicit stack while garbage collecting lists
+typedef struct list_stack_S {
+ list_T *list;
+ struct list_stack_S *prev;
+} list_stack_T;
+
+/// Structure representing one list item, used for sort array.
+typedef struct {
+ listitem_T *item; ///< Sorted list item.
+ int idx; ///< Sorted list item index.
+} ListSortItem;
+
+typedef int (*ListSorter)(const void *, const void *);
+
+#ifdef LOG_LIST_ACTIONS
+/// List actions log entry
+typedef struct {
+ uintptr_t l; ///< List log entry belongs to.
+ uintptr_t li1; ///< First list item log entry belongs to, if applicable.
+ uintptr_t li2; ///< Second list item log entry belongs to, if applicable.
+ int len; ///< List length when log entry was created.
+ const char *action; ///< Logged action.
+} ListLogEntry;
+
+typedef struct list_log ListLog;
+
+/// List actions log
+struct list_log {
+ ListLog *next; ///< Next chunk or NULL.
+ size_t capacity; ///< Number of entries in current chunk.
+ size_t size; ///< Current chunk size.
+ ListLogEntry entries[]; ///< Actual log entries.
+};
+#endif
+
+#endif // NVIM_EVAL_TYPVAL_DEFS_H
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 73b36b8611..6d29286a58 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -250,7 +250,7 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/func_attr.h"
-#include "nvim/lib/kvec.h"
+#include "klib/kvec.h"
// -V::1063
@@ -266,7 +266,7 @@ static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(
const MPConvStack *const mpstack, const int copyID,
const MPConvStackValType conv_type,
const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 3, 4, 7) REAL_FATTR_WARN_UNUSED_RESULT
+ REAL_FATTR_NONNULL_ARG(2, 3, 4, 7) REAL_FATTR_WARN_UNUSED_RESULT
REAL_FATTR_ALWAYS_INLINE;
/// Function for checking whether container references itself
@@ -301,7 +301,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv,
typval_T *const tv, const int copyID,
const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 4, 6) REAL_FATTR_WARN_UNUSED_RESULT;
+ REAL_FATTR_NONNULL_ARG(2, 4, 6) REAL_FATTR_WARN_UNUSED_RESULT;
/// Convert single value
///
@@ -339,7 +339,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
tv_blob_len(tv->vval.v_blob));
break;
case VAR_FUNC:
- TYPVAL_ENCODE_CONV_FUNC_START(tv, (char_u *)tv->vval.v_string);
+ TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string);
TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0);
TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1);
TYPVAL_ENCODE_CONV_FUNC_END(tv);
@@ -347,7 +347,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_PARTIAL: {
partial_T *const pt = tv->vval.v_partial;
(void)pt;
- TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : (char_u *)partial_name(pt))); // -V547
+ TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt))); // -V547
_mp_push(*mpstack, ((MPConvStackVal) { // -V779
.type = kMPConvPartial,
.tv = tv,
@@ -358,7 +358,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.pt = tv->vval.v_partial,
},
},
- }));
+ }));
break;
}
case VAR_LIST: {
@@ -381,7 +381,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(tv->vval.v_list),
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, _mp_last(*mpstack));
break;
}
@@ -459,8 +459,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const listitem_T *const highest_bits_li = (
TV_LIST_ITEM_NEXT(val_list, sign_li));
if (TV_LIST_ITEM_TV(highest_bits_li)->v_type != VAR_NUMBER
- || ((highest_bits
- = TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
+ || ((highest_bits = TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
< 0)) {
goto _convert_one_value_regular_dict;
}
@@ -536,7 +535,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(val_di->di_tv.vval.v_list),
},
},
- }));
+ }));
break;
}
case kMPMap: {
@@ -571,7 +570,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(val_list),
},
},
- }));
+ }));
break;
}
case kMPExt: {
@@ -581,8 +580,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|| tv_list_len((val_list = val_di->di_tv.vval.v_list)) != 2
|| (TV_LIST_ITEM_TV(tv_list_first(val_list))->v_type
!= VAR_NUMBER)
- || ((type
- = TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
+ || ((type = TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
> INT8_MAX)
|| type < INT8_MIN
|| (TV_LIST_ITEM_TV(tv_list_last(val_list))->v_type
@@ -622,7 +620,7 @@ _convert_one_value_regular_dict: {}
.todo = tv->vval.v_dict->dv_hashtab.ht_used,
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, tv->vval.v_dict,
_mp_last(*mpstack));
break;
@@ -640,7 +638,7 @@ typval_encode_stop_converting_one_item:
TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE(
TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME,
typval_T *const tv, const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 3) REAL_FATTR_WARN_UNUSED_RESULT;
+ REAL_FATTR_NONNULL_ARG(2, 3) REAL_FATTR_WARN_UNUSED_RESULT;
/// Convert the whole typval
///
@@ -758,7 +756,7 @@ typval_encode_stop_converting_one_item:
.todo = (size_t)pt->pt_argc,
},
},
- }));
+ }));
}
break;
case kMPConvPartialSelf: {
@@ -797,7 +795,7 @@ typval_encode_stop_converting_one_item:
.todo = dict->dv_hashtab.ht_used,
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(NULL, pt->pt_dict,
_mp_last(mpstack));
} else {
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
index ed70ba87ec..2f19144da3 100644
--- a/src/nvim/eval/typval_encode.h
+++ b/src/nvim/eval/typval_encode.h
@@ -10,9 +10,9 @@
#include <stddef.h>
#include <string.h>
+#include "klib/kvec.h"
#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
-#include "nvim/lib/kvec.h"
/// Type of the stack entry
typedef enum {
@@ -71,7 +71,7 @@ typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;
#define _mp_pop kv_pop
#define _mp_last kv_last
-static inline size_t tv_strlen(const typval_T *const tv)
+static inline size_t tv_strlen(const typval_T *tv)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT
REAL_FATTR_NONNULL_ALL;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index c46cb6ba5d..22c5b1954d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3,45 +3,52 @@
// User defined function support
+#include <assert.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lauxlib.h"
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
-#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline_defs.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/option_defs.h"
#include "nvim/os/input.h"
+#include "nvim/path.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/search.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
-// flags used in uf_flags
-#define FC_ABORT 0x01 // abort function on error
-#define FC_RANGE 0x02 // function accepts range
-#define FC_DICT 0x04 // Dict function, uses "self"
-#define FC_CLOSURE 0x08 // closure, uses outer scope variables
-#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
-#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
-#define FC_SANDBOX 0x40 // function defined in the sandbox
-#define FC_DEAD 0x80 // function kept only for reference to dfunc
-#define FC_EXPORT 0x100 // "export def Func()"
-#define FC_NOARGS 0x200 // no a: variables in lambda
-#define FC_VIM9 0x400 // defined in vim9 script file
-#define FC_CFUNC 0x800 // C function extension
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/userfunc.c.generated.h"
#endif
@@ -62,6 +69,8 @@ static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace
static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_nofunc = N_("E130: Unknown function: %s");
+static char e_no_white_space_allowed_before_str_str[]
+ = N_("E1068: No white space allowed before '%s': %s");
void func_init(void)
{
@@ -75,7 +84,7 @@ hashtab_T *func_tbl_get(void)
}
/// Get function arguments.
-static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int *varargs,
+static int get_function_args(char **argp, char endchar, garray_T *newargs, int *varargs,
garray_T *default_args, bool skip)
{
bool mustend = false;
@@ -85,10 +94,10 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
int i;
if (newargs != NULL) {
- ga_init(newargs, (int)sizeof(char_u *), 3);
+ ga_init(newargs, (int)sizeof(char *), 3);
}
if (default_args != NULL) {
- ga_init(default_args, (int)sizeof(char_u *), 3);
+ ga_init(default_args, (int)sizeof(char *), 3);
}
if (varargs != NULL) {
@@ -97,7 +106,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
// Isolate the arguments: "arg1, arg2, ...)"
bool any_default = false;
- while (*p != (char)endchar) {
+ while (*p != endchar) {
if (p[0] == '.' && p[1] == '.' && p[2] == '.') {
if (varargs != NULL) {
*varargs = true;
@@ -109,9 +118,9 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
while (ASCII_ISALNUM(*p) || *p == '_') {
p++;
}
- if (arg == p || isdigit(*arg)
- || (p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
- || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0)) {
+ if (arg == p || isdigit((uint8_t)(*arg))
+ || (p - arg == 9 && strncmp(arg, "firstline", 9) == 0)
+ || (p - arg == 8 && strncmp(arg, "lastline", 8) == 0)) {
if (!skip) {
semsg(_("E125: Illegal argument: %s"), arg);
}
@@ -125,7 +134,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
// Check for duplicate argument name.
for (i = 0; i < newargs->ga_len; i++) {
- if (STRCMP(((char **)(newargs->ga_data))[i], arg) == 0) {
+ if (strcmp(((char **)(newargs->ga_data))[i], arg) == 0) {
semsg(_("E853: Duplicate argument name: %s"), arg);
xfree(arg);
goto err_ret;
@@ -142,18 +151,18 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
any_default = true;
p = skipwhite(p) + 1;
p = skipwhite(p);
- char_u *expr = (char_u *)p;
+ char *expr = p;
if (eval1(&p, &rettv, false) != FAIL) {
ga_grow(default_args, 1);
// trim trailing whitespace
- while (p > (char *)expr && ascii_iswhite(p[-1])) {
+ while (p > expr && ascii_iswhite(p[-1])) {
p--;
}
c = (char_u)(*p);
*p = NUL;
- expr = vim_strsave(expr);
- ((char **)(default_args->ga_data))[default_args->ga_len] = (char *)expr;
+ expr = xstrdup(expr);
+ ((char **)(default_args->ga_data))[default_args->ga_len] = expr;
default_args->ga_len++;
*p = (char)c;
} else {
@@ -163,6 +172,15 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
emsg(_("E989: Non-default argument follows default argument"));
mustend = true;
}
+
+ if (ascii_iswhite(*p) && *skipwhite(p) == ',') {
+ // Be tolerant when skipping
+ if (!skip) {
+ semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
+ goto err_ret;
+ }
+ p = skipwhite(p);
+ }
if (*p == ',') {
p++;
} else {
@@ -170,14 +188,14 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
}
}
p = skipwhite(p);
- if (mustend && *p != (char)endchar) {
+ if (mustend && *p != endchar) {
if (!skip) {
semsg(_(e_invarg2), *argp);
}
break;
}
}
- if (*p != (char)endchar) {
+ if (*p != endchar) {
goto err_ret;
}
p++; // skip "endchar"
@@ -211,21 +229,21 @@ static void register_closure(ufunc_T *fp)
}
/// @return a name for a lambda. Returned in static memory.
-char_u *get_lambda_name(void)
+char *get_lambda_name(void)
{
- static char_u name[30];
+ static char name[30];
static int lambda_no = 0;
- snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
+ snprintf(name, sizeof(name), "<lambda>%d", ++lambda_no);
return name;
}
-static void set_ufunc_name(ufunc_T *fp, char_u *name)
+static void set_ufunc_name(ufunc_T *fp, char *name)
{
STRCPY(fp->uf_name, name);
- if (name[0] == K_SPECIAL) {
- fp->uf_name_exp = xmalloc(STRLEN(name) + 3);
+ if ((uint8_t)name[0] == K_SPECIAL) {
+ fp->uf_name_exp = xmalloc(strlen(name) + 3);
STRCPY(fp->uf_name_exp, "<SNR>");
STRCAT(fp->uf_name_exp, fp->uf_name + 3);
}
@@ -242,13 +260,13 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
partial_T *pt = NULL;
int varargs;
int ret;
- char_u *start = (char_u *)skipwhite(*arg + 1);
- char_u *s, *e;
+ char *start = skipwhite(*arg + 1);
+ char *s, *e;
bool *old_eval_lavars = eval_lavars_used;
bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
- ret = get_function_args((char **)&start, '-', NULL, NULL, NULL, true);
+ ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
if (ret == FAIL || *start != '>') {
return NOTDONE;
}
@@ -272,38 +290,39 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
// Get the start and the end of the expression.
*arg = skipwhite((*arg) + 1);
- s = (char_u *)(*arg);
+ s = *arg;
ret = skip_expr(arg);
if (ret == FAIL) {
goto errret;
}
- e = (char_u *)(*arg);
+ e = *arg;
*arg = skipwhite(*arg);
if (**arg != '}') {
+ semsg(_("E451: Expected }: %s"), *arg);
goto errret;
}
(*arg)++;
if (evaluate) {
int flags = 0;
- char_u *p;
+ char *p;
garray_T newlines;
- char_u *name = get_lambda_name();
+ char *name = get_lambda_name();
- fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1);
pt = xcalloc(1, sizeof(partial_T));
- ga_init(&newlines, (int)sizeof(char_u *), 1);
+ ga_init(&newlines, (int)sizeof(char *), 1);
ga_grow(&newlines, 1);
// Add "return " before the expression.
size_t len = (size_t)(7 + e - s + 1);
- p = (char_u *)xmalloc(len);
- ((char **)(newlines.ga_data))[newlines.ga_len++] = (char *)p;
+ p = xmalloc(len);
+ ((char **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
- STRLCPY(p + 7, s, e - s + 1);
- if (strstr((char *)p + 7, "a:") == NULL) {
+ xstrlcpy(p + 7, s, (size_t)(e - s) + 1);
+ if (strstr(p + 7, "a:") == NULL) {
// No a: variables are used for sure.
flags |= FC_NOARGS;
}
@@ -312,7 +331,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
set_ufunc_name(fp, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
- ga_init(&fp->uf_def_args, (int)sizeof(char_u *), 1);
+ ga_init(&fp->uf_def_args, (int)sizeof(char *), 1);
fp->uf_lines = newlines;
if (current_funccal != NULL && eval_lavars) {
flags |= FC_CLOSURE;
@@ -365,7 +384,7 @@ errret:
/// was not found.
///
/// @return name of the function.
-char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
+char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
if (partialp != NULL) {
@@ -376,10 +395,10 @@ char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp,
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
if (v->di_tv.vval.v_string == NULL) { // just in case
*lenp = 0;
- return (char_u *)"";
+ return "";
}
- *lenp = (int)STRLEN(v->di_tv.vval.v_string);
- return (char_u *)v->di_tv.vval.v_string;
+ *lenp = (int)strlen(v->di_tv.vval.v_string);
+ return v->di_tv.vval.v_string;
}
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) {
@@ -387,31 +406,31 @@ char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp,
if (pt == NULL) { // just in case
*lenp = 0;
- return (char_u *)"";
+ return "";
}
if (partialp != NULL) {
*partialp = pt;
}
- char_u *s = (char_u *)partial_name(pt);
- *lenp = (int)STRLEN(s);
+ char *s = partial_name(pt);
+ *lenp = (int)strlen(s);
return s;
}
- return (char_u *)name;
+ return (char *)name;
}
/// Give an error message with a function name. Handle <SNR> things.
///
/// @param ermsg must be passed without translation (use N_() instead of _()).
/// @param name function name
-void emsg_funcname(char *ermsg, const char_u *name)
+void emsg_funcname(char *ermsg, const char *name)
{
- char_u *p;
+ char *p;
- if (*name == K_SPECIAL) {
- p = concat_str((char_u *)"<SNR>", name + 3);
+ if ((uint8_t)(*name) == K_SPECIAL) {
+ p = concat_str("<SNR>", name + 3);
} else {
- p = (char_u *)name;
+ p = (char *)name;
}
semsg(_(ermsg), p);
@@ -429,7 +448,7 @@ void emsg_funcname(char *ermsg, const char_u *name)
/// @param funcexe various values
///
/// @return OK or FAIL.
-int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe)
+int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe)
{
char *argp;
int ret = OK;
@@ -439,12 +458,12 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
// Get the arguments.
argp = *arg;
while (argcount < MAX_FUNC_ARGS
- - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) {
+ - (funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc)) {
argp = skipwhite(argp + 1); // skip the '(' or ','
if (*argp == ')' || *argp == ',' || *argp == NUL) {
break;
}
- if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) {
+ if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) {
ret = FAIL;
break;
}
@@ -463,7 +482,7 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
int i = 0;
if (get_vim_var_nr(VV_TESTING)) {
- // Prepare for calling garbagecollect_for_testing(), need to know
+ // Prepare for calling test_garbagecollect_now(), need to know
// what variables are used on the call stack.
if (funcargs.ga_itemsize == 0) {
ga_init(&funcargs, (int)sizeof(typval_T *), 50);
@@ -473,7 +492,7 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = &argvars[i];
}
}
- ret = call_func((char *)name, len, rettv, argcount, argvars, funcexe);
+ ret = call_func(name, len, rettv, argcount, argvars, funcexe);
funcargs.ga_len -= i;
} else if (!aborting()) {
@@ -525,48 +544,47 @@ static inline bool eval_fname_sid(const char *const name)
///
/// @return transformed name: either `fname_buf` or a pointer to an allocated
/// memory.
-static char_u *fname_trans_sid(const char_u *const name, char_u *const fname_buf,
- char_u **const tofree, int *const error)
+static char *fname_trans_sid(const char *const name, char *const fname_buf, char **const tofree,
+ int *const error)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- char_u *fname;
- const int llen = eval_fname_script((const char *)name);
- if (llen > 0) {
- fname_buf[0] = K_SPECIAL;
- fname_buf[1] = KS_EXTRA;
- fname_buf[2] = KE_SNR;
- int i = 3;
- if (eval_fname_sid((const char *)name)) { // "<SID>" or "s:"
- if (current_sctx.sc_sid <= 0) {
- *error = ERROR_SCRIPT;
- } else {
- snprintf((char *)fname_buf + i, (size_t)(FLEN_FIXED + 1 - i), "%" PRId64 "_",
- (int64_t)current_sctx.sc_sid);
- i = (int)STRLEN(fname_buf);
- }
- }
- if ((size_t)i + STRLEN(name + llen) < FLEN_FIXED) {
- STRCPY(fname_buf + i, name + llen);
- fname = fname_buf;
+ const int llen = eval_fname_script(name);
+ if (llen == 0) {
+ return (char *)name; // no prefix
+ }
+
+ fname_buf[0] = (char)K_SPECIAL;
+ fname_buf[1] = (char)KS_EXTRA;
+ fname_buf[2] = KE_SNR;
+ int i = 3;
+ if (eval_fname_sid(name)) { // "<SID>" or "s:"
+ if (current_sctx.sc_sid <= 0) {
+ *error = FCERR_SCRIPT;
} else {
- fname = xmalloc((size_t)i + STRLEN(name + llen) + 1);
- *tofree = fname;
- memmove(fname, fname_buf, (size_t)i);
- STRCPY(fname + i, name + llen);
+ snprintf(fname_buf + i, (size_t)(FLEN_FIXED + 1 - i), "%" PRId64 "_",
+ (int64_t)current_sctx.sc_sid);
+ i = (int)strlen(fname_buf);
}
+ }
+ char *fname;
+ if ((size_t)i + strlen(name + llen) < FLEN_FIXED) {
+ STRCPY(fname_buf + i, name + llen);
+ fname = fname_buf;
} else {
- fname = (char_u *)name;
+ fname = xmalloc((size_t)i + strlen(name + llen) + 1);
+ *tofree = fname;
+ memmove(fname, fname_buf, (size_t)i);
+ STRCPY(fname + i, name + llen);
}
-
return fname;
}
/// Find a function by name, return pointer to it in ufuncs.
///
/// @return NULL for unknown function.
-ufunc_T *find_func(const char_u *name)
+ufunc_T *find_func(const char *name)
{
- hashitem_T *hi = hash_find(&func_hashtab, (char *)name);
+ hashitem_T *hi = hash_find(&func_hashtab, name);
if (!HASHITEM_EMPTY(hi)) {
return HI2UF(hi);
}
@@ -576,9 +594,9 @@ ufunc_T *find_func(const char_u *name)
/// Copy the function name of "fp" to buffer "buf".
/// "buf" must be able to hold the function name plus three bytes.
/// Takes care of script-local function names.
-static void cat_func_name(char_u *buf, ufunc_T *fp)
+static void cat_func_name(char *buf, ufunc_T *fp)
{
- if (fp->uf_name[0] == K_SPECIAL) {
+ if ((uint8_t)fp->uf_name[0] == K_SPECIAL) {
STRCPY(buf, "<SNR>");
STRCAT(buf, fp->uf_name + 3);
} else {
@@ -593,7 +611,7 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr)
STRCPY(v->di_key, name);
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(dp, v);
+ hash_add(&dp->dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_NUMBER;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_number = nr;
@@ -758,9 +776,9 @@ static void func_clear_items(ufunc_T *fp)
ga_clear_strings(&(fp->uf_lines));
XFREE_CLEAR(fp->uf_name_exp);
- if (fp->uf_cb_free != NULL) {
- fp->uf_cb_free(fp->uf_cb_state);
- fp->uf_cb_free = NULL;
+ if (fp->uf_flags & FC_LUAREF) {
+ api_free_luaref(fp->uf_luaref);
+ fp->uf_luaref = LUA_NOREF;
}
XFREE_CLEAR(fp->uf_tml_count);
@@ -828,7 +846,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
int fixvar_idx = 0; // index in fixvar[]
int ai;
bool islambda = false;
- char_u numbuf[NUMBUFLEN];
+ char numbuf[NUMBUFLEN];
char *name;
typval_T *tv_to_free[MAX_FUNC_ARGS];
int tv_to_free_len = 0;
@@ -852,7 +870,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
saveRedobuff(&save_redo);
did_save_redo = true;
}
- ++fp->uf_calls;
+ fp->uf_calls++;
// check for CTRL-C hit
line_breakcheck();
// prepare the funccall_T structure
@@ -863,14 +881,14 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
fc->rettv = rettv;
fc->level = ex_nesting_level;
// Check if this function has a breakpoint.
- fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0);
+ fc->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, (linenr_T)0);
fc->dbg_tick = debug_tick;
// Set up fields for closure.
ga_init(&fc->fc_funcs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
- if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0) {
+ if (strncmp(fp->uf_name, "<lambda>", 8) == 0) {
islambda = true;
}
@@ -889,11 +907,11 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
STRCPY(name, "self");
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_vars, v);
+ hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_DICT;
v->di_tv.v_lock = VAR_UNLOCKED;
v->di_tv.vval.v_dict = selfdict;
- ++selfdict->dv_refcount;
+ selfdict->dv_refcount++;
}
// Init a: variables, unless none found (in lambda).
@@ -915,7 +933,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
STRCPY(name, "000");
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_avars, v);
+ hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_LIST;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_list = &fc->l_varlist;
@@ -967,14 +985,14 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
break;
}
// "..." argument a:1, a:2, etc.
- snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1);
- name = (char *)numbuf;
+ snprintf(numbuf, sizeof(numbuf), "%d", ai + 1);
+ name = numbuf;
}
- if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) {
+ if (fixvar_idx < FIXVAR_CNT && strlen(name) <= VAR_SHORT_LEN) {
v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
} else {
- v = xmalloc(sizeof(dictitem_T) + STRLEN(name));
+ v = xmalloc(sizeof(dictitem_T) + strlen(name));
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC;
}
STRCPY(v->di_key, name);
@@ -993,16 +1011,16 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
// Named arguments can be accessed without the "a:" prefix in lambda
// expressions. Add to the l: dict.
tv_copy(&v->di_tv, &v->di_tv);
- tv_dict_add(&fc->l_vars, v);
+ hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key);
} else {
- tv_dict_add(&fc->l_avars, v);
+ hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key);
}
if (ai >= 0 && ai < MAX_FUNC_ARGS) {
listitem_T *li = &fc->l_listitems[ai];
*TV_LIST_ITEM_TV(li) = argvars[i];
- TV_LIST_ITEM_TV(li)->v_lock = VAR_FIXED;
+ TV_LIST_ITEM_TV(li)->v_lock = VAR_FIXED;
tv_list_append(&fc->l_varlist, li);
}
}
@@ -1058,7 +1076,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
bool func_not_yet_profiling_but_should =
do_profiling_yes
- && !fp->uf_profiling && has_profiling(false, fp->uf_name, NULL);
+ && !fp->uf_profiling && has_profiling(false, (char *)fp->uf_name, NULL);
if (func_not_yet_profiling_but_should) {
started_profiling = true;
@@ -1071,7 +1089,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
|| (fc->caller != NULL && fc->caller->func->uf_profiling));
if (func_or_func_caller_profiling) {
- ++fp->uf_tm_count;
+ fp->uf_tm_count++;
call_start = profile_start();
fp->uf_tm_children = profile_zero();
}
@@ -1083,7 +1101,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
const sctx_T save_current_sctx = current_sctx;
current_sctx = fp->uf_script_ctx;
save_did_emsg = did_emsg;
- did_emsg = FALSE;
+ did_emsg = false;
if (default_arg_err && (fp->uf_flags & FC_ABORT)) {
did_emsg = true;
@@ -1208,9 +1226,37 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
/// For the first we only count the name stored in func_hashtab as a reference,
/// using function() does not count as a reference, because the function is
/// looked up by name.
-static bool func_name_refcount(char_u *name)
+static bool func_name_refcount(const char *name)
+{
+ return isdigit((uint8_t)(*name)) || *name == '<';
+}
+
+/// Call a user function after checking the arguments.
+static int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv,
+ funcexe_T *funcexe, dict_T *selfdict)
+ FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5)
{
- return isdigit(*name) || *name == '<';
+ if (fp->uf_flags & FC_LUAREF) {
+ return typval_exec_lua_callable(fp->uf_luaref, argcount, argvars, rettv);
+ }
+
+ if ((fp->uf_flags & FC_RANGE) && funcexe->fe_doesrange != NULL) {
+ *funcexe->fe_doesrange = true;
+ }
+ int error;
+ if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
+ error = FCERR_TOOFEW;
+ } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) {
+ error = FCERR_TOOMANY;
+ } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) {
+ error = FCERR_DICT;
+ } else {
+ // Call the user function.
+ call_user_func(fp, argcount, argvars, rettv, funcexe->fe_firstline, funcexe->fe_lastline,
+ (fp->uf_flags & FC_DICT) ? selfdict : NULL);
+ error = FCERR_NONE;
+ }
+ return error;
}
static funccal_entry_T *funccal_stack = NULL;
@@ -1252,7 +1298,7 @@ void free_all_functions(void)
ufunc_T *fp;
uint64_t skipped = 0;
uint64_t todo = 1;
- uint64_t used;
+ int changed;
// Clean up the current_funccal chain and the funccal stack.
while (current_funccal != NULL) {
@@ -1276,9 +1322,9 @@ void free_all_functions(void)
if (func_name_refcount(fp->uf_name)) {
skipped++;
} else {
- used = func_hashtab.ht_used;
+ changed = func_hashtab.ht_changed;
func_clear(fp, true);
- if (used != func_hashtab.ht_used) {
+ if (changed != func_hashtab.ht_changed) {
skipped = 0;
break;
}
@@ -1322,10 +1368,10 @@ void free_all_functions(void)
/// @param[in] len length of "name", or -1 for NUL terminated.
///
/// @return true if "name" looks like a builtin function name: starts with a
-/// lower case letter and doesn't contain AUTOLOAD_CHAR.
+/// lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
static bool builtin_function(const char *name, int len)
{
- if (!ASCII_ISLOWER(name[0])) {
+ if (!ASCII_ISLOWER(name[0]) || name[1] == ':') {
return false;
}
@@ -1336,7 +1382,7 @@ static bool builtin_function(const char *name, int len)
return p == NULL;
}
-int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
+int func_call(char *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
{
typval_T argv[MAX_FUNC_ARGS + 1];
int argc = 0;
@@ -1353,12 +1399,12 @@ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict
});
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
- funcexe.partial = partial;
- funcexe.selfdict = selfdict;
- r = call_func((char *)name, -1, rettv, argc, argv, &funcexe);
+ funcexe.fe_firstline = curwin->w_cursor.lnum;
+ funcexe.fe_lastline = curwin->w_cursor.lnum;
+ funcexe.fe_evaluate = true;
+ funcexe.fe_partial = partial;
+ funcexe.fe_selfdict = selfdict;
+ r = call_func(name, -1, rettv, argc, argv, &funcexe);
func_call_skip_call:
// Free the arguments.
@@ -1369,35 +1415,50 @@ func_call_skip_call:
return r;
}
+/// call the 'callback' function and return the result as a number.
+/// Returns -2 when calling the function fails. Uses argv[0] to argv[argc - 1]
+/// for the function arguments. argv[argc] should have type VAR_UNKNOWN.
+///
+/// @param argcount number of "argvars"
+/// @param argvars vars for arguments, must have "argcount" PLUS ONE elements!
+varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argvars)
+{
+ typval_T rettv;
+ if (!callback_call(callback, argcount, argvars, &rettv)) {
+ return -2;
+ }
+
+ varnumber_T retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
+ return retval;
+}
+
/// Give an error message for the result of a function.
/// Nothing if "error" is FCERR_NONE.
-static void user_func_error(int error, const char_u *name)
+static void user_func_error(int error, const char *name)
FUNC_ATTR_NONNULL_ALL
{
switch (error) {
- case ERROR_UNKNOWN:
+ case FCERR_UNKNOWN:
emsg_funcname(N_("E117: Unknown function: %s"), name);
break;
- case ERROR_NOTMETHOD:
+ case FCERR_NOTMETHOD:
emsg_funcname(N_("E276: Cannot use function as a method: %s"), name);
break;
- case ERROR_DELETED:
+ case FCERR_DELETED:
emsg_funcname(N_("E933: Function was deleted: %s"), name);
break;
- case ERROR_TOOMANY:
+ case FCERR_TOOMANY:
emsg_funcname(_(e_toomanyarg), name);
break;
- case ERROR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"),
- name);
+ case FCERR_TOOFEW:
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"), name);
break;
- case ERROR_SCRIPT:
- emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
- name);
+ case FCERR_SCRIPT:
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), name);
break;
- case ERROR_DICT:
- emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
- name);
+ case FCERR_DICT:
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name);
break;
}
}
@@ -1435,27 +1496,27 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
{
int ret = FAIL;
- int error = ERROR_NONE;
+ int error = FCERR_NONE;
ufunc_T *fp = NULL;
- char_u fname_buf[FLEN_FIXED + 1];
- char_u *tofree = NULL;
- char_u *fname = NULL;
- char_u *name = NULL;
+ char fname_buf[FLEN_FIXED + 1];
+ char *tofree = NULL;
+ char *fname = NULL;
+ char *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
- dict_T *selfdict = funcexe->selfdict;
+ dict_T *selfdict = funcexe->fe_selfdict;
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
- // "funcexe->basetv" is not NULL
+ // "funcexe->fe_basetv" is not NULL
int argv_clear = 0;
int argv_base = 0;
- partial_T *partial = funcexe->partial;
+ partial_T *partial = funcexe->fe_partial;
// Initialize rettv so that it is safe for caller to invoke clear_tv(rettv)
// even when call_func() returns FAIL.
rettv->v_type = VAR_UNKNOWN;
if (len <= 0) {
- len = (int)STRLEN(funcname);
+ len = (int)strlen(funcname);
}
if (partial != NULL) {
fp = partial->pt_func;
@@ -1463,12 +1524,12 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
if (fp == NULL) {
// Make a copy of the name, if it comes from a funcref variable it could
// be changed or deleted in the called function.
- name = vim_strnsave((char_u *)funcname, (size_t)len);
+ name = xstrnsave(funcname, (size_t)len);
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
}
- if (funcexe->doesrange != NULL) {
- *funcexe->doesrange = false;
+ if (funcexe->fe_doesrange != NULL) {
+ *funcexe->fe_doesrange = false;
}
if (partial != NULL) {
@@ -1478,10 +1539,10 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto)) {
selfdict = partial->pt_dict;
}
- if (error == ERROR_NONE && partial->pt_argc > 0) {
+ if (error == FCERR_NONE && partial->pt_argc > 0) {
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
if (argv_clear + argcount_in >= MAX_FUNC_ARGS) {
- error = ERROR_TOOMANY;
+ error = FCERR_TOOMANY;
goto theend;
}
tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]);
@@ -1494,8 +1555,8 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
}
}
- if (error == ERROR_NONE && funcexe->evaluate) {
- char_u *rfname = fname;
+ if (error == FCERR_NONE && funcexe->fe_evaluate) {
+ char *rfname = fname;
// Ignore "g:" before a function name.
if (fp == NULL && fname[0] == 'g' && fname[1] == ':') {
@@ -1504,12 +1565,12 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
rettv->v_type = VAR_NUMBER; // default rettv is number zero
rettv->vval.v_number = 0;
- error = ERROR_UNKNOWN;
+ error = FCERR_UNKNOWN;
if (is_luafunc(partial)) {
if (len > 0) {
- error = ERROR_NONE;
- argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
+ error = FCERR_NONE;
+ argv_add_base(funcexe->fe_basetv, &argvars, &argcount, argv, &argv_base);
nlua_typval_call(funcname, (size_t)len, argvars, argcount, rettv);
} else {
// v:lua was called directly; show its name in the emsg
@@ -1524,71 +1585,50 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
// Trigger FuncUndefined event, may load the function.
if (fp == NULL
- && apply_autocmds(EVENT_FUNCUNDEFINED, (char *)rfname, (char *)rfname, true, NULL)
+ && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL)
&& !aborting()) {
// executed an autocommand, search for the function again
fp = find_func(rfname);
}
// Try loading a package.
- if (fp == NULL && script_autoload((const char *)rfname, STRLEN(rfname),
+ if (fp == NULL && script_autoload((const char *)rfname, strlen(rfname),
true) && !aborting()) {
// Loaded a package, search for the function again.
fp = find_func(rfname);
}
if (fp != NULL && (fp->uf_flags & FC_DELETED)) {
- error = ERROR_DELETED;
- } else if (fp != NULL && (fp->uf_flags & FC_CFUNC)) {
- cfunc_T cb = fp->uf_cb;
- error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state);
+ error = FCERR_DELETED;
} else if (fp != NULL) {
- if (funcexe->argv_func != NULL) {
+ if (funcexe->fe_argv_func != NULL) {
// postponed filling in the arguments, do it now
- argcount = funcexe->argv_func(argcount, argvars, argv_clear,
- fp->uf_args.ga_len);
+ argcount = funcexe->fe_argv_func(argcount, argvars, argv_clear, fp);
}
- argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
+ argv_add_base(funcexe->fe_basetv, &argvars, &argcount, argv, &argv_base);
- if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) {
- *funcexe->doesrange = true;
- }
- if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
- error = ERROR_TOOFEW;
- } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) {
- error = ERROR_TOOMANY;
- } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) {
- error = ERROR_DICT;
- } else {
- // Call the user function.
- call_user_func(fp, argcount, argvars, rettv, funcexe->firstline,
- funcexe->lastline,
- (fp->uf_flags & FC_DICT) ? selfdict : NULL);
- error = ERROR_NONE;
- }
+ error = call_user_func_check(fp, argcount, argvars, rettv, funcexe, selfdict);
}
- } else if (funcexe->basetv != NULL) {
+ } else if (funcexe->fe_basetv != NULL) {
// expr->method(): Find the method name in the table, call its
// implementation with the base as one of the arguments.
error = call_internal_method(fname, argcount, argvars, rettv,
- funcexe->basetv);
+ funcexe->fe_basetv);
} else {
// Find the function name in the table, call its implementation.
error = call_internal_func(fname, argcount, argvars, rettv);
}
- /*
- * The function call (or "FuncUndefined" autocommand sequence) might
- * have been aborted by an error, an interrupt, or an explicitly thrown
- * exception that has not been caught so far. This situation can be
- * tested for by calling aborting(). For an error in an internal
- * function or for the "E132" error in call_user_func(), however, the
- * throw point at which the "force_abort" flag (temporarily reset by
- * emsg()) is normally updated has not been reached yet. We need to
- * update that flag first to make aborting() reliable.
- */
+ // The function call (or "FuncUndefined" autocommand sequence) might
+ // have been aborted by an error, an interrupt, or an explicitly thrown
+ // exception that has not been caught so far. This situation can be
+ // tested for by calling aborting(). For an error in an internal
+ // function or for the "E132" error in call_user_func(), however, the
+ // throw point at which the "force_abort" flag (temporarily reset by
+ // emsg()) is normally updated has not been reached yet. We need to
+ // update that flag first to make aborting() reliable.
update_force_abort();
}
- if (error == ERROR_NONE) {
+ if (error == FCERR_NONE) {
ret = OK;
}
@@ -1596,7 +1636,7 @@ theend:
// Report an error unless the argument evaluation or function call has been
// cancelled due to an aborting error, an interrupt, or an exception.
if (!aborting()) {
- user_func_error(error, (name != NULL) ? name : (char_u *)funcname);
+ user_func_error(error, (name != NULL) ? name : funcname);
}
// clear the copies made from the partial
@@ -1610,6 +1650,11 @@ theend:
return ret;
}
+char *printable_func_name(ufunc_T *fp)
+{
+ return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
+}
+
/// List the head of the function: "name(arg1, arg2)".
///
/// @param[in] fp Function pointer.
@@ -1679,12 +1724,12 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
/// @param partial return: partial of a FuncRef
///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial)
+char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial)
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *name = NULL;
- const char_u *start;
- const char_u *end;
+ char *name = NULL;
+ const char *start;
+ const char *end;
int lead;
int len;
lval_T lv;
@@ -1692,7 +1737,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
if (fdp != NULL) {
CLEAR_POINTER(fdp);
}
- start = (char_u *)(*pp);
+ start = *pp;
// Check for hard coded <SNR>: already translated function ID (from a user
// command).
@@ -1700,19 +1745,19 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
&& (*pp)[2] == KE_SNR) {
*pp += 3;
len = get_id_len((const char **)pp) + 3;
- return (char_u *)xmemdupz(start, (size_t)len);
+ return xmemdupz(start, (size_t)len);
}
// A name starting with "<SID>" or "<SNR>" is local to a script. But
// don't skip over "s:", get_lval() needs it for "s:dict.func".
- lead = eval_fname_script((const char *)start);
+ lead = eval_fname_script(start);
if (lead > 2) {
start += lead;
}
// Note that TFN_ flags use the same values as GLV_ flags.
- end = (char_u *)get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
- lead > 2 ? 0 : FNE_CHECK_START);
+ end = get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
+ lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
if (!skip) {
emsg(_("E129: Function name required"));
@@ -1720,11 +1765,9 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
goto theend;
}
if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range))) {
- /*
- * Report an invalid expression in braces, unless the expression
- * evaluation has been cancelled due to an aborting error, an
- * interrupt, or an exception.
- */
+ // Report an invalid expression in braces, unless the expression
+ // evaluation has been cancelled due to an aborting error, an
+ // interrupt, or an exception.
if (!aborting()) {
if (end != NULL) {
semsg(_(e_invarg2), start);
@@ -1738,17 +1781,17 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
if (lv.ll_tv != NULL) {
if (fdp != NULL) {
fdp->fd_dict = lv.ll_dict;
- fdp->fd_newkey = (char_u *)lv.ll_newkey;
+ fdp->fd_newkey = lv.ll_newkey;
lv.ll_newkey = NULL;
fdp->fd_di = lv.ll_di;
}
if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL) {
- name = vim_strsave((char_u *)lv.ll_tv->vval.v_string);
+ name = xstrdup(lv.ll_tv->vval.v_string);
*pp = (char *)end;
} else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL) {
if (is_luafunc(lv.ll_tv->vval.v_partial) && *end == '.') {
- len = check_luafunc_name((const char *)end + 1, true);
+ len = check_luafunc_name(end + 1, true);
if (len == 0) {
semsg(e_invexpr2, "v:lua");
goto theend;
@@ -1757,7 +1800,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
memcpy(name, end + 1, (size_t)len);
*pp = (char *)end + 1 + len;
} else {
- name = vim_strsave((char_u *)partial_name(lv.ll_tv->vval.v_partial));
+ name = xstrdup(partial_name(lv.ll_tv->vval.v_partial));
*pp = (char *)end;
}
if (partial != NULL) {
@@ -1791,22 +1834,21 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
name = NULL;
}
} else if (!(flags & TFN_NO_DEREF)) {
- len = (int)(end - (char_u *)(*pp));
- name = deref_func_name((const char *)(*pp), &len, partial,
- flags & TFN_NO_AUTOLOAD);
- if (name == (char_u *)(*pp)) {
+ len = (int)(end - *pp);
+ name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
+ if (name == *pp) {
name = NULL;
}
}
if (name != NULL) {
- name = vim_strsave(name);
+ name = xstrdup(name);
*pp = (char *)end;
- if (STRNCMP(name, "<SNR>", 5) == 0) {
+ if (strncmp(name, "<SNR>", 5) == 0) {
// Change "<SNR>" to the byte sequence.
- name[0] = K_SPECIAL;
- name[1] = KS_EXTRA;
+ name[0] = (char)K_SPECIAL;
+ name[1] = (char)KS_EXTRA;
name[2] = KE_SNR;
- memmove(name + 3, name + 5, strlen((char *)name + 5) + 1);
+ memmove(name + 3, name + 5, strlen(name + 5) + 1);
}
goto theend;
}
@@ -1828,7 +1870,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
lv.ll_name += 2;
lv.ll_name_len -= 2;
}
- len = (int)((const char *)end - lv.ll_name);
+ len = (int)(end - lv.ll_name);
}
size_t sid_buf_len = 0;
@@ -1859,7 +1901,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
}
if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF)) {
- char_u *cp = xmemrchr(lv.ll_name, ':', lv.ll_name_len);
+ char *cp = xmemrchr(lv.ll_name, ':', lv.ll_name_len);
if (cp != NULL && cp < end) {
semsg(_("E884: Function name cannot contain a colon: %s"), start);
@@ -1869,8 +1911,8 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
name = xmalloc((size_t)len + (size_t)lead + 1);
if (!skip && lead > 0) {
- name[0] = K_SPECIAL;
- name[1] = KS_EXTRA;
+ name[0] = (char)K_SPECIAL;
+ name[1] = (char)KS_EXTRA;
name[2] = KE_SNR;
if (sid_buf_len > 0) { // If it's "<SID>"
memcpy(name + 3, sid_buf, sid_buf_len);
@@ -1885,18 +1927,105 @@ theend:
return name;
}
+/// If the "funcname" starts with "s:" or "<SID>", then expands it to the
+/// current script ID and returns the expanded function name. The caller should
+/// free the returned name. If not called from a script context or the function
+/// name doesn't start with these prefixes, then returns NULL.
+/// This doesn't check whether the script-local function exists or not.
+char *get_scriptlocal_funcname(char *funcname)
+{
+ if (funcname == NULL) {
+ return NULL;
+ }
+
+ if (strncmp(funcname, "s:", 2) != 0
+ && strncmp(funcname, "<SID>", 5) != 0) {
+ // The function name is not a script-local function name
+ return NULL;
+ }
+
+ if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) {
+ emsg(_(e_usingsid));
+ return NULL;
+ }
+
+ char sid_buf[25];
+ // Expand s: and <SID> prefix into <SNR>nr_<name>
+ snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
+ (int64_t)current_sctx.sc_sid);
+ const int off = *funcname == 's' ? 2 : 5;
+ char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1);
+ STRCPY(newname, sid_buf);
+ STRCAT(newname, funcname + off);
+
+ return newname;
+}
+
+/// Call trans_function_name(), except that a lambda is returned as-is.
+/// Returns the name in allocated memory.
+char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
+{
+ char *p = *name;
+ char *saved;
+
+ if (strncmp(p, "<lambda>", 8) == 0) {
+ p += 8;
+ (void)getdigits(&p, false, 0);
+ saved = xstrndup(*name, (size_t)(p - *name));
+ if (fudi != NULL) {
+ CLEAR_POINTER(fudi);
+ }
+ } else {
+ saved = trans_function_name(&p, skip, flags, fudi, NULL);
+ }
+ *name = p;
+ return saved;
+}
+
+#define MAX_FUNC_NESTING 50
+
+/// List functions.
+///
+/// @param regmatch When NULL, all of them.
+/// Otherwise functions matching "regmatch".
+static void list_functions(regmatch_T *regmatch)
+{
+ const int changed = func_hashtab.ht_changed;
+ size_t todo = func_hashtab.ht_used;
+ const hashitem_T *const ht_array = func_hashtab.ht_array;
+
+ for (const hashitem_T *hi = ht_array; todo > 0 && !got_int; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ ufunc_T *fp = HI2UF(hi);
+ todo--;
+ if ((fp->uf_flags & FC_DEAD) == 0
+ && (regmatch == NULL
+ ? (!message_filtered((char *)fp->uf_name)
+ && !func_name_refcount(fp->uf_name))
+ : (!isdigit((uint8_t)(*fp->uf_name))
+ && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) {
+ list_func_head(fp, false, false);
+ if (changed != func_hashtab.ht_changed) {
+ emsg(_("E454: function list was modified"));
+ return;
+ }
+ }
+ }
+ }
+}
+
/// ":function"
void ex_function(exarg_T *eap)
{
- char_u *theline;
- char_u *line_to_free = NULL;
- char_u c;
+ char *theline;
+ char *line_to_free = NULL;
+ char c;
int saved_did_emsg;
bool saved_wait_return = need_wait_return;
- char_u *name = NULL;
- char_u *p;
- char_u *arg;
- char_u *line_arg = NULL;
+ char *name = NULL;
+ char *p;
+ char *arg;
+ char *line_arg = NULL;
garray_T newargs;
garray_T default_args;
garray_T newlines;
@@ -1911,44 +2040,27 @@ void ex_function(exarg_T *eap)
static int func_nr = 0; // number for nameless function
int paren;
hashtab_T *ht;
- int todo;
hashitem_T *hi;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
bool is_heredoc = false;
- char_u *skip_until = NULL;
- char_u *heredoc_trimmed = NULL;
+ char *skip_until = NULL;
+ char *heredoc_trimmed = NULL;
bool show_block = false;
bool do_concat = true;
- /*
- * ":function" without argument: list functions.
- */
+ // ":function" without argument: list functions.
if (ends_excmd(*eap->arg)) {
if (!eap->skip) {
- todo = (int)func_hashtab.ht_used;
- for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- fp = HI2UF(hi);
- if (message_filtered(fp->uf_name)) {
- continue;
- }
- if (!func_name_refcount(fp->uf_name)) {
- list_func_head(fp, false, false);
- }
- }
- }
+ list_functions(NULL);
}
- eap->nextcmd = (char *)check_nextcmd((char_u *)eap->arg);
+ eap->nextcmd = check_nextcmd(eap->arg);
return;
}
- /*
- * ":function /pat": list functions matching pattern.
- */
+ // ":function /pat": list functions matching pattern.
if (*eap->arg == '/') {
- p = skip_regexp((char_u *)eap->arg + 1, '/', true, NULL);
+ p = skip_regexp(eap->arg + 1, '/', true);
if (!eap->skip) {
regmatch_T regmatch;
@@ -1958,25 +2070,14 @@ void ex_function(exarg_T *eap)
*p = c;
if (regmatch.regprog != NULL) {
regmatch.rm_ic = p_ic;
-
- todo = (int)func_hashtab.ht_used;
- for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- fp = HI2UF(hi);
- if (!isdigit(*fp->uf_name)
- && vim_regexec(&regmatch, (char *)fp->uf_name, 0)) {
- list_func_head(fp, false, false);
- }
- }
- }
+ list_functions(&regmatch);
vim_regfree(regmatch.regprog);
}
}
if (*p == '/') {
p++;
}
- eap->nextcmd = (char *)check_nextcmd(p);
+ eap->nextcmd = check_nextcmd(p);
return;
}
@@ -1994,30 +2095,27 @@ void ex_function(exarg_T *eap)
// "fudi.fd_di" set, "fudi.fd_newkey" == NULL
// s:func script-local function name
// g:func global function name, same as "func"
- p = (char_u *)eap->arg;
- name = trans_function_name((char **)&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL);
- paren = (vim_strchr((char *)p, '(') != NULL);
+ p = eap->arg;
+ name = save_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi);
+ paren = (vim_strchr(p, '(') != NULL);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) {
- /*
- * Return on an invalid expression in braces, unless the expression
- * evaluation has been cancelled due to an aborting error, an
- * interrupt, or an exception.
- */
+ // Return on an invalid expression in braces, unless the expression
+ // evaluation has been cancelled due to an aborting error, an
+ // interrupt, or an exception.
if (!aborting()) {
if (fudi.fd_newkey != NULL) {
semsg(_(e_dictkey), fudi.fd_newkey);
}
xfree(fudi.fd_newkey);
return;
- } else {
- eap->skip = TRUE;
}
+ eap->skip = true;
}
// An error in a function call during evaluation of an expression in magic
// braces should not cause the function not to be defined.
saved_did_emsg = did_emsg;
- did_emsg = FALSE;
+ did_emsg = false;
//
// ":function func" with only function name: list function.
@@ -2026,11 +2124,11 @@ void ex_function(exarg_T *eap)
// - exclude line numbers from function body
//
if (!paren) {
- if (!ends_excmd(*skipwhite((char *)p))) {
+ if (!ends_excmd(*skipwhite(p))) {
semsg(_(e_trailing_arg), p);
goto ret_free;
}
- eap->nextcmd = (char *)check_nextcmd(p);
+ eap->nextcmd = check_nextcmd(p);
if (eap->nextcmd != NULL) {
*p = NUL;
}
@@ -2052,7 +2150,7 @@ void ex_function(exarg_T *eap)
msg_putchar(' ');
}
}
- msg_prt_line((char_u *)FUNCLINE(fp, j), false);
+ msg_prt_line(FUNCLINE(fp, j), false);
ui_flush(); // show a line at a time
os_breakcheck();
}
@@ -2067,24 +2165,22 @@ void ex_function(exarg_T *eap)
goto ret_free;
}
- /*
- * ":function name(arg1, arg2)" Define function.
- */
- p = (char_u *)skipwhite((char *)p);
+ // ":function name(arg1, arg2)" Define function.
+ p = skipwhite(p);
if (*p != '(') {
if (!eap->skip) {
semsg(_("E124: Missing '(': %s"), eap->arg);
goto ret_free;
}
// attempt to continue by skipping some text
- if (vim_strchr((char *)p, '(') != NULL) {
- p = (char_u *)vim_strchr((char *)p, '(');
+ if (vim_strchr(p, '(') != NULL) {
+ p = vim_strchr(p, '(');
}
}
- p = (char_u *)skipwhite((char *)p + 1);
+ p = skipwhite(p + 1);
- ga_init(&newargs, (int)sizeof(char_u *), 3);
- ga_init(&newlines, (int)sizeof(char_u *), 3);
+ ga_init(&newargs, (int)sizeof(char *), 3);
+ ga_init(&newlines, (int)sizeof(char *), 3);
if (!eap->skip) {
// Check the name of the function. Unless it's a dictionary function
@@ -2095,7 +2191,7 @@ void ex_function(exarg_T *eap)
arg = fudi.fd_newkey;
}
if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) {
- int j = (*arg == K_SPECIAL) ? 3 : 0;
+ int j = ((uint8_t)(*arg) == K_SPECIAL) ? 3 : 0;
while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j]) : eval_isnamec(arg[j]))) {
j++;
}
@@ -2109,7 +2205,7 @@ void ex_function(exarg_T *eap)
}
}
- if (get_function_args((char **)&p, ')', &newargs, &varargs,
+ if (get_function_args(&p, ')', &newargs, &varargs,
&default_args, eap->skip) == FAIL) {
goto errret_2;
}
@@ -2121,23 +2217,22 @@ void ex_function(exarg_T *eap)
// find extra arguments "range", "dict", "abort" and "closure"
for (;;) {
- p = (char_u *)skipwhite((char *)p);
- if (STRNCMP(p, "range", 5) == 0) {
+ p = skipwhite(p);
+ if (strncmp(p, "range", 5) == 0) {
flags |= FC_RANGE;
p += 5;
- } else if (STRNCMP(p, "dict", 4) == 0) {
+ } else if (strncmp(p, "dict", 4) == 0) {
flags |= FC_DICT;
p += 4;
- } else if (STRNCMP(p, "abort", 5) == 0) {
+ } else if (strncmp(p, "abort", 5) == 0) {
flags |= FC_ABORT;
p += 5;
- } else if (STRNCMP(p, "closure", 7) == 0) {
+ } else if (strncmp(p, "closure", 7) == 0) {
flags |= FC_CLOSURE;
p += 7;
if (current_funccal == NULL) {
- emsg_funcname(N_
- ("E932: Closure function should not be at top level: %s"),
- name == NULL ? (char_u *)"" : name);
+ emsg_funcname(N_("E932: Closure function should not be at top level: %s"),
+ name == NULL ? "" : name);
goto erret;
}
} else {
@@ -2153,9 +2248,7 @@ void ex_function(exarg_T *eap)
semsg(_(e_trailing_arg), p);
}
- /*
- * Read the body of the function, until ":endfunction" is found.
- */
+ // Read the body of the function, until ":endfunction" is found.
if (KeyTyped) {
// Check if the function already exists, don't let the user type the
// whole function before telling him it doesn't work! For a script we
@@ -2193,9 +2286,9 @@ void ex_function(exarg_T *eap)
if (line_arg != NULL) {
// Use eap->arg, split up in parts by line breaks.
theline = line_arg;
- p = (char_u *)vim_strchr((char *)theline, '\n');
+ p = vim_strchr(theline, '\n');
if (p == NULL) {
- line_arg += STRLEN(line_arg);
+ line_arg += strlen(line_arg);
} else {
*p = NUL;
line_arg = p + 1;
@@ -2205,7 +2298,7 @@ void ex_function(exarg_T *eap)
if (eap->getline == NULL) {
theline = getcmdline(':', 0L, indent, do_concat);
} else {
- theline = (char_u *)eap->getline(':', eap->cookie, indent, do_concat);
+ theline = eap->getline(':', eap->cookie, indent, do_concat);
}
line_to_free = theline;
}
@@ -2235,18 +2328,18 @@ void ex_function(exarg_T *eap)
// * ":python <<EOF" and "EOF"
// * ":let {var-name} =<< [trim] {marker}" and "{marker}"
if (heredoc_trimmed == NULL
- || (is_heredoc && (char_u *)skipwhite((char *)theline) == theline)
- || STRNCMP(theline, heredoc_trimmed,
- STRLEN(heredoc_trimmed)) == 0) {
+ || (is_heredoc && skipwhite(theline) == theline)
+ || strncmp(theline, heredoc_trimmed,
+ strlen(heredoc_trimmed)) == 0) {
if (heredoc_trimmed == NULL) {
p = theline;
} else if (is_heredoc) {
- p = (char_u *)skipwhite((char *)theline) == theline
- ? theline : theline + STRLEN(heredoc_trimmed);
+ p = skipwhite(theline) == theline
+ ? theline : theline + strlen(heredoc_trimmed);
} else {
- p = theline + STRLEN(heredoc_trimmed);
+ p = theline + strlen(heredoc_trimmed);
}
- if (STRCMP(p, skip_until) == 0) {
+ if (strcmp(p, skip_until) == 0) {
XFREE_CLEAR(skip_until);
XFREE_CLEAR(heredoc_trimmed);
do_concat = true;
@@ -2258,27 +2351,26 @@ void ex_function(exarg_T *eap)
for (p = theline; ascii_iswhite(*p) || *p == ':'; p++) {}
// Check for "endfunction".
- if (checkforcmd((char **)&p, "endfunction", 4) && nesting-- == 0) {
+ if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) {
if (*p == '!') {
p++;
}
- char_u *nextcmd = NULL;
+ char *nextcmd = NULL;
if (*p == '|') {
nextcmd = p + 1;
- } else if (line_arg != NULL && *skipwhite((char *)line_arg) != NUL) {
+ } else if (line_arg != NULL && *skipwhite(line_arg) != NUL) {
nextcmd = line_arg;
} else if (*p != NUL && *p != '"' && p_verbose > 0) {
- give_warning2((char_u *)_("W22: Text found after :endfunction: %s"),
- p, true);
+ give_warning2(_("W22: Text found after :endfunction: %s"), p, true);
}
if (nextcmd != NULL) {
// Another command follows. If the line came from "eap" we
// can simply point into it, otherwise we need to change
// "eap->cmdlinep".
- eap->nextcmd = (char *)nextcmd;
+ eap->nextcmd = nextcmd;
if (line_to_free != NULL) {
xfree(*eap->cmdlinep);
- *eap->cmdlinep = (char *)line_to_free;
+ *eap->cmdlinep = line_to_free;
line_to_free = NULL;
}
}
@@ -2287,46 +2379,50 @@ void ex_function(exarg_T *eap)
// Increase indent inside "if", "while", "for" and "try", decrease
// at "end".
- if (indent > 2 && STRNCMP(p, "end", 3) == 0) {
+ if (indent > 2 && strncmp(p, "end", 3) == 0) {
indent -= 2;
- } else if (STRNCMP(p, "if", 2) == 0
- || STRNCMP(p, "wh", 2) == 0
- || STRNCMP(p, "for", 3) == 0
- || STRNCMP(p, "try", 3) == 0) {
+ } else if (strncmp(p, "if", 2) == 0
+ || strncmp(p, "wh", 2) == 0
+ || strncmp(p, "for", 3) == 0
+ || strncmp(p, "try", 3) == 0) {
indent += 2;
}
// Check for defining a function inside this function.
- if (checkforcmd((char **)&p, "function", 2)) {
+ if (checkforcmd(&p, "function", 2)) {
if (*p == '!') {
- p = (char_u *)skipwhite((char *)p + 1);
+ p = skipwhite(p + 1);
}
p += eval_fname_script((const char *)p);
- xfree(trans_function_name((char **)&p, true, 0, NULL, NULL));
- if (*skipwhite((char *)p) == '(') {
- nesting++;
- indent += 2;
+ xfree(trans_function_name(&p, true, 0, NULL, NULL));
+ if (*skipwhite(p) == '(') {
+ if (nesting == MAX_FUNC_NESTING - 1) {
+ emsg(_("E1058: function nesting too deep"));
+ } else {
+ nesting++;
+ indent += 2;
+ }
}
}
// Check for ":append", ":change", ":insert".
- p = (char_u *)skip_range((char *)p, NULL);
+ p = skip_range(p, NULL);
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
|| (p[0] == 'c'
&& (!ASCII_ISALPHA(p[1])
|| (p[1] == 'h' && (!ASCII_ISALPHA(p[2])
|| (p[2] == 'a'
- && (STRNCMP(&p[3], "nge", 3) != 0
+ && (strncmp(&p[3], "nge", 3) != 0
|| !ASCII_ISALPHA(p[6])))))))
|| (p[0] == 'i'
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
&& (!ASCII_ISALPHA(p[2])
|| (p[2] == 's')))))) {
- skip_until = vim_strsave((char_u *)".");
+ skip_until = xstrdup(".");
}
// heredoc: Check for ":python <<EOF", ":lua <<EOF", etc.
- arg = (char_u *)skipwhite((char *)skiptowhite(p));
+ arg = skipwhite(skiptowhite(p));
if (arg[0] == '<' && arg[1] == '<'
&& ((p[0] == 'p' && p[1] == 'y'
&& (!ASCII_ISALNUM(p[2]) || p[2] == 't'
@@ -2343,22 +2439,22 @@ void ex_function(exarg_T *eap)
|| (p[0] == 'm' && p[1] == 'z'
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
// ":python <<" continues until a dot, like ":append"
- p = (char_u *)skipwhite((char *)arg + 2);
+ p = skipwhite(arg + 2);
if (*p == NUL) {
- skip_until = vim_strsave((char_u *)".");
+ skip_until = xstrdup(".");
} else {
- skip_until = vim_strsave(p);
+ skip_until = xstrdup(p);
}
}
// Check for ":let v =<< [trim] EOF"
// and ":let [a, b] =<< [trim] EOF"
- arg = (char_u *)skipwhite((char *)skiptowhite(p));
+ arg = skipwhite(skiptowhite(p));
if (*arg == '[') {
- arg = (char_u *)vim_strchr((char *)arg, ']');
+ arg = vim_strchr(arg, ']');
}
if (arg != NULL) {
- arg = (char_u *)skipwhite((char *)skiptowhite(arg));
+ arg = skipwhite(skiptowhite(arg));
if (arg[0] == '='
&& arg[1] == '<'
&& arg[2] == '<'
@@ -2366,14 +2462,13 @@ void ex_function(exarg_T *eap)
&& p[1] == 'e'
&& (!ASCII_ISALNUM(p[2])
|| (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) {
- p = (char_u *)skipwhite((char *)arg + 3);
- if (STRNCMP(p, "trim", 4) == 0) {
+ p = skipwhite(arg + 3);
+ if (strncmp(p, "trim", 4) == 0) {
// Ignore leading white space.
- p = (char_u *)skipwhite((char *)p + 4);
- heredoc_trimmed =
- vim_strnsave(theline, (size_t)((char_u *)skipwhite((char *)theline) - theline));
+ p = skipwhite(p + 4);
+ heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline));
}
- skip_until = vim_strnsave(p, (size_t)(skiptowhite(p) - p));
+ skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p));
do_concat = false;
is_heredoc = true;
}
@@ -2386,8 +2481,8 @@ void ex_function(exarg_T *eap)
// Copy the line to newly allocated memory. get_one_sourceline()
// allocates 250 bytes per line, this saves 80% on average. The cost
// is an extra alloc/free.
- p = vim_strsave(theline);
- ((char **)(newlines.ga_data))[newlines.ga_len++] = (char *)p;
+ p = xstrdup(theline);
+ ((char **)(newlines.ga_data))[newlines.ga_len++] = p;
// Add NULL lines for continuation lines, so that the line count is
// equal to the index in the growarray.
@@ -2407,14 +2502,11 @@ void ex_function(exarg_T *eap)
goto erret;
}
- /*
- * If there are no errors, add the function
- */
+ // If there are no errors, add the function
if (fudi.fd_dict == NULL) {
- v = find_var((const char *)name, STRLEN(name), &ht, false);
+ v = find_var((const char *)name, strlen(name), &ht, false);
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
- emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
- name);
+ emsg_funcname(N_("E707: Function name conflicts with variable: %s"), name);
goto erret;
}
@@ -2429,8 +2521,7 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fp->uf_calls > 0) {
- emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
- name);
+ emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"), name);
goto erret;
}
if (fp->uf_refcount > 1) {
@@ -2441,7 +2532,7 @@ void ex_function(exarg_T *eap)
fp = NULL;
overwrite = true;
} else {
- char_u *exp_name = fp->uf_name_exp;
+ char *exp_name = fp->uf_name_exp;
// redefine existing function, keep the expanded name
XFREE_CLEAR(name);
fp->uf_name_exp = NULL;
@@ -2460,13 +2551,13 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fudi.fd_di == NULL) {
- if (var_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ if (value_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't add a function to a locked dictionary
goto erret;
}
- } else if (var_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ } else if (value_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't change an existing function if it is locked
goto erret;
}
@@ -2474,23 +2565,23 @@ void ex_function(exarg_T *eap)
// Give the function a sequential number. Can only be used with a
// Funcref!
xfree(name);
- sprintf(numbuf, "%d", ++func_nr);
- name = vim_strsave((char_u *)numbuf);
+ sprintf(numbuf, "%d", ++func_nr); // NOLINT(runtime/printf)
+ name = xstrdup(numbuf);
}
if (fp == NULL) {
- if (fudi.fd_dict == NULL && vim_strchr((char *)name, AUTOLOAD_CHAR) != NULL) {
+ if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) {
int slen, plen;
- char_u *scriptname;
+ char *scriptname;
// Check that the autoload name matches the script name.
int j = FAIL;
if (SOURCING_NAME != NULL) {
- scriptname = (char_u *)autoload_name((const char *)name, STRLEN(name));
- p = (char_u *)vim_strchr((char *)scriptname, '/');
- plen = (int)STRLEN(p);
- slen = (int)STRLEN(SOURCING_NAME);
- if (slen > plen && FNAMECMP(p, SOURCING_NAME + slen - plen) == 0) {
+ scriptname = autoload_name(name, strlen(name));
+ p = vim_strchr(scriptname, '/');
+ plen = (int)strlen(p);
+ slen = (int)strlen(SOURCING_NAME);
+ if (slen > plen && path_fnamecmp(p, SOURCING_NAME + slen - plen) == 0) {
j = OK;
}
xfree(scriptname);
@@ -2502,7 +2593,7 @@ void ex_function(exarg_T *eap)
}
}
- fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1);
if (fudi.fd_dict != NULL) {
if (fudi.fd_di == NULL) {
@@ -2518,7 +2609,7 @@ void ex_function(exarg_T *eap)
tv_clear(&fudi.fd_di->di_tv);
}
fudi.fd_di->di_tv.v_type = VAR_FUNC;
- fudi.fd_di->di_tv.vval.v_string = (char *)vim_strsave(name);
+ fudi.fd_di->di_tv.vval.v_string = xstrdup(name);
// behave like "dict" was used
flags |= FC_DICT;
@@ -2527,8 +2618,8 @@ void ex_function(exarg_T *eap)
// insert the new function in the function list
set_ufunc_name(fp, name);
if (overwrite) {
- hi = hash_find(&func_hashtab, (char *)name);
- hi->hi_key = UF2HIKEY(fp);
+ hi = hash_find(&func_hashtab, name);
+ hi->hi_key = (char *)UF2HIKEY(fp);
} else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) {
xfree(fp);
goto erret;
@@ -2584,8 +2675,8 @@ int eval_fname_script(const char *const p)
// Use mb_strnicmp() because in Turkish comparing the "I" may not work with
// the standard library function.
if (p[0] == '<'
- && (mb_strnicmp((char_u *)p + 1, (char_u *)"SID>", 4) == 0
- || mb_strnicmp((char_u *)p + 1, (char_u *)"SNR>", 4) == 0)) {
+ && (mb_strnicmp(p + 1, "SID>", 4) == 0
+ || mb_strnicmp(p + 1, "SNR>", 4) == 0)) {
return 5;
}
if (p[0] == 's' && p[1] == ':') {
@@ -2599,7 +2690,7 @@ bool translated_function_exists(const char *name)
if (builtin_function(name, -1)) {
return find_internal_func((char *)name) != NULL;
}
- return find_func((const char_u *)name) != NULL;
+ return find_func(name) != NULL;
}
/// Check whether function with the given name exists
@@ -2610,15 +2701,15 @@ bool translated_function_exists(const char *name)
/// @return true if it exists, false otherwise.
bool function_exists(const char *const name, bool no_deref)
{
- const char_u *nm = (const char_u *)name;
+ const char *nm = name;
bool n = false;
int flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
if (no_deref) {
flag |= TFN_NO_DEREF;
}
- char *const p = (char *)trans_function_name((char **)&nm, false, flag, NULL, NULL);
- nm = (char_u *)skipwhite((char *)nm);
+ char *const p = trans_function_name((char **)&nm, false, flag, NULL, NULL);
+ nm = skipwhite(nm);
// Only accept "funcname", "funcname ", "funcname (..." and
// "funcname(...", not "funcname!...".
@@ -2634,15 +2725,17 @@ bool function_exists(const char *const name, bool no_deref)
char *get_user_func_name(expand_T *xp, int idx)
{
static size_t done;
+ static int changed;
static hashitem_T *hi;
ufunc_T *fp;
if (idx == 0) {
done = 0;
hi = func_hashtab.ht_array;
+ changed = func_hashtab.ht_changed;
}
assert(hi);
- if (done < func_hashtab.ht_used) {
+ if (changed == func_hashtab.ht_changed && done < func_hashtab.ht_used) {
if (done++ > 0) {
hi++;
}
@@ -2652,11 +2745,11 @@ char *get_user_func_name(expand_T *xp, int idx)
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DICT)
- || STRNCMP(fp->uf_name, "<lambda>", 8) == 0) {
+ || strncmp(fp->uf_name, "<lambda>", 8) == 0) {
return ""; // don't show dict and lambda functions
}
- if (STRLEN(fp->uf_name) + 4 >= IOSIZE) {
+ if (strlen(fp->uf_name) + 4 >= IOSIZE) {
return (char *)fp->uf_name; // Prevent overflow.
}
@@ -2667,7 +2760,7 @@ char *get_user_func_name(expand_T *xp, int idx)
STRCAT(IObuff, ")");
}
}
- return (char *)IObuff;
+ return IObuff;
}
return NULL;
}
@@ -2676,12 +2769,12 @@ char *get_user_func_name(expand_T *xp, int idx)
void ex_delfunction(exarg_T *eap)
{
ufunc_T *fp = NULL;
- char_u *p;
- char_u *name;
+ char *p;
+ char *name;
funcdict_T fudi;
- p = (char_u *)eap->arg;
- name = trans_function_name((char **)&p, eap->skip, 0, &fudi, NULL);
+ p = eap->arg;
+ name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
xfree(fudi.fd_newkey);
if (name == NULL) {
if (fudi.fd_dict != NULL && !eap->skip) {
@@ -2689,16 +2782,23 @@ void ex_delfunction(exarg_T *eap)
}
return;
}
- if (!ends_excmd(*skipwhite((char *)p))) {
+ if (!ends_excmd(*skipwhite(p))) {
xfree(name);
semsg(_(e_trailing_arg), p);
return;
}
- eap->nextcmd = (char *)check_nextcmd(p);
+ eap->nextcmd = check_nextcmd(p);
if (eap->nextcmd != NULL) {
*p = NUL;
}
+ if (isdigit((uint8_t)(*name)) && fudi.fd_dict == NULL) {
+ if (!eap->skip) {
+ semsg(_(e_invarg2), eap->arg);
+ }
+ xfree(name);
+ return;
+ }
if (!eap->skip) {
fp = find_func(name);
}
@@ -2749,7 +2849,7 @@ void ex_delfunction(exarg_T *eap)
/// Unreference a Function: decrement the reference count and free it when it
/// becomes zero.
-void func_unref(char_u *name)
+void func_unref(char *name)
{
ufunc_T *fp = NULL;
@@ -2758,7 +2858,7 @@ void func_unref(char_u *name)
}
fp = find_func(name);
- if (fp == NULL && isdigit(*name)) {
+ if (fp == NULL && isdigit((uint8_t)(*name))) {
#ifdef EXITFREE
if (!entered_free_all_mem) {
internal_error("func_unref()");
@@ -2791,7 +2891,7 @@ void func_ptr_unref(ufunc_T *fp)
}
/// Count a reference to a Function.
-void func_ref(char_u *name)
+void func_ref(char *name)
{
ufunc_T *fp;
@@ -2801,7 +2901,7 @@ void func_ref(char_u *name)
fp = find_func(name);
if (fp != NULL) {
(fp->uf_refcount)++;
- } else if (isdigit(*name)) {
+ } else if (isdigit((uint8_t)(*name))) {
// Only give an error for a numbered function.
// Fail silently, when named or lambda function isn't found.
internal_error("func_ref()");
@@ -2845,9 +2945,9 @@ static int can_free_funccal(funccall_T *fc, int copyID)
/// ":return [expr]"
void ex_return(exarg_T *eap)
{
- char_u *arg = (char_u *)eap->arg;
+ char *arg = eap->arg;
typval_T rettv;
- int returning = FALSE;
+ int returning = false;
if (current_funccal == NULL) {
emsg(_("E133: :return not inside a function"));
@@ -2860,7 +2960,7 @@ void ex_return(exarg_T *eap)
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
- && eval0((char *)arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
+ && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
if (!eap->skip) {
returning = do_return(eap, false, true, &rettv);
} else {
@@ -2883,7 +2983,7 @@ void ex_return(exarg_T *eap)
if (returning) {
eap->nextcmd = NULL;
} else if (eap->nextcmd == NULL) { // no argument
- eap->nextcmd = (char *)check_nextcmd(arg);
+ eap->nextcmd = check_nextcmd(arg);
}
if (eap->skip) {
@@ -2891,15 +2991,13 @@ void ex_return(exarg_T *eap)
}
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// ":1,25call func(arg1, arg2)" function call.
void ex_call(exarg_T *eap)
{
- char_u *arg = (char_u *)eap->arg;
- char_u *startarg;
- char_u *name;
- char_u *tofree;
+ char *arg = eap->arg;
+ char *startarg;
+ char *name;
+ char *tofree;
int len;
typval_T rettv;
linenr_T lnum;
@@ -2920,7 +3018,7 @@ void ex_call(exarg_T *eap)
return;
}
- tofree = trans_function_name((char **)&arg, false, TFN_INT, &fudi, &partial);
+ tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial);
if (fudi.fd_newkey != NULL) {
// Still need to give an error message for missing key.
semsg(_(e_dictkey), fudi.fd_newkey);
@@ -2939,13 +3037,12 @@ void ex_call(exarg_T *eap)
// If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
// contents. For VAR_PARTIAL get its partial, unless we already have one
// from trans_function_name().
- len = (int)STRLEN(tofree);
- name = deref_func_name((const char *)tofree, &len,
- partial != NULL ? NULL : &partial, false);
+ len = (int)strlen(tofree);
+ name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false);
// Skip white space to allow ":call func ()". Not good, but required for
// backward compatibility.
- startarg = (char_u *)skipwhite((char *)arg);
+ startarg = skipwhite(arg);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
if (*startarg != '(') {
@@ -2969,13 +3066,13 @@ void ex_call(exarg_T *eap)
arg = startarg;
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = eap->line1;
- funcexe.lastline = eap->line2;
- funcexe.doesrange = &doesrange;
- funcexe.evaluate = true;
- funcexe.partial = partial;
- funcexe.selfdict = fudi.fd_dict;
- if (get_func_tv(name, -1, &rettv, (char **)&arg, &funcexe) == FAIL) {
+ funcexe.fe_firstline = eap->line1;
+ funcexe.fe_lastline = eap->line2;
+ funcexe.fe_doesrange = &doesrange;
+ funcexe.fe_evaluate = true;
+ funcexe.fe_partial = partial;
+ funcexe.fe_selfdict = fudi.fd_dict;
+ if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) {
failed = true;
break;
}
@@ -3004,7 +3101,7 @@ void ex_call(exarg_T *eap)
// When inside :try we need to check for following "| catch" or "| endtry".
// Not when there was an error, but do check if an exception was thrown.
- if ((!aborting() || current_exception != NULL) && (!failed || eap->cstack->cs_trylevel > 0)) {
+ if ((!aborting() || did_throw) && (!failed || eap->cstack->cs_trylevel > 0)) {
// Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
if (!failed && !aborting()) {
@@ -3012,7 +3109,7 @@ void ex_call(exarg_T *eap)
semsg(_(e_trailing_arg), arg);
}
} else {
- eap->nextcmd = (char *)check_nextcmd(arg);
+ eap->nextcmd = check_nextcmd(arg);
}
}
@@ -3029,8 +3126,8 @@ end:
/// @param is_cmd set when called due to a ":return" command.
/// @param rettv may point to a typval_T with the return rettv.
///
-/// @return TRUE when the return can be carried out,
-/// FALSE when the return gets pending.
+/// @return true when the return can be carried out,
+/// false when the return gets pending.
int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
{
int idx;
@@ -3080,7 +3177,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
}
report_make_pending(CSTP_RETURN, rettv);
} else {
- current_funccal->returned = TRUE;
+ current_funccal->returned = true;
// If the return is carried out now, store the return value. For
// a return immediately after reanimation, the value is already
@@ -3099,25 +3196,25 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
/// Generate a return command for producing the value of "rettv". The result
/// is an allocated string. Used by report_pending() for verbose messages.
-char_u *get_return_cmd(void *rettv)
+char *get_return_cmd(void *rettv)
{
- char_u *s = NULL;
- char_u *tofree = NULL;
+ char *s = NULL;
+ char *tofree = NULL;
if (rettv != NULL) {
- tofree = s = (char_u *)encode_tv2echo((typval_T *)rettv, NULL);
+ tofree = s = encode_tv2echo((typval_T *)rettv, NULL);
}
if (s == NULL) {
- s = (char_u *)"";
+ s = "";
}
STRCPY(IObuff, ":return ");
- STRLCPY(IObuff + 8, s, IOSIZE - 8);
- if (STRLEN(s) + 8 >= IOSIZE) {
+ xstrlcpy(IObuff + 8, s, IOSIZE - 8);
+ if (strlen(s) + 8 >= IOSIZE) {
STRCPY(IObuff + IOSIZE - 4, "...");
}
xfree(tofree);
- return vim_strsave(IObuff);
+ return xstrdup(IObuff);
}
/// Get next function line.
@@ -3128,12 +3225,12 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat)
{
funccall_T *fcp = (funccall_T *)cookie;
ufunc_T *fp = fcp->func;
- char_u *retval;
+ char *retval;
garray_T *gap; // growarray with function lines
// If breakpoints have been added/deleted need to check for it.
if (fcp->dbg_tick != debug_tick) {
- fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM);
+ fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM);
fcp->dbg_tick = debug_tick;
}
if (do_profiling == PROF_YES) {
@@ -3153,7 +3250,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat)
if (fcp->linenr >= gap->ga_len) {
retval = NULL;
} else {
- retval = (char_u *)xstrdup(((char **)(gap->ga_data))[fcp->linenr++]);
+ retval = xstrdup(((char **)(gap->ga_data))[fcp->linenr++]);
SOURCING_LNUM = fcp->linenr;
if (do_profiling == PROF_YES) {
func_line_start(cookie);
@@ -3163,16 +3260,16 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat)
// Did we encounter a breakpoint?
if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) {
- dbg_breakpoint(fp->uf_name, SOURCING_LNUM);
+ dbg_breakpoint((char *)fp->uf_name, SOURCING_LNUM);
// Find next breakpoint.
- fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM);
+ fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM);
fcp->dbg_tick = debug_tick;
}
- return (char *)retval;
+ return retval;
}
-/// @return TRUE if the currently active function should be ended, because a
+/// @return true if the currently active function should be ended, because a
/// return was encountered or an error occurred. Used inside a ":while".
int func_has_ended(void *cookie)
{
@@ -3184,7 +3281,7 @@ int func_has_ended(void *cookie)
|| fcp->returned;
}
-/// @return TRUE if cookie indicates a function which "abort"s on errors.
+/// @return true if cookie indicates a function which "abort"s on errors.
int func_has_abort(void *cookie)
{
return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT;
@@ -3194,17 +3291,17 @@ int func_has_abort(void *cookie)
/// Changes "rettv" in-place.
void make_partial(dict_T *const selfdict, typval_T *const rettv)
{
- char_u *fname;
- char_u *tofree = NULL;
+ char *fname;
+ char *tofree = NULL;
ufunc_T *fp;
- char_u fname_buf[FLEN_FIXED + 1];
+ char fname_buf[FLEN_FIXED + 1];
int error;
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL) {
fp = rettv->vval.v_partial->pt_func;
} else {
fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING
- ? (char_u *)rettv->vval.v_string
+ ? rettv->vval.v_string
: rettv->vval.v_partial->pt_name;
// Translate "s:func" to the stored function name.
fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
@@ -3221,7 +3318,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv)
pt->pt_auto = true;
if (rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING) {
// Just a function: Take over the function name and use selfdict.
- pt->pt_name = (char_u *)rettv->vval.v_string;
+ pt->pt_name = rettv->vval.v_string;
} else {
partial_T *ret_pt = rettv->vval.v_partial;
int i;
@@ -3230,7 +3327,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv)
// args. Can't take over name or args, the partial might
// be referenced elsewhere.
if (ret_pt->pt_name != NULL) {
- pt->pt_name = vim_strsave(ret_pt->pt_name);
+ pt->pt_name = xstrdup(ret_pt->pt_name);
func_ref(pt->pt_name);
} else {
pt->pt_func = ret_pt->pt_func;
@@ -3252,7 +3349,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv)
}
/// @return the name of the executed function.
-char_u *func_name(void *cookie)
+char *func_name(void *cookie)
{
return ((funccall_T *)cookie)->func->uf_name;
}
@@ -3275,7 +3372,7 @@ int func_level(void *cookie)
return ((funccall_T *)cookie)->level;
}
-/// @return TRUE when a function was ended by a ":return" command.
+/// @return true when a function was ended by a ":return" command.
int current_func_returned(void)
{
return current_funccal->returned;
@@ -3539,14 +3636,14 @@ bool set_ref_in_func_args(int copyID)
/// "ht_stack" is used to add hashtabs to be marked. Can be NULL.
///
/// @return true if setting references failed somehow.
-bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
+bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID)
{
ufunc_T *fp = fp_in;
funccall_T *fc;
- int error = ERROR_NONE;
- char_u fname_buf[FLEN_FIXED + 1];
- char_u *tofree = NULL;
- char_u *fname;
+ int error = FCERR_NONE;
+ char fname_buf[FLEN_FIXED + 1];
+ char *tofree = NULL;
+ char *fname;
bool abort = false;
if (name == NULL && fp_in == NULL) {
return false;
@@ -3565,20 +3662,18 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
return abort;
}
-/// Registers a C extension user function.
-char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
+/// Registers a luaref as a lambda.
+char *register_luafunc(LuaRef ref)
{
- char_u *name = get_lambda_name();
- ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ char *name = get_lambda_name();
+ ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1);
fp->uf_refcount = 1;
fp->uf_varargs = true;
- fp->uf_flags = FC_CFUNC;
+ fp->uf_flags = FC_LUAREF;
fp->uf_calls = 0;
fp->uf_script_ctx = current_sctx;
- fp->uf_cb = cb;
- fp->uf_cb_free = cb_free;
- fp->uf_cb_state = state;
+ fp->uf_luaref = ref;
STRCPY(fp->uf_name, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index 4b7007aae9..c8583f232c 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -1,18 +1,42 @@
#ifndef NVIM_EVAL_USERFUNC_H
#define NVIM_EVAL_USERFUNC_H
+#include <stdbool.h>
+#include <stddef.h>
+
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
+#include "nvim/garray.h"
+#include "nvim/hashtab.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+
+struct funccal_entry;
// From user function to hashitem and back.
#define UF2HIKEY(fp) ((fp)->uf_name)
#define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name)))
#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
-///< Structure used by trans_function_name()
+// flags used in uf_flags
+#define FC_ABORT 0x01 // abort function on error
+#define FC_RANGE 0x02 // function accepts range
+#define FC_DICT 0x04 // Dict function, uses "self"
+#define FC_CLOSURE 0x08 // closure, uses outer scope variables
+#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
+#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
+#define FC_SANDBOX 0x40 // function defined in the sandbox
+#define FC_DEAD 0x80 // function kept only for reference to dfunc
+#define FC_EXPORT 0x100 // "export def Func()"
+#define FC_NOARGS 0x200 // no a: variables in lambda
+#define FC_VIM9 0x400 // defined in vim9 script file
+#define FC_LUAREF 0x800 // luaref callback
+
+/// Structure used by trans_function_name()
typedef struct {
dict_T *fd_dict; ///< Dictionary used.
- char_u *fd_newkey; ///< New key in "dict" in allocated memory.
+ char *fd_newkey; ///< New key in "dict" in allocated memory.
dictitem_T *fd_di; ///< Dictionary item used.
} funcdict_T;
@@ -24,44 +48,43 @@ struct funccal_entry {
/// errors for when calling a function
typedef enum {
- ERROR_UNKNOWN = 0,
- ERROR_TOOMANY,
- ERROR_TOOFEW,
- ERROR_SCRIPT,
- ERROR_DICT,
- ERROR_NONE,
- ERROR_OTHER,
- ERROR_BOTH,
- ERROR_DELETED,
- ERROR_NOTMETHOD,
+ FCERR_UNKNOWN = 0,
+ FCERR_TOOMANY = 1,
+ FCERR_TOOFEW = 2,
+ FCERR_SCRIPT = 3,
+ FCERR_DICT = 4,
+ FCERR_NONE = 5,
+ FCERR_OTHER = 6,
+ FCERR_DELETED = 7,
+ FCERR_NOTMETHOD = 8, ///< function cannot be used as a method
} FnameTransError;
/// Used in funcexe_T. Returns the new argcount.
-typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip,
- int called_func_argcount);
+typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int partial_argcount,
+ ufunc_T *called_func);
/// Structure passed between functions dealing with function call execution.
typedef struct {
- ArgvFunc argv_func; ///< when not NULL, can be used to fill in arguments only
- ///< when the invoked function uses them
- linenr_T firstline; ///< first line of range
- linenr_T lastline; ///< last line of range
- bool *doesrange; ///< [out] if not NULL: function handled range
- bool evaluate; ///< actually evaluate expressions
- partial_T *partial; ///< for extra arguments
- dict_T *selfdict; ///< Dictionary for "self"
- typval_T *basetv; ///< base for base->method()
+ ArgvFunc fe_argv_func; ///< when not NULL, can be used to fill in arguments only
+ ///< when the invoked function uses them
+ linenr_T fe_firstline; ///< first line of range
+ linenr_T fe_lastline; ///< last line of range
+ bool *fe_doesrange; ///< [out] if not NULL: function handled range
+ bool fe_evaluate; ///< actually evaluate expressions
+ partial_T *fe_partial; ///< for extra arguments
+ dict_T *fe_selfdict; ///< Dictionary for "self"
+ typval_T *fe_basetv; ///< base for base->method()
} funcexe_T;
#define FUNCEXE_INIT (funcexe_T) { \
- .argv_func = NULL, \
- .firstline = 0, \
- .lastline = 0, \
- .doesrange = NULL, \
- .evaluate = false, \
- .partial = NULL, \
- .selfdict = NULL, \
- .basetv = NULL, \
+ .fe_argv_func = NULL, \
+ .fe_firstline = 0, \
+ .fe_lastline = 0, \
+ .fe_doesrange = NULL, \
+ .fe_evaluate = false, \
+ .fe_partial = NULL, \
+ .fe_selfdict = NULL, \
+ .fe_basetv = NULL, \
}
#define FUNCARG(fp, j) ((char **)(fp->uf_args.ga_data))[j]
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index b38849730a..3e593151fc 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -3,24 +3,43 @@
// eval/vars.c: functions for dealing with variables
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
-#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/hashtab.h"
+#include "nvim/macros.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/screen.h"
+#include "nvim/os/os.h"
#include "nvim/search.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -62,7 +81,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// Check for the optional 'trim' word before the marker
cmd = skipwhite(cmd);
- if (STRNCMP(cmd, "trim", 4) == 0
+ if (strncmp(cmd, "trim", 4) == 0
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
cmd = skipwhite(cmd + 4);
@@ -81,13 +100,13 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// The marker is the next word.
if (*cmd != NUL && *cmd != '"') {
marker = skipwhite(cmd);
- p = (char *)skiptowhite((char_u *)marker);
+ p = skiptowhite(marker);
if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
semsg(_(e_trailing_arg), p);
return NULL;
}
*p = NUL;
- if (islower(*marker)) {
+ if (islower((uint8_t)(*marker))) {
emsg(_("E221: Marker cannot start with lower case letter"));
return NULL;
}
@@ -110,10 +129,10 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// with "trim": skip the indent matching the :let line to find the
// marker
if (marker_indent_len > 0
- && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
+ && strncmp(theline, *eap->cmdlinep, (size_t)marker_indent_len) == 0) {
mi = marker_indent_len;
}
- if (STRCMP(marker, theline + mi) == 0) {
+ if (strcmp(marker, theline + mi) == 0) {
xfree(theline);
break;
}
@@ -189,8 +208,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
argend--;
}
expr = skipwhite(argend);
- if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
- && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
+ if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
+ && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) {
// ":let" without "=": list variables
if (*arg == '[') {
emsg(_(e_invarg));
@@ -207,7 +226,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
list_func_vars(&first);
list_vim_vars(&first);
}
- eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+ eap->nextcmd = check_nextcmd(arg);
} else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
// HERE document
list_T *l = heredoc_get(eap, expr + 3);
@@ -225,17 +244,19 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
op[0] = '=';
op[1] = NUL;
if (*expr != '=') {
- if (vim_strchr("+-*/%.", *expr) != NULL) {
+ if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
}
- expr = skipwhite(expr + 2);
+ expr += 2;
} else {
- expr = skipwhite(expr + 1);
+ expr += 1;
}
+ expr = skipwhite(expr);
+
if (eap->skip) {
emsg_skip++;
}
@@ -378,9 +399,8 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
}
}
return p + 1;
- } else {
- return skip_var_one((char *)arg);
}
+ return skip_var_one((char *)arg);
}
/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
@@ -413,7 +433,7 @@ void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *firs
// apply :filter /pat/ to variable name
xstrlcpy(buf, prefix, IOSIZE);
xstrlcat(buf, (char *)di->di_key, IOSIZE);
- if (message_filtered((char_u *)buf)) {
+ if (message_filtered(buf)) {
continue;
}
@@ -539,8 +559,6 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
return arg;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
///
/// @param[in] arg Start of the variable name.
@@ -558,8 +576,6 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
{
char *arg_end = NULL;
int len;
- int opt_flags;
- char *tofree = NULL;
// ":let $VAR = expr": Set environment variable.
if (*arg == '$') {
@@ -574,20 +590,20 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (len == 0) {
semsg(_(e_invarg2), name - 1);
} else {
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg)) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg))) == NULL) {
emsg(_(e_letunexp));
} else if (!check_secure()) {
+ char *tofree = NULL;
const char c1 = name[len];
name[len] = NUL;
const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
char *s = vim_getenv(name);
-
if (s != NULL) {
- tofree = (char *)concat_str((const char_u *)s, (const char_u *)p);
+ tofree = concat_str(s, p);
p = (const char *)tofree;
xfree(s);
}
@@ -609,10 +625,11 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
return NULL;
}
// Find the end of the name.
- char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
+ int scope;
+ char *const p = (char *)find_option_end((const char **)&arg, &scope);
if (p == NULL
|| (endchars != NULL
- && vim_strchr(endchars, *skipwhite(p)) == NULL)) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
emsg(_(e_letunexp));
} else {
varnumber_T n = 0;
@@ -621,11 +638,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
char *stringval = NULL;
const char *s = NULL;
bool failed = false;
+ uint32_t opt_p_flags;
+ char *tofree = NULL;
const char c1 = *p;
*p = NUL;
- opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, scope);
if (opt_type == gov_bool
|| opt_type == gov_number
|| opt_type == gov_hidden_bool
@@ -634,8 +653,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
n = (long)tv_get_number(tv);
}
- // Avoid setting a string option to the text "v:false" or similar.
- if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ if ((opt_p_flags & P_FUNC) && tv_is_func(*tv)) {
+ // If the option can be set to a function reference or a lambda
+ // and the passed value is a function reference, then convert it to
+ // the name (string) of the function reference.
+ s = tofree = encode_tv2string(tv, NULL);
+ } else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ // Avoid setting a string option to the text "v:false" or similar.
s = tv_get_string_chk(tv);
}
@@ -663,8 +687,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
} else if (opt_type == gov_string && stringval != NULL && s != NULL) {
// string
char *const oldstringval = stringval;
- stringval = (char *)concat_str((const char_u *)stringval,
- (const char_u *)s);
+ stringval = concat_str(stringval, s);
xfree(oldstringval);
s = stringval;
}
@@ -673,7 +696,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (!failed) {
if (opt_type != gov_string || s != NULL) {
- char *err = set_option_value(arg, n, s, opt_flags);
+ char *err = set_option_value(arg, n, s, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -684,6 +707,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
}
*p = c1;
xfree(stringval);
+ xfree(tofree);
}
// ":let @r = expr": Set register contents.
} else if (*arg == '@') {
@@ -692,10 +716,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
return NULL;
}
arg++;
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) {
emsg(_(e_letunexp));
} else {
char *s;
@@ -705,14 +729,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (p != NULL && op != NULL && *op == '.') {
s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
if (s != NULL) {
- ptofree = (char *)concat_str((char_u *)s, (const char_u *)p);
+ ptofree = concat_str(s, p);
p = (const char *)ptofree;
xfree(s);
}
}
if (p != NULL) {
- write_reg_contents(*arg == '@' ? '"' : *arg,
- (const char_u *)p, (ssize_t)STRLEN(p), false);
+ write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false);
arg_end = arg + 1;
}
xfree(ptofree);
@@ -724,7 +747,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
if (p != NULL && lv.ll_name != NULL) {
- if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
+ if (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL) {
emsg(_(e_letunexp));
} else {
set_var_lval(&lv, p, tv, copy, is_const, op);
@@ -745,8 +768,6 @@ void ex_unlet(exarg_T *eap)
ex_unletlock(eap, eap->arg, 0, do_unlet_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// ":lockvar" and ":unlockvar" commands
void ex_lockvar(exarg_T *eap)
{
@@ -763,8 +784,6 @@ void ex_lockvar(exarg_T *eap)
ex_unletlock(eap, arg, deep, do_lock_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Common parsing logic for :unlet, :lockvar and :unlockvar.
///
/// Invokes `callback` afterwards if successful and `eap->skip == false`.
@@ -791,6 +810,7 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca
semsg(_(e_invarg2), arg - 1);
return;
}
+ assert(*lv.ll_name == '$'); // suppress clang "Uninitialized argument value"
if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) {
error = true;
}
@@ -825,11 +845,9 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca
arg = skipwhite(name_end);
} while (!ends_excmd(*arg));
- eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+ eap->nextcmd = check_nextcmd(arg);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Unlet a variable indicated by `lp`.
///
/// @param[in] lp The lvalue.
@@ -846,7 +864,7 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
int cc;
if (lp->ll_tv == NULL) {
- cc = (char_u)(*name_end);
+ cc = (uint8_t)(*name_end);
*name_end = NUL;
// Environment variable, normal name or expanded name.
@@ -859,13 +877,13 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
} else if ((lp->ll_list != NULL
// ll_list is not NULL when lvalue is not in a list, NULL lists
// yield E689.
- && var_check_lock(tv_list_locked(lp->ll_list),
- lp->ll_name,
- lp->ll_name_len))
+ && value_check_lock(tv_list_locked(lp->ll_list),
+ lp->ll_name,
+ lp->ll_name_len))
|| (lp->ll_dict != NULL
- && var_check_lock(lp->ll_dict->dv_lock,
- lp->ll_name,
- lp->ll_name_len))) {
+ && value_check_lock(lp->ll_dict->dv_lock,
+ lp->ll_name,
+ lp->ll_name_len))) {
return FAIL;
} else if (lp->ll_range) {
assert(lp->ll_list != NULL);
@@ -874,18 +892,17 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
listitem_T *last_li = first_li;
for (;;) {
listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
- if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
- lp->ll_name,
- lp->ll_name_len)) {
+ if (value_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
+ lp->ll_name,
+ lp->ll_name_len)) {
return false;
}
lp->ll_li = li;
lp->ll_n1++;
if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) {
break;
- } else {
- last_li = lp->ll_li;
}
+ last_li = lp->ll_li;
}
tv_list_remove_items(lp->ll_list, first_li, last_li);
} else {
@@ -920,8 +937,6 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
return ret;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// unlet a variable
///
/// @param[in] name Variable name to unlet.
@@ -961,11 +976,11 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
dictitem_T *const di = TV_DICT_HI2DI(hi);
if (var_check_fixed(di->di_flags, name, TV_CSTRING)
|| var_check_ro(di->di_flags, name, TV_CSTRING)
- || var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ || value_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
- if (var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ if (value_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
@@ -992,8 +1007,6 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
return FAIL;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Lock or unlock variable indicated by `lp`.
///
/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
@@ -1010,10 +1023,6 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap
bool lock = eap->cmdidx == CMD_lockvar;
int ret = OK;
- if (deep == 0) { // Nothing to do.
- return OK;
- }
-
if (lp->ll_tv == NULL) {
if (*lp->ll_name == '$') {
semsg(_(e_lock_unlock), lp->ll_name);
@@ -1037,9 +1046,13 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap
} else {
di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK);
}
- tv_item_lock(&di->di_tv, deep, lock, false);
+ if (deep != 0) {
+ tv_item_lock(&di->di_tv, deep, lock, false);
+ }
}
}
+ } else if (deep == 0) {
+ // nothing to do
} else if (lp->ll_range) {
listitem_T *li = lp->ll_li;
@@ -1099,7 +1112,7 @@ int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, boo
/// NULL when it doesn't exist.
///
/// @see tv_get_string() for how long the pointer remains valid.
-char_u *get_var_value(const char *const name)
+char *get_var_value(const char *const name)
{
dictitem_T *v;
@@ -1107,7 +1120,7 @@ char_u *get_var_value(const char *const name)
if (v == NULL) {
return NULL;
}
- return (char_u *)tv_get_string(&v->di_tv);
+ return (char *)tv_get_string(&v->di_tv);
}
/// Clean up a list of internal variables.
@@ -1118,7 +1131,7 @@ void vars_clear(hashtab_T *ht)
vars_clear_ext(ht, true);
}
-/// Like vars_clear(), but only free the value if "free_val" is TRUE.
+/// Like vars_clear(), but only free the value if "free_val" is true.
void vars_clear_ext(hashtab_T *ht, int free_val)
{
int todo;
@@ -1162,7 +1175,7 @@ void delete_var(hashtab_T *ht, hashitem_T *hi)
static void list_one_var(dictitem_T *v, const char *prefix, int *first)
{
char *const s = encode_tv2echo(&v->di_tv, NULL);
- list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)STRLEN(v->di_key),
+ list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)strlen((char *)v->di_key),
v->di_tv.v_type, (s == NULL ? "" : s), first);
xfree(s);
}
@@ -1258,7 +1271,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = find_var_in_scoped_ht(name, name_len, true);
}
- if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
+ if (tv_is_func(*tv) && var_wrong_func_name(name, v == NULL)) {
return;
}
@@ -1269,12 +1282,18 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
return;
}
- // existing variable, need to clear the value
+ // Check in this order for backwards compatibility:
+ // - Whether the variable is read-only
+ // - Whether the variable value is locked
+ // - Whether the variable is locked
if (var_check_ro(v->di_flags, name, name_len)
- || var_check_lock(v->di_tv.v_lock, name, name_len)) {
+ || value_check_lock(v->di_tv.v_lock, name, name_len)
+ || var_check_lock(v->di_flags, name, name_len)) {
return;
}
+ // existing variable, need to clear the value
+
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
if (is_vimvarht(ht)) {
@@ -1300,7 +1319,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
} else if (strcmp(varname, "hlsearch") == 0) {
no_hlsearch = !v->di_tv.vval.v_number;
- redraw_all_later(SOME_VALID);
+ redraw_all_later(UPD_SOME_VALID);
}
return;
} else if (v->di_tv.v_type != tv->v_type) {
@@ -1330,7 +1349,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = xmalloc(sizeof(dictitem_T) + strlen(varname));
STRCPY(v->di_key, varname);
- if (tv_dict_add(dict, v) == FAIL) {
+ if (hash_add(ht, (char *)v->di_key) == FAIL) {
xfree(v);
return;
}
@@ -1349,12 +1368,8 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
}
if (watched) {
- if (oldtv.v_type == VAR_UNKNOWN) {
- tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
- } else {
- tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
- tv_clear(&oldtv);
- }
+ tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
+ tv_clear(&oldtv);
}
if (is_const) {
@@ -1409,6 +1424,26 @@ bool var_check_ro(const int flags, const char *name, size_t name_len)
return true;
}
+/// Return true if di_flags "flags" indicates variable "name" is locked.
+/// Also give an error message.
+bool var_check_lock(const int flags, const char *name, size_t name_len)
+{
+ if (!(flags & DI_FLAGS_LOCK)) {
+ return false;
+ }
+
+ if (name_len == TV_TRANSLATE) {
+ name = _(name);
+ name_len = strlen(name);
+ } else if (name_len == TV_CSTRING) {
+ name_len = strlen(name);
+ }
+
+ semsg(_("E1122: Variable is locked: %*s"), (int)name_len, name);
+
+ return true;
+}
+
/// Check whether variable is fixed (DI_FLAGS_FIX)
///
/// Also gives an error message.
@@ -1443,37 +1478,34 @@ bool var_check_fixed(const int flags, const char *name, size_t name_len)
return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if name is a valid name to assign funcref to
///
/// @param[in] name Possible function/funcref name.
/// @param[in] new_var True if it is a name for a variable.
///
-/// @return false in case of error, true in case of success. Also gives an
+/// @return false in case of success, true in case of failure. Also gives an
/// error message if appropriate.
-bool var_check_func_name(const char *const name, const bool new_var)
+bool var_wrong_func_name(const char *const name, const bool new_var)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
// Allow for w: b: s: and t:.
- if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':')
- && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
- ? name[2] : name[0])) {
+ // Allow autoload variable.
+ if (!(vim_strchr("wbst", (uint8_t)name[0]) != NULL && name[1] == ':')
+ && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2] : name[0])
+ && vim_strchr(name, '#') == NULL) {
semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
- return false;
+ return true;
}
// Don't allow hiding a function. When "v" is not NULL we might be
// assigning another function to the same var, the type is checked
// below.
if (new_var && function_exists(name, false)) {
semsg(_("E705: Variable name conflicts with existing function: %s"), name);
- return false;
+ return true;
}
- return true;
+ return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if a variable name is valid
///
/// @param[in] varname Variable name to check.
@@ -1627,7 +1659,7 @@ static void set_option_from_tv(const char *varname, typval_T *varp)
strval = tv_get_string_buf_chk(varp, nbuf);
}
if (!error && strval != NULL) {
- set_option_value(varname, numval, strval, OPT_LOCAL);
+ set_option_value_give_err(varname, numval, strval, OPT_LOCAL);
}
}
@@ -1648,25 +1680,27 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
const char *varname = tv_get_string_chk(&argvars[off + 1]);
typval_T *varp = &argvars[off + 2];
- if (win != NULL && varname != NULL && varp != NULL) {
- bool need_switch_win = !(tp == curtab && win == curwin);
- switchwin_T switchwin;
- if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
- if (*varname == '&') {
- set_option_from_tv(varname + 1, varp);
- } else {
- const size_t varname_len = strlen(varname);
- char *const winvarname = xmalloc(varname_len + 3);
- memcpy(winvarname, "w:", 2);
- memcpy(winvarname + 2, varname, varname_len + 1);
- set_var(winvarname, varname_len + 2, varp, true);
- xfree(winvarname);
- }
- }
- if (need_switch_win) {
- restore_win(&switchwin, true);
+ if (win == NULL || varname == NULL) {
+ return;
+ }
+
+ bool need_switch_win = !(tp == curtab && win == curwin);
+ switchwin_T switchwin;
+ if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
+ if (*varname == '&') {
+ set_option_from_tv(varname + 1, varp);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const winvarname = xmalloc(varname_len + 3);
+ memcpy(winvarname, "w:", 2);
+ memcpy(winvarname + 2, varname, varname_len + 1);
+ set_var(winvarname, varname_len + 2, varp, true);
+ xfree(winvarname);
}
}
+ if (need_switch_win) {
+ restore_win(&switchwin, true);
+ }
}
bool var_exists(const char *var)
@@ -1702,7 +1736,7 @@ bool var_exists(const char *var)
}
/// "gettabvar()" function
-void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_gettabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const varname = tv_get_string_chk(&argvars[1]);
tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
@@ -1716,19 +1750,19 @@ void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "gettabwinvar()" function
-void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_gettabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getwinvar(argvars, rettv, 1);
}
/// "getwinvar()" function
-void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_getwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
getwinvar(argvars, rettv, 0);
}
/// "getbufvar()" function
-void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const varname = tv_get_string_chk(&argvars[1]);
buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
@@ -1737,7 +1771,7 @@ void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// "settabvar()" function
-void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
rettv->vval.v_number = 0;
@@ -1749,38 +1783,40 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const varname = tv_get_string_chk(&argvars[1]);
typval_T *const varp = &argvars[2];
- if (varname != NULL && tp != NULL) {
- tabpage_T *const save_curtab = curtab;
- goto_tabpage_tp(tp, false, false);
+ if (varname == NULL || tp == NULL) {
+ return;
+ }
- const size_t varname_len = strlen(varname);
- char *const tabvarname = xmalloc(varname_len + 3);
- memcpy(tabvarname, "t:", 2);
- memcpy(tabvarname + 2, varname, varname_len + 1);
- set_var(tabvarname, varname_len + 2, varp, true);
- xfree(tabvarname);
-
- // Restore current tabpage.
- if (valid_tabpage(save_curtab)) {
- goto_tabpage_tp(save_curtab, false, false);
- }
+ tabpage_T *const save_curtab = curtab;
+ goto_tabpage_tp(tp, false, false);
+
+ const size_t varname_len = strlen(varname);
+ char *const tabvarname = xmalloc(varname_len + 3);
+ memcpy(tabvarname, "t:", 2);
+ memcpy(tabvarname + 2, varname, varname_len + 1);
+ set_var(tabvarname, varname_len + 2, varp, true);
+ xfree(tabvarname);
+
+ // Restore current tabpage.
+ if (valid_tabpage(save_curtab)) {
+ goto_tabpage_tp(save_curtab, false, false);
}
}
/// "settabwinvar()" function
-void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
setwinvar(argvars, rettv, 1);
}
/// "setwinvar()" function
-void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
setwinvar(argvars, rettv, 0);
}
/// "setbufvar()" function
-void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()
|| !tv_check_str_or_nr(&argvars[0])) {
@@ -1790,27 +1826,29 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
buf_T *const buf = tv_get_buf(&argvars[0], false);
typval_T *varp = &argvars[2];
- if (buf != NULL && varname != NULL) {
- if (*varname == '&') {
- aco_save_T aco;
+ if (buf == NULL || varname == NULL) {
+ return;
+ }
- // set curbuf to be our buf, temporarily
- aucmd_prepbuf(&aco, buf);
+ if (*varname == '&') {
+ aco_save_T aco;
- set_option_from_tv(varname + 1, varp);
+ // Set curbuf to be our buf, temporarily.
+ aucmd_prepbuf(&aco, buf);
- // reset notion of buffer
- aucmd_restbuf(&aco);
- } else {
- const size_t varname_len = STRLEN(varname);
- char *const bufvarname = xmalloc(varname_len + 3);
- buf_T *const save_curbuf = curbuf;
- curbuf = buf;
- memcpy(bufvarname, "b:", 2);
- memcpy(bufvarname + 2, varname, varname_len + 1);
- set_var(bufvarname, varname_len + 2, varp, true);
- xfree(bufvarname);
- curbuf = save_curbuf;
- }
+ set_option_from_tv(varname + 1, varp);
+
+ // reset notion of buffer
+ aucmd_restbuf(&aco);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const bufvarname = xmalloc(varname_len + 3);
+ buf_T *const save_curbuf = curbuf;
+ curbuf = buf;
+ memcpy(bufvarname, "b:", 2);
+ memcpy(bufvarname + 2, varname, varname_len + 1);
+ set_var(bufvarname, varname_len + 2, varp, true);
+ xfree(bufvarname);
+ curbuf = save_curbuf;
}
}
diff --git a/src/nvim/eval/vars.h b/src/nvim/eval/vars.h
index 73efc4938a..b87c9d62cb 100644
--- a/src/nvim/eval/vars.h
+++ b/src/nvim/eval/vars.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EVAL_VARS_H
#define NVIM_EVAL_VARS_H
-#include "nvim/ex_cmds_defs.h" // For exarg_T
+#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/vars.h.generated.h"
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
new file mode 100644
index 0000000000..f58a0c488a
--- /dev/null
+++ b/src/nvim/eval/window.c
@@ -0,0 +1,954 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// eval/window.c: Window related builtin functions
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/cursor.h"
+#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/window.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/macros.h"
+#include "nvim/memline_defs.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/move.h"
+#include "nvim/option_defs.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/window.c.generated.h"
+#endif
+
+static char *e_invalwindow = N_("E957: Invalid window number");
+static char e_cannot_resize_window_in_another_tab_page[]
+ = N_("E1308: Cannot resize a window in another tab page");
+
+static int win_getid(typval_T *argvars)
+{
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ return curwin->handle;
+ }
+ int winnr = (int)tv_get_number(&argvars[0]);
+ win_T *wp;
+ if (winnr <= 0) {
+ return 0;
+ }
+
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ wp = firstwin;
+ } else {
+ tabpage_T *tp = NULL;
+ int tabnr = (int)tv_get_number(&argvars[1]);
+ FOR_ALL_TABS(tp2) {
+ if (--tabnr == 0) {
+ tp = tp2;
+ break;
+ }
+ }
+ if (tp == NULL) {
+ return -1;
+ }
+ if (tp == curtab) {
+ wp = firstwin;
+ } else {
+ wp = tp->tp_firstwin;
+ }
+ }
+ for (; wp != NULL; wp = wp->w_next) {
+ if (--winnr == 0) {
+ return wp->handle;
+ }
+ }
+ return 0;
+}
+
+static void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
+{
+ handle_T id = (handle_T)tv_get_number(&argvars[0]);
+
+ int winnr = 1;
+ int tabnr = 1;
+ win_get_tabwin(id, &tabnr, &winnr);
+
+ list_T *const list = tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(list, tabnr);
+ tv_list_append_number(list, winnr);
+}
+
+win_T *win_id2wp(int id)
+{
+ return win_id2wp_tp(id, NULL);
+}
+
+/// Return the window and tab pointer of window "id".
+win_T *win_id2wp_tp(int id, tabpage_T **tpp)
+{
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ if (tpp != NULL) {
+ *tpp = tp;
+ }
+ return wp;
+ }
+ }
+
+ return NULL;
+}
+
+static int win_id2win(typval_T *argvars)
+{
+ int nr = 1;
+ int id = (int)tv_get_number(&argvars[0]);
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->handle == id) {
+ return nr;
+ }
+ nr++;
+ }
+ return 0;
+}
+
+void win_findbuf(typval_T *argvars, list_T *list)
+{
+ int bufnr = (int)tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer->b_fnum == bufnr) {
+ tv_list_append_number(list, wp->handle);
+ }
+ }
+}
+
+/// Find window specified by "vp" in tabpage "tp".
+///
+/// @param tp NULL for current tab page
+/// @return current window if "vp" is number zero.
+/// NULL if not found.
+win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr < 0) {
+ return NULL;
+ }
+
+ if (nr == 0) {
+ return curwin;
+ }
+
+ // This method accepts NULL as an alias for curtab.
+ if (tp == NULL) {
+ tp = curtab;
+ }
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ if (nr >= LOWEST_WIN_ID) {
+ if (wp->handle == nr) {
+ return wp;
+ }
+ } else if (--nr <= 0) {
+ return wp;
+ }
+ }
+ return NULL;
+}
+
+/// Find a window: When using a Window ID in any tab page, when using a number
+/// in the current tab page.
+win_T *find_win_by_nr_or_id(typval_T *vp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr >= LOWEST_WIN_ID) {
+ return win_id2wp((int)tv_get_number(vp));
+ }
+
+ return find_win_by_nr(vp, NULL);
+}
+
+/// Find window specified by "wvp" in tabpage "tvp".
+win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
+{
+ win_T *wp = NULL;
+ tabpage_T *tp = NULL;
+
+ if (wvp->v_type != VAR_UNKNOWN) {
+ if (tvp->v_type != VAR_UNKNOWN) {
+ long n = tv_get_number(tvp);
+ if (n >= 0) {
+ tp = find_tabpage((int)n);
+ }
+ } else {
+ tp = curtab;
+ }
+
+ if (tp != NULL) {
+ wp = find_win_by_nr(wvp, tp);
+ }
+ } else {
+ wp = curwin;
+ }
+
+ return wp;
+}
+
+/// Get the layout of the given tab page for winlayout().
+static void get_framelayout(const frame_T *fr, list_T *l, bool outer)
+{
+ if (fr == NULL) {
+ return;
+ }
+
+ list_T *fr_list;
+ if (outer) {
+ // outermost call from f_winlayout()
+ fr_list = l;
+ } else {
+ fr_list = tv_list_alloc(2);
+ tv_list_append_list(l, fr_list);
+ }
+
+ if (fr->fr_layout == FR_LEAF) {
+ if (fr->fr_win != NULL) {
+ tv_list_append_string(fr_list, "leaf", -1);
+ tv_list_append_number(fr_list, fr->fr_win->handle);
+ }
+ } else {
+ tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
+
+ list_T *const win_list = tv_list_alloc(kListLenUnknown);
+ tv_list_append_list(fr_list, win_list);
+ const frame_T *child = fr->fr_child;
+ while (child != NULL) {
+ get_framelayout(child, win_list, false);
+ child = child->fr_next;
+ }
+ }
+}
+
+/// Common code for tabpagewinnr() and winnr().
+static int get_winnr(tabpage_T *tp, typval_T *argvar)
+{
+ int nr = 1;
+
+ win_T *twin = (tp == curtab) ? curwin : tp->tp_curwin;
+ if (argvar->v_type != VAR_UNKNOWN) {
+ bool invalid_arg = false;
+ const char *const arg = tv_get_string_chk(argvar);
+ if (arg == NULL) {
+ nr = 0; // Type error; errmsg already given.
+ } else if (strcmp(arg, "$") == 0) {
+ twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
+ } else if (strcmp(arg, "#") == 0) {
+ twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
+ if (twin == NULL) {
+ nr = 0;
+ }
+ } else {
+ // Extract the window count (if specified). e.g. winnr('3j')
+ char *endp;
+ long count = strtol((char *)arg, &endp, 10);
+ if (count <= 0) {
+ // if count is not specified, default to 1
+ count = 1;
+ }
+ if (endp != NULL && *endp != '\0') {
+ if (strequal(endp, "j")) {
+ twin = win_vert_neighbor(tp, twin, false, count);
+ } else if (strequal(endp, "k")) {
+ twin = win_vert_neighbor(tp, twin, true, count);
+ } else if (strequal(endp, "h")) {
+ twin = win_horz_neighbor(tp, twin, true, count);
+ } else if (strequal(endp, "l")) {
+ twin = win_horz_neighbor(tp, twin, false, count);
+ } else {
+ invalid_arg = true;
+ }
+ } else {
+ invalid_arg = true;
+ }
+ }
+
+ if (invalid_arg) {
+ semsg(_(e_invexpr2), arg);
+ nr = 0;
+ }
+ }
+
+ if (nr <= 0) {
+ return 0;
+ }
+
+ for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ wp != twin; wp = wp->w_next) {
+ if (wp == NULL) {
+ // didn't find it in this tabpage
+ nr = 0;
+ break;
+ }
+ nr++;
+ }
+ return nr;
+}
+
+/// @return information about a window as a dictionary.
+static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ // make sure w_botline is valid
+ validate_botline(wp);
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
+ tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
+ tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
+ tv_dict_add_nr(dict, S_LEN("height"), wp->w_height_inner);
+ tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
+ tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
+ tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
+ tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
+ tv_dict_add_nr(dict, S_LEN("width"), wp->w_width_inner);
+ tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
+ tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
+ tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
+ tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("loclist"),
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
+
+ // Add a reference to window variables
+ tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
+
+ return dict;
+}
+
+/// @return information (variables, options, etc.) about a tab page
+/// as a dictionary.
+static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
+
+ list_T *const l = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ tv_list_append_number(l, (varnumber_T)wp->handle);
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), l);
+
+ // Make a reference to tabpage variables
+ tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
+
+ return dict;
+}
+
+/// "gettabinfo()" function
+void f_gettabinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tabpage_T *tparg = NULL;
+
+ tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
+ ? 1
+ : kListLenMayKnow));
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ // Information about one tab page
+ tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ if (tparg == NULL) {
+ return;
+ }
+ }
+
+ // Get information about a specific tab page or all tab pages
+ int tpnr = 0;
+ FOR_ALL_TABS(tp) {
+ tpnr++;
+ if (tparg != NULL && tp != tparg) {
+ continue;
+ }
+ dict_T *const d = get_tabpage_info(tp, tpnr);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (tparg != NULL) {
+ return;
+ }
+ }
+}
+
+/// "getwininfo()" function
+void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wparg = NULL;
+
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wparg = win_id2wp((int)tv_get_number(&argvars[0]));
+ if (wparg == NULL) {
+ return;
+ }
+ }
+
+ // Collect information about either all the windows across all the tab
+ // pages or one particular window.
+ int16_t tabnr = 0;
+ FOR_ALL_TABS(tp) {
+ tabnr++;
+ int16_t winnr = 0;
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ winnr++;
+ if (wparg != NULL && wp != wparg) {
+ continue;
+ }
+ dict_T *const d = get_win_info(wp, tabnr, winnr);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (wparg != NULL) {
+ // found information about a specific window
+ return;
+ }
+ }
+ }
+}
+
+/// "getwinpos({timeout})" function
+void f_getwinpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+}
+
+/// "getwinposx()" function
+void f_getwinposx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+}
+
+/// "getwinposy()" function
+void f_getwinposy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+}
+
+/// "tabpagenr()" function
+void f_tabpagenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int nr = 1;
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ const char *const arg = tv_get_string_chk(&argvars[0]);
+ nr = 0;
+ if (arg != NULL) {
+ if (strcmp(arg, "$") == 0) {
+ nr = tabpage_index(NULL) - 1;
+ } else if (strcmp(arg, "#") == 0) {
+ nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0;
+ } else {
+ semsg(_(e_invexpr2), arg);
+ }
+ }
+ } else {
+ nr = tabpage_index(curtab);
+ }
+ rettv->vval.v_number = nr;
+}
+
+/// "tabpagewinnr()" function
+void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int nr = 1;
+ tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ nr = 0;
+ } else {
+ nr = get_winnr(tp, &argvars[1]);
+ }
+ rettv->vval.v_number = nr;
+}
+
+/// "win_execute(win_id, command)" function
+void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ // Return an empty string if something fails.
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ int id = (int)tv_get_number(argvars);
+ tabpage_T *tp;
+ win_T *wp = win_id2wp_tp(id, &tp);
+ if (wp == NULL || tp == NULL) {
+ return;
+ }
+
+ WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1));
+}
+
+/// "win_findbuf()" function
+void f_win_findbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ win_findbuf(argvars, rettv->vval.v_list);
+}
+
+/// "win_getid()" function
+void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = win_getid(argvars);
+}
+
+/// "win_gotoid()" function
+void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int id = (int)tv_get_number(&argvars[0]);
+
+ if (cmdwin_type != 0) {
+ emsg(_(e_cmdwin));
+ return;
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ goto_tabpage_win(tp, wp);
+ rettv->vval.v_number = 1;
+ return;
+ }
+ }
+}
+
+/// "win_id2tabwin()" function
+void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_id2tabwin(argvars, rettv);
+}
+
+/// "win_id2win()" function
+void f_win_id2win(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = win_id2win(argvars);
+}
+
+/// "win_move_separator()" function
+void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = false;
+
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL || wp->w_floating) {
+ return;
+ }
+ if (!win_valid(wp)) {
+ emsg(_(e_cannot_resize_window_in_another_tab_page));
+ return;
+ }
+
+ int offset = (int)tv_get_number(&argvars[1]);
+ win_drag_vsep_line(wp, offset);
+ rettv->vval.v_number = true;
+}
+
+/// "win_move_statusline()" function
+void f_win_move_statusline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp;
+ int offset;
+
+ rettv->vval.v_number = false;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL || wp->w_floating) {
+ return;
+ }
+ if (!win_valid(wp)) {
+ emsg(_(e_cannot_resize_window_in_another_tab_page));
+ return;
+ }
+
+ offset = (int)tv_get_number(&argvars[1]);
+ win_drag_status_line(wp, offset);
+ rettv->vval.v_number = true;
+}
+
+/// "win_screenpos()" function
+void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, 2);
+ const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
+ tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
+ tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
+}
+
+/// Move the window wp into a new split of targetwin in a given direction
+static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
+{
+ int height = wp->w_height;
+ win_T *oldwin = curwin;
+
+ if (wp == targetwin || is_aucmd_win(wp)) {
+ return;
+ }
+
+ // Jump to the target window
+ if (curwin != targetwin) {
+ win_goto(targetwin);
+ }
+
+ // Remove the old window and frame from the tree of frames
+ int dir;
+ (void)winframe_remove(wp, &dir, NULL);
+ win_remove(wp, NULL);
+ last_status(false); // may need to remove last status line
+ (void)win_comp_pos(); // recompute window positions
+
+ // Split a window on the desired side and put the old window there
+ (void)win_split_ins(size, flags, wp, dir);
+
+ // If splitting horizontally, try to preserve height
+ if (size == 0 && !(flags & WSP_VERT)) {
+ win_setheight_win(height, wp);
+ if (p_ea) {
+ win_equal(wp, true, 'v');
+ }
+ }
+
+ if (oldwin != curwin) {
+ win_goto(oldwin);
+ }
+}
+
+/// "win_splitmove()" function
+void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ win_T *targetwin = find_win_by_nr_or_id(&argvars[1]);
+
+ if (wp == NULL || targetwin == NULL || wp == targetwin
+ || !win_valid(wp) || !win_valid(targetwin)
+ || win_valid_floating(wp) || win_valid_floating(targetwin)) {
+ emsg(_(e_invalwindow));
+ rettv->vval.v_number = -1;
+ return;
+ }
+
+ int flags = 0, size = 0;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ dict_T *d;
+ dictitem_T *di;
+
+ if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ d = argvars[2].vval.v_dict;
+ if (tv_dict_get_number(d, "vertical")) {
+ flags |= WSP_VERT;
+ }
+ if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
+ flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
+ }
+ size = (int)tv_dict_get_number(d, "size");
+ }
+
+ win_move_into_split(wp, targetwin, size, flags);
+}
+
+/// "win_gettype(nr)" function
+void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = curwin;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_string = xstrdup("unknown");
+ return;
+ }
+ }
+ if (is_aucmd_win(wp)) {
+ rettv->vval.v_string = xstrdup("autocmd");
+ } else if (wp->w_p_pvw) {
+ rettv->vval.v_string = xstrdup("preview");
+ } else if (wp->w_floating) {
+ rettv->vval.v_string = xstrdup("popup");
+ } else if (wp == curwin && cmdwin_type != 0) {
+ rettv->vval.v_string = xstrdup("command");
+ } else if (bt_quickfix(wp->w_buffer)) {
+ rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
+ }
+}
+
+/// "getcmdwintype()" function
+void f_getcmdwintype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ rettv->vval.v_string = xmallocz(1);
+ rettv->vval.v_string[0] = (char)cmdwin_type;
+}
+
+/// "winbufnr(nr)" function
+void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_buffer->b_fnum;
+ }
+}
+
+/// "wincol()" function
+void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wcol + 1;
+}
+
+/// "winheight(nr)" function
+void f_winheight(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_height_inner;
+ }
+}
+
+/// "winlayout()" function
+void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tabpage_T *tp;
+
+ tv_list_alloc_ret(rettv, 2);
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ return;
+ }
+ }
+
+ get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
+}
+
+/// "winline()" function
+void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wrow + 1;
+}
+
+/// "winnr()" function
+void f_winnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = get_winnr(curtab, &argvars[0]);
+}
+
+/// "winrestcmd()" function
+void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ char buf[50];
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 70);
+
+ // Do this twice to handle some window layouts properly.
+ for (int i = 0; i < 2; i++) {
+ int winnr = 1;
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ snprintf(buf, sizeof(buf), "%dresize %d|", winnr,
+ wp->w_height);
+ ga_concat(&ga, buf);
+ snprintf(buf, sizeof(buf), "vert %dresize %d|", winnr,
+ wp->w_width);
+ ga_concat(&ga, buf);
+ winnr++;
+ }
+ }
+ ga_append(&ga, NUL);
+
+ rettv->vval.v_string = ga.ga_data;
+ rettv->v_type = VAR_STRING;
+}
+
+/// "winrestview()" function
+void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ dict_T *dict = argvars[0].vval.v_dict;
+
+ if (argvars[0].v_type != VAR_DICT || dict == NULL) {
+ emsg(_(e_invarg));
+ } else {
+ dictitem_T *di;
+ if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
+ curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
+ curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
+ curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
+ curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
+ curwin->w_set_curswant = false;
+ }
+ if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
+ set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
+ }
+ if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
+ curwin->w_topfill = (int)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
+ curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
+ curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
+ }
+
+ check_cursor();
+ win_new_height(curwin, curwin->w_height);
+ win_new_width(curwin, curwin->w_width);
+ changed_window_setting();
+
+ if (curwin->w_topline <= 0) {
+ curwin->w_topline = 1;
+ }
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+ }
+ check_topfill(curwin, true);
+ }
+}
+
+/// "winsaveview()" function
+void f_winsaveview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_dict_alloc_ret(rettv);
+ dict_T *dict = rettv->vval.v_dict;
+
+ tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
+ tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
+ tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
+ update_curswant();
+ tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
+
+ tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
+ tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
+ tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
+ tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
+}
+
+/// "winwidth(nr)" function
+void f_winwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_width_inner;
+ }
+}
+
+/// Set "win" to be the curwin and "tp" to be the current tab page.
+/// restore_win() MUST be called to undo, also when FAIL is returned.
+/// No autocommands will be executed until restore_win() is called.
+///
+/// @param no_display if true the display won't be affected, no redraw is
+/// triggered, another tabpage access is limited.
+///
+/// @return FAIL if switching to "win" failed.
+int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
+{
+ block_autocmds();
+ return switch_win_noblock(switchwin, win, tp, no_display);
+}
+
+// As switch_win() but without blocking autocommands.
+int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
+{
+ CLEAR_POINTER(switchwin);
+ switchwin->sw_curwin = curwin;
+ if (win == curwin) {
+ switchwin->sw_same_win = true;
+ } else {
+ // Disable Visual selection, because redrawing may fail.
+ switchwin->sw_visual_active = VIsual_active;
+ VIsual_active = false;
+ }
+
+ if (tp != NULL) {
+ switchwin->sw_curtab = curtab;
+ if (no_display) {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = tp;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ } else {
+ goto_tabpage_tp(tp, false, false);
+ }
+ }
+ if (!win_valid(win)) {
+ return FAIL;
+ }
+ curwin = win;
+ curbuf = curwin->w_buffer;
+ return OK;
+}
+
+// Restore current tabpage and window saved by switch_win(), if still valid.
+// When "no_display" is true the display won't be affected, no redraw is
+// triggered.
+void restore_win(switchwin_T *switchwin, bool no_display)
+{
+ restore_win_noblock(switchwin, no_display);
+ unblock_autocmds();
+}
+
+// As restore_win() but without unblocking autocommands.
+void restore_win_noblock(switchwin_T *switchwin, bool no_display)
+{
+ if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
+ if (no_display) {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = switchwin->sw_curtab;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ } else {
+ goto_tabpage_tp(switchwin->sw_curtab, false, false);
+ }
+ }
+
+ if (!switchwin->sw_same_win) {
+ VIsual_active = switchwin->sw_visual_active;
+ }
+
+ if (win_valid(switchwin->sw_curwin)) {
+ curwin = switchwin->sw_curwin;
+ curbuf = curwin->w_buffer;
+ }
+}
diff --git a/src/nvim/eval/window.h b/src/nvim/eval/window.h
new file mode 100644
index 0000000000..995f0a55a9
--- /dev/null
+++ b/src/nvim/eval/window.h
@@ -0,0 +1,78 @@
+#ifndef NVIM_EVAL_WINDOW_H
+#define NVIM_EVAL_WINDOW_H
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/cursor.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/globals.h"
+#include "nvim/mark.h"
+#include "nvim/option_defs.h"
+#include "nvim/os/os.h"
+#include "nvim/pos.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+/// Structure used by switch_win() to pass values to restore_win()
+typedef struct {
+ win_T *sw_curwin;
+ tabpage_T *sw_curtab;
+ bool sw_same_win; ///< VIsual_active was not reset
+ bool sw_visual_active;
+} switchwin_T;
+
+/// Execute a block of code in the context of window `wp` in tabpage `tp`.
+/// Ensures the status line is redrawn and cursor position is valid if it is moved.
+#define WIN_EXECUTE(wp, tp, block) \
+ do { \
+ win_T *const wp_ = (wp); \
+ const pos_T curpos_ = wp_->w_cursor; \
+ char cwd_[MAXPATHL]; \
+ char autocwd_[MAXPATHL]; \
+ bool apply_acd_ = false; \
+ int cwd_status_ = FAIL; \
+ /* Getting and setting directory can be slow on some systems, only do */ \
+ /* this when the current or target window/tab have a local directory or */ \
+ /* 'acd' is set. */ \
+ if (curwin != wp \
+ && (curwin->w_localdir != NULL || wp->w_localdir != NULL \
+ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
+ || p_acd)) { \
+ cwd_status_ = os_dirname(cwd_, MAXPATHL); \
+ } \
+ /* If 'acd' is set, check we are using that directory. If yes, then */ \
+ /* apply 'acd' afterwards, otherwise restore the current directory. */ \
+ if (cwd_status_ == OK && p_acd) { \
+ do_autochdir(); \
+ apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \
+ } \
+ switchwin_T switchwin_; \
+ if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
+ check_cursor(); \
+ block; \
+ } \
+ restore_win_noblock(&switchwin_, true); \
+ if (apply_acd_) { \
+ do_autochdir(); \
+ } else if (cwd_status_ == OK) { \
+ os_chdir(cwd_); \
+ } \
+ /* Update the status line if the cursor moved. */ \
+ if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
+ wp_->w_redr_status = true; \
+ } \
+ /* In case the command moved the cursor or changed the Visual area, */ \
+ /* check it is valid. */ \
+ check_cursor(); \
+ if (VIsual_active) { \
+ check_pos(curbuf, &VIsual); \
+ } \
+ } while (false)
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/window.h.generated.h"
+#endif
+#endif // NVIM_EVAL_WINDOW_H