blob: 7213e0d19ce8fec97525ad3570766f7d5bda639b [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020024# include <time.h> /* for time_t */
25#endif
26
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010027static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020029
30#ifdef FEAT_FLOAT
31static void f_abs(typval_T *argvars, typval_T *rettv);
32static void f_acos(typval_T *argvars, typval_T *rettv);
33#endif
34static void f_add(typval_T *argvars, typval_T *rettv);
35static void f_and(typval_T *argvars, typval_T *rettv);
36static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020037static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020038static void f_argc(typval_T *argvars, typval_T *rettv);
39static void f_argidx(typval_T *argvars, typval_T *rettv);
40static void f_arglistid(typval_T *argvars, typval_T *rettv);
41static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020042#ifdef FEAT_FLOAT
43static void f_asin(typval_T *argvars, typval_T *rettv);
44static void f_atan(typval_T *argvars, typval_T *rettv);
45static void f_atan2(typval_T *argvars, typval_T *rettv);
46#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010047#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020048static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010049static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010050# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010051static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010052# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010053#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_browse(typval_T *argvars, typval_T *rettv);
55static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020056static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_bufexists(typval_T *argvars, typval_T *rettv);
58static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020059static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020060static void f_bufloaded(typval_T *argvars, typval_T *rettv);
61static void f_bufname(typval_T *argvars, typval_T *rettv);
62static void f_bufnr(typval_T *argvars, typval_T *rettv);
63static void f_bufwinid(typval_T *argvars, typval_T *rettv);
64static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
65static void f_byte2line(typval_T *argvars, typval_T *rettv);
66static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
67static void f_byteidx(typval_T *argvars, typval_T *rettv);
68static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
69static void f_call(typval_T *argvars, typval_T *rettv);
70#ifdef FEAT_FLOAT
71static void f_ceil(typval_T *argvars, typval_T *rettv);
72#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_changenr(typval_T *argvars, typval_T *rettv);
74static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020075static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077static void f_col(typval_T *argvars, typval_T *rettv);
78#if defined(FEAT_INS_EXPAND)
79static void f_complete(typval_T *argvars, typval_T *rettv);
80static void f_complete_add(typval_T *argvars, typval_T *rettv);
81static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +010082static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083#endif
84static void f_confirm(typval_T *argvars, typval_T *rettv);
85static void f_copy(typval_T *argvars, typval_T *rettv);
86#ifdef FEAT_FLOAT
87static void f_cos(typval_T *argvars, typval_T *rettv);
88static void f_cosh(typval_T *argvars, typval_T *rettv);
89#endif
90static void f_count(typval_T *argvars, typval_T *rettv);
91static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
92static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010093#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020094static void f_debugbreak(typval_T *argvars, typval_T *rettv);
95#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_deepcopy(typval_T *argvars, typval_T *rettv);
97static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020098static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_did_filetype(typval_T *argvars, typval_T *rettv);
100static void f_diff_filler(typval_T *argvars, typval_T *rettv);
101static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
102static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200103static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_escape(typval_T *argvars, typval_T *rettv);
105static void f_eval(typval_T *argvars, typval_T *rettv);
106static void f_eventhandler(typval_T *argvars, typval_T *rettv);
107static void f_executable(typval_T *argvars, typval_T *rettv);
108static void f_execute(typval_T *argvars, typval_T *rettv);
109static void f_exepath(typval_T *argvars, typval_T *rettv);
110static void f_exists(typval_T *argvars, typval_T *rettv);
111#ifdef FEAT_FLOAT
112static void f_exp(typval_T *argvars, typval_T *rettv);
113#endif
114static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200115static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200116static void f_extend(typval_T *argvars, typval_T *rettv);
117static void f_feedkeys(typval_T *argvars, typval_T *rettv);
118static void f_filereadable(typval_T *argvars, typval_T *rettv);
119static void f_filewritable(typval_T *argvars, typval_T *rettv);
120static void f_filter(typval_T *argvars, typval_T *rettv);
121static void f_finddir(typval_T *argvars, typval_T *rettv);
122static void f_findfile(typval_T *argvars, typval_T *rettv);
123#ifdef FEAT_FLOAT
124static void f_float2nr(typval_T *argvars, typval_T *rettv);
125static void f_floor(typval_T *argvars, typval_T *rettv);
126static void f_fmod(typval_T *argvars, typval_T *rettv);
127#endif
128static void f_fnameescape(typval_T *argvars, typval_T *rettv);
129static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
130static void f_foldclosed(typval_T *argvars, typval_T *rettv);
131static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
132static void f_foldlevel(typval_T *argvars, typval_T *rettv);
133static void f_foldtext(typval_T *argvars, typval_T *rettv);
134static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
135static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200136static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_function(typval_T *argvars, typval_T *rettv);
138static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
139static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200140static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_getbufline(typval_T *argvars, typval_T *rettv);
142static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100143static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200144static void f_getchar(typval_T *argvars, typval_T *rettv);
145static void f_getcharmod(typval_T *argvars, typval_T *rettv);
146static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
147static void f_getcmdline(typval_T *argvars, typval_T *rettv);
148#if defined(FEAT_CMDL_COMPL)
149static void f_getcompletion(typval_T *argvars, typval_T *rettv);
150#endif
151static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
152static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
153static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
154static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200155static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_getfontname(typval_T *argvars, typval_T *rettv);
157static void f_getfperm(typval_T *argvars, typval_T *rettv);
158static void f_getfsize(typval_T *argvars, typval_T *rettv);
159static void f_getftime(typval_T *argvars, typval_T *rettv);
160static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100161static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200163static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200164static void f_getpid(typval_T *argvars, typval_T *rettv);
165static void f_getcurpos(typval_T *argvars, typval_T *rettv);
166static void f_getpos(typval_T *argvars, typval_T *rettv);
167static void f_getqflist(typval_T *argvars, typval_T *rettv);
168static void f_getreg(typval_T *argvars, typval_T *rettv);
169static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200170static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_gettabvar(typval_T *argvars, typval_T *rettv);
172static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100173static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200174static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100175static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200176static void f_getwinposx(typval_T *argvars, typval_T *rettv);
177static void f_getwinposy(typval_T *argvars, typval_T *rettv);
178static void f_getwinvar(typval_T *argvars, typval_T *rettv);
179static void f_glob(typval_T *argvars, typval_T *rettv);
180static void f_globpath(typval_T *argvars, typval_T *rettv);
181static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
182static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200183static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
184static void f_hasmapto(typval_T *argvars, typval_T *rettv);
185static void f_histadd(typval_T *argvars, typval_T *rettv);
186static void f_histdel(typval_T *argvars, typval_T *rettv);
187static void f_histget(typval_T *argvars, typval_T *rettv);
188static void f_histnr(typval_T *argvars, typval_T *rettv);
189static void f_hlID(typval_T *argvars, typval_T *rettv);
190static void f_hlexists(typval_T *argvars, typval_T *rettv);
191static void f_hostname(typval_T *argvars, typval_T *rettv);
192static void f_iconv(typval_T *argvars, typval_T *rettv);
193static void f_indent(typval_T *argvars, typval_T *rettv);
194static void f_index(typval_T *argvars, typval_T *rettv);
195static void f_input(typval_T *argvars, typval_T *rettv);
196static void f_inputdialog(typval_T *argvars, typval_T *rettv);
197static void f_inputlist(typval_T *argvars, typval_T *rettv);
198static void f_inputrestore(typval_T *argvars, typval_T *rettv);
199static void f_inputsave(typval_T *argvars, typval_T *rettv);
200static void f_inputsecret(typval_T *argvars, typval_T *rettv);
201static void f_insert(typval_T *argvars, typval_T *rettv);
202static void f_invert(typval_T *argvars, typval_T *rettv);
203static void f_isdirectory(typval_T *argvars, typval_T *rettv);
204static void f_islocked(typval_T *argvars, typval_T *rettv);
205#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200206static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_isnan(typval_T *argvars, typval_T *rettv);
208#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
210static void f_len(typval_T *argvars, typval_T *rettv);
211static void f_libcall(typval_T *argvars, typval_T *rettv);
212static void f_libcallnr(typval_T *argvars, typval_T *rettv);
213static void f_line(typval_T *argvars, typval_T *rettv);
214static void f_line2byte(typval_T *argvars, typval_T *rettv);
215static void f_lispindent(typval_T *argvars, typval_T *rettv);
216static void f_localtime(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_log(typval_T *argvars, typval_T *rettv);
219static void f_log10(typval_T *argvars, typval_T *rettv);
220#endif
221#ifdef FEAT_LUA
222static void f_luaeval(typval_T *argvars, typval_T *rettv);
223#endif
224static void f_map(typval_T *argvars, typval_T *rettv);
225static void f_maparg(typval_T *argvars, typval_T *rettv);
226static void f_mapcheck(typval_T *argvars, typval_T *rettv);
227static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200228static void f_matchend(typval_T *argvars, typval_T *rettv);
229static void f_matchlist(typval_T *argvars, typval_T *rettv);
230static void f_matchstr(typval_T *argvars, typval_T *rettv);
231static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
232static void f_max(typval_T *argvars, typval_T *rettv);
233static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_mode(typval_T *argvars, typval_T *rettv);
236#ifdef FEAT_MZSCHEME
237static void f_mzeval(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
240static void f_nr2char(typval_T *argvars, typval_T *rettv);
241static void f_or(typval_T *argvars, typval_T *rettv);
242static void f_pathshorten(typval_T *argvars, typval_T *rettv);
243#ifdef FEAT_PERL
244static void f_perleval(typval_T *argvars, typval_T *rettv);
245#endif
246#ifdef FEAT_FLOAT
247static void f_pow(typval_T *argvars, typval_T *rettv);
248#endif
249static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
250static void f_printf(typval_T *argvars, typval_T *rettv);
251static void f_pumvisible(typval_T *argvars, typval_T *rettv);
252#ifdef FEAT_PYTHON3
253static void f_py3eval(typval_T *argvars, typval_T *rettv);
254#endif
255#ifdef FEAT_PYTHON
256static void f_pyeval(typval_T *argvars, typval_T *rettv);
257#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100258#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
259static void f_pyxeval(typval_T *argvars, typval_T *rettv);
260#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200262static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200263static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200264static void f_reg_executing(typval_T *argvars, typval_T *rettv);
265static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200266static void f_reltime(typval_T *argvars, typval_T *rettv);
267#ifdef FEAT_FLOAT
268static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_reltimestr(typval_T *argvars, typval_T *rettv);
271static void f_remote_expr(typval_T *argvars, typval_T *rettv);
272static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
273static void f_remote_peek(typval_T *argvars, typval_T *rettv);
274static void f_remote_read(typval_T *argvars, typval_T *rettv);
275static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100276static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200277static void f_remove(typval_T *argvars, typval_T *rettv);
278static void f_rename(typval_T *argvars, typval_T *rettv);
279static void f_repeat(typval_T *argvars, typval_T *rettv);
280static void f_resolve(typval_T *argvars, typval_T *rettv);
281static void f_reverse(typval_T *argvars, typval_T *rettv);
282#ifdef FEAT_FLOAT
283static void f_round(typval_T *argvars, typval_T *rettv);
284#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100285#ifdef FEAT_RUBY
286static void f_rubyeval(typval_T *argvars, typval_T *rettv);
287#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288static void f_screenattr(typval_T *argvars, typval_T *rettv);
289static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100290static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200291static void f_screencol(typval_T *argvars, typval_T *rettv);
292static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100293static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200294static void f_search(typval_T *argvars, typval_T *rettv);
295static void f_searchdecl(typval_T *argvars, typval_T *rettv);
296static void f_searchpair(typval_T *argvars, typval_T *rettv);
297static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
298static void f_searchpos(typval_T *argvars, typval_T *rettv);
299static void f_server2client(typval_T *argvars, typval_T *rettv);
300static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200301static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_setbufvar(typval_T *argvars, typval_T *rettv);
303static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
304static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200305static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306static void f_setfperm(typval_T *argvars, typval_T *rettv);
307static void f_setline(typval_T *argvars, typval_T *rettv);
308static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309static void f_setpos(typval_T *argvars, typval_T *rettv);
310static void f_setqflist(typval_T *argvars, typval_T *rettv);
311static void f_setreg(typval_T *argvars, typval_T *rettv);
312static void f_settabvar(typval_T *argvars, typval_T *rettv);
313static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100314static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315static void f_setwinvar(typval_T *argvars, typval_T *rettv);
316#ifdef FEAT_CRYPT
317static void f_sha256(typval_T *argvars, typval_T *rettv);
318#endif /* FEAT_CRYPT */
319static void f_shellescape(typval_T *argvars, typval_T *rettv);
320static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
321static void f_simplify(typval_T *argvars, typval_T *rettv);
322#ifdef FEAT_FLOAT
323static void f_sin(typval_T *argvars, typval_T *rettv);
324static void f_sinh(typval_T *argvars, typval_T *rettv);
325#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_soundfold(typval_T *argvars, typval_T *rettv);
327static void f_spellbadword(typval_T *argvars, typval_T *rettv);
328static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
329static void f_split(typval_T *argvars, typval_T *rettv);
330#ifdef FEAT_FLOAT
331static void f_sqrt(typval_T *argvars, typval_T *rettv);
332static void f_str2float(typval_T *argvars, typval_T *rettv);
333#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200334static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_str2nr(typval_T *argvars, typval_T *rettv);
336static void f_strchars(typval_T *argvars, typval_T *rettv);
337#ifdef HAVE_STRFTIME
338static void f_strftime(typval_T *argvars, typval_T *rettv);
339#endif
340static void f_strgetchar(typval_T *argvars, typval_T *rettv);
341static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342static void f_strlen(typval_T *argvars, typval_T *rettv);
343static void f_strcharpart(typval_T *argvars, typval_T *rettv);
344static void f_strpart(typval_T *argvars, typval_T *rettv);
345static void f_strridx(typval_T *argvars, typval_T *rettv);
346static void f_strtrans(typval_T *argvars, typval_T *rettv);
347static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
348static void f_strwidth(typval_T *argvars, typval_T *rettv);
349static void f_submatch(typval_T *argvars, typval_T *rettv);
350static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200351static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200352static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353static void f_synID(typval_T *argvars, typval_T *rettv);
354static void f_synIDattr(typval_T *argvars, typval_T *rettv);
355static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
356static void f_synstack(typval_T *argvars, typval_T *rettv);
357static void f_synconcealed(typval_T *argvars, typval_T *rettv);
358static void f_system(typval_T *argvars, typval_T *rettv);
359static void f_systemlist(typval_T *argvars, typval_T *rettv);
360static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
361static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
362static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
363static void f_taglist(typval_T *argvars, typval_T *rettv);
364static void f_tagfiles(typval_T *argvars, typval_T *rettv);
365static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366#ifdef FEAT_FLOAT
367static void f_tan(typval_T *argvars, typval_T *rettv);
368static void f_tanh(typval_T *argvars, typval_T *rettv);
369#endif
370#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200371static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200372static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373static void f_timer_start(typval_T *argvars, typval_T *rettv);
374static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200375static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200376#endif
377static void f_tolower(typval_T *argvars, typval_T *rettv);
378static void f_toupper(typval_T *argvars, typval_T *rettv);
379static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100380static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381#ifdef FEAT_FLOAT
382static void f_trunc(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_type(typval_T *argvars, typval_T *rettv);
385static void f_undofile(typval_T *argvars, typval_T *rettv);
386static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200387static void f_virtcol(typval_T *argvars, typval_T *rettv);
388static void f_visualmode(typval_T *argvars, typval_T *rettv);
389static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200390static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
392static void f_win_getid(typval_T *argvars, typval_T *rettv);
393static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
394static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
395static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100396static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397static void f_winbufnr(typval_T *argvars, typval_T *rettv);
398static void f_wincol(typval_T *argvars, typval_T *rettv);
399static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200400static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401static void f_winline(typval_T *argvars, typval_T *rettv);
402static void f_winnr(typval_T *argvars, typval_T *rettv);
403static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
404static void f_winrestview(typval_T *argvars, typval_T *rettv);
405static void f_winsaveview(typval_T *argvars, typval_T *rettv);
406static void f_winwidth(typval_T *argvars, typval_T *rettv);
407static void f_writefile(typval_T *argvars, typval_T *rettv);
408static void f_wordcount(typval_T *argvars, typval_T *rettv);
409static void f_xor(typval_T *argvars, typval_T *rettv);
410
411/*
412 * Array with names and number of arguments of all internal functions
413 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
414 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200415typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416{
417 char *f_name; /* function name */
418 char f_min_argc; /* minimal number of arguments */
419 char f_max_argc; /* maximal number of arguments */
420 void (*f_func)(typval_T *args, typval_T *rvar);
421 /* implementation of function */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200422} funcentry_T;
423
424static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200425{
426#ifdef FEAT_FLOAT
427 {"abs", 1, 1, f_abs},
428 {"acos", 1, 1, f_acos}, /* WJMc */
429#endif
430 {"add", 2, 2, f_add},
431 {"and", 2, 2, f_and},
432 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200433 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200434 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435 {"argidx", 0, 0, f_argidx},
436 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200437 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438#ifdef FEAT_FLOAT
439 {"asin", 1, 1, f_asin}, /* WJMc */
440#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100441 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100443 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200445 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200446 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100447 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448 {"assert_match", 2, 3, f_assert_match},
449 {"assert_notequal", 2, 3, f_assert_notequal},
450 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100451 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200452 {"assert_true", 1, 2, f_assert_true},
453#ifdef FEAT_FLOAT
454 {"atan", 1, 1, f_atan},
455 {"atan2", 2, 2, f_atan2},
456#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100457#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200458 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100459 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100460# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100461 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100462# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100463#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464 {"browse", 4, 4, f_browse},
465 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200466 {"bufadd", 1, 1, f_bufadd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467 {"bufexists", 1, 1, f_bufexists},
468 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
469 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
470 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
471 {"buflisted", 1, 1, f_buflisted},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200472 {"bufload", 1, 1, f_bufload},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473 {"bufloaded", 1, 1, f_bufloaded},
474 {"bufname", 1, 1, f_bufname},
475 {"bufnr", 1, 2, f_bufnr},
476 {"bufwinid", 1, 1, f_bufwinid},
477 {"bufwinnr", 1, 1, f_bufwinnr},
478 {"byte2line", 1, 1, f_byte2line},
479 {"byteidx", 2, 2, f_byteidx},
480 {"byteidxcomp", 2, 2, f_byteidxcomp},
481 {"call", 2, 3, f_call},
482#ifdef FEAT_FLOAT
483 {"ceil", 1, 1, f_ceil},
484#endif
485#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100486 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200488 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200489 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
490 {"ch_evalraw", 2, 3, f_ch_evalraw},
491 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
492 {"ch_getjob", 1, 1, f_ch_getjob},
493 {"ch_info", 1, 1, f_ch_info},
494 {"ch_log", 1, 2, f_ch_log},
495 {"ch_logfile", 1, 2, f_ch_logfile},
496 {"ch_open", 1, 2, f_ch_open},
497 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100498 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200499 {"ch_readraw", 1, 2, f_ch_readraw},
500 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
501 {"ch_sendraw", 2, 3, f_ch_sendraw},
502 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200503 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200504#endif
505 {"changenr", 0, 0, f_changenr},
506 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200507 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100509 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200510 {"col", 1, 1, f_col},
511#if defined(FEAT_INS_EXPAND)
512 {"complete", 2, 2, f_complete},
513 {"complete_add", 1, 1, f_complete_add},
514 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100515 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#endif
517 {"confirm", 1, 4, f_confirm},
518 {"copy", 1, 1, f_copy},
519#ifdef FEAT_FLOAT
520 {"cos", 1, 1, f_cos},
521 {"cosh", 1, 1, f_cosh},
522#endif
523 {"count", 2, 4, f_count},
524 {"cscope_connection",0,3, f_cscope_connection},
525 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100526#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200527 {"debugbreak", 1, 1, f_debugbreak},
528#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"deepcopy", 1, 2, f_deepcopy},
530 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200531 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200532 {"did_filetype", 0, 0, f_did_filetype},
533 {"diff_filler", 1, 1, f_diff_filler},
534 {"diff_hlID", 2, 2, f_diff_hlID},
535 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200536 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537 {"escape", 2, 2, f_escape},
538 {"eval", 1, 1, f_eval},
539 {"eventhandler", 0, 0, f_eventhandler},
540 {"executable", 1, 1, f_executable},
541 {"execute", 1, 2, f_execute},
542 {"exepath", 1, 1, f_exepath},
543 {"exists", 1, 1, f_exists},
544#ifdef FEAT_FLOAT
545 {"exp", 1, 1, f_exp},
546#endif
547 {"expand", 1, 3, f_expand},
Bram Moolenaar80dad482019-06-09 17:22:31 +0200548 {"expandcmd", 1, 1, f_expandcmd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549 {"extend", 2, 3, f_extend},
550 {"feedkeys", 1, 2, f_feedkeys},
551 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
552 {"filereadable", 1, 1, f_filereadable},
553 {"filewritable", 1, 1, f_filewritable},
554 {"filter", 2, 2, f_filter},
555 {"finddir", 1, 3, f_finddir},
556 {"findfile", 1, 3, f_findfile},
557#ifdef FEAT_FLOAT
558 {"float2nr", 1, 1, f_float2nr},
559 {"floor", 1, 1, f_floor},
560 {"fmod", 2, 2, f_fmod},
561#endif
562 {"fnameescape", 1, 1, f_fnameescape},
563 {"fnamemodify", 2, 2, f_fnamemodify},
564 {"foldclosed", 1, 1, f_foldclosed},
565 {"foldclosedend", 1, 1, f_foldclosedend},
566 {"foldlevel", 1, 1, f_foldlevel},
567 {"foldtext", 0, 0, f_foldtext},
568 {"foldtextresult", 1, 1, f_foldtextresult},
569 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200570 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200571 {"function", 1, 3, f_function},
572 {"garbagecollect", 0, 1, f_garbagecollect},
573 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200574 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575 {"getbufline", 2, 3, f_getbufline},
576 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100577 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578 {"getchar", 0, 1, f_getchar},
579 {"getcharmod", 0, 0, f_getcharmod},
580 {"getcharsearch", 0, 0, f_getcharsearch},
581 {"getcmdline", 0, 0, f_getcmdline},
582 {"getcmdpos", 0, 0, f_getcmdpos},
583 {"getcmdtype", 0, 0, f_getcmdtype},
584 {"getcmdwintype", 0, 0, f_getcmdwintype},
585#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200586 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200587#endif
588 {"getcurpos", 0, 0, f_getcurpos},
589 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200590 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200591 {"getfontname", 0, 1, f_getfontname},
592 {"getfperm", 1, 1, f_getfperm},
593 {"getfsize", 1, 1, f_getfsize},
594 {"getftime", 1, 1, f_getftime},
595 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100596 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200597 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200598 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100599 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600 {"getpid", 0, 0, f_getpid},
601 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200602 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603 {"getreg", 0, 3, f_getreg},
604 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200605 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200606 {"gettabvar", 2, 3, f_gettabvar},
607 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100608 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200609 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100610 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611 {"getwinposx", 0, 0, f_getwinposx},
612 {"getwinposy", 0, 0, f_getwinposy},
613 {"getwinvar", 2, 3, f_getwinvar},
614 {"glob", 1, 4, f_glob},
615 {"glob2regpat", 1, 1, f_glob2regpat},
616 {"globpath", 2, 5, f_globpath},
617 {"has", 1, 1, f_has},
618 {"has_key", 2, 2, f_has_key},
619 {"haslocaldir", 0, 2, f_haslocaldir},
620 {"hasmapto", 1, 3, f_hasmapto},
621 {"highlightID", 1, 1, f_hlID}, /* obsolete */
622 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
623 {"histadd", 2, 2, f_histadd},
624 {"histdel", 1, 2, f_histdel},
625 {"histget", 1, 2, f_histget},
626 {"histnr", 1, 1, f_histnr},
627 {"hlID", 1, 1, f_hlID},
628 {"hlexists", 1, 1, f_hlexists},
629 {"hostname", 0, 0, f_hostname},
630 {"iconv", 3, 3, f_iconv},
631 {"indent", 1, 1, f_indent},
632 {"index", 2, 4, f_index},
633 {"input", 1, 3, f_input},
634 {"inputdialog", 1, 3, f_inputdialog},
635 {"inputlist", 1, 1, f_inputlist},
636 {"inputrestore", 0, 0, f_inputrestore},
637 {"inputsave", 0, 0, f_inputsave},
638 {"inputsecret", 1, 2, f_inputsecret},
639 {"insert", 2, 3, f_insert},
640 {"invert", 1, 1, f_invert},
641 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200642#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
643 {"isinf", 1, 1, f_isinf},
644#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645 {"islocked", 1, 1, f_islocked},
646#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
647 {"isnan", 1, 1, f_isnan},
648#endif
649 {"items", 1, 1, f_items},
650#ifdef FEAT_JOB_CHANNEL
651 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200652 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"job_setoptions", 2, 2, f_job_setoptions},
654 {"job_start", 1, 2, f_job_start},
655 {"job_status", 1, 1, f_job_status},
656 {"job_stop", 1, 2, f_job_stop},
657#endif
658 {"join", 1, 2, f_join},
659 {"js_decode", 1, 1, f_js_decode},
660 {"js_encode", 1, 1, f_js_encode},
661 {"json_decode", 1, 1, f_json_decode},
662 {"json_encode", 1, 1, f_json_encode},
663 {"keys", 1, 1, f_keys},
664 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
665 {"len", 1, 1, f_len},
666 {"libcall", 3, 3, f_libcall},
667 {"libcallnr", 3, 3, f_libcallnr},
668 {"line", 1, 1, f_line},
669 {"line2byte", 1, 1, f_line2byte},
670 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200671 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200672 {"listener_add", 1, 2, f_listener_add},
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200673 {"listener_flush", 0, 1, f_listener_flush},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200674 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200675 {"localtime", 0, 0, f_localtime},
676#ifdef FEAT_FLOAT
677 {"log", 1, 1, f_log},
678 {"log10", 1, 1, f_log10},
679#endif
680#ifdef FEAT_LUA
681 {"luaeval", 1, 2, f_luaeval},
682#endif
683 {"map", 2, 2, f_map},
684 {"maparg", 1, 4, f_maparg},
685 {"mapcheck", 1, 3, f_mapcheck},
686 {"match", 2, 4, f_match},
687 {"matchadd", 2, 5, f_matchadd},
688 {"matchaddpos", 2, 5, f_matchaddpos},
689 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100690 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200691 {"matchend", 2, 4, f_matchend},
692 {"matchlist", 2, 4, f_matchlist},
693 {"matchstr", 2, 4, f_matchstr},
694 {"matchstrpos", 2, 4, f_matchstrpos},
695 {"max", 1, 1, f_max},
696 {"min", 1, 1, f_min},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697 {"mkdir", 1, 3, f_mkdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200698 {"mode", 0, 1, f_mode},
699#ifdef FEAT_MZSCHEME
700 {"mzeval", 1, 1, f_mzeval},
701#endif
702 {"nextnonblank", 1, 1, f_nextnonblank},
703 {"nr2char", 1, 2, f_nr2char},
704 {"or", 2, 2, f_or},
705 {"pathshorten", 1, 1, f_pathshorten},
706#ifdef FEAT_PERL
707 {"perleval", 1, 1, f_perleval},
708#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200709#ifdef FEAT_TEXT_PROP
Bram Moolenaarcc31ad92019-05-30 19:25:06 +0200710 {"popup_atcursor", 2, 2, f_popup_atcursor},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200711 {"popup_beval", 2, 2, f_popup_beval},
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200712 {"popup_clear", 0, 0, f_popup_clear},
Bram Moolenaar9eaac892019-06-01 22:49:29 +0200713 {"popup_close", 1, 2, f_popup_close},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200714 {"popup_create", 2, 2, f_popup_create},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200715 {"popup_dialog", 2, 2, f_popup_dialog},
Bram Moolenaara730e552019-06-16 19:05:31 +0200716 {"popup_filter_menu", 2, 2, f_popup_filter_menu},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200717 {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
Bram Moolenaar8c2a6002019-05-30 14:29:45 +0200718 {"popup_getoptions", 1, 1, f_popup_getoptions},
Bram Moolenaarccd6e342019-05-30 22:35:18 +0200719 {"popup_getpos", 1, 1, f_popup_getpos},
Bram Moolenaar56c0c472019-07-28 17:57:43 +0200720 {"popup_getpreview", 0, 0, f_popup_getpreview},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200721 {"popup_hide", 1, 1, f_popup_hide},
Bram Moolenaarb4f06282019-07-12 21:07:54 +0200722 {"popup_locate", 2, 2, f_popup_locate},
Bram Moolenaara730e552019-06-16 19:05:31 +0200723 {"popup_menu", 2, 2, f_popup_menu},
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200724 {"popup_move", 2, 2, f_popup_move},
Bram Moolenaar68d48f42019-06-12 22:42:41 +0200725 {"popup_notification", 2, 2, f_popup_notification},
Bram Moolenaarae943152019-06-16 22:54:14 +0200726 {"popup_setoptions", 2, 2, f_popup_setoptions},
Bram Moolenaardc2ce582019-06-16 15:32:14 +0200727 {"popup_settext", 2, 2, f_popup_settext},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200728 {"popup_show", 1, 1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200729#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200730#ifdef FEAT_FLOAT
731 {"pow", 2, 2, f_pow},
732#endif
733 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100734 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200735#ifdef FEAT_JOB_CHANNEL
736 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200737 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200738 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
739#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100740#ifdef FEAT_TEXT_PROP
741 {"prop_add", 3, 3, f_prop_add},
742 {"prop_clear", 1, 3, f_prop_clear},
743 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100744 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100745 {"prop_type_add", 2, 2, f_prop_type_add},
746 {"prop_type_change", 2, 2, f_prop_type_change},
747 {"prop_type_delete", 1, 2, f_prop_type_delete},
748 {"prop_type_get", 1, 2, f_prop_type_get},
749 {"prop_type_list", 0, 1, f_prop_type_list},
750#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751 {"pumvisible", 0, 0, f_pumvisible},
752#ifdef FEAT_PYTHON3
753 {"py3eval", 1, 1, f_py3eval},
754#endif
755#ifdef FEAT_PYTHON
756 {"pyeval", 1, 1, f_pyeval},
757#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100758#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
759 {"pyxeval", 1, 1, f_pyxeval},
760#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200761 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200762 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200764 {"reg_executing", 0, 0, f_reg_executing},
765 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766 {"reltime", 0, 2, f_reltime},
767#ifdef FEAT_FLOAT
768 {"reltimefloat", 1, 1, f_reltimefloat},
769#endif
770 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100771 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"remote_foreground", 1, 1, f_remote_foreground},
773 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100774 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200775 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100776 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777 {"remove", 2, 3, f_remove},
778 {"rename", 2, 2, f_rename},
779 {"repeat", 2, 2, f_repeat},
780 {"resolve", 1, 1, f_resolve},
781 {"reverse", 1, 1, f_reverse},
782#ifdef FEAT_FLOAT
783 {"round", 1, 1, f_round},
784#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100785#ifdef FEAT_RUBY
786 {"rubyeval", 1, 1, f_rubyeval},
787#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"screenattr", 2, 2, f_screenattr},
789 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100790 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200791 {"screencol", 0, 0, f_screencol},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200792 {"screenpos", 3, 3, f_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100794 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200795 {"search", 1, 4, f_search},
796 {"searchdecl", 1, 3, f_searchdecl},
797 {"searchpair", 3, 7, f_searchpair},
798 {"searchpairpos", 3, 7, f_searchpairpos},
799 {"searchpos", 1, 4, f_searchpos},
800 {"server2client", 2, 2, f_server2client},
801 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200802 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200803 {"setbufvar", 3, 3, f_setbufvar},
804 {"setcharsearch", 1, 1, f_setcharsearch},
805 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200806 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807 {"setfperm", 2, 2, f_setfperm},
808 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200809 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100810 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200811 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200812 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813 {"setreg", 2, 3, f_setreg},
814 {"settabvar", 3, 3, f_settabvar},
815 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100816 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817 {"setwinvar", 3, 3, f_setwinvar},
818#ifdef FEAT_CRYPT
819 {"sha256", 1, 1, f_sha256},
820#endif
821 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100822 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100823#ifdef FEAT_SIGNS
824 {"sign_define", 1, 2, f_sign_define},
825 {"sign_getdefined", 0, 1, f_sign_getdefined},
826 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100827 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100828 {"sign_place", 4, 5, f_sign_place},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200829 {"sign_placelist", 1, 1, f_sign_placelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100830 {"sign_undefine", 0, 1, f_sign_undefine},
831 {"sign_unplace", 1, 2, f_sign_unplace},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200832 {"sign_unplacelist", 1, 2, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100833#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200834 {"simplify", 1, 1, f_simplify},
835#ifdef FEAT_FLOAT
836 {"sin", 1, 1, f_sin},
837 {"sinh", 1, 1, f_sinh},
838#endif
839 {"sort", 1, 3, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200840#ifdef FEAT_SOUND
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200841 {"sound_clear", 0, 0, f_sound_clear},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200842 {"sound_playevent", 1, 2, f_sound_playevent},
843 {"sound_playfile", 1, 2, f_sound_playfile},
844 {"sound_stop", 1, 1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200845#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200846 {"soundfold", 1, 1, f_soundfold},
847 {"spellbadword", 0, 1, f_spellbadword},
848 {"spellsuggest", 1, 3, f_spellsuggest},
849 {"split", 1, 3, f_split},
850#ifdef FEAT_FLOAT
851 {"sqrt", 1, 1, f_sqrt},
852 {"str2float", 1, 1, f_str2float},
853#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200854 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200855 {"str2nr", 1, 2, f_str2nr},
856 {"strcharpart", 2, 3, f_strcharpart},
857 {"strchars", 1, 2, f_strchars},
858 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
859#ifdef HAVE_STRFTIME
860 {"strftime", 1, 2, f_strftime},
861#endif
862 {"strgetchar", 2, 2, f_strgetchar},
863 {"stridx", 2, 3, f_stridx},
864 {"string", 1, 1, f_string},
865 {"strlen", 1, 1, f_strlen},
866 {"strpart", 2, 3, f_strpart},
867 {"strridx", 2, 3, f_strridx},
868 {"strtrans", 1, 1, f_strtrans},
869 {"strwidth", 1, 1, f_strwidth},
870 {"submatch", 1, 2, f_submatch},
871 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200872 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200873 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874 {"synID", 3, 3, f_synID},
875 {"synIDattr", 2, 3, f_synIDattr},
876 {"synIDtrans", 1, 1, f_synIDtrans},
877 {"synconcealed", 2, 2, f_synconcealed},
878 {"synstack", 2, 2, f_synstack},
879 {"system", 1, 2, f_system},
880 {"systemlist", 1, 2, f_systemlist},
881 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
882 {"tabpagenr", 0, 1, f_tabpagenr},
883 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
884 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100885 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886#ifdef FEAT_FLOAT
887 {"tan", 1, 1, f_tan},
888 {"tanh", 1, 1, f_tanh},
889#endif
890 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200891#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100892 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
893 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100894 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200895 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200896# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
897 {"term_getansicolors", 1, 1, f_term_getansicolors},
898# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200899 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200900 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200901 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200902 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200903 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200904 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200905 {"term_getstatus", 1, 1, f_term_getstatus},
906 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200907 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200908 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200909 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200910 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200911# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
912 {"term_setansicolors", 2, 2, f_term_setansicolors},
913# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100914 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100915 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200916 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200917 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200918 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200919#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
921 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200922 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaaradc67142019-06-22 01:40:42 +0200924 {"test_garbagecollect_soon", 0, 0, f_test_garbagecollect_soon},
Bram Moolenaareda65222019-05-16 20:29:44 +0200925 {"test_getvalue", 1, 1, f_test_getvalue},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100926 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100927 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#ifdef FEAT_JOB_CHANNEL
929 {"test_null_channel", 0, 0, f_test_null_channel},
930#endif
931 {"test_null_dict", 0, 0, f_test_null_dict},
932#ifdef FEAT_JOB_CHANNEL
933 {"test_null_job", 0, 0, f_test_null_job},
934#endif
935 {"test_null_list", 0, 0, f_test_null_list},
936 {"test_null_partial", 0, 0, f_test_null_partial},
937 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200938 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100939 {"test_override", 2, 2, f_test_override},
940 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200941#ifdef FEAT_GUI
942 {"test_scrollbar", 3, 3, f_test_scrollbar},
943#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200944#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200945 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200946#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200947 {"test_settime", 1, 1, f_test_settime},
948#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200949 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200950 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951 {"timer_start", 2, 3, f_timer_start},
952 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200953 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200954#endif
955 {"tolower", 1, 1, f_tolower},
956 {"toupper", 1, 1, f_toupper},
957 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100958 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200959#ifdef FEAT_FLOAT
960 {"trunc", 1, 1, f_trunc},
961#endif
962 {"type", 1, 1, f_type},
963 {"undofile", 1, 1, f_undofile},
964 {"undotree", 0, 0, f_undotree},
965 {"uniq", 1, 3, f_uniq},
966 {"values", 1, 1, f_values},
967 {"virtcol", 1, 1, f_virtcol},
968 {"visualmode", 0, 1, f_visualmode},
969 {"wildmenumode", 0, 0, f_wildmenumode},
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200970 {"win_execute", 2, 3, f_win_execute},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971 {"win_findbuf", 1, 1, f_win_findbuf},
972 {"win_getid", 0, 2, f_win_getid},
973 {"win_gotoid", 1, 1, f_win_gotoid},
974 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
975 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100976 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977 {"winbufnr", 1, 1, f_winbufnr},
978 {"wincol", 0, 0, f_wincol},
979 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200980 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981 {"winline", 0, 0, f_winline},
982 {"winnr", 0, 1, f_winnr},
983 {"winrestcmd", 0, 0, f_winrestcmd},
984 {"winrestview", 1, 1, f_winrestview},
985 {"winsaveview", 0, 0, f_winsaveview},
986 {"winwidth", 1, 1, f_winwidth},
987 {"wordcount", 0, 0, f_wordcount},
988 {"writefile", 2, 3, f_writefile},
989 {"xor", 2, 2, f_xor},
990};
991
Bram Moolenaarac92e252019-08-03 21:58:38 +0200992/*
993 * Methods that call the internal function with the base as the first argument.
994 */
995static funcentry_T base_methods[] =
996{
997 {"add", 1, 1, f_add},
998 {"copy", 0, 0, f_copy},
999 {"count", 1, 3, f_count},
1000 {"empty", 0, 0, f_empty},
1001 {"extend", 1, 2, f_extend},
1002 {"filter", 1, 1, f_filter},
1003 {"get", 1, 2, f_get},
1004 {"index", 1, 3, f_index},
1005 {"insert", 1, 2, f_insert},
1006 {"items", 0, 0, f_items},
1007 {"join", 0, 1, f_join},
1008 {"keys", 0, 0, f_keys},
1009 {"len", 0, 0, f_len},
1010 {"map", 1, 1, f_map},
1011 {"max", 0, 0, f_max},
1012 {"min", 0, 0, f_min},
1013 {"remove", 1, 2, f_remove},
1014 {"repeat", 1, 1, f_repeat},
1015 {"reverse", 0, 0, f_reverse},
1016 {"sort", 0, 2, f_sort},
1017 {"string", 0, 0, f_string},
1018 {"type", 0, 0, f_type},
1019 {"uniq", 0, 2, f_uniq},
1020 {"values", 0, 0, f_values},
1021};
1022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001023#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1024
1025/*
1026 * Function given to ExpandGeneric() to obtain the list of internal
1027 * or user defined function names.
1028 */
1029 char_u *
1030get_function_name(expand_T *xp, int idx)
1031{
1032 static int intidx = -1;
1033 char_u *name;
1034
1035 if (idx == 0)
1036 intidx = -1;
1037 if (intidx < 0)
1038 {
1039 name = get_user_func_name(xp, idx);
1040 if (name != NULL)
1041 return name;
1042 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001044 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001046 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001047 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048 STRCAT(IObuff, ")");
1049 return IObuff;
1050 }
1051
1052 return NULL;
1053}
1054
1055/*
1056 * Function given to ExpandGeneric() to obtain the list of internal or
1057 * user defined variable or function names.
1058 */
1059 char_u *
1060get_expr_name(expand_T *xp, int idx)
1061{
1062 static int intidx = -1;
1063 char_u *name;
1064
1065 if (idx == 0)
1066 intidx = -1;
1067 if (intidx < 0)
1068 {
1069 name = get_function_name(xp, idx);
1070 if (name != NULL)
1071 return name;
1072 }
1073 return get_user_var_name(xp, ++intidx);
1074}
1075
1076#endif /* FEAT_CMDL_COMPL */
1077
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078/*
Bram Moolenaarac92e252019-08-03 21:58:38 +02001079 * Find internal function in table "functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 * Return index, or -1 if not found
1081 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001082 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001083find_internal_func(
Bram Moolenaarac92e252019-08-03 21:58:38 +02001084 char_u *name, // name of the function
1085 funcentry_T *functions) // functions table to use
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001086{
1087 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001088 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001089 int cmp;
1090 int x;
1091
Bram Moolenaarac92e252019-08-03 21:58:38 +02001092 if (functions == global_functions)
1093 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
1094 else
1095 last = (int)(sizeof(base_methods) / sizeof(funcentry_T)) - 1;
1096
1097 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001098 while (first <= last)
1099 {
1100 x = first + ((unsigned)(last - first) >> 1);
1101 cmp = STRCMP(name, functions[x].f_name);
1102 if (cmp < 0)
1103 last = x - 1;
1104 else if (cmp > 0)
1105 first = x + 1;
1106 else
1107 return x;
1108 }
1109 return -1;
1110}
1111
1112 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001113has_internal_func(char_u *name)
1114{
1115 return find_internal_func(name, global_functions) >= 0;
1116}
1117
1118 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001119call_internal_func(
1120 char_u *name,
1121 int argcount,
1122 typval_T *argvars,
1123 typval_T *rettv)
1124{
1125 int i;
1126
Bram Moolenaarac92e252019-08-03 21:58:38 +02001127 i = find_internal_func(name, global_functions);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001128 if (i < 0)
1129 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001130 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001131 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001132 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001133 return ERROR_TOOMANY;
1134 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001135 global_functions[i].f_func(argvars, rettv);
1136 return ERROR_NONE;
1137}
1138
1139/*
1140 * Invoke a method for base->method().
1141 */
1142 int
1143call_internal_method(
1144 char_u *name,
1145 int argcount,
1146 typval_T *argvars,
1147 typval_T *rettv,
1148 typval_T *basetv)
1149{
1150 int i;
1151 int fi;
1152 typval_T argv[MAX_FUNC_ARGS + 1];
1153
1154 fi = find_internal_func(name, base_methods);
1155 if (fi < 0)
1156 return ERROR_UNKNOWN;
1157 if (argcount < base_methods[fi].f_min_argc)
1158 return ERROR_TOOFEW;
1159 if (argcount > base_methods[fi].f_max_argc)
1160 return ERROR_TOOMANY;
1161
1162 argv[0] = *basetv;
1163 for (i = 0; i < argcount; ++i)
1164 argv[i + 1] = argvars[i];
1165 argv[argcount + 1].v_type = VAR_UNKNOWN;
1166
1167 base_methods[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168 return ERROR_NONE;
1169}
1170
1171/*
1172 * Return TRUE for a non-zero Number and a non-empty String.
1173 */
1174 static int
1175non_zero_arg(typval_T *argvars)
1176{
1177 return ((argvars[0].v_type == VAR_NUMBER
1178 && argvars[0].vval.v_number != 0)
1179 || (argvars[0].v_type == VAR_SPECIAL
1180 && argvars[0].vval.v_number == VVAL_TRUE)
1181 || (argvars[0].v_type == VAR_STRING
1182 && argvars[0].vval.v_string != NULL
1183 && *argvars[0].vval.v_string != NUL));
1184}
1185
1186/*
1187 * Get the lnum from the first argument.
1188 * Also accepts ".", "$", etc., but that only works for the current buffer.
1189 * Returns -1 on error.
1190 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001191 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001192tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193{
1194 typval_T rettv;
1195 linenr_T lnum;
1196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001197 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001198 if (lnum == 0) /* no valid number, try using line() */
1199 {
1200 rettv.v_type = VAR_NUMBER;
1201 f_line(argvars, &rettv);
1202 lnum = (linenr_T)rettv.vval.v_number;
1203 clear_tv(&rettv);
1204 }
1205 return lnum;
1206}
1207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001208/*
1209 * Get the lnum from the first argument.
1210 * Also accepts "$", then "buf" is used.
1211 * Returns 0 on error.
1212 */
1213 static linenr_T
1214tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1215{
1216 if (argvars[0].v_type == VAR_STRING
1217 && argvars[0].vval.v_string != NULL
1218 && argvars[0].vval.v_string[0] == '$'
1219 && buf != NULL)
1220 return buf->b_ml.ml_line_count;
1221 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1222}
1223
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001224#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001225/*
1226 * Get the float value of "argvars[0]" into "f".
1227 * Returns FAIL when the argument is not a Number or Float.
1228 */
1229 static int
1230get_float_arg(typval_T *argvars, float_T *f)
1231{
1232 if (argvars[0].v_type == VAR_FLOAT)
1233 {
1234 *f = argvars[0].vval.v_float;
1235 return OK;
1236 }
1237 if (argvars[0].v_type == VAR_NUMBER)
1238 {
1239 *f = (float_T)argvars[0].vval.v_number;
1240 return OK;
1241 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001242 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001243 return FAIL;
1244}
1245
1246/*
1247 * "abs(expr)" function
1248 */
1249 static void
1250f_abs(typval_T *argvars, typval_T *rettv)
1251{
1252 if (argvars[0].v_type == VAR_FLOAT)
1253 {
1254 rettv->v_type = VAR_FLOAT;
1255 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1256 }
1257 else
1258 {
1259 varnumber_T n;
1260 int error = FALSE;
1261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001262 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001263 if (error)
1264 rettv->vval.v_number = -1;
1265 else if (n > 0)
1266 rettv->vval.v_number = n;
1267 else
1268 rettv->vval.v_number = -n;
1269 }
1270}
1271
1272/*
1273 * "acos()" function
1274 */
1275 static void
1276f_acos(typval_T *argvars, typval_T *rettv)
1277{
1278 float_T f = 0.0;
1279
1280 rettv->v_type = VAR_FLOAT;
1281 if (get_float_arg(argvars, &f) == OK)
1282 rettv->vval.v_float = acos(f);
1283 else
1284 rettv->vval.v_float = 0.0;
1285}
1286#endif
1287
1288/*
1289 * "add(list, item)" function
1290 */
1291 static void
1292f_add(typval_T *argvars, typval_T *rettv)
1293{
1294 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001295 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001296
1297 rettv->vval.v_number = 1; /* Default: Failed */
1298 if (argvars[0].v_type == VAR_LIST)
1299 {
1300 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001301 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302 (char_u *)N_("add() argument"), TRUE)
1303 && list_append_tv(l, &argvars[1]) == OK)
1304 copy_tv(&argvars[0], rettv);
1305 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001306 else if (argvars[0].v_type == VAR_BLOB)
1307 {
1308 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001309 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001310 (char_u *)N_("add() argument"), TRUE))
1311 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001312 int error = FALSE;
1313 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1314
1315 if (!error)
1316 {
1317 ga_append(&b->bv_ga, (int)n);
1318 copy_tv(&argvars[0], rettv);
1319 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001320 }
1321 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001322 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001323 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001324}
1325
1326/*
1327 * "and(expr, expr)" function
1328 */
1329 static void
1330f_and(typval_T *argvars, typval_T *rettv)
1331{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001332 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1333 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001334}
1335
1336/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001337 * If there is a window for "curbuf", make it the current window.
1338 */
1339 static void
1340find_win_for_curbuf(void)
1341{
1342 wininfo_T *wip;
1343
1344 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1345 {
1346 if (wip->wi_win != NULL)
1347 {
1348 curwin = wip->wi_win;
1349 break;
1350 }
1351 }
1352}
1353
1354/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001356 */
1357 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001358set_buffer_lines(
1359 buf_T *buf,
1360 linenr_T lnum_arg,
1361 int append,
1362 typval_T *lines,
1363 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364{
Bram Moolenaarca851592018-06-06 21:04:07 +02001365 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1366 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 list_T *l = NULL;
1368 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001369 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001370 linenr_T append_lnum;
1371 buf_T *curbuf_save = NULL;
1372 win_T *curwin_save = NULL;
1373 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001374
Bram Moolenaarca851592018-06-06 21:04:07 +02001375 /* When using the current buffer ml_mfp will be set if needed. Useful when
1376 * setline() is used on startup. For other buffers the buffer must be
1377 * loaded. */
1378 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001379 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001380 rettv->vval.v_number = 1; /* FAIL */
1381 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382 }
1383
Bram Moolenaarca851592018-06-06 21:04:07 +02001384 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001385 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001386 curbuf_save = curbuf;
1387 curwin_save = curwin;
1388 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001389 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001390 }
1391
1392 if (append)
1393 // appendbufline() uses the line number below which we insert
1394 append_lnum = lnum - 1;
1395 else
1396 // setbufline() uses the line number above which we insert, we only
1397 // append if it's below the last line
1398 append_lnum = curbuf->b_ml.ml_line_count;
1399
1400 if (lines->v_type == VAR_LIST)
1401 {
1402 l = lines->vval.v_list;
1403 li = l->lv_first;
1404 }
1405 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001406 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001407
1408 /* default result is zero == OK */
1409 for (;;)
1410 {
1411 if (l != NULL)
1412 {
1413 /* list argument, get next string */
1414 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001415 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001416 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001417 li = li->li_next;
1418 }
1419
Bram Moolenaarca851592018-06-06 21:04:07 +02001420 rettv->vval.v_number = 1; /* FAIL */
1421 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1422 break;
1423
1424 /* When coming here from Insert mode, sync undo, so that this can be
1425 * undone separately from what was previously inserted. */
1426 if (u_sync_once == 2)
1427 {
1428 u_sync_once = 1; /* notify that u_sync() was called */
1429 u_sync(TRUE);
1430 }
1431
1432 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1433 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001434 // Existing line, replace it.
1435 // Removes any existing text properties.
1436 if (u_savesub(lnum) == OK && ml_replace_len(
1437 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001438 {
1439 changed_bytes(lnum, 0);
1440 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1441 check_cursor_col();
1442 rettv->vval.v_number = 0; /* OK */
1443 }
1444 }
1445 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1446 {
1447 /* append the line */
1448 ++added;
1449 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1450 rettv->vval.v_number = 0; /* OK */
1451 }
1452
1453 if (l == NULL) /* only one string argument */
1454 break;
1455 ++lnum;
1456 }
1457
1458 if (added > 0)
1459 {
1460 win_T *wp;
1461 tabpage_T *tp;
1462
1463 appended_lines_mark(append_lnum, added);
1464 FOR_ALL_TAB_WINDOWS(tp, wp)
1465 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1466 wp->w_cursor.lnum += added;
1467 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001468 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001469 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001470
1471 if (!is_curbuf)
1472 {
1473 curbuf = curbuf_save;
1474 curwin = curwin_save;
1475 }
1476}
1477
1478/*
1479 * "append(lnum, string/list)" function
1480 */
1481 static void
1482f_append(typval_T *argvars, typval_T *rettv)
1483{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001484 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001485
1486 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1487}
1488
1489/*
1490 * "appendbufline(buf, lnum, string/list)" function
1491 */
1492 static void
1493f_appendbufline(typval_T *argvars, typval_T *rettv)
1494{
1495 linenr_T lnum;
1496 buf_T *buf;
1497
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001498 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001499 if (buf == NULL)
1500 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001502 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001503 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001504 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1505 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506}
1507
1508/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001509 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510 */
1511 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001512f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001513{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001514 win_T *wp;
1515
1516 if (argvars[0].v_type == VAR_UNKNOWN)
1517 // use the current window
1518 rettv->vval.v_number = ARGCOUNT;
1519 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001520 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001521 // use the global argument list
1522 rettv->vval.v_number = GARGCOUNT;
1523 else
1524 {
1525 // use the argument list of the specified window
1526 wp = find_win_by_nr_or_id(&argvars[0]);
1527 if (wp != NULL)
1528 rettv->vval.v_number = WARGCOUNT(wp);
1529 else
1530 rettv->vval.v_number = -1;
1531 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532}
1533
1534/*
1535 * "argidx()" function
1536 */
1537 static void
1538f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1539{
1540 rettv->vval.v_number = curwin->w_arg_idx;
1541}
1542
1543/*
1544 * "arglistid()" function
1545 */
1546 static void
1547f_arglistid(typval_T *argvars, typval_T *rettv)
1548{
1549 win_T *wp;
1550
1551 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001552 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553 if (wp != NULL)
1554 rettv->vval.v_number = wp->w_alist->id;
1555}
1556
1557/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001558 * Get the argument list for a given window
1559 */
1560 static void
1561get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1562{
1563 int idx;
1564
1565 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1566 for (idx = 0; idx < argcount; ++idx)
1567 list_append_string(rettv->vval.v_list,
1568 alist_name(&arglist[idx]), -1);
1569}
1570
1571/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572 * "argv(nr)" function
1573 */
1574 static void
1575f_argv(typval_T *argvars, typval_T *rettv)
1576{
1577 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001578 aentry_T *arglist = NULL;
1579 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580
1581 if (argvars[0].v_type != VAR_UNKNOWN)
1582 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001583 if (argvars[1].v_type == VAR_UNKNOWN)
1584 {
1585 arglist = ARGLIST;
1586 argcount = ARGCOUNT;
1587 }
1588 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001589 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001590 {
1591 arglist = GARGLIST;
1592 argcount = GARGCOUNT;
1593 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001595 {
1596 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1597
1598 if (wp != NULL)
1599 {
1600 /* Use the argument list of the specified window */
1601 arglist = WARGLIST(wp);
1602 argcount = WARGCOUNT(wp);
1603 }
1604 }
1605
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001607 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001608 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001609 if (arglist != NULL && idx >= 0 && idx < argcount)
1610 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1611 else if (idx == -1)
1612 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001614 else
1615 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616}
1617
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618#ifdef FEAT_FLOAT
1619/*
1620 * "asin()" function
1621 */
1622 static void
1623f_asin(typval_T *argvars, typval_T *rettv)
1624{
1625 float_T f = 0.0;
1626
1627 rettv->v_type = VAR_FLOAT;
1628 if (get_float_arg(argvars, &f) == OK)
1629 rettv->vval.v_float = asin(f);
1630 else
1631 rettv->vval.v_float = 0.0;
1632}
1633
1634/*
1635 * "atan()" function
1636 */
1637 static void
1638f_atan(typval_T *argvars, typval_T *rettv)
1639{
1640 float_T f = 0.0;
1641
1642 rettv->v_type = VAR_FLOAT;
1643 if (get_float_arg(argvars, &f) == OK)
1644 rettv->vval.v_float = atan(f);
1645 else
1646 rettv->vval.v_float = 0.0;
1647}
1648
1649/*
1650 * "atan2()" function
1651 */
1652 static void
1653f_atan2(typval_T *argvars, typval_T *rettv)
1654{
1655 float_T fx = 0.0, fy = 0.0;
1656
1657 rettv->v_type = VAR_FLOAT;
1658 if (get_float_arg(argvars, &fx) == OK
1659 && get_float_arg(&argvars[1], &fy) == OK)
1660 rettv->vval.v_float = atan2(fx, fy);
1661 else
1662 rettv->vval.v_float = 0.0;
1663}
1664#endif
1665
1666/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001667 * "balloon_show()" function
1668 */
1669#ifdef FEAT_BEVAL
1670 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001671f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1672{
1673 rettv->v_type = VAR_STRING;
1674 if (balloonEval != NULL)
1675 {
1676 if (balloonEval->msg == NULL)
1677 rettv->vval.v_string = NULL;
1678 else
1679 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1680 }
1681}
1682
1683 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001684f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1685{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001686 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001687 {
1688 if (argvars[0].v_type == VAR_LIST
1689# ifdef FEAT_GUI
1690 && !gui.in_use
1691# endif
1692 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001693 {
1694 list_T *l = argvars[0].vval.v_list;
1695
1696 // empty list removes the balloon
1697 post_balloon(balloonEval, NULL,
1698 l == NULL || l->lv_len == 0 ? NULL : l);
1699 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001700 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001701 {
1702 char_u *mesg = tv_get_string_chk(&argvars[0]);
1703
1704 if (mesg != NULL)
1705 // empty string removes the balloon
1706 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1707 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001708 }
1709}
1710
Bram Moolenaar669a8282017-11-19 20:13:05 +01001711# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001712 static void
1713f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1714{
1715 if (rettv_list_alloc(rettv) == OK)
1716 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001717 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001718
1719 if (msg != NULL)
1720 {
1721 pumitem_T *array;
1722 int size = split_message(msg, &array);
1723 int i;
1724
1725 /* Skip the first and last item, they are always empty. */
1726 for (i = 1; i < size - 1; ++i)
1727 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001728 while (size > 0)
1729 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001730 vim_free(array);
1731 }
1732 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001733}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001734# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001735#endif
1736
1737/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001738 * "browse(save, title, initdir, default)" function
1739 */
1740 static void
1741f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1742{
1743#ifdef FEAT_BROWSE
1744 int save;
1745 char_u *title;
1746 char_u *initdir;
1747 char_u *defname;
1748 char_u buf[NUMBUFLEN];
1749 char_u buf2[NUMBUFLEN];
1750 int error = FALSE;
1751
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001752 save = (int)tv_get_number_chk(&argvars[0], &error);
1753 title = tv_get_string_chk(&argvars[1]);
1754 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1755 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001756
1757 if (error || title == NULL || initdir == NULL || defname == NULL)
1758 rettv->vval.v_string = NULL;
1759 else
1760 rettv->vval.v_string =
1761 do_browse(save ? BROWSE_SAVE : 0,
1762 title, defname, NULL, initdir, NULL, curbuf);
1763#else
1764 rettv->vval.v_string = NULL;
1765#endif
1766 rettv->v_type = VAR_STRING;
1767}
1768
1769/*
1770 * "browsedir(title, initdir)" function
1771 */
1772 static void
1773f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1774{
1775#ifdef FEAT_BROWSE
1776 char_u *title;
1777 char_u *initdir;
1778 char_u buf[NUMBUFLEN];
1779
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001780 title = tv_get_string_chk(&argvars[0]);
1781 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001782
1783 if (title == NULL || initdir == NULL)
1784 rettv->vval.v_string = NULL;
1785 else
1786 rettv->vval.v_string = do_browse(BROWSE_DIR,
1787 title, NULL, NULL, initdir, NULL, curbuf);
1788#else
1789 rettv->vval.v_string = NULL;
1790#endif
1791 rettv->v_type = VAR_STRING;
1792}
1793
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794/*
1795 * Find a buffer by number or exact name.
1796 */
1797 static buf_T *
1798find_buffer(typval_T *avar)
1799{
1800 buf_T *buf = NULL;
1801
1802 if (avar->v_type == VAR_NUMBER)
1803 buf = buflist_findnr((int)avar->vval.v_number);
1804 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1805 {
1806 buf = buflist_findname_exp(avar->vval.v_string);
1807 if (buf == NULL)
1808 {
1809 /* No full path name match, try a match with a URL or a "nofile"
1810 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001811 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 if (buf->b_fname != NULL
1813 && (path_with_url(buf->b_fname)
1814#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001815 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001816#endif
1817 )
1818 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1819 break;
1820 }
1821 }
1822 return buf;
1823}
1824
1825/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001826 * "bufadd(expr)" function
1827 */
1828 static void
1829f_bufadd(typval_T *argvars, typval_T *rettv)
1830{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001831 char_u *name = tv_get_string(&argvars[0]);
1832
1833 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001834}
1835
1836/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837 * "bufexists(expr)" function
1838 */
1839 static void
1840f_bufexists(typval_T *argvars, typval_T *rettv)
1841{
1842 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1843}
1844
1845/*
1846 * "buflisted(expr)" function
1847 */
1848 static void
1849f_buflisted(typval_T *argvars, typval_T *rettv)
1850{
1851 buf_T *buf;
1852
1853 buf = find_buffer(&argvars[0]);
1854 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1855}
1856
1857/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001858 * "bufload(expr)" function
1859 */
1860 static void
1861f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1862{
1863 buf_T *buf = get_buf_arg(&argvars[0]);
1864
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001865 if (buf != NULL)
1866 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001867}
1868
1869/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001870 * "bufloaded(expr)" function
1871 */
1872 static void
1873f_bufloaded(typval_T *argvars, typval_T *rettv)
1874{
1875 buf_T *buf;
1876
1877 buf = find_buffer(&argvars[0]);
1878 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1879}
1880
1881 buf_T *
1882buflist_find_by_name(char_u *name, int curtab_only)
1883{
1884 int save_magic;
1885 char_u *save_cpo;
1886 buf_T *buf;
1887
1888 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1889 save_magic = p_magic;
1890 p_magic = TRUE;
1891 save_cpo = p_cpo;
1892 p_cpo = (char_u *)"";
1893
1894 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1895 TRUE, FALSE, curtab_only));
1896
1897 p_magic = save_magic;
1898 p_cpo = save_cpo;
1899 return buf;
1900}
1901
1902/*
1903 * Get buffer by number or pattern.
1904 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001905 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001906tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001907{
1908 char_u *name = tv->vval.v_string;
1909 buf_T *buf;
1910
1911 if (tv->v_type == VAR_NUMBER)
1912 return buflist_findnr((int)tv->vval.v_number);
1913 if (tv->v_type != VAR_STRING)
1914 return NULL;
1915 if (name == NULL || *name == NUL)
1916 return curbuf;
1917 if (name[0] == '$' && name[1] == NUL)
1918 return lastbuf;
1919
1920 buf = buflist_find_by_name(name, curtab_only);
1921
1922 /* If not found, try expanding the name, like done for bufexists(). */
1923 if (buf == NULL)
1924 buf = find_buffer(tv);
1925
1926 return buf;
1927}
1928
1929/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001930 * Get the buffer from "arg" and give an error and return NULL if it is not
1931 * valid.
1932 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001933 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001934get_buf_arg(typval_T *arg)
1935{
1936 buf_T *buf;
1937
1938 ++emsg_off;
1939 buf = tv_get_buf(arg, FALSE);
1940 --emsg_off;
1941 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001942 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001943 return buf;
1944}
1945
1946/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001947 * "bufname(expr)" function
1948 */
1949 static void
1950f_bufname(typval_T *argvars, typval_T *rettv)
1951{
1952 buf_T *buf;
1953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001954 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001956 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 rettv->v_type = VAR_STRING;
1958 if (buf != NULL && buf->b_fname != NULL)
1959 rettv->vval.v_string = vim_strsave(buf->b_fname);
1960 else
1961 rettv->vval.v_string = NULL;
1962 --emsg_off;
1963}
1964
1965/*
1966 * "bufnr(expr)" function
1967 */
1968 static void
1969f_bufnr(typval_T *argvars, typval_T *rettv)
1970{
1971 buf_T *buf;
1972 int error = FALSE;
1973 char_u *name;
1974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001975 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001977 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 --emsg_off;
1979
1980 /* If the buffer isn't found and the second argument is not zero create a
1981 * new buffer. */
1982 if (buf == NULL
1983 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001984 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001986 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 && !error)
1988 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1989
1990 if (buf != NULL)
1991 rettv->vval.v_number = buf->b_fnum;
1992 else
1993 rettv->vval.v_number = -1;
1994}
1995
1996 static void
1997buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1998{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 win_T *wp;
2000 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 buf_T *buf;
2002
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002003 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002005 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002006 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002007 {
2008 ++winnr;
2009 if (wp->w_buffer == buf)
2010 break;
2011 }
2012 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 --emsg_off;
2014}
2015
2016/*
2017 * "bufwinid(nr)" function
2018 */
2019 static void
2020f_bufwinid(typval_T *argvars, typval_T *rettv)
2021{
2022 buf_win_common(argvars, rettv, FALSE);
2023}
2024
2025/*
2026 * "bufwinnr(nr)" function
2027 */
2028 static void
2029f_bufwinnr(typval_T *argvars, typval_T *rettv)
2030{
2031 buf_win_common(argvars, rettv, TRUE);
2032}
2033
2034/*
2035 * "byte2line(byte)" function
2036 */
2037 static void
2038f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2039{
2040#ifndef FEAT_BYTEOFF
2041 rettv->vval.v_number = -1;
2042#else
2043 long boff = 0;
2044
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002045 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 if (boff < 0)
2047 rettv->vval.v_number = -1;
2048 else
2049 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2050 (linenr_T)0, &boff);
2051#endif
2052}
2053
2054 static void
2055byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2056{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002057 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 char_u *str;
2059 varnumber_T idx;
2060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002061 str = tv_get_string_chk(&argvars[0]);
2062 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 rettv->vval.v_number = -1;
2064 if (str == NULL || idx < 0)
2065 return;
2066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067 t = str;
2068 for ( ; idx > 0; idx--)
2069 {
2070 if (*t == NUL) /* EOL reached */
2071 return;
2072 if (enc_utf8 && comp)
2073 t += utf_ptr2len(t);
2074 else
2075 t += (*mb_ptr2len)(t);
2076 }
2077 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078}
2079
2080/*
2081 * "byteidx()" function
2082 */
2083 static void
2084f_byteidx(typval_T *argvars, typval_T *rettv)
2085{
2086 byteidx(argvars, rettv, FALSE);
2087}
2088
2089/*
2090 * "byteidxcomp()" function
2091 */
2092 static void
2093f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2094{
2095 byteidx(argvars, rettv, TRUE);
2096}
2097
2098/*
2099 * "call(func, arglist [, dict])" function
2100 */
2101 static void
2102f_call(typval_T *argvars, typval_T *rettv)
2103{
2104 char_u *func;
2105 partial_T *partial = NULL;
2106 dict_T *selfdict = NULL;
2107
2108 if (argvars[1].v_type != VAR_LIST)
2109 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002110 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111 return;
2112 }
2113 if (argvars[1].vval.v_list == NULL)
2114 return;
2115
2116 if (argvars[0].v_type == VAR_FUNC)
2117 func = argvars[0].vval.v_string;
2118 else if (argvars[0].v_type == VAR_PARTIAL)
2119 {
2120 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002121 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 }
2123 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002124 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002125 if (*func == NUL)
2126 return; /* type error or empty name */
2127
2128 if (argvars[2].v_type != VAR_UNKNOWN)
2129 {
2130 if (argvars[2].v_type != VAR_DICT)
2131 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002132 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133 return;
2134 }
2135 selfdict = argvars[2].vval.v_dict;
2136 }
2137
2138 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2139}
2140
2141#ifdef FEAT_FLOAT
2142/*
2143 * "ceil({float})" function
2144 */
2145 static void
2146f_ceil(typval_T *argvars, typval_T *rettv)
2147{
2148 float_T f = 0.0;
2149
2150 rettv->v_type = VAR_FLOAT;
2151 if (get_float_arg(argvars, &f) == OK)
2152 rettv->vval.v_float = ceil(f);
2153 else
2154 rettv->vval.v_float = 0.0;
2155}
2156#endif
2157
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158/*
2159 * "changenr()" function
2160 */
2161 static void
2162f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2163{
2164 rettv->vval.v_number = curbuf->b_u_seq_cur;
2165}
2166
2167/*
2168 * "char2nr(string)" function
2169 */
2170 static void
2171f_char2nr(typval_T *argvars, typval_T *rettv)
2172{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 if (has_mbyte)
2174 {
2175 int utf8 = 0;
2176
2177 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002178 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179
2180 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002181 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002183 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184 }
2185 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002186 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002187}
2188
2189/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002190 * "chdir(dir)" function
2191 */
2192 static void
2193f_chdir(typval_T *argvars, typval_T *rettv)
2194{
2195 char_u *cwd;
2196 cdscope_T scope = CDSCOPE_GLOBAL;
2197
2198 rettv->v_type = VAR_STRING;
2199 rettv->vval.v_string = NULL;
2200
2201 if (argvars[0].v_type != VAR_STRING)
2202 return;
2203
2204 // Return the current directory
2205 cwd = alloc(MAXPATHL);
2206 if (cwd != NULL)
2207 {
2208 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2209 {
2210#ifdef BACKSLASH_IN_FILENAME
2211 slash_adjust(cwd);
2212#endif
2213 rettv->vval.v_string = vim_strsave(cwd);
2214 }
2215 vim_free(cwd);
2216 }
2217
2218 if (curwin->w_localdir != NULL)
2219 scope = CDSCOPE_WINDOW;
2220 else if (curtab->tp_localdir != NULL)
2221 scope = CDSCOPE_TABPAGE;
2222
2223 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2224 // Directory change failed
2225 VIM_CLEAR(rettv->vval.v_string);
2226}
2227
2228/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229 * "cindent(lnum)" function
2230 */
2231 static void
2232f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2233{
2234#ifdef FEAT_CINDENT
2235 pos_T pos;
2236 linenr_T lnum;
2237
2238 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002239 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002240 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2241 {
2242 curwin->w_cursor.lnum = lnum;
2243 rettv->vval.v_number = get_c_indent();
2244 curwin->w_cursor = pos;
2245 }
2246 else
2247#endif
2248 rettv->vval.v_number = -1;
2249}
2250
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002251 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002252get_optional_window(typval_T *argvars, int idx)
2253{
2254 win_T *win = curwin;
2255
2256 if (argvars[idx].v_type != VAR_UNKNOWN)
2257 {
2258 win = find_win_by_nr_or_id(&argvars[idx]);
2259 if (win == NULL)
2260 {
2261 emsg(_(e_invalwindow));
2262 return NULL;
2263 }
2264 }
2265 return win;
2266}
2267
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 * "col(string)" function
2270 */
2271 static void
2272f_col(typval_T *argvars, typval_T *rettv)
2273{
2274 colnr_T col = 0;
2275 pos_T *fp;
2276 int fnum = curbuf->b_fnum;
2277
2278 fp = var2fpos(&argvars[0], FALSE, &fnum);
2279 if (fp != NULL && fnum == curbuf->b_fnum)
2280 {
2281 if (fp->col == MAXCOL)
2282 {
2283 /* '> can be MAXCOL, get the length of the line then */
2284 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2285 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2286 else
2287 col = MAXCOL;
2288 }
2289 else
2290 {
2291 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 /* col(".") when the cursor is on the NUL at the end of the line
2293 * because of "coladd" can be seen as an extra column. */
2294 if (virtual_active() && fp == &curwin->w_cursor)
2295 {
2296 char_u *p = ml_get_cursor();
2297
2298 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2299 curwin->w_virtcol - curwin->w_cursor.coladd))
2300 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 int l;
2302
2303 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2304 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 }
2306 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002307 }
2308 }
2309 rettv->vval.v_number = col;
2310}
2311
2312#if defined(FEAT_INS_EXPAND)
2313/*
2314 * "complete()" function
2315 */
2316 static void
2317f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2318{
2319 int startcol;
2320
2321 if ((State & INSERT) == 0)
2322 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002323 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002324 return;
2325 }
2326
2327 /* Check for undo allowed here, because if something was already inserted
2328 * the line was already saved for undo and this check isn't done. */
2329 if (!undo_allowed())
2330 return;
2331
2332 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2333 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002334 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335 return;
2336 }
2337
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002338 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002339 if (startcol <= 0)
2340 return;
2341
2342 set_completion(startcol - 1, argvars[1].vval.v_list);
2343}
2344
2345/*
2346 * "complete_add()" function
2347 */
2348 static void
2349f_complete_add(typval_T *argvars, typval_T *rettv)
2350{
2351 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2352}
2353
2354/*
2355 * "complete_check()" function
2356 */
2357 static void
2358f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2359{
2360 int saved = RedrawingDisabled;
2361
2362 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002363 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002364 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 RedrawingDisabled = saved;
2366}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002367
2368/*
2369 * "complete_info()" function
2370 */
2371 static void
2372f_complete_info(typval_T *argvars, typval_T *rettv)
2373{
2374 list_T *what_list = NULL;
2375
2376 if (rettv_dict_alloc(rettv) != OK)
2377 return;
2378
2379 if (argvars[0].v_type != VAR_UNKNOWN)
2380 {
2381 if (argvars[0].v_type != VAR_LIST)
2382 {
2383 emsg(_(e_listreq));
2384 return;
2385 }
2386 what_list = argvars[0].vval.v_list;
2387 }
2388 get_complete_info(what_list, rettv->vval.v_dict);
2389}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390#endif
2391
2392/*
2393 * "confirm(message, buttons[, default [, type]])" function
2394 */
2395 static void
2396f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2397{
2398#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2399 char_u *message;
2400 char_u *buttons = NULL;
2401 char_u buf[NUMBUFLEN];
2402 char_u buf2[NUMBUFLEN];
2403 int def = 1;
2404 int type = VIM_GENERIC;
2405 char_u *typestr;
2406 int error = FALSE;
2407
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002408 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002409 if (message == NULL)
2410 error = TRUE;
2411 if (argvars[1].v_type != VAR_UNKNOWN)
2412 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002413 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 if (buttons == NULL)
2415 error = TRUE;
2416 if (argvars[2].v_type != VAR_UNKNOWN)
2417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002418 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 if (argvars[3].v_type != VAR_UNKNOWN)
2420 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002421 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422 if (typestr == NULL)
2423 error = TRUE;
2424 else
2425 {
2426 switch (TOUPPER_ASC(*typestr))
2427 {
2428 case 'E': type = VIM_ERROR; break;
2429 case 'Q': type = VIM_QUESTION; break;
2430 case 'I': type = VIM_INFO; break;
2431 case 'W': type = VIM_WARNING; break;
2432 case 'G': type = VIM_GENERIC; break;
2433 }
2434 }
2435 }
2436 }
2437 }
2438
2439 if (buttons == NULL || *buttons == NUL)
2440 buttons = (char_u *)_("&Ok");
2441
2442 if (!error)
2443 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2444 def, NULL, FALSE);
2445#endif
2446}
2447
2448/*
2449 * "copy()" function
2450 */
2451 static void
2452f_copy(typval_T *argvars, typval_T *rettv)
2453{
2454 item_copy(&argvars[0], rettv, FALSE, 0);
2455}
2456
2457#ifdef FEAT_FLOAT
2458/*
2459 * "cos()" function
2460 */
2461 static void
2462f_cos(typval_T *argvars, typval_T *rettv)
2463{
2464 float_T f = 0.0;
2465
2466 rettv->v_type = VAR_FLOAT;
2467 if (get_float_arg(argvars, &f) == OK)
2468 rettv->vval.v_float = cos(f);
2469 else
2470 rettv->vval.v_float = 0.0;
2471}
2472
2473/*
2474 * "cosh()" function
2475 */
2476 static void
2477f_cosh(typval_T *argvars, typval_T *rettv)
2478{
2479 float_T f = 0.0;
2480
2481 rettv->v_type = VAR_FLOAT;
2482 if (get_float_arg(argvars, &f) == OK)
2483 rettv->vval.v_float = cosh(f);
2484 else
2485 rettv->vval.v_float = 0.0;
2486}
2487#endif
2488
2489/*
2490 * "count()" function
2491 */
2492 static void
2493f_count(typval_T *argvars, typval_T *rettv)
2494{
2495 long n = 0;
2496 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002497 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498
Bram Moolenaar9966b212017-07-28 16:46:57 +02002499 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002500 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002501
2502 if (argvars[0].v_type == VAR_STRING)
2503 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002504 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002505 char_u *p = argvars[0].vval.v_string;
2506 char_u *next;
2507
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002508 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002509 {
2510 if (ic)
2511 {
2512 size_t len = STRLEN(expr);
2513
2514 while (*p != NUL)
2515 {
2516 if (MB_STRNICMP(p, expr, len) == 0)
2517 {
2518 ++n;
2519 p += len;
2520 }
2521 else
2522 MB_PTR_ADV(p);
2523 }
2524 }
2525 else
2526 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2527 != NULL)
2528 {
2529 ++n;
2530 p = next + STRLEN(expr);
2531 }
2532 }
2533
2534 }
2535 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536 {
2537 listitem_T *li;
2538 list_T *l;
2539 long idx;
2540
2541 if ((l = argvars[0].vval.v_list) != NULL)
2542 {
2543 li = l->lv_first;
2544 if (argvars[2].v_type != VAR_UNKNOWN)
2545 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546 if (argvars[3].v_type != VAR_UNKNOWN)
2547 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002548 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 if (!error)
2550 {
2551 li = list_find(l, idx);
2552 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002553 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555 }
2556 if (error)
2557 li = NULL;
2558 }
2559
2560 for ( ; li != NULL; li = li->li_next)
2561 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2562 ++n;
2563 }
2564 }
2565 else if (argvars[0].v_type == VAR_DICT)
2566 {
2567 int todo;
2568 dict_T *d;
2569 hashitem_T *hi;
2570
2571 if ((d = argvars[0].vval.v_dict) != NULL)
2572 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002573 if (argvars[2].v_type != VAR_UNKNOWN)
2574 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002575 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002576 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 }
2578
2579 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2580 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2581 {
2582 if (!HASHITEM_EMPTY(hi))
2583 {
2584 --todo;
2585 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2586 ++n;
2587 }
2588 }
2589 }
2590 }
2591 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002592 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 rettv->vval.v_number = n;
2594}
2595
2596/*
2597 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2598 *
2599 * Checks the existence of a cscope connection.
2600 */
2601 static void
2602f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2603{
2604#ifdef FEAT_CSCOPE
2605 int num = 0;
2606 char_u *dbpath = NULL;
2607 char_u *prepend = NULL;
2608 char_u buf[NUMBUFLEN];
2609
2610 if (argvars[0].v_type != VAR_UNKNOWN
2611 && argvars[1].v_type != VAR_UNKNOWN)
2612 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002613 num = (int)tv_get_number(&argvars[0]);
2614 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002616 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 }
2618
2619 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2620#endif
2621}
2622
2623/*
2624 * "cursor(lnum, col)" function, or
2625 * "cursor(list)"
2626 *
2627 * Moves the cursor to the specified line and column.
2628 * Returns 0 when the position could be set, -1 otherwise.
2629 */
2630 static void
2631f_cursor(typval_T *argvars, typval_T *rettv)
2632{
2633 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002634 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 int set_curswant = TRUE;
2636
2637 rettv->vval.v_number = -1;
2638 if (argvars[1].v_type == VAR_UNKNOWN)
2639 {
2640 pos_T pos;
2641 colnr_T curswant = -1;
2642
2643 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2644 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002645 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002646 return;
2647 }
2648 line = pos.lnum;
2649 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002650 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (curswant >= 0)
2652 {
2653 curwin->w_curswant = curswant - 1;
2654 set_curswant = FALSE;
2655 }
2656 }
2657 else
2658 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002659 line = tv_get_lnum(argvars);
2660 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002661 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002662 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002664 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002665 return; /* type error; errmsg already given */
2666 if (line > 0)
2667 curwin->w_cursor.lnum = line;
2668 if (col > 0)
2669 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002670 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671
2672 /* Make sure the cursor is in a valid position. */
2673 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 /* Correct cursor for multi-byte character. */
2675 if (has_mbyte)
2676 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677
2678 curwin->w_set_curswant = set_curswant;
2679 rettv->vval.v_number = 0;
2680}
2681
Bram Moolenaar4f974752019-02-17 17:44:42 +01002682#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002683/*
2684 * "debugbreak()" function
2685 */
2686 static void
2687f_debugbreak(typval_T *argvars, typval_T *rettv)
2688{
2689 int pid;
2690
2691 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002692 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002693 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002694 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002695 else
2696 {
2697 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2698
2699 if (hProcess != NULL)
2700 {
2701 DebugBreakProcess(hProcess);
2702 CloseHandle(hProcess);
2703 rettv->vval.v_number = OK;
2704 }
2705 }
2706}
2707#endif
2708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709/*
2710 * "deepcopy()" function
2711 */
2712 static void
2713f_deepcopy(typval_T *argvars, typval_T *rettv)
2714{
2715 int noref = 0;
2716 int copyID;
2717
2718 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002719 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002720 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002721 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002722 else
2723 {
2724 copyID = get_copyID();
2725 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2726 }
2727}
2728
2729/*
2730 * "delete()" function
2731 */
2732 static void
2733f_delete(typval_T *argvars, typval_T *rettv)
2734{
2735 char_u nbuf[NUMBUFLEN];
2736 char_u *name;
2737 char_u *flags;
2738
2739 rettv->vval.v_number = -1;
2740 if (check_restricted() || check_secure())
2741 return;
2742
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002743 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002744 if (name == NULL || *name == NUL)
2745 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002746 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002747 return;
2748 }
2749
2750 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002751 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002752 else
2753 flags = (char_u *)"";
2754
2755 if (*flags == NUL)
2756 /* delete a file */
2757 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2758 else if (STRCMP(flags, "d") == 0)
2759 /* delete an empty directory */
2760 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2761 else if (STRCMP(flags, "rf") == 0)
2762 /* delete a directory recursively */
2763 rettv->vval.v_number = delete_recursive(name);
2764 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002765 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766}
2767
2768/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002769 * "deletebufline()" function
2770 */
2771 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002772f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002773{
2774 buf_T *buf;
2775 linenr_T first, last;
2776 linenr_T lnum;
2777 long count;
2778 int is_curbuf;
2779 buf_T *curbuf_save = NULL;
2780 win_T *curwin_save = NULL;
2781 tabpage_T *tp;
2782 win_T *wp;
2783
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002784 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002785 if (buf == NULL)
2786 {
2787 rettv->vval.v_number = 1; /* FAIL */
2788 return;
2789 }
2790 is_curbuf = buf == curbuf;
2791
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002792 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002793 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002794 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002795 else
2796 last = first;
2797
2798 if (buf->b_ml.ml_mfp == NULL || first < 1
2799 || first > buf->b_ml.ml_line_count || last < first)
2800 {
2801 rettv->vval.v_number = 1; /* FAIL */
2802 return;
2803 }
2804
2805 if (!is_curbuf)
2806 {
2807 curbuf_save = curbuf;
2808 curwin_save = curwin;
2809 curbuf = buf;
2810 find_win_for_curbuf();
2811 }
2812 if (last > curbuf->b_ml.ml_line_count)
2813 last = curbuf->b_ml.ml_line_count;
2814 count = last - first + 1;
2815
2816 // When coming here from Insert mode, sync undo, so that this can be
2817 // undone separately from what was previously inserted.
2818 if (u_sync_once == 2)
2819 {
2820 u_sync_once = 1; // notify that u_sync() was called
2821 u_sync(TRUE);
2822 }
2823
2824 if (u_save(first - 1, last + 1) == FAIL)
2825 {
2826 rettv->vval.v_number = 1; /* FAIL */
2827 return;
2828 }
2829
2830 for (lnum = first; lnum <= last; ++lnum)
2831 ml_delete(first, TRUE);
2832
2833 FOR_ALL_TAB_WINDOWS(tp, wp)
2834 if (wp->w_buffer == buf)
2835 {
2836 if (wp->w_cursor.lnum > last)
2837 wp->w_cursor.lnum -= count;
2838 else if (wp->w_cursor.lnum> first)
2839 wp->w_cursor.lnum = first;
2840 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2841 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2842 }
2843 check_cursor_col();
2844 deleted_lines_mark(first, count);
2845
2846 if (!is_curbuf)
2847 {
2848 curbuf = curbuf_save;
2849 curwin = curwin_save;
2850 }
2851}
2852
2853/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002854 * "did_filetype()" function
2855 */
2856 static void
2857f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2858{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002859 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860}
2861
2862/*
2863 * "diff_filler()" function
2864 */
2865 static void
2866f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2867{
2868#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002869 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870#endif
2871}
2872
2873/*
2874 * "diff_hlID()" function
2875 */
2876 static void
2877f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2878{
2879#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002880 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002881 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002882 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002883 static int fnum = 0;
2884 static int change_start = 0;
2885 static int change_end = 0;
2886 static hlf_T hlID = (hlf_T)0;
2887 int filler_lines;
2888 int col;
2889
2890 if (lnum < 0) /* ignore type error in {lnum} arg */
2891 lnum = 0;
2892 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002893 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002894 || fnum != curbuf->b_fnum)
2895 {
2896 /* New line, buffer, change: need to get the values. */
2897 filler_lines = diff_check(curwin, lnum);
2898 if (filler_lines < 0)
2899 {
2900 if (filler_lines == -1)
2901 {
2902 change_start = MAXCOL;
2903 change_end = -1;
2904 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2905 hlID = HLF_ADD; /* added line */
2906 else
2907 hlID = HLF_CHD; /* changed line */
2908 }
2909 else
2910 hlID = HLF_ADD; /* added line */
2911 }
2912 else
2913 hlID = (hlf_T)0;
2914 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002915 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002916 fnum = curbuf->b_fnum;
2917 }
2918
2919 if (hlID == HLF_CHD || hlID == HLF_TXD)
2920 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002921 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 if (col >= change_start && col <= change_end)
2923 hlID = HLF_TXD; /* changed text */
2924 else
2925 hlID = HLF_CHD; /* changed line */
2926 }
2927 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2928#endif
2929}
2930
2931/*
2932 * "empty({expr})" function
2933 */
2934 static void
2935f_empty(typval_T *argvars, typval_T *rettv)
2936{
2937 int n = FALSE;
2938
2939 switch (argvars[0].v_type)
2940 {
2941 case VAR_STRING:
2942 case VAR_FUNC:
2943 n = argvars[0].vval.v_string == NULL
2944 || *argvars[0].vval.v_string == NUL;
2945 break;
2946 case VAR_PARTIAL:
2947 n = FALSE;
2948 break;
2949 case VAR_NUMBER:
2950 n = argvars[0].vval.v_number == 0;
2951 break;
2952 case VAR_FLOAT:
2953#ifdef FEAT_FLOAT
2954 n = argvars[0].vval.v_float == 0.0;
2955 break;
2956#endif
2957 case VAR_LIST:
2958 n = argvars[0].vval.v_list == NULL
2959 || argvars[0].vval.v_list->lv_first == NULL;
2960 break;
2961 case VAR_DICT:
2962 n = argvars[0].vval.v_dict == NULL
2963 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2964 break;
2965 case VAR_SPECIAL:
2966 n = argvars[0].vval.v_number != VVAL_TRUE;
2967 break;
2968
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002969 case VAR_BLOB:
2970 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002971 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2972 break;
2973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002974 case VAR_JOB:
2975#ifdef FEAT_JOB_CHANNEL
2976 n = argvars[0].vval.v_job == NULL
2977 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2978 break;
2979#endif
2980 case VAR_CHANNEL:
2981#ifdef FEAT_JOB_CHANNEL
2982 n = argvars[0].vval.v_channel == NULL
2983 || !channel_is_open(argvars[0].vval.v_channel);
2984 break;
2985#endif
2986 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002987 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002988 n = TRUE;
2989 break;
2990 }
2991
2992 rettv->vval.v_number = n;
2993}
2994
2995/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002996 * "environ()" function
2997 */
2998 static void
2999f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3000{
3001#if !defined(AMIGA)
3002 int i = 0;
3003 char_u *entry, *value;
3004# ifdef MSWIN
3005 extern wchar_t **_wenviron;
3006# else
3007 extern char **environ;
3008# endif
3009
3010 if (rettv_dict_alloc(rettv) != OK)
3011 return;
3012
3013# ifdef MSWIN
3014 if (*_wenviron == NULL)
3015 return;
3016# else
3017 if (*environ == NULL)
3018 return;
3019# endif
3020
3021 for (i = 0; ; ++i)
3022 {
3023# ifdef MSWIN
3024 short_u *p;
3025
3026 if ((p = (short_u *)_wenviron[i]) == NULL)
3027 return;
3028 entry = utf16_to_enc(p, NULL);
3029# else
3030 if ((entry = (char_u *)environ[i]) == NULL)
3031 return;
3032 entry = vim_strsave(entry);
3033# endif
3034 if (entry == NULL) // out of memory
3035 return;
3036 if ((value = vim_strchr(entry, '=')) == NULL)
3037 {
3038 vim_free(entry);
3039 continue;
3040 }
3041 *value++ = NUL;
3042 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3043 vim_free(entry);
3044 }
3045#endif
3046}
3047
3048/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003049 * "escape({string}, {chars})" function
3050 */
3051 static void
3052f_escape(typval_T *argvars, typval_T *rettv)
3053{
3054 char_u buf[NUMBUFLEN];
3055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003056 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3057 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 rettv->v_type = VAR_STRING;
3059}
3060
3061/*
3062 * "eval()" function
3063 */
3064 static void
3065f_eval(typval_T *argvars, typval_T *rettv)
3066{
3067 char_u *s, *p;
3068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003069 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003070 if (s != NULL)
3071 s = skipwhite(s);
3072
3073 p = s;
3074 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3075 {
3076 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003077 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078 need_clr_eos = FALSE;
3079 rettv->v_type = VAR_NUMBER;
3080 rettv->vval.v_number = 0;
3081 }
3082 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003083 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003084}
3085
3086/*
3087 * "eventhandler()" function
3088 */
3089 static void
3090f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3091{
3092 rettv->vval.v_number = vgetc_busy;
3093}
3094
3095/*
3096 * "executable()" function
3097 */
3098 static void
3099f_executable(typval_T *argvars, typval_T *rettv)
3100{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003101 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102
3103 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003104 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003105}
3106
3107static garray_T redir_execute_ga;
3108
3109/*
3110 * Append "value[value_len]" to the execute() output.
3111 */
3112 void
3113execute_redir_str(char_u *value, int value_len)
3114{
3115 int len;
3116
3117 if (value_len == -1)
3118 len = (int)STRLEN(value); /* Append the entire string */
3119 else
3120 len = value_len; /* Append only "value_len" characters */
3121 if (ga_grow(&redir_execute_ga, len) == OK)
3122 {
3123 mch_memmove((char *)redir_execute_ga.ga_data
3124 + redir_execute_ga.ga_len, value, len);
3125 redir_execute_ga.ga_len += len;
3126 }
3127}
3128
3129/*
3130 * Get next line from a list.
3131 * Called by do_cmdline() to get the next line.
3132 * Returns allocated string, or NULL for end of function.
3133 */
3134
3135 static char_u *
3136get_list_line(
3137 int c UNUSED,
3138 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003139 int indent UNUSED,
3140 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003141{
3142 listitem_T **p = (listitem_T **)cookie;
3143 listitem_T *item = *p;
3144 char_u buf[NUMBUFLEN];
3145 char_u *s;
3146
3147 if (item == NULL)
3148 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003149 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150 *p = item->li_next;
3151 return s == NULL ? NULL : vim_strsave(s);
3152}
3153
3154/*
3155 * "execute()" function
3156 */
3157 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003158execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159{
3160 char_u *cmd = NULL;
3161 list_T *list = NULL;
3162 int save_msg_silent = msg_silent;
3163 int save_emsg_silent = emsg_silent;
3164 int save_emsg_noredir = emsg_noredir;
3165 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003166 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003168 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003169 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003170
3171 rettv->vval.v_string = NULL;
3172 rettv->v_type = VAR_STRING;
3173
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003174 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003175 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003176 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003177 if (list == NULL || list->lv_first == NULL)
3178 /* empty list, no commands, empty output */
3179 return;
3180 ++list->lv_refcount;
3181 }
3182 else
3183 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003184 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003185 if (cmd == NULL)
3186 return;
3187 }
3188
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003189 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003190 {
3191 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003192 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193
3194 if (s == NULL)
3195 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003196 if (*s == NUL)
3197 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198 if (STRNCMP(s, "silent", 6) == 0)
3199 ++msg_silent;
3200 if (STRCMP(s, "silent!") == 0)
3201 {
3202 emsg_silent = TRUE;
3203 emsg_noredir = TRUE;
3204 }
3205 }
3206 else
3207 ++msg_silent;
3208
3209 if (redir_execute)
3210 save_ga = redir_execute_ga;
3211 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3212 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003213 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003214 if (!echo_output)
3215 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216
3217 if (cmd != NULL)
3218 do_cmdline_cmd(cmd);
3219 else
3220 {
3221 listitem_T *item = list->lv_first;
3222
3223 do_cmdline(NULL, get_list_line, (void *)&item,
3224 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3225 --list->lv_refcount;
3226 }
3227
Bram Moolenaard297f352017-01-29 20:31:21 +01003228 /* Need to append a NUL to the result. */
3229 if (ga_grow(&redir_execute_ga, 1) == OK)
3230 {
3231 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3232 rettv->vval.v_string = redir_execute_ga.ga_data;
3233 }
3234 else
3235 {
3236 ga_clear(&redir_execute_ga);
3237 rettv->vval.v_string = NULL;
3238 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239 msg_silent = save_msg_silent;
3240 emsg_silent = save_emsg_silent;
3241 emsg_noredir = save_emsg_noredir;
3242
3243 redir_execute = save_redir_execute;
3244 if (redir_execute)
3245 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003246 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003248 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003249 if (echo_output)
3250 // When not working silently: put it in column zero. A following
3251 // "echon" will overwrite the message, unavoidably.
3252 msg_col = 0;
3253 else
3254 // When working silently: Put it back where it was, since nothing
3255 // should have been written.
3256 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257}
3258
3259/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003260 * "execute()" function
3261 */
3262 static void
3263f_execute(typval_T *argvars, typval_T *rettv)
3264{
3265 execute_common(argvars, rettv, 0);
3266}
3267
3268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 * "exepath()" function
3270 */
3271 static void
3272f_exepath(typval_T *argvars, typval_T *rettv)
3273{
3274 char_u *p = NULL;
3275
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003276 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003277 rettv->v_type = VAR_STRING;
3278 rettv->vval.v_string = p;
3279}
3280
3281/*
3282 * "exists()" function
3283 */
3284 static void
3285f_exists(typval_T *argvars, typval_T *rettv)
3286{
3287 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003289
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003290 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003291 if (*p == '$') /* environment variable */
3292 {
3293 /* first try "normal" environment variables (fast) */
3294 if (mch_getenv(p + 1) != NULL)
3295 n = TRUE;
3296 else
3297 {
3298 /* try expanding things like $VIM and ${HOME} */
3299 p = expand_env_save(p);
3300 if (p != NULL && *p != '$')
3301 n = TRUE;
3302 vim_free(p);
3303 }
3304 }
3305 else if (*p == '&' || *p == '+') /* option */
3306 {
3307 n = (get_option_tv(&p, NULL, TRUE) == OK);
3308 if (*skipwhite(p) != NUL)
3309 n = FALSE; /* trailing garbage */
3310 }
3311 else if (*p == '*') /* internal or user defined function */
3312 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003313 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 }
3315 else if (*p == ':')
3316 {
3317 n = cmd_exists(p + 1);
3318 }
3319 else if (*p == '#')
3320 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 if (p[1] == '#')
3322 n = autocmd_supported(p + 2);
3323 else
3324 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003325 }
3326 else /* internal variable */
3327 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003328 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329 }
3330
3331 rettv->vval.v_number = n;
3332}
3333
3334#ifdef FEAT_FLOAT
3335/*
3336 * "exp()" function
3337 */
3338 static void
3339f_exp(typval_T *argvars, typval_T *rettv)
3340{
3341 float_T f = 0.0;
3342
3343 rettv->v_type = VAR_FLOAT;
3344 if (get_float_arg(argvars, &f) == OK)
3345 rettv->vval.v_float = exp(f);
3346 else
3347 rettv->vval.v_float = 0.0;
3348}
3349#endif
3350
3351/*
3352 * "expand()" function
3353 */
3354 static void
3355f_expand(typval_T *argvars, typval_T *rettv)
3356{
3357 char_u *s;
3358 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003359 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3361 expand_T xpc;
3362 int error = FALSE;
3363 char_u *result;
3364
3365 rettv->v_type = VAR_STRING;
3366 if (argvars[1].v_type != VAR_UNKNOWN
3367 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003368 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003370 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003372 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003373 if (*s == '%' || *s == '#' || *s == '<')
3374 {
3375 ++emsg_off;
3376 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3377 --emsg_off;
3378 if (rettv->v_type == VAR_LIST)
3379 {
3380 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3381 list_append_string(rettv->vval.v_list, result, -1);
3382 else
3383 vim_free(result);
3384 }
3385 else
3386 rettv->vval.v_string = result;
3387 }
3388 else
3389 {
3390 /* When the optional second argument is non-zero, don't remove matches
3391 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3392 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003393 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003394 options |= WILD_KEEP_ALL;
3395 if (!error)
3396 {
3397 ExpandInit(&xpc);
3398 xpc.xp_context = EXPAND_FILES;
3399 if (p_wic)
3400 options += WILD_ICASE;
3401 if (rettv->v_type == VAR_STRING)
3402 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3403 options, WILD_ALL);
3404 else if (rettv_list_alloc(rettv) != FAIL)
3405 {
3406 int i;
3407
3408 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3409 for (i = 0; i < xpc.xp_numfiles; i++)
3410 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3411 ExpandCleanup(&xpc);
3412 }
3413 }
3414 else
3415 rettv->vval.v_string = NULL;
3416 }
3417}
3418
3419/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003420 * "expandcmd()" function
3421 * Expand all the special characters in a command string.
3422 */
3423 static void
3424f_expandcmd(typval_T *argvars, typval_T *rettv)
3425{
3426 exarg_T eap;
3427 char_u *cmdstr;
3428 char *errormsg = NULL;
3429
3430 rettv->v_type = VAR_STRING;
3431 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3432
3433 memset(&eap, 0, sizeof(eap));
3434 eap.cmd = cmdstr;
3435 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003436 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003437 eap.usefilter = FALSE;
3438 eap.nextcmd = NULL;
3439 eap.cmdidx = CMD_USER;
3440
3441 expand_filename(&eap, &cmdstr, &errormsg);
3442 if (errormsg != NULL && *errormsg != NUL)
3443 emsg(errormsg);
3444
3445 rettv->vval.v_string = cmdstr;
3446}
3447
3448/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 * "extend(list, list [, idx])" function
3450 * "extend(dict, dict [, action])" function
3451 */
3452 static void
3453f_extend(typval_T *argvars, typval_T *rettv)
3454{
3455 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3456
3457 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3458 {
3459 list_T *l1, *l2;
3460 listitem_T *item;
3461 long before;
3462 int error = FALSE;
3463
3464 l1 = argvars[0].vval.v_list;
3465 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003466 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467 && l2 != NULL)
3468 {
3469 if (argvars[2].v_type != VAR_UNKNOWN)
3470 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003471 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 if (error)
3473 return; /* type error; errmsg already given */
3474
3475 if (before == l1->lv_len)
3476 item = NULL;
3477 else
3478 {
3479 item = list_find(l1, before);
3480 if (item == NULL)
3481 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003482 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 return;
3484 }
3485 }
3486 }
3487 else
3488 item = NULL;
3489 list_extend(l1, l2, item);
3490
3491 copy_tv(&argvars[0], rettv);
3492 }
3493 }
3494 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3495 {
3496 dict_T *d1, *d2;
3497 char_u *action;
3498 int i;
3499
3500 d1 = argvars[0].vval.v_dict;
3501 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003502 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503 && d2 != NULL)
3504 {
3505 /* Check the third argument. */
3506 if (argvars[2].v_type != VAR_UNKNOWN)
3507 {
3508 static char *(av[]) = {"keep", "force", "error"};
3509
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003510 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511 if (action == NULL)
3512 return; /* type error; errmsg already given */
3513 for (i = 0; i < 3; ++i)
3514 if (STRCMP(action, av[i]) == 0)
3515 break;
3516 if (i == 3)
3517 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003518 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519 return;
3520 }
3521 }
3522 else
3523 action = (char_u *)"force";
3524
3525 dict_extend(d1, d2, action);
3526
3527 copy_tv(&argvars[0], rettv);
3528 }
3529 }
3530 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003531 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003532}
3533
3534/*
3535 * "feedkeys()" function
3536 */
3537 static void
3538f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3539{
3540 int remap = TRUE;
3541 int insert = FALSE;
3542 char_u *keys, *flags;
3543 char_u nbuf[NUMBUFLEN];
3544 int typed = FALSE;
3545 int execute = FALSE;
3546 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003547 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548 char_u *keys_esc;
3549
3550 /* This is not allowed in the sandbox. If the commands would still be
3551 * executed in the sandbox it would be OK, but it probably happens later,
3552 * when "sandbox" is no longer set. */
3553 if (check_secure())
3554 return;
3555
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003556 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003557
3558 if (argvars[1].v_type != VAR_UNKNOWN)
3559 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003560 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 for ( ; *flags != NUL; ++flags)
3562 {
3563 switch (*flags)
3564 {
3565 case 'n': remap = FALSE; break;
3566 case 'm': remap = TRUE; break;
3567 case 't': typed = TRUE; break;
3568 case 'i': insert = TRUE; break;
3569 case 'x': execute = TRUE; break;
3570 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003571 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 }
3573 }
3574 }
3575
3576 if (*keys != NUL || execute)
3577 {
3578 /* Need to escape K_SPECIAL and CSI before putting the string in the
3579 * typeahead buffer. */
3580 keys_esc = vim_strsave_escape_csi(keys);
3581 if (keys_esc != NULL)
3582 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003583 if (lowlevel)
3584 {
3585#ifdef USE_INPUT_BUF
3586 add_to_input_buf(keys, (int)STRLEN(keys));
3587#else
3588 emsg(_("E980: lowlevel input not supported"));
3589#endif
3590 }
3591 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003592 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003593 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003595 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003596#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003597 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003598#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003599 )
3600 typebuf_was_filled = TRUE;
3601 }
3602 vim_free(keys_esc);
3603
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003604 if (execute)
3605 {
3606 int save_msg_scroll = msg_scroll;
3607
3608 /* Avoid a 1 second delay when the keys start Insert mode. */
3609 msg_scroll = FALSE;
3610
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003611 if (!dangerous)
3612 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003613 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003614 if (!dangerous)
3615 --ex_normal_busy;
3616
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617 msg_scroll |= save_msg_scroll;
3618 }
3619 }
3620 }
3621}
3622
3623/*
3624 * "filereadable()" function
3625 */
3626 static void
3627f_filereadable(typval_T *argvars, typval_T *rettv)
3628{
3629 int fd;
3630 char_u *p;
3631 int n;
3632
3633#ifndef O_NONBLOCK
3634# define O_NONBLOCK 0
3635#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003636 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3638 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3639 {
3640 n = TRUE;
3641 close(fd);
3642 }
3643 else
3644 n = FALSE;
3645
3646 rettv->vval.v_number = n;
3647}
3648
3649/*
3650 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3651 * rights to write into.
3652 */
3653 static void
3654f_filewritable(typval_T *argvars, typval_T *rettv)
3655{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003656 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657}
3658
3659 static void
3660findfilendir(
3661 typval_T *argvars UNUSED,
3662 typval_T *rettv,
3663 int find_what UNUSED)
3664{
3665#ifdef FEAT_SEARCHPATH
3666 char_u *fname;
3667 char_u *fresult = NULL;
3668 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3669 char_u *p;
3670 char_u pathbuf[NUMBUFLEN];
3671 int count = 1;
3672 int first = TRUE;
3673 int error = FALSE;
3674#endif
3675
3676 rettv->vval.v_string = NULL;
3677 rettv->v_type = VAR_STRING;
3678
3679#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003680 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681
3682 if (argvars[1].v_type != VAR_UNKNOWN)
3683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003684 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685 if (p == NULL)
3686 error = TRUE;
3687 else
3688 {
3689 if (*p != NUL)
3690 path = p;
3691
3692 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003693 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694 }
3695 }
3696
3697 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3698 error = TRUE;
3699
3700 if (*fname != NUL && !error)
3701 {
3702 do
3703 {
3704 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3705 vim_free(fresult);
3706 fresult = find_file_in_path_option(first ? fname : NULL,
3707 first ? (int)STRLEN(fname) : 0,
3708 0, first, path,
3709 find_what,
3710 curbuf->b_ffname,
3711 find_what == FINDFILE_DIR
3712 ? (char_u *)"" : curbuf->b_p_sua);
3713 first = FALSE;
3714
3715 if (fresult != NULL && rettv->v_type == VAR_LIST)
3716 list_append_string(rettv->vval.v_list, fresult, -1);
3717
3718 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3719 }
3720
3721 if (rettv->v_type == VAR_STRING)
3722 rettv->vval.v_string = fresult;
3723#endif
3724}
3725
3726/*
3727 * "filter()" function
3728 */
3729 static void
3730f_filter(typval_T *argvars, typval_T *rettv)
3731{
3732 filter_map(argvars, rettv, FALSE);
3733}
3734
3735/*
3736 * "finddir({fname}[, {path}[, {count}]])" function
3737 */
3738 static void
3739f_finddir(typval_T *argvars, typval_T *rettv)
3740{
3741 findfilendir(argvars, rettv, FINDFILE_DIR);
3742}
3743
3744/*
3745 * "findfile({fname}[, {path}[, {count}]])" function
3746 */
3747 static void
3748f_findfile(typval_T *argvars, typval_T *rettv)
3749{
3750 findfilendir(argvars, rettv, FINDFILE_FILE);
3751}
3752
3753#ifdef FEAT_FLOAT
3754/*
3755 * "float2nr({float})" function
3756 */
3757 static void
3758f_float2nr(typval_T *argvars, typval_T *rettv)
3759{
3760 float_T f = 0.0;
3761
3762 if (get_float_arg(argvars, &f) == OK)
3763 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003764 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003765 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003766 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003767 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003768 else
3769 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 }
3771}
3772
3773/*
3774 * "floor({float})" function
3775 */
3776 static void
3777f_floor(typval_T *argvars, typval_T *rettv)
3778{
3779 float_T f = 0.0;
3780
3781 rettv->v_type = VAR_FLOAT;
3782 if (get_float_arg(argvars, &f) == OK)
3783 rettv->vval.v_float = floor(f);
3784 else
3785 rettv->vval.v_float = 0.0;
3786}
3787
3788/*
3789 * "fmod()" function
3790 */
3791 static void
3792f_fmod(typval_T *argvars, typval_T *rettv)
3793{
3794 float_T fx = 0.0, fy = 0.0;
3795
3796 rettv->v_type = VAR_FLOAT;
3797 if (get_float_arg(argvars, &fx) == OK
3798 && get_float_arg(&argvars[1], &fy) == OK)
3799 rettv->vval.v_float = fmod(fx, fy);
3800 else
3801 rettv->vval.v_float = 0.0;
3802}
3803#endif
3804
3805/*
3806 * "fnameescape({string})" function
3807 */
3808 static void
3809f_fnameescape(typval_T *argvars, typval_T *rettv)
3810{
3811 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003812 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813 rettv->v_type = VAR_STRING;
3814}
3815
3816/*
3817 * "fnamemodify({fname}, {mods})" function
3818 */
3819 static void
3820f_fnamemodify(typval_T *argvars, typval_T *rettv)
3821{
3822 char_u *fname;
3823 char_u *mods;
3824 int usedlen = 0;
3825 int len;
3826 char_u *fbuf = NULL;
3827 char_u buf[NUMBUFLEN];
3828
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003829 fname = tv_get_string_chk(&argvars[0]);
3830 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831 if (fname == NULL || mods == NULL)
3832 fname = NULL;
3833 else
3834 {
3835 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003836 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837 }
3838
3839 rettv->v_type = VAR_STRING;
3840 if (fname == NULL)
3841 rettv->vval.v_string = NULL;
3842 else
3843 rettv->vval.v_string = vim_strnsave(fname, len);
3844 vim_free(fbuf);
3845}
3846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847/*
3848 * "foldclosed()" function
3849 */
3850 static void
3851foldclosed_both(
3852 typval_T *argvars UNUSED,
3853 typval_T *rettv,
3854 int end UNUSED)
3855{
3856#ifdef FEAT_FOLDING
3857 linenr_T lnum;
3858 linenr_T first, last;
3859
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003860 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3862 {
3863 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3864 {
3865 if (end)
3866 rettv->vval.v_number = (varnumber_T)last;
3867 else
3868 rettv->vval.v_number = (varnumber_T)first;
3869 return;
3870 }
3871 }
3872#endif
3873 rettv->vval.v_number = -1;
3874}
3875
3876/*
3877 * "foldclosed()" function
3878 */
3879 static void
3880f_foldclosed(typval_T *argvars, typval_T *rettv)
3881{
3882 foldclosed_both(argvars, rettv, FALSE);
3883}
3884
3885/*
3886 * "foldclosedend()" function
3887 */
3888 static void
3889f_foldclosedend(typval_T *argvars, typval_T *rettv)
3890{
3891 foldclosed_both(argvars, rettv, TRUE);
3892}
3893
3894/*
3895 * "foldlevel()" function
3896 */
3897 static void
3898f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3899{
3900#ifdef FEAT_FOLDING
3901 linenr_T lnum;
3902
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003903 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003904 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3905 rettv->vval.v_number = foldLevel(lnum);
3906#endif
3907}
3908
3909/*
3910 * "foldtext()" function
3911 */
3912 static void
3913f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3914{
3915#ifdef FEAT_FOLDING
3916 linenr_T foldstart;
3917 linenr_T foldend;
3918 char_u *dashes;
3919 linenr_T lnum;
3920 char_u *s;
3921 char_u *r;
3922 int len;
3923 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003924 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925#endif
3926
3927 rettv->v_type = VAR_STRING;
3928 rettv->vval.v_string = NULL;
3929#ifdef FEAT_FOLDING
3930 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3931 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3932 dashes = get_vim_var_str(VV_FOLDDASHES);
3933 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3934 && dashes != NULL)
3935 {
3936 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003937 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003938 if (!linewhite(lnum))
3939 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940
3941 /* Find interesting text in this line. */
3942 s = skipwhite(ml_get(lnum));
3943 /* skip C comment-start */
3944 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3945 {
3946 s = skipwhite(s + 2);
3947 if (*skipwhite(s) == NUL
3948 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3949 {
3950 s = skipwhite(ml_get(lnum + 1));
3951 if (*s == '*')
3952 s = skipwhite(s + 1);
3953 }
3954 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003955 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003956 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003957 r = alloc(STRLEN(txt)
3958 + STRLEN(dashes) // for %s
3959 + 20 // for %3ld
3960 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961 if (r != NULL)
3962 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003963 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003964 len = (int)STRLEN(r);
3965 STRCAT(r, s);
3966 /* remove 'foldmarker' and 'commentstring' */
3967 foldtext_cleanup(r + len);
3968 rettv->vval.v_string = r;
3969 }
3970 }
3971#endif
3972}
3973
3974/*
3975 * "foldtextresult(lnum)" function
3976 */
3977 static void
3978f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3979{
3980#ifdef FEAT_FOLDING
3981 linenr_T lnum;
3982 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003983 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 foldinfo_T foldinfo;
3985 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003986 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987#endif
3988
3989 rettv->v_type = VAR_STRING;
3990 rettv->vval.v_string = NULL;
3991#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003992 if (entered)
3993 return; /* reject recursive use */
3994 entered = TRUE;
3995
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003996 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 /* treat illegal types and illegal string values for {lnum} the same */
3998 if (lnum < 0)
3999 lnum = 0;
4000 fold_count = foldedCount(curwin, lnum, &foldinfo);
4001 if (fold_count > 0)
4002 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004003 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4004 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004005 if (text == buf)
4006 text = vim_strsave(text);
4007 rettv->vval.v_string = text;
4008 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004009
4010 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011#endif
4012}
4013
4014/*
4015 * "foreground()" function
4016 */
4017 static void
4018f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4019{
4020#ifdef FEAT_GUI
4021 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004022 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004024 return;
4025 }
4026#endif
4027#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004028 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029#endif
4030}
4031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004032 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004033common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034{
4035 char_u *s;
4036 char_u *name;
4037 int use_string = FALSE;
4038 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004039 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004040
4041 if (argvars[0].v_type == VAR_FUNC)
4042 {
4043 /* function(MyFunc, [arg], dict) */
4044 s = argvars[0].vval.v_string;
4045 }
4046 else if (argvars[0].v_type == VAR_PARTIAL
4047 && argvars[0].vval.v_partial != NULL)
4048 {
4049 /* function(dict.MyFunc, [arg]) */
4050 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004051 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004052 }
4053 else
4054 {
4055 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004056 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 use_string = TRUE;
4058 }
4059
Bram Moolenaar843b8842016-08-21 14:36:15 +02004060 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004061 {
4062 name = s;
4063 trans_name = trans_function_name(&name, FALSE,
4064 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4065 if (*name != NUL)
4066 s = NULL;
4067 }
4068
Bram Moolenaar843b8842016-08-21 14:36:15 +02004069 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4070 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004071 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004073 else if (trans_name != NULL && (is_funcref
4074 ? find_func(trans_name) == NULL
4075 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004076 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004077 else
4078 {
4079 int dict_idx = 0;
4080 int arg_idx = 0;
4081 list_T *list = NULL;
4082
4083 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4084 {
4085 char sid_buf[25];
4086 int off = *s == 's' ? 2 : 5;
4087
4088 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4089 * also be called from another script. Using trans_function_name()
4090 * would also work, but some plugins depend on the name being
4091 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004092 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004093 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004094 if (name != NULL)
4095 {
4096 STRCPY(name, sid_buf);
4097 STRCAT(name, s + off);
4098 }
4099 }
4100 else
4101 name = vim_strsave(s);
4102
4103 if (argvars[1].v_type != VAR_UNKNOWN)
4104 {
4105 if (argvars[2].v_type != VAR_UNKNOWN)
4106 {
4107 /* function(name, [args], dict) */
4108 arg_idx = 1;
4109 dict_idx = 2;
4110 }
4111 else if (argvars[1].v_type == VAR_DICT)
4112 /* function(name, dict) */
4113 dict_idx = 1;
4114 else
4115 /* function(name, [args]) */
4116 arg_idx = 1;
4117 if (dict_idx > 0)
4118 {
4119 if (argvars[dict_idx].v_type != VAR_DICT)
4120 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004121 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004122 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004123 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004124 }
4125 if (argvars[dict_idx].vval.v_dict == NULL)
4126 dict_idx = 0;
4127 }
4128 if (arg_idx > 0)
4129 {
4130 if (argvars[arg_idx].v_type != VAR_LIST)
4131 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004132 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004133 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004134 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004135 }
4136 list = argvars[arg_idx].vval.v_list;
4137 if (list == NULL || list->lv_len == 0)
4138 arg_idx = 0;
4139 }
4140 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004141 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004142 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004143 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004144
4145 /* result is a VAR_PARTIAL */
4146 if (pt == NULL)
4147 vim_free(name);
4148 else
4149 {
4150 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4151 {
4152 listitem_T *li;
4153 int i = 0;
4154 int arg_len = 0;
4155 int lv_len = 0;
4156
4157 if (arg_pt != NULL)
4158 arg_len = arg_pt->pt_argc;
4159 if (list != NULL)
4160 lv_len = list->lv_len;
4161 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004162 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163 if (pt->pt_argv == NULL)
4164 {
4165 vim_free(pt);
4166 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004167 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004168 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004169 for (i = 0; i < arg_len; i++)
4170 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4171 if (lv_len > 0)
4172 for (li = list->lv_first; li != NULL;
4173 li = li->li_next)
4174 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004175 }
4176
4177 /* For "function(dict.func, [], dict)" and "func" is a partial
4178 * use "dict". That is backwards compatible. */
4179 if (dict_idx > 0)
4180 {
4181 /* The dict is bound explicitly, pt_auto is FALSE. */
4182 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4183 ++pt->pt_dict->dv_refcount;
4184 }
4185 else if (arg_pt != NULL)
4186 {
4187 /* If the dict was bound automatically the result is also
4188 * bound automatically. */
4189 pt->pt_dict = arg_pt->pt_dict;
4190 pt->pt_auto = arg_pt->pt_auto;
4191 if (pt->pt_dict != NULL)
4192 ++pt->pt_dict->dv_refcount;
4193 }
4194
4195 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004196 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4197 {
4198 pt->pt_func = arg_pt->pt_func;
4199 func_ptr_ref(pt->pt_func);
4200 vim_free(name);
4201 }
4202 else if (is_funcref)
4203 {
4204 pt->pt_func = find_func(trans_name);
4205 func_ptr_ref(pt->pt_func);
4206 vim_free(name);
4207 }
4208 else
4209 {
4210 pt->pt_name = name;
4211 func_ref(name);
4212 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004213 }
4214 rettv->v_type = VAR_PARTIAL;
4215 rettv->vval.v_partial = pt;
4216 }
4217 else
4218 {
4219 /* result is a VAR_FUNC */
4220 rettv->v_type = VAR_FUNC;
4221 rettv->vval.v_string = name;
4222 func_ref(name);
4223 }
4224 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004225theend:
4226 vim_free(trans_name);
4227}
4228
4229/*
4230 * "funcref()" function
4231 */
4232 static void
4233f_funcref(typval_T *argvars, typval_T *rettv)
4234{
4235 common_function(argvars, rettv, TRUE);
4236}
4237
4238/*
4239 * "function()" function
4240 */
4241 static void
4242f_function(typval_T *argvars, typval_T *rettv)
4243{
4244 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245}
4246
4247/*
4248 * "garbagecollect()" function
4249 */
4250 static void
4251f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4252{
4253 /* This is postponed until we are back at the toplevel, because we may be
4254 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4255 want_garbage_collect = TRUE;
4256
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004257 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258 garbage_collect_at_exit = TRUE;
4259}
4260
4261/*
4262 * "get()" function
4263 */
4264 static void
4265f_get(typval_T *argvars, typval_T *rettv)
4266{
4267 listitem_T *li;
4268 list_T *l;
4269 dictitem_T *di;
4270 dict_T *d;
4271 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004272 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004273
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004274 if (argvars[0].v_type == VAR_BLOB)
4275 {
4276 int error = FALSE;
4277 int idx = tv_get_number_chk(&argvars[1], &error);
4278
4279 if (!error)
4280 {
4281 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004282 if (idx < 0)
4283 idx = blob_len(argvars[0].vval.v_blob) + idx;
4284 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4285 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004286 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004287 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004288 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004289 tv = rettv;
4290 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004291 }
4292 }
4293 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004294 {
4295 if ((l = argvars[0].vval.v_list) != NULL)
4296 {
4297 int error = FALSE;
4298
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004299 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004300 if (!error && li != NULL)
4301 tv = &li->li_tv;
4302 }
4303 }
4304 else if (argvars[0].v_type == VAR_DICT)
4305 {
4306 if ((d = argvars[0].vval.v_dict) != NULL)
4307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004308 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 if (di != NULL)
4310 tv = &di->di_tv;
4311 }
4312 }
4313 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4314 {
4315 partial_T *pt;
4316 partial_T fref_pt;
4317
4318 if (argvars[0].v_type == VAR_PARTIAL)
4319 pt = argvars[0].vval.v_partial;
4320 else
4321 {
4322 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4323 fref_pt.pt_name = argvars[0].vval.v_string;
4324 pt = &fref_pt;
4325 }
4326
4327 if (pt != NULL)
4328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004329 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004330 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004331
4332 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4333 {
4334 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004335 n = partial_name(pt);
4336 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004337 rettv->vval.v_string = NULL;
4338 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004339 {
4340 rettv->vval.v_string = vim_strsave(n);
4341 if (rettv->v_type == VAR_FUNC)
4342 func_ref(rettv->vval.v_string);
4343 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004344 }
4345 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004346 {
4347 what_is_dict = TRUE;
4348 if (pt->pt_dict != NULL)
4349 rettv_dict_set(rettv, pt->pt_dict);
4350 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004351 else if (STRCMP(what, "args") == 0)
4352 {
4353 rettv->v_type = VAR_LIST;
4354 if (rettv_list_alloc(rettv) == OK)
4355 {
4356 int i;
4357
4358 for (i = 0; i < pt->pt_argc; ++i)
4359 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4360 }
4361 }
4362 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004363 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004364
4365 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4366 // third argument
4367 if (!what_is_dict)
4368 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004369 }
4370 }
4371 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004372 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373
4374 if (tv == NULL)
4375 {
4376 if (argvars[2].v_type != VAR_UNKNOWN)
4377 copy_tv(&argvars[2], rettv);
4378 }
4379 else
4380 copy_tv(tv, rettv);
4381}
4382
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004383/*
4384 * Returns buffer options, variables and other attributes in a dictionary.
4385 */
4386 static dict_T *
4387get_buffer_info(buf_T *buf)
4388{
4389 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004390 tabpage_T *tp;
4391 win_T *wp;
4392 list_T *windows;
4393
4394 dict = dict_alloc();
4395 if (dict == NULL)
4396 return NULL;
4397
Bram Moolenaare0be1672018-07-08 16:50:37 +02004398 dict_add_number(dict, "bufnr", buf->b_fnum);
4399 dict_add_string(dict, "name", buf->b_ffname);
4400 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4401 : buflist_findlnum(buf));
4402 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4403 dict_add_number(dict, "listed", buf->b_p_bl);
4404 dict_add_number(dict, "changed", bufIsChanged(buf));
4405 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4406 dict_add_number(dict, "hidden",
4407 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004408
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004409 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004410 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004411
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004412 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004413 windows = list_alloc();
4414 if (windows != NULL)
4415 {
4416 FOR_ALL_TAB_WINDOWS(tp, wp)
4417 if (wp->w_buffer == buf)
4418 list_append_number(windows, (varnumber_T)wp->w_id);
4419 dict_add_list(dict, "windows", windows);
4420 }
4421
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004422#ifdef FEAT_TEXT_PROP
4423 // List of popup windows displaying this buffer
4424 windows = list_alloc();
4425 if (windows != NULL)
4426 {
4427 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4428 if (wp->w_buffer == buf)
4429 list_append_number(windows, (varnumber_T)wp->w_id);
4430 FOR_ALL_TABPAGES(tp)
4431 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4432 if (wp->w_buffer == buf)
4433 list_append_number(windows, (varnumber_T)wp->w_id);
4434
4435 dict_add_list(dict, "popups", windows);
4436 }
4437#endif
4438
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004439#ifdef FEAT_SIGNS
4440 if (buf->b_signlist != NULL)
4441 {
4442 /* List of signs placed in this buffer */
4443 list_T *signs = list_alloc();
4444 if (signs != NULL)
4445 {
4446 get_buffer_signs(buf, signs);
4447 dict_add_list(dict, "signs", signs);
4448 }
4449 }
4450#endif
4451
4452 return dict;
4453}
4454
4455/*
4456 * "getbufinfo()" function
4457 */
4458 static void
4459f_getbufinfo(typval_T *argvars, typval_T *rettv)
4460{
4461 buf_T *buf = NULL;
4462 buf_T *argbuf = NULL;
4463 dict_T *d;
4464 int filtered = FALSE;
4465 int sel_buflisted = FALSE;
4466 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004467 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004468
4469 if (rettv_list_alloc(rettv) != OK)
4470 return;
4471
4472 /* List of all the buffers or selected buffers */
4473 if (argvars[0].v_type == VAR_DICT)
4474 {
4475 dict_T *sel_d = argvars[0].vval.v_dict;
4476
4477 if (sel_d != NULL)
4478 {
4479 dictitem_T *di;
4480
4481 filtered = TRUE;
4482
4483 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004484 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004485 sel_buflisted = TRUE;
4486
4487 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004488 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004489 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004490
4491 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004492 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004493 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004494 }
4495 }
4496 else if (argvars[0].v_type != VAR_UNKNOWN)
4497 {
4498 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004499 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004500 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004501 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004502 --emsg_off;
4503 if (argbuf == NULL)
4504 return;
4505 }
4506
4507 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004508 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004509 {
4510 if (argbuf != NULL && argbuf != buf)
4511 continue;
4512 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004513 || (sel_buflisted && !buf->b_p_bl)
4514 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004515 continue;
4516
4517 d = get_buffer_info(buf);
4518 if (d != NULL)
4519 list_append_dict(rettv->vval.v_list, d);
4520 if (argbuf != NULL)
4521 return;
4522 }
4523}
4524
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004525/*
4526 * Get line or list of lines from buffer "buf" into "rettv".
4527 * Return a range (from start to end) of lines in rettv from the specified
4528 * buffer.
4529 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4530 */
4531 static void
4532get_buffer_lines(
4533 buf_T *buf,
4534 linenr_T start,
4535 linenr_T end,
4536 int retlist,
4537 typval_T *rettv)
4538{
4539 char_u *p;
4540
4541 rettv->v_type = VAR_STRING;
4542 rettv->vval.v_string = NULL;
4543 if (retlist && rettv_list_alloc(rettv) == FAIL)
4544 return;
4545
4546 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4547 return;
4548
4549 if (!retlist)
4550 {
4551 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4552 p = ml_get_buf(buf, start, FALSE);
4553 else
4554 p = (char_u *)"";
4555 rettv->vval.v_string = vim_strsave(p);
4556 }
4557 else
4558 {
4559 if (end < start)
4560 return;
4561
4562 if (start < 1)
4563 start = 1;
4564 if (end > buf->b_ml.ml_line_count)
4565 end = buf->b_ml.ml_line_count;
4566 while (start <= end)
4567 if (list_append_string(rettv->vval.v_list,
4568 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4569 break;
4570 }
4571}
4572
4573/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574 * "getbufline()" function
4575 */
4576 static void
4577f_getbufline(typval_T *argvars, typval_T *rettv)
4578{
4579 linenr_T lnum;
4580 linenr_T end;
4581 buf_T *buf;
4582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004583 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004585 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 --emsg_off;
4587
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004588 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004589 if (argvars[2].v_type == VAR_UNKNOWN)
4590 end = lnum;
4591 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004592 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593
4594 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4595}
4596
4597/*
4598 * "getbufvar()" function
4599 */
4600 static void
4601f_getbufvar(typval_T *argvars, typval_T *rettv)
4602{
4603 buf_T *buf;
4604 buf_T *save_curbuf;
4605 char_u *varname;
4606 dictitem_T *v;
4607 int done = FALSE;
4608
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004609 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4610 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004612 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004613
4614 rettv->v_type = VAR_STRING;
4615 rettv->vval.v_string = NULL;
4616
4617 if (buf != NULL && varname != NULL)
4618 {
4619 /* set curbuf to be our buf, temporarily */
4620 save_curbuf = curbuf;
4621 curbuf = buf;
4622
Bram Moolenaar30567352016-08-27 21:25:44 +02004623 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004624 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004625 if (varname[1] == NUL)
4626 {
4627 /* get all buffer-local options in a dict */
4628 dict_T *opts = get_winbuf_options(TRUE);
4629
4630 if (opts != NULL)
4631 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004632 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004633 done = TRUE;
4634 }
4635 }
4636 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4637 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004638 done = TRUE;
4639 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640 else
4641 {
4642 /* Look up the variable. */
4643 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4644 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4645 'b', varname, FALSE);
4646 if (v != NULL)
4647 {
4648 copy_tv(&v->di_tv, rettv);
4649 done = TRUE;
4650 }
4651 }
4652
4653 /* restore previous notion of curbuf */
4654 curbuf = save_curbuf;
4655 }
4656
4657 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4658 /* use the default value */
4659 copy_tv(&argvars[2], rettv);
4660
4661 --emsg_off;
4662}
4663
4664/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004665 * "getchangelist()" function
4666 */
4667 static void
4668f_getchangelist(typval_T *argvars, typval_T *rettv)
4669{
4670#ifdef FEAT_JUMPLIST
4671 buf_T *buf;
4672 int i;
4673 list_T *l;
4674 dict_T *d;
4675#endif
4676
4677 if (rettv_list_alloc(rettv) != OK)
4678 return;
4679
4680#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004681 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004682 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004683 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004684 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004685 if (buf == NULL)
4686 return;
4687
4688 l = list_alloc();
4689 if (l == NULL)
4690 return;
4691
4692 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4693 return;
4694 /*
4695 * The current window change list index tracks only the position in the
4696 * current buffer change list. For other buffers, use the change list
4697 * length as the current index.
4698 */
4699 list_append_number(rettv->vval.v_list,
4700 (varnumber_T)((buf == curwin->w_buffer)
4701 ? curwin->w_changelistidx : buf->b_changelistlen));
4702
4703 for (i = 0; i < buf->b_changelistlen; ++i)
4704 {
4705 if (buf->b_changelist[i].lnum == 0)
4706 continue;
4707 if ((d = dict_alloc()) == NULL)
4708 return;
4709 if (list_append_dict(l, d) == FAIL)
4710 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004711 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4712 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004713 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004714 }
4715#endif
4716}
4717/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 * "getchar()" function
4719 */
4720 static void
4721f_getchar(typval_T *argvars, typval_T *rettv)
4722{
4723 varnumber_T n;
4724 int error = FALSE;
4725
Bram Moolenaar84d93902018-09-11 20:10:20 +02004726#ifdef MESSAGE_QUEUE
4727 // vpeekc() used to check for messages, but that caused problems, invoking
4728 // a callback where it was not expected. Some plugins use getchar(1) in a
4729 // loop to await a message, therefore make sure we check for messages here.
4730 parse_queued_messages();
4731#endif
4732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 /* Position the cursor. Needed after a message that ends in a space. */
4734 windgoto(msg_row, msg_col);
4735
4736 ++no_mapping;
4737 ++allow_keys;
4738 for (;;)
4739 {
4740 if (argvars[0].v_type == VAR_UNKNOWN)
4741 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004742 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004743 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004744 /* getchar(1): only check if char avail */
4745 n = vpeekc_any();
4746 else if (error || vpeekc_any() == NUL)
4747 /* illegal argument or getchar(0) and no char avail: return zero */
4748 n = 0;
4749 else
4750 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004751 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752
4753 if (n == K_IGNORE)
4754 continue;
4755 break;
4756 }
4757 --no_mapping;
4758 --allow_keys;
4759
4760 set_vim_var_nr(VV_MOUSE_WIN, 0);
4761 set_vim_var_nr(VV_MOUSE_WINID, 0);
4762 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4763 set_vim_var_nr(VV_MOUSE_COL, 0);
4764
4765 rettv->vval.v_number = n;
4766 if (IS_SPECIAL(n) || mod_mask != 0)
4767 {
4768 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4769 int i = 0;
4770
4771 /* Turn a special key into three bytes, plus modifier. */
4772 if (mod_mask != 0)
4773 {
4774 temp[i++] = K_SPECIAL;
4775 temp[i++] = KS_MODIFIER;
4776 temp[i++] = mod_mask;
4777 }
4778 if (IS_SPECIAL(n))
4779 {
4780 temp[i++] = K_SPECIAL;
4781 temp[i++] = K_SECOND(n);
4782 temp[i++] = K_THIRD(n);
4783 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004784 else if (has_mbyte)
4785 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004786 else
4787 temp[i++] = n;
4788 temp[i++] = NUL;
4789 rettv->v_type = VAR_STRING;
4790 rettv->vval.v_string = vim_strsave(temp);
4791
4792#ifdef FEAT_MOUSE
4793 if (is_mouse_key(n))
4794 {
4795 int row = mouse_row;
4796 int col = mouse_col;
4797 win_T *win;
4798 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004799 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800 int winnr = 1;
4801
4802 if (row >= 0 && col >= 0)
4803 {
4804 /* Find the window at the mouse coordinates and compute the
4805 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004806 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004807 if (win == NULL)
4808 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004809 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004810# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004811 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004812 winnr = 0;
4813 else
4814# endif
4815 for (wp = firstwin; wp != win && wp != NULL;
4816 wp = wp->w_next)
4817 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004818 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4819 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4820 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4821 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4822 }
4823 }
4824#endif
4825 }
4826}
4827
4828/*
4829 * "getcharmod()" function
4830 */
4831 static void
4832f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4833{
4834 rettv->vval.v_number = mod_mask;
4835}
4836
4837/*
4838 * "getcharsearch()" function
4839 */
4840 static void
4841f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4842{
4843 if (rettv_dict_alloc(rettv) != FAIL)
4844 {
4845 dict_T *dict = rettv->vval.v_dict;
4846
Bram Moolenaare0be1672018-07-08 16:50:37 +02004847 dict_add_string(dict, "char", last_csearch());
4848 dict_add_number(dict, "forward", last_csearch_forward());
4849 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850 }
4851}
4852
4853/*
4854 * "getcmdline()" function
4855 */
4856 static void
4857f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4858{
4859 rettv->v_type = VAR_STRING;
4860 rettv->vval.v_string = get_cmdline_str();
4861}
4862
4863/*
4864 * "getcmdpos()" function
4865 */
4866 static void
4867f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4868{
4869 rettv->vval.v_number = get_cmdline_pos() + 1;
4870}
4871
4872/*
4873 * "getcmdtype()" function
4874 */
4875 static void
4876f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4877{
4878 rettv->v_type = VAR_STRING;
4879 rettv->vval.v_string = alloc(2);
4880 if (rettv->vval.v_string != NULL)
4881 {
4882 rettv->vval.v_string[0] = get_cmdline_type();
4883 rettv->vval.v_string[1] = NUL;
4884 }
4885}
4886
4887/*
4888 * "getcmdwintype()" function
4889 */
4890 static void
4891f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4892{
4893 rettv->v_type = VAR_STRING;
4894 rettv->vval.v_string = NULL;
4895#ifdef FEAT_CMDWIN
4896 rettv->vval.v_string = alloc(2);
4897 if (rettv->vval.v_string != NULL)
4898 {
4899 rettv->vval.v_string[0] = cmdwin_type;
4900 rettv->vval.v_string[1] = NUL;
4901 }
4902#endif
4903}
4904
4905#if defined(FEAT_CMDL_COMPL)
4906/*
4907 * "getcompletion()" function
4908 */
4909 static void
4910f_getcompletion(typval_T *argvars, typval_T *rettv)
4911{
4912 char_u *pat;
4913 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004914 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004915 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4916 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004918 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004919 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004920
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 if (p_wic)
4922 options |= WILD_ICASE;
4923
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004924 /* For filtered results, 'wildignore' is used */
4925 if (!filtered)
4926 options |= WILD_KEEP_ALL;
4927
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004929 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004931 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932 if (xpc.xp_context == EXPAND_NOTHING)
4933 {
4934 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004935 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004937 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004938 return;
4939 }
4940
4941# if defined(FEAT_MENU)
4942 if (xpc.xp_context == EXPAND_MENUS)
4943 {
4944 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4945 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4946 }
4947# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004948#ifdef FEAT_CSCOPE
4949 if (xpc.xp_context == EXPAND_CSCOPE)
4950 {
4951 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4952 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4953 }
4954#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004955#ifdef FEAT_SIGNS
4956 if (xpc.xp_context == EXPAND_SIGN)
4957 {
4958 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4959 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4960 }
4961#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004962
4963 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4964 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4965 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004966 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004967
4968 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4969
4970 for (i = 0; i < xpc.xp_numfiles; i++)
4971 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4972 }
4973 vim_free(pat);
4974 ExpandCleanup(&xpc);
4975}
4976#endif
4977
4978/*
4979 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004980 *
4981 * Return the current working directory of a window in a tab page.
4982 * First optional argument 'winnr' is the window number or -1 and the second
4983 * optional argument 'tabnr' is the tab page number.
4984 *
4985 * If no arguments are supplied, then return the directory of the current
4986 * window.
4987 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4988 * the specified window.
4989 * If 'winnr' is 0 then return the directory of the current window.
4990 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4991 * directory of the specified tab page. Otherwise return the directory of the
4992 * specified window in the specified tab page.
4993 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 */
4995 static void
4996f_getcwd(typval_T *argvars, typval_T *rettv)
4997{
4998 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004999 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005001 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002
5003 rettv->v_type = VAR_STRING;
5004 rettv->vval.v_string = NULL;
5005
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005006 if (argvars[0].v_type == VAR_NUMBER
5007 && argvars[0].vval.v_number == -1
5008 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005009 global = TRUE;
5010 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005011 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005012
5013 if (wp != NULL && wp->w_localdir != NULL)
5014 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005015 else if (tp != NULL && tp->tp_localdir != NULL)
5016 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5017 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005019 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005020 rettv->vval.v_string = vim_strsave(globaldir);
5021 else
5022 {
5023 cwd = alloc(MAXPATHL);
5024 if (cwd != NULL)
5025 {
5026 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5027 rettv->vval.v_string = vim_strsave(cwd);
5028 vim_free(cwd);
5029 }
5030 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005032#ifdef BACKSLASH_IN_FILENAME
5033 if (rettv->vval.v_string != NULL)
5034 slash_adjust(rettv->vval.v_string);
5035#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036}
5037
5038/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005039 * "getenv()" function
5040 */
5041 static void
5042f_getenv(typval_T *argvars, typval_T *rettv)
5043{
5044 int mustfree = FALSE;
5045 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5046
5047 if (p == NULL)
5048 {
5049 rettv->v_type = VAR_SPECIAL;
5050 rettv->vval.v_number = VVAL_NULL;
5051 return;
5052 }
5053 if (!mustfree)
5054 p = vim_strsave(p);
5055 rettv->vval.v_string = p;
5056 rettv->v_type = VAR_STRING;
5057}
5058
5059/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 * "getfontname()" function
5061 */
5062 static void
5063f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5064{
5065 rettv->v_type = VAR_STRING;
5066 rettv->vval.v_string = NULL;
5067#ifdef FEAT_GUI
5068 if (gui.in_use)
5069 {
5070 GuiFont font;
5071 char_u *name = NULL;
5072
5073 if (argvars[0].v_type == VAR_UNKNOWN)
5074 {
5075 /* Get the "Normal" font. Either the name saved by
5076 * hl_set_font_name() or from the font ID. */
5077 font = gui.norm_font;
5078 name = hl_get_font_name();
5079 }
5080 else
5081 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005082 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005083 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5084 return;
5085 font = gui_mch_get_font(name, FALSE);
5086 if (font == NOFONT)
5087 return; /* Invalid font name, return empty string. */
5088 }
5089 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5090 if (argvars[0].v_type != VAR_UNKNOWN)
5091 gui_mch_free_font(font);
5092 }
5093#endif
5094}
5095
5096/*
5097 * "getfperm({fname})" function
5098 */
5099 static void
5100f_getfperm(typval_T *argvars, typval_T *rettv)
5101{
5102 char_u *fname;
5103 stat_T st;
5104 char_u *perm = NULL;
5105 char_u flags[] = "rwx";
5106 int i;
5107
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005108 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109
5110 rettv->v_type = VAR_STRING;
5111 if (mch_stat((char *)fname, &st) >= 0)
5112 {
5113 perm = vim_strsave((char_u *)"---------");
5114 if (perm != NULL)
5115 {
5116 for (i = 0; i < 9; i++)
5117 {
5118 if (st.st_mode & (1 << (8 - i)))
5119 perm[i] = flags[i % 3];
5120 }
5121 }
5122 }
5123 rettv->vval.v_string = perm;
5124}
5125
5126/*
5127 * "getfsize({fname})" function
5128 */
5129 static void
5130f_getfsize(typval_T *argvars, typval_T *rettv)
5131{
5132 char_u *fname;
5133 stat_T st;
5134
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005135 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005136
5137 rettv->v_type = VAR_NUMBER;
5138
5139 if (mch_stat((char *)fname, &st) >= 0)
5140 {
5141 if (mch_isdir(fname))
5142 rettv->vval.v_number = 0;
5143 else
5144 {
5145 rettv->vval.v_number = (varnumber_T)st.st_size;
5146
5147 /* non-perfect check for overflow */
5148 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5149 rettv->vval.v_number = -2;
5150 }
5151 }
5152 else
5153 rettv->vval.v_number = -1;
5154}
5155
5156/*
5157 * "getftime({fname})" function
5158 */
5159 static void
5160f_getftime(typval_T *argvars, typval_T *rettv)
5161{
5162 char_u *fname;
5163 stat_T st;
5164
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005165 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166
5167 if (mch_stat((char *)fname, &st) >= 0)
5168 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5169 else
5170 rettv->vval.v_number = -1;
5171}
5172
5173/*
5174 * "getftype({fname})" function
5175 */
5176 static void
5177f_getftype(typval_T *argvars, typval_T *rettv)
5178{
5179 char_u *fname;
5180 stat_T st;
5181 char_u *type = NULL;
5182 char *t;
5183
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005184 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005185
5186 rettv->v_type = VAR_STRING;
5187 if (mch_lstat((char *)fname, &st) >= 0)
5188 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005189 if (S_ISREG(st.st_mode))
5190 t = "file";
5191 else if (S_ISDIR(st.st_mode))
5192 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 else if (S_ISLNK(st.st_mode))
5194 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005195 else if (S_ISBLK(st.st_mode))
5196 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 else if (S_ISCHR(st.st_mode))
5198 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 else if (S_ISFIFO(st.st_mode))
5200 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005202 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 else
5204 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 type = vim_strsave((char_u *)t);
5206 }
5207 rettv->vval.v_string = type;
5208}
5209
5210/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005211 * "getjumplist()" function
5212 */
5213 static void
5214f_getjumplist(typval_T *argvars, typval_T *rettv)
5215{
5216#ifdef FEAT_JUMPLIST
5217 win_T *wp;
5218 int i;
5219 list_T *l;
5220 dict_T *d;
5221#endif
5222
5223 if (rettv_list_alloc(rettv) != OK)
5224 return;
5225
5226#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005227 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005228 if (wp == NULL)
5229 return;
5230
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005231 cleanup_jumplist(wp, TRUE);
5232
Bram Moolenaar4f505882018-02-10 21:06:32 +01005233 l = list_alloc();
5234 if (l == NULL)
5235 return;
5236
5237 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5238 return;
5239 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5240
5241 for (i = 0; i < wp->w_jumplistlen; ++i)
5242 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005243 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5244 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005245 if ((d = dict_alloc()) == NULL)
5246 return;
5247 if (list_append_dict(l, d) == FAIL)
5248 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005249 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5250 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005251 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005252 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005253 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005254 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005255 }
5256#endif
5257}
5258
5259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005260 * "getline(lnum, [end])" function
5261 */
5262 static void
5263f_getline(typval_T *argvars, typval_T *rettv)
5264{
5265 linenr_T lnum;
5266 linenr_T end;
5267 int retlist;
5268
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005269 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005270 if (argvars[1].v_type == VAR_UNKNOWN)
5271 {
5272 end = 0;
5273 retlist = FALSE;
5274 }
5275 else
5276 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005277 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278 retlist = TRUE;
5279 }
5280
5281 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5282}
5283
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005284#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005285 static void
5286get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5287{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005288 if (what_arg->v_type == VAR_UNKNOWN)
5289 {
5290 if (rettv_list_alloc(rettv) == OK)
5291 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005292 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005293 }
5294 else
5295 {
5296 if (rettv_dict_alloc(rettv) == OK)
5297 if (is_qf || (wp != NULL))
5298 {
5299 if (what_arg->v_type == VAR_DICT)
5300 {
5301 dict_T *d = what_arg->vval.v_dict;
5302
5303 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005304 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005305 }
5306 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005307 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005308 }
5309 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005310}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005311#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005312
5313/*
5314 * "getloclist()" function
5315 */
5316 static void
5317f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5318{
5319#ifdef FEAT_QUICKFIX
5320 win_T *wp;
5321
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005322 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005323 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5324#endif
5325}
5326
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005327/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328 * "getpid()" function
5329 */
5330 static void
5331f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5332{
5333 rettv->vval.v_number = mch_get_pid();
5334}
5335
5336 static void
5337getpos_both(
5338 typval_T *argvars,
5339 typval_T *rettv,
5340 int getcurpos)
5341{
5342 pos_T *fp;
5343 list_T *l;
5344 int fnum = -1;
5345
5346 if (rettv_list_alloc(rettv) == OK)
5347 {
5348 l = rettv->vval.v_list;
5349 if (getcurpos)
5350 fp = &curwin->w_cursor;
5351 else
5352 fp = var2fpos(&argvars[0], TRUE, &fnum);
5353 if (fnum != -1)
5354 list_append_number(l, (varnumber_T)fnum);
5355 else
5356 list_append_number(l, (varnumber_T)0);
5357 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5358 : (varnumber_T)0);
5359 list_append_number(l, (fp != NULL)
5360 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5361 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005362 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005363 (varnumber_T)0);
5364 if (getcurpos)
5365 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005366 int save_set_curswant = curwin->w_set_curswant;
5367 colnr_T save_curswant = curwin->w_curswant;
5368 colnr_T save_virtcol = curwin->w_virtcol;
5369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005370 update_curswant();
5371 list_append_number(l, curwin->w_curswant == MAXCOL ?
5372 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005373
5374 // Do not change "curswant", as it is unexpected that a get
5375 // function has a side effect.
5376 if (save_set_curswant)
5377 {
5378 curwin->w_set_curswant = save_set_curswant;
5379 curwin->w_curswant = save_curswant;
5380 curwin->w_virtcol = save_virtcol;
5381 curwin->w_valid &= ~VALID_VIRTCOL;
5382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383 }
5384 }
5385 else
5386 rettv->vval.v_number = FALSE;
5387}
5388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005389/*
5390 * "getcurpos()" function
5391 */
5392 static void
5393f_getcurpos(typval_T *argvars, typval_T *rettv)
5394{
5395 getpos_both(argvars, rettv, TRUE);
5396}
5397
5398/*
5399 * "getpos(string)" function
5400 */
5401 static void
5402f_getpos(typval_T *argvars, typval_T *rettv)
5403{
5404 getpos_both(argvars, rettv, FALSE);
5405}
5406
5407/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005408 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005409 */
5410 static void
5411f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5412{
5413#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005414 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005415#endif
5416}
5417
5418/*
5419 * "getreg()" function
5420 */
5421 static void
5422f_getreg(typval_T *argvars, typval_T *rettv)
5423{
5424 char_u *strregname;
5425 int regname;
5426 int arg2 = FALSE;
5427 int return_list = FALSE;
5428 int error = FALSE;
5429
5430 if (argvars[0].v_type != VAR_UNKNOWN)
5431 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005432 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005433 error = strregname == NULL;
5434 if (argvars[1].v_type != VAR_UNKNOWN)
5435 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005436 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005438 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439 }
5440 }
5441 else
5442 strregname = get_vim_var_str(VV_REG);
5443
5444 if (error)
5445 return;
5446
5447 regname = (strregname == NULL ? '"' : *strregname);
5448 if (regname == 0)
5449 regname = '"';
5450
5451 if (return_list)
5452 {
5453 rettv->v_type = VAR_LIST;
5454 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5455 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5456 if (rettv->vval.v_list == NULL)
5457 (void)rettv_list_alloc(rettv);
5458 else
5459 ++rettv->vval.v_list->lv_refcount;
5460 }
5461 else
5462 {
5463 rettv->v_type = VAR_STRING;
5464 rettv->vval.v_string = get_reg_contents(regname,
5465 arg2 ? GREG_EXPR_SRC : 0);
5466 }
5467}
5468
5469/*
5470 * "getregtype()" function
5471 */
5472 static void
5473f_getregtype(typval_T *argvars, typval_T *rettv)
5474{
5475 char_u *strregname;
5476 int regname;
5477 char_u buf[NUMBUFLEN + 2];
5478 long reglen = 0;
5479
5480 if (argvars[0].v_type != VAR_UNKNOWN)
5481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005482 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 if (strregname == NULL) /* type error; errmsg already given */
5484 {
5485 rettv->v_type = VAR_STRING;
5486 rettv->vval.v_string = NULL;
5487 return;
5488 }
5489 }
5490 else
5491 /* Default to v:register */
5492 strregname = get_vim_var_str(VV_REG);
5493
5494 regname = (strregname == NULL ? '"' : *strregname);
5495 if (regname == 0)
5496 regname = '"';
5497
5498 buf[0] = NUL;
5499 buf[1] = NUL;
5500 switch (get_reg_type(regname, &reglen))
5501 {
5502 case MLINE: buf[0] = 'V'; break;
5503 case MCHAR: buf[0] = 'v'; break;
5504 case MBLOCK:
5505 buf[0] = Ctrl_V;
5506 sprintf((char *)buf + 1, "%ld", reglen + 1);
5507 break;
5508 }
5509 rettv->v_type = VAR_STRING;
5510 rettv->vval.v_string = vim_strsave(buf);
5511}
5512
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005513/*
5514 * Returns information (variables, options, etc.) about a tab page
5515 * as a dictionary.
5516 */
5517 static dict_T *
5518get_tabpage_info(tabpage_T *tp, int tp_idx)
5519{
5520 win_T *wp;
5521 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005522 list_T *l;
5523
5524 dict = dict_alloc();
5525 if (dict == NULL)
5526 return NULL;
5527
Bram Moolenaare0be1672018-07-08 16:50:37 +02005528 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005529
5530 l = list_alloc();
5531 if (l != NULL)
5532 {
5533 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005534 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005535 list_append_number(l, (varnumber_T)wp->w_id);
5536 dict_add_list(dict, "windows", l);
5537 }
5538
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005539 /* Make a reference to tabpage variables */
5540 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541
5542 return dict;
5543}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005544
5545/*
5546 * "gettabinfo()" function
5547 */
5548 static void
5549f_gettabinfo(typval_T *argvars, typval_T *rettv)
5550{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005551 tabpage_T *tp, *tparg = NULL;
5552 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005553 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005554
5555 if (rettv_list_alloc(rettv) != OK)
5556 return;
5557
5558 if (argvars[0].v_type != VAR_UNKNOWN)
5559 {
5560 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005561 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005562 if (tparg == NULL)
5563 return;
5564 }
5565
5566 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005567 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005568 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005569 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005570 if (tparg != NULL && tp != tparg)
5571 continue;
5572 d = get_tabpage_info(tp, tpnr);
5573 if (d != NULL)
5574 list_append_dict(rettv->vval.v_list, d);
5575 if (tparg != NULL)
5576 return;
5577 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005578}
5579
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580/*
5581 * "gettabvar()" function
5582 */
5583 static void
5584f_gettabvar(typval_T *argvars, typval_T *rettv)
5585{
5586 win_T *oldcurwin;
5587 tabpage_T *tp, *oldtabpage;
5588 dictitem_T *v;
5589 char_u *varname;
5590 int done = FALSE;
5591
5592 rettv->v_type = VAR_STRING;
5593 rettv->vval.v_string = NULL;
5594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005595 varname = tv_get_string_chk(&argvars[1]);
5596 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005597 if (tp != NULL && varname != NULL)
5598 {
5599 /* Set tp to be our tabpage, temporarily. Also set the window to the
5600 * first window in the tabpage, otherwise the window is not valid. */
5601 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005602 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5603 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 {
5605 /* look up the variable */
5606 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5607 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5608 if (v != NULL)
5609 {
5610 copy_tv(&v->di_tv, rettv);
5611 done = TRUE;
5612 }
5613 }
5614
5615 /* restore previous notion of curwin */
5616 restore_win(oldcurwin, oldtabpage, TRUE);
5617 }
5618
5619 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5620 copy_tv(&argvars[2], rettv);
5621}
5622
5623/*
5624 * "gettabwinvar()" function
5625 */
5626 static void
5627f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5628{
5629 getwinvar(argvars, rettv, 1);
5630}
5631
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005633 * "gettagstack()" function
5634 */
5635 static void
5636f_gettagstack(typval_T *argvars, typval_T *rettv)
5637{
5638 win_T *wp = curwin; // default is current window
5639
5640 if (rettv_dict_alloc(rettv) != OK)
5641 return;
5642
5643 if (argvars[0].v_type != VAR_UNKNOWN)
5644 {
5645 wp = find_win_by_nr_or_id(&argvars[0]);
5646 if (wp == NULL)
5647 return;
5648 }
5649
5650 get_tagstack(wp, rettv->vval.v_dict);
5651}
5652
5653/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005654 * Returns information about a window as a dictionary.
5655 */
5656 static dict_T *
5657get_win_info(win_T *wp, short tpnr, short winnr)
5658{
5659 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005660
5661 dict = dict_alloc();
5662 if (dict == NULL)
5663 return NULL;
5664
Bram Moolenaare0be1672018-07-08 16:50:37 +02005665 dict_add_number(dict, "tabnr", tpnr);
5666 dict_add_number(dict, "winnr", winnr);
5667 dict_add_number(dict, "winid", wp->w_id);
5668 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005669 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005670 dict_add_number(dict, "topline", wp->w_topline);
5671 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005672#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005673 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005674#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005675 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005676 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005677 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005678
Bram Moolenaar69905d12017-08-13 18:14:47 +02005679#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005680 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005681#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005682#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005683 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5684 dict_add_number(dict, "loclist",
5685 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005686#endif
5687
Bram Moolenaar30567352016-08-27 21:25:44 +02005688 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005689 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005690
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005691 return dict;
5692}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005693
5694/*
5695 * "getwininfo()" function
5696 */
5697 static void
5698f_getwininfo(typval_T *argvars, typval_T *rettv)
5699{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005700 tabpage_T *tp;
5701 win_T *wp = NULL, *wparg = NULL;
5702 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005703 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005704
5705 if (rettv_list_alloc(rettv) != OK)
5706 return;
5707
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005708 if (argvars[0].v_type != VAR_UNKNOWN)
5709 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005710 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005711 if (wparg == NULL)
5712 return;
5713 }
5714
5715 /* Collect information about either all the windows across all the tab
5716 * pages or one particular window.
5717 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005718 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005719 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005720 tabnr++;
5721 winnr = 0;
5722 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005723 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005724 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005725 if (wparg != NULL && wp != wparg)
5726 continue;
5727 d = get_win_info(wp, tabnr, winnr);
5728 if (d != NULL)
5729 list_append_dict(rettv->vval.v_list, d);
5730 if (wparg != NULL)
5731 /* found information about a specific window */
5732 return;
5733 }
5734 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005735}
5736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005738 * "win_execute()" function
5739 */
5740 static void
5741f_win_execute(typval_T *argvars, typval_T *rettv)
5742{
5743 int id = (int)tv_get_number(argvars);
5744 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005745 win_T *save_curwin;
5746 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005747
5748 if (wp != NULL)
5749 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005750 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5751 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005752 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005753 check_cursor();
5754 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005755 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005756 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005757 }
5758}
5759
5760/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005761 * "win_findbuf()" function
5762 */
5763 static void
5764f_win_findbuf(typval_T *argvars, typval_T *rettv)
5765{
5766 if (rettv_list_alloc(rettv) != FAIL)
5767 win_findbuf(argvars, rettv->vval.v_list);
5768}
5769
5770/*
5771 * "win_getid()" function
5772 */
5773 static void
5774f_win_getid(typval_T *argvars, typval_T *rettv)
5775{
5776 rettv->vval.v_number = win_getid(argvars);
5777}
5778
5779/*
5780 * "win_gotoid()" function
5781 */
5782 static void
5783f_win_gotoid(typval_T *argvars, typval_T *rettv)
5784{
5785 rettv->vval.v_number = win_gotoid(argvars);
5786}
5787
5788/*
5789 * "win_id2tabwin()" function
5790 */
5791 static void
5792f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5793{
5794 if (rettv_list_alloc(rettv) != FAIL)
5795 win_id2tabwin(argvars, rettv->vval.v_list);
5796}
5797
5798/*
5799 * "win_id2win()" function
5800 */
5801 static void
5802f_win_id2win(typval_T *argvars, typval_T *rettv)
5803{
5804 rettv->vval.v_number = win_id2win(argvars);
5805}
5806
5807/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005808 * "win_screenpos()" function
5809 */
5810 static void
5811f_win_screenpos(typval_T *argvars, typval_T *rettv)
5812{
5813 win_T *wp;
5814
5815 if (rettv_list_alloc(rettv) == FAIL)
5816 return;
5817
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005818 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005819 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5820 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5821}
5822
5823/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005824 * "getwinpos({timeout})" function
5825 */
5826 static void
5827f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5828{
5829 int x = -1;
5830 int y = -1;
5831
5832 if (rettv_list_alloc(rettv) == FAIL)
5833 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005834#if defined(FEAT_GUI) \
5835 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5836 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005837 {
5838 varnumber_T timeout = 100;
5839
5840 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005841 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005842
5843 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005844 }
5845#endif
5846 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5847 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5848}
5849
5850
5851/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005852 * "getwinposx()" function
5853 */
5854 static void
5855f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5856{
5857 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005858#if defined(FEAT_GUI) \
5859 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5860 || defined(MSWIN)
5861
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005862 {
5863 int x, y;
5864
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005865 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005866 rettv->vval.v_number = x;
5867 }
5868#endif
5869}
5870
5871/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005872 * "getwinposy()" function
5873 */
5874 static void
5875f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5876{
5877 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005878#if defined(FEAT_GUI) \
5879 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5880 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005881 {
5882 int x, y;
5883
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005884 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005885 rettv->vval.v_number = y;
5886 }
5887#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888}
5889
5890/*
5891 * "getwinvar()" function
5892 */
5893 static void
5894f_getwinvar(typval_T *argvars, typval_T *rettv)
5895{
5896 getwinvar(argvars, rettv, 0);
5897}
5898
5899/*
5900 * "glob()" function
5901 */
5902 static void
5903f_glob(typval_T *argvars, typval_T *rettv)
5904{
5905 int options = WILD_SILENT|WILD_USE_NL;
5906 expand_T xpc;
5907 int error = FALSE;
5908
5909 /* When the optional second argument is non-zero, don't remove matches
5910 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5911 rettv->v_type = VAR_STRING;
5912 if (argvars[1].v_type != VAR_UNKNOWN)
5913 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005914 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915 options |= WILD_KEEP_ALL;
5916 if (argvars[2].v_type != VAR_UNKNOWN)
5917 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005918 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005919 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005920 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005921 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005922 options |= WILD_ALLLINKS;
5923 }
5924 }
5925 if (!error)
5926 {
5927 ExpandInit(&xpc);
5928 xpc.xp_context = EXPAND_FILES;
5929 if (p_wic)
5930 options += WILD_ICASE;
5931 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005932 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005933 NULL, options, WILD_ALL);
5934 else if (rettv_list_alloc(rettv) != FAIL)
5935 {
5936 int i;
5937
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005938 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005939 NULL, options, WILD_ALL_KEEP);
5940 for (i = 0; i < xpc.xp_numfiles; i++)
5941 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5942
5943 ExpandCleanup(&xpc);
5944 }
5945 }
5946 else
5947 rettv->vval.v_string = NULL;
5948}
5949
5950/*
5951 * "globpath()" function
5952 */
5953 static void
5954f_globpath(typval_T *argvars, typval_T *rettv)
5955{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005956 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005957 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005958 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005959 int error = FALSE;
5960 garray_T ga;
5961 int i;
5962
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005963 // When the optional second argument is non-zero, don't remove matches
5964 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005965 rettv->v_type = VAR_STRING;
5966 if (argvars[2].v_type != VAR_UNKNOWN)
5967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005968 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005969 flags |= WILD_KEEP_ALL;
5970 if (argvars[3].v_type != VAR_UNKNOWN)
5971 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005972 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005973 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005974 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005975 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 flags |= WILD_ALLLINKS;
5977 }
5978 }
5979 if (file != NULL && !error)
5980 {
5981 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005982 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 if (rettv->v_type == VAR_STRING)
5984 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5985 else if (rettv_list_alloc(rettv) != FAIL)
5986 for (i = 0; i < ga.ga_len; ++i)
5987 list_append_string(rettv->vval.v_list,
5988 ((char_u **)(ga.ga_data))[i], -1);
5989 ga_clear_strings(&ga);
5990 }
5991 else
5992 rettv->vval.v_string = NULL;
5993}
5994
5995/*
5996 * "glob2regpat()" function
5997 */
5998 static void
5999f_glob2regpat(typval_T *argvars, typval_T *rettv)
6000{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006001 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002
6003 rettv->v_type = VAR_STRING;
6004 rettv->vval.v_string = (pat == NULL)
6005 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6006}
6007
6008/* for VIM_VERSION_ defines */
6009#include "version.h"
6010
6011/*
6012 * "has()" function
6013 */
6014 static void
6015f_has(typval_T *argvars, typval_T *rettv)
6016{
6017 int i;
6018 char_u *name;
6019 int n = FALSE;
6020 static char *(has_list[]) =
6021 {
6022#ifdef AMIGA
6023 "amiga",
6024# ifdef FEAT_ARP
6025 "arp",
6026# endif
6027#endif
6028#ifdef __BEOS__
6029 "beos",
6030#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006031#if defined(BSD) && !defined(MACOS_X)
6032 "bsd",
6033#endif
6034#ifdef hpux
6035 "hpux",
6036#endif
6037#ifdef __linux__
6038 "linux",
6039#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006040#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006041 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6042 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006043# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006044 "macunix", /* Mac OS X, with the darwin feature */
6045 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006046# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006047#endif
6048#ifdef __QNX__
6049 "qnx",
6050#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006051#ifdef SUN_SYSTEM
6052 "sun",
6053#else
6054 "moon",
6055#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056#ifdef UNIX
6057 "unix",
6058#endif
6059#ifdef VMS
6060 "vms",
6061#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006062#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 "win32",
6064#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006065#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066 "win32unix",
6067#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006068#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006069 "win64",
6070#endif
6071#ifdef EBCDIC
6072 "ebcdic",
6073#endif
6074#ifndef CASE_INSENSITIVE_FILENAME
6075 "fname_case",
6076#endif
6077#ifdef HAVE_ACL
6078 "acl",
6079#endif
6080#ifdef FEAT_ARABIC
6081 "arabic",
6082#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006084#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006085 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006086#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006087#ifdef FEAT_AUTOSERVERNAME
6088 "autoservername",
6089#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006090#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006092# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006093 "balloon_multiline",
6094# endif
6095#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006096#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006097 "balloon_eval_term",
6098#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6100 "builtin_terms",
6101# ifdef ALL_BUILTIN_TCAPS
6102 "all_builtin_terms",
6103# endif
6104#endif
6105#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006106 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006107 || defined(FEAT_GUI_MOTIF))
6108 "browsefilter",
6109#endif
6110#ifdef FEAT_BYTEOFF
6111 "byte_offset",
6112#endif
6113#ifdef FEAT_JOB_CHANNEL
6114 "channel",
6115#endif
6116#ifdef FEAT_CINDENT
6117 "cindent",
6118#endif
6119#ifdef FEAT_CLIENTSERVER
6120 "clientserver",
6121#endif
6122#ifdef FEAT_CLIPBOARD
6123 "clipboard",
6124#endif
6125#ifdef FEAT_CMDL_COMPL
6126 "cmdline_compl",
6127#endif
6128#ifdef FEAT_CMDHIST
6129 "cmdline_hist",
6130#endif
6131#ifdef FEAT_COMMENTS
6132 "comments",
6133#endif
6134#ifdef FEAT_CONCEAL
6135 "conceal",
6136#endif
6137#ifdef FEAT_CRYPT
6138 "cryptv",
6139 "crypt-blowfish",
6140 "crypt-blowfish2",
6141#endif
6142#ifdef FEAT_CSCOPE
6143 "cscope",
6144#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006145 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146#ifdef CURSOR_SHAPE
6147 "cursorshape",
6148#endif
6149#ifdef DEBUG
6150 "debug",
6151#endif
6152#ifdef FEAT_CON_DIALOG
6153 "dialog_con",
6154#endif
6155#ifdef FEAT_GUI_DIALOG
6156 "dialog_gui",
6157#endif
6158#ifdef FEAT_DIFF
6159 "diff",
6160#endif
6161#ifdef FEAT_DIGRAPHS
6162 "digraphs",
6163#endif
6164#ifdef FEAT_DIRECTX
6165 "directx",
6166#endif
6167#ifdef FEAT_DND
6168 "dnd",
6169#endif
6170#ifdef FEAT_EMACS_TAGS
6171 "emacs_tags",
6172#endif
6173 "eval", /* always present, of course! */
6174 "ex_extra", /* graduated feature */
6175#ifdef FEAT_SEARCH_EXTRA
6176 "extra_search",
6177#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006178#ifdef FEAT_SEARCHPATH
6179 "file_in_path",
6180#endif
6181#ifdef FEAT_FILTERPIPE
6182 "filterpipe",
6183#endif
6184#ifdef FEAT_FIND_ID
6185 "find_in_path",
6186#endif
6187#ifdef FEAT_FLOAT
6188 "float",
6189#endif
6190#ifdef FEAT_FOLDING
6191 "folding",
6192#endif
6193#ifdef FEAT_FOOTER
6194 "footer",
6195#endif
6196#if !defined(USE_SYSTEM) && defined(UNIX)
6197 "fork",
6198#endif
6199#ifdef FEAT_GETTEXT
6200 "gettext",
6201#endif
6202#ifdef FEAT_GUI
6203 "gui",
6204#endif
6205#ifdef FEAT_GUI_ATHENA
6206# ifdef FEAT_GUI_NEXTAW
6207 "gui_neXtaw",
6208# else
6209 "gui_athena",
6210# endif
6211#endif
6212#ifdef FEAT_GUI_GTK
6213 "gui_gtk",
6214# ifdef USE_GTK3
6215 "gui_gtk3",
6216# else
6217 "gui_gtk2",
6218# endif
6219#endif
6220#ifdef FEAT_GUI_GNOME
6221 "gui_gnome",
6222#endif
6223#ifdef FEAT_GUI_MAC
6224 "gui_mac",
6225#endif
6226#ifdef FEAT_GUI_MOTIF
6227 "gui_motif",
6228#endif
6229#ifdef FEAT_GUI_PHOTON
6230 "gui_photon",
6231#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006232#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006233 "gui_win32",
6234#endif
6235#ifdef FEAT_HANGULIN
6236 "hangul_input",
6237#endif
6238#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6239 "iconv",
6240#endif
6241#ifdef FEAT_INS_EXPAND
6242 "insert_expand",
6243#endif
6244#ifdef FEAT_JOB_CHANNEL
6245 "job",
6246#endif
6247#ifdef FEAT_JUMPLIST
6248 "jumplist",
6249#endif
6250#ifdef FEAT_KEYMAP
6251 "keymap",
6252#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006253 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254#ifdef FEAT_LANGMAP
6255 "langmap",
6256#endif
6257#ifdef FEAT_LIBCALL
6258 "libcall",
6259#endif
6260#ifdef FEAT_LINEBREAK
6261 "linebreak",
6262#endif
6263#ifdef FEAT_LISP
6264 "lispindent",
6265#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006267 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268#ifdef FEAT_LUA
6269# ifndef DYNAMIC_LUA
6270 "lua",
6271# endif
6272#endif
6273#ifdef FEAT_MENU
6274 "menu",
6275#endif
6276#ifdef FEAT_SESSION
6277 "mksession",
6278#endif
6279#ifdef FEAT_MODIFY_FNAME
6280 "modify_fname",
6281#endif
6282#ifdef FEAT_MOUSE
6283 "mouse",
6284#endif
6285#ifdef FEAT_MOUSESHAPE
6286 "mouseshape",
6287#endif
6288#if defined(UNIX) || defined(VMS)
6289# ifdef FEAT_MOUSE_DEC
6290 "mouse_dec",
6291# endif
6292# ifdef FEAT_MOUSE_GPM
6293 "mouse_gpm",
6294# endif
6295# ifdef FEAT_MOUSE_JSB
6296 "mouse_jsbterm",
6297# endif
6298# ifdef FEAT_MOUSE_NET
6299 "mouse_netterm",
6300# endif
6301# ifdef FEAT_MOUSE_PTERM
6302 "mouse_pterm",
6303# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006304# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305 "mouse_sgr",
6306# endif
6307# ifdef FEAT_SYSMOUSE
6308 "mouse_sysmouse",
6309# endif
6310# ifdef FEAT_MOUSE_URXVT
6311 "mouse_urxvt",
6312# endif
6313# ifdef FEAT_MOUSE_XTERM
6314 "mouse_xterm",
6315# endif
6316#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318#ifdef FEAT_MBYTE_IME
6319 "multi_byte_ime",
6320#endif
6321#ifdef FEAT_MULTI_LANG
6322 "multi_lang",
6323#endif
6324#ifdef FEAT_MZSCHEME
6325#ifndef DYNAMIC_MZSCHEME
6326 "mzscheme",
6327#endif
6328#endif
6329#ifdef FEAT_NUM64
6330 "num64",
6331#endif
6332#ifdef FEAT_OLE
6333 "ole",
6334#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006335#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006336 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006337#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338#ifdef FEAT_PATH_EXTRA
6339 "path_extra",
6340#endif
6341#ifdef FEAT_PERL
6342#ifndef DYNAMIC_PERL
6343 "perl",
6344#endif
6345#endif
6346#ifdef FEAT_PERSISTENT_UNDO
6347 "persistent_undo",
6348#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006349#if defined(FEAT_PYTHON)
6350 "python_compiled",
6351# if defined(DYNAMIC_PYTHON)
6352 "python_dynamic",
6353# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006355 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006356# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006358#if defined(FEAT_PYTHON3)
6359 "python3_compiled",
6360# if defined(DYNAMIC_PYTHON3)
6361 "python3_dynamic",
6362# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006364 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006365# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366#endif
6367#ifdef FEAT_POSTSCRIPT
6368 "postscript",
6369#endif
6370#ifdef FEAT_PRINTER
6371 "printer",
6372#endif
6373#ifdef FEAT_PROFILE
6374 "profile",
6375#endif
6376#ifdef FEAT_RELTIME
6377 "reltime",
6378#endif
6379#ifdef FEAT_QUICKFIX
6380 "quickfix",
6381#endif
6382#ifdef FEAT_RIGHTLEFT
6383 "rightleft",
6384#endif
6385#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6386 "ruby",
6387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006388 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389#ifdef FEAT_CMDL_INFO
6390 "showcmd",
6391 "cmdline_info",
6392#endif
6393#ifdef FEAT_SIGNS
6394 "signs",
6395#endif
6396#ifdef FEAT_SMARTINDENT
6397 "smartindent",
6398#endif
6399#ifdef STARTUPTIME
6400 "startuptime",
6401#endif
6402#ifdef FEAT_STL_OPT
6403 "statusline",
6404#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405#ifdef FEAT_NETBEANS_INTG
6406 "netbeans_intg",
6407#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006408#ifdef FEAT_SOUND
6409 "sound",
6410#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411#ifdef FEAT_SPELL
6412 "spell",
6413#endif
6414#ifdef FEAT_SYN_HL
6415 "syntax",
6416#endif
6417#if defined(USE_SYSTEM) || !defined(UNIX)
6418 "system",
6419#endif
6420#ifdef FEAT_TAG_BINS
6421 "tag_binary",
6422#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006423#ifdef FEAT_TCL
6424# ifndef DYNAMIC_TCL
6425 "tcl",
6426# endif
6427#endif
6428#ifdef FEAT_TERMGUICOLORS
6429 "termguicolors",
6430#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006431#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006432 "terminal",
6433#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006434#ifdef TERMINFO
6435 "terminfo",
6436#endif
6437#ifdef FEAT_TERMRESPONSE
6438 "termresponse",
6439#endif
6440#ifdef FEAT_TEXTOBJ
6441 "textobjects",
6442#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006443#ifdef FEAT_TEXT_PROP
6444 "textprop",
6445#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006446#ifdef HAVE_TGETENT
6447 "tgetent",
6448#endif
6449#ifdef FEAT_TIMERS
6450 "timers",
6451#endif
6452#ifdef FEAT_TITLE
6453 "title",
6454#endif
6455#ifdef FEAT_TOOLBAR
6456 "toolbar",
6457#endif
6458#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6459 "unnamedplus",
6460#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461 "user-commands", /* was accidentally included in 5.4 */
6462 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006463#ifdef FEAT_VARTABS
6464 "vartabs",
6465#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006466 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006467#ifdef FEAT_VIMINFO
6468 "viminfo",
6469#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006470 "vimscript-1",
6471 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006472 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006477#ifdef FEAT_VTP
6478 "vtp",
6479#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480#ifdef FEAT_WILDIGN
6481 "wildignore",
6482#endif
6483#ifdef FEAT_WILDMENU
6484 "wildmenu",
6485#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487#ifdef FEAT_WAK
6488 "winaltkeys",
6489#endif
6490#ifdef FEAT_WRITEBACKUP
6491 "writebackup",
6492#endif
6493#ifdef FEAT_XIM
6494 "xim",
6495#endif
6496#ifdef FEAT_XFONTSET
6497 "xfontset",
6498#endif
6499#ifdef FEAT_XPM_W32
6500 "xpm",
6501 "xpm_w32", /* for backward compatibility */
6502#else
6503# if defined(HAVE_XPM)
6504 "xpm",
6505# endif
6506#endif
6507#ifdef USE_XSMP
6508 "xsmp",
6509#endif
6510#ifdef USE_XSMP_INTERACT
6511 "xsmp_interact",
6512#endif
6513#ifdef FEAT_XCLIPBOARD
6514 "xterm_clipboard",
6515#endif
6516#ifdef FEAT_XTERM_SAVE
6517 "xterm_save",
6518#endif
6519#if defined(UNIX) && defined(FEAT_X11)
6520 "X11",
6521#endif
6522 NULL
6523 };
6524
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006525 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526 for (i = 0; has_list[i] != NULL; ++i)
6527 if (STRICMP(name, has_list[i]) == 0)
6528 {
6529 n = TRUE;
6530 break;
6531 }
6532
6533 if (n == FALSE)
6534 {
6535 if (STRNICMP(name, "patch", 5) == 0)
6536 {
6537 if (name[5] == '-'
6538 && STRLEN(name) >= 11
6539 && vim_isdigit(name[6])
6540 && vim_isdigit(name[8])
6541 && vim_isdigit(name[10]))
6542 {
6543 int major = atoi((char *)name + 6);
6544 int minor = atoi((char *)name + 8);
6545
6546 /* Expect "patch-9.9.01234". */
6547 n = (major < VIM_VERSION_MAJOR
6548 || (major == VIM_VERSION_MAJOR
6549 && (minor < VIM_VERSION_MINOR
6550 || (minor == VIM_VERSION_MINOR
6551 && has_patch(atoi((char *)name + 10))))));
6552 }
6553 else
6554 n = has_patch(atoi((char *)name + 5));
6555 }
6556 else if (STRICMP(name, "vim_starting") == 0)
6557 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006558 else if (STRICMP(name, "ttyin") == 0)
6559 n = mch_input_isatty();
6560 else if (STRICMP(name, "ttyout") == 0)
6561 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562 else if (STRICMP(name, "multi_byte_encoding") == 0)
6563 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006564#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565 else if (STRICMP(name, "balloon_multiline") == 0)
6566 n = multiline_balloon_available();
6567#endif
6568#ifdef DYNAMIC_TCL
6569 else if (STRICMP(name, "tcl") == 0)
6570 n = tcl_enabled(FALSE);
6571#endif
6572#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6573 else if (STRICMP(name, "iconv") == 0)
6574 n = iconv_enabled(FALSE);
6575#endif
6576#ifdef DYNAMIC_LUA
6577 else if (STRICMP(name, "lua") == 0)
6578 n = lua_enabled(FALSE);
6579#endif
6580#ifdef DYNAMIC_MZSCHEME
6581 else if (STRICMP(name, "mzscheme") == 0)
6582 n = mzscheme_enabled(FALSE);
6583#endif
6584#ifdef DYNAMIC_RUBY
6585 else if (STRICMP(name, "ruby") == 0)
6586 n = ruby_enabled(FALSE);
6587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588#ifdef DYNAMIC_PYTHON
6589 else if (STRICMP(name, "python") == 0)
6590 n = python_enabled(FALSE);
6591#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006592#ifdef DYNAMIC_PYTHON3
6593 else if (STRICMP(name, "python3") == 0)
6594 n = python3_enabled(FALSE);
6595#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006596#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6597 else if (STRICMP(name, "pythonx") == 0)
6598 {
6599# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6600 if (p_pyx == 0)
6601 n = python3_enabled(FALSE) || python_enabled(FALSE);
6602 else if (p_pyx == 3)
6603 n = python3_enabled(FALSE);
6604 else if (p_pyx == 2)
6605 n = python_enabled(FALSE);
6606# elif defined(DYNAMIC_PYTHON)
6607 n = python_enabled(FALSE);
6608# elif defined(DYNAMIC_PYTHON3)
6609 n = python3_enabled(FALSE);
6610# endif
6611 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612#endif
6613#ifdef DYNAMIC_PERL
6614 else if (STRICMP(name, "perl") == 0)
6615 n = perl_enabled(FALSE);
6616#endif
6617#ifdef FEAT_GUI
6618 else if (STRICMP(name, "gui_running") == 0)
6619 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620# ifdef FEAT_BROWSE
6621 else if (STRICMP(name, "browse") == 0)
6622 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6623# endif
6624#endif
6625#ifdef FEAT_SYN_HL
6626 else if (STRICMP(name, "syntax_items") == 0)
6627 n = syntax_present(curwin);
6628#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006629#ifdef FEAT_VTP
6630 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006631 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006632#endif
6633#ifdef FEAT_NETBEANS_INTG
6634 else if (STRICMP(name, "netbeans_enabled") == 0)
6635 n = netbeans_active();
6636#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006637#ifdef FEAT_MOUSE_GPM
6638 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6639 n = gpm_enabled();
6640#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006641#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006642 else if (STRICMP(name, "terminal") == 0)
6643 n = terminal_enabled();
6644#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006645#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006646 else if (STRICMP(name, "conpty") == 0)
6647 n = use_conpty();
6648#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649 }
6650
6651 rettv->vval.v_number = n;
6652}
6653
6654/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006655 * "haslocaldir()" function
6656 */
6657 static void
6658f_haslocaldir(typval_T *argvars, typval_T *rettv)
6659{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006660 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006661 win_T *wp = NULL;
6662
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006663 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6664
6665 // Check for window-local and tab-local directories
6666 if (wp != NULL && wp->w_localdir != NULL)
6667 rettv->vval.v_number = 1;
6668 else if (tp != NULL && tp->tp_localdir != NULL)
6669 rettv->vval.v_number = 2;
6670 else
6671 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672}
6673
6674/*
6675 * "hasmapto()" function
6676 */
6677 static void
6678f_hasmapto(typval_T *argvars, typval_T *rettv)
6679{
6680 char_u *name;
6681 char_u *mode;
6682 char_u buf[NUMBUFLEN];
6683 int abbr = FALSE;
6684
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006685 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 if (argvars[1].v_type == VAR_UNKNOWN)
6687 mode = (char_u *)"nvo";
6688 else
6689 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006690 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 }
6694
6695 if (map_to_exists(name, mode, abbr))
6696 rettv->vval.v_number = TRUE;
6697 else
6698 rettv->vval.v_number = FALSE;
6699}
6700
6701/*
6702 * "histadd()" function
6703 */
6704 static void
6705f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6706{
6707#ifdef FEAT_CMDHIST
6708 int histype;
6709 char_u *str;
6710 char_u buf[NUMBUFLEN];
6711#endif
6712
6713 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006714 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006715 return;
6716#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006717 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 histype = str != NULL ? get_histtype(str) : -1;
6719 if (histype >= 0)
6720 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006721 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722 if (*str != NUL)
6723 {
6724 init_history();
6725 add_to_history(histype, str, FALSE, NUL);
6726 rettv->vval.v_number = TRUE;
6727 return;
6728 }
6729 }
6730#endif
6731}
6732
6733/*
6734 * "histdel()" function
6735 */
6736 static void
6737f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6738{
6739#ifdef FEAT_CMDHIST
6740 int n;
6741 char_u buf[NUMBUFLEN];
6742 char_u *str;
6743
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006744 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006745 if (str == NULL)
6746 n = 0;
6747 else if (argvars[1].v_type == VAR_UNKNOWN)
6748 /* only one argument: clear entire history */
6749 n = clr_history(get_histtype(str));
6750 else if (argvars[1].v_type == VAR_NUMBER)
6751 /* index given: remove that entry */
6752 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006753 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754 else
6755 /* string given: remove all matching entries */
6756 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 rettv->vval.v_number = n;
6759#endif
6760}
6761
6762/*
6763 * "histget()" function
6764 */
6765 static void
6766f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6767{
6768#ifdef FEAT_CMDHIST
6769 int type;
6770 int idx;
6771 char_u *str;
6772
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006773 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 if (str == NULL)
6775 rettv->vval.v_string = NULL;
6776 else
6777 {
6778 type = get_histtype(str);
6779 if (argvars[1].v_type == VAR_UNKNOWN)
6780 idx = get_history_idx(type);
6781 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006782 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783 /* -1 on type error */
6784 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6785 }
6786#else
6787 rettv->vval.v_string = NULL;
6788#endif
6789 rettv->v_type = VAR_STRING;
6790}
6791
6792/*
6793 * "histnr()" function
6794 */
6795 static void
6796f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6797{
6798 int i;
6799
6800#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006801 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802
6803 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6804 if (i >= HIST_CMD && i < HIST_COUNT)
6805 i = get_history_idx(i);
6806 else
6807#endif
6808 i = -1;
6809 rettv->vval.v_number = i;
6810}
6811
6812/*
6813 * "highlightID(name)" function
6814 */
6815 static void
6816f_hlID(typval_T *argvars, typval_T *rettv)
6817{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006818 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819}
6820
6821/*
6822 * "highlight_exists()" function
6823 */
6824 static void
6825f_hlexists(typval_T *argvars, typval_T *rettv)
6826{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006827 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828}
6829
6830/*
6831 * "hostname()" function
6832 */
6833 static void
6834f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6835{
6836 char_u hostname[256];
6837
6838 mch_get_host_name(hostname, 256);
6839 rettv->v_type = VAR_STRING;
6840 rettv->vval.v_string = vim_strsave(hostname);
6841}
6842
6843/*
6844 * iconv() function
6845 */
6846 static void
6847f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6848{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006849 char_u buf1[NUMBUFLEN];
6850 char_u buf2[NUMBUFLEN];
6851 char_u *from, *to, *str;
6852 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853
6854 rettv->v_type = VAR_STRING;
6855 rettv->vval.v_string = NULL;
6856
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006857 str = tv_get_string(&argvars[0]);
6858 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6859 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006860 vimconv.vc_type = CONV_NONE;
6861 convert_setup(&vimconv, from, to);
6862
6863 /* If the encodings are equal, no conversion needed. */
6864 if (vimconv.vc_type == CONV_NONE)
6865 rettv->vval.v_string = vim_strsave(str);
6866 else
6867 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6868
6869 convert_setup(&vimconv, NULL, NULL);
6870 vim_free(from);
6871 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006872}
6873
6874/*
6875 * "indent()" function
6876 */
6877 static void
6878f_indent(typval_T *argvars, typval_T *rettv)
6879{
6880 linenr_T lnum;
6881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006882 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6884 rettv->vval.v_number = get_indent_lnum(lnum);
6885 else
6886 rettv->vval.v_number = -1;
6887}
6888
6889/*
6890 * "index()" function
6891 */
6892 static void
6893f_index(typval_T *argvars, typval_T *rettv)
6894{
6895 list_T *l;
6896 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006897 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006898 long idx = 0;
6899 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006900 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006901
6902 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006903 if (argvars[0].v_type == VAR_BLOB)
6904 {
6905 typval_T tv;
6906 int start = 0;
6907
6908 if (argvars[2].v_type != VAR_UNKNOWN)
6909 {
6910 start = tv_get_number_chk(&argvars[2], &error);
6911 if (error)
6912 return;
6913 }
6914 b = argvars[0].vval.v_blob;
6915 if (b == NULL)
6916 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006917 if (start < 0)
6918 {
6919 start = blob_len(b) + start;
6920 if (start < 0)
6921 start = 0;
6922 }
6923
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006924 for (idx = start; idx < blob_len(b); ++idx)
6925 {
6926 tv.v_type = VAR_NUMBER;
6927 tv.vval.v_number = blob_get(b, idx);
6928 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6929 {
6930 rettv->vval.v_number = idx;
6931 return;
6932 }
6933 }
6934 return;
6935 }
6936 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006938 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006939 return;
6940 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006941
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006942 l = argvars[0].vval.v_list;
6943 if (l != NULL)
6944 {
6945 item = l->lv_first;
6946 if (argvars[2].v_type != VAR_UNKNOWN)
6947 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 /* Start at specified item. Use the cached index that list_find()
6949 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006950 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006951 idx = l->lv_idx;
6952 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006953 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 if (error)
6955 item = NULL;
6956 }
6957
6958 for ( ; item != NULL; item = item->li_next, ++idx)
6959 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6960 {
6961 rettv->vval.v_number = idx;
6962 break;
6963 }
6964 }
6965}
6966
6967static int inputsecret_flag = 0;
6968
6969/*
6970 * "input()" function
6971 * Also handles inputsecret() when inputsecret is set.
6972 */
6973 static void
6974f_input(typval_T *argvars, typval_T *rettv)
6975{
6976 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6977}
6978
6979/*
6980 * "inputdialog()" function
6981 */
6982 static void
6983f_inputdialog(typval_T *argvars, typval_T *rettv)
6984{
6985#if defined(FEAT_GUI_TEXTDIALOG)
6986 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6987 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6988 {
6989 char_u *message;
6990 char_u buf[NUMBUFLEN];
6991 char_u *defstr = (char_u *)"";
6992
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006993 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006995 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006996 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6997 else
6998 IObuff[0] = NUL;
6999 if (message != NULL && defstr != NULL
7000 && do_dialog(VIM_QUESTION, NULL, message,
7001 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7002 rettv->vval.v_string = vim_strsave(IObuff);
7003 else
7004 {
7005 if (message != NULL && defstr != NULL
7006 && argvars[1].v_type != VAR_UNKNOWN
7007 && argvars[2].v_type != VAR_UNKNOWN)
7008 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007009 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 else
7011 rettv->vval.v_string = NULL;
7012 }
7013 rettv->v_type = VAR_STRING;
7014 }
7015 else
7016#endif
7017 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7018}
7019
7020/*
7021 * "inputlist()" function
7022 */
7023 static void
7024f_inputlist(typval_T *argvars, typval_T *rettv)
7025{
7026 listitem_T *li;
7027 int selected;
7028 int mouse_used;
7029
7030#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007031 /* While starting up, there is no place to enter text. When running tests
7032 * with --not-a-term we assume feedkeys() will be used. */
7033 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 return;
7035#endif
7036 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7037 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007038 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 return;
7040 }
7041
7042 msg_start();
7043 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7044 lines_left = Rows; /* avoid more prompt */
7045 msg_scroll = TRUE;
7046 msg_clr_eos();
7047
7048 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7049 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007050 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007051 msg_putchar('\n');
7052 }
7053
7054 /* Ask for choice. */
7055 selected = prompt_for_number(&mouse_used);
7056 if (mouse_used)
7057 selected -= lines_left;
7058
7059 rettv->vval.v_number = selected;
7060}
7061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7063
7064/*
7065 * "inputrestore()" function
7066 */
7067 static void
7068f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7069{
7070 if (ga_userinput.ga_len > 0)
7071 {
7072 --ga_userinput.ga_len;
7073 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7074 + ga_userinput.ga_len);
7075 /* default return is zero == OK */
7076 }
7077 else if (p_verbose > 1)
7078 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007079 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 rettv->vval.v_number = 1; /* Failed */
7081 }
7082}
7083
7084/*
7085 * "inputsave()" function
7086 */
7087 static void
7088f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7089{
7090 /* Add an entry to the stack of typeahead storage. */
7091 if (ga_grow(&ga_userinput, 1) == OK)
7092 {
7093 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7094 + ga_userinput.ga_len);
7095 ++ga_userinput.ga_len;
7096 /* default return is zero == OK */
7097 }
7098 else
7099 rettv->vval.v_number = 1; /* Failed */
7100}
7101
7102/*
7103 * "inputsecret()" function
7104 */
7105 static void
7106f_inputsecret(typval_T *argvars, typval_T *rettv)
7107{
7108 ++cmdline_star;
7109 ++inputsecret_flag;
7110 f_input(argvars, rettv);
7111 --cmdline_star;
7112 --inputsecret_flag;
7113}
7114
7115/*
7116 * "insert()" function
7117 */
7118 static void
7119f_insert(typval_T *argvars, typval_T *rettv)
7120{
7121 long before = 0;
7122 listitem_T *item;
7123 list_T *l;
7124 int error = FALSE;
7125
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007126 if (argvars[0].v_type == VAR_BLOB)
7127 {
7128 int val, len;
7129 char_u *p;
7130
7131 len = blob_len(argvars[0].vval.v_blob);
7132 if (argvars[2].v_type != VAR_UNKNOWN)
7133 {
7134 before = (long)tv_get_number_chk(&argvars[2], &error);
7135 if (error)
7136 return; // type error; errmsg already given
7137 if (before < 0 || before > len)
7138 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007139 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007140 return;
7141 }
7142 }
7143 val = tv_get_number_chk(&argvars[1], &error);
7144 if (error)
7145 return;
7146 if (val < 0 || val > 255)
7147 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007148 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007149 return;
7150 }
7151
7152 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7153 return;
7154 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7155 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7156 *(p + before) = val;
7157 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7158
7159 copy_tv(&argvars[0], rettv);
7160 }
7161 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007162 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007163 else if ((l = argvars[0].vval.v_list) != NULL
7164 && !var_check_lock(l->lv_lock,
7165 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166 {
7167 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007168 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169 if (error)
7170 return; /* type error; errmsg already given */
7171
7172 if (before == l->lv_len)
7173 item = NULL;
7174 else
7175 {
7176 item = list_find(l, before);
7177 if (item == NULL)
7178 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007179 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007180 l = NULL;
7181 }
7182 }
7183 if (l != NULL)
7184 {
7185 list_insert_tv(l, &argvars[1], item);
7186 copy_tv(&argvars[0], rettv);
7187 }
7188 }
7189}
7190
7191/*
7192 * "invert(expr)" function
7193 */
7194 static void
7195f_invert(typval_T *argvars, typval_T *rettv)
7196{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007197 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007198}
7199
7200/*
7201 * "isdirectory()" function
7202 */
7203 static void
7204f_isdirectory(typval_T *argvars, typval_T *rettv)
7205{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007206 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007207}
7208
7209/*
7210 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7211 * or it refers to a List or Dictionary that is locked.
7212 */
7213 static int
7214tv_islocked(typval_T *tv)
7215{
7216 return (tv->v_lock & VAR_LOCKED)
7217 || (tv->v_type == VAR_LIST
7218 && tv->vval.v_list != NULL
7219 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7220 || (tv->v_type == VAR_DICT
7221 && tv->vval.v_dict != NULL
7222 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7223}
7224
7225/*
7226 * "islocked()" function
7227 */
7228 static void
7229f_islocked(typval_T *argvars, typval_T *rettv)
7230{
7231 lval_T lv;
7232 char_u *end;
7233 dictitem_T *di;
7234
7235 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007236 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007237 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238 if (end != NULL && lv.ll_name != NULL)
7239 {
7240 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007241 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007242 else
7243 {
7244 if (lv.ll_tv == NULL)
7245 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007246 di = find_var(lv.ll_name, NULL, TRUE);
7247 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007249 /* Consider a variable locked when:
7250 * 1. the variable itself is locked
7251 * 2. the value of the variable is locked.
7252 * 3. the List or Dict value is locked.
7253 */
7254 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7255 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 }
7257 }
7258 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007259 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007260 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007261 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 else if (lv.ll_list != NULL)
7263 /* List item. */
7264 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7265 else
7266 /* Dictionary item. */
7267 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7268 }
7269 }
7270
7271 clear_lval(&lv);
7272}
7273
7274#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7275/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007276 * "isinf()" function
7277 */
7278 static void
7279f_isinf(typval_T *argvars, typval_T *rettv)
7280{
7281 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7282 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7283}
7284
7285/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286 * "isnan()" function
7287 */
7288 static void
7289f_isnan(typval_T *argvars, typval_T *rettv)
7290{
7291 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7292 && isnan(argvars[0].vval.v_float);
7293}
7294#endif
7295
7296/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 * "last_buffer_nr()" function.
7298 */
7299 static void
7300f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7301{
7302 int n = 0;
7303 buf_T *buf;
7304
Bram Moolenaar29323592016-07-24 22:04:11 +02007305 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 if (n < buf->b_fnum)
7307 n = buf->b_fnum;
7308
7309 rettv->vval.v_number = n;
7310}
7311
7312/*
7313 * "len()" function
7314 */
7315 static void
7316f_len(typval_T *argvars, typval_T *rettv)
7317{
7318 switch (argvars[0].v_type)
7319 {
7320 case VAR_STRING:
7321 case VAR_NUMBER:
7322 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007323 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007325 case VAR_BLOB:
7326 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7327 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007328 case VAR_LIST:
7329 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7330 break;
7331 case VAR_DICT:
7332 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7333 break;
7334 case VAR_UNKNOWN:
7335 case VAR_SPECIAL:
7336 case VAR_FLOAT:
7337 case VAR_FUNC:
7338 case VAR_PARTIAL:
7339 case VAR_JOB:
7340 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007341 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 break;
7343 }
7344}
7345
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007347libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348{
7349#ifdef FEAT_LIBCALL
7350 char_u *string_in;
7351 char_u **string_result;
7352 int nr_result;
7353#endif
7354
7355 rettv->v_type = type;
7356 if (type != VAR_NUMBER)
7357 rettv->vval.v_string = NULL;
7358
7359 if (check_restricted() || check_secure())
7360 return;
7361
7362#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007363 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7365 {
7366 string_in = NULL;
7367 if (argvars[2].v_type == VAR_STRING)
7368 string_in = argvars[2].vval.v_string;
7369 if (type == VAR_NUMBER)
7370 string_result = NULL;
7371 else
7372 string_result = &rettv->vval.v_string;
7373 if (mch_libcall(argvars[0].vval.v_string,
7374 argvars[1].vval.v_string,
7375 string_in,
7376 argvars[2].vval.v_number,
7377 string_result,
7378 &nr_result) == OK
7379 && type == VAR_NUMBER)
7380 rettv->vval.v_number = nr_result;
7381 }
7382#endif
7383}
7384
7385/*
7386 * "libcall()" function
7387 */
7388 static void
7389f_libcall(typval_T *argvars, typval_T *rettv)
7390{
7391 libcall_common(argvars, rettv, VAR_STRING);
7392}
7393
7394/*
7395 * "libcallnr()" function
7396 */
7397 static void
7398f_libcallnr(typval_T *argvars, typval_T *rettv)
7399{
7400 libcall_common(argvars, rettv, VAR_NUMBER);
7401}
7402
7403/*
7404 * "line(string)" function
7405 */
7406 static void
7407f_line(typval_T *argvars, typval_T *rettv)
7408{
7409 linenr_T lnum = 0;
7410 pos_T *fp;
7411 int fnum;
7412
7413 fp = var2fpos(&argvars[0], TRUE, &fnum);
7414 if (fp != NULL)
7415 lnum = fp->lnum;
7416 rettv->vval.v_number = lnum;
7417}
7418
7419/*
7420 * "line2byte(lnum)" function
7421 */
7422 static void
7423f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7424{
7425#ifndef FEAT_BYTEOFF
7426 rettv->vval.v_number = -1;
7427#else
7428 linenr_T lnum;
7429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007430 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7432 rettv->vval.v_number = -1;
7433 else
7434 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7435 if (rettv->vval.v_number >= 0)
7436 ++rettv->vval.v_number;
7437#endif
7438}
7439
7440/*
7441 * "lispindent(lnum)" function
7442 */
7443 static void
7444f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7445{
7446#ifdef FEAT_LISP
7447 pos_T pos;
7448 linenr_T lnum;
7449
7450 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007451 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007452 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7453 {
7454 curwin->w_cursor.lnum = lnum;
7455 rettv->vval.v_number = get_lisp_indent();
7456 curwin->w_cursor = pos;
7457 }
7458 else
7459#endif
7460 rettv->vval.v_number = -1;
7461}
7462
7463/*
7464 * "localtime()" function
7465 */
7466 static void
7467f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7468{
7469 rettv->vval.v_number = (varnumber_T)time(NULL);
7470}
7471
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007472#ifdef FEAT_FLOAT
7473/*
7474 * "log()" function
7475 */
7476 static void
7477f_log(typval_T *argvars, typval_T *rettv)
7478{
7479 float_T f = 0.0;
7480
7481 rettv->v_type = VAR_FLOAT;
7482 if (get_float_arg(argvars, &f) == OK)
7483 rettv->vval.v_float = log(f);
7484 else
7485 rettv->vval.v_float = 0.0;
7486}
7487
7488/*
7489 * "log10()" function
7490 */
7491 static void
7492f_log10(typval_T *argvars, typval_T *rettv)
7493{
7494 float_T f = 0.0;
7495
7496 rettv->v_type = VAR_FLOAT;
7497 if (get_float_arg(argvars, &f) == OK)
7498 rettv->vval.v_float = log10(f);
7499 else
7500 rettv->vval.v_float = 0.0;
7501}
7502#endif
7503
7504#ifdef FEAT_LUA
7505/*
7506 * "luaeval()" function
7507 */
7508 static void
7509f_luaeval(typval_T *argvars, typval_T *rettv)
7510{
7511 char_u *str;
7512 char_u buf[NUMBUFLEN];
7513
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007514 if (check_restricted() || check_secure())
7515 return;
7516
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007517 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 do_luaeval(str, argvars + 1, rettv);
7519}
7520#endif
7521
7522/*
7523 * "map()" function
7524 */
7525 static void
7526f_map(typval_T *argvars, typval_T *rettv)
7527{
7528 filter_map(argvars, rettv, TRUE);
7529}
7530
7531/*
7532 * "maparg()" function
7533 */
7534 static void
7535f_maparg(typval_T *argvars, typval_T *rettv)
7536{
7537 get_maparg(argvars, rettv, TRUE);
7538}
7539
7540/*
7541 * "mapcheck()" function
7542 */
7543 static void
7544f_mapcheck(typval_T *argvars, typval_T *rettv)
7545{
7546 get_maparg(argvars, rettv, FALSE);
7547}
7548
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007549typedef enum
7550{
7551 MATCH_END, /* matchend() */
7552 MATCH_MATCH, /* match() */
7553 MATCH_STR, /* matchstr() */
7554 MATCH_LIST, /* matchlist() */
7555 MATCH_POS /* matchstrpos() */
7556} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007557
7558 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007559find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007560{
7561 char_u *str = NULL;
7562 long len = 0;
7563 char_u *expr = NULL;
7564 char_u *pat;
7565 regmatch_T regmatch;
7566 char_u patbuf[NUMBUFLEN];
7567 char_u strbuf[NUMBUFLEN];
7568 char_u *save_cpo;
7569 long start = 0;
7570 long nth = 1;
7571 colnr_T startcol = 0;
7572 int match = 0;
7573 list_T *l = NULL;
7574 listitem_T *li = NULL;
7575 long idx = 0;
7576 char_u *tofree = NULL;
7577
7578 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7579 save_cpo = p_cpo;
7580 p_cpo = (char_u *)"";
7581
7582 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007583 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007585 /* type MATCH_LIST: return empty list when there are no matches.
7586 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007587 if (rettv_list_alloc(rettv) == FAIL)
7588 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007589 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 && (list_append_string(rettv->vval.v_list,
7591 (char_u *)"", 0) == FAIL
7592 || list_append_number(rettv->vval.v_list,
7593 (varnumber_T)-1) == FAIL
7594 || list_append_number(rettv->vval.v_list,
7595 (varnumber_T)-1) == FAIL
7596 || list_append_number(rettv->vval.v_list,
7597 (varnumber_T)-1) == FAIL))
7598 {
7599 list_free(rettv->vval.v_list);
7600 rettv->vval.v_list = NULL;
7601 goto theend;
7602 }
7603 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007604 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007605 {
7606 rettv->v_type = VAR_STRING;
7607 rettv->vval.v_string = NULL;
7608 }
7609
7610 if (argvars[0].v_type == VAR_LIST)
7611 {
7612 if ((l = argvars[0].vval.v_list) == NULL)
7613 goto theend;
7614 li = l->lv_first;
7615 }
7616 else
7617 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007618 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619 len = (long)STRLEN(str);
7620 }
7621
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007622 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623 if (pat == NULL)
7624 goto theend;
7625
7626 if (argvars[2].v_type != VAR_UNKNOWN)
7627 {
7628 int error = FALSE;
7629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007630 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 if (error)
7632 goto theend;
7633 if (l != NULL)
7634 {
7635 li = list_find(l, start);
7636 if (li == NULL)
7637 goto theend;
7638 idx = l->lv_idx; /* use the cached index */
7639 }
7640 else
7641 {
7642 if (start < 0)
7643 start = 0;
7644 if (start > len)
7645 goto theend;
7646 /* When "count" argument is there ignore matches before "start",
7647 * otherwise skip part of the string. Differs when pattern is "^"
7648 * or "\<". */
7649 if (argvars[3].v_type != VAR_UNKNOWN)
7650 startcol = start;
7651 else
7652 {
7653 str += start;
7654 len -= start;
7655 }
7656 }
7657
7658 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007659 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007660 if (error)
7661 goto theend;
7662 }
7663
7664 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7665 if (regmatch.regprog != NULL)
7666 {
7667 regmatch.rm_ic = p_ic;
7668
7669 for (;;)
7670 {
7671 if (l != NULL)
7672 {
7673 if (li == NULL)
7674 {
7675 match = FALSE;
7676 break;
7677 }
7678 vim_free(tofree);
7679 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7680 if (str == NULL)
7681 break;
7682 }
7683
7684 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7685
7686 if (match && --nth <= 0)
7687 break;
7688 if (l == NULL && !match)
7689 break;
7690
7691 /* Advance to just after the match. */
7692 if (l != NULL)
7693 {
7694 li = li->li_next;
7695 ++idx;
7696 }
7697 else
7698 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699 startcol = (colnr_T)(regmatch.startp[0]
7700 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007701 if (startcol > (colnr_T)len
7702 || str + startcol <= regmatch.startp[0])
7703 {
7704 match = FALSE;
7705 break;
7706 }
7707 }
7708 }
7709
7710 if (match)
7711 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007712 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007713 {
7714 listitem_T *li1 = rettv->vval.v_list->lv_first;
7715 listitem_T *li2 = li1->li_next;
7716 listitem_T *li3 = li2->li_next;
7717 listitem_T *li4 = li3->li_next;
7718
7719 vim_free(li1->li_tv.vval.v_string);
7720 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7721 (int)(regmatch.endp[0] - regmatch.startp[0]));
7722 li3->li_tv.vval.v_number =
7723 (varnumber_T)(regmatch.startp[0] - expr);
7724 li4->li_tv.vval.v_number =
7725 (varnumber_T)(regmatch.endp[0] - expr);
7726 if (l != NULL)
7727 li2->li_tv.vval.v_number = (varnumber_T)idx;
7728 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007729 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007730 {
7731 int i;
7732
7733 /* return list with matched string and submatches */
7734 for (i = 0; i < NSUBEXP; ++i)
7735 {
7736 if (regmatch.endp[i] == NULL)
7737 {
7738 if (list_append_string(rettv->vval.v_list,
7739 (char_u *)"", 0) == FAIL)
7740 break;
7741 }
7742 else if (list_append_string(rettv->vval.v_list,
7743 regmatch.startp[i],
7744 (int)(regmatch.endp[i] - regmatch.startp[i]))
7745 == FAIL)
7746 break;
7747 }
7748 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007749 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 {
7751 /* return matched string */
7752 if (l != NULL)
7753 copy_tv(&li->li_tv, rettv);
7754 else
7755 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7756 (int)(regmatch.endp[0] - regmatch.startp[0]));
7757 }
7758 else if (l != NULL)
7759 rettv->vval.v_number = idx;
7760 else
7761 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007762 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763 rettv->vval.v_number =
7764 (varnumber_T)(regmatch.startp[0] - str);
7765 else
7766 rettv->vval.v_number =
7767 (varnumber_T)(regmatch.endp[0] - str);
7768 rettv->vval.v_number += (varnumber_T)(str - expr);
7769 }
7770 }
7771 vim_regfree(regmatch.regprog);
7772 }
7773
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007774theend:
7775 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 /* matchstrpos() without a list: drop the second item. */
7777 listitem_remove(rettv->vval.v_list,
7778 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007779 vim_free(tofree);
7780 p_cpo = save_cpo;
7781}
7782
7783/*
7784 * "match()" function
7785 */
7786 static void
7787f_match(typval_T *argvars, typval_T *rettv)
7788{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007789 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007790}
7791
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792/*
7793 * "matchend()" function
7794 */
7795 static void
7796f_matchend(typval_T *argvars, typval_T *rettv)
7797{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007798 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799}
7800
7801/*
7802 * "matchlist()" function
7803 */
7804 static void
7805f_matchlist(typval_T *argvars, typval_T *rettv)
7806{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007807 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007808}
7809
7810/*
7811 * "matchstr()" function
7812 */
7813 static void
7814f_matchstr(typval_T *argvars, typval_T *rettv)
7815{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007816 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007817}
7818
7819/*
7820 * "matchstrpos()" function
7821 */
7822 static void
7823f_matchstrpos(typval_T *argvars, typval_T *rettv)
7824{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007825 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826}
7827
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007828 static void
7829max_min(typval_T *argvars, typval_T *rettv, int domax)
7830{
7831 varnumber_T n = 0;
7832 varnumber_T i;
7833 int error = FALSE;
7834
7835 if (argvars[0].v_type == VAR_LIST)
7836 {
7837 list_T *l;
7838 listitem_T *li;
7839
7840 l = argvars[0].vval.v_list;
7841 if (l != NULL)
7842 {
7843 li = l->lv_first;
7844 if (li != NULL)
7845 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007846 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847 for (;;)
7848 {
7849 li = li->li_next;
7850 if (li == NULL)
7851 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007852 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 if (domax ? i > n : i < n)
7854 n = i;
7855 }
7856 }
7857 }
7858 }
7859 else if (argvars[0].v_type == VAR_DICT)
7860 {
7861 dict_T *d;
7862 int first = TRUE;
7863 hashitem_T *hi;
7864 int todo;
7865
7866 d = argvars[0].vval.v_dict;
7867 if (d != NULL)
7868 {
7869 todo = (int)d->dv_hashtab.ht_used;
7870 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7871 {
7872 if (!HASHITEM_EMPTY(hi))
7873 {
7874 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007875 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 if (first)
7877 {
7878 n = i;
7879 first = FALSE;
7880 }
7881 else if (domax ? i > n : i < n)
7882 n = i;
7883 }
7884 }
7885 }
7886 }
7887 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007888 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007889 rettv->vval.v_number = error ? 0 : n;
7890}
7891
7892/*
7893 * "max()" function
7894 */
7895 static void
7896f_max(typval_T *argvars, typval_T *rettv)
7897{
7898 max_min(argvars, rettv, TRUE);
7899}
7900
7901/*
7902 * "min()" function
7903 */
7904 static void
7905f_min(typval_T *argvars, typval_T *rettv)
7906{
7907 max_min(argvars, rettv, FALSE);
7908}
7909
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910/*
7911 * Create the directory in which "dir" is located, and higher levels when
7912 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007913 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 */
7915 static int
7916mkdir_recurse(char_u *dir, int prot)
7917{
7918 char_u *p;
7919 char_u *updir;
7920 int r = FAIL;
7921
7922 /* Get end of directory name in "dir".
7923 * We're done when it's "/" or "c:/". */
7924 p = gettail_sep(dir);
7925 if (p <= get_past_head(dir))
7926 return OK;
7927
7928 /* If the directory exists we're done. Otherwise: create it.*/
7929 updir = vim_strnsave(dir, (int)(p - dir));
7930 if (updir == NULL)
7931 return FAIL;
7932 if (mch_isdir(updir))
7933 r = OK;
7934 else if (mkdir_recurse(updir, prot) == OK)
7935 r = vim_mkdir_emsg(updir, prot);
7936 vim_free(updir);
7937 return r;
7938}
7939
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940/*
7941 * "mkdir()" function
7942 */
7943 static void
7944f_mkdir(typval_T *argvars, typval_T *rettv)
7945{
7946 char_u *dir;
7947 char_u buf[NUMBUFLEN];
7948 int prot = 0755;
7949
7950 rettv->vval.v_number = FAIL;
7951 if (check_restricted() || check_secure())
7952 return;
7953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007954 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007956 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007958 if (*gettail(dir) == NUL)
7959 /* remove trailing slashes */
7960 *gettail_sep(dir) = NUL;
7961
7962 if (argvars[1].v_type != VAR_UNKNOWN)
7963 {
7964 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007965 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007966 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007967 if (prot == -1)
7968 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007970 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007971 {
7972 if (mch_isdir(dir))
7973 {
7974 /* With the "p" flag it's OK if the dir already exists. */
7975 rettv->vval.v_number = OK;
7976 return;
7977 }
7978 mkdir_recurse(dir, prot);
7979 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007981 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983
7984/*
7985 * "mode()" function
7986 */
7987 static void
7988f_mode(typval_T *argvars, typval_T *rettv)
7989{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007990 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991
Bram Moolenaar612cc382018-07-29 15:34:26 +02007992 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993
7994 if (time_for_testing == 93784)
7995 {
7996 /* Testing the two-character code. */
7997 buf[0] = 'x';
7998 buf[1] = '!';
7999 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008000#ifdef FEAT_TERMINAL
8001 else if (term_use_loop())
8002 buf[0] = 't';
8003#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 else if (VIsual_active)
8005 {
8006 if (VIsual_select)
8007 buf[0] = VIsual_mode + 's' - 'v';
8008 else
8009 buf[0] = VIsual_mode;
8010 }
8011 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8012 || State == CONFIRM)
8013 {
8014 buf[0] = 'r';
8015 if (State == ASKMORE)
8016 buf[1] = 'm';
8017 else if (State == CONFIRM)
8018 buf[1] = '?';
8019 }
8020 else if (State == EXTERNCMD)
8021 buf[0] = '!';
8022 else if (State & INSERT)
8023 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008024 if (State & VREPLACE_FLAG)
8025 {
8026 buf[0] = 'R';
8027 buf[1] = 'v';
8028 }
8029 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008030 {
8031 if (State & REPLACE_FLAG)
8032 buf[0] = 'R';
8033 else
8034 buf[0] = 'i';
8035#ifdef FEAT_INS_EXPAND
8036 if (ins_compl_active())
8037 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008038 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008039 buf[1] = 'x';
8040#endif
8041 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008043 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044 {
8045 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008046 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008047 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008048 else if (exmode_active == EXMODE_NORMAL)
8049 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050 }
8051 else
8052 {
8053 buf[0] = 'n';
8054 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008055 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008056 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008057 // to be able to detect force-linewise/blockwise/characterwise operations
8058 buf[2] = motion_force;
8059 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008060 else if (restart_edit == 'I' || restart_edit == 'R'
8061 || restart_edit == 'V')
8062 {
8063 buf[1] = 'i';
8064 buf[2] = restart_edit;
8065 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 }
8067
8068 /* Clear out the minor mode when the argument is not a non-zero number or
8069 * non-empty string. */
8070 if (!non_zero_arg(&argvars[0]))
8071 buf[1] = NUL;
8072
8073 rettv->vval.v_string = vim_strsave(buf);
8074 rettv->v_type = VAR_STRING;
8075}
8076
8077#if defined(FEAT_MZSCHEME) || defined(PROTO)
8078/*
8079 * "mzeval()" function
8080 */
8081 static void
8082f_mzeval(typval_T *argvars, typval_T *rettv)
8083{
8084 char_u *str;
8085 char_u buf[NUMBUFLEN];
8086
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008087 if (check_restricted() || check_secure())
8088 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008089 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008090 do_mzeval(str, rettv);
8091}
8092
8093 void
8094mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8095{
8096 typval_T argvars[3];
8097
8098 argvars[0].v_type = VAR_STRING;
8099 argvars[0].vval.v_string = name;
8100 copy_tv(args, &argvars[1]);
8101 argvars[2].v_type = VAR_UNKNOWN;
8102 f_call(argvars, rettv);
8103 clear_tv(&argvars[1]);
8104}
8105#endif
8106
8107/*
8108 * "nextnonblank()" function
8109 */
8110 static void
8111f_nextnonblank(typval_T *argvars, typval_T *rettv)
8112{
8113 linenr_T lnum;
8114
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008115 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116 {
8117 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8118 {
8119 lnum = 0;
8120 break;
8121 }
8122 if (*skipwhite(ml_get(lnum)) != NUL)
8123 break;
8124 }
8125 rettv->vval.v_number = lnum;
8126}
8127
8128/*
8129 * "nr2char()" function
8130 */
8131 static void
8132f_nr2char(typval_T *argvars, typval_T *rettv)
8133{
8134 char_u buf[NUMBUFLEN];
8135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136 if (has_mbyte)
8137 {
8138 int utf8 = 0;
8139
8140 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008141 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008143 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008145 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 }
8147 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008149 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150 buf[1] = NUL;
8151 }
8152 rettv->v_type = VAR_STRING;
8153 rettv->vval.v_string = vim_strsave(buf);
8154}
8155
8156/*
8157 * "or(expr, expr)" function
8158 */
8159 static void
8160f_or(typval_T *argvars, typval_T *rettv)
8161{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008162 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8163 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164}
8165
8166/*
8167 * "pathshorten()" function
8168 */
8169 static void
8170f_pathshorten(typval_T *argvars, typval_T *rettv)
8171{
8172 char_u *p;
8173
8174 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 if (p == NULL)
8177 rettv->vval.v_string = NULL;
8178 else
8179 {
8180 p = vim_strsave(p);
8181 rettv->vval.v_string = p;
8182 if (p != NULL)
8183 shorten_dir(p);
8184 }
8185}
8186
8187#ifdef FEAT_PERL
8188/*
8189 * "perleval()" function
8190 */
8191 static void
8192f_perleval(typval_T *argvars, typval_T *rettv)
8193{
8194 char_u *str;
8195 char_u buf[NUMBUFLEN];
8196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008197 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198 do_perleval(str, rettv);
8199}
8200#endif
8201
8202#ifdef FEAT_FLOAT
8203/*
8204 * "pow()" function
8205 */
8206 static void
8207f_pow(typval_T *argvars, typval_T *rettv)
8208{
8209 float_T fx = 0.0, fy = 0.0;
8210
8211 rettv->v_type = VAR_FLOAT;
8212 if (get_float_arg(argvars, &fx) == OK
8213 && get_float_arg(&argvars[1], &fy) == OK)
8214 rettv->vval.v_float = pow(fx, fy);
8215 else
8216 rettv->vval.v_float = 0.0;
8217}
8218#endif
8219
8220/*
8221 * "prevnonblank()" function
8222 */
8223 static void
8224f_prevnonblank(typval_T *argvars, typval_T *rettv)
8225{
8226 linenr_T lnum;
8227
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008228 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008229 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8230 lnum = 0;
8231 else
8232 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8233 --lnum;
8234 rettv->vval.v_number = lnum;
8235}
8236
8237/* This dummy va_list is here because:
8238 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8239 * - locally in the function results in a "used before set" warning
8240 * - using va_start() to initialize it gives "function with fixed args" error */
8241static va_list ap;
8242
8243/*
8244 * "printf()" function
8245 */
8246 static void
8247f_printf(typval_T *argvars, typval_T *rettv)
8248{
8249 char_u buf[NUMBUFLEN];
8250 int len;
8251 char_u *s;
8252 int saved_did_emsg = did_emsg;
8253 char *fmt;
8254
8255 rettv->v_type = VAR_STRING;
8256 rettv->vval.v_string = NULL;
8257
8258 /* Get the required length, allocate the buffer and do it for real. */
8259 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008260 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008261 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008262 if (!did_emsg)
8263 {
8264 s = alloc(len + 1);
8265 if (s != NULL)
8266 {
8267 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008268 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8269 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270 }
8271 }
8272 did_emsg |= saved_did_emsg;
8273}
8274
8275/*
8276 * "pumvisible()" function
8277 */
8278 static void
8279f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8280{
8281#ifdef FEAT_INS_EXPAND
8282 if (pum_visible())
8283 rettv->vval.v_number = 1;
8284#endif
8285}
8286
8287#ifdef FEAT_PYTHON3
8288/*
8289 * "py3eval()" function
8290 */
8291 static void
8292f_py3eval(typval_T *argvars, typval_T *rettv)
8293{
8294 char_u *str;
8295 char_u buf[NUMBUFLEN];
8296
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008297 if (check_restricted() || check_secure())
8298 return;
8299
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008300 if (p_pyx == 0)
8301 p_pyx = 3;
8302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008303 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304 do_py3eval(str, rettv);
8305}
8306#endif
8307
8308#ifdef FEAT_PYTHON
8309/*
8310 * "pyeval()" function
8311 */
8312 static void
8313f_pyeval(typval_T *argvars, typval_T *rettv)
8314{
8315 char_u *str;
8316 char_u buf[NUMBUFLEN];
8317
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008318 if (check_restricted() || check_secure())
8319 return;
8320
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008321 if (p_pyx == 0)
8322 p_pyx = 2;
8323
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008324 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008325 do_pyeval(str, rettv);
8326}
8327#endif
8328
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008329#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8330/*
8331 * "pyxeval()" function
8332 */
8333 static void
8334f_pyxeval(typval_T *argvars, typval_T *rettv)
8335{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008336 if (check_restricted() || check_secure())
8337 return;
8338
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008339# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8340 init_pyxversion();
8341 if (p_pyx == 2)
8342 f_pyeval(argvars, rettv);
8343 else
8344 f_py3eval(argvars, rettv);
8345# elif defined(FEAT_PYTHON)
8346 f_pyeval(argvars, rettv);
8347# elif defined(FEAT_PYTHON3)
8348 f_py3eval(argvars, rettv);
8349# endif
8350}
8351#endif
8352
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353/*
8354 * "range()" function
8355 */
8356 static void
8357f_range(typval_T *argvars, typval_T *rettv)
8358{
8359 varnumber_T start;
8360 varnumber_T end;
8361 varnumber_T stride = 1;
8362 varnumber_T i;
8363 int error = FALSE;
8364
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008365 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008366 if (argvars[1].v_type == VAR_UNKNOWN)
8367 {
8368 end = start - 1;
8369 start = 0;
8370 }
8371 else
8372 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008373 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008375 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 }
8377
8378 if (error)
8379 return; /* type error; errmsg already given */
8380 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008381 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008383 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 else
8385 {
8386 if (rettv_list_alloc(rettv) == OK)
8387 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8388 if (list_append_number(rettv->vval.v_list,
8389 (varnumber_T)i) == FAIL)
8390 break;
8391 }
8392}
8393
8394/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008395 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008396 */
8397 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008398readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008399{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008400 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008401 typval_T save_val;
8402 typval_T rettv;
8403 typval_T argv[2];
8404 int retval = 0;
8405 int error = FALSE;
8406
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008407 if (expr->v_type == VAR_UNKNOWN)
8408 return 1;
8409
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008410 prepare_vimvar(VV_VAL, &save_val);
8411 set_vim_var_string(VV_VAL, name, -1);
8412 argv[0].v_type = VAR_STRING;
8413 argv[0].vval.v_string = name;
8414
8415 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8416 goto theend;
8417
8418 retval = tv_get_number_chk(&rettv, &error);
8419 if (error)
8420 retval = -1;
8421 clear_tv(&rettv);
8422
8423theend:
8424 set_vim_var_string(VV_VAL, NULL, 0);
8425 restore_vimvar(VV_VAL, &save_val);
8426 return retval;
8427}
8428
8429/*
8430 * "readdir()" function
8431 */
8432 static void
8433f_readdir(typval_T *argvars, typval_T *rettv)
8434{
8435 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008436 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008437 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008438 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008439 garray_T ga;
8440 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008441
8442 if (rettv_list_alloc(rettv) == FAIL)
8443 return;
8444 path = tv_get_string(&argvars[0]);
8445 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008446
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008447 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8448 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008449 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008450 for (i = 0; i < ga.ga_len; i++)
8451 {
8452 p = ((char_u **)ga.ga_data)[i];
8453 list_append_string(rettv->vval.v_list, p, -1);
8454 }
8455 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008456 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008457}
8458
8459/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008460 * "readfile()" function
8461 */
8462 static void
8463f_readfile(typval_T *argvars, typval_T *rettv)
8464{
8465 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008466 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008467 int failed = FALSE;
8468 char_u *fname;
8469 FILE *fd;
8470 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8471 int io_size = sizeof(buf);
8472 int readlen; /* size of last fread() */
8473 char_u *prev = NULL; /* previously read bytes, if any */
8474 long prevlen = 0; /* length of data in prev */
8475 long prevsize = 0; /* size of prev buffer */
8476 long maxline = MAXLNUM;
8477 long cnt = 0;
8478 char_u *p; /* position in buf */
8479 char_u *start; /* start of current line */
8480
8481 if (argvars[1].v_type != VAR_UNKNOWN)
8482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008483 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008485 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8486 blob = TRUE;
8487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008488 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008489 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 }
8491
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008492 if (blob)
8493 {
8494 if (rettv_blob_alloc(rettv) == FAIL)
8495 return;
8496 }
8497 else
8498 {
8499 if (rettv_list_alloc(rettv) == FAIL)
8500 return;
8501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502
8503 /* Always open the file in binary mode, library functions have a mind of
8504 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008505 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008506 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008508 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008509 return;
8510 }
8511
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008512 if (blob)
8513 {
8514 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8515 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008516 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008517 blob_free(rettv->vval.v_blob);
8518 }
8519 fclose(fd);
8520 return;
8521 }
8522
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 while (cnt < maxline || maxline < 0)
8524 {
8525 readlen = (int)fread(buf, 1, io_size, fd);
8526
8527 /* This for loop processes what was read, but is also entered at end
8528 * of file so that either:
8529 * - an incomplete line gets written
8530 * - a "binary" file gets an empty line at the end if it ends in a
8531 * newline. */
8532 for (p = buf, start = buf;
8533 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8534 ++p)
8535 {
8536 if (*p == '\n' || readlen <= 0)
8537 {
8538 listitem_T *li;
8539 char_u *s = NULL;
8540 long_u len = p - start;
8541
8542 /* Finished a line. Remove CRs before NL. */
8543 if (readlen > 0 && !binary)
8544 {
8545 while (len > 0 && start[len - 1] == '\r')
8546 --len;
8547 /* removal may cross back to the "prev" string */
8548 if (len == 0)
8549 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8550 --prevlen;
8551 }
8552 if (prevlen == 0)
8553 s = vim_strnsave(start, (int)len);
8554 else
8555 {
8556 /* Change "prev" buffer to be the right size. This way
8557 * the bytes are only copied once, and very long lines are
8558 * allocated only once. */
8559 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8560 {
8561 mch_memmove(s + prevlen, start, len);
8562 s[prevlen + len] = NUL;
8563 prev = NULL; /* the list will own the string */
8564 prevlen = prevsize = 0;
8565 }
8566 }
8567 if (s == NULL)
8568 {
8569 do_outofmem_msg((long_u) prevlen + len + 1);
8570 failed = TRUE;
8571 break;
8572 }
8573
8574 if ((li = listitem_alloc()) == NULL)
8575 {
8576 vim_free(s);
8577 failed = TRUE;
8578 break;
8579 }
8580 li->li_tv.v_type = VAR_STRING;
8581 li->li_tv.v_lock = 0;
8582 li->li_tv.vval.v_string = s;
8583 list_append(rettv->vval.v_list, li);
8584
8585 start = p + 1; /* step over newline */
8586 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8587 break;
8588 }
8589 else if (*p == NUL)
8590 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008591 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8592 * when finding the BF and check the previous two bytes. */
8593 else if (*p == 0xbf && enc_utf8 && !binary)
8594 {
8595 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8596 * + 1, these may be in the "prev" string. */
8597 char_u back1 = p >= buf + 1 ? p[-1]
8598 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8599 char_u back2 = p >= buf + 2 ? p[-2]
8600 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8601 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8602
8603 if (back2 == 0xef && back1 == 0xbb)
8604 {
8605 char_u *dest = p - 2;
8606
8607 /* Usually a BOM is at the beginning of a file, and so at
8608 * the beginning of a line; then we can just step over it.
8609 */
8610 if (start == dest)
8611 start = p + 1;
8612 else
8613 {
8614 /* have to shuffle buf to close gap */
8615 int adjust_prevlen = 0;
8616
8617 if (dest < buf)
8618 {
8619 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8620 dest = buf;
8621 }
8622 if (readlen > p - buf + 1)
8623 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8624 readlen -= 3 - adjust_prevlen;
8625 prevlen -= adjust_prevlen;
8626 p = dest - 1;
8627 }
8628 }
8629 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008630 } /* for */
8631
8632 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8633 break;
8634 if (start < p)
8635 {
8636 /* There's part of a line in buf, store it in "prev". */
8637 if (p - start + prevlen >= prevsize)
8638 {
8639 /* need bigger "prev" buffer */
8640 char_u *newprev;
8641
8642 /* A common use case is ordinary text files and "prev" gets a
8643 * fragment of a line, so the first allocation is made
8644 * small, to avoid repeatedly 'allocing' large and
8645 * 'reallocing' small. */
8646 if (prevsize == 0)
8647 prevsize = (long)(p - start);
8648 else
8649 {
8650 long grow50pc = (prevsize * 3) / 2;
8651 long growmin = (long)((p - start) * 2 + prevlen);
8652 prevsize = grow50pc > growmin ? grow50pc : growmin;
8653 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008654 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008655 if (newprev == NULL)
8656 {
8657 do_outofmem_msg((long_u)prevsize);
8658 failed = TRUE;
8659 break;
8660 }
8661 prev = newprev;
8662 }
8663 /* Add the line part to end of "prev". */
8664 mch_memmove(prev + prevlen, start, p - start);
8665 prevlen += (long)(p - start);
8666 }
8667 } /* while */
8668
8669 /*
8670 * For a negative line count use only the lines at the end of the file,
8671 * free the rest.
8672 */
8673 if (!failed && maxline < 0)
8674 while (cnt > -maxline)
8675 {
8676 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8677 --cnt;
8678 }
8679
8680 if (failed)
8681 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008682 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008683 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008684 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008685 }
8686
8687 vim_free(prev);
8688 fclose(fd);
8689}
8690
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008691 static void
8692return_register(int regname, typval_T *rettv)
8693{
8694 char_u buf[2] = {0, 0};
8695
8696 buf[0] = (char_u)regname;
8697 rettv->v_type = VAR_STRING;
8698 rettv->vval.v_string = vim_strsave(buf);
8699}
8700
8701/*
8702 * "reg_executing()" function
8703 */
8704 static void
8705f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8706{
8707 return_register(reg_executing, rettv);
8708}
8709
8710/*
8711 * "reg_recording()" function
8712 */
8713 static void
8714f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8715{
8716 return_register(reg_recording, rettv);
8717}
8718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720/*
8721 * Convert a List to proftime_T.
8722 * Return FAIL when there is something wrong.
8723 */
8724 static int
8725list2proftime(typval_T *arg, proftime_T *tm)
8726{
8727 long n1, n2;
8728 int error = FALSE;
8729
8730 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8731 || arg->vval.v_list->lv_len != 2)
8732 return FAIL;
8733 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8734 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008735# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008736 tm->HighPart = n1;
8737 tm->LowPart = n2;
8738# else
8739 tm->tv_sec = n1;
8740 tm->tv_usec = n2;
8741# endif
8742 return error ? FAIL : OK;
8743}
8744#endif /* FEAT_RELTIME */
8745
8746/*
8747 * "reltime()" function
8748 */
8749 static void
8750f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8751{
8752#ifdef FEAT_RELTIME
8753 proftime_T res;
8754 proftime_T start;
8755
8756 if (argvars[0].v_type == VAR_UNKNOWN)
8757 {
8758 /* No arguments: get current time. */
8759 profile_start(&res);
8760 }
8761 else if (argvars[1].v_type == VAR_UNKNOWN)
8762 {
8763 if (list2proftime(&argvars[0], &res) == FAIL)
8764 return;
8765 profile_end(&res);
8766 }
8767 else
8768 {
8769 /* Two arguments: compute the difference. */
8770 if (list2proftime(&argvars[0], &start) == FAIL
8771 || list2proftime(&argvars[1], &res) == FAIL)
8772 return;
8773 profile_sub(&res, &start);
8774 }
8775
8776 if (rettv_list_alloc(rettv) == OK)
8777 {
8778 long n1, n2;
8779
Bram Moolenaar4f974752019-02-17 17:44:42 +01008780# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008781 n1 = res.HighPart;
8782 n2 = res.LowPart;
8783# else
8784 n1 = res.tv_sec;
8785 n2 = res.tv_usec;
8786# endif
8787 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8788 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8789 }
8790#endif
8791}
8792
8793#ifdef FEAT_FLOAT
8794/*
8795 * "reltimefloat()" function
8796 */
8797 static void
8798f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8799{
8800# ifdef FEAT_RELTIME
8801 proftime_T tm;
8802# endif
8803
8804 rettv->v_type = VAR_FLOAT;
8805 rettv->vval.v_float = 0;
8806# ifdef FEAT_RELTIME
8807 if (list2proftime(&argvars[0], &tm) == OK)
8808 rettv->vval.v_float = profile_float(&tm);
8809# endif
8810}
8811#endif
8812
8813/*
8814 * "reltimestr()" function
8815 */
8816 static void
8817f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8818{
8819#ifdef FEAT_RELTIME
8820 proftime_T tm;
8821#endif
8822
8823 rettv->v_type = VAR_STRING;
8824 rettv->vval.v_string = NULL;
8825#ifdef FEAT_RELTIME
8826 if (list2proftime(&argvars[0], &tm) == OK)
8827 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8828#endif
8829}
8830
8831#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008832 static void
8833make_connection(void)
8834{
8835 if (X_DISPLAY == NULL
8836# ifdef FEAT_GUI
8837 && !gui.in_use
8838# endif
8839 )
8840 {
8841 x_force_connect = TRUE;
8842 setup_term_clip();
8843 x_force_connect = FALSE;
8844 }
8845}
8846
8847 static int
8848check_connection(void)
8849{
8850 make_connection();
8851 if (X_DISPLAY == NULL)
8852 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008853 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854 return FAIL;
8855 }
8856 return OK;
8857}
8858#endif
8859
8860#ifdef FEAT_CLIENTSERVER
8861 static void
8862remote_common(typval_T *argvars, typval_T *rettv, int expr)
8863{
8864 char_u *server_name;
8865 char_u *keys;
8866 char_u *r = NULL;
8867 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008868 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008869# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870 HWND w;
8871# else
8872 Window w;
8873# endif
8874
8875 if (check_restricted() || check_secure())
8876 return;
8877
8878# ifdef FEAT_X11
8879 if (check_connection() == FAIL)
8880 return;
8881# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008882 if (argvars[2].v_type != VAR_UNKNOWN
8883 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008884 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008885
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008886 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008887 if (server_name == NULL)
8888 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008889 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008890# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008891 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008892# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008893 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8894 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008895# endif
8896 {
8897 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008898 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008899 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008900 vim_free(r);
8901 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008903 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008904 return;
8905 }
8906
8907 rettv->vval.v_string = r;
8908
8909 if (argvars[2].v_type != VAR_UNKNOWN)
8910 {
8911 dictitem_T v;
8912 char_u str[30];
8913 char_u *idvar;
8914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008915 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008916 if (idvar != NULL && *idvar != NUL)
8917 {
8918 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8919 v.di_tv.v_type = VAR_STRING;
8920 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008921 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008922 vim_free(v.di_tv.vval.v_string);
8923 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008924 }
8925}
8926#endif
8927
8928/*
8929 * "remote_expr()" function
8930 */
8931 static void
8932f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8933{
8934 rettv->v_type = VAR_STRING;
8935 rettv->vval.v_string = NULL;
8936#ifdef FEAT_CLIENTSERVER
8937 remote_common(argvars, rettv, TRUE);
8938#endif
8939}
8940
8941/*
8942 * "remote_foreground()" function
8943 */
8944 static void
8945f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8946{
8947#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008948# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008949 /* On Win32 it's done in this application. */
8950 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008951 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008952
8953 if (server_name != NULL)
8954 serverForeground(server_name);
8955 }
8956# else
8957 /* Send a foreground() expression to the server. */
8958 argvars[1].v_type = VAR_STRING;
8959 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8960 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008961 rettv->v_type = VAR_STRING;
8962 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008963 remote_common(argvars, rettv, TRUE);
8964 vim_free(argvars[1].vval.v_string);
8965# endif
8966#endif
8967}
8968
8969 static void
8970f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8971{
8972#ifdef FEAT_CLIENTSERVER
8973 dictitem_T v;
8974 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008975# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008976 long_u n = 0;
8977# endif
8978 char_u *serverid;
8979
8980 if (check_restricted() || check_secure())
8981 {
8982 rettv->vval.v_number = -1;
8983 return;
8984 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008985 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008986 if (serverid == NULL)
8987 {
8988 rettv->vval.v_number = -1;
8989 return; /* type error; errmsg already given */
8990 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008991# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008992 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8993 if (n == 0)
8994 rettv->vval.v_number = -1;
8995 else
8996 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008997 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008998 rettv->vval.v_number = (s != NULL);
8999 }
9000# else
9001 if (check_connection() == FAIL)
9002 return;
9003
9004 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9005 serverStrToWin(serverid), &s);
9006# endif
9007
9008 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9009 {
9010 char_u *retvar;
9011
9012 v.di_tv.v_type = VAR_STRING;
9013 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009014 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009015 if (retvar != NULL)
9016 set_var(retvar, &v.di_tv, FALSE);
9017 vim_free(v.di_tv.vval.v_string);
9018 }
9019#else
9020 rettv->vval.v_number = -1;
9021#endif
9022}
9023
9024 static void
9025f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9026{
9027 char_u *r = NULL;
9028
9029#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009030 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009031
9032 if (serverid != NULL && !check_restricted() && !check_secure())
9033 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009034 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009035# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009036 /* The server's HWND is encoded in the 'id' parameter */
9037 long_u n = 0;
9038# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009039
9040 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009041 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009042
Bram Moolenaar4f974752019-02-17 17:44:42 +01009043# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009044 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9045 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009046 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009047 if (r == NULL)
9048# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009049 if (check_connection() == FAIL
9050 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9051 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009052# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009053 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009054 }
9055#endif
9056 rettv->v_type = VAR_STRING;
9057 rettv->vval.v_string = r;
9058}
9059
9060/*
9061 * "remote_send()" function
9062 */
9063 static void
9064f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9065{
9066 rettv->v_type = VAR_STRING;
9067 rettv->vval.v_string = NULL;
9068#ifdef FEAT_CLIENTSERVER
9069 remote_common(argvars, rettv, FALSE);
9070#endif
9071}
9072
9073/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009074 * "remote_startserver()" function
9075 */
9076 static void
9077f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9078{
9079#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009080 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009081
9082 if (server == NULL)
9083 return; /* type error; errmsg already given */
9084 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009085 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009086 else
9087 {
9088# ifdef FEAT_X11
9089 if (check_connection() == OK)
9090 serverRegisterName(X_DISPLAY, server);
9091# else
9092 serverSetName(server);
9093# endif
9094 }
9095#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009096 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009097#endif
9098}
9099
9100/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009101 * "remove()" function
9102 */
9103 static void
9104f_remove(typval_T *argvars, typval_T *rettv)
9105{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009106 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9107
9108 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009109 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009110 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009111 blob_remove(argvars, rettv);
9112 else if (argvars[0].v_type == VAR_LIST)
9113 list_remove(argvars, rettv, arg_errmsg);
9114 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009115 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009116}
9117
9118/*
9119 * "rename({from}, {to})" function
9120 */
9121 static void
9122f_rename(typval_T *argvars, typval_T *rettv)
9123{
9124 char_u buf[NUMBUFLEN];
9125
9126 if (check_restricted() || check_secure())
9127 rettv->vval.v_number = -1;
9128 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009129 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9130 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009131}
9132
9133/*
9134 * "repeat()" function
9135 */
9136 static void
9137f_repeat(typval_T *argvars, typval_T *rettv)
9138{
9139 char_u *p;
9140 int n;
9141 int slen;
9142 int len;
9143 char_u *r;
9144 int i;
9145
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009146 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009147 if (argvars[0].v_type == VAR_LIST)
9148 {
9149 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9150 while (n-- > 0)
9151 if (list_extend(rettv->vval.v_list,
9152 argvars[0].vval.v_list, NULL) == FAIL)
9153 break;
9154 }
9155 else
9156 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009157 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009158 rettv->v_type = VAR_STRING;
9159 rettv->vval.v_string = NULL;
9160
9161 slen = (int)STRLEN(p);
9162 len = slen * n;
9163 if (len <= 0)
9164 return;
9165
9166 r = alloc(len + 1);
9167 if (r != NULL)
9168 {
9169 for (i = 0; i < n; i++)
9170 mch_memmove(r + i * slen, p, (size_t)slen);
9171 r[len] = NUL;
9172 }
9173
9174 rettv->vval.v_string = r;
9175 }
9176}
9177
9178/*
9179 * "resolve()" function
9180 */
9181 static void
9182f_resolve(typval_T *argvars, typval_T *rettv)
9183{
9184 char_u *p;
9185#ifdef HAVE_READLINK
9186 char_u *buf = NULL;
9187#endif
9188
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009189 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009190#ifdef FEAT_SHORTCUT
9191 {
9192 char_u *v = NULL;
9193
Bram Moolenaardce1e892019-02-10 23:18:53 +01009194 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009195 if (v != NULL)
9196 rettv->vval.v_string = v;
9197 else
9198 rettv->vval.v_string = vim_strsave(p);
9199 }
9200#else
9201# ifdef HAVE_READLINK
9202 {
9203 char_u *cpy;
9204 int len;
9205 char_u *remain = NULL;
9206 char_u *q;
9207 int is_relative_to_current = FALSE;
9208 int has_trailing_pathsep = FALSE;
9209 int limit = 100;
9210
9211 p = vim_strsave(p);
9212
9213 if (p[0] == '.' && (vim_ispathsep(p[1])
9214 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9215 is_relative_to_current = TRUE;
9216
9217 len = STRLEN(p);
9218 if (len > 0 && after_pathsep(p, p + len))
9219 {
9220 has_trailing_pathsep = TRUE;
9221 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9222 }
9223
9224 q = getnextcomp(p);
9225 if (*q != NUL)
9226 {
9227 /* Separate the first path component in "p", and keep the
9228 * remainder (beginning with the path separator). */
9229 remain = vim_strsave(q - 1);
9230 q[-1] = NUL;
9231 }
9232
9233 buf = alloc(MAXPATHL + 1);
9234 if (buf == NULL)
9235 goto fail;
9236
9237 for (;;)
9238 {
9239 for (;;)
9240 {
9241 len = readlink((char *)p, (char *)buf, MAXPATHL);
9242 if (len <= 0)
9243 break;
9244 buf[len] = NUL;
9245
9246 if (limit-- == 0)
9247 {
9248 vim_free(p);
9249 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009250 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009251 rettv->vval.v_string = NULL;
9252 goto fail;
9253 }
9254
9255 /* Ensure that the result will have a trailing path separator
9256 * if the argument has one. */
9257 if (remain == NULL && has_trailing_pathsep)
9258 add_pathsep(buf);
9259
9260 /* Separate the first path component in the link value and
9261 * concatenate the remainders. */
9262 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9263 if (*q != NUL)
9264 {
9265 if (remain == NULL)
9266 remain = vim_strsave(q - 1);
9267 else
9268 {
9269 cpy = concat_str(q - 1, remain);
9270 if (cpy != NULL)
9271 {
9272 vim_free(remain);
9273 remain = cpy;
9274 }
9275 }
9276 q[-1] = NUL;
9277 }
9278
9279 q = gettail(p);
9280 if (q > p && *q == NUL)
9281 {
9282 /* Ignore trailing path separator. */
9283 q[-1] = NUL;
9284 q = gettail(p);
9285 }
9286 if (q > p && !mch_isFullName(buf))
9287 {
9288 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009289 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009290 if (cpy != NULL)
9291 {
9292 STRCPY(cpy, p);
9293 STRCPY(gettail(cpy), buf);
9294 vim_free(p);
9295 p = cpy;
9296 }
9297 }
9298 else
9299 {
9300 vim_free(p);
9301 p = vim_strsave(buf);
9302 }
9303 }
9304
9305 if (remain == NULL)
9306 break;
9307
9308 /* Append the first path component of "remain" to "p". */
9309 q = getnextcomp(remain + 1);
9310 len = q - remain - (*q != NUL);
9311 cpy = vim_strnsave(p, STRLEN(p) + len);
9312 if (cpy != NULL)
9313 {
9314 STRNCAT(cpy, remain, len);
9315 vim_free(p);
9316 p = cpy;
9317 }
9318 /* Shorten "remain". */
9319 if (*q != NUL)
9320 STRMOVE(remain, q - 1);
9321 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009322 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009323 }
9324
9325 /* If the result is a relative path name, make it explicitly relative to
9326 * the current directory if and only if the argument had this form. */
9327 if (!vim_ispathsep(*p))
9328 {
9329 if (is_relative_to_current
9330 && *p != NUL
9331 && !(p[0] == '.'
9332 && (p[1] == NUL
9333 || vim_ispathsep(p[1])
9334 || (p[1] == '.'
9335 && (p[2] == NUL
9336 || vim_ispathsep(p[2]))))))
9337 {
9338 /* Prepend "./". */
9339 cpy = concat_str((char_u *)"./", p);
9340 if (cpy != NULL)
9341 {
9342 vim_free(p);
9343 p = cpy;
9344 }
9345 }
9346 else if (!is_relative_to_current)
9347 {
9348 /* Strip leading "./". */
9349 q = p;
9350 while (q[0] == '.' && vim_ispathsep(q[1]))
9351 q += 2;
9352 if (q > p)
9353 STRMOVE(p, p + 2);
9354 }
9355 }
9356
9357 /* Ensure that the result will have no trailing path separator
9358 * if the argument had none. But keep "/" or "//". */
9359 if (!has_trailing_pathsep)
9360 {
9361 q = p + STRLEN(p);
9362 if (after_pathsep(p, q))
9363 *gettail_sep(p) = NUL;
9364 }
9365
9366 rettv->vval.v_string = p;
9367 }
9368# else
9369 rettv->vval.v_string = vim_strsave(p);
9370# endif
9371#endif
9372
9373 simplify_filename(rettv->vval.v_string);
9374
9375#ifdef HAVE_READLINK
9376fail:
9377 vim_free(buf);
9378#endif
9379 rettv->v_type = VAR_STRING;
9380}
9381
9382/*
9383 * "reverse({list})" function
9384 */
9385 static void
9386f_reverse(typval_T *argvars, typval_T *rettv)
9387{
9388 list_T *l;
9389 listitem_T *li, *ni;
9390
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009391 if (argvars[0].v_type == VAR_BLOB)
9392 {
9393 blob_T *b = argvars[0].vval.v_blob;
9394 int i, len = blob_len(b);
9395
9396 for (i = 0; i < len / 2; i++)
9397 {
9398 int tmp = blob_get(b, i);
9399
9400 blob_set(b, i, blob_get(b, len - i - 1));
9401 blob_set(b, len - i - 1, tmp);
9402 }
9403 rettv_blob_set(rettv, b);
9404 return;
9405 }
9406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009407 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009408 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009409 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009410 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009411 (char_u *)N_("reverse() argument"), TRUE))
9412 {
9413 li = l->lv_last;
9414 l->lv_first = l->lv_last = NULL;
9415 l->lv_len = 0;
9416 while (li != NULL)
9417 {
9418 ni = li->li_prev;
9419 list_append(l, li);
9420 li = ni;
9421 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009422 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009423 l->lv_idx = l->lv_len - l->lv_idx - 1;
9424 }
9425}
9426
9427#define SP_NOMOVE 0x01 /* don't move cursor */
9428#define SP_REPEAT 0x02 /* repeat to find outer pair */
9429#define SP_RETCOUNT 0x04 /* return matchcount */
9430#define SP_SETPCMARK 0x08 /* set previous context mark */
9431#define SP_START 0x10 /* accept match at start position */
9432#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9433#define SP_END 0x40 /* leave cursor at end of match */
9434#define SP_COLUMN 0x80 /* start at cursor column */
9435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009436/*
9437 * Get flags for a search function.
9438 * Possibly sets "p_ws".
9439 * Returns BACKWARD, FORWARD or zero (for an error).
9440 */
9441 static int
9442get_search_arg(typval_T *varp, int *flagsp)
9443{
9444 int dir = FORWARD;
9445 char_u *flags;
9446 char_u nbuf[NUMBUFLEN];
9447 int mask;
9448
9449 if (varp->v_type != VAR_UNKNOWN)
9450 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009451 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009452 if (flags == NULL)
9453 return 0; /* type error; errmsg already given */
9454 while (*flags != NUL)
9455 {
9456 switch (*flags)
9457 {
9458 case 'b': dir = BACKWARD; break;
9459 case 'w': p_ws = TRUE; break;
9460 case 'W': p_ws = FALSE; break;
9461 default: mask = 0;
9462 if (flagsp != NULL)
9463 switch (*flags)
9464 {
9465 case 'c': mask = SP_START; break;
9466 case 'e': mask = SP_END; break;
9467 case 'm': mask = SP_RETCOUNT; break;
9468 case 'n': mask = SP_NOMOVE; break;
9469 case 'p': mask = SP_SUBPAT; break;
9470 case 'r': mask = SP_REPEAT; break;
9471 case 's': mask = SP_SETPCMARK; break;
9472 case 'z': mask = SP_COLUMN; break;
9473 }
9474 if (mask == 0)
9475 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009476 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009477 dir = 0;
9478 }
9479 else
9480 *flagsp |= mask;
9481 }
9482 if (dir == 0)
9483 break;
9484 ++flags;
9485 }
9486 }
9487 return dir;
9488}
9489
9490/*
9491 * Shared by search() and searchpos() functions.
9492 */
9493 static int
9494search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9495{
9496 int flags;
9497 char_u *pat;
9498 pos_T pos;
9499 pos_T save_cursor;
9500 int save_p_ws = p_ws;
9501 int dir;
9502 int retval = 0; /* default: FAIL */
9503 long lnum_stop = 0;
9504 proftime_T tm;
9505#ifdef FEAT_RELTIME
9506 long time_limit = 0;
9507#endif
9508 int options = SEARCH_KEEP;
9509 int subpatnum;
9510
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009511 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009512 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9513 if (dir == 0)
9514 goto theend;
9515 flags = *flagsp;
9516 if (flags & SP_START)
9517 options |= SEARCH_START;
9518 if (flags & SP_END)
9519 options |= SEARCH_END;
9520 if (flags & SP_COLUMN)
9521 options |= SEARCH_COL;
9522
9523 /* Optional arguments: line number to stop searching and timeout. */
9524 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9525 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009526 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009527 if (lnum_stop < 0)
9528 goto theend;
9529#ifdef FEAT_RELTIME
9530 if (argvars[3].v_type != VAR_UNKNOWN)
9531 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009532 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009533 if (time_limit < 0)
9534 goto theend;
9535 }
9536#endif
9537 }
9538
9539#ifdef FEAT_RELTIME
9540 /* Set the time limit, if there is one. */
9541 profile_setlimit(time_limit, &tm);
9542#endif
9543
9544 /*
9545 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9546 * Check to make sure only those flags are set.
9547 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9548 * flags cannot be set. Check for that condition also.
9549 */
9550 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9551 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9552 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009553 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009554 goto theend;
9555 }
9556
9557 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009558 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009559 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009560 if (subpatnum != FAIL)
9561 {
9562 if (flags & SP_SUBPAT)
9563 retval = subpatnum;
9564 else
9565 retval = pos.lnum;
9566 if (flags & SP_SETPCMARK)
9567 setpcmark();
9568 curwin->w_cursor = pos;
9569 if (match_pos != NULL)
9570 {
9571 /* Store the match cursor position */
9572 match_pos->lnum = pos.lnum;
9573 match_pos->col = pos.col + 1;
9574 }
9575 /* "/$" will put the cursor after the end of the line, may need to
9576 * correct that here */
9577 check_cursor();
9578 }
9579
9580 /* If 'n' flag is used: restore cursor position. */
9581 if (flags & SP_NOMOVE)
9582 curwin->w_cursor = save_cursor;
9583 else
9584 curwin->w_set_curswant = TRUE;
9585theend:
9586 p_ws = save_p_ws;
9587
9588 return retval;
9589}
9590
9591#ifdef FEAT_FLOAT
9592
9593/*
9594 * round() is not in C90, use ceil() or floor() instead.
9595 */
9596 float_T
9597vim_round(float_T f)
9598{
9599 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9600}
9601
9602/*
9603 * "round({float})" function
9604 */
9605 static void
9606f_round(typval_T *argvars, typval_T *rettv)
9607{
9608 float_T f = 0.0;
9609
9610 rettv->v_type = VAR_FLOAT;
9611 if (get_float_arg(argvars, &f) == OK)
9612 rettv->vval.v_float = vim_round(f);
9613 else
9614 rettv->vval.v_float = 0.0;
9615}
9616#endif
9617
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009618#ifdef FEAT_RUBY
9619/*
9620 * "rubyeval()" function
9621 */
9622 static void
9623f_rubyeval(typval_T *argvars, typval_T *rettv)
9624{
9625 char_u *str;
9626 char_u buf[NUMBUFLEN];
9627
9628 str = tv_get_string_buf(&argvars[0], buf);
9629 do_rubyeval(str, rettv);
9630}
9631#endif
9632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009633/*
9634 * "screenattr()" function
9635 */
9636 static void
9637f_screenattr(typval_T *argvars, typval_T *rettv)
9638{
9639 int row;
9640 int col;
9641 int c;
9642
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009643 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9644 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009645 if (row < 0 || row >= screen_Rows
9646 || col < 0 || col >= screen_Columns)
9647 c = -1;
9648 else
9649 c = ScreenAttrs[LineOffset[row] + col];
9650 rettv->vval.v_number = c;
9651}
9652
9653/*
9654 * "screenchar()" function
9655 */
9656 static void
9657f_screenchar(typval_T *argvars, typval_T *rettv)
9658{
9659 int row;
9660 int col;
9661 int off;
9662 int c;
9663
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009664 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9665 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009666 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009667 c = -1;
9668 else
9669 {
9670 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 if (enc_utf8 && ScreenLinesUC[off] != 0)
9672 c = ScreenLinesUC[off];
9673 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009674 c = ScreenLines[off];
9675 }
9676 rettv->vval.v_number = c;
9677}
9678
9679/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009680 * "screenchars()" function
9681 */
9682 static void
9683f_screenchars(typval_T *argvars, typval_T *rettv)
9684{
9685 int row;
9686 int col;
9687 int off;
9688 int c;
9689 int i;
9690
9691 if (rettv_list_alloc(rettv) == FAIL)
9692 return;
9693 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9694 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9695 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9696 return;
9697
9698 off = LineOffset[row] + col;
9699 if (enc_utf8 && ScreenLinesUC[off] != 0)
9700 c = ScreenLinesUC[off];
9701 else
9702 c = ScreenLines[off];
9703 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9704
9705 if (enc_utf8)
9706
9707 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9708 list_append_number(rettv->vval.v_list,
9709 (varnumber_T)ScreenLinesC[i][off]);
9710}
9711
9712/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009713 * "screencol()" function
9714 *
9715 * First column is 1 to be consistent with virtcol().
9716 */
9717 static void
9718f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9719{
9720 rettv->vval.v_number = screen_screencol() + 1;
9721}
9722
9723/*
9724 * "screenrow()" function
9725 */
9726 static void
9727f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9728{
9729 rettv->vval.v_number = screen_screenrow() + 1;
9730}
9731
9732/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009733 * "screenstring()" function
9734 */
9735 static void
9736f_screenstring(typval_T *argvars, typval_T *rettv)
9737{
9738 int row;
9739 int col;
9740 int off;
9741 int c;
9742 int i;
9743 char_u buf[MB_MAXBYTES + 1];
9744 int buflen = 0;
9745
9746 rettv->vval.v_string = NULL;
9747 rettv->v_type = VAR_STRING;
9748
9749 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9750 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9751 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9752 return;
9753
9754 off = LineOffset[row] + col;
9755 if (enc_utf8 && ScreenLinesUC[off] != 0)
9756 c = ScreenLinesUC[off];
9757 else
9758 c = ScreenLines[off];
9759 buflen += mb_char2bytes(c, buf);
9760
9761 if (enc_utf8)
9762 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9763 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9764
9765 buf[buflen] = NUL;
9766 rettv->vval.v_string = vim_strsave(buf);
9767}
9768
9769/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009770 * "search()" function
9771 */
9772 static void
9773f_search(typval_T *argvars, typval_T *rettv)
9774{
9775 int flags = 0;
9776
9777 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9778}
9779
9780/*
9781 * "searchdecl()" function
9782 */
9783 static void
9784f_searchdecl(typval_T *argvars, typval_T *rettv)
9785{
9786 int locally = 1;
9787 int thisblock = 0;
9788 int error = FALSE;
9789 char_u *name;
9790
9791 rettv->vval.v_number = 1; /* default: FAIL */
9792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009793 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009794 if (argvars[1].v_type != VAR_UNKNOWN)
9795 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009796 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009797 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009798 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009799 }
9800 if (!error && name != NULL)
9801 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9802 locally, thisblock, SEARCH_KEEP) == FAIL;
9803}
9804
9805/*
9806 * Used by searchpair() and searchpairpos()
9807 */
9808 static int
9809searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9810{
9811 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009812 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009813 int save_p_ws = p_ws;
9814 int dir;
9815 int flags = 0;
9816 char_u nbuf1[NUMBUFLEN];
9817 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009818 int retval = 0; /* default: FAIL */
9819 long lnum_stop = 0;
9820 long time_limit = 0;
9821
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009822 /* Get the three pattern arguments: start, middle, end. Will result in an
9823 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009824 spat = tv_get_string_chk(&argvars[0]);
9825 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9826 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 if (spat == NULL || mpat == NULL || epat == NULL)
9828 goto theend; /* type error */
9829
9830 /* Handle the optional fourth argument: flags */
9831 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9832 if (dir == 0)
9833 goto theend;
9834
9835 /* Don't accept SP_END or SP_SUBPAT.
9836 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9837 */
9838 if ((flags & (SP_END | SP_SUBPAT)) != 0
9839 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9840 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009841 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009842 goto theend;
9843 }
9844
9845 /* Using 'r' implies 'W', otherwise it doesn't work. */
9846 if (flags & SP_REPEAT)
9847 p_ws = FALSE;
9848
9849 /* Optional fifth argument: skip expression */
9850 if (argvars[3].v_type == VAR_UNKNOWN
9851 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009852 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009853 else
9854 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009855 skip = &argvars[4];
9856 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9857 && skip->v_type != VAR_STRING)
9858 {
9859 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009860 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009861 goto theend;
9862 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009863 if (argvars[5].v_type != VAR_UNKNOWN)
9864 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009865 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009866 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009867 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009868 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009869 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009870 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009871#ifdef FEAT_RELTIME
9872 if (argvars[6].v_type != VAR_UNKNOWN)
9873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009874 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009875 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009876 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009877 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009878 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009879 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880 }
9881#endif
9882 }
9883 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009884
9885 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9886 match_pos, lnum_stop, time_limit);
9887
9888theend:
9889 p_ws = save_p_ws;
9890
9891 return retval;
9892}
9893
9894/*
9895 * "searchpair()" function
9896 */
9897 static void
9898f_searchpair(typval_T *argvars, typval_T *rettv)
9899{
9900 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9901}
9902
9903/*
9904 * "searchpairpos()" function
9905 */
9906 static void
9907f_searchpairpos(typval_T *argvars, typval_T *rettv)
9908{
9909 pos_T match_pos;
9910 int lnum = 0;
9911 int col = 0;
9912
9913 if (rettv_list_alloc(rettv) == FAIL)
9914 return;
9915
9916 if (searchpair_cmn(argvars, &match_pos) > 0)
9917 {
9918 lnum = match_pos.lnum;
9919 col = match_pos.col;
9920 }
9921
9922 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9923 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9924}
9925
9926/*
9927 * Search for a start/middle/end thing.
9928 * Used by searchpair(), see its documentation for the details.
9929 * Returns 0 or -1 for no match,
9930 */
9931 long
9932do_searchpair(
9933 char_u *spat, /* start pattern */
9934 char_u *mpat, /* middle pattern */
9935 char_u *epat, /* end pattern */
9936 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009937 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938 int flags, /* SP_SETPCMARK and other SP_ values */
9939 pos_T *match_pos,
9940 linenr_T lnum_stop, /* stop at this line if not zero */
9941 long time_limit UNUSED) /* stop after this many msec */
9942{
9943 char_u *save_cpo;
9944 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9945 long retval = 0;
9946 pos_T pos;
9947 pos_T firstpos;
9948 pos_T foundpos;
9949 pos_T save_cursor;
9950 pos_T save_pos;
9951 int n;
9952 int r;
9953 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009954 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 int err;
9956 int options = SEARCH_KEEP;
9957 proftime_T tm;
9958
9959 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9960 save_cpo = p_cpo;
9961 p_cpo = empty_option;
9962
9963#ifdef FEAT_RELTIME
9964 /* Set the time limit, if there is one. */
9965 profile_setlimit(time_limit, &tm);
9966#endif
9967
9968 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9969 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009970 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9971 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009972 if (pat2 == NULL || pat3 == NULL)
9973 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009974 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009975 if (*mpat == NUL)
9976 STRCPY(pat3, pat2);
9977 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009978 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009979 spat, epat, mpat);
9980 if (flags & SP_START)
9981 options |= SEARCH_START;
9982
Bram Moolenaar48570482017-10-30 21:48:41 +01009983 if (skip != NULL)
9984 {
9985 /* Empty string means to not use the skip expression. */
9986 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9987 use_skip = skip->vval.v_string != NULL
9988 && *skip->vval.v_string != NUL;
9989 }
9990
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009991 save_cursor = curwin->w_cursor;
9992 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009993 CLEAR_POS(&firstpos);
9994 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009995 pat = pat3;
9996 for (;;)
9997 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009998 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009999 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010000 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010001 /* didn't find it or found the first match again: FAIL */
10002 break;
10003
10004 if (firstpos.lnum == 0)
10005 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010006 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010007 {
10008 /* Found the same position again. Can happen with a pattern that
10009 * has "\zs" at the end and searching backwards. Advance one
10010 * character and try again. */
10011 if (dir == BACKWARD)
10012 decl(&pos);
10013 else
10014 incl(&pos);
10015 }
10016 foundpos = pos;
10017
10018 /* clear the start flag to avoid getting stuck here */
10019 options &= ~SEARCH_START;
10020
10021 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010022 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010023 {
10024 save_pos = curwin->w_cursor;
10025 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010026 err = FALSE;
10027 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010028 curwin->w_cursor = save_pos;
10029 if (err)
10030 {
10031 /* Evaluating {skip} caused an error, break here. */
10032 curwin->w_cursor = save_cursor;
10033 retval = -1;
10034 break;
10035 }
10036 if (r)
10037 continue;
10038 }
10039
10040 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10041 {
10042 /* Found end when searching backwards or start when searching
10043 * forward: nested pair. */
10044 ++nest;
10045 pat = pat2; /* nested, don't search for middle */
10046 }
10047 else
10048 {
10049 /* Found end when searching forward or start when searching
10050 * backward: end of (nested) pair; or found middle in outer pair. */
10051 if (--nest == 1)
10052 pat = pat3; /* outer level, search for middle */
10053 }
10054
10055 if (nest == 0)
10056 {
10057 /* Found the match: return matchcount or line number. */
10058 if (flags & SP_RETCOUNT)
10059 ++retval;
10060 else
10061 retval = pos.lnum;
10062 if (flags & SP_SETPCMARK)
10063 setpcmark();
10064 curwin->w_cursor = pos;
10065 if (!(flags & SP_REPEAT))
10066 break;
10067 nest = 1; /* search for next unmatched */
10068 }
10069 }
10070
10071 if (match_pos != NULL)
10072 {
10073 /* Store the match cursor position */
10074 match_pos->lnum = curwin->w_cursor.lnum;
10075 match_pos->col = curwin->w_cursor.col + 1;
10076 }
10077
10078 /* If 'n' flag is used or search failed: restore cursor position. */
10079 if ((flags & SP_NOMOVE) || retval == 0)
10080 curwin->w_cursor = save_cursor;
10081
10082theend:
10083 vim_free(pat2);
10084 vim_free(pat3);
10085 if (p_cpo == empty_option)
10086 p_cpo = save_cpo;
10087 else
10088 /* Darn, evaluating the {skip} expression changed the value. */
10089 free_string_option(save_cpo);
10090
10091 return retval;
10092}
10093
10094/*
10095 * "searchpos()" function
10096 */
10097 static void
10098f_searchpos(typval_T *argvars, typval_T *rettv)
10099{
10100 pos_T match_pos;
10101 int lnum = 0;
10102 int col = 0;
10103 int n;
10104 int flags = 0;
10105
10106 if (rettv_list_alloc(rettv) == FAIL)
10107 return;
10108
10109 n = search_cmn(argvars, &match_pos, &flags);
10110 if (n > 0)
10111 {
10112 lnum = match_pos.lnum;
10113 col = match_pos.col;
10114 }
10115
10116 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10117 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10118 if (flags & SP_SUBPAT)
10119 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10120}
10121
10122 static void
10123f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10124{
10125#ifdef FEAT_CLIENTSERVER
10126 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010127 char_u *server = tv_get_string_chk(&argvars[0]);
10128 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010129
10130 rettv->vval.v_number = -1;
10131 if (server == NULL || reply == NULL)
10132 return;
10133 if (check_restricted() || check_secure())
10134 return;
10135# ifdef FEAT_X11
10136 if (check_connection() == FAIL)
10137 return;
10138# endif
10139
10140 if (serverSendReply(server, reply) < 0)
10141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010142 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010143 return;
10144 }
10145 rettv->vval.v_number = 0;
10146#else
10147 rettv->vval.v_number = -1;
10148#endif
10149}
10150
10151 static void
10152f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10153{
10154 char_u *r = NULL;
10155
10156#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010157# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010158 r = serverGetVimNames();
10159# else
10160 make_connection();
10161 if (X_DISPLAY != NULL)
10162 r = serverGetVimNames(X_DISPLAY);
10163# endif
10164#endif
10165 rettv->v_type = VAR_STRING;
10166 rettv->vval.v_string = r;
10167}
10168
10169/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010170 * "setbufline()" function
10171 */
10172 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010173f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010174{
10175 linenr_T lnum;
10176 buf_T *buf;
10177
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010178 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010179 if (buf == NULL)
10180 rettv->vval.v_number = 1; /* FAIL */
10181 else
10182 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010183 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010184 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010185 }
10186}
10187
10188/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010189 * "setbufvar()" function
10190 */
10191 static void
10192f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10193{
10194 buf_T *buf;
10195 char_u *varname, *bufvarname;
10196 typval_T *varp;
10197 char_u nbuf[NUMBUFLEN];
10198
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010199 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010200 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010201 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10202 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010203 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010204 varp = &argvars[2];
10205
10206 if (buf != NULL && varname != NULL && varp != NULL)
10207 {
10208 if (*varname == '&')
10209 {
10210 long numval;
10211 char_u *strval;
10212 int error = FALSE;
10213 aco_save_T aco;
10214
10215 /* set curbuf to be our buf, temporarily */
10216 aucmd_prepbuf(&aco, buf);
10217
10218 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010219 numval = (long)tv_get_number_chk(varp, &error);
10220 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010221 if (!error && strval != NULL)
10222 set_option_value(varname, numval, strval, OPT_LOCAL);
10223
10224 /* reset notion of buffer */
10225 aucmd_restbuf(&aco);
10226 }
10227 else
10228 {
10229 buf_T *save_curbuf = curbuf;
10230
Bram Moolenaar964b3742019-05-24 18:54:09 +020010231 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010232 if (bufvarname != NULL)
10233 {
10234 curbuf = buf;
10235 STRCPY(bufvarname, "b:");
10236 STRCPY(bufvarname + 2, varname);
10237 set_var(bufvarname, varp, TRUE);
10238 vim_free(bufvarname);
10239 curbuf = save_curbuf;
10240 }
10241 }
10242 }
10243}
10244
10245 static void
10246f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10247{
10248 dict_T *d;
10249 dictitem_T *di;
10250 char_u *csearch;
10251
10252 if (argvars[0].v_type != VAR_DICT)
10253 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010254 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010255 return;
10256 }
10257
10258 if ((d = argvars[0].vval.v_dict) != NULL)
10259 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010260 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010261 if (csearch != NULL)
10262 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010263 if (enc_utf8)
10264 {
10265 int pcc[MAX_MCO];
10266 int c = utfc_ptr2char(csearch, pcc);
10267
10268 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10269 }
10270 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 set_last_csearch(PTR2CHAR(csearch),
10272 csearch, MB_PTR2LEN(csearch));
10273 }
10274
10275 di = dict_find(d, (char_u *)"forward", -1);
10276 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010277 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010278 ? FORWARD : BACKWARD);
10279
10280 di = dict_find(d, (char_u *)"until", -1);
10281 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010282 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010283 }
10284}
10285
10286/*
10287 * "setcmdpos()" function
10288 */
10289 static void
10290f_setcmdpos(typval_T *argvars, typval_T *rettv)
10291{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010292 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010293
10294 if (pos >= 0)
10295 rettv->vval.v_number = set_cmdline_pos(pos);
10296}
10297
10298/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010299 * "setenv()" function
10300 */
10301 static void
10302f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10303{
10304 char_u namebuf[NUMBUFLEN];
10305 char_u valbuf[NUMBUFLEN];
10306 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10307
10308 if (argvars[1].v_type == VAR_SPECIAL
10309 && argvars[1].vval.v_number == VVAL_NULL)
10310 vim_unsetenv(name);
10311 else
10312 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10313}
10314
10315/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010316 * "setfperm({fname}, {mode})" function
10317 */
10318 static void
10319f_setfperm(typval_T *argvars, typval_T *rettv)
10320{
10321 char_u *fname;
10322 char_u modebuf[NUMBUFLEN];
10323 char_u *mode_str;
10324 int i;
10325 int mask;
10326 int mode = 0;
10327
10328 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010329 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010330 if (fname == NULL)
10331 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010332 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010333 if (mode_str == NULL)
10334 return;
10335 if (STRLEN(mode_str) != 9)
10336 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010337 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010338 return;
10339 }
10340
10341 mask = 1;
10342 for (i = 8; i >= 0; --i)
10343 {
10344 if (mode_str[i] != '-')
10345 mode |= mask;
10346 mask = mask << 1;
10347 }
10348 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10349}
10350
10351/*
10352 * "setline()" function
10353 */
10354 static void
10355f_setline(typval_T *argvars, typval_T *rettv)
10356{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010357 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010358
Bram Moolenaarca851592018-06-06 21:04:07 +020010359 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010360}
10361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010362/*
10363 * Used by "setqflist()" and "setloclist()" functions
10364 */
10365 static void
10366set_qf_ll_list(
10367 win_T *wp UNUSED,
10368 typval_T *list_arg UNUSED,
10369 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010370 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010371 typval_T *rettv)
10372{
10373#ifdef FEAT_QUICKFIX
10374 static char *e_invact = N_("E927: Invalid action: '%s'");
10375 char_u *act;
10376 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010377 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010378#endif
10379
10380 rettv->vval.v_number = -1;
10381
10382#ifdef FEAT_QUICKFIX
10383 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010384 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010385 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010386 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010387 else
10388 {
10389 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010390 dict_T *d = NULL;
10391 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010392
10393 if (action_arg->v_type == VAR_STRING)
10394 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010395 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396 if (act == NULL)
10397 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010398 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10399 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400 action = *act;
10401 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010402 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010403 }
10404 else if (action_arg->v_type == VAR_UNKNOWN)
10405 action = ' ';
10406 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010407 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010408
Bram Moolenaard823fa92016-08-12 16:29:27 +020010409 if (action_arg->v_type != VAR_UNKNOWN
10410 && what_arg->v_type != VAR_UNKNOWN)
10411 {
10412 if (what_arg->v_type == VAR_DICT)
10413 d = what_arg->vval.v_dict;
10414 else
10415 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010416 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010417 valid_dict = FALSE;
10418 }
10419 }
10420
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010421 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010422 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010423 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10424 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010425 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010426 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010427 }
10428#endif
10429}
10430
10431/*
10432 * "setloclist()" function
10433 */
10434 static void
10435f_setloclist(typval_T *argvars, typval_T *rettv)
10436{
10437 win_T *win;
10438
10439 rettv->vval.v_number = -1;
10440
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010441 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010442 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010443 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010444}
10445
10446/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447 * "setpos()" function
10448 */
10449 static void
10450f_setpos(typval_T *argvars, typval_T *rettv)
10451{
10452 pos_T pos;
10453 int fnum;
10454 char_u *name;
10455 colnr_T curswant = -1;
10456
10457 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010458 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010459 if (name != NULL)
10460 {
10461 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10462 {
10463 if (--pos.col < 0)
10464 pos.col = 0;
10465 if (name[0] == '.' && name[1] == NUL)
10466 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010467 /* set cursor; "fnum" is ignored */
10468 curwin->w_cursor = pos;
10469 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010470 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010471 curwin->w_curswant = curswant - 1;
10472 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010473 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010474 check_cursor();
10475 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010476 }
10477 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10478 {
10479 /* set mark */
10480 if (setmark_pos(name[1], &pos, fnum) == OK)
10481 rettv->vval.v_number = 0;
10482 }
10483 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010484 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010485 }
10486 }
10487}
10488
10489/*
10490 * "setqflist()" function
10491 */
10492 static void
10493f_setqflist(typval_T *argvars, typval_T *rettv)
10494{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010495 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010496}
10497
10498/*
10499 * "setreg()" function
10500 */
10501 static void
10502f_setreg(typval_T *argvars, typval_T *rettv)
10503{
10504 int regname;
10505 char_u *strregname;
10506 char_u *stropt;
10507 char_u *strval;
10508 int append;
10509 char_u yank_type;
10510 long block_len;
10511
10512 block_len = -1;
10513 yank_type = MAUTO;
10514 append = FALSE;
10515
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010516 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010517 rettv->vval.v_number = 1; /* FAIL is default */
10518
10519 if (strregname == NULL)
10520 return; /* type error; errmsg already given */
10521 regname = *strregname;
10522 if (regname == 0 || regname == '@')
10523 regname = '"';
10524
10525 if (argvars[2].v_type != VAR_UNKNOWN)
10526 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010527 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010528 if (stropt == NULL)
10529 return; /* type error */
10530 for (; *stropt != NUL; ++stropt)
10531 switch (*stropt)
10532 {
10533 case 'a': case 'A': /* append */
10534 append = TRUE;
10535 break;
10536 case 'v': case 'c': /* character-wise selection */
10537 yank_type = MCHAR;
10538 break;
10539 case 'V': case 'l': /* line-wise selection */
10540 yank_type = MLINE;
10541 break;
10542 case 'b': case Ctrl_V: /* block-wise selection */
10543 yank_type = MBLOCK;
10544 if (VIM_ISDIGIT(stropt[1]))
10545 {
10546 ++stropt;
10547 block_len = getdigits(&stropt) - 1;
10548 --stropt;
10549 }
10550 break;
10551 }
10552 }
10553
10554 if (argvars[1].v_type == VAR_LIST)
10555 {
10556 char_u **lstval;
10557 char_u **allocval;
10558 char_u buf[NUMBUFLEN];
10559 char_u **curval;
10560 char_u **curallocval;
10561 list_T *ll = argvars[1].vval.v_list;
10562 listitem_T *li;
10563 int len;
10564
10565 /* If the list is NULL handle like an empty list. */
10566 len = ll == NULL ? 0 : ll->lv_len;
10567
10568 /* First half: use for pointers to result lines; second half: use for
10569 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010570 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010571 if (lstval == NULL)
10572 return;
10573 curval = lstval;
10574 allocval = lstval + len + 2;
10575 curallocval = allocval;
10576
10577 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10578 li = li->li_next)
10579 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010580 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010581 if (strval == NULL)
10582 goto free_lstval;
10583 if (strval == buf)
10584 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010585 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010586 * overwrite the string. */
10587 strval = vim_strsave(buf);
10588 if (strval == NULL)
10589 goto free_lstval;
10590 *curallocval++ = strval;
10591 }
10592 *curval++ = strval;
10593 }
10594 *curval++ = NULL;
10595
10596 write_reg_contents_lst(regname, lstval, -1,
10597 append, yank_type, block_len);
10598free_lstval:
10599 while (curallocval > allocval)
10600 vim_free(*--curallocval);
10601 vim_free(lstval);
10602 }
10603 else
10604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010605 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010606 if (strval == NULL)
10607 return;
10608 write_reg_contents_ex(regname, strval, -1,
10609 append, yank_type, block_len);
10610 }
10611 rettv->vval.v_number = 0;
10612}
10613
10614/*
10615 * "settabvar()" function
10616 */
10617 static void
10618f_settabvar(typval_T *argvars, typval_T *rettv)
10619{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010620 tabpage_T *save_curtab;
10621 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010622 char_u *varname, *tabvarname;
10623 typval_T *varp;
10624
10625 rettv->vval.v_number = 0;
10626
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010627 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010628 return;
10629
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010630 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10631 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 varp = &argvars[2];
10633
Bram Moolenaar4033c552017-09-16 20:54:51 +020010634 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010635 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636 save_curtab = curtab;
10637 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010638
Bram Moolenaar964b3742019-05-24 18:54:09 +020010639 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010640 if (tabvarname != NULL)
10641 {
10642 STRCPY(tabvarname, "t:");
10643 STRCPY(tabvarname + 2, varname);
10644 set_var(tabvarname, varp, TRUE);
10645 vim_free(tabvarname);
10646 }
10647
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648 /* Restore current tabpage */
10649 if (valid_tabpage(save_curtab))
10650 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010651 }
10652}
10653
10654/*
10655 * "settabwinvar()" function
10656 */
10657 static void
10658f_settabwinvar(typval_T *argvars, typval_T *rettv)
10659{
10660 setwinvar(argvars, rettv, 1);
10661}
10662
10663/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010664 * "settagstack()" function
10665 */
10666 static void
10667f_settagstack(typval_T *argvars, typval_T *rettv)
10668{
10669 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10670 win_T *wp;
10671 dict_T *d;
10672 int action = 'r';
10673
10674 rettv->vval.v_number = -1;
10675
10676 // first argument: window number or id
10677 wp = find_win_by_nr_or_id(&argvars[0]);
10678 if (wp == NULL)
10679 return;
10680
10681 // second argument: dict with items to set in the tag stack
10682 if (argvars[1].v_type != VAR_DICT)
10683 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010684 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010685 return;
10686 }
10687 d = argvars[1].vval.v_dict;
10688 if (d == NULL)
10689 return;
10690
10691 // third argument: action - 'a' for append and 'r' for replace.
10692 // default is to replace the stack.
10693 if (argvars[2].v_type == VAR_UNKNOWN)
10694 action = 'r';
10695 else if (argvars[2].v_type == VAR_STRING)
10696 {
10697 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010698 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010699 if (actstr == NULL)
10700 return;
10701 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10702 action = *actstr;
10703 else
10704 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010705 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010706 return;
10707 }
10708 }
10709 else
10710 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010711 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010712 return;
10713 }
10714
10715 if (set_tagstack(wp, d, action) == OK)
10716 rettv->vval.v_number = 0;
10717}
10718
10719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010720 * "setwinvar()" function
10721 */
10722 static void
10723f_setwinvar(typval_T *argvars, typval_T *rettv)
10724{
10725 setwinvar(argvars, rettv, 0);
10726}
10727
10728#ifdef FEAT_CRYPT
10729/*
10730 * "sha256({string})" function
10731 */
10732 static void
10733f_sha256(typval_T *argvars, typval_T *rettv)
10734{
10735 char_u *p;
10736
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010737 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010738 rettv->vval.v_string = vim_strsave(
10739 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10740 rettv->v_type = VAR_STRING;
10741}
10742#endif /* FEAT_CRYPT */
10743
10744/*
10745 * "shellescape({string})" function
10746 */
10747 static void
10748f_shellescape(typval_T *argvars, typval_T *rettv)
10749{
Bram Moolenaar20615522017-06-05 18:46:26 +020010750 int do_special = non_zero_arg(&argvars[1]);
10751
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010752 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010753 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010754 rettv->v_type = VAR_STRING;
10755}
10756
10757/*
10758 * shiftwidth() function
10759 */
10760 static void
10761f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10762{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010763 rettv->vval.v_number = 0;
10764
10765 if (argvars[0].v_type != VAR_UNKNOWN)
10766 {
10767 long col;
10768
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010769 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010770 if (col < 0)
10771 return; // type error; errmsg already given
10772#ifdef FEAT_VARTABS
10773 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10774 return;
10775#endif
10776 }
10777
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010778 rettv->vval.v_number = get_sw_value(curbuf);
10779}
10780
10781/*
10782 * "simplify()" function
10783 */
10784 static void
10785f_simplify(typval_T *argvars, typval_T *rettv)
10786{
10787 char_u *p;
10788
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010789 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010790 rettv->vval.v_string = vim_strsave(p);
10791 simplify_filename(rettv->vval.v_string); /* simplify in place */
10792 rettv->v_type = VAR_STRING;
10793}
10794
10795#ifdef FEAT_FLOAT
10796/*
10797 * "sin()" function
10798 */
10799 static void
10800f_sin(typval_T *argvars, typval_T *rettv)
10801{
10802 float_T f = 0.0;
10803
10804 rettv->v_type = VAR_FLOAT;
10805 if (get_float_arg(argvars, &f) == OK)
10806 rettv->vval.v_float = sin(f);
10807 else
10808 rettv->vval.v_float = 0.0;
10809}
10810
10811/*
10812 * "sinh()" function
10813 */
10814 static void
10815f_sinh(typval_T *argvars, typval_T *rettv)
10816{
10817 float_T f = 0.0;
10818
10819 rettv->v_type = VAR_FLOAT;
10820 if (get_float_arg(argvars, &f) == OK)
10821 rettv->vval.v_float = sinh(f);
10822 else
10823 rettv->vval.v_float = 0.0;
10824}
10825#endif
10826
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010827/*
10828 * "soundfold({word})" function
10829 */
10830 static void
10831f_soundfold(typval_T *argvars, typval_T *rettv)
10832{
10833 char_u *s;
10834
10835 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010836 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837#ifdef FEAT_SPELL
10838 rettv->vval.v_string = eval_soundfold(s);
10839#else
10840 rettv->vval.v_string = vim_strsave(s);
10841#endif
10842}
10843
10844/*
10845 * "spellbadword()" function
10846 */
10847 static void
10848f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10849{
10850 char_u *word = (char_u *)"";
10851 hlf_T attr = HLF_COUNT;
10852 int len = 0;
10853
10854 if (rettv_list_alloc(rettv) == FAIL)
10855 return;
10856
10857#ifdef FEAT_SPELL
10858 if (argvars[0].v_type == VAR_UNKNOWN)
10859 {
10860 /* Find the start and length of the badly spelled word. */
10861 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10862 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010863 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010864 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010865 curwin->w_set_curswant = TRUE;
10866 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010867 }
10868 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10869 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010870 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010871 int capcol = -1;
10872
10873 if (str != NULL)
10874 {
10875 /* Check the argument for spelling. */
10876 while (*str != NUL)
10877 {
10878 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10879 if (attr != HLF_COUNT)
10880 {
10881 word = str;
10882 break;
10883 }
10884 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010885 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010886 }
10887 }
10888 }
10889#endif
10890
10891 list_append_string(rettv->vval.v_list, word, len);
10892 list_append_string(rettv->vval.v_list, (char_u *)(
10893 attr == HLF_SPB ? "bad" :
10894 attr == HLF_SPR ? "rare" :
10895 attr == HLF_SPL ? "local" :
10896 attr == HLF_SPC ? "caps" :
10897 ""), -1);
10898}
10899
10900/*
10901 * "spellsuggest()" function
10902 */
10903 static void
10904f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10905{
10906#ifdef FEAT_SPELL
10907 char_u *str;
10908 int typeerr = FALSE;
10909 int maxcount;
10910 garray_T ga;
10911 int i;
10912 listitem_T *li;
10913 int need_capital = FALSE;
10914#endif
10915
10916 if (rettv_list_alloc(rettv) == FAIL)
10917 return;
10918
10919#ifdef FEAT_SPELL
10920 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010922 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010923 if (argvars[1].v_type != VAR_UNKNOWN)
10924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010925 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926 if (maxcount <= 0)
10927 return;
10928 if (argvars[2].v_type != VAR_UNKNOWN)
10929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010930 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931 if (typeerr)
10932 return;
10933 }
10934 }
10935 else
10936 maxcount = 25;
10937
10938 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10939
10940 for (i = 0; i < ga.ga_len; ++i)
10941 {
10942 str = ((char_u **)ga.ga_data)[i];
10943
10944 li = listitem_alloc();
10945 if (li == NULL)
10946 vim_free(str);
10947 else
10948 {
10949 li->li_tv.v_type = VAR_STRING;
10950 li->li_tv.v_lock = 0;
10951 li->li_tv.vval.v_string = str;
10952 list_append(rettv->vval.v_list, li);
10953 }
10954 }
10955 ga_clear(&ga);
10956 }
10957#endif
10958}
10959
10960 static void
10961f_split(typval_T *argvars, typval_T *rettv)
10962{
10963 char_u *str;
10964 char_u *end;
10965 char_u *pat = NULL;
10966 regmatch_T regmatch;
10967 char_u patbuf[NUMBUFLEN];
10968 char_u *save_cpo;
10969 int match;
10970 colnr_T col = 0;
10971 int keepempty = FALSE;
10972 int typeerr = FALSE;
10973
10974 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10975 save_cpo = p_cpo;
10976 p_cpo = (char_u *)"";
10977
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010978 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 if (argvars[1].v_type != VAR_UNKNOWN)
10980 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010981 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010982 if (pat == NULL)
10983 typeerr = TRUE;
10984 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010985 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010986 }
10987 if (pat == NULL || *pat == NUL)
10988 pat = (char_u *)"[\\x01- ]\\+";
10989
10990 if (rettv_list_alloc(rettv) == FAIL)
10991 return;
10992 if (typeerr)
10993 return;
10994
10995 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10996 if (regmatch.regprog != NULL)
10997 {
10998 regmatch.rm_ic = FALSE;
10999 while (*str != NUL || keepempty)
11000 {
11001 if (*str == NUL)
11002 match = FALSE; /* empty item at the end */
11003 else
11004 match = vim_regexec_nl(&regmatch, str, col);
11005 if (match)
11006 end = regmatch.startp[0];
11007 else
11008 end = str + STRLEN(str);
11009 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11010 && *str != NUL && match && end < regmatch.endp[0]))
11011 {
11012 if (list_append_string(rettv->vval.v_list, str,
11013 (int)(end - str)) == FAIL)
11014 break;
11015 }
11016 if (!match)
11017 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011018 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011019 if (regmatch.endp[0] > str)
11020 col = 0;
11021 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011022 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011023 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011024 str = regmatch.endp[0];
11025 }
11026
11027 vim_regfree(regmatch.regprog);
11028 }
11029
11030 p_cpo = save_cpo;
11031}
11032
11033#ifdef FEAT_FLOAT
11034/*
11035 * "sqrt()" function
11036 */
11037 static void
11038f_sqrt(typval_T *argvars, typval_T *rettv)
11039{
11040 float_T f = 0.0;
11041
11042 rettv->v_type = VAR_FLOAT;
11043 if (get_float_arg(argvars, &f) == OK)
11044 rettv->vval.v_float = sqrt(f);
11045 else
11046 rettv->vval.v_float = 0.0;
11047}
11048
11049/*
11050 * "str2float()" function
11051 */
11052 static void
11053f_str2float(typval_T *argvars, typval_T *rettv)
11054{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011055 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011056 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011057
Bram Moolenaar08243d22017-01-10 16:12:29 +010011058 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 p = skipwhite(p + 1);
11060 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011061 if (isneg)
11062 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 rettv->v_type = VAR_FLOAT;
11064}
11065#endif
11066
11067/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011068 * "str2list()" function
11069 */
11070 static void
11071f_str2list(typval_T *argvars, typval_T *rettv)
11072{
11073 char_u *p;
11074 int utf8 = FALSE;
11075
11076 if (rettv_list_alloc(rettv) == FAIL)
11077 return;
11078
11079 if (argvars[1].v_type != VAR_UNKNOWN)
11080 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11081
11082 p = tv_get_string(&argvars[0]);
11083
11084 if (has_mbyte || utf8)
11085 {
11086 int (*ptr2len)(char_u *);
11087 int (*ptr2char)(char_u *);
11088
11089 if (utf8 || enc_utf8)
11090 {
11091 ptr2len = utf_ptr2len;
11092 ptr2char = utf_ptr2char;
11093 }
11094 else
11095 {
11096 ptr2len = mb_ptr2len;
11097 ptr2char = mb_ptr2char;
11098 }
11099
11100 for ( ; *p != NUL; p += (*ptr2len)(p))
11101 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11102 }
11103 else
11104 for ( ; *p != NUL; ++p)
11105 list_append_number(rettv->vval.v_list, *p);
11106}
11107
11108/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011109 * "str2nr()" function
11110 */
11111 static void
11112f_str2nr(typval_T *argvars, typval_T *rettv)
11113{
11114 int base = 10;
11115 char_u *p;
11116 varnumber_T n;
11117 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011118 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011119
11120 if (argvars[1].v_type != VAR_UNKNOWN)
11121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011122 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011123 if (base != 2 && base != 8 && base != 10 && base != 16)
11124 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011125 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011126 return;
11127 }
11128 }
11129
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011130 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011131 isneg = (*p == '-');
11132 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011133 p = skipwhite(p + 1);
11134 switch (base)
11135 {
11136 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11137 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11138 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11139 default: what = 0;
11140 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011141 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11142 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011143 if (isneg)
11144 rettv->vval.v_number = -n;
11145 else
11146 rettv->vval.v_number = n;
11147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011148}
11149
11150#ifdef HAVE_STRFTIME
11151/*
11152 * "strftime({format}[, {time}])" function
11153 */
11154 static void
11155f_strftime(typval_T *argvars, typval_T *rettv)
11156{
11157 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011158 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011159 struct tm *curtime;
11160 time_t seconds;
11161 char_u *p;
11162
11163 rettv->v_type = VAR_STRING;
11164
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011165 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011166 if (argvars[1].v_type == VAR_UNKNOWN)
11167 seconds = time(NULL);
11168 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011169 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011170 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011171 /* MSVC returns NULL for an invalid value of seconds. */
11172 if (curtime == NULL)
11173 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11174 else
11175 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011176 vimconv_T conv;
11177 char_u *enc;
11178
11179 conv.vc_type = CONV_NONE;
11180 enc = enc_locale();
11181 convert_setup(&conv, p_enc, enc);
11182 if (conv.vc_type != CONV_NONE)
11183 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011184 if (p != NULL)
11185 (void)strftime((char *)result_buf, sizeof(result_buf),
11186 (char *)p, curtime);
11187 else
11188 result_buf[0] = NUL;
11189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011190 if (conv.vc_type != CONV_NONE)
11191 vim_free(p);
11192 convert_setup(&conv, enc, p_enc);
11193 if (conv.vc_type != CONV_NONE)
11194 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11195 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011196 rettv->vval.v_string = vim_strsave(result_buf);
11197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011198 /* Release conversion descriptors */
11199 convert_setup(&conv, NULL, NULL);
11200 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011201 }
11202}
11203#endif
11204
11205/*
11206 * "strgetchar()" function
11207 */
11208 static void
11209f_strgetchar(typval_T *argvars, typval_T *rettv)
11210{
11211 char_u *str;
11212 int len;
11213 int error = FALSE;
11214 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011215 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011216
11217 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011218 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011219 if (str == NULL)
11220 return;
11221 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011222 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011223 if (error)
11224 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011225
Bram Moolenaar13505972019-01-24 15:04:48 +010011226 while (charidx >= 0 && byteidx < len)
11227 {
11228 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011230 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11231 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011232 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011233 --charidx;
11234 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011235 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236}
11237
11238/*
11239 * "stridx()" function
11240 */
11241 static void
11242f_stridx(typval_T *argvars, typval_T *rettv)
11243{
11244 char_u buf[NUMBUFLEN];
11245 char_u *needle;
11246 char_u *haystack;
11247 char_u *save_haystack;
11248 char_u *pos;
11249 int start_idx;
11250
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011251 needle = tv_get_string_chk(&argvars[1]);
11252 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253 rettv->vval.v_number = -1;
11254 if (needle == NULL || haystack == NULL)
11255 return; /* type error; errmsg already given */
11256
11257 if (argvars[2].v_type != VAR_UNKNOWN)
11258 {
11259 int error = FALSE;
11260
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011261 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011262 if (error || start_idx >= (int)STRLEN(haystack))
11263 return;
11264 if (start_idx >= 0)
11265 haystack += start_idx;
11266 }
11267
11268 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11269 if (pos != NULL)
11270 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11271}
11272
11273/*
11274 * "string()" function
11275 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011276 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011277f_string(typval_T *argvars, typval_T *rettv)
11278{
11279 char_u *tofree;
11280 char_u numbuf[NUMBUFLEN];
11281
11282 rettv->v_type = VAR_STRING;
11283 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11284 get_copyID());
11285 /* Make a copy if we have a value but it's not in allocated memory. */
11286 if (rettv->vval.v_string != NULL && tofree == NULL)
11287 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11288}
11289
11290/*
11291 * "strlen()" function
11292 */
11293 static void
11294f_strlen(typval_T *argvars, typval_T *rettv)
11295{
11296 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011297 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011298}
11299
11300/*
11301 * "strchars()" function
11302 */
11303 static void
11304f_strchars(typval_T *argvars, typval_T *rettv)
11305{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011306 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011307 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011308 varnumber_T len = 0;
11309 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011310
11311 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011312 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011313 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011314 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011315 else
11316 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11318 while (*s != NUL)
11319 {
11320 func_mb_ptr2char_adv(&s);
11321 ++len;
11322 }
11323 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011324 }
11325}
11326
11327/*
11328 * "strdisplaywidth()" function
11329 */
11330 static void
11331f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11332{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011333 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011334 int col = 0;
11335
11336 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011337 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011338
11339 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11340}
11341
11342/*
11343 * "strwidth()" function
11344 */
11345 static void
11346f_strwidth(typval_T *argvars, typval_T *rettv)
11347{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011348 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011349
Bram Moolenaar13505972019-01-24 15:04:48 +010011350 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011351}
11352
11353/*
11354 * "strcharpart()" function
11355 */
11356 static void
11357f_strcharpart(typval_T *argvars, typval_T *rettv)
11358{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011359 char_u *p;
11360 int nchar;
11361 int nbyte = 0;
11362 int charlen;
11363 int len = 0;
11364 int slen;
11365 int error = FALSE;
11366
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011367 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011368 slen = (int)STRLEN(p);
11369
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011370 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011371 if (!error)
11372 {
11373 if (nchar > 0)
11374 while (nchar > 0 && nbyte < slen)
11375 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011376 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011377 --nchar;
11378 }
11379 else
11380 nbyte = nchar;
11381 if (argvars[2].v_type != VAR_UNKNOWN)
11382 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011383 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384 while (charlen > 0 && nbyte + len < slen)
11385 {
11386 int off = nbyte + len;
11387
11388 if (off < 0)
11389 len += 1;
11390 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011391 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011392 --charlen;
11393 }
11394 }
11395 else
11396 len = slen - nbyte; /* default: all bytes that are available. */
11397 }
11398
11399 /*
11400 * Only return the overlap between the specified part and the actual
11401 * string.
11402 */
11403 if (nbyte < 0)
11404 {
11405 len += nbyte;
11406 nbyte = 0;
11407 }
11408 else if (nbyte > slen)
11409 nbyte = slen;
11410 if (len < 0)
11411 len = 0;
11412 else if (nbyte + len > slen)
11413 len = slen - nbyte;
11414
11415 rettv->v_type = VAR_STRING;
11416 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011417}
11418
11419/*
11420 * "strpart()" function
11421 */
11422 static void
11423f_strpart(typval_T *argvars, typval_T *rettv)
11424{
11425 char_u *p;
11426 int n;
11427 int len;
11428 int slen;
11429 int error = FALSE;
11430
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011431 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011432 slen = (int)STRLEN(p);
11433
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011434 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011435 if (error)
11436 len = 0;
11437 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011438 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011439 else
11440 len = slen - n; /* default len: all bytes that are available. */
11441
11442 /*
11443 * Only return the overlap between the specified part and the actual
11444 * string.
11445 */
11446 if (n < 0)
11447 {
11448 len += n;
11449 n = 0;
11450 }
11451 else if (n > slen)
11452 n = slen;
11453 if (len < 0)
11454 len = 0;
11455 else if (n + len > slen)
11456 len = slen - n;
11457
11458 rettv->v_type = VAR_STRING;
11459 rettv->vval.v_string = vim_strnsave(p + n, len);
11460}
11461
11462/*
11463 * "strridx()" function
11464 */
11465 static void
11466f_strridx(typval_T *argvars, typval_T *rettv)
11467{
11468 char_u buf[NUMBUFLEN];
11469 char_u *needle;
11470 char_u *haystack;
11471 char_u *rest;
11472 char_u *lastmatch = NULL;
11473 int haystack_len, end_idx;
11474
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011475 needle = tv_get_string_chk(&argvars[1]);
11476 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011477
11478 rettv->vval.v_number = -1;
11479 if (needle == NULL || haystack == NULL)
11480 return; /* type error; errmsg already given */
11481
11482 haystack_len = (int)STRLEN(haystack);
11483 if (argvars[2].v_type != VAR_UNKNOWN)
11484 {
11485 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011486 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011487 if (end_idx < 0)
11488 return; /* can never find a match */
11489 }
11490 else
11491 end_idx = haystack_len;
11492
11493 if (*needle == NUL)
11494 {
11495 /* Empty string matches past the end. */
11496 lastmatch = haystack + end_idx;
11497 }
11498 else
11499 {
11500 for (rest = haystack; *rest != '\0'; ++rest)
11501 {
11502 rest = (char_u *)strstr((char *)rest, (char *)needle);
11503 if (rest == NULL || rest > haystack + end_idx)
11504 break;
11505 lastmatch = rest;
11506 }
11507 }
11508
11509 if (lastmatch == NULL)
11510 rettv->vval.v_number = -1;
11511 else
11512 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11513}
11514
11515/*
11516 * "strtrans()" function
11517 */
11518 static void
11519f_strtrans(typval_T *argvars, typval_T *rettv)
11520{
11521 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011522 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011523}
11524
11525/*
11526 * "submatch()" function
11527 */
11528 static void
11529f_submatch(typval_T *argvars, typval_T *rettv)
11530{
11531 int error = FALSE;
11532 int no;
11533 int retList = 0;
11534
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011535 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011536 if (error)
11537 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011538 if (no < 0 || no >= NSUBEXP)
11539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011540 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011541 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011543 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011544 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011545 if (error)
11546 return;
11547
11548 if (retList == 0)
11549 {
11550 rettv->v_type = VAR_STRING;
11551 rettv->vval.v_string = reg_submatch(no);
11552 }
11553 else
11554 {
11555 rettv->v_type = VAR_LIST;
11556 rettv->vval.v_list = reg_submatch_list(no);
11557 }
11558}
11559
11560/*
11561 * "substitute()" function
11562 */
11563 static void
11564f_substitute(typval_T *argvars, typval_T *rettv)
11565{
11566 char_u patbuf[NUMBUFLEN];
11567 char_u subbuf[NUMBUFLEN];
11568 char_u flagsbuf[NUMBUFLEN];
11569
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011570 char_u *str = tv_get_string_chk(&argvars[0]);
11571 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011572 char_u *sub = NULL;
11573 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011574 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011575
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011576 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11577 expr = &argvars[2];
11578 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011579 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011580
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011581 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011582 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11583 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011584 rettv->vval.v_string = NULL;
11585 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011586 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011587}
11588
11589/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011590 * "swapinfo(swap_filename)" function
11591 */
11592 static void
11593f_swapinfo(typval_T *argvars, typval_T *rettv)
11594{
11595 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011596 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011597}
11598
11599/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011600 * "swapname(expr)" function
11601 */
11602 static void
11603f_swapname(typval_T *argvars, typval_T *rettv)
11604{
11605 buf_T *buf;
11606
11607 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011608 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011609 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11610 || buf->b_ml.ml_mfp->mf_fname == NULL)
11611 rettv->vval.v_string = NULL;
11612 else
11613 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11614}
11615
11616/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011617 * "synID(lnum, col, trans)" function
11618 */
11619 static void
11620f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11621{
11622 int id = 0;
11623#ifdef FEAT_SYN_HL
11624 linenr_T lnum;
11625 colnr_T col;
11626 int trans;
11627 int transerr = FALSE;
11628
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011629 lnum = tv_get_lnum(argvars); /* -1 on type error */
11630 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11631 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011632
11633 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11634 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11635 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11636#endif
11637
11638 rettv->vval.v_number = id;
11639}
11640
11641/*
11642 * "synIDattr(id, what [, mode])" function
11643 */
11644 static void
11645f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11646{
11647 char_u *p = NULL;
11648#ifdef FEAT_SYN_HL
11649 int id;
11650 char_u *what;
11651 char_u *mode;
11652 char_u modebuf[NUMBUFLEN];
11653 int modec;
11654
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011655 id = (int)tv_get_number(&argvars[0]);
11656 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011657 if (argvars[2].v_type != VAR_UNKNOWN)
11658 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011659 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011660 modec = TOLOWER_ASC(mode[0]);
11661 if (modec != 't' && modec != 'c' && modec != 'g')
11662 modec = 0; /* replace invalid with current */
11663 }
11664 else
11665 {
11666#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11667 if (USE_24BIT)
11668 modec = 'g';
11669 else
11670#endif
11671 if (t_colors > 1)
11672 modec = 'c';
11673 else
11674 modec = 't';
11675 }
11676
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011677 switch (TOLOWER_ASC(what[0]))
11678 {
11679 case 'b':
11680 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11681 p = highlight_color(id, what, modec);
11682 else /* bold */
11683 p = highlight_has_attr(id, HL_BOLD, modec);
11684 break;
11685
11686 case 'f': /* fg[#] or font */
11687 p = highlight_color(id, what, modec);
11688 break;
11689
11690 case 'i':
11691 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11692 p = highlight_has_attr(id, HL_INVERSE, modec);
11693 else /* italic */
11694 p = highlight_has_attr(id, HL_ITALIC, modec);
11695 break;
11696
11697 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011698 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011699 break;
11700
11701 case 'r': /* reverse */
11702 p = highlight_has_attr(id, HL_INVERSE, modec);
11703 break;
11704
11705 case 's':
11706 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11707 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011708 /* strikeout */
11709 else if (TOLOWER_ASC(what[1]) == 't' &&
11710 TOLOWER_ASC(what[2]) == 'r')
11711 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011712 else /* standout */
11713 p = highlight_has_attr(id, HL_STANDOUT, modec);
11714 break;
11715
11716 case 'u':
11717 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11718 /* underline */
11719 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11720 else
11721 /* undercurl */
11722 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11723 break;
11724 }
11725
11726 if (p != NULL)
11727 p = vim_strsave(p);
11728#endif
11729 rettv->v_type = VAR_STRING;
11730 rettv->vval.v_string = p;
11731}
11732
11733/*
11734 * "synIDtrans(id)" function
11735 */
11736 static void
11737f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11738{
11739 int id;
11740
11741#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011742 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011743
11744 if (id > 0)
11745 id = syn_get_final_id(id);
11746 else
11747#endif
11748 id = 0;
11749
11750 rettv->vval.v_number = id;
11751}
11752
11753/*
11754 * "synconcealed(lnum, col)" function
11755 */
11756 static void
11757f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11758{
11759#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11760 linenr_T lnum;
11761 colnr_T col;
11762 int syntax_flags = 0;
11763 int cchar;
11764 int matchid = 0;
11765 char_u str[NUMBUFLEN];
11766#endif
11767
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011768 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011769
11770#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011771 lnum = tv_get_lnum(argvars); /* -1 on type error */
11772 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011773
11774 vim_memset(str, NUL, sizeof(str));
11775
11776 if (rettv_list_alloc(rettv) != FAIL)
11777 {
11778 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11779 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11780 && curwin->w_p_cole > 0)
11781 {
11782 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11783 syntax_flags = get_syntax_info(&matchid);
11784
11785 /* get the conceal character */
11786 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11787 {
11788 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011789 if (cchar == NUL && curwin->w_p_cole == 1)
11790 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011791 if (cchar != NUL)
11792 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011793 if (has_mbyte)
11794 (*mb_char2bytes)(cchar, str);
11795 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011796 str[0] = cchar;
11797 }
11798 }
11799 }
11800
11801 list_append_number(rettv->vval.v_list,
11802 (syntax_flags & HL_CONCEAL) != 0);
11803 /* -1 to auto-determine strlen */
11804 list_append_string(rettv->vval.v_list, str, -1);
11805 list_append_number(rettv->vval.v_list, matchid);
11806 }
11807#endif
11808}
11809
11810/*
11811 * "synstack(lnum, col)" function
11812 */
11813 static void
11814f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11815{
11816#ifdef FEAT_SYN_HL
11817 linenr_T lnum;
11818 colnr_T col;
11819 int i;
11820 int id;
11821#endif
11822
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011823 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011824
11825#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011826 lnum = tv_get_lnum(argvars); /* -1 on type error */
11827 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011828
11829 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11830 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11831 && rettv_list_alloc(rettv) != FAIL)
11832 {
11833 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11834 for (i = 0; ; ++i)
11835 {
11836 id = syn_get_stack_item(i);
11837 if (id < 0)
11838 break;
11839 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11840 break;
11841 }
11842 }
11843#endif
11844}
11845
11846 static void
11847get_cmd_output_as_rettv(
11848 typval_T *argvars,
11849 typval_T *rettv,
11850 int retlist)
11851{
11852 char_u *res = NULL;
11853 char_u *p;
11854 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011855 int err = FALSE;
11856 FILE *fd;
11857 list_T *list = NULL;
11858 int flags = SHELL_SILENT;
11859
11860 rettv->v_type = VAR_STRING;
11861 rettv->vval.v_string = NULL;
11862 if (check_restricted() || check_secure())
11863 goto errret;
11864
11865 if (argvars[1].v_type != VAR_UNKNOWN)
11866 {
11867 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011868 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011869 * command.
11870 */
11871 if ((infile = vim_tempname('i', TRUE)) == NULL)
11872 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011873 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011874 goto errret;
11875 }
11876
11877 fd = mch_fopen((char *)infile, WRITEBIN);
11878 if (fd == NULL)
11879 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011880 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011881 goto errret;
11882 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011883 if (argvars[1].v_type == VAR_NUMBER)
11884 {
11885 linenr_T lnum;
11886 buf_T *buf;
11887
11888 buf = buflist_findnr(argvars[1].vval.v_number);
11889 if (buf == NULL)
11890 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011891 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011892 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011893 goto errret;
11894 }
11895
11896 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11897 {
11898 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11899 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11900 {
11901 err = TRUE;
11902 break;
11903 }
11904 if (putc(NL, fd) == EOF)
11905 {
11906 err = TRUE;
11907 break;
11908 }
11909 }
11910 }
11911 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011912 {
11913 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11914 err = TRUE;
11915 }
11916 else
11917 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011918 size_t len;
11919 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011920
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011921 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011922 if (p == NULL)
11923 {
11924 fclose(fd);
11925 goto errret; /* type error; errmsg already given */
11926 }
11927 len = STRLEN(p);
11928 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11929 err = TRUE;
11930 }
11931 if (fclose(fd) != 0)
11932 err = TRUE;
11933 if (err)
11934 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011935 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011936 goto errret;
11937 }
11938 }
11939
11940 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11941 * echoes typeahead, that messes up the display. */
11942 if (!msg_silent)
11943 flags += SHELL_COOKED;
11944
11945 if (retlist)
11946 {
11947 int len;
11948 listitem_T *li;
11949 char_u *s = NULL;
11950 char_u *start;
11951 char_u *end;
11952 int i;
11953
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011954 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011955 if (res == NULL)
11956 goto errret;
11957
11958 list = list_alloc();
11959 if (list == NULL)
11960 goto errret;
11961
11962 for (i = 0; i < len; ++i)
11963 {
11964 start = res + i;
11965 while (i < len && res[i] != NL)
11966 ++i;
11967 end = res + i;
11968
Bram Moolenaar964b3742019-05-24 18:54:09 +020011969 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011970 if (s == NULL)
11971 goto errret;
11972
11973 for (p = s; start < end; ++p, ++start)
11974 *p = *start == NUL ? NL : *start;
11975 *p = NUL;
11976
11977 li = listitem_alloc();
11978 if (li == NULL)
11979 {
11980 vim_free(s);
11981 goto errret;
11982 }
11983 li->li_tv.v_type = VAR_STRING;
11984 li->li_tv.v_lock = 0;
11985 li->li_tv.vval.v_string = s;
11986 list_append(list, li);
11987 }
11988
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011989 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011990 list = NULL;
11991 }
11992 else
11993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011994 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011995#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011996 /* translate <CR><NL> into <NL> */
11997 if (res != NULL)
11998 {
11999 char_u *s, *d;
12000
12001 d = res;
12002 for (s = res; *s; ++s)
12003 {
12004 if (s[0] == CAR && s[1] == NL)
12005 ++s;
12006 *d++ = *s;
12007 }
12008 *d = NUL;
12009 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012010#endif
12011 rettv->vval.v_string = res;
12012 res = NULL;
12013 }
12014
12015errret:
12016 if (infile != NULL)
12017 {
12018 mch_remove(infile);
12019 vim_free(infile);
12020 }
12021 if (res != NULL)
12022 vim_free(res);
12023 if (list != NULL)
12024 list_free(list);
12025}
12026
12027/*
12028 * "system()" function
12029 */
12030 static void
12031f_system(typval_T *argvars, typval_T *rettv)
12032{
12033 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12034}
12035
12036/*
12037 * "systemlist()" function
12038 */
12039 static void
12040f_systemlist(typval_T *argvars, typval_T *rettv)
12041{
12042 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12043}
12044
12045/*
12046 * "tabpagebuflist()" function
12047 */
12048 static void
12049f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12050{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012051 tabpage_T *tp;
12052 win_T *wp = NULL;
12053
12054 if (argvars[0].v_type == VAR_UNKNOWN)
12055 wp = firstwin;
12056 else
12057 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012058 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012059 if (tp != NULL)
12060 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12061 }
12062 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12063 {
12064 for (; wp != NULL; wp = wp->w_next)
12065 if (list_append_number(rettv->vval.v_list,
12066 wp->w_buffer->b_fnum) == FAIL)
12067 break;
12068 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012069}
12070
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012071/*
12072 * "tabpagenr()" function
12073 */
12074 static void
12075f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12076{
12077 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012078 char_u *arg;
12079
12080 if (argvars[0].v_type != VAR_UNKNOWN)
12081 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012082 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012083 nr = 0;
12084 if (arg != NULL)
12085 {
12086 if (STRCMP(arg, "$") == 0)
12087 nr = tabpage_index(NULL) - 1;
12088 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012089 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012090 }
12091 }
12092 else
12093 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012094 rettv->vval.v_number = nr;
12095}
12096
12097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012098/*
12099 * Common code for tabpagewinnr() and winnr().
12100 */
12101 static int
12102get_winnr(tabpage_T *tp, typval_T *argvar)
12103{
12104 win_T *twin;
12105 int nr = 1;
12106 win_T *wp;
12107 char_u *arg;
12108
12109 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12110 if (argvar->v_type != VAR_UNKNOWN)
12111 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012112 int invalid_arg = FALSE;
12113
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012114 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012115 if (arg == NULL)
12116 nr = 0; /* type error; errmsg already given */
12117 else if (STRCMP(arg, "$") == 0)
12118 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12119 else if (STRCMP(arg, "#") == 0)
12120 {
12121 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12122 if (twin == NULL)
12123 nr = 0;
12124 }
12125 else
12126 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012127 long count;
12128 char_u *endp;
12129
12130 // Extract the window count (if specified). e.g. winnr('3j')
12131 count = strtol((char *)arg, (char **)&endp, 10);
12132 if (count <= 0)
12133 count = 1; // if count is not specified, default to 1
12134 if (endp != NULL && *endp != '\0')
12135 {
12136 if (STRCMP(endp, "j") == 0)
12137 twin = win_vert_neighbor(tp, twin, FALSE, count);
12138 else if (STRCMP(endp, "k") == 0)
12139 twin = win_vert_neighbor(tp, twin, TRUE, count);
12140 else if (STRCMP(endp, "h") == 0)
12141 twin = win_horz_neighbor(tp, twin, TRUE, count);
12142 else if (STRCMP(endp, "l") == 0)
12143 twin = win_horz_neighbor(tp, twin, FALSE, count);
12144 else
12145 invalid_arg = TRUE;
12146 }
12147 else
12148 invalid_arg = TRUE;
12149 }
12150
12151 if (invalid_arg)
12152 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012153 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012154 nr = 0;
12155 }
12156 }
12157
12158 if (nr > 0)
12159 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12160 wp != twin; wp = wp->w_next)
12161 {
12162 if (wp == NULL)
12163 {
12164 /* didn't find it in this tabpage */
12165 nr = 0;
12166 break;
12167 }
12168 ++nr;
12169 }
12170 return nr;
12171}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012172
12173/*
12174 * "tabpagewinnr()" function
12175 */
12176 static void
12177f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12178{
12179 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012180 tabpage_T *tp;
12181
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012182 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012183 if (tp == NULL)
12184 nr = 0;
12185 else
12186 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012187 rettv->vval.v_number = nr;
12188}
12189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190/*
12191 * "tagfiles()" function
12192 */
12193 static void
12194f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12195{
12196 char_u *fname;
12197 tagname_T tn;
12198 int first;
12199
12200 if (rettv_list_alloc(rettv) == FAIL)
12201 return;
12202 fname = alloc(MAXPATHL);
12203 if (fname == NULL)
12204 return;
12205
12206 for (first = TRUE; ; first = FALSE)
12207 if (get_tagfname(&tn, first, fname) == FAIL
12208 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12209 break;
12210 tagname_free(&tn);
12211 vim_free(fname);
12212}
12213
12214/*
12215 * "taglist()" function
12216 */
12217 static void
12218f_taglist(typval_T *argvars, typval_T *rettv)
12219{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012220 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012221 char_u *tag_pattern;
12222
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012223 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012224
12225 rettv->vval.v_number = FALSE;
12226 if (*tag_pattern == NUL)
12227 return;
12228
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012229 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012230 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012231 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012232 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012233}
12234
12235/*
12236 * "tempname()" function
12237 */
12238 static void
12239f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12240{
12241 static int x = 'A';
12242
12243 rettv->v_type = VAR_STRING;
12244 rettv->vval.v_string = vim_tempname(x, FALSE);
12245
12246 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12247 * names. Skip 'I' and 'O', they are used for shell redirection. */
12248 do
12249 {
12250 if (x == 'Z')
12251 x = '0';
12252 else if (x == '9')
12253 x = 'A';
12254 else
12255 {
12256#ifdef EBCDIC
12257 if (x == 'I')
12258 x = 'J';
12259 else if (x == 'R')
12260 x = 'S';
12261 else
12262#endif
12263 ++x;
12264 }
12265 } while (x == 'I' || x == 'O');
12266}
12267
12268#ifdef FEAT_FLOAT
12269/*
12270 * "tan()" function
12271 */
12272 static void
12273f_tan(typval_T *argvars, typval_T *rettv)
12274{
12275 float_T f = 0.0;
12276
12277 rettv->v_type = VAR_FLOAT;
12278 if (get_float_arg(argvars, &f) == OK)
12279 rettv->vval.v_float = tan(f);
12280 else
12281 rettv->vval.v_float = 0.0;
12282}
12283
12284/*
12285 * "tanh()" function
12286 */
12287 static void
12288f_tanh(typval_T *argvars, typval_T *rettv)
12289{
12290 float_T f = 0.0;
12291
12292 rettv->v_type = VAR_FLOAT;
12293 if (get_float_arg(argvars, &f) == OK)
12294 rettv->vval.v_float = tanh(f);
12295 else
12296 rettv->vval.v_float = 0.0;
12297}
12298#endif
12299
12300/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012301 * Get a callback from "arg". It can be a Funcref or a function name.
12302 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012303 * "cb_name" is not allocated.
12304 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012305 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012306 callback_T
12307get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012308{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012309 callback_T res;
12310
12311 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012312 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12313 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012314 res.cb_partial = arg->vval.v_partial;
12315 ++res.cb_partial->pt_refcount;
12316 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012317 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012318 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012319 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012320 res.cb_partial = NULL;
12321 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12322 {
12323 // Note that we don't make a copy of the string.
12324 res.cb_name = arg->vval.v_string;
12325 func_ref(res.cb_name);
12326 }
12327 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12328 {
12329 res.cb_name = (char_u *)"";
12330 }
12331 else
12332 {
12333 emsg(_("E921: Invalid callback argument"));
12334 res.cb_name = NULL;
12335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012337 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012338}
12339
12340/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012341 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012342 */
12343 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012344put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012345{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012346 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012347 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012348 tv->v_type = VAR_PARTIAL;
12349 tv->vval.v_partial = cb->cb_partial;
12350 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012351 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012352 else
12353 {
12354 tv->v_type = VAR_FUNC;
12355 tv->vval.v_string = vim_strsave(cb->cb_name);
12356 func_ref(cb->cb_name);
12357 }
12358}
12359
12360/*
12361 * Make a copy of "src" into "dest", allocating the function name if needed,
12362 * without incrementing the refcount.
12363 */
12364 void
12365set_callback(callback_T *dest, callback_T *src)
12366{
12367 if (src->cb_partial == NULL)
12368 {
12369 // just a function name, make a copy
12370 dest->cb_name = vim_strsave(src->cb_name);
12371 dest->cb_free_name = TRUE;
12372 }
12373 else
12374 {
12375 // cb_name is a pointer into cb_partial
12376 dest->cb_name = src->cb_name;
12377 dest->cb_free_name = FALSE;
12378 }
12379 dest->cb_partial = src->cb_partial;
12380}
12381
12382/*
12383 * Unref/free "callback" returned by get_callback() or set_callback().
12384 */
12385 void
12386free_callback(callback_T *callback)
12387{
12388 if (callback->cb_partial != NULL)
12389 {
12390 partial_unref(callback->cb_partial);
12391 callback->cb_partial = NULL;
12392 }
12393 else if (callback->cb_name != NULL)
12394 func_unref(callback->cb_name);
12395 if (callback->cb_free_name)
12396 {
12397 vim_free(callback->cb_name);
12398 callback->cb_free_name = FALSE;
12399 }
12400 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012401}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012402
12403#ifdef FEAT_TIMERS
12404/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012405 * "timer_info([timer])" function
12406 */
12407 static void
12408f_timer_info(typval_T *argvars, typval_T *rettv)
12409{
12410 timer_T *timer = NULL;
12411
12412 if (rettv_list_alloc(rettv) != OK)
12413 return;
12414 if (argvars[0].v_type != VAR_UNKNOWN)
12415 {
12416 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012417 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012418 else
12419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012420 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012421 if (timer != NULL)
12422 add_timer_info(rettv, timer);
12423 }
12424 }
12425 else
12426 add_timer_info_all(rettv);
12427}
12428
12429/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012430 * "timer_pause(timer, paused)" function
12431 */
12432 static void
12433f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12434{
12435 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012436 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012437
12438 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012439 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012440 else
12441 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012442 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012443 if (timer != NULL)
12444 timer->tr_paused = paused;
12445 }
12446}
12447
12448/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012449 * "timer_start(time, callback [, options])" function
12450 */
12451 static void
12452f_timer_start(typval_T *argvars, typval_T *rettv)
12453{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012454 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012455 timer_T *timer;
12456 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012457 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012458 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459
Bram Moolenaar75537a92016-09-05 22:45:28 +020012460 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461 if (check_secure())
12462 return;
12463 if (argvars[2].v_type != VAR_UNKNOWN)
12464 {
12465 if (argvars[2].v_type != VAR_DICT
12466 || (dict = argvars[2].vval.v_dict) == NULL)
12467 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012468 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012469 return;
12470 }
12471 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012472 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012473 }
12474
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012475 callback = get_callback(&argvars[1]);
12476 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012477 return;
12478
12479 timer = create_timer(msec, repeat);
12480 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012481 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012482 else
12483 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012484 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012485 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012486 }
12487}
12488
12489/*
12490 * "timer_stop(timer)" function
12491 */
12492 static void
12493f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12494{
12495 timer_T *timer;
12496
12497 if (argvars[0].v_type != VAR_NUMBER)
12498 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012499 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012500 return;
12501 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012502 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012503 if (timer != NULL)
12504 stop_timer(timer);
12505}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012506
12507/*
12508 * "timer_stopall()" function
12509 */
12510 static void
12511f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12512{
12513 stop_all_timers();
12514}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012515#endif
12516
12517/*
12518 * "tolower(string)" function
12519 */
12520 static void
12521f_tolower(typval_T *argvars, typval_T *rettv)
12522{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012523 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012524 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012525}
12526
12527/*
12528 * "toupper(string)" function
12529 */
12530 static void
12531f_toupper(typval_T *argvars, typval_T *rettv)
12532{
12533 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012534 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012535}
12536
12537/*
12538 * "tr(string, fromstr, tostr)" function
12539 */
12540 static void
12541f_tr(typval_T *argvars, typval_T *rettv)
12542{
12543 char_u *in_str;
12544 char_u *fromstr;
12545 char_u *tostr;
12546 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012547 int inlen;
12548 int fromlen;
12549 int tolen;
12550 int idx;
12551 char_u *cpstr;
12552 int cplen;
12553 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012554 char_u buf[NUMBUFLEN];
12555 char_u buf2[NUMBUFLEN];
12556 garray_T ga;
12557
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012558 in_str = tv_get_string(&argvars[0]);
12559 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12560 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012561
12562 /* Default return value: empty string. */
12563 rettv->v_type = VAR_STRING;
12564 rettv->vval.v_string = NULL;
12565 if (fromstr == NULL || tostr == NULL)
12566 return; /* type error; errmsg already given */
12567 ga_init2(&ga, (int)sizeof(char), 80);
12568
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012569 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012570 /* not multi-byte: fromstr and tostr must be the same length */
12571 if (STRLEN(fromstr) != STRLEN(tostr))
12572 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012573error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012574 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575 ga_clear(&ga);
12576 return;
12577 }
12578
12579 /* fromstr and tostr have to contain the same number of chars */
12580 while (*in_str != NUL)
12581 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012582 if (has_mbyte)
12583 {
12584 inlen = (*mb_ptr2len)(in_str);
12585 cpstr = in_str;
12586 cplen = inlen;
12587 idx = 0;
12588 for (p = fromstr; *p != NUL; p += fromlen)
12589 {
12590 fromlen = (*mb_ptr2len)(p);
12591 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12592 {
12593 for (p = tostr; *p != NUL; p += tolen)
12594 {
12595 tolen = (*mb_ptr2len)(p);
12596 if (idx-- == 0)
12597 {
12598 cplen = tolen;
12599 cpstr = p;
12600 break;
12601 }
12602 }
12603 if (*p == NUL) /* tostr is shorter than fromstr */
12604 goto error;
12605 break;
12606 }
12607 ++idx;
12608 }
12609
12610 if (first && cpstr == in_str)
12611 {
12612 /* Check that fromstr and tostr have the same number of
12613 * (multi-byte) characters. Done only once when a character
12614 * of in_str doesn't appear in fromstr. */
12615 first = FALSE;
12616 for (p = tostr; *p != NUL; p += tolen)
12617 {
12618 tolen = (*mb_ptr2len)(p);
12619 --idx;
12620 }
12621 if (idx != 0)
12622 goto error;
12623 }
12624
12625 (void)ga_grow(&ga, cplen);
12626 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12627 ga.ga_len += cplen;
12628
12629 in_str += inlen;
12630 }
12631 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012632 {
12633 /* When not using multi-byte chars we can do it faster. */
12634 p = vim_strchr(fromstr, *in_str);
12635 if (p != NULL)
12636 ga_append(&ga, tostr[p - fromstr]);
12637 else
12638 ga_append(&ga, *in_str);
12639 ++in_str;
12640 }
12641 }
12642
12643 /* add a terminating NUL */
12644 (void)ga_grow(&ga, 1);
12645 ga_append(&ga, NUL);
12646
12647 rettv->vval.v_string = ga.ga_data;
12648}
12649
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012650/*
12651 * "trim({expr})" function
12652 */
12653 static void
12654f_trim(typval_T *argvars, typval_T *rettv)
12655{
12656 char_u buf1[NUMBUFLEN];
12657 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012658 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012659 char_u *mask = NULL;
12660 char_u *tail;
12661 char_u *prev;
12662 char_u *p;
12663 int c1;
12664
12665 rettv->v_type = VAR_STRING;
12666 if (head == NULL)
12667 {
12668 rettv->vval.v_string = NULL;
12669 return;
12670 }
12671
12672 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012673 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012674
12675 while (*head != NUL)
12676 {
12677 c1 = PTR2CHAR(head);
12678 if (mask == NULL)
12679 {
12680 if (c1 > ' ' && c1 != 0xa0)
12681 break;
12682 }
12683 else
12684 {
12685 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12686 if (c1 == PTR2CHAR(p))
12687 break;
12688 if (*p == NUL)
12689 break;
12690 }
12691 MB_PTR_ADV(head);
12692 }
12693
12694 for (tail = head + STRLEN(head); tail > head; tail = prev)
12695 {
12696 prev = tail;
12697 MB_PTR_BACK(head, prev);
12698 c1 = PTR2CHAR(prev);
12699 if (mask == NULL)
12700 {
12701 if (c1 > ' ' && c1 != 0xa0)
12702 break;
12703 }
12704 else
12705 {
12706 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12707 if (c1 == PTR2CHAR(p))
12708 break;
12709 if (*p == NUL)
12710 break;
12711 }
12712 }
12713 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12714}
12715
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012716#ifdef FEAT_FLOAT
12717/*
12718 * "trunc({float})" function
12719 */
12720 static void
12721f_trunc(typval_T *argvars, typval_T *rettv)
12722{
12723 float_T f = 0.0;
12724
12725 rettv->v_type = VAR_FLOAT;
12726 if (get_float_arg(argvars, &f) == OK)
12727 /* trunc() is not in C90, use floor() or ceil() instead. */
12728 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12729 else
12730 rettv->vval.v_float = 0.0;
12731}
12732#endif
12733
12734/*
12735 * "type(expr)" function
12736 */
12737 static void
12738f_type(typval_T *argvars, typval_T *rettv)
12739{
12740 int n = -1;
12741
12742 switch (argvars[0].v_type)
12743 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012744 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12745 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012746 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012747 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12748 case VAR_LIST: n = VAR_TYPE_LIST; break;
12749 case VAR_DICT: n = VAR_TYPE_DICT; break;
12750 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751 case VAR_SPECIAL:
12752 if (argvars[0].vval.v_number == VVAL_FALSE
12753 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012754 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012755 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012756 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012757 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012758 case VAR_JOB: n = VAR_TYPE_JOB; break;
12759 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012760 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012762 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012763 n = -1;
12764 break;
12765 }
12766 rettv->vval.v_number = n;
12767}
12768
12769/*
12770 * "undofile(name)" function
12771 */
12772 static void
12773f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12774{
12775 rettv->v_type = VAR_STRING;
12776#ifdef FEAT_PERSISTENT_UNDO
12777 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012778 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012779
12780 if (*fname == NUL)
12781 {
12782 /* If there is no file name there will be no undo file. */
12783 rettv->vval.v_string = NULL;
12784 }
12785 else
12786 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012787 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788
12789 if (ffname != NULL)
12790 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12791 vim_free(ffname);
12792 }
12793 }
12794#else
12795 rettv->vval.v_string = NULL;
12796#endif
12797}
12798
12799/*
12800 * "undotree()" function
12801 */
12802 static void
12803f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12804{
12805 if (rettv_dict_alloc(rettv) == OK)
12806 {
12807 dict_T *dict = rettv->vval.v_dict;
12808 list_T *list;
12809
Bram Moolenaare0be1672018-07-08 16:50:37 +020012810 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12811 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12812 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12813 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12814 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12815 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012816
12817 list = list_alloc();
12818 if (list != NULL)
12819 {
12820 u_eval_tree(curbuf->b_u_oldhead, list);
12821 dict_add_list(dict, "entries", list);
12822 }
12823 }
12824}
12825
12826/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012827 * "virtcol(string)" function
12828 */
12829 static void
12830f_virtcol(typval_T *argvars, typval_T *rettv)
12831{
12832 colnr_T vcol = 0;
12833 pos_T *fp;
12834 int fnum = curbuf->b_fnum;
12835
12836 fp = var2fpos(&argvars[0], FALSE, &fnum);
12837 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12838 && fnum == curbuf->b_fnum)
12839 {
12840 getvvcol(curwin, fp, NULL, NULL, &vcol);
12841 ++vcol;
12842 }
12843
12844 rettv->vval.v_number = vcol;
12845}
12846
12847/*
12848 * "visualmode()" function
12849 */
12850 static void
12851f_visualmode(typval_T *argvars, typval_T *rettv)
12852{
12853 char_u str[2];
12854
12855 rettv->v_type = VAR_STRING;
12856 str[0] = curbuf->b_visual_mode_eval;
12857 str[1] = NUL;
12858 rettv->vval.v_string = vim_strsave(str);
12859
12860 /* A non-zero number or non-empty string argument: reset mode. */
12861 if (non_zero_arg(&argvars[0]))
12862 curbuf->b_visual_mode_eval = NUL;
12863}
12864
12865/*
12866 * "wildmenumode()" function
12867 */
12868 static void
12869f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12870{
12871#ifdef FEAT_WILDMENU
12872 if (wild_menu_showing)
12873 rettv->vval.v_number = 1;
12874#endif
12875}
12876
12877/*
12878 * "winbufnr(nr)" function
12879 */
12880 static void
12881f_winbufnr(typval_T *argvars, typval_T *rettv)
12882{
12883 win_T *wp;
12884
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012885 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012886 if (wp == NULL)
12887 rettv->vval.v_number = -1;
12888 else
12889 rettv->vval.v_number = wp->w_buffer->b_fnum;
12890}
12891
12892/*
12893 * "wincol()" function
12894 */
12895 static void
12896f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12897{
12898 validate_cursor();
12899 rettv->vval.v_number = curwin->w_wcol + 1;
12900}
12901
12902/*
12903 * "winheight(nr)" function
12904 */
12905 static void
12906f_winheight(typval_T *argvars, typval_T *rettv)
12907{
12908 win_T *wp;
12909
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012910 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012911 if (wp == NULL)
12912 rettv->vval.v_number = -1;
12913 else
12914 rettv->vval.v_number = wp->w_height;
12915}
12916
12917/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012918 * "winlayout()" function
12919 */
12920 static void
12921f_winlayout(typval_T *argvars, typval_T *rettv)
12922{
12923 tabpage_T *tp;
12924
12925 if (rettv_list_alloc(rettv) != OK)
12926 return;
12927
12928 if (argvars[0].v_type == VAR_UNKNOWN)
12929 tp = curtab;
12930 else
12931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012932 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012933 if (tp == NULL)
12934 return;
12935 }
12936
12937 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12938}
12939
12940/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012941 * "winline()" function
12942 */
12943 static void
12944f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12945{
12946 validate_cursor();
12947 rettv->vval.v_number = curwin->w_wrow + 1;
12948}
12949
12950/*
12951 * "winnr()" function
12952 */
12953 static void
12954f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12955{
12956 int nr = 1;
12957
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012958 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012959 rettv->vval.v_number = nr;
12960}
12961
12962/*
12963 * "winrestcmd()" function
12964 */
12965 static void
12966f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12967{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012968 win_T *wp;
12969 int winnr = 1;
12970 garray_T ga;
12971 char_u buf[50];
12972
12973 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012974 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012975 {
12976 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12977 ga_concat(&ga, buf);
12978 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12979 ga_concat(&ga, buf);
12980 ++winnr;
12981 }
12982 ga_append(&ga, NUL);
12983
12984 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012985 rettv->v_type = VAR_STRING;
12986}
12987
12988/*
12989 * "winrestview()" function
12990 */
12991 static void
12992f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12993{
12994 dict_T *dict;
12995
12996 if (argvars[0].v_type != VAR_DICT
12997 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012998 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012999 else
13000 {
13001 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013002 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013003 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013004 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013005 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013006 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013007 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13008 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013009 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013010 curwin->w_set_curswant = FALSE;
13011 }
13012
13013 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013014 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013015#ifdef FEAT_DIFF
13016 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013017 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013018#endif
13019 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013020 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013021 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013022 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013023
13024 check_cursor();
13025 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013026 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013027 changed_window_setting();
13028
13029 if (curwin->w_topline <= 0)
13030 curwin->w_topline = 1;
13031 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13032 curwin->w_topline = curbuf->b_ml.ml_line_count;
13033#ifdef FEAT_DIFF
13034 check_topfill(curwin, TRUE);
13035#endif
13036 }
13037}
13038
13039/*
13040 * "winsaveview()" function
13041 */
13042 static void
13043f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13044{
13045 dict_T *dict;
13046
13047 if (rettv_dict_alloc(rettv) == FAIL)
13048 return;
13049 dict = rettv->vval.v_dict;
13050
Bram Moolenaare0be1672018-07-08 16:50:37 +020013051 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13052 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013053 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013054 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013055 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013056
Bram Moolenaare0be1672018-07-08 16:50:37 +020013057 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013059 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013060#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013061 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13062 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013063}
13064
13065/*
13066 * "winwidth(nr)" function
13067 */
13068 static void
13069f_winwidth(typval_T *argvars, typval_T *rettv)
13070{
13071 win_T *wp;
13072
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013073 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013074 if (wp == NULL)
13075 rettv->vval.v_number = -1;
13076 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013077 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078}
13079
13080/*
13081 * "wordcount()" function
13082 */
13083 static void
13084f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13085{
13086 if (rettv_dict_alloc(rettv) == FAIL)
13087 return;
13088 cursor_pos_info(rettv->vval.v_dict);
13089}
13090
13091/*
13092 * "writefile()" function
13093 */
13094 static void
13095f_writefile(typval_T *argvars, typval_T *rettv)
13096{
13097 int binary = FALSE;
13098 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013099#ifdef HAVE_FSYNC
13100 int do_fsync = p_fs;
13101#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013102 char_u *fname;
13103 FILE *fd;
13104 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013105 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013106 list_T *list = NULL;
13107 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013108
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013109 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013110 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013111 return;
13112
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013113 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013114 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013115 list = argvars[0].vval.v_list;
13116 if (list == NULL)
13117 return;
13118 for (li = list->lv_first; li != NULL; li = li->li_next)
13119 if (tv_get_string_chk(&li->li_tv) == NULL)
13120 return;
13121 }
13122 else if (argvars[0].v_type == VAR_BLOB)
13123 {
13124 blob = argvars[0].vval.v_blob;
13125 if (blob == NULL)
13126 return;
13127 }
13128 else
13129 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013130 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131 return;
13132 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013133
13134 if (argvars[2].v_type != VAR_UNKNOWN)
13135 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013136 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013137
13138 if (arg2 == NULL)
13139 return;
13140 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013141 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013142 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013143 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013144#ifdef HAVE_FSYNC
13145 if (vim_strchr(arg2, 's') != NULL)
13146 do_fsync = TRUE;
13147 else if (vim_strchr(arg2, 'S') != NULL)
13148 do_fsync = FALSE;
13149#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013150 }
13151
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013152 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013153 if (fname == NULL)
13154 return;
13155
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013156 /* Always open the file in binary mode, library functions have a mind of
13157 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013158 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13159 append ? APPENDBIN : WRITEBIN)) == NULL)
13160 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013161 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013162 ret = -1;
13163 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013164 else if (blob)
13165 {
13166 if (write_blob(fd, blob) == FAIL)
13167 ret = -1;
13168#ifdef HAVE_FSYNC
13169 else if (do_fsync)
13170 // Ignore the error, the user wouldn't know what to do about it.
13171 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013172 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013173#endif
13174 fclose(fd);
13175 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013176 else
13177 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013178 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013179 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013180#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013181 else if (do_fsync)
13182 /* Ignore the error, the user wouldn't know what to do about it.
13183 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013184 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013185#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 fclose(fd);
13187 }
13188
13189 rettv->vval.v_number = ret;
13190}
13191
13192/*
13193 * "xor(expr, expr)" function
13194 */
13195 static void
13196f_xor(typval_T *argvars, typval_T *rettv)
13197{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013198 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13199 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013200}
13201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013202#endif /* FEAT_EVAL */