blob: 3b7b901dac6e1191857120c429dbf141aae8a6a5 [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{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200417 char *f_name; // function name
418 char f_min_argc; // minimal number of arguments
419 char f_max_argc; // maximal number of arguments
420 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200422 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200423} funcentry_T;
424
425static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426{
427#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200428 {"abs", 1, 1, 0, f_abs},
429 {"acos", 1, 1, 0, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200431 {"add", 2, 2, 0, f_add},
432 {"and", 2, 2, 0, f_and},
433 {"append", 2, 2, 0, f_append},
434 {"appendbufline", 3, 3, 0, f_appendbufline},
435 {"argc", 0, 1, 0, f_argc},
436 {"argidx", 0, 0, 0, f_argidx},
437 {"arglistid", 0, 2, 0, f_arglistid},
438 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200440 {"asin", 1, 1, 0, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200442 {"assert_beeps", 1, 2, 0, f_assert_beeps},
443 {"assert_equal", 2, 3, 0, f_assert_equal},
444 {"assert_equalfile", 2, 2, 0, f_assert_equalfile},
445 {"assert_exception", 1, 2, 0, f_assert_exception},
446 {"assert_fails", 1, 3, 0, f_assert_fails},
447 {"assert_false", 1, 2, 0, f_assert_false},
448 {"assert_inrange", 3, 4, 0, f_assert_inrange},
449 {"assert_match", 2, 3, 0, f_assert_match},
450 {"assert_notequal", 2, 3, 0, f_assert_notequal},
451 {"assert_notmatch", 2, 3, 0, f_assert_notmatch},
452 {"assert_report", 1, 1, 0, f_assert_report},
453 {"assert_true", 1, 2, 0, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200454#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200455 {"atan", 1, 1, 0, f_atan},
456 {"atan2", 2, 2, 0, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100458#ifdef FEAT_BEVAL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200459 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
460 {"balloon_show", 1, 1, 0, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100461# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200462 {"balloon_split", 1, 1, 0, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100463# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100464#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200465 {"browse", 4, 4, 0, f_browse},
466 {"browsedir", 2, 2, 0, f_browsedir},
467 {"bufadd", 1, 1, 0, f_bufadd},
468 {"bufexists", 1, 1, 0, f_bufexists},
469 {"buffer_exists", 1, 1, 0, f_bufexists}, // obsolete
470 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
471 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
472 {"buflisted", 1, 1, 0, f_buflisted},
473 {"bufload", 1, 1, 0, f_bufload},
474 {"bufloaded", 1, 1, 0, f_bufloaded},
475 {"bufname", 1, 1, 0, f_bufname},
476 {"bufnr", 1, 2, 0, f_bufnr},
477 {"bufwinid", 1, 1, 0, f_bufwinid},
478 {"bufwinnr", 1, 1, 0, f_bufwinnr},
479 {"byte2line", 1, 1, 0, f_byte2line},
480 {"byteidx", 2, 2, 0, f_byteidx},
481 {"byteidxcomp", 2, 2, 0, f_byteidxcomp},
482 {"call", 2, 3, 0, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200483#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200484 {"ceil", 1, 1, 0, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485#endif
486#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200487 {"ch_canread", 1, 1, 0, f_ch_canread},
488 {"ch_close", 1, 1, 0, f_ch_close},
489 {"ch_close_in", 1, 1, 0, f_ch_close_in},
490 {"ch_evalexpr", 2, 3, 0, f_ch_evalexpr},
491 {"ch_evalraw", 2, 3, 0, f_ch_evalraw},
492 {"ch_getbufnr", 2, 2, 0, f_ch_getbufnr},
493 {"ch_getjob", 1, 1, 0, f_ch_getjob},
494 {"ch_info", 1, 1, 0, f_ch_info},
495 {"ch_log", 1, 2, 0, f_ch_log},
496 {"ch_logfile", 1, 2, 0, f_ch_logfile},
497 {"ch_open", 1, 2, 0, f_ch_open},
498 {"ch_read", 1, 2, 0, f_ch_read},
499 {"ch_readblob", 1, 2, 0, f_ch_readblob},
500 {"ch_readraw", 1, 2, 0, f_ch_readraw},
501 {"ch_sendexpr", 2, 3, 0, f_ch_sendexpr},
502 {"ch_sendraw", 2, 3, 0, f_ch_sendraw},
503 {"ch_setoptions", 2, 2, 0, f_ch_setoptions},
504 {"ch_status", 1, 2, 0, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200506 {"changenr", 0, 0, 0, f_changenr},
507 {"char2nr", 1, 2, 0, f_char2nr},
508 {"chdir", 1, 1, 0, f_chdir},
509 {"cindent", 1, 1, 0, f_cindent},
510 {"clearmatches", 0, 1, 0, f_clearmatches},
511 {"col", 1, 1, 0, f_col},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512#if defined(FEAT_INS_EXPAND)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200513 {"complete", 2, 2, 0, f_complete},
514 {"complete_add", 1, 1, 0, f_complete_add},
515 {"complete_check", 0, 0, 0, f_complete_check},
516 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200518 {"confirm", 1, 4, 0, f_confirm},
519 {"copy", 1, 1, 0, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200521 {"cos", 1, 1, 0, f_cos},
522 {"cosh", 1, 1, 0, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200524 {"count", 2, 4, 0, f_count},
525 {"cscope_connection",0,3, 0, f_cscope_connection},
526 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100527#ifdef MSWIN
Bram Moolenaar25e42232019-08-04 15:04:10 +0200528 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200529#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200530 {"deepcopy", 1, 2, 0, f_deepcopy},
531 {"delete", 1, 2, 0, f_delete},
532 {"deletebufline", 2, 3, 0, f_deletebufline},
533 {"did_filetype", 0, 0, 0, f_did_filetype},
534 {"diff_filler", 1, 1, 0, f_diff_filler},
535 {"diff_hlID", 2, 2, 0, f_diff_hlID},
536 {"empty", 1, 1, 0, f_empty},
537 {"environ", 0, 0, 0, f_environ},
538 {"escape", 2, 2, 0, f_escape},
539 {"eval", 1, 1, 0, f_eval},
540 {"eventhandler", 0, 0, 0, f_eventhandler},
541 {"executable", 1, 1, 0, f_executable},
542 {"execute", 1, 2, 0, f_execute},
543 {"exepath", 1, 1, 0, f_exepath},
544 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200546 {"exp", 1, 1, 0, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200548 {"expand", 1, 3, 0, f_expand},
549 {"expandcmd", 1, 1, 0, f_expandcmd},
550 {"extend", 2, 3, 0, f_extend},
551 {"feedkeys", 1, 2, 0, f_feedkeys},
552 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
553 {"filereadable", 1, 1, 0, f_filereadable},
554 {"filewritable", 1, 1, 0, f_filewritable},
555 {"filter", 2, 2, 0, f_filter},
556 {"finddir", 1, 3, 0, f_finddir},
557 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200559 {"float2nr", 1, 1, 0, f_float2nr},
560 {"floor", 1, 1, 0, f_floor},
561 {"fmod", 2, 2, 0, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200562#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200563 {"fnameescape", 1, 1, 0, f_fnameescape},
564 {"fnamemodify", 2, 2, 0, f_fnamemodify},
565 {"foldclosed", 1, 1, 0, f_foldclosed},
566 {"foldclosedend", 1, 1, 0, f_foldclosedend},
567 {"foldlevel", 1, 1, 0, f_foldlevel},
568 {"foldtext", 0, 0, 0, f_foldtext},
569 {"foldtextresult", 1, 1, 0, f_foldtextresult},
570 {"foreground", 0, 0, 0, f_foreground},
571 {"funcref", 1, 3, 0, f_funcref},
572 {"function", 1, 3, 0, f_function},
573 {"garbagecollect", 0, 1, 0, f_garbagecollect},
574 {"get", 2, 3, 0, f_get},
575 {"getbufinfo", 0, 1, 0, f_getbufinfo},
576 {"getbufline", 2, 3, 0, f_getbufline},
577 {"getbufvar", 2, 3, 0, f_getbufvar},
578 {"getchangelist", 1, 1, 0, f_getchangelist},
579 {"getchar", 0, 1, 0, f_getchar},
580 {"getcharmod", 0, 0, 0, f_getcharmod},
581 {"getcharsearch", 0, 0, 0, f_getcharsearch},
582 {"getcmdline", 0, 0, 0, f_getcmdline},
583 {"getcmdpos", 0, 0, 0, f_getcmdpos},
584 {"getcmdtype", 0, 0, 0, f_getcmdtype},
585 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586#if defined(FEAT_CMDL_COMPL)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200587 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200589 {"getcurpos", 0, 0, 0, f_getcurpos},
590 {"getcwd", 0, 2, 0, f_getcwd},
591 {"getenv", 1, 1, 0, f_getenv},
592 {"getfontname", 0, 1, 0, f_getfontname},
593 {"getfperm", 1, 1, 0, f_getfperm},
594 {"getfsize", 1, 1, 0, f_getfsize},
595 {"getftime", 1, 1, 0, f_getftime},
596 {"getftype", 1, 1, 0, f_getftype},
597 {"getjumplist", 0, 2, 0, f_getjumplist},
598 {"getline", 1, 2, 0, f_getline},
599 {"getloclist", 1, 2, 0, f_getloclist},
600 {"getmatches", 0, 1, 0, f_getmatches},
601 {"getpid", 0, 0, 0, f_getpid},
602 {"getpos", 1, 1, 0, f_getpos},
603 {"getqflist", 0, 1, 0, f_getqflist},
604 {"getreg", 0, 3, 0, f_getreg},
605 {"getregtype", 0, 1, 0, f_getregtype},
606 {"gettabinfo", 0, 1, 0, f_gettabinfo},
607 {"gettabvar", 2, 3, 0, f_gettabvar},
608 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
609 {"gettagstack", 0, 1, 0, f_gettagstack},
610 {"getwininfo", 0, 1, 0, f_getwininfo},
611 {"getwinpos", 0, 1, 0, f_getwinpos},
612 {"getwinposx", 0, 0, 0, f_getwinposx},
613 {"getwinposy", 0, 0, 0, f_getwinposy},
614 {"getwinvar", 2, 3, 0, f_getwinvar},
615 {"glob", 1, 4, 0, f_glob},
616 {"glob2regpat", 1, 1, 0, f_glob2regpat},
617 {"globpath", 2, 5, 0, f_globpath},
618 {"has", 1, 1, 0, f_has},
619 {"has_key", 2, 2, 0, f_has_key},
620 {"haslocaldir", 0, 2, 0, f_haslocaldir},
621 {"hasmapto", 1, 3, 0, f_hasmapto},
622 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
623 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
624 {"histadd", 2, 2, 0, f_histadd},
625 {"histdel", 1, 2, 0, f_histdel},
626 {"histget", 1, 2, 0, f_histget},
627 {"histnr", 1, 1, 0, f_histnr},
628 {"hlID", 1, 1, 0, f_hlID},
629 {"hlexists", 1, 1, 0, f_hlexists},
630 {"hostname", 0, 0, 0, f_hostname},
631 {"iconv", 3, 3, 0, f_iconv},
632 {"indent", 1, 1, 0, f_indent},
633 {"index", 2, 4, 0, f_index},
634 {"input", 1, 3, 0, f_input},
635 {"inputdialog", 1, 3, 0, f_inputdialog},
636 {"inputlist", 1, 1, 0, f_inputlist},
637 {"inputrestore", 0, 0, 0, f_inputrestore},
638 {"inputsave", 0, 0, 0, f_inputsave},
639 {"inputsecret", 1, 2, 0, f_inputsecret},
640 {"insert", 2, 3, 0, f_insert},
641 {"invert", 1, 1, 0, f_invert},
642 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200643#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200644 {"isinf", 1, 1, 0, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200645#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200646 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200648 {"isnan", 1, 1, 0, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200650 {"items", 1, 1, 0, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200652 {"job_getchannel", 1, 1, 0, f_job_getchannel},
653 {"job_info", 0, 1, 0, f_job_info},
654 {"job_setoptions", 2, 2, 0, f_job_setoptions},
655 {"job_start", 1, 2, 0, f_job_start},
656 {"job_status", 1, 1, 0, f_job_status},
657 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200659 {"join", 1, 2, 0, f_join},
660 {"js_decode", 1, 1, 0, f_js_decode},
661 {"js_encode", 1, 1, 0, f_js_encode},
662 {"json_decode", 1, 1, 0, f_json_decode},
663 {"json_encode", 1, 1, 0, f_json_encode},
664 {"keys", 1, 1, 0, f_keys},
665 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
666 {"len", 1, 1, 0, f_len},
667 {"libcall", 3, 3, 0, f_libcall},
668 {"libcallnr", 3, 3, 0, f_libcallnr},
669 {"line", 1, 1, 0, f_line},
670 {"line2byte", 1, 1, 0, f_line2byte},
671 {"lispindent", 1, 1, 0, f_lispindent},
672 {"list2str", 1, 2, 0, f_list2str},
673 {"listener_add", 1, 2, 0, f_listener_add},
674 {"listener_flush", 0, 1, 0, f_listener_flush},
675 {"listener_remove", 1, 1, 0, f_listener_remove},
676 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200677#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200678 {"log", 1, 1, 0, f_log},
679 {"log10", 1, 1, 0, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680#endif
681#ifdef FEAT_LUA
Bram Moolenaar25e42232019-08-04 15:04:10 +0200682 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200683#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200684 {"map", 2, 2, 0, f_map},
685 {"maparg", 1, 4, 0, f_maparg},
686 {"mapcheck", 1, 3, 0, f_mapcheck},
687 {"match", 2, 4, 0, f_match},
688 {"matchadd", 2, 5, 0, f_matchadd},
689 {"matchaddpos", 2, 5, 0, f_matchaddpos},
690 {"matcharg", 1, 1, 0, f_matcharg},
691 {"matchdelete", 1, 2, 0, f_matchdelete},
692 {"matchend", 2, 4, 0, f_matchend},
693 {"matchlist", 2, 4, 0, f_matchlist},
694 {"matchstr", 2, 4, 0, f_matchstr},
695 {"matchstrpos", 2, 4, 0, f_matchstrpos},
696 {"max", 1, 1, 0, f_max},
697 {"min", 1, 1, 0, f_min},
698 {"mkdir", 1, 3, 0, f_mkdir},
699 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#ifdef FEAT_MZSCHEME
Bram Moolenaar25e42232019-08-04 15:04:10 +0200701 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200703 {"nextnonblank", 1, 1, 0, f_nextnonblank},
704 {"nr2char", 1, 2, 0, f_nr2char},
705 {"or", 2, 2, 0, f_or},
706 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200707#ifdef FEAT_PERL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200708 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200710#ifdef FEAT_TEXT_PROP
Bram Moolenaar25e42232019-08-04 15:04:10 +0200711 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
712 {"popup_beval", 2, 2, 0, f_popup_beval},
713 {"popup_clear", 0, 0, 0, f_popup_clear},
714 {"popup_close", 1, 2, 0, f_popup_close},
715 {"popup_create", 2, 2, 0, f_popup_create},
716 {"popup_dialog", 2, 2, 0, f_popup_dialog},
717 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
718 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
719 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
720 {"popup_getpos", 1, 1, 0, f_popup_getpos},
721 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
722 {"popup_hide", 1, 1, 0, f_popup_hide},
723 {"popup_locate", 2, 2, 0, f_popup_locate},
724 {"popup_menu", 2, 2, 0, f_popup_menu},
725 {"popup_move", 2, 2, 0, f_popup_move},
726 {"popup_notification", 2, 2, 0, f_popup_notification},
727 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
728 {"popup_settext", 2, 2, 0, f_popup_settext},
729 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200730#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200731#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200732 {"pow", 2, 2, 0, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200734 {"prevnonblank", 1, 1, 0, f_prevnonblank},
735 {"printf", 1, 19, 0, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200736#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200737 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
738 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
739 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200740#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100741#ifdef FEAT_TEXT_PROP
Bram Moolenaar25e42232019-08-04 15:04:10 +0200742 {"prop_add", 3, 3, 0, f_prop_add},
743 {"prop_clear", 1, 3, 0, f_prop_clear},
744 {"prop_list", 1, 2, 0, f_prop_list},
745 {"prop_remove", 1, 3, 0, f_prop_remove},
746 {"prop_type_add", 2, 2, 0, f_prop_type_add},
747 {"prop_type_change", 2, 2, 0, f_prop_type_change},
748 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
749 {"prop_type_get", 1, 2, 0, f_prop_type_get},
750 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100751#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200752 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#ifdef FEAT_PYTHON3
Bram Moolenaar25e42232019-08-04 15:04:10 +0200754 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755#endif
756#ifdef FEAT_PYTHON
Bram Moolenaar25e42232019-08-04 15:04:10 +0200757 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100759#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200760 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100761#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200762 {"range", 1, 3, 0, f_range},
763 {"readdir", 1, 2, 0, f_readdir},
764 {"readfile", 1, 3, 0, f_readfile},
765 {"reg_executing", 0, 0, 0, f_reg_executing},
766 {"reg_recording", 0, 0, 0, f_reg_recording},
767 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200769 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200770#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200771 {"reltimestr", 1, 1, 0, f_reltimestr},
772 {"remote_expr", 2, 4, 0, f_remote_expr},
773 {"remote_foreground", 1, 1, 0, f_remote_foreground},
774 {"remote_peek", 1, 2, 0, f_remote_peek},
775 {"remote_read", 1, 2, 0, f_remote_read},
776 {"remote_send", 2, 3, 0, f_remote_send},
777 {"remote_startserver", 1, 1, 0, f_remote_startserver},
778 {"remove", 2, 3, 0, f_remove},
779 {"rename", 2, 2, 0, f_rename},
780 {"repeat", 2, 2, 0, f_repeat},
781 {"resolve", 1, 1, 0, f_resolve},
782 {"reverse", 1, 1, 0, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200784 {"round", 1, 1, 0, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200785#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100786#ifdef FEAT_RUBY
Bram Moolenaar25e42232019-08-04 15:04:10 +0200787 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100788#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200789 {"screenattr", 2, 2, 0, f_screenattr},
790 {"screenchar", 2, 2, 0, f_screenchar},
791 {"screenchars", 2, 2, 0, f_screenchars},
792 {"screencol", 0, 0, 0, f_screencol},
793 {"screenpos", 3, 3, 0, f_screenpos},
794 {"screenrow", 0, 0, 0, f_screenrow},
795 {"screenstring", 2, 2, 0, f_screenstring},
796 {"search", 1, 4, 0, f_search},
797 {"searchdecl", 1, 3, 0, f_searchdecl},
798 {"searchpair", 3, 7, 0, f_searchpair},
799 {"searchpairpos", 3, 7, 0, f_searchpairpos},
800 {"searchpos", 1, 4, 0, f_searchpos},
801 {"server2client", 2, 2, 0, f_server2client},
802 {"serverlist", 0, 0, 0, f_serverlist},
803 {"setbufline", 3, 3, 0, f_setbufline},
804 {"setbufvar", 3, 3, 0, f_setbufvar},
805 {"setcharsearch", 1, 1, 0, f_setcharsearch},
806 {"setcmdpos", 1, 1, 0, f_setcmdpos},
807 {"setenv", 2, 2, 0, f_setenv},
808 {"setfperm", 2, 2, 0, f_setfperm},
809 {"setline", 2, 2, 0, f_setline},
810 {"setloclist", 2, 4, 0, f_setloclist},
811 {"setmatches", 1, 2, 0, f_setmatches},
812 {"setpos", 2, 2, 0, f_setpos},
813 {"setqflist", 1, 3, 0, f_setqflist},
814 {"setreg", 2, 3, 0, f_setreg},
815 {"settabvar", 3, 3, 0, f_settabvar},
816 {"settabwinvar", 4, 4, 0, f_settabwinvar},
817 {"settagstack", 2, 3, 0, f_settagstack},
818 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#ifdef FEAT_CRYPT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200820 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200822 {"shellescape", 1, 2, 0, f_shellescape},
823 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100824#ifdef FEAT_SIGNS
Bram Moolenaar25e42232019-08-04 15:04:10 +0200825 {"sign_define", 1, 2, 0, f_sign_define},
826 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
827 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
828 {"sign_jump", 3, 3, 0, f_sign_jump},
829 {"sign_place", 4, 5, 0, f_sign_place},
830 {"sign_placelist", 1, 1, 0, f_sign_placelist},
831 {"sign_undefine", 0, 1, 0, f_sign_undefine},
832 {"sign_unplace", 1, 2, 0, f_sign_unplace},
833 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100834#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200835 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200837 {"sin", 1, 1, 0, f_sin},
838 {"sinh", 1, 1, 0, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200840 {"sort", 1, 3, 0, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200841#ifdef FEAT_SOUND
Bram Moolenaar25e42232019-08-04 15:04:10 +0200842 {"sound_clear", 0, 0, 0, f_sound_clear},
843 {"sound_playevent", 1, 2, 0, f_sound_playevent},
844 {"sound_playfile", 1, 2, 0, f_sound_playfile},
845 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200846#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200847 {"soundfold", 1, 1, 0, f_soundfold},
848 {"spellbadword", 0, 1, 0, f_spellbadword},
849 {"spellsuggest", 1, 3, 0, f_spellsuggest},
850 {"split", 1, 3, 0, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200852 {"sqrt", 1, 1, 0, f_sqrt},
853 {"str2float", 1, 1, 0, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200855 {"str2list", 1, 2, 0, f_str2list},
856 {"str2nr", 1, 2, 0, f_str2nr},
857 {"strcharpart", 2, 3, 0, f_strcharpart},
858 {"strchars", 1, 2, 0, f_strchars},
859 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860#ifdef HAVE_STRFTIME
Bram Moolenaar25e42232019-08-04 15:04:10 +0200861 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200862#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200863 {"strgetchar", 2, 2, 0, f_strgetchar},
864 {"stridx", 2, 3, 0, f_stridx},
865 {"string", 1, 1, 0, f_string},
866 {"strlen", 1, 1, 0, f_strlen},
867 {"strpart", 2, 3, 0, f_strpart},
868 {"strridx", 2, 3, 0, f_strridx},
869 {"strtrans", 1, 1, 0, f_strtrans},
870 {"strwidth", 1, 1, 0, f_strwidth},
871 {"submatch", 1, 2, 0, f_submatch},
872 {"substitute", 4, 4, 0, f_substitute},
873 {"swapinfo", 1, 1, 0, f_swapinfo},
874 {"swapname", 1, 1, 0, f_swapname},
875 {"synID", 3, 3, 0, f_synID},
876 {"synIDattr", 2, 3, 0, f_synIDattr},
877 {"synIDtrans", 1, 1, 0, f_synIDtrans},
878 {"synconcealed", 2, 2, 0, f_synconcealed},
879 {"synstack", 2, 2, 0, f_synstack},
880 {"system", 1, 2, 0, f_system},
881 {"systemlist", 1, 2, 0, f_systemlist},
882 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
883 {"tabpagenr", 0, 1, 0, f_tabpagenr},
884 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
885 {"tagfiles", 0, 0, 0, f_tagfiles},
886 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200888 {"tan", 1, 1, 0, f_tan},
889 {"tanh", 1, 1, 0, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200891 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200892#ifdef FEAT_TERMINAL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200893 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
894 {"term_dumpload", 1, 2, 0, f_term_dumpload},
895 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
896 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200897# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200898 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200899# endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200900 {"term_getattr", 2, 2, 0, f_term_getattr},
901 {"term_getcursor", 1, 1, 0, f_term_getcursor},
902 {"term_getjob", 1, 1, 0, f_term_getjob},
903 {"term_getline", 2, 2, 0, f_term_getline},
904 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
905 {"term_getsize", 1, 1, 0, f_term_getsize},
906 {"term_getstatus", 1, 1, 0, f_term_getstatus},
907 {"term_gettitle", 1, 1, 0, f_term_gettitle},
908 {"term_gettty", 1, 2, 0, f_term_gettty},
909 {"term_list", 0, 0, 0, f_term_list},
910 {"term_scrape", 2, 2, 0, f_term_scrape},
911 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200912# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200913 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200914# endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200915 {"term_setkill", 2, 2, 0, f_term_setkill},
916 {"term_setrestore", 2, 2, 0, f_term_setrestore},
917 {"term_setsize", 3, 3, 0, f_term_setsize},
918 {"term_start", 1, 2, 0, f_term_start},
919 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200920#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200921 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
922 {"test_autochdir", 0, 0, 0, f_test_autochdir},
923 {"test_feedinput", 1, 1, 0, f_test_feedinput},
924 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
925 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
926 {"test_getvalue", 1, 1, 0, f_test_getvalue},
927 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
928 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200930 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200932 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200934 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200936 {"test_null_list", 0, 0, 0, f_test_null_list},
937 {"test_null_partial", 0, 0, 0, f_test_null_partial},
938 {"test_null_string", 0, 0, 0, f_test_null_string},
939 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
940 {"test_override", 2, 2, 0, f_test_override},
941 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200942#ifdef FEAT_GUI
Bram Moolenaar25e42232019-08-04 15:04:10 +0200943 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200944#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200945#ifdef FEAT_MOUSE
Bram Moolenaar25e42232019-08-04 15:04:10 +0200946 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200947#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200948 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#ifdef FEAT_TIMERS
Bram Moolenaar25e42232019-08-04 15:04:10 +0200950 {"timer_info", 0, 1, 0, f_timer_info},
951 {"timer_pause", 2, 2, 0, f_timer_pause},
952 {"timer_start", 2, 3, 0, f_timer_start},
953 {"timer_stop", 1, 1, 0, f_timer_stop},
954 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200956 {"tolower", 1, 1, 0, f_tolower},
957 {"toupper", 1, 1, 0, f_toupper},
958 {"tr", 3, 3, 0, f_tr},
959 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200960#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200961 {"trunc", 1, 1, 0, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200963 {"type", 1, 1, 0, f_type},
964 {"undofile", 1, 1, 0, f_undofile},
965 {"undotree", 0, 0, 0, f_undotree},
966 {"uniq", 1, 3, 0, f_uniq},
967 {"values", 1, 1, 0, f_values},
968 {"virtcol", 1, 1, 0, f_virtcol},
969 {"visualmode", 0, 1, 0, f_visualmode},
970 {"wildmenumode", 0, 0, 0, f_wildmenumode},
971 {"win_execute", 2, 3, 0, f_win_execute},
972 {"win_findbuf", 1, 1, 0, f_win_findbuf},
973 {"win_getid", 0, 2, 0, f_win_getid},
974 {"win_gotoid", 1, 1, 0, f_win_gotoid},
975 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
976 {"win_id2win", 1, 1, 0, f_win_id2win},
977 {"win_screenpos", 1, 1, 0, f_win_screenpos},
978 {"winbufnr", 1, 1, 0, f_winbufnr},
979 {"wincol", 0, 0, 0, f_wincol},
980 {"winheight", 1, 1, 0, f_winheight},
981 {"winlayout", 0, 1, 0, f_winlayout},
982 {"winline", 0, 0, 0, f_winline},
983 {"winnr", 0, 1, 0, f_winnr},
984 {"winrestcmd", 0, 0, 0, f_winrestcmd},
985 {"winrestview", 1, 1, 0, f_winrestview},
986 {"winsaveview", 0, 0, 0, f_winsaveview},
987 {"winwidth", 1, 1, 0, f_winwidth},
988 {"wordcount", 0, 0, 0, f_wordcount},
989 {"writefile", 2, 3, 0, f_writefile},
990 {"xor", 2, 2, 0, f_xor},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200991};
992
Bram Moolenaar25e42232019-08-04 15:04:10 +0200993// values for f_argtype
994#define FEARG_LAST 1 // base is the last argument
995#define FEARG_2 2 // base is the second argument
996
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997/*
998 * Methods that call the internal function with the base as the first argument.
999 */
1000static funcentry_T base_methods[] =
1001{
Bram Moolenaar25e42232019-08-04 15:04:10 +02001002 {"add", 1, 1, 0, f_add},
1003 {"append", 1, 1, FEARG_LAST, f_append},
1004 {"appendbufline", 2, 2, FEARG_LAST, f_appendbufline},
1005 {"assert_equal", 1, 2, FEARG_2, f_assert_equal},
1006 {"assert_notequal", 1, 2, FEARG_2, f_assert_notequal},
1007 {"copy", 0, 0, 0, f_copy},
1008 {"count", 1, 3, 0, f_count},
1009 {"empty", 0, 0, 0, f_empty},
1010 {"eval", 0, 0, 0, f_eval},
1011 {"extend", 1, 2, 0, f_extend},
1012 {"filter", 1, 1, 0, f_filter},
1013 {"get", 1, 2, 0, f_get},
1014 {"index", 1, 3, 0, f_index},
1015 {"insert", 1, 2, 0, f_insert},
1016 {"items", 0, 0, 0, f_items},
1017 {"join", 0, 1, 0, f_join},
1018 {"keys", 0, 0, 0, f_keys},
1019 {"len", 0, 0, 0, f_len},
1020 {"map", 1, 1, 0, f_map},
1021 {"max", 0, 0, 0, f_max},
1022 {"min", 0, 0, 0, f_min},
1023 {"remove", 1, 2, 0, f_remove},
1024 {"repeat", 1, 1, 0, f_repeat},
1025 {"reverse", 0, 0, 0, f_reverse},
1026 {"sort", 0, 2, 0, f_sort},
1027 {"string", 0, 0, 0, f_string},
1028 {"type", 0, 0, 0, f_type},
1029 {"uniq", 0, 2, 0, f_uniq},
1030 {"values", 0, 0, 0, f_values},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001031};
1032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001033#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1034
1035/*
1036 * Function given to ExpandGeneric() to obtain the list of internal
1037 * or user defined function names.
1038 */
1039 char_u *
1040get_function_name(expand_T *xp, int idx)
1041{
1042 static int intidx = -1;
1043 char_u *name;
1044
1045 if (idx == 0)
1046 intidx = -1;
1047 if (intidx < 0)
1048 {
1049 name = get_user_func_name(xp, idx);
1050 if (name != NULL)
1051 return name;
1052 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001053 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001054 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001055 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001056 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001057 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001058 STRCAT(IObuff, ")");
1059 return IObuff;
1060 }
1061
1062 return NULL;
1063}
1064
1065/*
1066 * Function given to ExpandGeneric() to obtain the list of internal or
1067 * user defined variable or function names.
1068 */
1069 char_u *
1070get_expr_name(expand_T *xp, int idx)
1071{
1072 static int intidx = -1;
1073 char_u *name;
1074
1075 if (idx == 0)
1076 intidx = -1;
1077 if (intidx < 0)
1078 {
1079 name = get_function_name(xp, idx);
1080 if (name != NULL)
1081 return name;
1082 }
1083 return get_user_var_name(xp, ++intidx);
1084}
1085
1086#endif /* FEAT_CMDL_COMPL */
1087
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001088/*
Bram Moolenaarac92e252019-08-03 21:58:38 +02001089 * Find internal function in table "functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 * Return index, or -1 if not found
1091 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001092 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001093find_internal_func(
Bram Moolenaarac92e252019-08-03 21:58:38 +02001094 char_u *name, // name of the function
1095 funcentry_T *functions) // functions table to use
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001096{
1097 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001098 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001099 int cmp;
1100 int x;
1101
Bram Moolenaarac92e252019-08-03 21:58:38 +02001102 if (functions == global_functions)
1103 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
1104 else
1105 last = (int)(sizeof(base_methods) / sizeof(funcentry_T)) - 1;
1106
1107 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001108 while (first <= last)
1109 {
1110 x = first + ((unsigned)(last - first) >> 1);
1111 cmp = STRCMP(name, functions[x].f_name);
1112 if (cmp < 0)
1113 last = x - 1;
1114 else if (cmp > 0)
1115 first = x + 1;
1116 else
1117 return x;
1118 }
1119 return -1;
1120}
1121
1122 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001123has_internal_func(char_u *name)
1124{
1125 return find_internal_func(name, global_functions) >= 0;
1126}
1127
1128 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001129call_internal_func(
1130 char_u *name,
1131 int argcount,
1132 typval_T *argvars,
1133 typval_T *rettv)
1134{
1135 int i;
1136
Bram Moolenaarac92e252019-08-03 21:58:38 +02001137 i = find_internal_func(name, global_functions);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001138 if (i < 0)
1139 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001140 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001141 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001142 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001143 return ERROR_TOOMANY;
1144 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001145 global_functions[i].f_func(argvars, rettv);
1146 return ERROR_NONE;
1147}
1148
1149/*
1150 * Invoke a method for base->method().
1151 */
1152 int
1153call_internal_method(
1154 char_u *name,
1155 int argcount,
1156 typval_T *argvars,
1157 typval_T *rettv,
1158 typval_T *basetv)
1159{
1160 int i;
1161 int fi;
1162 typval_T argv[MAX_FUNC_ARGS + 1];
1163
1164 fi = find_internal_func(name, base_methods);
1165 if (fi < 0)
1166 return ERROR_UNKNOWN;
1167 if (argcount < base_methods[fi].f_min_argc)
1168 return ERROR_TOOFEW;
1169 if (argcount > base_methods[fi].f_max_argc)
1170 return ERROR_TOOMANY;
1171
Bram Moolenaar25e42232019-08-04 15:04:10 +02001172 if (base_methods[fi].f_argtype == FEARG_LAST)
1173 {
1174 // base value goes last
1175 for (i = 0; i < argcount; ++i)
1176 argv[i] = argvars[i];
1177 argv[argcount] = *basetv;
1178 }
1179 else if (base_methods[fi].f_argtype == FEARG_2)
1180 {
1181 // base value goes second
1182 argv[0] = argvars[0];
1183 argv[1] = *basetv;
1184 for (i = 1; i < argcount; ++i)
1185 argv[i + 1] = argvars[i];
1186 }
1187 else
1188 {
1189 argv[0] = *basetv;
1190 for (i = 0; i < argcount; ++i)
1191 argv[i + 1] = argvars[i];
1192 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001193 argv[argcount + 1].v_type = VAR_UNKNOWN;
1194
1195 base_methods[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001196 return ERROR_NONE;
1197}
1198
1199/*
1200 * Return TRUE for a non-zero Number and a non-empty String.
1201 */
1202 static int
1203non_zero_arg(typval_T *argvars)
1204{
1205 return ((argvars[0].v_type == VAR_NUMBER
1206 && argvars[0].vval.v_number != 0)
1207 || (argvars[0].v_type == VAR_SPECIAL
1208 && argvars[0].vval.v_number == VVAL_TRUE)
1209 || (argvars[0].v_type == VAR_STRING
1210 && argvars[0].vval.v_string != NULL
1211 && *argvars[0].vval.v_string != NUL));
1212}
1213
1214/*
1215 * Get the lnum from the first argument.
1216 * Also accepts ".", "$", etc., but that only works for the current buffer.
1217 * Returns -1 on error.
1218 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001219 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001220tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001221{
1222 typval_T rettv;
1223 linenr_T lnum;
1224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001225 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001226 if (lnum == 0) /* no valid number, try using line() */
1227 {
1228 rettv.v_type = VAR_NUMBER;
1229 f_line(argvars, &rettv);
1230 lnum = (linenr_T)rettv.vval.v_number;
1231 clear_tv(&rettv);
1232 }
1233 return lnum;
1234}
1235
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001236/*
1237 * Get the lnum from the first argument.
1238 * Also accepts "$", then "buf" is used.
1239 * Returns 0 on error.
1240 */
1241 static linenr_T
1242tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1243{
1244 if (argvars[0].v_type == VAR_STRING
1245 && argvars[0].vval.v_string != NULL
1246 && argvars[0].vval.v_string[0] == '$'
1247 && buf != NULL)
1248 return buf->b_ml.ml_line_count;
1249 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1250}
1251
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001253/*
1254 * Get the float value of "argvars[0]" into "f".
1255 * Returns FAIL when the argument is not a Number or Float.
1256 */
1257 static int
1258get_float_arg(typval_T *argvars, float_T *f)
1259{
1260 if (argvars[0].v_type == VAR_FLOAT)
1261 {
1262 *f = argvars[0].vval.v_float;
1263 return OK;
1264 }
1265 if (argvars[0].v_type == VAR_NUMBER)
1266 {
1267 *f = (float_T)argvars[0].vval.v_number;
1268 return OK;
1269 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001270 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001271 return FAIL;
1272}
1273
1274/*
1275 * "abs(expr)" function
1276 */
1277 static void
1278f_abs(typval_T *argvars, typval_T *rettv)
1279{
1280 if (argvars[0].v_type == VAR_FLOAT)
1281 {
1282 rettv->v_type = VAR_FLOAT;
1283 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1284 }
1285 else
1286 {
1287 varnumber_T n;
1288 int error = FALSE;
1289
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001290 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 if (error)
1292 rettv->vval.v_number = -1;
1293 else if (n > 0)
1294 rettv->vval.v_number = n;
1295 else
1296 rettv->vval.v_number = -n;
1297 }
1298}
1299
1300/*
1301 * "acos()" function
1302 */
1303 static void
1304f_acos(typval_T *argvars, typval_T *rettv)
1305{
1306 float_T f = 0.0;
1307
1308 rettv->v_type = VAR_FLOAT;
1309 if (get_float_arg(argvars, &f) == OK)
1310 rettv->vval.v_float = acos(f);
1311 else
1312 rettv->vval.v_float = 0.0;
1313}
1314#endif
1315
1316/*
1317 * "add(list, item)" function
1318 */
1319 static void
1320f_add(typval_T *argvars, typval_T *rettv)
1321{
1322 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001323 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001324
1325 rettv->vval.v_number = 1; /* Default: Failed */
1326 if (argvars[0].v_type == VAR_LIST)
1327 {
1328 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001329 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001330 (char_u *)N_("add() argument"), TRUE)
1331 && list_append_tv(l, &argvars[1]) == OK)
1332 copy_tv(&argvars[0], rettv);
1333 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001334 else if (argvars[0].v_type == VAR_BLOB)
1335 {
1336 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001337 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001338 (char_u *)N_("add() argument"), TRUE))
1339 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001340 int error = FALSE;
1341 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1342
1343 if (!error)
1344 {
1345 ga_append(&b->bv_ga, (int)n);
1346 copy_tv(&argvars[0], rettv);
1347 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001348 }
1349 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001351 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352}
1353
1354/*
1355 * "and(expr, expr)" function
1356 */
1357 static void
1358f_and(typval_T *argvars, typval_T *rettv)
1359{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001360 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1361 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001362}
1363
1364/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001365 * If there is a window for "curbuf", make it the current window.
1366 */
1367 static void
1368find_win_for_curbuf(void)
1369{
1370 wininfo_T *wip;
1371
1372 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1373 {
1374 if (wip->wi_win != NULL)
1375 {
1376 curwin = wip->wi_win;
1377 break;
1378 }
1379 }
1380}
1381
1382/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001383 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001384 */
1385 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001386set_buffer_lines(
1387 buf_T *buf,
1388 linenr_T lnum_arg,
1389 int append,
1390 typval_T *lines,
1391 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001392{
Bram Moolenaarca851592018-06-06 21:04:07 +02001393 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1394 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001395 list_T *l = NULL;
1396 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001397 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001398 linenr_T append_lnum;
1399 buf_T *curbuf_save = NULL;
1400 win_T *curwin_save = NULL;
1401 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001402
Bram Moolenaarca851592018-06-06 21:04:07 +02001403 /* When using the current buffer ml_mfp will be set if needed. Useful when
1404 * setline() is used on startup. For other buffers the buffer must be
1405 * loaded. */
1406 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001407 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001408 rettv->vval.v_number = 1; /* FAIL */
1409 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001410 }
1411
Bram Moolenaarca851592018-06-06 21:04:07 +02001412 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001413 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001414 curbuf_save = curbuf;
1415 curwin_save = curwin;
1416 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001417 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001418 }
1419
1420 if (append)
1421 // appendbufline() uses the line number below which we insert
1422 append_lnum = lnum - 1;
1423 else
1424 // setbufline() uses the line number above which we insert, we only
1425 // append if it's below the last line
1426 append_lnum = curbuf->b_ml.ml_line_count;
1427
1428 if (lines->v_type == VAR_LIST)
1429 {
1430 l = lines->vval.v_list;
1431 li = l->lv_first;
1432 }
1433 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001434 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001435
1436 /* default result is zero == OK */
1437 for (;;)
1438 {
1439 if (l != NULL)
1440 {
1441 /* list argument, get next string */
1442 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001444 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001445 li = li->li_next;
1446 }
1447
Bram Moolenaarca851592018-06-06 21:04:07 +02001448 rettv->vval.v_number = 1; /* FAIL */
1449 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1450 break;
1451
1452 /* When coming here from Insert mode, sync undo, so that this can be
1453 * undone separately from what was previously inserted. */
1454 if (u_sync_once == 2)
1455 {
1456 u_sync_once = 1; /* notify that u_sync() was called */
1457 u_sync(TRUE);
1458 }
1459
1460 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1461 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001462 // Existing line, replace it.
1463 // Removes any existing text properties.
1464 if (u_savesub(lnum) == OK && ml_replace_len(
1465 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001466 {
1467 changed_bytes(lnum, 0);
1468 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1469 check_cursor_col();
1470 rettv->vval.v_number = 0; /* OK */
1471 }
1472 }
1473 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1474 {
1475 /* append the line */
1476 ++added;
1477 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1478 rettv->vval.v_number = 0; /* OK */
1479 }
1480
1481 if (l == NULL) /* only one string argument */
1482 break;
1483 ++lnum;
1484 }
1485
1486 if (added > 0)
1487 {
1488 win_T *wp;
1489 tabpage_T *tp;
1490
1491 appended_lines_mark(append_lnum, added);
1492 FOR_ALL_TAB_WINDOWS(tp, wp)
1493 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1494 wp->w_cursor.lnum += added;
1495 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001496 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001498
1499 if (!is_curbuf)
1500 {
1501 curbuf = curbuf_save;
1502 curwin = curwin_save;
1503 }
1504}
1505
1506/*
1507 * "append(lnum, string/list)" function
1508 */
1509 static void
1510f_append(typval_T *argvars, typval_T *rettv)
1511{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001512 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001513
1514 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1515}
1516
1517/*
1518 * "appendbufline(buf, lnum, string/list)" function
1519 */
1520 static void
1521f_appendbufline(typval_T *argvars, typval_T *rettv)
1522{
1523 linenr_T lnum;
1524 buf_T *buf;
1525
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001526 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001527 if (buf == NULL)
1528 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001530 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001531 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001532 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1533 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001534}
1535
1536/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001537 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001538 */
1539 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001540f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001542 win_T *wp;
1543
1544 if (argvars[0].v_type == VAR_UNKNOWN)
1545 // use the current window
1546 rettv->vval.v_number = ARGCOUNT;
1547 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001548 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001549 // use the global argument list
1550 rettv->vval.v_number = GARGCOUNT;
1551 else
1552 {
1553 // use the argument list of the specified window
1554 wp = find_win_by_nr_or_id(&argvars[0]);
1555 if (wp != NULL)
1556 rettv->vval.v_number = WARGCOUNT(wp);
1557 else
1558 rettv->vval.v_number = -1;
1559 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560}
1561
1562/*
1563 * "argidx()" function
1564 */
1565 static void
1566f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1567{
1568 rettv->vval.v_number = curwin->w_arg_idx;
1569}
1570
1571/*
1572 * "arglistid()" function
1573 */
1574 static void
1575f_arglistid(typval_T *argvars, typval_T *rettv)
1576{
1577 win_T *wp;
1578
1579 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001580 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001581 if (wp != NULL)
1582 rettv->vval.v_number = wp->w_alist->id;
1583}
1584
1585/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001586 * Get the argument list for a given window
1587 */
1588 static void
1589get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1590{
1591 int idx;
1592
1593 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1594 for (idx = 0; idx < argcount; ++idx)
1595 list_append_string(rettv->vval.v_list,
1596 alist_name(&arglist[idx]), -1);
1597}
1598
1599/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001600 * "argv(nr)" function
1601 */
1602 static void
1603f_argv(typval_T *argvars, typval_T *rettv)
1604{
1605 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001606 aentry_T *arglist = NULL;
1607 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608
1609 if (argvars[0].v_type != VAR_UNKNOWN)
1610 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001611 if (argvars[1].v_type == VAR_UNKNOWN)
1612 {
1613 arglist = ARGLIST;
1614 argcount = ARGCOUNT;
1615 }
1616 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001617 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001618 {
1619 arglist = GARGLIST;
1620 argcount = GARGCOUNT;
1621 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001623 {
1624 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1625
1626 if (wp != NULL)
1627 {
1628 /* Use the argument list of the specified window */
1629 arglist = WARGLIST(wp);
1630 argcount = WARGCOUNT(wp);
1631 }
1632 }
1633
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001635 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001636 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001637 if (arglist != NULL && idx >= 0 && idx < argcount)
1638 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1639 else if (idx == -1)
1640 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001641 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001642 else
1643 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001644}
1645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646#ifdef FEAT_FLOAT
1647/*
1648 * "asin()" function
1649 */
1650 static void
1651f_asin(typval_T *argvars, typval_T *rettv)
1652{
1653 float_T f = 0.0;
1654
1655 rettv->v_type = VAR_FLOAT;
1656 if (get_float_arg(argvars, &f) == OK)
1657 rettv->vval.v_float = asin(f);
1658 else
1659 rettv->vval.v_float = 0.0;
1660}
1661
1662/*
1663 * "atan()" function
1664 */
1665 static void
1666f_atan(typval_T *argvars, typval_T *rettv)
1667{
1668 float_T f = 0.0;
1669
1670 rettv->v_type = VAR_FLOAT;
1671 if (get_float_arg(argvars, &f) == OK)
1672 rettv->vval.v_float = atan(f);
1673 else
1674 rettv->vval.v_float = 0.0;
1675}
1676
1677/*
1678 * "atan2()" function
1679 */
1680 static void
1681f_atan2(typval_T *argvars, typval_T *rettv)
1682{
1683 float_T fx = 0.0, fy = 0.0;
1684
1685 rettv->v_type = VAR_FLOAT;
1686 if (get_float_arg(argvars, &fx) == OK
1687 && get_float_arg(&argvars[1], &fy) == OK)
1688 rettv->vval.v_float = atan2(fx, fy);
1689 else
1690 rettv->vval.v_float = 0.0;
1691}
1692#endif
1693
1694/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001695 * "balloon_show()" function
1696 */
1697#ifdef FEAT_BEVAL
1698 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001699f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1700{
1701 rettv->v_type = VAR_STRING;
1702 if (balloonEval != NULL)
1703 {
1704 if (balloonEval->msg == NULL)
1705 rettv->vval.v_string = NULL;
1706 else
1707 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1708 }
1709}
1710
1711 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001712f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1713{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001714 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001715 {
1716 if (argvars[0].v_type == VAR_LIST
1717# ifdef FEAT_GUI
1718 && !gui.in_use
1719# endif
1720 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001721 {
1722 list_T *l = argvars[0].vval.v_list;
1723
1724 // empty list removes the balloon
1725 post_balloon(balloonEval, NULL,
1726 l == NULL || l->lv_len == 0 ? NULL : l);
1727 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001728 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001729 {
1730 char_u *mesg = tv_get_string_chk(&argvars[0]);
1731
1732 if (mesg != NULL)
1733 // empty string removes the balloon
1734 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1735 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001736 }
1737}
1738
Bram Moolenaar669a8282017-11-19 20:13:05 +01001739# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001740 static void
1741f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1742{
1743 if (rettv_list_alloc(rettv) == OK)
1744 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001745 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001746
1747 if (msg != NULL)
1748 {
1749 pumitem_T *array;
1750 int size = split_message(msg, &array);
1751 int i;
1752
1753 /* Skip the first and last item, they are always empty. */
1754 for (i = 1; i < size - 1; ++i)
1755 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001756 while (size > 0)
1757 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001758 vim_free(array);
1759 }
1760 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001761}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001762# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001763#endif
1764
1765/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001766 * "browse(save, title, initdir, default)" function
1767 */
1768 static void
1769f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1770{
1771#ifdef FEAT_BROWSE
1772 int save;
1773 char_u *title;
1774 char_u *initdir;
1775 char_u *defname;
1776 char_u buf[NUMBUFLEN];
1777 char_u buf2[NUMBUFLEN];
1778 int error = FALSE;
1779
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001780 save = (int)tv_get_number_chk(&argvars[0], &error);
1781 title = tv_get_string_chk(&argvars[1]);
1782 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1783 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784
1785 if (error || title == NULL || initdir == NULL || defname == NULL)
1786 rettv->vval.v_string = NULL;
1787 else
1788 rettv->vval.v_string =
1789 do_browse(save ? BROWSE_SAVE : 0,
1790 title, defname, NULL, initdir, NULL, curbuf);
1791#else
1792 rettv->vval.v_string = NULL;
1793#endif
1794 rettv->v_type = VAR_STRING;
1795}
1796
1797/*
1798 * "browsedir(title, initdir)" function
1799 */
1800 static void
1801f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1802{
1803#ifdef FEAT_BROWSE
1804 char_u *title;
1805 char_u *initdir;
1806 char_u buf[NUMBUFLEN];
1807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001808 title = tv_get_string_chk(&argvars[0]);
1809 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001810
1811 if (title == NULL || initdir == NULL)
1812 rettv->vval.v_string = NULL;
1813 else
1814 rettv->vval.v_string = do_browse(BROWSE_DIR,
1815 title, NULL, NULL, initdir, NULL, curbuf);
1816#else
1817 rettv->vval.v_string = NULL;
1818#endif
1819 rettv->v_type = VAR_STRING;
1820}
1821
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822/*
1823 * Find a buffer by number or exact name.
1824 */
1825 static buf_T *
1826find_buffer(typval_T *avar)
1827{
1828 buf_T *buf = NULL;
1829
1830 if (avar->v_type == VAR_NUMBER)
1831 buf = buflist_findnr((int)avar->vval.v_number);
1832 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1833 {
1834 buf = buflist_findname_exp(avar->vval.v_string);
1835 if (buf == NULL)
1836 {
1837 /* No full path name match, try a match with a URL or a "nofile"
1838 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001839 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840 if (buf->b_fname != NULL
1841 && (path_with_url(buf->b_fname)
1842#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001843 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844#endif
1845 )
1846 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1847 break;
1848 }
1849 }
1850 return buf;
1851}
1852
1853/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001854 * "bufadd(expr)" function
1855 */
1856 static void
1857f_bufadd(typval_T *argvars, typval_T *rettv)
1858{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001859 char_u *name = tv_get_string(&argvars[0]);
1860
1861 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001862}
1863
1864/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001865 * "bufexists(expr)" function
1866 */
1867 static void
1868f_bufexists(typval_T *argvars, typval_T *rettv)
1869{
1870 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1871}
1872
1873/*
1874 * "buflisted(expr)" function
1875 */
1876 static void
1877f_buflisted(typval_T *argvars, typval_T *rettv)
1878{
1879 buf_T *buf;
1880
1881 buf = find_buffer(&argvars[0]);
1882 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1883}
1884
1885/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001886 * "bufload(expr)" function
1887 */
1888 static void
1889f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1890{
1891 buf_T *buf = get_buf_arg(&argvars[0]);
1892
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001893 if (buf != NULL)
1894 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001895}
1896
1897/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898 * "bufloaded(expr)" function
1899 */
1900 static void
1901f_bufloaded(typval_T *argvars, typval_T *rettv)
1902{
1903 buf_T *buf;
1904
1905 buf = find_buffer(&argvars[0]);
1906 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1907}
1908
1909 buf_T *
1910buflist_find_by_name(char_u *name, int curtab_only)
1911{
1912 int save_magic;
1913 char_u *save_cpo;
1914 buf_T *buf;
1915
1916 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1917 save_magic = p_magic;
1918 p_magic = TRUE;
1919 save_cpo = p_cpo;
1920 p_cpo = (char_u *)"";
1921
1922 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1923 TRUE, FALSE, curtab_only));
1924
1925 p_magic = save_magic;
1926 p_cpo = save_cpo;
1927 return buf;
1928}
1929
1930/*
1931 * Get buffer by number or pattern.
1932 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001933 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001934tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935{
1936 char_u *name = tv->vval.v_string;
1937 buf_T *buf;
1938
1939 if (tv->v_type == VAR_NUMBER)
1940 return buflist_findnr((int)tv->vval.v_number);
1941 if (tv->v_type != VAR_STRING)
1942 return NULL;
1943 if (name == NULL || *name == NUL)
1944 return curbuf;
1945 if (name[0] == '$' && name[1] == NUL)
1946 return lastbuf;
1947
1948 buf = buflist_find_by_name(name, curtab_only);
1949
1950 /* If not found, try expanding the name, like done for bufexists(). */
1951 if (buf == NULL)
1952 buf = find_buffer(tv);
1953
1954 return buf;
1955}
1956
1957/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001958 * Get the buffer from "arg" and give an error and return NULL if it is not
1959 * valid.
1960 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001961 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001962get_buf_arg(typval_T *arg)
1963{
1964 buf_T *buf;
1965
1966 ++emsg_off;
1967 buf = tv_get_buf(arg, FALSE);
1968 --emsg_off;
1969 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001970 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001971 return buf;
1972}
1973
1974/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001975 * "bufname(expr)" function
1976 */
1977 static void
1978f_bufname(typval_T *argvars, typval_T *rettv)
1979{
1980 buf_T *buf;
1981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001982 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001983 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001984 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 rettv->v_type = VAR_STRING;
1986 if (buf != NULL && buf->b_fname != NULL)
1987 rettv->vval.v_string = vim_strsave(buf->b_fname);
1988 else
1989 rettv->vval.v_string = NULL;
1990 --emsg_off;
1991}
1992
1993/*
1994 * "bufnr(expr)" function
1995 */
1996 static void
1997f_bufnr(typval_T *argvars, typval_T *rettv)
1998{
1999 buf_T *buf;
2000 int error = FALSE;
2001 char_u *name;
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], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 --emsg_off;
2007
2008 /* If the buffer isn't found and the second argument is not zero create a
2009 * new buffer. */
2010 if (buf == NULL
2011 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002012 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002014 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002015 && !error)
2016 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2017
2018 if (buf != NULL)
2019 rettv->vval.v_number = buf->b_fnum;
2020 else
2021 rettv->vval.v_number = -1;
2022}
2023
2024 static void
2025buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2026{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002027 win_T *wp;
2028 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002029 buf_T *buf;
2030
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002031 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002033 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002034 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 {
2036 ++winnr;
2037 if (wp->w_buffer == buf)
2038 break;
2039 }
2040 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041 --emsg_off;
2042}
2043
2044/*
2045 * "bufwinid(nr)" function
2046 */
2047 static void
2048f_bufwinid(typval_T *argvars, typval_T *rettv)
2049{
2050 buf_win_common(argvars, rettv, FALSE);
2051}
2052
2053/*
2054 * "bufwinnr(nr)" function
2055 */
2056 static void
2057f_bufwinnr(typval_T *argvars, typval_T *rettv)
2058{
2059 buf_win_common(argvars, rettv, TRUE);
2060}
2061
2062/*
2063 * "byte2line(byte)" function
2064 */
2065 static void
2066f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2067{
2068#ifndef FEAT_BYTEOFF
2069 rettv->vval.v_number = -1;
2070#else
2071 long boff = 0;
2072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002073 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002074 if (boff < 0)
2075 rettv->vval.v_number = -1;
2076 else
2077 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2078 (linenr_T)0, &boff);
2079#endif
2080}
2081
2082 static void
2083byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2084{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 char_u *str;
2087 varnumber_T idx;
2088
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002089 str = tv_get_string_chk(&argvars[0]);
2090 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002091 rettv->vval.v_number = -1;
2092 if (str == NULL || idx < 0)
2093 return;
2094
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 t = str;
2096 for ( ; idx > 0; idx--)
2097 {
2098 if (*t == NUL) /* EOL reached */
2099 return;
2100 if (enc_utf8 && comp)
2101 t += utf_ptr2len(t);
2102 else
2103 t += (*mb_ptr2len)(t);
2104 }
2105 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106}
2107
2108/*
2109 * "byteidx()" function
2110 */
2111 static void
2112f_byteidx(typval_T *argvars, typval_T *rettv)
2113{
2114 byteidx(argvars, rettv, FALSE);
2115}
2116
2117/*
2118 * "byteidxcomp()" function
2119 */
2120 static void
2121f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2122{
2123 byteidx(argvars, rettv, TRUE);
2124}
2125
2126/*
2127 * "call(func, arglist [, dict])" function
2128 */
2129 static void
2130f_call(typval_T *argvars, typval_T *rettv)
2131{
2132 char_u *func;
2133 partial_T *partial = NULL;
2134 dict_T *selfdict = NULL;
2135
2136 if (argvars[1].v_type != VAR_LIST)
2137 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002138 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002139 return;
2140 }
2141 if (argvars[1].vval.v_list == NULL)
2142 return;
2143
2144 if (argvars[0].v_type == VAR_FUNC)
2145 func = argvars[0].vval.v_string;
2146 else if (argvars[0].v_type == VAR_PARTIAL)
2147 {
2148 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002149 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150 }
2151 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002152 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 if (*func == NUL)
2154 return; /* type error or empty name */
2155
2156 if (argvars[2].v_type != VAR_UNKNOWN)
2157 {
2158 if (argvars[2].v_type != VAR_DICT)
2159 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002160 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 return;
2162 }
2163 selfdict = argvars[2].vval.v_dict;
2164 }
2165
2166 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2167}
2168
2169#ifdef FEAT_FLOAT
2170/*
2171 * "ceil({float})" function
2172 */
2173 static void
2174f_ceil(typval_T *argvars, typval_T *rettv)
2175{
2176 float_T f = 0.0;
2177
2178 rettv->v_type = VAR_FLOAT;
2179 if (get_float_arg(argvars, &f) == OK)
2180 rettv->vval.v_float = ceil(f);
2181 else
2182 rettv->vval.v_float = 0.0;
2183}
2184#endif
2185
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002186/*
2187 * "changenr()" function
2188 */
2189 static void
2190f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2191{
2192 rettv->vval.v_number = curbuf->b_u_seq_cur;
2193}
2194
2195/*
2196 * "char2nr(string)" function
2197 */
2198 static void
2199f_char2nr(typval_T *argvars, typval_T *rettv)
2200{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201 if (has_mbyte)
2202 {
2203 int utf8 = 0;
2204
2205 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002206 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207
2208 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002209 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002211 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 }
2213 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002214 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002215}
2216
2217/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002218 * "chdir(dir)" function
2219 */
2220 static void
2221f_chdir(typval_T *argvars, typval_T *rettv)
2222{
2223 char_u *cwd;
2224 cdscope_T scope = CDSCOPE_GLOBAL;
2225
2226 rettv->v_type = VAR_STRING;
2227 rettv->vval.v_string = NULL;
2228
2229 if (argvars[0].v_type != VAR_STRING)
2230 return;
2231
2232 // Return the current directory
2233 cwd = alloc(MAXPATHL);
2234 if (cwd != NULL)
2235 {
2236 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2237 {
2238#ifdef BACKSLASH_IN_FILENAME
2239 slash_adjust(cwd);
2240#endif
2241 rettv->vval.v_string = vim_strsave(cwd);
2242 }
2243 vim_free(cwd);
2244 }
2245
2246 if (curwin->w_localdir != NULL)
2247 scope = CDSCOPE_WINDOW;
2248 else if (curtab->tp_localdir != NULL)
2249 scope = CDSCOPE_TABPAGE;
2250
2251 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2252 // Directory change failed
2253 VIM_CLEAR(rettv->vval.v_string);
2254}
2255
2256/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002257 * "cindent(lnum)" function
2258 */
2259 static void
2260f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2261{
2262#ifdef FEAT_CINDENT
2263 pos_T pos;
2264 linenr_T lnum;
2265
2266 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002267 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2269 {
2270 curwin->w_cursor.lnum = lnum;
2271 rettv->vval.v_number = get_c_indent();
2272 curwin->w_cursor = pos;
2273 }
2274 else
2275#endif
2276 rettv->vval.v_number = -1;
2277}
2278
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002279 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002280get_optional_window(typval_T *argvars, int idx)
2281{
2282 win_T *win = curwin;
2283
2284 if (argvars[idx].v_type != VAR_UNKNOWN)
2285 {
2286 win = find_win_by_nr_or_id(&argvars[idx]);
2287 if (win == NULL)
2288 {
2289 emsg(_(e_invalwindow));
2290 return NULL;
2291 }
2292 }
2293 return win;
2294}
2295
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 * "col(string)" function
2298 */
2299 static void
2300f_col(typval_T *argvars, typval_T *rettv)
2301{
2302 colnr_T col = 0;
2303 pos_T *fp;
2304 int fnum = curbuf->b_fnum;
2305
2306 fp = var2fpos(&argvars[0], FALSE, &fnum);
2307 if (fp != NULL && fnum == curbuf->b_fnum)
2308 {
2309 if (fp->col == MAXCOL)
2310 {
2311 /* '> can be MAXCOL, get the length of the line then */
2312 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2313 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2314 else
2315 col = MAXCOL;
2316 }
2317 else
2318 {
2319 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002320 /* col(".") when the cursor is on the NUL at the end of the line
2321 * because of "coladd" can be seen as an extra column. */
2322 if (virtual_active() && fp == &curwin->w_cursor)
2323 {
2324 char_u *p = ml_get_cursor();
2325
2326 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2327 curwin->w_virtcol - curwin->w_cursor.coladd))
2328 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002329 int l;
2330
2331 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2332 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002333 }
2334 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335 }
2336 }
2337 rettv->vval.v_number = col;
2338}
2339
2340#if defined(FEAT_INS_EXPAND)
2341/*
2342 * "complete()" function
2343 */
2344 static void
2345f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2346{
2347 int startcol;
2348
2349 if ((State & INSERT) == 0)
2350 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002351 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002352 return;
2353 }
2354
2355 /* Check for undo allowed here, because if something was already inserted
2356 * the line was already saved for undo and this check isn't done. */
2357 if (!undo_allowed())
2358 return;
2359
2360 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2361 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002362 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 return;
2364 }
2365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002366 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 if (startcol <= 0)
2368 return;
2369
2370 set_completion(startcol - 1, argvars[1].vval.v_list);
2371}
2372
2373/*
2374 * "complete_add()" function
2375 */
2376 static void
2377f_complete_add(typval_T *argvars, typval_T *rettv)
2378{
2379 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2380}
2381
2382/*
2383 * "complete_check()" function
2384 */
2385 static void
2386f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2387{
2388 int saved = RedrawingDisabled;
2389
2390 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002391 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002392 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002393 RedrawingDisabled = saved;
2394}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002395
2396/*
2397 * "complete_info()" function
2398 */
2399 static void
2400f_complete_info(typval_T *argvars, typval_T *rettv)
2401{
2402 list_T *what_list = NULL;
2403
2404 if (rettv_dict_alloc(rettv) != OK)
2405 return;
2406
2407 if (argvars[0].v_type != VAR_UNKNOWN)
2408 {
2409 if (argvars[0].v_type != VAR_LIST)
2410 {
2411 emsg(_(e_listreq));
2412 return;
2413 }
2414 what_list = argvars[0].vval.v_list;
2415 }
2416 get_complete_info(what_list, rettv->vval.v_dict);
2417}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002418#endif
2419
2420/*
2421 * "confirm(message, buttons[, default [, type]])" function
2422 */
2423 static void
2424f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2425{
2426#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2427 char_u *message;
2428 char_u *buttons = NULL;
2429 char_u buf[NUMBUFLEN];
2430 char_u buf2[NUMBUFLEN];
2431 int def = 1;
2432 int type = VIM_GENERIC;
2433 char_u *typestr;
2434 int error = FALSE;
2435
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002436 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 if (message == NULL)
2438 error = TRUE;
2439 if (argvars[1].v_type != VAR_UNKNOWN)
2440 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002441 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 if (buttons == NULL)
2443 error = TRUE;
2444 if (argvars[2].v_type != VAR_UNKNOWN)
2445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002446 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 if (argvars[3].v_type != VAR_UNKNOWN)
2448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (typestr == NULL)
2451 error = TRUE;
2452 else
2453 {
2454 switch (TOUPPER_ASC(*typestr))
2455 {
2456 case 'E': type = VIM_ERROR; break;
2457 case 'Q': type = VIM_QUESTION; break;
2458 case 'I': type = VIM_INFO; break;
2459 case 'W': type = VIM_WARNING; break;
2460 case 'G': type = VIM_GENERIC; break;
2461 }
2462 }
2463 }
2464 }
2465 }
2466
2467 if (buttons == NULL || *buttons == NUL)
2468 buttons = (char_u *)_("&Ok");
2469
2470 if (!error)
2471 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2472 def, NULL, FALSE);
2473#endif
2474}
2475
2476/*
2477 * "copy()" function
2478 */
2479 static void
2480f_copy(typval_T *argvars, typval_T *rettv)
2481{
2482 item_copy(&argvars[0], rettv, FALSE, 0);
2483}
2484
2485#ifdef FEAT_FLOAT
2486/*
2487 * "cos()" function
2488 */
2489 static void
2490f_cos(typval_T *argvars, typval_T *rettv)
2491{
2492 float_T f = 0.0;
2493
2494 rettv->v_type = VAR_FLOAT;
2495 if (get_float_arg(argvars, &f) == OK)
2496 rettv->vval.v_float = cos(f);
2497 else
2498 rettv->vval.v_float = 0.0;
2499}
2500
2501/*
2502 * "cosh()" function
2503 */
2504 static void
2505f_cosh(typval_T *argvars, typval_T *rettv)
2506{
2507 float_T f = 0.0;
2508
2509 rettv->v_type = VAR_FLOAT;
2510 if (get_float_arg(argvars, &f) == OK)
2511 rettv->vval.v_float = cosh(f);
2512 else
2513 rettv->vval.v_float = 0.0;
2514}
2515#endif
2516
2517/*
2518 * "count()" function
2519 */
2520 static void
2521f_count(typval_T *argvars, typval_T *rettv)
2522{
2523 long n = 0;
2524 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002525 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526
Bram Moolenaar9966b212017-07-28 16:46:57 +02002527 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002528 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002529
2530 if (argvars[0].v_type == VAR_STRING)
2531 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002532 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002533 char_u *p = argvars[0].vval.v_string;
2534 char_u *next;
2535
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002536 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002537 {
2538 if (ic)
2539 {
2540 size_t len = STRLEN(expr);
2541
2542 while (*p != NUL)
2543 {
2544 if (MB_STRNICMP(p, expr, len) == 0)
2545 {
2546 ++n;
2547 p += len;
2548 }
2549 else
2550 MB_PTR_ADV(p);
2551 }
2552 }
2553 else
2554 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2555 != NULL)
2556 {
2557 ++n;
2558 p = next + STRLEN(expr);
2559 }
2560 }
2561
2562 }
2563 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002564 {
2565 listitem_T *li;
2566 list_T *l;
2567 long idx;
2568
2569 if ((l = argvars[0].vval.v_list) != NULL)
2570 {
2571 li = l->lv_first;
2572 if (argvars[2].v_type != VAR_UNKNOWN)
2573 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 if (argvars[3].v_type != VAR_UNKNOWN)
2575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002576 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 if (!error)
2578 {
2579 li = list_find(l, idx);
2580 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002581 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 }
2583 }
2584 if (error)
2585 li = NULL;
2586 }
2587
2588 for ( ; li != NULL; li = li->li_next)
2589 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2590 ++n;
2591 }
2592 }
2593 else if (argvars[0].v_type == VAR_DICT)
2594 {
2595 int todo;
2596 dict_T *d;
2597 hashitem_T *hi;
2598
2599 if ((d = argvars[0].vval.v_dict) != NULL)
2600 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 if (argvars[2].v_type != VAR_UNKNOWN)
2602 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002604 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605 }
2606
2607 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2608 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2609 {
2610 if (!HASHITEM_EMPTY(hi))
2611 {
2612 --todo;
2613 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2614 ++n;
2615 }
2616 }
2617 }
2618 }
2619 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002620 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 rettv->vval.v_number = n;
2622}
2623
2624/*
2625 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2626 *
2627 * Checks the existence of a cscope connection.
2628 */
2629 static void
2630f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2631{
2632#ifdef FEAT_CSCOPE
2633 int num = 0;
2634 char_u *dbpath = NULL;
2635 char_u *prepend = NULL;
2636 char_u buf[NUMBUFLEN];
2637
2638 if (argvars[0].v_type != VAR_UNKNOWN
2639 && argvars[1].v_type != VAR_UNKNOWN)
2640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002641 num = (int)tv_get_number(&argvars[0]);
2642 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002644 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002645 }
2646
2647 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2648#endif
2649}
2650
2651/*
2652 * "cursor(lnum, col)" function, or
2653 * "cursor(list)"
2654 *
2655 * Moves the cursor to the specified line and column.
2656 * Returns 0 when the position could be set, -1 otherwise.
2657 */
2658 static void
2659f_cursor(typval_T *argvars, typval_T *rettv)
2660{
2661 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002662 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 int set_curswant = TRUE;
2664
2665 rettv->vval.v_number = -1;
2666 if (argvars[1].v_type == VAR_UNKNOWN)
2667 {
2668 pos_T pos;
2669 colnr_T curswant = -1;
2670
2671 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002673 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 return;
2675 }
2676 line = pos.lnum;
2677 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002678 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 if (curswant >= 0)
2680 {
2681 curwin->w_curswant = curswant - 1;
2682 set_curswant = FALSE;
2683 }
2684 }
2685 else
2686 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002687 line = tv_get_lnum(argvars);
2688 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002690 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002692 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 return; /* type error; errmsg already given */
2694 if (line > 0)
2695 curwin->w_cursor.lnum = line;
2696 if (col > 0)
2697 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002698 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699
2700 /* Make sure the cursor is in a valid position. */
2701 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 /* Correct cursor for multi-byte character. */
2703 if (has_mbyte)
2704 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705
2706 curwin->w_set_curswant = set_curswant;
2707 rettv->vval.v_number = 0;
2708}
2709
Bram Moolenaar4f974752019-02-17 17:44:42 +01002710#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002711/*
2712 * "debugbreak()" function
2713 */
2714 static void
2715f_debugbreak(typval_T *argvars, typval_T *rettv)
2716{
2717 int pid;
2718
2719 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002720 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002721 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002722 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002723 else
2724 {
2725 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2726
2727 if (hProcess != NULL)
2728 {
2729 DebugBreakProcess(hProcess);
2730 CloseHandle(hProcess);
2731 rettv->vval.v_number = OK;
2732 }
2733 }
2734}
2735#endif
2736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002737/*
2738 * "deepcopy()" function
2739 */
2740 static void
2741f_deepcopy(typval_T *argvars, typval_T *rettv)
2742{
2743 int noref = 0;
2744 int copyID;
2745
2746 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002747 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002749 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750 else
2751 {
2752 copyID = get_copyID();
2753 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2754 }
2755}
2756
2757/*
2758 * "delete()" function
2759 */
2760 static void
2761f_delete(typval_T *argvars, typval_T *rettv)
2762{
2763 char_u nbuf[NUMBUFLEN];
2764 char_u *name;
2765 char_u *flags;
2766
2767 rettv->vval.v_number = -1;
2768 if (check_restricted() || check_secure())
2769 return;
2770
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002771 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002772 if (name == NULL || *name == NUL)
2773 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002774 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002775 return;
2776 }
2777
2778 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002779 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 else
2781 flags = (char_u *)"";
2782
2783 if (*flags == NUL)
2784 /* delete a file */
2785 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2786 else if (STRCMP(flags, "d") == 0)
2787 /* delete an empty directory */
2788 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2789 else if (STRCMP(flags, "rf") == 0)
2790 /* delete a directory recursively */
2791 rettv->vval.v_number = delete_recursive(name);
2792 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002793 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002794}
2795
2796/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002797 * "deletebufline()" function
2798 */
2799 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002800f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002801{
2802 buf_T *buf;
2803 linenr_T first, last;
2804 linenr_T lnum;
2805 long count;
2806 int is_curbuf;
2807 buf_T *curbuf_save = NULL;
2808 win_T *curwin_save = NULL;
2809 tabpage_T *tp;
2810 win_T *wp;
2811
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002812 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002813 if (buf == NULL)
2814 {
2815 rettv->vval.v_number = 1; /* FAIL */
2816 return;
2817 }
2818 is_curbuf = buf == curbuf;
2819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002820 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002821 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002822 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002823 else
2824 last = first;
2825
2826 if (buf->b_ml.ml_mfp == NULL || first < 1
2827 || first > buf->b_ml.ml_line_count || last < first)
2828 {
2829 rettv->vval.v_number = 1; /* FAIL */
2830 return;
2831 }
2832
2833 if (!is_curbuf)
2834 {
2835 curbuf_save = curbuf;
2836 curwin_save = curwin;
2837 curbuf = buf;
2838 find_win_for_curbuf();
2839 }
2840 if (last > curbuf->b_ml.ml_line_count)
2841 last = curbuf->b_ml.ml_line_count;
2842 count = last - first + 1;
2843
2844 // When coming here from Insert mode, sync undo, so that this can be
2845 // undone separately from what was previously inserted.
2846 if (u_sync_once == 2)
2847 {
2848 u_sync_once = 1; // notify that u_sync() was called
2849 u_sync(TRUE);
2850 }
2851
2852 if (u_save(first - 1, last + 1) == FAIL)
2853 {
2854 rettv->vval.v_number = 1; /* FAIL */
2855 return;
2856 }
2857
2858 for (lnum = first; lnum <= last; ++lnum)
2859 ml_delete(first, TRUE);
2860
2861 FOR_ALL_TAB_WINDOWS(tp, wp)
2862 if (wp->w_buffer == buf)
2863 {
2864 if (wp->w_cursor.lnum > last)
2865 wp->w_cursor.lnum -= count;
2866 else if (wp->w_cursor.lnum> first)
2867 wp->w_cursor.lnum = first;
2868 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2869 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2870 }
2871 check_cursor_col();
2872 deleted_lines_mark(first, count);
2873
2874 if (!is_curbuf)
2875 {
2876 curbuf = curbuf_save;
2877 curwin = curwin_save;
2878 }
2879}
2880
2881/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882 * "did_filetype()" function
2883 */
2884 static void
2885f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2886{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888}
2889
2890/*
2891 * "diff_filler()" function
2892 */
2893 static void
2894f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2895{
2896#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002897 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002898#endif
2899}
2900
2901/*
2902 * "diff_hlID()" function
2903 */
2904 static void
2905f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2906{
2907#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002908 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002910 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002911 static int fnum = 0;
2912 static int change_start = 0;
2913 static int change_end = 0;
2914 static hlf_T hlID = (hlf_T)0;
2915 int filler_lines;
2916 int col;
2917
2918 if (lnum < 0) /* ignore type error in {lnum} arg */
2919 lnum = 0;
2920 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002921 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 || fnum != curbuf->b_fnum)
2923 {
2924 /* New line, buffer, change: need to get the values. */
2925 filler_lines = diff_check(curwin, lnum);
2926 if (filler_lines < 0)
2927 {
2928 if (filler_lines == -1)
2929 {
2930 change_start = MAXCOL;
2931 change_end = -1;
2932 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2933 hlID = HLF_ADD; /* added line */
2934 else
2935 hlID = HLF_CHD; /* changed line */
2936 }
2937 else
2938 hlID = HLF_ADD; /* added line */
2939 }
2940 else
2941 hlID = (hlf_T)0;
2942 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002943 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944 fnum = curbuf->b_fnum;
2945 }
2946
2947 if (hlID == HLF_CHD || hlID == HLF_TXD)
2948 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002949 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002950 if (col >= change_start && col <= change_end)
2951 hlID = HLF_TXD; /* changed text */
2952 else
2953 hlID = HLF_CHD; /* changed line */
2954 }
2955 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2956#endif
2957}
2958
2959/*
2960 * "empty({expr})" function
2961 */
2962 static void
2963f_empty(typval_T *argvars, typval_T *rettv)
2964{
2965 int n = FALSE;
2966
2967 switch (argvars[0].v_type)
2968 {
2969 case VAR_STRING:
2970 case VAR_FUNC:
2971 n = argvars[0].vval.v_string == NULL
2972 || *argvars[0].vval.v_string == NUL;
2973 break;
2974 case VAR_PARTIAL:
2975 n = FALSE;
2976 break;
2977 case VAR_NUMBER:
2978 n = argvars[0].vval.v_number == 0;
2979 break;
2980 case VAR_FLOAT:
2981#ifdef FEAT_FLOAT
2982 n = argvars[0].vval.v_float == 0.0;
2983 break;
2984#endif
2985 case VAR_LIST:
2986 n = argvars[0].vval.v_list == NULL
2987 || argvars[0].vval.v_list->lv_first == NULL;
2988 break;
2989 case VAR_DICT:
2990 n = argvars[0].vval.v_dict == NULL
2991 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2992 break;
2993 case VAR_SPECIAL:
2994 n = argvars[0].vval.v_number != VVAL_TRUE;
2995 break;
2996
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002997 case VAR_BLOB:
2998 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002999 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3000 break;
3001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003002 case VAR_JOB:
3003#ifdef FEAT_JOB_CHANNEL
3004 n = argvars[0].vval.v_job == NULL
3005 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3006 break;
3007#endif
3008 case VAR_CHANNEL:
3009#ifdef FEAT_JOB_CHANNEL
3010 n = argvars[0].vval.v_channel == NULL
3011 || !channel_is_open(argvars[0].vval.v_channel);
3012 break;
3013#endif
3014 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003015 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 n = TRUE;
3017 break;
3018 }
3019
3020 rettv->vval.v_number = n;
3021}
3022
3023/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003024 * "environ()" function
3025 */
3026 static void
3027f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3028{
3029#if !defined(AMIGA)
3030 int i = 0;
3031 char_u *entry, *value;
3032# ifdef MSWIN
3033 extern wchar_t **_wenviron;
3034# else
3035 extern char **environ;
3036# endif
3037
3038 if (rettv_dict_alloc(rettv) != OK)
3039 return;
3040
3041# ifdef MSWIN
3042 if (*_wenviron == NULL)
3043 return;
3044# else
3045 if (*environ == NULL)
3046 return;
3047# endif
3048
3049 for (i = 0; ; ++i)
3050 {
3051# ifdef MSWIN
3052 short_u *p;
3053
3054 if ((p = (short_u *)_wenviron[i]) == NULL)
3055 return;
3056 entry = utf16_to_enc(p, NULL);
3057# else
3058 if ((entry = (char_u *)environ[i]) == NULL)
3059 return;
3060 entry = vim_strsave(entry);
3061# endif
3062 if (entry == NULL) // out of memory
3063 return;
3064 if ((value = vim_strchr(entry, '=')) == NULL)
3065 {
3066 vim_free(entry);
3067 continue;
3068 }
3069 *value++ = NUL;
3070 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3071 vim_free(entry);
3072 }
3073#endif
3074}
3075
3076/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 * "escape({string}, {chars})" function
3078 */
3079 static void
3080f_escape(typval_T *argvars, typval_T *rettv)
3081{
3082 char_u buf[NUMBUFLEN];
3083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003084 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3085 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 rettv->v_type = VAR_STRING;
3087}
3088
3089/*
3090 * "eval()" function
3091 */
3092 static void
3093f_eval(typval_T *argvars, typval_T *rettv)
3094{
3095 char_u *s, *p;
3096
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003097 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098 if (s != NULL)
3099 s = skipwhite(s);
3100
3101 p = s;
3102 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3103 {
3104 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003105 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003106 need_clr_eos = FALSE;
3107 rettv->v_type = VAR_NUMBER;
3108 rettv->vval.v_number = 0;
3109 }
3110 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003111 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003112}
3113
3114/*
3115 * "eventhandler()" function
3116 */
3117 static void
3118f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3119{
3120 rettv->vval.v_number = vgetc_busy;
3121}
3122
3123/*
3124 * "executable()" function
3125 */
3126 static void
3127f_executable(typval_T *argvars, typval_T *rettv)
3128{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003129 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003130
3131 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003132 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003133}
3134
3135static garray_T redir_execute_ga;
3136
3137/*
3138 * Append "value[value_len]" to the execute() output.
3139 */
3140 void
3141execute_redir_str(char_u *value, int value_len)
3142{
3143 int len;
3144
3145 if (value_len == -1)
3146 len = (int)STRLEN(value); /* Append the entire string */
3147 else
3148 len = value_len; /* Append only "value_len" characters */
3149 if (ga_grow(&redir_execute_ga, len) == OK)
3150 {
3151 mch_memmove((char *)redir_execute_ga.ga_data
3152 + redir_execute_ga.ga_len, value, len);
3153 redir_execute_ga.ga_len += len;
3154 }
3155}
3156
3157/*
3158 * Get next line from a list.
3159 * Called by do_cmdline() to get the next line.
3160 * Returns allocated string, or NULL for end of function.
3161 */
3162
3163 static char_u *
3164get_list_line(
3165 int c UNUSED,
3166 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003167 int indent UNUSED,
3168 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003169{
3170 listitem_T **p = (listitem_T **)cookie;
3171 listitem_T *item = *p;
3172 char_u buf[NUMBUFLEN];
3173 char_u *s;
3174
3175 if (item == NULL)
3176 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003177 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003178 *p = item->li_next;
3179 return s == NULL ? NULL : vim_strsave(s);
3180}
3181
3182/*
3183 * "execute()" function
3184 */
3185 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003186execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003187{
3188 char_u *cmd = NULL;
3189 list_T *list = NULL;
3190 int save_msg_silent = msg_silent;
3191 int save_emsg_silent = emsg_silent;
3192 int save_emsg_noredir = emsg_noredir;
3193 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003194 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003195 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003196 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003197 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198
3199 rettv->vval.v_string = NULL;
3200 rettv->v_type = VAR_STRING;
3201
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003202 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003203 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003204 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003205 if (list == NULL || list->lv_first == NULL)
3206 /* empty list, no commands, empty output */
3207 return;
3208 ++list->lv_refcount;
3209 }
3210 else
3211 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003212 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003213 if (cmd == NULL)
3214 return;
3215 }
3216
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003217 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003218 {
3219 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003220 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003221
3222 if (s == NULL)
3223 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003224 if (*s == NUL)
3225 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003226 if (STRNCMP(s, "silent", 6) == 0)
3227 ++msg_silent;
3228 if (STRCMP(s, "silent!") == 0)
3229 {
3230 emsg_silent = TRUE;
3231 emsg_noredir = TRUE;
3232 }
3233 }
3234 else
3235 ++msg_silent;
3236
3237 if (redir_execute)
3238 save_ga = redir_execute_ga;
3239 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3240 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003241 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003242 if (!echo_output)
3243 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244
3245 if (cmd != NULL)
3246 do_cmdline_cmd(cmd);
3247 else
3248 {
3249 listitem_T *item = list->lv_first;
3250
3251 do_cmdline(NULL, get_list_line, (void *)&item,
3252 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3253 --list->lv_refcount;
3254 }
3255
Bram Moolenaard297f352017-01-29 20:31:21 +01003256 /* Need to append a NUL to the result. */
3257 if (ga_grow(&redir_execute_ga, 1) == OK)
3258 {
3259 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3260 rettv->vval.v_string = redir_execute_ga.ga_data;
3261 }
3262 else
3263 {
3264 ga_clear(&redir_execute_ga);
3265 rettv->vval.v_string = NULL;
3266 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 msg_silent = save_msg_silent;
3268 emsg_silent = save_emsg_silent;
3269 emsg_noredir = save_emsg_noredir;
3270
3271 redir_execute = save_redir_execute;
3272 if (redir_execute)
3273 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003274 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003276 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003277 if (echo_output)
3278 // When not working silently: put it in column zero. A following
3279 // "echon" will overwrite the message, unavoidably.
3280 msg_col = 0;
3281 else
3282 // When working silently: Put it back where it was, since nothing
3283 // should have been written.
3284 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003285}
3286
3287/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003288 * "execute()" function
3289 */
3290 static void
3291f_execute(typval_T *argvars, typval_T *rettv)
3292{
3293 execute_common(argvars, rettv, 0);
3294}
3295
3296/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 * "exepath()" function
3298 */
3299 static void
3300f_exepath(typval_T *argvars, typval_T *rettv)
3301{
3302 char_u *p = NULL;
3303
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003304 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305 rettv->v_type = VAR_STRING;
3306 rettv->vval.v_string = p;
3307}
3308
3309/*
3310 * "exists()" function
3311 */
3312 static void
3313f_exists(typval_T *argvars, typval_T *rettv)
3314{
3315 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003318 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003319 if (*p == '$') /* environment variable */
3320 {
3321 /* first try "normal" environment variables (fast) */
3322 if (mch_getenv(p + 1) != NULL)
3323 n = TRUE;
3324 else
3325 {
3326 /* try expanding things like $VIM and ${HOME} */
3327 p = expand_env_save(p);
3328 if (p != NULL && *p != '$')
3329 n = TRUE;
3330 vim_free(p);
3331 }
3332 }
3333 else if (*p == '&' || *p == '+') /* option */
3334 {
3335 n = (get_option_tv(&p, NULL, TRUE) == OK);
3336 if (*skipwhite(p) != NUL)
3337 n = FALSE; /* trailing garbage */
3338 }
3339 else if (*p == '*') /* internal or user defined function */
3340 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003341 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 }
3343 else if (*p == ':')
3344 {
3345 n = cmd_exists(p + 1);
3346 }
3347 else if (*p == '#')
3348 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003349 if (p[1] == '#')
3350 n = autocmd_supported(p + 2);
3351 else
3352 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003353 }
3354 else /* internal variable */
3355 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003356 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003357 }
3358
3359 rettv->vval.v_number = n;
3360}
3361
3362#ifdef FEAT_FLOAT
3363/*
3364 * "exp()" function
3365 */
3366 static void
3367f_exp(typval_T *argvars, typval_T *rettv)
3368{
3369 float_T f = 0.0;
3370
3371 rettv->v_type = VAR_FLOAT;
3372 if (get_float_arg(argvars, &f) == OK)
3373 rettv->vval.v_float = exp(f);
3374 else
3375 rettv->vval.v_float = 0.0;
3376}
3377#endif
3378
3379/*
3380 * "expand()" function
3381 */
3382 static void
3383f_expand(typval_T *argvars, typval_T *rettv)
3384{
3385 char_u *s;
3386 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003387 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003388 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3389 expand_T xpc;
3390 int error = FALSE;
3391 char_u *result;
3392
3393 rettv->v_type = VAR_STRING;
3394 if (argvars[1].v_type != VAR_UNKNOWN
3395 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003396 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003397 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003398 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003400 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401 if (*s == '%' || *s == '#' || *s == '<')
3402 {
3403 ++emsg_off;
3404 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3405 --emsg_off;
3406 if (rettv->v_type == VAR_LIST)
3407 {
3408 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3409 list_append_string(rettv->vval.v_list, result, -1);
3410 else
3411 vim_free(result);
3412 }
3413 else
3414 rettv->vval.v_string = result;
3415 }
3416 else
3417 {
3418 /* When the optional second argument is non-zero, don't remove matches
3419 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3420 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003421 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 options |= WILD_KEEP_ALL;
3423 if (!error)
3424 {
3425 ExpandInit(&xpc);
3426 xpc.xp_context = EXPAND_FILES;
3427 if (p_wic)
3428 options += WILD_ICASE;
3429 if (rettv->v_type == VAR_STRING)
3430 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3431 options, WILD_ALL);
3432 else if (rettv_list_alloc(rettv) != FAIL)
3433 {
3434 int i;
3435
3436 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3437 for (i = 0; i < xpc.xp_numfiles; i++)
3438 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3439 ExpandCleanup(&xpc);
3440 }
3441 }
3442 else
3443 rettv->vval.v_string = NULL;
3444 }
3445}
3446
3447/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003448 * "expandcmd()" function
3449 * Expand all the special characters in a command string.
3450 */
3451 static void
3452f_expandcmd(typval_T *argvars, typval_T *rettv)
3453{
3454 exarg_T eap;
3455 char_u *cmdstr;
3456 char *errormsg = NULL;
3457
3458 rettv->v_type = VAR_STRING;
3459 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3460
3461 memset(&eap, 0, sizeof(eap));
3462 eap.cmd = cmdstr;
3463 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003464 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003465 eap.usefilter = FALSE;
3466 eap.nextcmd = NULL;
3467 eap.cmdidx = CMD_USER;
3468
3469 expand_filename(&eap, &cmdstr, &errormsg);
3470 if (errormsg != NULL && *errormsg != NUL)
3471 emsg(errormsg);
3472
3473 rettv->vval.v_string = cmdstr;
3474}
3475
3476/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477 * "extend(list, list [, idx])" function
3478 * "extend(dict, dict [, action])" function
3479 */
3480 static void
3481f_extend(typval_T *argvars, typval_T *rettv)
3482{
3483 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3484
3485 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3486 {
3487 list_T *l1, *l2;
3488 listitem_T *item;
3489 long before;
3490 int error = FALSE;
3491
3492 l1 = argvars[0].vval.v_list;
3493 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003494 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495 && l2 != NULL)
3496 {
3497 if (argvars[2].v_type != VAR_UNKNOWN)
3498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003499 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500 if (error)
3501 return; /* type error; errmsg already given */
3502
3503 if (before == l1->lv_len)
3504 item = NULL;
3505 else
3506 {
3507 item = list_find(l1, before);
3508 if (item == NULL)
3509 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003510 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511 return;
3512 }
3513 }
3514 }
3515 else
3516 item = NULL;
3517 list_extend(l1, l2, item);
3518
3519 copy_tv(&argvars[0], rettv);
3520 }
3521 }
3522 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3523 {
3524 dict_T *d1, *d2;
3525 char_u *action;
3526 int i;
3527
3528 d1 = argvars[0].vval.v_dict;
3529 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003530 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003531 && d2 != NULL)
3532 {
3533 /* Check the third argument. */
3534 if (argvars[2].v_type != VAR_UNKNOWN)
3535 {
3536 static char *(av[]) = {"keep", "force", "error"};
3537
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003538 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003539 if (action == NULL)
3540 return; /* type error; errmsg already given */
3541 for (i = 0; i < 3; ++i)
3542 if (STRCMP(action, av[i]) == 0)
3543 break;
3544 if (i == 3)
3545 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003546 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003547 return;
3548 }
3549 }
3550 else
3551 action = (char_u *)"force";
3552
3553 dict_extend(d1, d2, action);
3554
3555 copy_tv(&argvars[0], rettv);
3556 }
3557 }
3558 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003559 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003560}
3561
3562/*
3563 * "feedkeys()" function
3564 */
3565 static void
3566f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3567{
3568 int remap = TRUE;
3569 int insert = FALSE;
3570 char_u *keys, *flags;
3571 char_u nbuf[NUMBUFLEN];
3572 int typed = FALSE;
3573 int execute = FALSE;
3574 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003575 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576 char_u *keys_esc;
3577
3578 /* This is not allowed in the sandbox. If the commands would still be
3579 * executed in the sandbox it would be OK, but it probably happens later,
3580 * when "sandbox" is no longer set. */
3581 if (check_secure())
3582 return;
3583
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003584 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585
3586 if (argvars[1].v_type != VAR_UNKNOWN)
3587 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003588 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589 for ( ; *flags != NUL; ++flags)
3590 {
3591 switch (*flags)
3592 {
3593 case 'n': remap = FALSE; break;
3594 case 'm': remap = TRUE; break;
3595 case 't': typed = TRUE; break;
3596 case 'i': insert = TRUE; break;
3597 case 'x': execute = TRUE; break;
3598 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003599 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600 }
3601 }
3602 }
3603
3604 if (*keys != NUL || execute)
3605 {
3606 /* Need to escape K_SPECIAL and CSI before putting the string in the
3607 * typeahead buffer. */
3608 keys_esc = vim_strsave_escape_csi(keys);
3609 if (keys_esc != NULL)
3610 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003611 if (lowlevel)
3612 {
3613#ifdef USE_INPUT_BUF
3614 add_to_input_buf(keys, (int)STRLEN(keys));
3615#else
3616 emsg(_("E980: lowlevel input not supported"));
3617#endif
3618 }
3619 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003620 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003621 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003623 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003624#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003625 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003626#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003627 )
3628 typebuf_was_filled = TRUE;
3629 }
3630 vim_free(keys_esc);
3631
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003632 if (execute)
3633 {
3634 int save_msg_scroll = msg_scroll;
3635
3636 /* Avoid a 1 second delay when the keys start Insert mode. */
3637 msg_scroll = FALSE;
3638
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003639 if (!dangerous)
3640 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003641 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003642 if (!dangerous)
3643 --ex_normal_busy;
3644
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003645 msg_scroll |= save_msg_scroll;
3646 }
3647 }
3648 }
3649}
3650
3651/*
3652 * "filereadable()" function
3653 */
3654 static void
3655f_filereadable(typval_T *argvars, typval_T *rettv)
3656{
3657 int fd;
3658 char_u *p;
3659 int n;
3660
3661#ifndef O_NONBLOCK
3662# define O_NONBLOCK 0
3663#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003664 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003665 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3666 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3667 {
3668 n = TRUE;
3669 close(fd);
3670 }
3671 else
3672 n = FALSE;
3673
3674 rettv->vval.v_number = n;
3675}
3676
3677/*
3678 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3679 * rights to write into.
3680 */
3681 static void
3682f_filewritable(typval_T *argvars, typval_T *rettv)
3683{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003684 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685}
3686
3687 static void
3688findfilendir(
3689 typval_T *argvars UNUSED,
3690 typval_T *rettv,
3691 int find_what UNUSED)
3692{
3693#ifdef FEAT_SEARCHPATH
3694 char_u *fname;
3695 char_u *fresult = NULL;
3696 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3697 char_u *p;
3698 char_u pathbuf[NUMBUFLEN];
3699 int count = 1;
3700 int first = TRUE;
3701 int error = FALSE;
3702#endif
3703
3704 rettv->vval.v_string = NULL;
3705 rettv->v_type = VAR_STRING;
3706
3707#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003708 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709
3710 if (argvars[1].v_type != VAR_UNKNOWN)
3711 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003712 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713 if (p == NULL)
3714 error = TRUE;
3715 else
3716 {
3717 if (*p != NUL)
3718 path = p;
3719
3720 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003721 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722 }
3723 }
3724
3725 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3726 error = TRUE;
3727
3728 if (*fname != NUL && !error)
3729 {
3730 do
3731 {
3732 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3733 vim_free(fresult);
3734 fresult = find_file_in_path_option(first ? fname : NULL,
3735 first ? (int)STRLEN(fname) : 0,
3736 0, first, path,
3737 find_what,
3738 curbuf->b_ffname,
3739 find_what == FINDFILE_DIR
3740 ? (char_u *)"" : curbuf->b_p_sua);
3741 first = FALSE;
3742
3743 if (fresult != NULL && rettv->v_type == VAR_LIST)
3744 list_append_string(rettv->vval.v_list, fresult, -1);
3745
3746 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3747 }
3748
3749 if (rettv->v_type == VAR_STRING)
3750 rettv->vval.v_string = fresult;
3751#endif
3752}
3753
3754/*
3755 * "filter()" function
3756 */
3757 static void
3758f_filter(typval_T *argvars, typval_T *rettv)
3759{
3760 filter_map(argvars, rettv, FALSE);
3761}
3762
3763/*
3764 * "finddir({fname}[, {path}[, {count}]])" function
3765 */
3766 static void
3767f_finddir(typval_T *argvars, typval_T *rettv)
3768{
3769 findfilendir(argvars, rettv, FINDFILE_DIR);
3770}
3771
3772/*
3773 * "findfile({fname}[, {path}[, {count}]])" function
3774 */
3775 static void
3776f_findfile(typval_T *argvars, typval_T *rettv)
3777{
3778 findfilendir(argvars, rettv, FINDFILE_FILE);
3779}
3780
3781#ifdef FEAT_FLOAT
3782/*
3783 * "float2nr({float})" function
3784 */
3785 static void
3786f_float2nr(typval_T *argvars, typval_T *rettv)
3787{
3788 float_T f = 0.0;
3789
3790 if (get_float_arg(argvars, &f) == OK)
3791 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003792 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003793 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003794 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003795 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 else
3797 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003798 }
3799}
3800
3801/*
3802 * "floor({float})" function
3803 */
3804 static void
3805f_floor(typval_T *argvars, typval_T *rettv)
3806{
3807 float_T f = 0.0;
3808
3809 rettv->v_type = VAR_FLOAT;
3810 if (get_float_arg(argvars, &f) == OK)
3811 rettv->vval.v_float = floor(f);
3812 else
3813 rettv->vval.v_float = 0.0;
3814}
3815
3816/*
3817 * "fmod()" function
3818 */
3819 static void
3820f_fmod(typval_T *argvars, typval_T *rettv)
3821{
3822 float_T fx = 0.0, fy = 0.0;
3823
3824 rettv->v_type = VAR_FLOAT;
3825 if (get_float_arg(argvars, &fx) == OK
3826 && get_float_arg(&argvars[1], &fy) == OK)
3827 rettv->vval.v_float = fmod(fx, fy);
3828 else
3829 rettv->vval.v_float = 0.0;
3830}
3831#endif
3832
3833/*
3834 * "fnameescape({string})" function
3835 */
3836 static void
3837f_fnameescape(typval_T *argvars, typval_T *rettv)
3838{
3839 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003840 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003841 rettv->v_type = VAR_STRING;
3842}
3843
3844/*
3845 * "fnamemodify({fname}, {mods})" function
3846 */
3847 static void
3848f_fnamemodify(typval_T *argvars, typval_T *rettv)
3849{
3850 char_u *fname;
3851 char_u *mods;
3852 int usedlen = 0;
3853 int len;
3854 char_u *fbuf = NULL;
3855 char_u buf[NUMBUFLEN];
3856
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003857 fname = tv_get_string_chk(&argvars[0]);
3858 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003859 if (fname == NULL || mods == NULL)
3860 fname = NULL;
3861 else
3862 {
3863 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003864 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003865 }
3866
3867 rettv->v_type = VAR_STRING;
3868 if (fname == NULL)
3869 rettv->vval.v_string = NULL;
3870 else
3871 rettv->vval.v_string = vim_strnsave(fname, len);
3872 vim_free(fbuf);
3873}
3874
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003875/*
3876 * "foldclosed()" function
3877 */
3878 static void
3879foldclosed_both(
3880 typval_T *argvars UNUSED,
3881 typval_T *rettv,
3882 int end UNUSED)
3883{
3884#ifdef FEAT_FOLDING
3885 linenr_T lnum;
3886 linenr_T first, last;
3887
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003888 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3890 {
3891 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3892 {
3893 if (end)
3894 rettv->vval.v_number = (varnumber_T)last;
3895 else
3896 rettv->vval.v_number = (varnumber_T)first;
3897 return;
3898 }
3899 }
3900#endif
3901 rettv->vval.v_number = -1;
3902}
3903
3904/*
3905 * "foldclosed()" function
3906 */
3907 static void
3908f_foldclosed(typval_T *argvars, typval_T *rettv)
3909{
3910 foldclosed_both(argvars, rettv, FALSE);
3911}
3912
3913/*
3914 * "foldclosedend()" function
3915 */
3916 static void
3917f_foldclosedend(typval_T *argvars, typval_T *rettv)
3918{
3919 foldclosed_both(argvars, rettv, TRUE);
3920}
3921
3922/*
3923 * "foldlevel()" function
3924 */
3925 static void
3926f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3927{
3928#ifdef FEAT_FOLDING
3929 linenr_T lnum;
3930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003931 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3933 rettv->vval.v_number = foldLevel(lnum);
3934#endif
3935}
3936
3937/*
3938 * "foldtext()" function
3939 */
3940 static void
3941f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3942{
3943#ifdef FEAT_FOLDING
3944 linenr_T foldstart;
3945 linenr_T foldend;
3946 char_u *dashes;
3947 linenr_T lnum;
3948 char_u *s;
3949 char_u *r;
3950 int len;
3951 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003952 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953#endif
3954
3955 rettv->v_type = VAR_STRING;
3956 rettv->vval.v_string = NULL;
3957#ifdef FEAT_FOLDING
3958 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3959 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3960 dashes = get_vim_var_str(VV_FOLDDASHES);
3961 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3962 && dashes != NULL)
3963 {
3964 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003965 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966 if (!linewhite(lnum))
3967 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003968
3969 /* Find interesting text in this line. */
3970 s = skipwhite(ml_get(lnum));
3971 /* skip C comment-start */
3972 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3973 {
3974 s = skipwhite(s + 2);
3975 if (*skipwhite(s) == NUL
3976 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3977 {
3978 s = skipwhite(ml_get(lnum + 1));
3979 if (*s == '*')
3980 s = skipwhite(s + 1);
3981 }
3982 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003983 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003984 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003985 r = alloc(STRLEN(txt)
3986 + STRLEN(dashes) // for %s
3987 + 20 // for %3ld
3988 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003989 if (r != NULL)
3990 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003991 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003992 len = (int)STRLEN(r);
3993 STRCAT(r, s);
3994 /* remove 'foldmarker' and 'commentstring' */
3995 foldtext_cleanup(r + len);
3996 rettv->vval.v_string = r;
3997 }
3998 }
3999#endif
4000}
4001
4002/*
4003 * "foldtextresult(lnum)" function
4004 */
4005 static void
4006f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4007{
4008#ifdef FEAT_FOLDING
4009 linenr_T lnum;
4010 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004011 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012 foldinfo_T foldinfo;
4013 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004014 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004015#endif
4016
4017 rettv->v_type = VAR_STRING;
4018 rettv->vval.v_string = NULL;
4019#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004020 if (entered)
4021 return; /* reject recursive use */
4022 entered = TRUE;
4023
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004024 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004025 /* treat illegal types and illegal string values for {lnum} the same */
4026 if (lnum < 0)
4027 lnum = 0;
4028 fold_count = foldedCount(curwin, lnum, &foldinfo);
4029 if (fold_count > 0)
4030 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004031 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4032 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 if (text == buf)
4034 text = vim_strsave(text);
4035 rettv->vval.v_string = text;
4036 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004037
4038 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004039#endif
4040}
4041
4042/*
4043 * "foreground()" function
4044 */
4045 static void
4046f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4047{
4048#ifdef FEAT_GUI
4049 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004050 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004052 return;
4053 }
4054#endif
4055#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004056 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057#endif
4058}
4059
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004060 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004061common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004062{
4063 char_u *s;
4064 char_u *name;
4065 int use_string = FALSE;
4066 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004067 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068
4069 if (argvars[0].v_type == VAR_FUNC)
4070 {
4071 /* function(MyFunc, [arg], dict) */
4072 s = argvars[0].vval.v_string;
4073 }
4074 else if (argvars[0].v_type == VAR_PARTIAL
4075 && argvars[0].vval.v_partial != NULL)
4076 {
4077 /* function(dict.MyFunc, [arg]) */
4078 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004079 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 }
4081 else
4082 {
4083 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004084 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004085 use_string = TRUE;
4086 }
4087
Bram Moolenaar843b8842016-08-21 14:36:15 +02004088 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004089 {
4090 name = s;
4091 trans_name = trans_function_name(&name, FALSE,
4092 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4093 if (*name != NUL)
4094 s = NULL;
4095 }
4096
Bram Moolenaar843b8842016-08-21 14:36:15 +02004097 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4098 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004099 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004100 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004101 else if (trans_name != NULL && (is_funcref
4102 ? find_func(trans_name) == NULL
4103 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004104 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105 else
4106 {
4107 int dict_idx = 0;
4108 int arg_idx = 0;
4109 list_T *list = NULL;
4110
4111 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4112 {
4113 char sid_buf[25];
4114 int off = *s == 's' ? 2 : 5;
4115
4116 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4117 * also be called from another script. Using trans_function_name()
4118 * would also work, but some plugins depend on the name being
4119 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004120 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004121 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004122 if (name != NULL)
4123 {
4124 STRCPY(name, sid_buf);
4125 STRCAT(name, s + off);
4126 }
4127 }
4128 else
4129 name = vim_strsave(s);
4130
4131 if (argvars[1].v_type != VAR_UNKNOWN)
4132 {
4133 if (argvars[2].v_type != VAR_UNKNOWN)
4134 {
4135 /* function(name, [args], dict) */
4136 arg_idx = 1;
4137 dict_idx = 2;
4138 }
4139 else if (argvars[1].v_type == VAR_DICT)
4140 /* function(name, dict) */
4141 dict_idx = 1;
4142 else
4143 /* function(name, [args]) */
4144 arg_idx = 1;
4145 if (dict_idx > 0)
4146 {
4147 if (argvars[dict_idx].v_type != VAR_DICT)
4148 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004149 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004151 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004152 }
4153 if (argvars[dict_idx].vval.v_dict == NULL)
4154 dict_idx = 0;
4155 }
4156 if (arg_idx > 0)
4157 {
4158 if (argvars[arg_idx].v_type != VAR_LIST)
4159 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004160 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004162 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163 }
4164 list = argvars[arg_idx].vval.v_list;
4165 if (list == NULL || list->lv_len == 0)
4166 arg_idx = 0;
4167 }
4168 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004169 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004171 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004172
4173 /* result is a VAR_PARTIAL */
4174 if (pt == NULL)
4175 vim_free(name);
4176 else
4177 {
4178 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4179 {
4180 listitem_T *li;
4181 int i = 0;
4182 int arg_len = 0;
4183 int lv_len = 0;
4184
4185 if (arg_pt != NULL)
4186 arg_len = arg_pt->pt_argc;
4187 if (list != NULL)
4188 lv_len = list->lv_len;
4189 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004190 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004191 if (pt->pt_argv == NULL)
4192 {
4193 vim_free(pt);
4194 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004195 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004196 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004197 for (i = 0; i < arg_len; i++)
4198 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4199 if (lv_len > 0)
4200 for (li = list->lv_first; li != NULL;
4201 li = li->li_next)
4202 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 }
4204
4205 /* For "function(dict.func, [], dict)" and "func" is a partial
4206 * use "dict". That is backwards compatible. */
4207 if (dict_idx > 0)
4208 {
4209 /* The dict is bound explicitly, pt_auto is FALSE. */
4210 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4211 ++pt->pt_dict->dv_refcount;
4212 }
4213 else if (arg_pt != NULL)
4214 {
4215 /* If the dict was bound automatically the result is also
4216 * bound automatically. */
4217 pt->pt_dict = arg_pt->pt_dict;
4218 pt->pt_auto = arg_pt->pt_auto;
4219 if (pt->pt_dict != NULL)
4220 ++pt->pt_dict->dv_refcount;
4221 }
4222
4223 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004224 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4225 {
4226 pt->pt_func = arg_pt->pt_func;
4227 func_ptr_ref(pt->pt_func);
4228 vim_free(name);
4229 }
4230 else if (is_funcref)
4231 {
4232 pt->pt_func = find_func(trans_name);
4233 func_ptr_ref(pt->pt_func);
4234 vim_free(name);
4235 }
4236 else
4237 {
4238 pt->pt_name = name;
4239 func_ref(name);
4240 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004241 }
4242 rettv->v_type = VAR_PARTIAL;
4243 rettv->vval.v_partial = pt;
4244 }
4245 else
4246 {
4247 /* result is a VAR_FUNC */
4248 rettv->v_type = VAR_FUNC;
4249 rettv->vval.v_string = name;
4250 func_ref(name);
4251 }
4252 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004253theend:
4254 vim_free(trans_name);
4255}
4256
4257/*
4258 * "funcref()" function
4259 */
4260 static void
4261f_funcref(typval_T *argvars, typval_T *rettv)
4262{
4263 common_function(argvars, rettv, TRUE);
4264}
4265
4266/*
4267 * "function()" function
4268 */
4269 static void
4270f_function(typval_T *argvars, typval_T *rettv)
4271{
4272 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004273}
4274
4275/*
4276 * "garbagecollect()" function
4277 */
4278 static void
4279f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4280{
4281 /* This is postponed until we are back at the toplevel, because we may be
4282 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4283 want_garbage_collect = TRUE;
4284
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004285 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 garbage_collect_at_exit = TRUE;
4287}
4288
4289/*
4290 * "get()" function
4291 */
4292 static void
4293f_get(typval_T *argvars, typval_T *rettv)
4294{
4295 listitem_T *li;
4296 list_T *l;
4297 dictitem_T *di;
4298 dict_T *d;
4299 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004300 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004302 if (argvars[0].v_type == VAR_BLOB)
4303 {
4304 int error = FALSE;
4305 int idx = tv_get_number_chk(&argvars[1], &error);
4306
4307 if (!error)
4308 {
4309 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004310 if (idx < 0)
4311 idx = blob_len(argvars[0].vval.v_blob) + idx;
4312 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4313 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004314 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004315 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004316 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004317 tv = rettv;
4318 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004319 }
4320 }
4321 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004322 {
4323 if ((l = argvars[0].vval.v_list) != NULL)
4324 {
4325 int error = FALSE;
4326
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004327 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004328 if (!error && li != NULL)
4329 tv = &li->li_tv;
4330 }
4331 }
4332 else if (argvars[0].v_type == VAR_DICT)
4333 {
4334 if ((d = argvars[0].vval.v_dict) != NULL)
4335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004336 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004337 if (di != NULL)
4338 tv = &di->di_tv;
4339 }
4340 }
4341 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4342 {
4343 partial_T *pt;
4344 partial_T fref_pt;
4345
4346 if (argvars[0].v_type == VAR_PARTIAL)
4347 pt = argvars[0].vval.v_partial;
4348 else
4349 {
4350 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4351 fref_pt.pt_name = argvars[0].vval.v_string;
4352 pt = &fref_pt;
4353 }
4354
4355 if (pt != NULL)
4356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004357 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004358 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004359
4360 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4361 {
4362 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004363 n = partial_name(pt);
4364 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004365 rettv->vval.v_string = NULL;
4366 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004367 {
4368 rettv->vval.v_string = vim_strsave(n);
4369 if (rettv->v_type == VAR_FUNC)
4370 func_ref(rettv->vval.v_string);
4371 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004372 }
4373 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004374 {
4375 what_is_dict = TRUE;
4376 if (pt->pt_dict != NULL)
4377 rettv_dict_set(rettv, pt->pt_dict);
4378 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 else if (STRCMP(what, "args") == 0)
4380 {
4381 rettv->v_type = VAR_LIST;
4382 if (rettv_list_alloc(rettv) == OK)
4383 {
4384 int i;
4385
4386 for (i = 0; i < pt->pt_argc; ++i)
4387 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4388 }
4389 }
4390 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004391 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004392
4393 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4394 // third argument
4395 if (!what_is_dict)
4396 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 }
4398 }
4399 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004400 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004401
4402 if (tv == NULL)
4403 {
4404 if (argvars[2].v_type != VAR_UNKNOWN)
4405 copy_tv(&argvars[2], rettv);
4406 }
4407 else
4408 copy_tv(tv, rettv);
4409}
4410
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004411/*
4412 * Returns buffer options, variables and other attributes in a dictionary.
4413 */
4414 static dict_T *
4415get_buffer_info(buf_T *buf)
4416{
4417 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004418 tabpage_T *tp;
4419 win_T *wp;
4420 list_T *windows;
4421
4422 dict = dict_alloc();
4423 if (dict == NULL)
4424 return NULL;
4425
Bram Moolenaare0be1672018-07-08 16:50:37 +02004426 dict_add_number(dict, "bufnr", buf->b_fnum);
4427 dict_add_string(dict, "name", buf->b_ffname);
4428 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4429 : buflist_findlnum(buf));
4430 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4431 dict_add_number(dict, "listed", buf->b_p_bl);
4432 dict_add_number(dict, "changed", bufIsChanged(buf));
4433 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4434 dict_add_number(dict, "hidden",
4435 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004436
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004437 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004438 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004439
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004440 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004441 windows = list_alloc();
4442 if (windows != NULL)
4443 {
4444 FOR_ALL_TAB_WINDOWS(tp, wp)
4445 if (wp->w_buffer == buf)
4446 list_append_number(windows, (varnumber_T)wp->w_id);
4447 dict_add_list(dict, "windows", windows);
4448 }
4449
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004450#ifdef FEAT_TEXT_PROP
4451 // List of popup windows displaying this buffer
4452 windows = list_alloc();
4453 if (windows != NULL)
4454 {
4455 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4456 if (wp->w_buffer == buf)
4457 list_append_number(windows, (varnumber_T)wp->w_id);
4458 FOR_ALL_TABPAGES(tp)
4459 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4460 if (wp->w_buffer == buf)
4461 list_append_number(windows, (varnumber_T)wp->w_id);
4462
4463 dict_add_list(dict, "popups", windows);
4464 }
4465#endif
4466
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004467#ifdef FEAT_SIGNS
4468 if (buf->b_signlist != NULL)
4469 {
4470 /* List of signs placed in this buffer */
4471 list_T *signs = list_alloc();
4472 if (signs != NULL)
4473 {
4474 get_buffer_signs(buf, signs);
4475 dict_add_list(dict, "signs", signs);
4476 }
4477 }
4478#endif
4479
4480 return dict;
4481}
4482
4483/*
4484 * "getbufinfo()" function
4485 */
4486 static void
4487f_getbufinfo(typval_T *argvars, typval_T *rettv)
4488{
4489 buf_T *buf = NULL;
4490 buf_T *argbuf = NULL;
4491 dict_T *d;
4492 int filtered = FALSE;
4493 int sel_buflisted = FALSE;
4494 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004495 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004496
4497 if (rettv_list_alloc(rettv) != OK)
4498 return;
4499
4500 /* List of all the buffers or selected buffers */
4501 if (argvars[0].v_type == VAR_DICT)
4502 {
4503 dict_T *sel_d = argvars[0].vval.v_dict;
4504
4505 if (sel_d != NULL)
4506 {
4507 dictitem_T *di;
4508
4509 filtered = TRUE;
4510
4511 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004512 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004513 sel_buflisted = TRUE;
4514
4515 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004516 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004517 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004518
4519 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004520 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004521 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004522 }
4523 }
4524 else if (argvars[0].v_type != VAR_UNKNOWN)
4525 {
4526 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004527 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004528 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004529 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004530 --emsg_off;
4531 if (argbuf == NULL)
4532 return;
4533 }
4534
4535 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004536 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004537 {
4538 if (argbuf != NULL && argbuf != buf)
4539 continue;
4540 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004541 || (sel_buflisted && !buf->b_p_bl)
4542 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004543 continue;
4544
4545 d = get_buffer_info(buf);
4546 if (d != NULL)
4547 list_append_dict(rettv->vval.v_list, d);
4548 if (argbuf != NULL)
4549 return;
4550 }
4551}
4552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553/*
4554 * Get line or list of lines from buffer "buf" into "rettv".
4555 * Return a range (from start to end) of lines in rettv from the specified
4556 * buffer.
4557 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4558 */
4559 static void
4560get_buffer_lines(
4561 buf_T *buf,
4562 linenr_T start,
4563 linenr_T end,
4564 int retlist,
4565 typval_T *rettv)
4566{
4567 char_u *p;
4568
4569 rettv->v_type = VAR_STRING;
4570 rettv->vval.v_string = NULL;
4571 if (retlist && rettv_list_alloc(rettv) == FAIL)
4572 return;
4573
4574 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4575 return;
4576
4577 if (!retlist)
4578 {
4579 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4580 p = ml_get_buf(buf, start, FALSE);
4581 else
4582 p = (char_u *)"";
4583 rettv->vval.v_string = vim_strsave(p);
4584 }
4585 else
4586 {
4587 if (end < start)
4588 return;
4589
4590 if (start < 1)
4591 start = 1;
4592 if (end > buf->b_ml.ml_line_count)
4593 end = buf->b_ml.ml_line_count;
4594 while (start <= end)
4595 if (list_append_string(rettv->vval.v_list,
4596 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4597 break;
4598 }
4599}
4600
4601/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004602 * "getbufline()" function
4603 */
4604 static void
4605f_getbufline(typval_T *argvars, typval_T *rettv)
4606{
4607 linenr_T lnum;
4608 linenr_T end;
4609 buf_T *buf;
4610
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004611 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004612 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004613 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004614 --emsg_off;
4615
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004616 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004617 if (argvars[2].v_type == VAR_UNKNOWN)
4618 end = lnum;
4619 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004620 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004621
4622 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4623}
4624
4625/*
4626 * "getbufvar()" function
4627 */
4628 static void
4629f_getbufvar(typval_T *argvars, typval_T *rettv)
4630{
4631 buf_T *buf;
4632 buf_T *save_curbuf;
4633 char_u *varname;
4634 dictitem_T *v;
4635 int done = FALSE;
4636
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004637 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4638 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004639 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004640 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004641
4642 rettv->v_type = VAR_STRING;
4643 rettv->vval.v_string = NULL;
4644
4645 if (buf != NULL && varname != NULL)
4646 {
4647 /* set curbuf to be our buf, temporarily */
4648 save_curbuf = curbuf;
4649 curbuf = buf;
4650
Bram Moolenaar30567352016-08-27 21:25:44 +02004651 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004652 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004653 if (varname[1] == NUL)
4654 {
4655 /* get all buffer-local options in a dict */
4656 dict_T *opts = get_winbuf_options(TRUE);
4657
4658 if (opts != NULL)
4659 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004660 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004661 done = TRUE;
4662 }
4663 }
4664 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4665 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004666 done = TRUE;
4667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668 else
4669 {
4670 /* Look up the variable. */
4671 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4672 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4673 'b', varname, FALSE);
4674 if (v != NULL)
4675 {
4676 copy_tv(&v->di_tv, rettv);
4677 done = TRUE;
4678 }
4679 }
4680
4681 /* restore previous notion of curbuf */
4682 curbuf = save_curbuf;
4683 }
4684
4685 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4686 /* use the default value */
4687 copy_tv(&argvars[2], rettv);
4688
4689 --emsg_off;
4690}
4691
4692/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004693 * "getchangelist()" function
4694 */
4695 static void
4696f_getchangelist(typval_T *argvars, typval_T *rettv)
4697{
4698#ifdef FEAT_JUMPLIST
4699 buf_T *buf;
4700 int i;
4701 list_T *l;
4702 dict_T *d;
4703#endif
4704
4705 if (rettv_list_alloc(rettv) != OK)
4706 return;
4707
4708#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004709 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004710 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004711 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004712 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004713 if (buf == NULL)
4714 return;
4715
4716 l = list_alloc();
4717 if (l == NULL)
4718 return;
4719
4720 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4721 return;
4722 /*
4723 * The current window change list index tracks only the position in the
4724 * current buffer change list. For other buffers, use the change list
4725 * length as the current index.
4726 */
4727 list_append_number(rettv->vval.v_list,
4728 (varnumber_T)((buf == curwin->w_buffer)
4729 ? curwin->w_changelistidx : buf->b_changelistlen));
4730
4731 for (i = 0; i < buf->b_changelistlen; ++i)
4732 {
4733 if (buf->b_changelist[i].lnum == 0)
4734 continue;
4735 if ((d = dict_alloc()) == NULL)
4736 return;
4737 if (list_append_dict(l, d) == FAIL)
4738 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004739 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4740 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004741 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004742 }
4743#endif
4744}
4745/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 * "getchar()" function
4747 */
4748 static void
4749f_getchar(typval_T *argvars, typval_T *rettv)
4750{
4751 varnumber_T n;
4752 int error = FALSE;
4753
Bram Moolenaar84d93902018-09-11 20:10:20 +02004754#ifdef MESSAGE_QUEUE
4755 // vpeekc() used to check for messages, but that caused problems, invoking
4756 // a callback where it was not expected. Some plugins use getchar(1) in a
4757 // loop to await a message, therefore make sure we check for messages here.
4758 parse_queued_messages();
4759#endif
4760
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761 /* Position the cursor. Needed after a message that ends in a space. */
4762 windgoto(msg_row, msg_col);
4763
4764 ++no_mapping;
4765 ++allow_keys;
4766 for (;;)
4767 {
4768 if (argvars[0].v_type == VAR_UNKNOWN)
4769 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004770 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004771 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004772 /* getchar(1): only check if char avail */
4773 n = vpeekc_any();
4774 else if (error || vpeekc_any() == NUL)
4775 /* illegal argument or getchar(0) and no char avail: return zero */
4776 n = 0;
4777 else
4778 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004779 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004780
4781 if (n == K_IGNORE)
4782 continue;
4783 break;
4784 }
4785 --no_mapping;
4786 --allow_keys;
4787
4788 set_vim_var_nr(VV_MOUSE_WIN, 0);
4789 set_vim_var_nr(VV_MOUSE_WINID, 0);
4790 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4791 set_vim_var_nr(VV_MOUSE_COL, 0);
4792
4793 rettv->vval.v_number = n;
4794 if (IS_SPECIAL(n) || mod_mask != 0)
4795 {
4796 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4797 int i = 0;
4798
4799 /* Turn a special key into three bytes, plus modifier. */
4800 if (mod_mask != 0)
4801 {
4802 temp[i++] = K_SPECIAL;
4803 temp[i++] = KS_MODIFIER;
4804 temp[i++] = mod_mask;
4805 }
4806 if (IS_SPECIAL(n))
4807 {
4808 temp[i++] = K_SPECIAL;
4809 temp[i++] = K_SECOND(n);
4810 temp[i++] = K_THIRD(n);
4811 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004812 else if (has_mbyte)
4813 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814 else
4815 temp[i++] = n;
4816 temp[i++] = NUL;
4817 rettv->v_type = VAR_STRING;
4818 rettv->vval.v_string = vim_strsave(temp);
4819
4820#ifdef FEAT_MOUSE
4821 if (is_mouse_key(n))
4822 {
4823 int row = mouse_row;
4824 int col = mouse_col;
4825 win_T *win;
4826 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004827 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828 int winnr = 1;
4829
4830 if (row >= 0 && col >= 0)
4831 {
4832 /* Find the window at the mouse coordinates and compute the
4833 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004834 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004835 if (win == NULL)
4836 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004837 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004838# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004839 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004840 winnr = 0;
4841 else
4842# endif
4843 for (wp = firstwin; wp != win && wp != NULL;
4844 wp = wp->w_next)
4845 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004846 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4847 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4848 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4849 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4850 }
4851 }
4852#endif
4853 }
4854}
4855
4856/*
4857 * "getcharmod()" function
4858 */
4859 static void
4860f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4861{
4862 rettv->vval.v_number = mod_mask;
4863}
4864
4865/*
4866 * "getcharsearch()" function
4867 */
4868 static void
4869f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4870{
4871 if (rettv_dict_alloc(rettv) != FAIL)
4872 {
4873 dict_T *dict = rettv->vval.v_dict;
4874
Bram Moolenaare0be1672018-07-08 16:50:37 +02004875 dict_add_string(dict, "char", last_csearch());
4876 dict_add_number(dict, "forward", last_csearch_forward());
4877 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878 }
4879}
4880
4881/*
4882 * "getcmdline()" function
4883 */
4884 static void
4885f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4886{
4887 rettv->v_type = VAR_STRING;
4888 rettv->vval.v_string = get_cmdline_str();
4889}
4890
4891/*
4892 * "getcmdpos()" function
4893 */
4894 static void
4895f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4896{
4897 rettv->vval.v_number = get_cmdline_pos() + 1;
4898}
4899
4900/*
4901 * "getcmdtype()" function
4902 */
4903 static void
4904f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4905{
4906 rettv->v_type = VAR_STRING;
4907 rettv->vval.v_string = alloc(2);
4908 if (rettv->vval.v_string != NULL)
4909 {
4910 rettv->vval.v_string[0] = get_cmdline_type();
4911 rettv->vval.v_string[1] = NUL;
4912 }
4913}
4914
4915/*
4916 * "getcmdwintype()" function
4917 */
4918 static void
4919f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4920{
4921 rettv->v_type = VAR_STRING;
4922 rettv->vval.v_string = NULL;
4923#ifdef FEAT_CMDWIN
4924 rettv->vval.v_string = alloc(2);
4925 if (rettv->vval.v_string != NULL)
4926 {
4927 rettv->vval.v_string[0] = cmdwin_type;
4928 rettv->vval.v_string[1] = NUL;
4929 }
4930#endif
4931}
4932
4933#if defined(FEAT_CMDL_COMPL)
4934/*
4935 * "getcompletion()" function
4936 */
4937 static void
4938f_getcompletion(typval_T *argvars, typval_T *rettv)
4939{
4940 char_u *pat;
4941 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004942 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004943 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4944 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004946 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004947 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004949 if (p_wic)
4950 options |= WILD_ICASE;
4951
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004952 /* For filtered results, 'wildignore' is used */
4953 if (!filtered)
4954 options |= WILD_KEEP_ALL;
4955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004957 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004959 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960 if (xpc.xp_context == EXPAND_NOTHING)
4961 {
4962 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004963 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004964 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004965 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004966 return;
4967 }
4968
4969# if defined(FEAT_MENU)
4970 if (xpc.xp_context == EXPAND_MENUS)
4971 {
4972 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4973 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4974 }
4975# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004976#ifdef FEAT_CSCOPE
4977 if (xpc.xp_context == EXPAND_CSCOPE)
4978 {
4979 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4980 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4981 }
4982#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004983#ifdef FEAT_SIGNS
4984 if (xpc.xp_context == EXPAND_SIGN)
4985 {
4986 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4987 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4988 }
4989#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004990
4991 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4992 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4993 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004994 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004995
4996 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4997
4998 for (i = 0; i < xpc.xp_numfiles; i++)
4999 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5000 }
5001 vim_free(pat);
5002 ExpandCleanup(&xpc);
5003}
5004#endif
5005
5006/*
5007 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005008 *
5009 * Return the current working directory of a window in a tab page.
5010 * First optional argument 'winnr' is the window number or -1 and the second
5011 * optional argument 'tabnr' is the tab page number.
5012 *
5013 * If no arguments are supplied, then return the directory of the current
5014 * window.
5015 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
5016 * the specified window.
5017 * If 'winnr' is 0 then return the directory of the current window.
5018 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
5019 * directory of the specified tab page. Otherwise return the directory of the
5020 * specified window in the specified tab page.
5021 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005022 */
5023 static void
5024f_getcwd(typval_T *argvars, typval_T *rettv)
5025{
5026 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005027 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005028 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005029 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005030
5031 rettv->v_type = VAR_STRING;
5032 rettv->vval.v_string = NULL;
5033
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005034 if (argvars[0].v_type == VAR_NUMBER
5035 && argvars[0].vval.v_number == -1
5036 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005037 global = TRUE;
5038 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005039 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005040
5041 if (wp != NULL && wp->w_localdir != NULL)
5042 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005043 else if (tp != NULL && tp->tp_localdir != NULL)
5044 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5045 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005046 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005047 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048 rettv->vval.v_string = vim_strsave(globaldir);
5049 else
5050 {
5051 cwd = alloc(MAXPATHL);
5052 if (cwd != NULL)
5053 {
5054 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5055 rettv->vval.v_string = vim_strsave(cwd);
5056 vim_free(cwd);
5057 }
5058 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005060#ifdef BACKSLASH_IN_FILENAME
5061 if (rettv->vval.v_string != NULL)
5062 slash_adjust(rettv->vval.v_string);
5063#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005064}
5065
5066/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005067 * "getenv()" function
5068 */
5069 static void
5070f_getenv(typval_T *argvars, typval_T *rettv)
5071{
5072 int mustfree = FALSE;
5073 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5074
5075 if (p == NULL)
5076 {
5077 rettv->v_type = VAR_SPECIAL;
5078 rettv->vval.v_number = VVAL_NULL;
5079 return;
5080 }
5081 if (!mustfree)
5082 p = vim_strsave(p);
5083 rettv->vval.v_string = p;
5084 rettv->v_type = VAR_STRING;
5085}
5086
5087/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 * "getfontname()" function
5089 */
5090 static void
5091f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5092{
5093 rettv->v_type = VAR_STRING;
5094 rettv->vval.v_string = NULL;
5095#ifdef FEAT_GUI
5096 if (gui.in_use)
5097 {
5098 GuiFont font;
5099 char_u *name = NULL;
5100
5101 if (argvars[0].v_type == VAR_UNKNOWN)
5102 {
5103 /* Get the "Normal" font. Either the name saved by
5104 * hl_set_font_name() or from the font ID. */
5105 font = gui.norm_font;
5106 name = hl_get_font_name();
5107 }
5108 else
5109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005110 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5112 return;
5113 font = gui_mch_get_font(name, FALSE);
5114 if (font == NOFONT)
5115 return; /* Invalid font name, return empty string. */
5116 }
5117 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5118 if (argvars[0].v_type != VAR_UNKNOWN)
5119 gui_mch_free_font(font);
5120 }
5121#endif
5122}
5123
5124/*
5125 * "getfperm({fname})" function
5126 */
5127 static void
5128f_getfperm(typval_T *argvars, typval_T *rettv)
5129{
5130 char_u *fname;
5131 stat_T st;
5132 char_u *perm = NULL;
5133 char_u flags[] = "rwx";
5134 int i;
5135
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137
5138 rettv->v_type = VAR_STRING;
5139 if (mch_stat((char *)fname, &st) >= 0)
5140 {
5141 perm = vim_strsave((char_u *)"---------");
5142 if (perm != NULL)
5143 {
5144 for (i = 0; i < 9; i++)
5145 {
5146 if (st.st_mode & (1 << (8 - i)))
5147 perm[i] = flags[i % 3];
5148 }
5149 }
5150 }
5151 rettv->vval.v_string = perm;
5152}
5153
5154/*
5155 * "getfsize({fname})" function
5156 */
5157 static void
5158f_getfsize(typval_T *argvars, typval_T *rettv)
5159{
5160 char_u *fname;
5161 stat_T st;
5162
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005163 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164
5165 rettv->v_type = VAR_NUMBER;
5166
5167 if (mch_stat((char *)fname, &st) >= 0)
5168 {
5169 if (mch_isdir(fname))
5170 rettv->vval.v_number = 0;
5171 else
5172 {
5173 rettv->vval.v_number = (varnumber_T)st.st_size;
5174
5175 /* non-perfect check for overflow */
5176 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5177 rettv->vval.v_number = -2;
5178 }
5179 }
5180 else
5181 rettv->vval.v_number = -1;
5182}
5183
5184/*
5185 * "getftime({fname})" function
5186 */
5187 static void
5188f_getftime(typval_T *argvars, typval_T *rettv)
5189{
5190 char_u *fname;
5191 stat_T st;
5192
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005193 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005194
5195 if (mch_stat((char *)fname, &st) >= 0)
5196 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5197 else
5198 rettv->vval.v_number = -1;
5199}
5200
5201/*
5202 * "getftype({fname})" function
5203 */
5204 static void
5205f_getftype(typval_T *argvars, typval_T *rettv)
5206{
5207 char_u *fname;
5208 stat_T st;
5209 char_u *type = NULL;
5210 char *t;
5211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005212 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213
5214 rettv->v_type = VAR_STRING;
5215 if (mch_lstat((char *)fname, &st) >= 0)
5216 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005217 if (S_ISREG(st.st_mode))
5218 t = "file";
5219 else if (S_ISDIR(st.st_mode))
5220 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005221 else if (S_ISLNK(st.st_mode))
5222 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005223 else if (S_ISBLK(st.st_mode))
5224 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225 else if (S_ISCHR(st.st_mode))
5226 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227 else if (S_ISFIFO(st.st_mode))
5228 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005230 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231 else
5232 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233 type = vim_strsave((char_u *)t);
5234 }
5235 rettv->vval.v_string = type;
5236}
5237
5238/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005239 * "getjumplist()" function
5240 */
5241 static void
5242f_getjumplist(typval_T *argvars, typval_T *rettv)
5243{
5244#ifdef FEAT_JUMPLIST
5245 win_T *wp;
5246 int i;
5247 list_T *l;
5248 dict_T *d;
5249#endif
5250
5251 if (rettv_list_alloc(rettv) != OK)
5252 return;
5253
5254#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005255 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005256 if (wp == NULL)
5257 return;
5258
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005259 cleanup_jumplist(wp, TRUE);
5260
Bram Moolenaar4f505882018-02-10 21:06:32 +01005261 l = list_alloc();
5262 if (l == NULL)
5263 return;
5264
5265 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5266 return;
5267 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5268
5269 for (i = 0; i < wp->w_jumplistlen; ++i)
5270 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005271 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5272 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005273 if ((d = dict_alloc()) == NULL)
5274 return;
5275 if (list_append_dict(l, d) == FAIL)
5276 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005277 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5278 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005279 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005280 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005281 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005282 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005283 }
5284#endif
5285}
5286
5287/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 * "getline(lnum, [end])" function
5289 */
5290 static void
5291f_getline(typval_T *argvars, typval_T *rettv)
5292{
5293 linenr_T lnum;
5294 linenr_T end;
5295 int retlist;
5296
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005297 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 if (argvars[1].v_type == VAR_UNKNOWN)
5299 {
5300 end = 0;
5301 retlist = FALSE;
5302 }
5303 else
5304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005305 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306 retlist = TRUE;
5307 }
5308
5309 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5310}
5311
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005312#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005313 static void
5314get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5315{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005316 if (what_arg->v_type == VAR_UNKNOWN)
5317 {
5318 if (rettv_list_alloc(rettv) == OK)
5319 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005320 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005321 }
5322 else
5323 {
5324 if (rettv_dict_alloc(rettv) == OK)
5325 if (is_qf || (wp != NULL))
5326 {
5327 if (what_arg->v_type == VAR_DICT)
5328 {
5329 dict_T *d = what_arg->vval.v_dict;
5330
5331 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005332 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005333 }
5334 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005335 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005336 }
5337 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005338}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005339#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005340
5341/*
5342 * "getloclist()" function
5343 */
5344 static void
5345f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5346{
5347#ifdef FEAT_QUICKFIX
5348 win_T *wp;
5349
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005350 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005351 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5352#endif
5353}
5354
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005355/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356 * "getpid()" function
5357 */
5358 static void
5359f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5360{
5361 rettv->vval.v_number = mch_get_pid();
5362}
5363
5364 static void
5365getpos_both(
5366 typval_T *argvars,
5367 typval_T *rettv,
5368 int getcurpos)
5369{
5370 pos_T *fp;
5371 list_T *l;
5372 int fnum = -1;
5373
5374 if (rettv_list_alloc(rettv) == OK)
5375 {
5376 l = rettv->vval.v_list;
5377 if (getcurpos)
5378 fp = &curwin->w_cursor;
5379 else
5380 fp = var2fpos(&argvars[0], TRUE, &fnum);
5381 if (fnum != -1)
5382 list_append_number(l, (varnumber_T)fnum);
5383 else
5384 list_append_number(l, (varnumber_T)0);
5385 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5386 : (varnumber_T)0);
5387 list_append_number(l, (fp != NULL)
5388 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5389 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005390 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391 (varnumber_T)0);
5392 if (getcurpos)
5393 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005394 int save_set_curswant = curwin->w_set_curswant;
5395 colnr_T save_curswant = curwin->w_curswant;
5396 colnr_T save_virtcol = curwin->w_virtcol;
5397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005398 update_curswant();
5399 list_append_number(l, curwin->w_curswant == MAXCOL ?
5400 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005401
5402 // Do not change "curswant", as it is unexpected that a get
5403 // function has a side effect.
5404 if (save_set_curswant)
5405 {
5406 curwin->w_set_curswant = save_set_curswant;
5407 curwin->w_curswant = save_curswant;
5408 curwin->w_virtcol = save_virtcol;
5409 curwin->w_valid &= ~VALID_VIRTCOL;
5410 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 }
5412 }
5413 else
5414 rettv->vval.v_number = FALSE;
5415}
5416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417/*
5418 * "getcurpos()" function
5419 */
5420 static void
5421f_getcurpos(typval_T *argvars, typval_T *rettv)
5422{
5423 getpos_both(argvars, rettv, TRUE);
5424}
5425
5426/*
5427 * "getpos(string)" function
5428 */
5429 static void
5430f_getpos(typval_T *argvars, typval_T *rettv)
5431{
5432 getpos_both(argvars, rettv, FALSE);
5433}
5434
5435/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005436 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437 */
5438 static void
5439f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5440{
5441#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005442 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443#endif
5444}
5445
5446/*
5447 * "getreg()" function
5448 */
5449 static void
5450f_getreg(typval_T *argvars, typval_T *rettv)
5451{
5452 char_u *strregname;
5453 int regname;
5454 int arg2 = FALSE;
5455 int return_list = FALSE;
5456 int error = FALSE;
5457
5458 if (argvars[0].v_type != VAR_UNKNOWN)
5459 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005460 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005461 error = strregname == NULL;
5462 if (argvars[1].v_type != VAR_UNKNOWN)
5463 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005464 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005465 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005466 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467 }
5468 }
5469 else
5470 strregname = get_vim_var_str(VV_REG);
5471
5472 if (error)
5473 return;
5474
5475 regname = (strregname == NULL ? '"' : *strregname);
5476 if (regname == 0)
5477 regname = '"';
5478
5479 if (return_list)
5480 {
5481 rettv->v_type = VAR_LIST;
5482 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5483 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5484 if (rettv->vval.v_list == NULL)
5485 (void)rettv_list_alloc(rettv);
5486 else
5487 ++rettv->vval.v_list->lv_refcount;
5488 }
5489 else
5490 {
5491 rettv->v_type = VAR_STRING;
5492 rettv->vval.v_string = get_reg_contents(regname,
5493 arg2 ? GREG_EXPR_SRC : 0);
5494 }
5495}
5496
5497/*
5498 * "getregtype()" function
5499 */
5500 static void
5501f_getregtype(typval_T *argvars, typval_T *rettv)
5502{
5503 char_u *strregname;
5504 int regname;
5505 char_u buf[NUMBUFLEN + 2];
5506 long reglen = 0;
5507
5508 if (argvars[0].v_type != VAR_UNKNOWN)
5509 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005510 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 if (strregname == NULL) /* type error; errmsg already given */
5512 {
5513 rettv->v_type = VAR_STRING;
5514 rettv->vval.v_string = NULL;
5515 return;
5516 }
5517 }
5518 else
5519 /* Default to v:register */
5520 strregname = get_vim_var_str(VV_REG);
5521
5522 regname = (strregname == NULL ? '"' : *strregname);
5523 if (regname == 0)
5524 regname = '"';
5525
5526 buf[0] = NUL;
5527 buf[1] = NUL;
5528 switch (get_reg_type(regname, &reglen))
5529 {
5530 case MLINE: buf[0] = 'V'; break;
5531 case MCHAR: buf[0] = 'v'; break;
5532 case MBLOCK:
5533 buf[0] = Ctrl_V;
5534 sprintf((char *)buf + 1, "%ld", reglen + 1);
5535 break;
5536 }
5537 rettv->v_type = VAR_STRING;
5538 rettv->vval.v_string = vim_strsave(buf);
5539}
5540
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541/*
5542 * Returns information (variables, options, etc.) about a tab page
5543 * as a dictionary.
5544 */
5545 static dict_T *
5546get_tabpage_info(tabpage_T *tp, int tp_idx)
5547{
5548 win_T *wp;
5549 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005550 list_T *l;
5551
5552 dict = dict_alloc();
5553 if (dict == NULL)
5554 return NULL;
5555
Bram Moolenaare0be1672018-07-08 16:50:37 +02005556 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005557
5558 l = list_alloc();
5559 if (l != NULL)
5560 {
5561 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005562 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005563 list_append_number(l, (varnumber_T)wp->w_id);
5564 dict_add_list(dict, "windows", l);
5565 }
5566
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005567 /* Make a reference to tabpage variables */
5568 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005569
5570 return dict;
5571}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005572
5573/*
5574 * "gettabinfo()" function
5575 */
5576 static void
5577f_gettabinfo(typval_T *argvars, typval_T *rettv)
5578{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005579 tabpage_T *tp, *tparg = NULL;
5580 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005581 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005582
5583 if (rettv_list_alloc(rettv) != OK)
5584 return;
5585
5586 if (argvars[0].v_type != VAR_UNKNOWN)
5587 {
5588 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005589 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005590 if (tparg == NULL)
5591 return;
5592 }
5593
5594 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005595 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005596 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005597 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005598 if (tparg != NULL && tp != tparg)
5599 continue;
5600 d = get_tabpage_info(tp, tpnr);
5601 if (d != NULL)
5602 list_append_dict(rettv->vval.v_list, d);
5603 if (tparg != NULL)
5604 return;
5605 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005606}
5607
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005608/*
5609 * "gettabvar()" function
5610 */
5611 static void
5612f_gettabvar(typval_T *argvars, typval_T *rettv)
5613{
5614 win_T *oldcurwin;
5615 tabpage_T *tp, *oldtabpage;
5616 dictitem_T *v;
5617 char_u *varname;
5618 int done = FALSE;
5619
5620 rettv->v_type = VAR_STRING;
5621 rettv->vval.v_string = NULL;
5622
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005623 varname = tv_get_string_chk(&argvars[1]);
5624 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 if (tp != NULL && varname != NULL)
5626 {
5627 /* Set tp to be our tabpage, temporarily. Also set the window to the
5628 * first window in the tabpage, otherwise the window is not valid. */
5629 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005630 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5631 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632 {
5633 /* look up the variable */
5634 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5635 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5636 if (v != NULL)
5637 {
5638 copy_tv(&v->di_tv, rettv);
5639 done = TRUE;
5640 }
5641 }
5642
5643 /* restore previous notion of curwin */
5644 restore_win(oldcurwin, oldtabpage, TRUE);
5645 }
5646
5647 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5648 copy_tv(&argvars[2], rettv);
5649}
5650
5651/*
5652 * "gettabwinvar()" function
5653 */
5654 static void
5655f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5656{
5657 getwinvar(argvars, rettv, 1);
5658}
5659
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005660/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005661 * "gettagstack()" function
5662 */
5663 static void
5664f_gettagstack(typval_T *argvars, typval_T *rettv)
5665{
5666 win_T *wp = curwin; // default is current window
5667
5668 if (rettv_dict_alloc(rettv) != OK)
5669 return;
5670
5671 if (argvars[0].v_type != VAR_UNKNOWN)
5672 {
5673 wp = find_win_by_nr_or_id(&argvars[0]);
5674 if (wp == NULL)
5675 return;
5676 }
5677
5678 get_tagstack(wp, rettv->vval.v_dict);
5679}
5680
5681/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005682 * Returns information about a window as a dictionary.
5683 */
5684 static dict_T *
5685get_win_info(win_T *wp, short tpnr, short winnr)
5686{
5687 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005688
5689 dict = dict_alloc();
5690 if (dict == NULL)
5691 return NULL;
5692
Bram Moolenaare0be1672018-07-08 16:50:37 +02005693 dict_add_number(dict, "tabnr", tpnr);
5694 dict_add_number(dict, "winnr", winnr);
5695 dict_add_number(dict, "winid", wp->w_id);
5696 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005697 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005698 dict_add_number(dict, "topline", wp->w_topline);
5699 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005700#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005701 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005702#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005703 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005704 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005705 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005706
Bram Moolenaar69905d12017-08-13 18:14:47 +02005707#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005708 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005709#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005710#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005711 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5712 dict_add_number(dict, "loclist",
5713 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005714#endif
5715
Bram Moolenaar30567352016-08-27 21:25:44 +02005716 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005717 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005718
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005719 return dict;
5720}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005721
5722/*
5723 * "getwininfo()" function
5724 */
5725 static void
5726f_getwininfo(typval_T *argvars, typval_T *rettv)
5727{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005728 tabpage_T *tp;
5729 win_T *wp = NULL, *wparg = NULL;
5730 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005731 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005732
5733 if (rettv_list_alloc(rettv) != OK)
5734 return;
5735
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005736 if (argvars[0].v_type != VAR_UNKNOWN)
5737 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005738 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005739 if (wparg == NULL)
5740 return;
5741 }
5742
5743 /* Collect information about either all the windows across all the tab
5744 * pages or one particular window.
5745 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005746 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005747 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005748 tabnr++;
5749 winnr = 0;
5750 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005751 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005752 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005753 if (wparg != NULL && wp != wparg)
5754 continue;
5755 d = get_win_info(wp, tabnr, winnr);
5756 if (d != NULL)
5757 list_append_dict(rettv->vval.v_list, d);
5758 if (wparg != NULL)
5759 /* found information about a specific window */
5760 return;
5761 }
5762 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005763}
5764
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005765/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005766 * "win_execute()" function
5767 */
5768 static void
5769f_win_execute(typval_T *argvars, typval_T *rettv)
5770{
5771 int id = (int)tv_get_number(argvars);
5772 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005773 win_T *save_curwin;
5774 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005775
5776 if (wp != NULL)
5777 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005778 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5779 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005780 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005781 check_cursor();
5782 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005783 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005784 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005785 }
5786}
5787
5788/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 * "win_findbuf()" function
5790 */
5791 static void
5792f_win_findbuf(typval_T *argvars, typval_T *rettv)
5793{
5794 if (rettv_list_alloc(rettv) != FAIL)
5795 win_findbuf(argvars, rettv->vval.v_list);
5796}
5797
5798/*
5799 * "win_getid()" function
5800 */
5801 static void
5802f_win_getid(typval_T *argvars, typval_T *rettv)
5803{
5804 rettv->vval.v_number = win_getid(argvars);
5805}
5806
5807/*
5808 * "win_gotoid()" function
5809 */
5810 static void
5811f_win_gotoid(typval_T *argvars, typval_T *rettv)
5812{
5813 rettv->vval.v_number = win_gotoid(argvars);
5814}
5815
5816/*
5817 * "win_id2tabwin()" function
5818 */
5819 static void
5820f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5821{
5822 if (rettv_list_alloc(rettv) != FAIL)
5823 win_id2tabwin(argvars, rettv->vval.v_list);
5824}
5825
5826/*
5827 * "win_id2win()" function
5828 */
5829 static void
5830f_win_id2win(typval_T *argvars, typval_T *rettv)
5831{
5832 rettv->vval.v_number = win_id2win(argvars);
5833}
5834
5835/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005836 * "win_screenpos()" function
5837 */
5838 static void
5839f_win_screenpos(typval_T *argvars, typval_T *rettv)
5840{
5841 win_T *wp;
5842
5843 if (rettv_list_alloc(rettv) == FAIL)
5844 return;
5845
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005846 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005847 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5848 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5849}
5850
5851/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005852 * "getwinpos({timeout})" function
5853 */
5854 static void
5855f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5856{
5857 int x = -1;
5858 int y = -1;
5859
5860 if (rettv_list_alloc(rettv) == FAIL)
5861 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005862#if defined(FEAT_GUI) \
5863 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5864 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005865 {
5866 varnumber_T timeout = 100;
5867
5868 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005869 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005870
5871 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005872 }
5873#endif
5874 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5875 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5876}
5877
5878
5879/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005880 * "getwinposx()" function
5881 */
5882 static void
5883f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5884{
5885 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005886#if defined(FEAT_GUI) \
5887 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5888 || defined(MSWIN)
5889
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005890 {
5891 int x, y;
5892
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005893 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005894 rettv->vval.v_number = x;
5895 }
5896#endif
5897}
5898
5899/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 * "getwinposy()" function
5901 */
5902 static void
5903f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5904{
5905 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005906#if defined(FEAT_GUI) \
5907 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5908 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005909 {
5910 int x, y;
5911
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005912 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005913 rettv->vval.v_number = y;
5914 }
5915#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005916}
5917
5918/*
5919 * "getwinvar()" function
5920 */
5921 static void
5922f_getwinvar(typval_T *argvars, typval_T *rettv)
5923{
5924 getwinvar(argvars, rettv, 0);
5925}
5926
5927/*
5928 * "glob()" function
5929 */
5930 static void
5931f_glob(typval_T *argvars, typval_T *rettv)
5932{
5933 int options = WILD_SILENT|WILD_USE_NL;
5934 expand_T xpc;
5935 int error = FALSE;
5936
5937 /* When the optional second argument is non-zero, don't remove matches
5938 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5939 rettv->v_type = VAR_STRING;
5940 if (argvars[1].v_type != VAR_UNKNOWN)
5941 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005942 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943 options |= WILD_KEEP_ALL;
5944 if (argvars[2].v_type != VAR_UNKNOWN)
5945 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005946 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005947 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005948 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005949 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005950 options |= WILD_ALLLINKS;
5951 }
5952 }
5953 if (!error)
5954 {
5955 ExpandInit(&xpc);
5956 xpc.xp_context = EXPAND_FILES;
5957 if (p_wic)
5958 options += WILD_ICASE;
5959 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005960 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005961 NULL, options, WILD_ALL);
5962 else if (rettv_list_alloc(rettv) != FAIL)
5963 {
5964 int i;
5965
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005966 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005967 NULL, options, WILD_ALL_KEEP);
5968 for (i = 0; i < xpc.xp_numfiles; i++)
5969 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5970
5971 ExpandCleanup(&xpc);
5972 }
5973 }
5974 else
5975 rettv->vval.v_string = NULL;
5976}
5977
5978/*
5979 * "globpath()" function
5980 */
5981 static void
5982f_globpath(typval_T *argvars, typval_T *rettv)
5983{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005984 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005986 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005987 int error = FALSE;
5988 garray_T ga;
5989 int i;
5990
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005991 // When the optional second argument is non-zero, don't remove matches
5992 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 rettv->v_type = VAR_STRING;
5994 if (argvars[2].v_type != VAR_UNKNOWN)
5995 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005996 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 flags |= WILD_KEEP_ALL;
5998 if (argvars[3].v_type != VAR_UNKNOWN)
5999 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006000 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006001 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006003 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 flags |= WILD_ALLLINKS;
6005 }
6006 }
6007 if (file != NULL && !error)
6008 {
6009 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006010 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 if (rettv->v_type == VAR_STRING)
6012 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6013 else if (rettv_list_alloc(rettv) != FAIL)
6014 for (i = 0; i < ga.ga_len; ++i)
6015 list_append_string(rettv->vval.v_list,
6016 ((char_u **)(ga.ga_data))[i], -1);
6017 ga_clear_strings(&ga);
6018 }
6019 else
6020 rettv->vval.v_string = NULL;
6021}
6022
6023/*
6024 * "glob2regpat()" function
6025 */
6026 static void
6027f_glob2regpat(typval_T *argvars, typval_T *rettv)
6028{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006029 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030
6031 rettv->v_type = VAR_STRING;
6032 rettv->vval.v_string = (pat == NULL)
6033 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6034}
6035
6036/* for VIM_VERSION_ defines */
6037#include "version.h"
6038
6039/*
6040 * "has()" function
6041 */
6042 static void
6043f_has(typval_T *argvars, typval_T *rettv)
6044{
6045 int i;
6046 char_u *name;
6047 int n = FALSE;
6048 static char *(has_list[]) =
6049 {
6050#ifdef AMIGA
6051 "amiga",
6052# ifdef FEAT_ARP
6053 "arp",
6054# endif
6055#endif
6056#ifdef __BEOS__
6057 "beos",
6058#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006059#if defined(BSD) && !defined(MACOS_X)
6060 "bsd",
6061#endif
6062#ifdef hpux
6063 "hpux",
6064#endif
6065#ifdef __linux__
6066 "linux",
6067#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006068#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006069 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6070 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006071# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006072 "macunix", /* Mac OS X, with the darwin feature */
6073 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006074# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075#endif
6076#ifdef __QNX__
6077 "qnx",
6078#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006079#ifdef SUN_SYSTEM
6080 "sun",
6081#else
6082 "moon",
6083#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084#ifdef UNIX
6085 "unix",
6086#endif
6087#ifdef VMS
6088 "vms",
6089#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006090#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091 "win32",
6092#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006093#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094 "win32unix",
6095#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006096#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006097 "win64",
6098#endif
6099#ifdef EBCDIC
6100 "ebcdic",
6101#endif
6102#ifndef CASE_INSENSITIVE_FILENAME
6103 "fname_case",
6104#endif
6105#ifdef HAVE_ACL
6106 "acl",
6107#endif
6108#ifdef FEAT_ARABIC
6109 "arabic",
6110#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006111 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006112#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006113 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006114#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006115#ifdef FEAT_AUTOSERVERNAME
6116 "autoservername",
6117#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006118#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006119 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006120# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006121 "balloon_multiline",
6122# endif
6123#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006124#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006125 "balloon_eval_term",
6126#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006127#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6128 "builtin_terms",
6129# ifdef ALL_BUILTIN_TCAPS
6130 "all_builtin_terms",
6131# endif
6132#endif
6133#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006134 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006135 || defined(FEAT_GUI_MOTIF))
6136 "browsefilter",
6137#endif
6138#ifdef FEAT_BYTEOFF
6139 "byte_offset",
6140#endif
6141#ifdef FEAT_JOB_CHANNEL
6142 "channel",
6143#endif
6144#ifdef FEAT_CINDENT
6145 "cindent",
6146#endif
6147#ifdef FEAT_CLIENTSERVER
6148 "clientserver",
6149#endif
6150#ifdef FEAT_CLIPBOARD
6151 "clipboard",
6152#endif
6153#ifdef FEAT_CMDL_COMPL
6154 "cmdline_compl",
6155#endif
6156#ifdef FEAT_CMDHIST
6157 "cmdline_hist",
6158#endif
6159#ifdef FEAT_COMMENTS
6160 "comments",
6161#endif
6162#ifdef FEAT_CONCEAL
6163 "conceal",
6164#endif
6165#ifdef FEAT_CRYPT
6166 "cryptv",
6167 "crypt-blowfish",
6168 "crypt-blowfish2",
6169#endif
6170#ifdef FEAT_CSCOPE
6171 "cscope",
6172#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006173 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174#ifdef CURSOR_SHAPE
6175 "cursorshape",
6176#endif
6177#ifdef DEBUG
6178 "debug",
6179#endif
6180#ifdef FEAT_CON_DIALOG
6181 "dialog_con",
6182#endif
6183#ifdef FEAT_GUI_DIALOG
6184 "dialog_gui",
6185#endif
6186#ifdef FEAT_DIFF
6187 "diff",
6188#endif
6189#ifdef FEAT_DIGRAPHS
6190 "digraphs",
6191#endif
6192#ifdef FEAT_DIRECTX
6193 "directx",
6194#endif
6195#ifdef FEAT_DND
6196 "dnd",
6197#endif
6198#ifdef FEAT_EMACS_TAGS
6199 "emacs_tags",
6200#endif
6201 "eval", /* always present, of course! */
6202 "ex_extra", /* graduated feature */
6203#ifdef FEAT_SEARCH_EXTRA
6204 "extra_search",
6205#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006206#ifdef FEAT_SEARCHPATH
6207 "file_in_path",
6208#endif
6209#ifdef FEAT_FILTERPIPE
6210 "filterpipe",
6211#endif
6212#ifdef FEAT_FIND_ID
6213 "find_in_path",
6214#endif
6215#ifdef FEAT_FLOAT
6216 "float",
6217#endif
6218#ifdef FEAT_FOLDING
6219 "folding",
6220#endif
6221#ifdef FEAT_FOOTER
6222 "footer",
6223#endif
6224#if !defined(USE_SYSTEM) && defined(UNIX)
6225 "fork",
6226#endif
6227#ifdef FEAT_GETTEXT
6228 "gettext",
6229#endif
6230#ifdef FEAT_GUI
6231 "gui",
6232#endif
6233#ifdef FEAT_GUI_ATHENA
6234# ifdef FEAT_GUI_NEXTAW
6235 "gui_neXtaw",
6236# else
6237 "gui_athena",
6238# endif
6239#endif
6240#ifdef FEAT_GUI_GTK
6241 "gui_gtk",
6242# ifdef USE_GTK3
6243 "gui_gtk3",
6244# else
6245 "gui_gtk2",
6246# endif
6247#endif
6248#ifdef FEAT_GUI_GNOME
6249 "gui_gnome",
6250#endif
6251#ifdef FEAT_GUI_MAC
6252 "gui_mac",
6253#endif
6254#ifdef FEAT_GUI_MOTIF
6255 "gui_motif",
6256#endif
6257#ifdef FEAT_GUI_PHOTON
6258 "gui_photon",
6259#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006260#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261 "gui_win32",
6262#endif
6263#ifdef FEAT_HANGULIN
6264 "hangul_input",
6265#endif
6266#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6267 "iconv",
6268#endif
6269#ifdef FEAT_INS_EXPAND
6270 "insert_expand",
6271#endif
6272#ifdef FEAT_JOB_CHANNEL
6273 "job",
6274#endif
6275#ifdef FEAT_JUMPLIST
6276 "jumplist",
6277#endif
6278#ifdef FEAT_KEYMAP
6279 "keymap",
6280#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006281 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282#ifdef FEAT_LANGMAP
6283 "langmap",
6284#endif
6285#ifdef FEAT_LIBCALL
6286 "libcall",
6287#endif
6288#ifdef FEAT_LINEBREAK
6289 "linebreak",
6290#endif
6291#ifdef FEAT_LISP
6292 "lispindent",
6293#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296#ifdef FEAT_LUA
6297# ifndef DYNAMIC_LUA
6298 "lua",
6299# endif
6300#endif
6301#ifdef FEAT_MENU
6302 "menu",
6303#endif
6304#ifdef FEAT_SESSION
6305 "mksession",
6306#endif
6307#ifdef FEAT_MODIFY_FNAME
6308 "modify_fname",
6309#endif
6310#ifdef FEAT_MOUSE
6311 "mouse",
6312#endif
6313#ifdef FEAT_MOUSESHAPE
6314 "mouseshape",
6315#endif
6316#if defined(UNIX) || defined(VMS)
6317# ifdef FEAT_MOUSE_DEC
6318 "mouse_dec",
6319# endif
6320# ifdef FEAT_MOUSE_GPM
6321 "mouse_gpm",
6322# endif
6323# ifdef FEAT_MOUSE_JSB
6324 "mouse_jsbterm",
6325# endif
6326# ifdef FEAT_MOUSE_NET
6327 "mouse_netterm",
6328# endif
6329# ifdef FEAT_MOUSE_PTERM
6330 "mouse_pterm",
6331# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006332# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 "mouse_sgr",
6334# endif
6335# ifdef FEAT_SYSMOUSE
6336 "mouse_sysmouse",
6337# endif
6338# ifdef FEAT_MOUSE_URXVT
6339 "mouse_urxvt",
6340# endif
6341# ifdef FEAT_MOUSE_XTERM
6342 "mouse_xterm",
6343# endif
6344#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346#ifdef FEAT_MBYTE_IME
6347 "multi_byte_ime",
6348#endif
6349#ifdef FEAT_MULTI_LANG
6350 "multi_lang",
6351#endif
6352#ifdef FEAT_MZSCHEME
6353#ifndef DYNAMIC_MZSCHEME
6354 "mzscheme",
6355#endif
6356#endif
6357#ifdef FEAT_NUM64
6358 "num64",
6359#endif
6360#ifdef FEAT_OLE
6361 "ole",
6362#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006363#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006365#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366#ifdef FEAT_PATH_EXTRA
6367 "path_extra",
6368#endif
6369#ifdef FEAT_PERL
6370#ifndef DYNAMIC_PERL
6371 "perl",
6372#endif
6373#endif
6374#ifdef FEAT_PERSISTENT_UNDO
6375 "persistent_undo",
6376#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006377#if defined(FEAT_PYTHON)
6378 "python_compiled",
6379# if defined(DYNAMIC_PYTHON)
6380 "python_dynamic",
6381# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006383 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006384# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006386#if defined(FEAT_PYTHON3)
6387 "python3_compiled",
6388# if defined(DYNAMIC_PYTHON3)
6389 "python3_dynamic",
6390# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006391 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006392 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006393# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394#endif
6395#ifdef FEAT_POSTSCRIPT
6396 "postscript",
6397#endif
6398#ifdef FEAT_PRINTER
6399 "printer",
6400#endif
6401#ifdef FEAT_PROFILE
6402 "profile",
6403#endif
6404#ifdef FEAT_RELTIME
6405 "reltime",
6406#endif
6407#ifdef FEAT_QUICKFIX
6408 "quickfix",
6409#endif
6410#ifdef FEAT_RIGHTLEFT
6411 "rightleft",
6412#endif
6413#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6414 "ruby",
6415#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417#ifdef FEAT_CMDL_INFO
6418 "showcmd",
6419 "cmdline_info",
6420#endif
6421#ifdef FEAT_SIGNS
6422 "signs",
6423#endif
6424#ifdef FEAT_SMARTINDENT
6425 "smartindent",
6426#endif
6427#ifdef STARTUPTIME
6428 "startuptime",
6429#endif
6430#ifdef FEAT_STL_OPT
6431 "statusline",
6432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433#ifdef FEAT_NETBEANS_INTG
6434 "netbeans_intg",
6435#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006436#ifdef FEAT_SOUND
6437 "sound",
6438#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439#ifdef FEAT_SPELL
6440 "spell",
6441#endif
6442#ifdef FEAT_SYN_HL
6443 "syntax",
6444#endif
6445#if defined(USE_SYSTEM) || !defined(UNIX)
6446 "system",
6447#endif
6448#ifdef FEAT_TAG_BINS
6449 "tag_binary",
6450#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451#ifdef FEAT_TCL
6452# ifndef DYNAMIC_TCL
6453 "tcl",
6454# endif
6455#endif
6456#ifdef FEAT_TERMGUICOLORS
6457 "termguicolors",
6458#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006459#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006460 "terminal",
6461#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462#ifdef TERMINFO
6463 "terminfo",
6464#endif
6465#ifdef FEAT_TERMRESPONSE
6466 "termresponse",
6467#endif
6468#ifdef FEAT_TEXTOBJ
6469 "textobjects",
6470#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006471#ifdef FEAT_TEXT_PROP
6472 "textprop",
6473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474#ifdef HAVE_TGETENT
6475 "tgetent",
6476#endif
6477#ifdef FEAT_TIMERS
6478 "timers",
6479#endif
6480#ifdef FEAT_TITLE
6481 "title",
6482#endif
6483#ifdef FEAT_TOOLBAR
6484 "toolbar",
6485#endif
6486#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6487 "unnamedplus",
6488#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 "user-commands", /* was accidentally included in 5.4 */
6490 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006491#ifdef FEAT_VARTABS
6492 "vartabs",
6493#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006494 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495#ifdef FEAT_VIMINFO
6496 "viminfo",
6497#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006498 "vimscript-1",
6499 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006500 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006505#ifdef FEAT_VTP
6506 "vtp",
6507#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508#ifdef FEAT_WILDIGN
6509 "wildignore",
6510#endif
6511#ifdef FEAT_WILDMENU
6512 "wildmenu",
6513#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515#ifdef FEAT_WAK
6516 "winaltkeys",
6517#endif
6518#ifdef FEAT_WRITEBACKUP
6519 "writebackup",
6520#endif
6521#ifdef FEAT_XIM
6522 "xim",
6523#endif
6524#ifdef FEAT_XFONTSET
6525 "xfontset",
6526#endif
6527#ifdef FEAT_XPM_W32
6528 "xpm",
6529 "xpm_w32", /* for backward compatibility */
6530#else
6531# if defined(HAVE_XPM)
6532 "xpm",
6533# endif
6534#endif
6535#ifdef USE_XSMP
6536 "xsmp",
6537#endif
6538#ifdef USE_XSMP_INTERACT
6539 "xsmp_interact",
6540#endif
6541#ifdef FEAT_XCLIPBOARD
6542 "xterm_clipboard",
6543#endif
6544#ifdef FEAT_XTERM_SAVE
6545 "xterm_save",
6546#endif
6547#if defined(UNIX) && defined(FEAT_X11)
6548 "X11",
6549#endif
6550 NULL
6551 };
6552
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006553 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554 for (i = 0; has_list[i] != NULL; ++i)
6555 if (STRICMP(name, has_list[i]) == 0)
6556 {
6557 n = TRUE;
6558 break;
6559 }
6560
6561 if (n == FALSE)
6562 {
6563 if (STRNICMP(name, "patch", 5) == 0)
6564 {
6565 if (name[5] == '-'
6566 && STRLEN(name) >= 11
6567 && vim_isdigit(name[6])
6568 && vim_isdigit(name[8])
6569 && vim_isdigit(name[10]))
6570 {
6571 int major = atoi((char *)name + 6);
6572 int minor = atoi((char *)name + 8);
6573
6574 /* Expect "patch-9.9.01234". */
6575 n = (major < VIM_VERSION_MAJOR
6576 || (major == VIM_VERSION_MAJOR
6577 && (minor < VIM_VERSION_MINOR
6578 || (minor == VIM_VERSION_MINOR
6579 && has_patch(atoi((char *)name + 10))))));
6580 }
6581 else
6582 n = has_patch(atoi((char *)name + 5));
6583 }
6584 else if (STRICMP(name, "vim_starting") == 0)
6585 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006586 else if (STRICMP(name, "ttyin") == 0)
6587 n = mch_input_isatty();
6588 else if (STRICMP(name, "ttyout") == 0)
6589 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 else if (STRICMP(name, "multi_byte_encoding") == 0)
6591 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006592#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 else if (STRICMP(name, "balloon_multiline") == 0)
6594 n = multiline_balloon_available();
6595#endif
6596#ifdef DYNAMIC_TCL
6597 else if (STRICMP(name, "tcl") == 0)
6598 n = tcl_enabled(FALSE);
6599#endif
6600#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6601 else if (STRICMP(name, "iconv") == 0)
6602 n = iconv_enabled(FALSE);
6603#endif
6604#ifdef DYNAMIC_LUA
6605 else if (STRICMP(name, "lua") == 0)
6606 n = lua_enabled(FALSE);
6607#endif
6608#ifdef DYNAMIC_MZSCHEME
6609 else if (STRICMP(name, "mzscheme") == 0)
6610 n = mzscheme_enabled(FALSE);
6611#endif
6612#ifdef DYNAMIC_RUBY
6613 else if (STRICMP(name, "ruby") == 0)
6614 n = ruby_enabled(FALSE);
6615#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616#ifdef DYNAMIC_PYTHON
6617 else if (STRICMP(name, "python") == 0)
6618 n = python_enabled(FALSE);
6619#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620#ifdef DYNAMIC_PYTHON3
6621 else if (STRICMP(name, "python3") == 0)
6622 n = python3_enabled(FALSE);
6623#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006624#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6625 else if (STRICMP(name, "pythonx") == 0)
6626 {
6627# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6628 if (p_pyx == 0)
6629 n = python3_enabled(FALSE) || python_enabled(FALSE);
6630 else if (p_pyx == 3)
6631 n = python3_enabled(FALSE);
6632 else if (p_pyx == 2)
6633 n = python_enabled(FALSE);
6634# elif defined(DYNAMIC_PYTHON)
6635 n = python_enabled(FALSE);
6636# elif defined(DYNAMIC_PYTHON3)
6637 n = python3_enabled(FALSE);
6638# endif
6639 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640#endif
6641#ifdef DYNAMIC_PERL
6642 else if (STRICMP(name, "perl") == 0)
6643 n = perl_enabled(FALSE);
6644#endif
6645#ifdef FEAT_GUI
6646 else if (STRICMP(name, "gui_running") == 0)
6647 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648# ifdef FEAT_BROWSE
6649 else if (STRICMP(name, "browse") == 0)
6650 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6651# endif
6652#endif
6653#ifdef FEAT_SYN_HL
6654 else if (STRICMP(name, "syntax_items") == 0)
6655 n = syntax_present(curwin);
6656#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006657#ifdef FEAT_VTP
6658 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006659 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660#endif
6661#ifdef FEAT_NETBEANS_INTG
6662 else if (STRICMP(name, "netbeans_enabled") == 0)
6663 n = netbeans_active();
6664#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006665#ifdef FEAT_MOUSE_GPM
6666 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6667 n = gpm_enabled();
6668#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006669#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006670 else if (STRICMP(name, "terminal") == 0)
6671 n = terminal_enabled();
6672#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006673#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006674 else if (STRICMP(name, "conpty") == 0)
6675 n = use_conpty();
6676#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 }
6678
6679 rettv->vval.v_number = n;
6680}
6681
6682/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 * "haslocaldir()" function
6684 */
6685 static void
6686f_haslocaldir(typval_T *argvars, typval_T *rettv)
6687{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006688 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 win_T *wp = NULL;
6690
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006691 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6692
6693 // Check for window-local and tab-local directories
6694 if (wp != NULL && wp->w_localdir != NULL)
6695 rettv->vval.v_number = 1;
6696 else if (tp != NULL && tp->tp_localdir != NULL)
6697 rettv->vval.v_number = 2;
6698 else
6699 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700}
6701
6702/*
6703 * "hasmapto()" function
6704 */
6705 static void
6706f_hasmapto(typval_T *argvars, typval_T *rettv)
6707{
6708 char_u *name;
6709 char_u *mode;
6710 char_u buf[NUMBUFLEN];
6711 int abbr = FALSE;
6712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006713 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006714 if (argvars[1].v_type == VAR_UNKNOWN)
6715 mode = (char_u *)"nvo";
6716 else
6717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006718 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006719 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006720 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006721 }
6722
6723 if (map_to_exists(name, mode, abbr))
6724 rettv->vval.v_number = TRUE;
6725 else
6726 rettv->vval.v_number = FALSE;
6727}
6728
6729/*
6730 * "histadd()" function
6731 */
6732 static void
6733f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6734{
6735#ifdef FEAT_CMDHIST
6736 int histype;
6737 char_u *str;
6738 char_u buf[NUMBUFLEN];
6739#endif
6740
6741 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006742 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006743 return;
6744#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006745 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 histype = str != NULL ? get_histtype(str) : -1;
6747 if (histype >= 0)
6748 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006749 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750 if (*str != NUL)
6751 {
6752 init_history();
6753 add_to_history(histype, str, FALSE, NUL);
6754 rettv->vval.v_number = TRUE;
6755 return;
6756 }
6757 }
6758#endif
6759}
6760
6761/*
6762 * "histdel()" function
6763 */
6764 static void
6765f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6766{
6767#ifdef FEAT_CMDHIST
6768 int n;
6769 char_u buf[NUMBUFLEN];
6770 char_u *str;
6771
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006772 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 if (str == NULL)
6774 n = 0;
6775 else if (argvars[1].v_type == VAR_UNKNOWN)
6776 /* only one argument: clear entire history */
6777 n = clr_history(get_histtype(str));
6778 else if (argvars[1].v_type == VAR_NUMBER)
6779 /* index given: remove that entry */
6780 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006781 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 else
6783 /* string given: remove all matching entries */
6784 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006785 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006786 rettv->vval.v_number = n;
6787#endif
6788}
6789
6790/*
6791 * "histget()" function
6792 */
6793 static void
6794f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6795{
6796#ifdef FEAT_CMDHIST
6797 int type;
6798 int idx;
6799 char_u *str;
6800
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006801 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802 if (str == NULL)
6803 rettv->vval.v_string = NULL;
6804 else
6805 {
6806 type = get_histtype(str);
6807 if (argvars[1].v_type == VAR_UNKNOWN)
6808 idx = get_history_idx(type);
6809 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006810 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 /* -1 on type error */
6812 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6813 }
6814#else
6815 rettv->vval.v_string = NULL;
6816#endif
6817 rettv->v_type = VAR_STRING;
6818}
6819
6820/*
6821 * "histnr()" function
6822 */
6823 static void
6824f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6825{
6826 int i;
6827
6828#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006829 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830
6831 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6832 if (i >= HIST_CMD && i < HIST_COUNT)
6833 i = get_history_idx(i);
6834 else
6835#endif
6836 i = -1;
6837 rettv->vval.v_number = i;
6838}
6839
6840/*
6841 * "highlightID(name)" function
6842 */
6843 static void
6844f_hlID(typval_T *argvars, typval_T *rettv)
6845{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006846 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006847}
6848
6849/*
6850 * "highlight_exists()" function
6851 */
6852 static void
6853f_hlexists(typval_T *argvars, typval_T *rettv)
6854{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006855 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856}
6857
6858/*
6859 * "hostname()" function
6860 */
6861 static void
6862f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6863{
6864 char_u hostname[256];
6865
6866 mch_get_host_name(hostname, 256);
6867 rettv->v_type = VAR_STRING;
6868 rettv->vval.v_string = vim_strsave(hostname);
6869}
6870
6871/*
6872 * iconv() function
6873 */
6874 static void
6875f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6876{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 char_u buf1[NUMBUFLEN];
6878 char_u buf2[NUMBUFLEN];
6879 char_u *from, *to, *str;
6880 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006881
6882 rettv->v_type = VAR_STRING;
6883 rettv->vval.v_string = NULL;
6884
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006885 str = tv_get_string(&argvars[0]);
6886 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6887 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 vimconv.vc_type = CONV_NONE;
6889 convert_setup(&vimconv, from, to);
6890
6891 /* If the encodings are equal, no conversion needed. */
6892 if (vimconv.vc_type == CONV_NONE)
6893 rettv->vval.v_string = vim_strsave(str);
6894 else
6895 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6896
6897 convert_setup(&vimconv, NULL, NULL);
6898 vim_free(from);
6899 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006900}
6901
6902/*
6903 * "indent()" function
6904 */
6905 static void
6906f_indent(typval_T *argvars, typval_T *rettv)
6907{
6908 linenr_T lnum;
6909
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006910 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6912 rettv->vval.v_number = get_indent_lnum(lnum);
6913 else
6914 rettv->vval.v_number = -1;
6915}
6916
6917/*
6918 * "index()" function
6919 */
6920 static void
6921f_index(typval_T *argvars, typval_T *rettv)
6922{
6923 list_T *l;
6924 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006925 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 long idx = 0;
6927 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006928 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006929
6930 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006931 if (argvars[0].v_type == VAR_BLOB)
6932 {
6933 typval_T tv;
6934 int start = 0;
6935
6936 if (argvars[2].v_type != VAR_UNKNOWN)
6937 {
6938 start = tv_get_number_chk(&argvars[2], &error);
6939 if (error)
6940 return;
6941 }
6942 b = argvars[0].vval.v_blob;
6943 if (b == NULL)
6944 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006945 if (start < 0)
6946 {
6947 start = blob_len(b) + start;
6948 if (start < 0)
6949 start = 0;
6950 }
6951
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006952 for (idx = start; idx < blob_len(b); ++idx)
6953 {
6954 tv.v_type = VAR_NUMBER;
6955 tv.vval.v_number = blob_get(b, idx);
6956 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6957 {
6958 rettv->vval.v_number = idx;
6959 return;
6960 }
6961 }
6962 return;
6963 }
6964 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006965 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006966 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006967 return;
6968 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 l = argvars[0].vval.v_list;
6971 if (l != NULL)
6972 {
6973 item = l->lv_first;
6974 if (argvars[2].v_type != VAR_UNKNOWN)
6975 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 /* Start at specified item. Use the cached index that list_find()
6977 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006978 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 idx = l->lv_idx;
6980 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006981 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 if (error)
6983 item = NULL;
6984 }
6985
6986 for ( ; item != NULL; item = item->li_next, ++idx)
6987 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6988 {
6989 rettv->vval.v_number = idx;
6990 break;
6991 }
6992 }
6993}
6994
6995static int inputsecret_flag = 0;
6996
6997/*
6998 * "input()" function
6999 * Also handles inputsecret() when inputsecret is set.
7000 */
7001 static void
7002f_input(typval_T *argvars, typval_T *rettv)
7003{
7004 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7005}
7006
7007/*
7008 * "inputdialog()" function
7009 */
7010 static void
7011f_inputdialog(typval_T *argvars, typval_T *rettv)
7012{
7013#if defined(FEAT_GUI_TEXTDIALOG)
7014 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7015 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7016 {
7017 char_u *message;
7018 char_u buf[NUMBUFLEN];
7019 char_u *defstr = (char_u *)"";
7020
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007021 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007022 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007023 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7025 else
7026 IObuff[0] = NUL;
7027 if (message != NULL && defstr != NULL
7028 && do_dialog(VIM_QUESTION, NULL, message,
7029 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7030 rettv->vval.v_string = vim_strsave(IObuff);
7031 else
7032 {
7033 if (message != NULL && defstr != NULL
7034 && argvars[1].v_type != VAR_UNKNOWN
7035 && argvars[2].v_type != VAR_UNKNOWN)
7036 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007037 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 else
7039 rettv->vval.v_string = NULL;
7040 }
7041 rettv->v_type = VAR_STRING;
7042 }
7043 else
7044#endif
7045 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7046}
7047
7048/*
7049 * "inputlist()" function
7050 */
7051 static void
7052f_inputlist(typval_T *argvars, typval_T *rettv)
7053{
7054 listitem_T *li;
7055 int selected;
7056 int mouse_used;
7057
7058#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007059 /* While starting up, there is no place to enter text. When running tests
7060 * with --not-a-term we assume feedkeys() will be used. */
7061 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 return;
7063#endif
7064 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7065 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007066 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067 return;
7068 }
7069
7070 msg_start();
7071 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7072 lines_left = Rows; /* avoid more prompt */
7073 msg_scroll = TRUE;
7074 msg_clr_eos();
7075
7076 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7077 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007078 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007079 msg_putchar('\n');
7080 }
7081
7082 /* Ask for choice. */
7083 selected = prompt_for_number(&mouse_used);
7084 if (mouse_used)
7085 selected -= lines_left;
7086
7087 rettv->vval.v_number = selected;
7088}
7089
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007090static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7091
7092/*
7093 * "inputrestore()" function
7094 */
7095 static void
7096f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7097{
7098 if (ga_userinput.ga_len > 0)
7099 {
7100 --ga_userinput.ga_len;
7101 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7102 + ga_userinput.ga_len);
7103 /* default return is zero == OK */
7104 }
7105 else if (p_verbose > 1)
7106 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007107 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 rettv->vval.v_number = 1; /* Failed */
7109 }
7110}
7111
7112/*
7113 * "inputsave()" function
7114 */
7115 static void
7116f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7117{
7118 /* Add an entry to the stack of typeahead storage. */
7119 if (ga_grow(&ga_userinput, 1) == OK)
7120 {
7121 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7122 + ga_userinput.ga_len);
7123 ++ga_userinput.ga_len;
7124 /* default return is zero == OK */
7125 }
7126 else
7127 rettv->vval.v_number = 1; /* Failed */
7128}
7129
7130/*
7131 * "inputsecret()" function
7132 */
7133 static void
7134f_inputsecret(typval_T *argvars, typval_T *rettv)
7135{
7136 ++cmdline_star;
7137 ++inputsecret_flag;
7138 f_input(argvars, rettv);
7139 --cmdline_star;
7140 --inputsecret_flag;
7141}
7142
7143/*
7144 * "insert()" function
7145 */
7146 static void
7147f_insert(typval_T *argvars, typval_T *rettv)
7148{
7149 long before = 0;
7150 listitem_T *item;
7151 list_T *l;
7152 int error = FALSE;
7153
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007154 if (argvars[0].v_type == VAR_BLOB)
7155 {
7156 int val, len;
7157 char_u *p;
7158
7159 len = blob_len(argvars[0].vval.v_blob);
7160 if (argvars[2].v_type != VAR_UNKNOWN)
7161 {
7162 before = (long)tv_get_number_chk(&argvars[2], &error);
7163 if (error)
7164 return; // type error; errmsg already given
7165 if (before < 0 || before > len)
7166 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007167 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007168 return;
7169 }
7170 }
7171 val = tv_get_number_chk(&argvars[1], &error);
7172 if (error)
7173 return;
7174 if (val < 0 || val > 255)
7175 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007176 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007177 return;
7178 }
7179
7180 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7181 return;
7182 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7183 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7184 *(p + before) = val;
7185 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7186
7187 copy_tv(&argvars[0], rettv);
7188 }
7189 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007190 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007191 else if ((l = argvars[0].vval.v_list) != NULL
7192 && !var_check_lock(l->lv_lock,
7193 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007194 {
7195 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007196 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 if (error)
7198 return; /* type error; errmsg already given */
7199
7200 if (before == l->lv_len)
7201 item = NULL;
7202 else
7203 {
7204 item = list_find(l, before);
7205 if (item == NULL)
7206 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007207 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 l = NULL;
7209 }
7210 }
7211 if (l != NULL)
7212 {
7213 list_insert_tv(l, &argvars[1], item);
7214 copy_tv(&argvars[0], rettv);
7215 }
7216 }
7217}
7218
7219/*
7220 * "invert(expr)" function
7221 */
7222 static void
7223f_invert(typval_T *argvars, typval_T *rettv)
7224{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007225 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007226}
7227
7228/*
7229 * "isdirectory()" function
7230 */
7231 static void
7232f_isdirectory(typval_T *argvars, typval_T *rettv)
7233{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007234 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235}
7236
7237/*
7238 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7239 * or it refers to a List or Dictionary that is locked.
7240 */
7241 static int
7242tv_islocked(typval_T *tv)
7243{
7244 return (tv->v_lock & VAR_LOCKED)
7245 || (tv->v_type == VAR_LIST
7246 && tv->vval.v_list != NULL
7247 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7248 || (tv->v_type == VAR_DICT
7249 && tv->vval.v_dict != NULL
7250 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7251}
7252
7253/*
7254 * "islocked()" function
7255 */
7256 static void
7257f_islocked(typval_T *argvars, typval_T *rettv)
7258{
7259 lval_T lv;
7260 char_u *end;
7261 dictitem_T *di;
7262
7263 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007264 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007265 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 if (end != NULL && lv.ll_name != NULL)
7267 {
7268 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007269 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007270 else
7271 {
7272 if (lv.ll_tv == NULL)
7273 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007274 di = find_var(lv.ll_name, NULL, TRUE);
7275 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007276 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007277 /* Consider a variable locked when:
7278 * 1. the variable itself is locked
7279 * 2. the value of the variable is locked.
7280 * 3. the List or Dict value is locked.
7281 */
7282 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7283 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284 }
7285 }
7286 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007287 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007289 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290 else if (lv.ll_list != NULL)
7291 /* List item. */
7292 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7293 else
7294 /* Dictionary item. */
7295 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7296 }
7297 }
7298
7299 clear_lval(&lv);
7300}
7301
7302#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7303/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007304 * "isinf()" function
7305 */
7306 static void
7307f_isinf(typval_T *argvars, typval_T *rettv)
7308{
7309 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7310 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7311}
7312
7313/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007314 * "isnan()" function
7315 */
7316 static void
7317f_isnan(typval_T *argvars, typval_T *rettv)
7318{
7319 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7320 && isnan(argvars[0].vval.v_float);
7321}
7322#endif
7323
7324/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 * "last_buffer_nr()" function.
7326 */
7327 static void
7328f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7329{
7330 int n = 0;
7331 buf_T *buf;
7332
Bram Moolenaar29323592016-07-24 22:04:11 +02007333 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007334 if (n < buf->b_fnum)
7335 n = buf->b_fnum;
7336
7337 rettv->vval.v_number = n;
7338}
7339
7340/*
7341 * "len()" function
7342 */
7343 static void
7344f_len(typval_T *argvars, typval_T *rettv)
7345{
7346 switch (argvars[0].v_type)
7347 {
7348 case VAR_STRING:
7349 case VAR_NUMBER:
7350 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007351 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007353 case VAR_BLOB:
7354 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7355 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 case VAR_LIST:
7357 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7358 break;
7359 case VAR_DICT:
7360 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7361 break;
7362 case VAR_UNKNOWN:
7363 case VAR_SPECIAL:
7364 case VAR_FLOAT:
7365 case VAR_FUNC:
7366 case VAR_PARTIAL:
7367 case VAR_JOB:
7368 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007369 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 break;
7371 }
7372}
7373
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007375libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376{
7377#ifdef FEAT_LIBCALL
7378 char_u *string_in;
7379 char_u **string_result;
7380 int nr_result;
7381#endif
7382
7383 rettv->v_type = type;
7384 if (type != VAR_NUMBER)
7385 rettv->vval.v_string = NULL;
7386
7387 if (check_restricted() || check_secure())
7388 return;
7389
7390#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007391 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7393 {
7394 string_in = NULL;
7395 if (argvars[2].v_type == VAR_STRING)
7396 string_in = argvars[2].vval.v_string;
7397 if (type == VAR_NUMBER)
7398 string_result = NULL;
7399 else
7400 string_result = &rettv->vval.v_string;
7401 if (mch_libcall(argvars[0].vval.v_string,
7402 argvars[1].vval.v_string,
7403 string_in,
7404 argvars[2].vval.v_number,
7405 string_result,
7406 &nr_result) == OK
7407 && type == VAR_NUMBER)
7408 rettv->vval.v_number = nr_result;
7409 }
7410#endif
7411}
7412
7413/*
7414 * "libcall()" function
7415 */
7416 static void
7417f_libcall(typval_T *argvars, typval_T *rettv)
7418{
7419 libcall_common(argvars, rettv, VAR_STRING);
7420}
7421
7422/*
7423 * "libcallnr()" function
7424 */
7425 static void
7426f_libcallnr(typval_T *argvars, typval_T *rettv)
7427{
7428 libcall_common(argvars, rettv, VAR_NUMBER);
7429}
7430
7431/*
7432 * "line(string)" function
7433 */
7434 static void
7435f_line(typval_T *argvars, typval_T *rettv)
7436{
7437 linenr_T lnum = 0;
7438 pos_T *fp;
7439 int fnum;
7440
7441 fp = var2fpos(&argvars[0], TRUE, &fnum);
7442 if (fp != NULL)
7443 lnum = fp->lnum;
7444 rettv->vval.v_number = lnum;
7445}
7446
7447/*
7448 * "line2byte(lnum)" function
7449 */
7450 static void
7451f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7452{
7453#ifndef FEAT_BYTEOFF
7454 rettv->vval.v_number = -1;
7455#else
7456 linenr_T lnum;
7457
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007458 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7460 rettv->vval.v_number = -1;
7461 else
7462 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7463 if (rettv->vval.v_number >= 0)
7464 ++rettv->vval.v_number;
7465#endif
7466}
7467
7468/*
7469 * "lispindent(lnum)" function
7470 */
7471 static void
7472f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7473{
7474#ifdef FEAT_LISP
7475 pos_T pos;
7476 linenr_T lnum;
7477
7478 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007479 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007480 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7481 {
7482 curwin->w_cursor.lnum = lnum;
7483 rettv->vval.v_number = get_lisp_indent();
7484 curwin->w_cursor = pos;
7485 }
7486 else
7487#endif
7488 rettv->vval.v_number = -1;
7489}
7490
7491/*
7492 * "localtime()" function
7493 */
7494 static void
7495f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7496{
7497 rettv->vval.v_number = (varnumber_T)time(NULL);
7498}
7499
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007500#ifdef FEAT_FLOAT
7501/*
7502 * "log()" function
7503 */
7504 static void
7505f_log(typval_T *argvars, typval_T *rettv)
7506{
7507 float_T f = 0.0;
7508
7509 rettv->v_type = VAR_FLOAT;
7510 if (get_float_arg(argvars, &f) == OK)
7511 rettv->vval.v_float = log(f);
7512 else
7513 rettv->vval.v_float = 0.0;
7514}
7515
7516/*
7517 * "log10()" function
7518 */
7519 static void
7520f_log10(typval_T *argvars, typval_T *rettv)
7521{
7522 float_T f = 0.0;
7523
7524 rettv->v_type = VAR_FLOAT;
7525 if (get_float_arg(argvars, &f) == OK)
7526 rettv->vval.v_float = log10(f);
7527 else
7528 rettv->vval.v_float = 0.0;
7529}
7530#endif
7531
7532#ifdef FEAT_LUA
7533/*
7534 * "luaeval()" function
7535 */
7536 static void
7537f_luaeval(typval_T *argvars, typval_T *rettv)
7538{
7539 char_u *str;
7540 char_u buf[NUMBUFLEN];
7541
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007542 if (check_restricted() || check_secure())
7543 return;
7544
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 do_luaeval(str, argvars + 1, rettv);
7547}
7548#endif
7549
7550/*
7551 * "map()" function
7552 */
7553 static void
7554f_map(typval_T *argvars, typval_T *rettv)
7555{
7556 filter_map(argvars, rettv, TRUE);
7557}
7558
7559/*
7560 * "maparg()" function
7561 */
7562 static void
7563f_maparg(typval_T *argvars, typval_T *rettv)
7564{
7565 get_maparg(argvars, rettv, TRUE);
7566}
7567
7568/*
7569 * "mapcheck()" function
7570 */
7571 static void
7572f_mapcheck(typval_T *argvars, typval_T *rettv)
7573{
7574 get_maparg(argvars, rettv, FALSE);
7575}
7576
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007577typedef enum
7578{
7579 MATCH_END, /* matchend() */
7580 MATCH_MATCH, /* match() */
7581 MATCH_STR, /* matchstr() */
7582 MATCH_LIST, /* matchlist() */
7583 MATCH_POS /* matchstrpos() */
7584} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585
7586 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007587find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588{
7589 char_u *str = NULL;
7590 long len = 0;
7591 char_u *expr = NULL;
7592 char_u *pat;
7593 regmatch_T regmatch;
7594 char_u patbuf[NUMBUFLEN];
7595 char_u strbuf[NUMBUFLEN];
7596 char_u *save_cpo;
7597 long start = 0;
7598 long nth = 1;
7599 colnr_T startcol = 0;
7600 int match = 0;
7601 list_T *l = NULL;
7602 listitem_T *li = NULL;
7603 long idx = 0;
7604 char_u *tofree = NULL;
7605
7606 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7607 save_cpo = p_cpo;
7608 p_cpo = (char_u *)"";
7609
7610 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007611 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007613 /* type MATCH_LIST: return empty list when there are no matches.
7614 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615 if (rettv_list_alloc(rettv) == FAIL)
7616 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007617 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007618 && (list_append_string(rettv->vval.v_list,
7619 (char_u *)"", 0) == FAIL
7620 || list_append_number(rettv->vval.v_list,
7621 (varnumber_T)-1) == FAIL
7622 || list_append_number(rettv->vval.v_list,
7623 (varnumber_T)-1) == FAIL
7624 || list_append_number(rettv->vval.v_list,
7625 (varnumber_T)-1) == FAIL))
7626 {
7627 list_free(rettv->vval.v_list);
7628 rettv->vval.v_list = NULL;
7629 goto theend;
7630 }
7631 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007632 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 {
7634 rettv->v_type = VAR_STRING;
7635 rettv->vval.v_string = NULL;
7636 }
7637
7638 if (argvars[0].v_type == VAR_LIST)
7639 {
7640 if ((l = argvars[0].vval.v_list) == NULL)
7641 goto theend;
7642 li = l->lv_first;
7643 }
7644 else
7645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 len = (long)STRLEN(str);
7648 }
7649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007650 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007651 if (pat == NULL)
7652 goto theend;
7653
7654 if (argvars[2].v_type != VAR_UNKNOWN)
7655 {
7656 int error = FALSE;
7657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007658 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 if (error)
7660 goto theend;
7661 if (l != NULL)
7662 {
7663 li = list_find(l, start);
7664 if (li == NULL)
7665 goto theend;
7666 idx = l->lv_idx; /* use the cached index */
7667 }
7668 else
7669 {
7670 if (start < 0)
7671 start = 0;
7672 if (start > len)
7673 goto theend;
7674 /* When "count" argument is there ignore matches before "start",
7675 * otherwise skip part of the string. Differs when pattern is "^"
7676 * or "\<". */
7677 if (argvars[3].v_type != VAR_UNKNOWN)
7678 startcol = start;
7679 else
7680 {
7681 str += start;
7682 len -= start;
7683 }
7684 }
7685
7686 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007687 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007688 if (error)
7689 goto theend;
7690 }
7691
7692 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7693 if (regmatch.regprog != NULL)
7694 {
7695 regmatch.rm_ic = p_ic;
7696
7697 for (;;)
7698 {
7699 if (l != NULL)
7700 {
7701 if (li == NULL)
7702 {
7703 match = FALSE;
7704 break;
7705 }
7706 vim_free(tofree);
7707 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7708 if (str == NULL)
7709 break;
7710 }
7711
7712 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7713
7714 if (match && --nth <= 0)
7715 break;
7716 if (l == NULL && !match)
7717 break;
7718
7719 /* Advance to just after the match. */
7720 if (l != NULL)
7721 {
7722 li = li->li_next;
7723 ++idx;
7724 }
7725 else
7726 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727 startcol = (colnr_T)(regmatch.startp[0]
7728 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007729 if (startcol > (colnr_T)len
7730 || str + startcol <= regmatch.startp[0])
7731 {
7732 match = FALSE;
7733 break;
7734 }
7735 }
7736 }
7737
7738 if (match)
7739 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007740 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 {
7742 listitem_T *li1 = rettv->vval.v_list->lv_first;
7743 listitem_T *li2 = li1->li_next;
7744 listitem_T *li3 = li2->li_next;
7745 listitem_T *li4 = li3->li_next;
7746
7747 vim_free(li1->li_tv.vval.v_string);
7748 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7749 (int)(regmatch.endp[0] - regmatch.startp[0]));
7750 li3->li_tv.vval.v_number =
7751 (varnumber_T)(regmatch.startp[0] - expr);
7752 li4->li_tv.vval.v_number =
7753 (varnumber_T)(regmatch.endp[0] - expr);
7754 if (l != NULL)
7755 li2->li_tv.vval.v_number = (varnumber_T)idx;
7756 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007757 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758 {
7759 int i;
7760
7761 /* return list with matched string and submatches */
7762 for (i = 0; i < NSUBEXP; ++i)
7763 {
7764 if (regmatch.endp[i] == NULL)
7765 {
7766 if (list_append_string(rettv->vval.v_list,
7767 (char_u *)"", 0) == FAIL)
7768 break;
7769 }
7770 else if (list_append_string(rettv->vval.v_list,
7771 regmatch.startp[i],
7772 (int)(regmatch.endp[i] - regmatch.startp[i]))
7773 == FAIL)
7774 break;
7775 }
7776 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007777 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 {
7779 /* return matched string */
7780 if (l != NULL)
7781 copy_tv(&li->li_tv, rettv);
7782 else
7783 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7784 (int)(regmatch.endp[0] - regmatch.startp[0]));
7785 }
7786 else if (l != NULL)
7787 rettv->vval.v_number = idx;
7788 else
7789 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007790 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007791 rettv->vval.v_number =
7792 (varnumber_T)(regmatch.startp[0] - str);
7793 else
7794 rettv->vval.v_number =
7795 (varnumber_T)(regmatch.endp[0] - str);
7796 rettv->vval.v_number += (varnumber_T)(str - expr);
7797 }
7798 }
7799 vim_regfree(regmatch.regprog);
7800 }
7801
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007802theend:
7803 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 /* matchstrpos() without a list: drop the second item. */
7805 listitem_remove(rettv->vval.v_list,
7806 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807 vim_free(tofree);
7808 p_cpo = save_cpo;
7809}
7810
7811/*
7812 * "match()" function
7813 */
7814 static void
7815f_match(typval_T *argvars, typval_T *rettv)
7816{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007817 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007818}
7819
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007820/*
7821 * "matchend()" function
7822 */
7823 static void
7824f_matchend(typval_T *argvars, typval_T *rettv)
7825{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007826 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007827}
7828
7829/*
7830 * "matchlist()" function
7831 */
7832 static void
7833f_matchlist(typval_T *argvars, typval_T *rettv)
7834{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007835 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007836}
7837
7838/*
7839 * "matchstr()" function
7840 */
7841 static void
7842f_matchstr(typval_T *argvars, typval_T *rettv)
7843{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007844 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007845}
7846
7847/*
7848 * "matchstrpos()" function
7849 */
7850 static void
7851f_matchstrpos(typval_T *argvars, typval_T *rettv)
7852{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007853 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854}
7855
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 static void
7857max_min(typval_T *argvars, typval_T *rettv, int domax)
7858{
7859 varnumber_T n = 0;
7860 varnumber_T i;
7861 int error = FALSE;
7862
7863 if (argvars[0].v_type == VAR_LIST)
7864 {
7865 list_T *l;
7866 listitem_T *li;
7867
7868 l = argvars[0].vval.v_list;
7869 if (l != NULL)
7870 {
7871 li = l->lv_first;
7872 if (li != NULL)
7873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007874 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 for (;;)
7876 {
7877 li = li->li_next;
7878 if (li == NULL)
7879 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007880 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007881 if (domax ? i > n : i < n)
7882 n = i;
7883 }
7884 }
7885 }
7886 }
7887 else if (argvars[0].v_type == VAR_DICT)
7888 {
7889 dict_T *d;
7890 int first = TRUE;
7891 hashitem_T *hi;
7892 int todo;
7893
7894 d = argvars[0].vval.v_dict;
7895 if (d != NULL)
7896 {
7897 todo = (int)d->dv_hashtab.ht_used;
7898 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7899 {
7900 if (!HASHITEM_EMPTY(hi))
7901 {
7902 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007903 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 if (first)
7905 {
7906 n = i;
7907 first = FALSE;
7908 }
7909 else if (domax ? i > n : i < n)
7910 n = i;
7911 }
7912 }
7913 }
7914 }
7915 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007916 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917 rettv->vval.v_number = error ? 0 : n;
7918}
7919
7920/*
7921 * "max()" function
7922 */
7923 static void
7924f_max(typval_T *argvars, typval_T *rettv)
7925{
7926 max_min(argvars, rettv, TRUE);
7927}
7928
7929/*
7930 * "min()" function
7931 */
7932 static void
7933f_min(typval_T *argvars, typval_T *rettv)
7934{
7935 max_min(argvars, rettv, FALSE);
7936}
7937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007938/*
7939 * Create the directory in which "dir" is located, and higher levels when
7940 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007941 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 */
7943 static int
7944mkdir_recurse(char_u *dir, int prot)
7945{
7946 char_u *p;
7947 char_u *updir;
7948 int r = FAIL;
7949
7950 /* Get end of directory name in "dir".
7951 * We're done when it's "/" or "c:/". */
7952 p = gettail_sep(dir);
7953 if (p <= get_past_head(dir))
7954 return OK;
7955
7956 /* If the directory exists we're done. Otherwise: create it.*/
7957 updir = vim_strnsave(dir, (int)(p - dir));
7958 if (updir == NULL)
7959 return FAIL;
7960 if (mch_isdir(updir))
7961 r = OK;
7962 else if (mkdir_recurse(updir, prot) == OK)
7963 r = vim_mkdir_emsg(updir, prot);
7964 vim_free(updir);
7965 return r;
7966}
7967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007968/*
7969 * "mkdir()" function
7970 */
7971 static void
7972f_mkdir(typval_T *argvars, typval_T *rettv)
7973{
7974 char_u *dir;
7975 char_u buf[NUMBUFLEN];
7976 int prot = 0755;
7977
7978 rettv->vval.v_number = FAIL;
7979 if (check_restricted() || check_secure())
7980 return;
7981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007982 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007984 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007986 if (*gettail(dir) == NUL)
7987 /* remove trailing slashes */
7988 *gettail_sep(dir) = NUL;
7989
7990 if (argvars[1].v_type != VAR_UNKNOWN)
7991 {
7992 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007994 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007995 if (prot == -1)
7996 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007998 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007999 {
8000 if (mch_isdir(dir))
8001 {
8002 /* With the "p" flag it's OK if the dir already exists. */
8003 rettv->vval.v_number = OK;
8004 return;
8005 }
8006 mkdir_recurse(dir, prot);
8007 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008009 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008010}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011
8012/*
8013 * "mode()" function
8014 */
8015 static void
8016f_mode(typval_T *argvars, typval_T *rettv)
8017{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008018 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019
Bram Moolenaar612cc382018-07-29 15:34:26 +02008020 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021
8022 if (time_for_testing == 93784)
8023 {
8024 /* Testing the two-character code. */
8025 buf[0] = 'x';
8026 buf[1] = '!';
8027 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008028#ifdef FEAT_TERMINAL
8029 else if (term_use_loop())
8030 buf[0] = 't';
8031#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032 else if (VIsual_active)
8033 {
8034 if (VIsual_select)
8035 buf[0] = VIsual_mode + 's' - 'v';
8036 else
8037 buf[0] = VIsual_mode;
8038 }
8039 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8040 || State == CONFIRM)
8041 {
8042 buf[0] = 'r';
8043 if (State == ASKMORE)
8044 buf[1] = 'm';
8045 else if (State == CONFIRM)
8046 buf[1] = '?';
8047 }
8048 else if (State == EXTERNCMD)
8049 buf[0] = '!';
8050 else if (State & INSERT)
8051 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008052 if (State & VREPLACE_FLAG)
8053 {
8054 buf[0] = 'R';
8055 buf[1] = 'v';
8056 }
8057 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008058 {
8059 if (State & REPLACE_FLAG)
8060 buf[0] = 'R';
8061 else
8062 buf[0] = 'i';
8063#ifdef FEAT_INS_EXPAND
8064 if (ins_compl_active())
8065 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008066 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008067 buf[1] = 'x';
8068#endif
8069 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008071 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008072 {
8073 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008074 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008076 else if (exmode_active == EXMODE_NORMAL)
8077 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078 }
8079 else
8080 {
8081 buf[0] = 'n';
8082 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008083 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008085 // to be able to detect force-linewise/blockwise/characterwise operations
8086 buf[2] = motion_force;
8087 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008088 else if (restart_edit == 'I' || restart_edit == 'R'
8089 || restart_edit == 'V')
8090 {
8091 buf[1] = 'i';
8092 buf[2] = restart_edit;
8093 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 }
8095
8096 /* Clear out the minor mode when the argument is not a non-zero number or
8097 * non-empty string. */
8098 if (!non_zero_arg(&argvars[0]))
8099 buf[1] = NUL;
8100
8101 rettv->vval.v_string = vim_strsave(buf);
8102 rettv->v_type = VAR_STRING;
8103}
8104
8105#if defined(FEAT_MZSCHEME) || defined(PROTO)
8106/*
8107 * "mzeval()" function
8108 */
8109 static void
8110f_mzeval(typval_T *argvars, typval_T *rettv)
8111{
8112 char_u *str;
8113 char_u buf[NUMBUFLEN];
8114
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008115 if (check_restricted() || check_secure())
8116 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008117 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 do_mzeval(str, rettv);
8119}
8120
8121 void
8122mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8123{
8124 typval_T argvars[3];
8125
8126 argvars[0].v_type = VAR_STRING;
8127 argvars[0].vval.v_string = name;
8128 copy_tv(args, &argvars[1]);
8129 argvars[2].v_type = VAR_UNKNOWN;
8130 f_call(argvars, rettv);
8131 clear_tv(&argvars[1]);
8132}
8133#endif
8134
8135/*
8136 * "nextnonblank()" function
8137 */
8138 static void
8139f_nextnonblank(typval_T *argvars, typval_T *rettv)
8140{
8141 linenr_T lnum;
8142
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008143 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144 {
8145 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8146 {
8147 lnum = 0;
8148 break;
8149 }
8150 if (*skipwhite(ml_get(lnum)) != NUL)
8151 break;
8152 }
8153 rettv->vval.v_number = lnum;
8154}
8155
8156/*
8157 * "nr2char()" function
8158 */
8159 static void
8160f_nr2char(typval_T *argvars, typval_T *rettv)
8161{
8162 char_u buf[NUMBUFLEN];
8163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 if (has_mbyte)
8165 {
8166 int utf8 = 0;
8167
8168 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008169 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008170 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008171 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008173 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 }
8175 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008177 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178 buf[1] = NUL;
8179 }
8180 rettv->v_type = VAR_STRING;
8181 rettv->vval.v_string = vim_strsave(buf);
8182}
8183
8184/*
8185 * "or(expr, expr)" function
8186 */
8187 static void
8188f_or(typval_T *argvars, typval_T *rettv)
8189{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008190 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8191 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192}
8193
8194/*
8195 * "pathshorten()" function
8196 */
8197 static void
8198f_pathshorten(typval_T *argvars, typval_T *rettv)
8199{
8200 char_u *p;
8201
8202 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008203 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204 if (p == NULL)
8205 rettv->vval.v_string = NULL;
8206 else
8207 {
8208 p = vim_strsave(p);
8209 rettv->vval.v_string = p;
8210 if (p != NULL)
8211 shorten_dir(p);
8212 }
8213}
8214
8215#ifdef FEAT_PERL
8216/*
8217 * "perleval()" function
8218 */
8219 static void
8220f_perleval(typval_T *argvars, typval_T *rettv)
8221{
8222 char_u *str;
8223 char_u buf[NUMBUFLEN];
8224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008225 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 do_perleval(str, rettv);
8227}
8228#endif
8229
8230#ifdef FEAT_FLOAT
8231/*
8232 * "pow()" function
8233 */
8234 static void
8235f_pow(typval_T *argvars, typval_T *rettv)
8236{
8237 float_T fx = 0.0, fy = 0.0;
8238
8239 rettv->v_type = VAR_FLOAT;
8240 if (get_float_arg(argvars, &fx) == OK
8241 && get_float_arg(&argvars[1], &fy) == OK)
8242 rettv->vval.v_float = pow(fx, fy);
8243 else
8244 rettv->vval.v_float = 0.0;
8245}
8246#endif
8247
8248/*
8249 * "prevnonblank()" function
8250 */
8251 static void
8252f_prevnonblank(typval_T *argvars, typval_T *rettv)
8253{
8254 linenr_T lnum;
8255
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008256 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8258 lnum = 0;
8259 else
8260 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8261 --lnum;
8262 rettv->vval.v_number = lnum;
8263}
8264
8265/* This dummy va_list is here because:
8266 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8267 * - locally in the function results in a "used before set" warning
8268 * - using va_start() to initialize it gives "function with fixed args" error */
8269static va_list ap;
8270
8271/*
8272 * "printf()" function
8273 */
8274 static void
8275f_printf(typval_T *argvars, typval_T *rettv)
8276{
8277 char_u buf[NUMBUFLEN];
8278 int len;
8279 char_u *s;
8280 int saved_did_emsg = did_emsg;
8281 char *fmt;
8282
8283 rettv->v_type = VAR_STRING;
8284 rettv->vval.v_string = NULL;
8285
8286 /* Get the required length, allocate the buffer and do it for real. */
8287 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008288 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008289 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 if (!did_emsg)
8291 {
8292 s = alloc(len + 1);
8293 if (s != NULL)
8294 {
8295 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008296 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8297 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008298 }
8299 }
8300 did_emsg |= saved_did_emsg;
8301}
8302
8303/*
8304 * "pumvisible()" function
8305 */
8306 static void
8307f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8308{
8309#ifdef FEAT_INS_EXPAND
8310 if (pum_visible())
8311 rettv->vval.v_number = 1;
8312#endif
8313}
8314
8315#ifdef FEAT_PYTHON3
8316/*
8317 * "py3eval()" function
8318 */
8319 static void
8320f_py3eval(typval_T *argvars, typval_T *rettv)
8321{
8322 char_u *str;
8323 char_u buf[NUMBUFLEN];
8324
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008325 if (check_restricted() || check_secure())
8326 return;
8327
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008328 if (p_pyx == 0)
8329 p_pyx = 3;
8330
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008331 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008332 do_py3eval(str, rettv);
8333}
8334#endif
8335
8336#ifdef FEAT_PYTHON
8337/*
8338 * "pyeval()" function
8339 */
8340 static void
8341f_pyeval(typval_T *argvars, typval_T *rettv)
8342{
8343 char_u *str;
8344 char_u buf[NUMBUFLEN];
8345
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008346 if (check_restricted() || check_secure())
8347 return;
8348
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008349 if (p_pyx == 0)
8350 p_pyx = 2;
8351
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008352 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 do_pyeval(str, rettv);
8354}
8355#endif
8356
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008357#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8358/*
8359 * "pyxeval()" function
8360 */
8361 static void
8362f_pyxeval(typval_T *argvars, typval_T *rettv)
8363{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008364 if (check_restricted() || check_secure())
8365 return;
8366
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008367# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8368 init_pyxversion();
8369 if (p_pyx == 2)
8370 f_pyeval(argvars, rettv);
8371 else
8372 f_py3eval(argvars, rettv);
8373# elif defined(FEAT_PYTHON)
8374 f_pyeval(argvars, rettv);
8375# elif defined(FEAT_PYTHON3)
8376 f_py3eval(argvars, rettv);
8377# endif
8378}
8379#endif
8380
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381/*
8382 * "range()" function
8383 */
8384 static void
8385f_range(typval_T *argvars, typval_T *rettv)
8386{
8387 varnumber_T start;
8388 varnumber_T end;
8389 varnumber_T stride = 1;
8390 varnumber_T i;
8391 int error = FALSE;
8392
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008393 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 if (argvars[1].v_type == VAR_UNKNOWN)
8395 {
8396 end = start - 1;
8397 start = 0;
8398 }
8399 else
8400 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008401 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008403 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 }
8405
8406 if (error)
8407 return; /* type error; errmsg already given */
8408 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008409 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008411 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008412 else
8413 {
8414 if (rettv_list_alloc(rettv) == OK)
8415 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8416 if (list_append_number(rettv->vval.v_list,
8417 (varnumber_T)i) == FAIL)
8418 break;
8419 }
8420}
8421
8422/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008423 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008424 */
8425 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008426readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008427{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008428 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008429 typval_T save_val;
8430 typval_T rettv;
8431 typval_T argv[2];
8432 int retval = 0;
8433 int error = FALSE;
8434
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008435 if (expr->v_type == VAR_UNKNOWN)
8436 return 1;
8437
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008438 prepare_vimvar(VV_VAL, &save_val);
8439 set_vim_var_string(VV_VAL, name, -1);
8440 argv[0].v_type = VAR_STRING;
8441 argv[0].vval.v_string = name;
8442
8443 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8444 goto theend;
8445
8446 retval = tv_get_number_chk(&rettv, &error);
8447 if (error)
8448 retval = -1;
8449 clear_tv(&rettv);
8450
8451theend:
8452 set_vim_var_string(VV_VAL, NULL, 0);
8453 restore_vimvar(VV_VAL, &save_val);
8454 return retval;
8455}
8456
8457/*
8458 * "readdir()" function
8459 */
8460 static void
8461f_readdir(typval_T *argvars, typval_T *rettv)
8462{
8463 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008464 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008465 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008466 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008467 garray_T ga;
8468 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008469
8470 if (rettv_list_alloc(rettv) == FAIL)
8471 return;
8472 path = tv_get_string(&argvars[0]);
8473 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008474
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008475 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8476 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008477 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008478 for (i = 0; i < ga.ga_len; i++)
8479 {
8480 p = ((char_u **)ga.ga_data)[i];
8481 list_append_string(rettv->vval.v_list, p, -1);
8482 }
8483 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008484 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008485}
8486
8487/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008488 * "readfile()" function
8489 */
8490 static void
8491f_readfile(typval_T *argvars, typval_T *rettv)
8492{
8493 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008494 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008495 int failed = FALSE;
8496 char_u *fname;
8497 FILE *fd;
8498 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8499 int io_size = sizeof(buf);
8500 int readlen; /* size of last fread() */
8501 char_u *prev = NULL; /* previously read bytes, if any */
8502 long prevlen = 0; /* length of data in prev */
8503 long prevsize = 0; /* size of prev buffer */
8504 long maxline = MAXLNUM;
8505 long cnt = 0;
8506 char_u *p; /* position in buf */
8507 char_u *start; /* start of current line */
8508
8509 if (argvars[1].v_type != VAR_UNKNOWN)
8510 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008511 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008513 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8514 blob = TRUE;
8515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008516 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008517 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008518 }
8519
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008520 if (blob)
8521 {
8522 if (rettv_blob_alloc(rettv) == FAIL)
8523 return;
8524 }
8525 else
8526 {
8527 if (rettv_list_alloc(rettv) == FAIL)
8528 return;
8529 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530
8531 /* Always open the file in binary mode, library functions have a mind of
8532 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008533 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008534 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8535 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008536 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008537 return;
8538 }
8539
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008540 if (blob)
8541 {
8542 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8543 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008544 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008545 blob_free(rettv->vval.v_blob);
8546 }
8547 fclose(fd);
8548 return;
8549 }
8550
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551 while (cnt < maxline || maxline < 0)
8552 {
8553 readlen = (int)fread(buf, 1, io_size, fd);
8554
8555 /* This for loop processes what was read, but is also entered at end
8556 * of file so that either:
8557 * - an incomplete line gets written
8558 * - a "binary" file gets an empty line at the end if it ends in a
8559 * newline. */
8560 for (p = buf, start = buf;
8561 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8562 ++p)
8563 {
8564 if (*p == '\n' || readlen <= 0)
8565 {
8566 listitem_T *li;
8567 char_u *s = NULL;
8568 long_u len = p - start;
8569
8570 /* Finished a line. Remove CRs before NL. */
8571 if (readlen > 0 && !binary)
8572 {
8573 while (len > 0 && start[len - 1] == '\r')
8574 --len;
8575 /* removal may cross back to the "prev" string */
8576 if (len == 0)
8577 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8578 --prevlen;
8579 }
8580 if (prevlen == 0)
8581 s = vim_strnsave(start, (int)len);
8582 else
8583 {
8584 /* Change "prev" buffer to be the right size. This way
8585 * the bytes are only copied once, and very long lines are
8586 * allocated only once. */
8587 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8588 {
8589 mch_memmove(s + prevlen, start, len);
8590 s[prevlen + len] = NUL;
8591 prev = NULL; /* the list will own the string */
8592 prevlen = prevsize = 0;
8593 }
8594 }
8595 if (s == NULL)
8596 {
8597 do_outofmem_msg((long_u) prevlen + len + 1);
8598 failed = TRUE;
8599 break;
8600 }
8601
8602 if ((li = listitem_alloc()) == NULL)
8603 {
8604 vim_free(s);
8605 failed = TRUE;
8606 break;
8607 }
8608 li->li_tv.v_type = VAR_STRING;
8609 li->li_tv.v_lock = 0;
8610 li->li_tv.vval.v_string = s;
8611 list_append(rettv->vval.v_list, li);
8612
8613 start = p + 1; /* step over newline */
8614 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8615 break;
8616 }
8617 else if (*p == NUL)
8618 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008619 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8620 * when finding the BF and check the previous two bytes. */
8621 else if (*p == 0xbf && enc_utf8 && !binary)
8622 {
8623 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8624 * + 1, these may be in the "prev" string. */
8625 char_u back1 = p >= buf + 1 ? p[-1]
8626 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8627 char_u back2 = p >= buf + 2 ? p[-2]
8628 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8629 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8630
8631 if (back2 == 0xef && back1 == 0xbb)
8632 {
8633 char_u *dest = p - 2;
8634
8635 /* Usually a BOM is at the beginning of a file, and so at
8636 * the beginning of a line; then we can just step over it.
8637 */
8638 if (start == dest)
8639 start = p + 1;
8640 else
8641 {
8642 /* have to shuffle buf to close gap */
8643 int adjust_prevlen = 0;
8644
8645 if (dest < buf)
8646 {
8647 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8648 dest = buf;
8649 }
8650 if (readlen > p - buf + 1)
8651 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8652 readlen -= 3 - adjust_prevlen;
8653 prevlen -= adjust_prevlen;
8654 p = dest - 1;
8655 }
8656 }
8657 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008658 } /* for */
8659
8660 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8661 break;
8662 if (start < p)
8663 {
8664 /* There's part of a line in buf, store it in "prev". */
8665 if (p - start + prevlen >= prevsize)
8666 {
8667 /* need bigger "prev" buffer */
8668 char_u *newprev;
8669
8670 /* A common use case is ordinary text files and "prev" gets a
8671 * fragment of a line, so the first allocation is made
8672 * small, to avoid repeatedly 'allocing' large and
8673 * 'reallocing' small. */
8674 if (prevsize == 0)
8675 prevsize = (long)(p - start);
8676 else
8677 {
8678 long grow50pc = (prevsize * 3) / 2;
8679 long growmin = (long)((p - start) * 2 + prevlen);
8680 prevsize = grow50pc > growmin ? grow50pc : growmin;
8681 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008682 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008683 if (newprev == NULL)
8684 {
8685 do_outofmem_msg((long_u)prevsize);
8686 failed = TRUE;
8687 break;
8688 }
8689 prev = newprev;
8690 }
8691 /* Add the line part to end of "prev". */
8692 mch_memmove(prev + prevlen, start, p - start);
8693 prevlen += (long)(p - start);
8694 }
8695 } /* while */
8696
8697 /*
8698 * For a negative line count use only the lines at the end of the file,
8699 * free the rest.
8700 */
8701 if (!failed && maxline < 0)
8702 while (cnt > -maxline)
8703 {
8704 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8705 --cnt;
8706 }
8707
8708 if (failed)
8709 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008710 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008711 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008712 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008713 }
8714
8715 vim_free(prev);
8716 fclose(fd);
8717}
8718
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008719 static void
8720return_register(int regname, typval_T *rettv)
8721{
8722 char_u buf[2] = {0, 0};
8723
8724 buf[0] = (char_u)regname;
8725 rettv->v_type = VAR_STRING;
8726 rettv->vval.v_string = vim_strsave(buf);
8727}
8728
8729/*
8730 * "reg_executing()" function
8731 */
8732 static void
8733f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8734{
8735 return_register(reg_executing, rettv);
8736}
8737
8738/*
8739 * "reg_recording()" function
8740 */
8741 static void
8742f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8743{
8744 return_register(reg_recording, rettv);
8745}
8746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748/*
8749 * Convert a List to proftime_T.
8750 * Return FAIL when there is something wrong.
8751 */
8752 static int
8753list2proftime(typval_T *arg, proftime_T *tm)
8754{
8755 long n1, n2;
8756 int error = FALSE;
8757
8758 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8759 || arg->vval.v_list->lv_len != 2)
8760 return FAIL;
8761 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8762 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008763# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008764 tm->HighPart = n1;
8765 tm->LowPart = n2;
8766# else
8767 tm->tv_sec = n1;
8768 tm->tv_usec = n2;
8769# endif
8770 return error ? FAIL : OK;
8771}
8772#endif /* FEAT_RELTIME */
8773
8774/*
8775 * "reltime()" function
8776 */
8777 static void
8778f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8779{
8780#ifdef FEAT_RELTIME
8781 proftime_T res;
8782 proftime_T start;
8783
8784 if (argvars[0].v_type == VAR_UNKNOWN)
8785 {
8786 /* No arguments: get current time. */
8787 profile_start(&res);
8788 }
8789 else if (argvars[1].v_type == VAR_UNKNOWN)
8790 {
8791 if (list2proftime(&argvars[0], &res) == FAIL)
8792 return;
8793 profile_end(&res);
8794 }
8795 else
8796 {
8797 /* Two arguments: compute the difference. */
8798 if (list2proftime(&argvars[0], &start) == FAIL
8799 || list2proftime(&argvars[1], &res) == FAIL)
8800 return;
8801 profile_sub(&res, &start);
8802 }
8803
8804 if (rettv_list_alloc(rettv) == OK)
8805 {
8806 long n1, n2;
8807
Bram Moolenaar4f974752019-02-17 17:44:42 +01008808# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008809 n1 = res.HighPart;
8810 n2 = res.LowPart;
8811# else
8812 n1 = res.tv_sec;
8813 n2 = res.tv_usec;
8814# endif
8815 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8816 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8817 }
8818#endif
8819}
8820
8821#ifdef FEAT_FLOAT
8822/*
8823 * "reltimefloat()" function
8824 */
8825 static void
8826f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8827{
8828# ifdef FEAT_RELTIME
8829 proftime_T tm;
8830# endif
8831
8832 rettv->v_type = VAR_FLOAT;
8833 rettv->vval.v_float = 0;
8834# ifdef FEAT_RELTIME
8835 if (list2proftime(&argvars[0], &tm) == OK)
8836 rettv->vval.v_float = profile_float(&tm);
8837# endif
8838}
8839#endif
8840
8841/*
8842 * "reltimestr()" function
8843 */
8844 static void
8845f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8846{
8847#ifdef FEAT_RELTIME
8848 proftime_T tm;
8849#endif
8850
8851 rettv->v_type = VAR_STRING;
8852 rettv->vval.v_string = NULL;
8853#ifdef FEAT_RELTIME
8854 if (list2proftime(&argvars[0], &tm) == OK)
8855 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8856#endif
8857}
8858
8859#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008860 static void
8861make_connection(void)
8862{
8863 if (X_DISPLAY == NULL
8864# ifdef FEAT_GUI
8865 && !gui.in_use
8866# endif
8867 )
8868 {
8869 x_force_connect = TRUE;
8870 setup_term_clip();
8871 x_force_connect = FALSE;
8872 }
8873}
8874
8875 static int
8876check_connection(void)
8877{
8878 make_connection();
8879 if (X_DISPLAY == NULL)
8880 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008881 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008882 return FAIL;
8883 }
8884 return OK;
8885}
8886#endif
8887
8888#ifdef FEAT_CLIENTSERVER
8889 static void
8890remote_common(typval_T *argvars, typval_T *rettv, int expr)
8891{
8892 char_u *server_name;
8893 char_u *keys;
8894 char_u *r = NULL;
8895 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008896 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008897# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 HWND w;
8899# else
8900 Window w;
8901# endif
8902
8903 if (check_restricted() || check_secure())
8904 return;
8905
8906# ifdef FEAT_X11
8907 if (check_connection() == FAIL)
8908 return;
8909# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008910 if (argvars[2].v_type != VAR_UNKNOWN
8911 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008912 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008914 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008915 if (server_name == NULL)
8916 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008917 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008918# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008919 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008920# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008921 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8922 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008923# endif
8924 {
8925 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008926 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008927 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008928 vim_free(r);
8929 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008930 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008931 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932 return;
8933 }
8934
8935 rettv->vval.v_string = r;
8936
8937 if (argvars[2].v_type != VAR_UNKNOWN)
8938 {
8939 dictitem_T v;
8940 char_u str[30];
8941 char_u *idvar;
8942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008943 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008944 if (idvar != NULL && *idvar != NUL)
8945 {
8946 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8947 v.di_tv.v_type = VAR_STRING;
8948 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008949 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008950 vim_free(v.di_tv.vval.v_string);
8951 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008952 }
8953}
8954#endif
8955
8956/*
8957 * "remote_expr()" function
8958 */
8959 static void
8960f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8961{
8962 rettv->v_type = VAR_STRING;
8963 rettv->vval.v_string = NULL;
8964#ifdef FEAT_CLIENTSERVER
8965 remote_common(argvars, rettv, TRUE);
8966#endif
8967}
8968
8969/*
8970 * "remote_foreground()" function
8971 */
8972 static void
8973f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8974{
8975#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008976# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008977 /* On Win32 it's done in this application. */
8978 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008979 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008980
8981 if (server_name != NULL)
8982 serverForeground(server_name);
8983 }
8984# else
8985 /* Send a foreground() expression to the server. */
8986 argvars[1].v_type = VAR_STRING;
8987 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8988 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008989 rettv->v_type = VAR_STRING;
8990 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008991 remote_common(argvars, rettv, TRUE);
8992 vim_free(argvars[1].vval.v_string);
8993# endif
8994#endif
8995}
8996
8997 static void
8998f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8999{
9000#ifdef FEAT_CLIENTSERVER
9001 dictitem_T v;
9002 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009003# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009004 long_u n = 0;
9005# endif
9006 char_u *serverid;
9007
9008 if (check_restricted() || check_secure())
9009 {
9010 rettv->vval.v_number = -1;
9011 return;
9012 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009013 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009014 if (serverid == NULL)
9015 {
9016 rettv->vval.v_number = -1;
9017 return; /* type error; errmsg already given */
9018 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009019# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009020 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9021 if (n == 0)
9022 rettv->vval.v_number = -1;
9023 else
9024 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009025 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 rettv->vval.v_number = (s != NULL);
9027 }
9028# else
9029 if (check_connection() == FAIL)
9030 return;
9031
9032 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9033 serverStrToWin(serverid), &s);
9034# endif
9035
9036 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9037 {
9038 char_u *retvar;
9039
9040 v.di_tv.v_type = VAR_STRING;
9041 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009042 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009043 if (retvar != NULL)
9044 set_var(retvar, &v.di_tv, FALSE);
9045 vim_free(v.di_tv.vval.v_string);
9046 }
9047#else
9048 rettv->vval.v_number = -1;
9049#endif
9050}
9051
9052 static void
9053f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9054{
9055 char_u *r = NULL;
9056
9057#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009058 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009059
9060 if (serverid != NULL && !check_restricted() && !check_secure())
9061 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009062 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009063# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009064 /* The server's HWND is encoded in the 'id' parameter */
9065 long_u n = 0;
9066# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009067
9068 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009069 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009070
Bram Moolenaar4f974752019-02-17 17:44:42 +01009071# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009072 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9073 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009074 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009075 if (r == NULL)
9076# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009077 if (check_connection() == FAIL
9078 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9079 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009080# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009081 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009082 }
9083#endif
9084 rettv->v_type = VAR_STRING;
9085 rettv->vval.v_string = r;
9086}
9087
9088/*
9089 * "remote_send()" function
9090 */
9091 static void
9092f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9093{
9094 rettv->v_type = VAR_STRING;
9095 rettv->vval.v_string = NULL;
9096#ifdef FEAT_CLIENTSERVER
9097 remote_common(argvars, rettv, FALSE);
9098#endif
9099}
9100
9101/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009102 * "remote_startserver()" function
9103 */
9104 static void
9105f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9106{
9107#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009108 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009109
9110 if (server == NULL)
9111 return; /* type error; errmsg already given */
9112 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009113 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009114 else
9115 {
9116# ifdef FEAT_X11
9117 if (check_connection() == OK)
9118 serverRegisterName(X_DISPLAY, server);
9119# else
9120 serverSetName(server);
9121# endif
9122 }
9123#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009124 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009125#endif
9126}
9127
9128/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009129 * "remove()" function
9130 */
9131 static void
9132f_remove(typval_T *argvars, typval_T *rettv)
9133{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009134 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9135
9136 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009137 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009138 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009139 blob_remove(argvars, rettv);
9140 else if (argvars[0].v_type == VAR_LIST)
9141 list_remove(argvars, rettv, arg_errmsg);
9142 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009143 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009144}
9145
9146/*
9147 * "rename({from}, {to})" function
9148 */
9149 static void
9150f_rename(typval_T *argvars, typval_T *rettv)
9151{
9152 char_u buf[NUMBUFLEN];
9153
9154 if (check_restricted() || check_secure())
9155 rettv->vval.v_number = -1;
9156 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009157 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9158 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009159}
9160
9161/*
9162 * "repeat()" function
9163 */
9164 static void
9165f_repeat(typval_T *argvars, typval_T *rettv)
9166{
9167 char_u *p;
9168 int n;
9169 int slen;
9170 int len;
9171 char_u *r;
9172 int i;
9173
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009174 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009175 if (argvars[0].v_type == VAR_LIST)
9176 {
9177 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9178 while (n-- > 0)
9179 if (list_extend(rettv->vval.v_list,
9180 argvars[0].vval.v_list, NULL) == FAIL)
9181 break;
9182 }
9183 else
9184 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009185 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009186 rettv->v_type = VAR_STRING;
9187 rettv->vval.v_string = NULL;
9188
9189 slen = (int)STRLEN(p);
9190 len = slen * n;
9191 if (len <= 0)
9192 return;
9193
9194 r = alloc(len + 1);
9195 if (r != NULL)
9196 {
9197 for (i = 0; i < n; i++)
9198 mch_memmove(r + i * slen, p, (size_t)slen);
9199 r[len] = NUL;
9200 }
9201
9202 rettv->vval.v_string = r;
9203 }
9204}
9205
9206/*
9207 * "resolve()" function
9208 */
9209 static void
9210f_resolve(typval_T *argvars, typval_T *rettv)
9211{
9212 char_u *p;
9213#ifdef HAVE_READLINK
9214 char_u *buf = NULL;
9215#endif
9216
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009217 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009218#ifdef FEAT_SHORTCUT
9219 {
9220 char_u *v = NULL;
9221
Bram Moolenaardce1e892019-02-10 23:18:53 +01009222 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009223 if (v != NULL)
9224 rettv->vval.v_string = v;
9225 else
9226 rettv->vval.v_string = vim_strsave(p);
9227 }
9228#else
9229# ifdef HAVE_READLINK
9230 {
9231 char_u *cpy;
9232 int len;
9233 char_u *remain = NULL;
9234 char_u *q;
9235 int is_relative_to_current = FALSE;
9236 int has_trailing_pathsep = FALSE;
9237 int limit = 100;
9238
9239 p = vim_strsave(p);
9240
9241 if (p[0] == '.' && (vim_ispathsep(p[1])
9242 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9243 is_relative_to_current = TRUE;
9244
9245 len = STRLEN(p);
9246 if (len > 0 && after_pathsep(p, p + len))
9247 {
9248 has_trailing_pathsep = TRUE;
9249 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9250 }
9251
9252 q = getnextcomp(p);
9253 if (*q != NUL)
9254 {
9255 /* Separate the first path component in "p", and keep the
9256 * remainder (beginning with the path separator). */
9257 remain = vim_strsave(q - 1);
9258 q[-1] = NUL;
9259 }
9260
9261 buf = alloc(MAXPATHL + 1);
9262 if (buf == NULL)
9263 goto fail;
9264
9265 for (;;)
9266 {
9267 for (;;)
9268 {
9269 len = readlink((char *)p, (char *)buf, MAXPATHL);
9270 if (len <= 0)
9271 break;
9272 buf[len] = NUL;
9273
9274 if (limit-- == 0)
9275 {
9276 vim_free(p);
9277 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009278 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009279 rettv->vval.v_string = NULL;
9280 goto fail;
9281 }
9282
9283 /* Ensure that the result will have a trailing path separator
9284 * if the argument has one. */
9285 if (remain == NULL && has_trailing_pathsep)
9286 add_pathsep(buf);
9287
9288 /* Separate the first path component in the link value and
9289 * concatenate the remainders. */
9290 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9291 if (*q != NUL)
9292 {
9293 if (remain == NULL)
9294 remain = vim_strsave(q - 1);
9295 else
9296 {
9297 cpy = concat_str(q - 1, remain);
9298 if (cpy != NULL)
9299 {
9300 vim_free(remain);
9301 remain = cpy;
9302 }
9303 }
9304 q[-1] = NUL;
9305 }
9306
9307 q = gettail(p);
9308 if (q > p && *q == NUL)
9309 {
9310 /* Ignore trailing path separator. */
9311 q[-1] = NUL;
9312 q = gettail(p);
9313 }
9314 if (q > p && !mch_isFullName(buf))
9315 {
9316 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009317 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009318 if (cpy != NULL)
9319 {
9320 STRCPY(cpy, p);
9321 STRCPY(gettail(cpy), buf);
9322 vim_free(p);
9323 p = cpy;
9324 }
9325 }
9326 else
9327 {
9328 vim_free(p);
9329 p = vim_strsave(buf);
9330 }
9331 }
9332
9333 if (remain == NULL)
9334 break;
9335
9336 /* Append the first path component of "remain" to "p". */
9337 q = getnextcomp(remain + 1);
9338 len = q - remain - (*q != NUL);
9339 cpy = vim_strnsave(p, STRLEN(p) + len);
9340 if (cpy != NULL)
9341 {
9342 STRNCAT(cpy, remain, len);
9343 vim_free(p);
9344 p = cpy;
9345 }
9346 /* Shorten "remain". */
9347 if (*q != NUL)
9348 STRMOVE(remain, q - 1);
9349 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009350 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009351 }
9352
9353 /* If the result is a relative path name, make it explicitly relative to
9354 * the current directory if and only if the argument had this form. */
9355 if (!vim_ispathsep(*p))
9356 {
9357 if (is_relative_to_current
9358 && *p != NUL
9359 && !(p[0] == '.'
9360 && (p[1] == NUL
9361 || vim_ispathsep(p[1])
9362 || (p[1] == '.'
9363 && (p[2] == NUL
9364 || vim_ispathsep(p[2]))))))
9365 {
9366 /* Prepend "./". */
9367 cpy = concat_str((char_u *)"./", p);
9368 if (cpy != NULL)
9369 {
9370 vim_free(p);
9371 p = cpy;
9372 }
9373 }
9374 else if (!is_relative_to_current)
9375 {
9376 /* Strip leading "./". */
9377 q = p;
9378 while (q[0] == '.' && vim_ispathsep(q[1]))
9379 q += 2;
9380 if (q > p)
9381 STRMOVE(p, p + 2);
9382 }
9383 }
9384
9385 /* Ensure that the result will have no trailing path separator
9386 * if the argument had none. But keep "/" or "//". */
9387 if (!has_trailing_pathsep)
9388 {
9389 q = p + STRLEN(p);
9390 if (after_pathsep(p, q))
9391 *gettail_sep(p) = NUL;
9392 }
9393
9394 rettv->vval.v_string = p;
9395 }
9396# else
9397 rettv->vval.v_string = vim_strsave(p);
9398# endif
9399#endif
9400
9401 simplify_filename(rettv->vval.v_string);
9402
9403#ifdef HAVE_READLINK
9404fail:
9405 vim_free(buf);
9406#endif
9407 rettv->v_type = VAR_STRING;
9408}
9409
9410/*
9411 * "reverse({list})" function
9412 */
9413 static void
9414f_reverse(typval_T *argvars, typval_T *rettv)
9415{
9416 list_T *l;
9417 listitem_T *li, *ni;
9418
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009419 if (argvars[0].v_type == VAR_BLOB)
9420 {
9421 blob_T *b = argvars[0].vval.v_blob;
9422 int i, len = blob_len(b);
9423
9424 for (i = 0; i < len / 2; i++)
9425 {
9426 int tmp = blob_get(b, i);
9427
9428 blob_set(b, i, blob_get(b, len - i - 1));
9429 blob_set(b, len - i - 1, tmp);
9430 }
9431 rettv_blob_set(rettv, b);
9432 return;
9433 }
9434
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009435 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009436 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009437 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009438 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009439 (char_u *)N_("reverse() argument"), TRUE))
9440 {
9441 li = l->lv_last;
9442 l->lv_first = l->lv_last = NULL;
9443 l->lv_len = 0;
9444 while (li != NULL)
9445 {
9446 ni = li->li_prev;
9447 list_append(l, li);
9448 li = ni;
9449 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009450 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009451 l->lv_idx = l->lv_len - l->lv_idx - 1;
9452 }
9453}
9454
9455#define SP_NOMOVE 0x01 /* don't move cursor */
9456#define SP_REPEAT 0x02 /* repeat to find outer pair */
9457#define SP_RETCOUNT 0x04 /* return matchcount */
9458#define SP_SETPCMARK 0x08 /* set previous context mark */
9459#define SP_START 0x10 /* accept match at start position */
9460#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9461#define SP_END 0x40 /* leave cursor at end of match */
9462#define SP_COLUMN 0x80 /* start at cursor column */
9463
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009464/*
9465 * Get flags for a search function.
9466 * Possibly sets "p_ws".
9467 * Returns BACKWARD, FORWARD or zero (for an error).
9468 */
9469 static int
9470get_search_arg(typval_T *varp, int *flagsp)
9471{
9472 int dir = FORWARD;
9473 char_u *flags;
9474 char_u nbuf[NUMBUFLEN];
9475 int mask;
9476
9477 if (varp->v_type != VAR_UNKNOWN)
9478 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009479 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480 if (flags == NULL)
9481 return 0; /* type error; errmsg already given */
9482 while (*flags != NUL)
9483 {
9484 switch (*flags)
9485 {
9486 case 'b': dir = BACKWARD; break;
9487 case 'w': p_ws = TRUE; break;
9488 case 'W': p_ws = FALSE; break;
9489 default: mask = 0;
9490 if (flagsp != NULL)
9491 switch (*flags)
9492 {
9493 case 'c': mask = SP_START; break;
9494 case 'e': mask = SP_END; break;
9495 case 'm': mask = SP_RETCOUNT; break;
9496 case 'n': mask = SP_NOMOVE; break;
9497 case 'p': mask = SP_SUBPAT; break;
9498 case 'r': mask = SP_REPEAT; break;
9499 case 's': mask = SP_SETPCMARK; break;
9500 case 'z': mask = SP_COLUMN; break;
9501 }
9502 if (mask == 0)
9503 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009504 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009505 dir = 0;
9506 }
9507 else
9508 *flagsp |= mask;
9509 }
9510 if (dir == 0)
9511 break;
9512 ++flags;
9513 }
9514 }
9515 return dir;
9516}
9517
9518/*
9519 * Shared by search() and searchpos() functions.
9520 */
9521 static int
9522search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9523{
9524 int flags;
9525 char_u *pat;
9526 pos_T pos;
9527 pos_T save_cursor;
9528 int save_p_ws = p_ws;
9529 int dir;
9530 int retval = 0; /* default: FAIL */
9531 long lnum_stop = 0;
9532 proftime_T tm;
9533#ifdef FEAT_RELTIME
9534 long time_limit = 0;
9535#endif
9536 int options = SEARCH_KEEP;
9537 int subpatnum;
9538
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009539 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009540 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9541 if (dir == 0)
9542 goto theend;
9543 flags = *flagsp;
9544 if (flags & SP_START)
9545 options |= SEARCH_START;
9546 if (flags & SP_END)
9547 options |= SEARCH_END;
9548 if (flags & SP_COLUMN)
9549 options |= SEARCH_COL;
9550
9551 /* Optional arguments: line number to stop searching and timeout. */
9552 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9553 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009554 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009555 if (lnum_stop < 0)
9556 goto theend;
9557#ifdef FEAT_RELTIME
9558 if (argvars[3].v_type != VAR_UNKNOWN)
9559 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009560 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009561 if (time_limit < 0)
9562 goto theend;
9563 }
9564#endif
9565 }
9566
9567#ifdef FEAT_RELTIME
9568 /* Set the time limit, if there is one. */
9569 profile_setlimit(time_limit, &tm);
9570#endif
9571
9572 /*
9573 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9574 * Check to make sure only those flags are set.
9575 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9576 * flags cannot be set. Check for that condition also.
9577 */
9578 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9579 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9580 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009581 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009582 goto theend;
9583 }
9584
9585 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009586 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009587 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009588 if (subpatnum != FAIL)
9589 {
9590 if (flags & SP_SUBPAT)
9591 retval = subpatnum;
9592 else
9593 retval = pos.lnum;
9594 if (flags & SP_SETPCMARK)
9595 setpcmark();
9596 curwin->w_cursor = pos;
9597 if (match_pos != NULL)
9598 {
9599 /* Store the match cursor position */
9600 match_pos->lnum = pos.lnum;
9601 match_pos->col = pos.col + 1;
9602 }
9603 /* "/$" will put the cursor after the end of the line, may need to
9604 * correct that here */
9605 check_cursor();
9606 }
9607
9608 /* If 'n' flag is used: restore cursor position. */
9609 if (flags & SP_NOMOVE)
9610 curwin->w_cursor = save_cursor;
9611 else
9612 curwin->w_set_curswant = TRUE;
9613theend:
9614 p_ws = save_p_ws;
9615
9616 return retval;
9617}
9618
9619#ifdef FEAT_FLOAT
9620
9621/*
9622 * round() is not in C90, use ceil() or floor() instead.
9623 */
9624 float_T
9625vim_round(float_T f)
9626{
9627 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9628}
9629
9630/*
9631 * "round({float})" function
9632 */
9633 static void
9634f_round(typval_T *argvars, typval_T *rettv)
9635{
9636 float_T f = 0.0;
9637
9638 rettv->v_type = VAR_FLOAT;
9639 if (get_float_arg(argvars, &f) == OK)
9640 rettv->vval.v_float = vim_round(f);
9641 else
9642 rettv->vval.v_float = 0.0;
9643}
9644#endif
9645
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009646#ifdef FEAT_RUBY
9647/*
9648 * "rubyeval()" function
9649 */
9650 static void
9651f_rubyeval(typval_T *argvars, typval_T *rettv)
9652{
9653 char_u *str;
9654 char_u buf[NUMBUFLEN];
9655
9656 str = tv_get_string_buf(&argvars[0], buf);
9657 do_rubyeval(str, rettv);
9658}
9659#endif
9660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009661/*
9662 * "screenattr()" function
9663 */
9664 static void
9665f_screenattr(typval_T *argvars, typval_T *rettv)
9666{
9667 int row;
9668 int col;
9669 int c;
9670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009671 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9672 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009673 if (row < 0 || row >= screen_Rows
9674 || col < 0 || col >= screen_Columns)
9675 c = -1;
9676 else
9677 c = ScreenAttrs[LineOffset[row] + col];
9678 rettv->vval.v_number = c;
9679}
9680
9681/*
9682 * "screenchar()" function
9683 */
9684 static void
9685f_screenchar(typval_T *argvars, typval_T *rettv)
9686{
9687 int row;
9688 int col;
9689 int off;
9690 int c;
9691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009692 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9693 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009694 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009695 c = -1;
9696 else
9697 {
9698 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009699 if (enc_utf8 && ScreenLinesUC[off] != 0)
9700 c = ScreenLinesUC[off];
9701 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009702 c = ScreenLines[off];
9703 }
9704 rettv->vval.v_number = c;
9705}
9706
9707/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009708 * "screenchars()" function
9709 */
9710 static void
9711f_screenchars(typval_T *argvars, typval_T *rettv)
9712{
9713 int row;
9714 int col;
9715 int off;
9716 int c;
9717 int i;
9718
9719 if (rettv_list_alloc(rettv) == FAIL)
9720 return;
9721 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9722 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9723 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9724 return;
9725
9726 off = LineOffset[row] + col;
9727 if (enc_utf8 && ScreenLinesUC[off] != 0)
9728 c = ScreenLinesUC[off];
9729 else
9730 c = ScreenLines[off];
9731 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9732
9733 if (enc_utf8)
9734
9735 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9736 list_append_number(rettv->vval.v_list,
9737 (varnumber_T)ScreenLinesC[i][off]);
9738}
9739
9740/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009741 * "screencol()" function
9742 *
9743 * First column is 1 to be consistent with virtcol().
9744 */
9745 static void
9746f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9747{
9748 rettv->vval.v_number = screen_screencol() + 1;
9749}
9750
9751/*
9752 * "screenrow()" function
9753 */
9754 static void
9755f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9756{
9757 rettv->vval.v_number = screen_screenrow() + 1;
9758}
9759
9760/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009761 * "screenstring()" function
9762 */
9763 static void
9764f_screenstring(typval_T *argvars, typval_T *rettv)
9765{
9766 int row;
9767 int col;
9768 int off;
9769 int c;
9770 int i;
9771 char_u buf[MB_MAXBYTES + 1];
9772 int buflen = 0;
9773
9774 rettv->vval.v_string = NULL;
9775 rettv->v_type = VAR_STRING;
9776
9777 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9778 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9779 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9780 return;
9781
9782 off = LineOffset[row] + col;
9783 if (enc_utf8 && ScreenLinesUC[off] != 0)
9784 c = ScreenLinesUC[off];
9785 else
9786 c = ScreenLines[off];
9787 buflen += mb_char2bytes(c, buf);
9788
9789 if (enc_utf8)
9790 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9791 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9792
9793 buf[buflen] = NUL;
9794 rettv->vval.v_string = vim_strsave(buf);
9795}
9796
9797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 * "search()" function
9799 */
9800 static void
9801f_search(typval_T *argvars, typval_T *rettv)
9802{
9803 int flags = 0;
9804
9805 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9806}
9807
9808/*
9809 * "searchdecl()" function
9810 */
9811 static void
9812f_searchdecl(typval_T *argvars, typval_T *rettv)
9813{
9814 int locally = 1;
9815 int thisblock = 0;
9816 int error = FALSE;
9817 char_u *name;
9818
9819 rettv->vval.v_number = 1; /* default: FAIL */
9820
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009821 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009822 if (argvars[1].v_type != VAR_UNKNOWN)
9823 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009824 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009826 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 }
9828 if (!error && name != NULL)
9829 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9830 locally, thisblock, SEARCH_KEEP) == FAIL;
9831}
9832
9833/*
9834 * Used by searchpair() and searchpairpos()
9835 */
9836 static int
9837searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9838{
9839 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009840 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 int save_p_ws = p_ws;
9842 int dir;
9843 int flags = 0;
9844 char_u nbuf1[NUMBUFLEN];
9845 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009846 int retval = 0; /* default: FAIL */
9847 long lnum_stop = 0;
9848 long time_limit = 0;
9849
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009850 /* Get the three pattern arguments: start, middle, end. Will result in an
9851 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009852 spat = tv_get_string_chk(&argvars[0]);
9853 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9854 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009855 if (spat == NULL || mpat == NULL || epat == NULL)
9856 goto theend; /* type error */
9857
9858 /* Handle the optional fourth argument: flags */
9859 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9860 if (dir == 0)
9861 goto theend;
9862
9863 /* Don't accept SP_END or SP_SUBPAT.
9864 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9865 */
9866 if ((flags & (SP_END | SP_SUBPAT)) != 0
9867 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9868 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009869 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009870 goto theend;
9871 }
9872
9873 /* Using 'r' implies 'W', otherwise it doesn't work. */
9874 if (flags & SP_REPEAT)
9875 p_ws = FALSE;
9876
9877 /* Optional fifth argument: skip expression */
9878 if (argvars[3].v_type == VAR_UNKNOWN
9879 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009880 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009881 else
9882 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009883 skip = &argvars[4];
9884 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9885 && skip->v_type != VAR_STRING)
9886 {
9887 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009888 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009889 goto theend;
9890 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009891 if (argvars[5].v_type != VAR_UNKNOWN)
9892 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009893 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009894 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009895 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009896 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009897 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009898 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009899#ifdef FEAT_RELTIME
9900 if (argvars[6].v_type != VAR_UNKNOWN)
9901 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009902 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009903 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009904 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009905 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009906 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009907 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009908 }
9909#endif
9910 }
9911 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009912
9913 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9914 match_pos, lnum_stop, time_limit);
9915
9916theend:
9917 p_ws = save_p_ws;
9918
9919 return retval;
9920}
9921
9922/*
9923 * "searchpair()" function
9924 */
9925 static void
9926f_searchpair(typval_T *argvars, typval_T *rettv)
9927{
9928 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9929}
9930
9931/*
9932 * "searchpairpos()" function
9933 */
9934 static void
9935f_searchpairpos(typval_T *argvars, typval_T *rettv)
9936{
9937 pos_T match_pos;
9938 int lnum = 0;
9939 int col = 0;
9940
9941 if (rettv_list_alloc(rettv) == FAIL)
9942 return;
9943
9944 if (searchpair_cmn(argvars, &match_pos) > 0)
9945 {
9946 lnum = match_pos.lnum;
9947 col = match_pos.col;
9948 }
9949
9950 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9951 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9952}
9953
9954/*
9955 * Search for a start/middle/end thing.
9956 * Used by searchpair(), see its documentation for the details.
9957 * Returns 0 or -1 for no match,
9958 */
9959 long
9960do_searchpair(
9961 char_u *spat, /* start pattern */
9962 char_u *mpat, /* middle pattern */
9963 char_u *epat, /* end pattern */
9964 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009965 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009966 int flags, /* SP_SETPCMARK and other SP_ values */
9967 pos_T *match_pos,
9968 linenr_T lnum_stop, /* stop at this line if not zero */
9969 long time_limit UNUSED) /* stop after this many msec */
9970{
9971 char_u *save_cpo;
9972 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9973 long retval = 0;
9974 pos_T pos;
9975 pos_T firstpos;
9976 pos_T foundpos;
9977 pos_T save_cursor;
9978 pos_T save_pos;
9979 int n;
9980 int r;
9981 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009982 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009983 int err;
9984 int options = SEARCH_KEEP;
9985 proftime_T tm;
9986
9987 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9988 save_cpo = p_cpo;
9989 p_cpo = empty_option;
9990
9991#ifdef FEAT_RELTIME
9992 /* Set the time limit, if there is one. */
9993 profile_setlimit(time_limit, &tm);
9994#endif
9995
9996 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9997 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009998 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9999 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010000 if (pat2 == NULL || pat3 == NULL)
10001 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010002 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010003 if (*mpat == NUL)
10004 STRCPY(pat3, pat2);
10005 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010006 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010007 spat, epat, mpat);
10008 if (flags & SP_START)
10009 options |= SEARCH_START;
10010
Bram Moolenaar48570482017-10-30 21:48:41 +010010011 if (skip != NULL)
10012 {
10013 /* Empty string means to not use the skip expression. */
10014 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10015 use_skip = skip->vval.v_string != NULL
10016 && *skip->vval.v_string != NUL;
10017 }
10018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 save_cursor = curwin->w_cursor;
10020 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010021 CLEAR_POS(&firstpos);
10022 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010023 pat = pat3;
10024 for (;;)
10025 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010026 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010027 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010028 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010029 /* didn't find it or found the first match again: FAIL */
10030 break;
10031
10032 if (firstpos.lnum == 0)
10033 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010034 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010035 {
10036 /* Found the same position again. Can happen with a pattern that
10037 * has "\zs" at the end and searching backwards. Advance one
10038 * character and try again. */
10039 if (dir == BACKWARD)
10040 decl(&pos);
10041 else
10042 incl(&pos);
10043 }
10044 foundpos = pos;
10045
10046 /* clear the start flag to avoid getting stuck here */
10047 options &= ~SEARCH_START;
10048
10049 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010050 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010051 {
10052 save_pos = curwin->w_cursor;
10053 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010054 err = FALSE;
10055 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010056 curwin->w_cursor = save_pos;
10057 if (err)
10058 {
10059 /* Evaluating {skip} caused an error, break here. */
10060 curwin->w_cursor = save_cursor;
10061 retval = -1;
10062 break;
10063 }
10064 if (r)
10065 continue;
10066 }
10067
10068 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10069 {
10070 /* Found end when searching backwards or start when searching
10071 * forward: nested pair. */
10072 ++nest;
10073 pat = pat2; /* nested, don't search for middle */
10074 }
10075 else
10076 {
10077 /* Found end when searching forward or start when searching
10078 * backward: end of (nested) pair; or found middle in outer pair. */
10079 if (--nest == 1)
10080 pat = pat3; /* outer level, search for middle */
10081 }
10082
10083 if (nest == 0)
10084 {
10085 /* Found the match: return matchcount or line number. */
10086 if (flags & SP_RETCOUNT)
10087 ++retval;
10088 else
10089 retval = pos.lnum;
10090 if (flags & SP_SETPCMARK)
10091 setpcmark();
10092 curwin->w_cursor = pos;
10093 if (!(flags & SP_REPEAT))
10094 break;
10095 nest = 1; /* search for next unmatched */
10096 }
10097 }
10098
10099 if (match_pos != NULL)
10100 {
10101 /* Store the match cursor position */
10102 match_pos->lnum = curwin->w_cursor.lnum;
10103 match_pos->col = curwin->w_cursor.col + 1;
10104 }
10105
10106 /* If 'n' flag is used or search failed: restore cursor position. */
10107 if ((flags & SP_NOMOVE) || retval == 0)
10108 curwin->w_cursor = save_cursor;
10109
10110theend:
10111 vim_free(pat2);
10112 vim_free(pat3);
10113 if (p_cpo == empty_option)
10114 p_cpo = save_cpo;
10115 else
10116 /* Darn, evaluating the {skip} expression changed the value. */
10117 free_string_option(save_cpo);
10118
10119 return retval;
10120}
10121
10122/*
10123 * "searchpos()" function
10124 */
10125 static void
10126f_searchpos(typval_T *argvars, typval_T *rettv)
10127{
10128 pos_T match_pos;
10129 int lnum = 0;
10130 int col = 0;
10131 int n;
10132 int flags = 0;
10133
10134 if (rettv_list_alloc(rettv) == FAIL)
10135 return;
10136
10137 n = search_cmn(argvars, &match_pos, &flags);
10138 if (n > 0)
10139 {
10140 lnum = match_pos.lnum;
10141 col = match_pos.col;
10142 }
10143
10144 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10145 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10146 if (flags & SP_SUBPAT)
10147 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10148}
10149
10150 static void
10151f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10152{
10153#ifdef FEAT_CLIENTSERVER
10154 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010155 char_u *server = tv_get_string_chk(&argvars[0]);
10156 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010157
10158 rettv->vval.v_number = -1;
10159 if (server == NULL || reply == NULL)
10160 return;
10161 if (check_restricted() || check_secure())
10162 return;
10163# ifdef FEAT_X11
10164 if (check_connection() == FAIL)
10165 return;
10166# endif
10167
10168 if (serverSendReply(server, reply) < 0)
10169 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010170 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010171 return;
10172 }
10173 rettv->vval.v_number = 0;
10174#else
10175 rettv->vval.v_number = -1;
10176#endif
10177}
10178
10179 static void
10180f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10181{
10182 char_u *r = NULL;
10183
10184#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010185# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010186 r = serverGetVimNames();
10187# else
10188 make_connection();
10189 if (X_DISPLAY != NULL)
10190 r = serverGetVimNames(X_DISPLAY);
10191# endif
10192#endif
10193 rettv->v_type = VAR_STRING;
10194 rettv->vval.v_string = r;
10195}
10196
10197/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010198 * "setbufline()" function
10199 */
10200 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010201f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010202{
10203 linenr_T lnum;
10204 buf_T *buf;
10205
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010206 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010207 if (buf == NULL)
10208 rettv->vval.v_number = 1; /* FAIL */
10209 else
10210 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010211 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010212 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010213 }
10214}
10215
10216/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010217 * "setbufvar()" function
10218 */
10219 static void
10220f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10221{
10222 buf_T *buf;
10223 char_u *varname, *bufvarname;
10224 typval_T *varp;
10225 char_u nbuf[NUMBUFLEN];
10226
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010227 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010228 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010229 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10230 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010231 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010232 varp = &argvars[2];
10233
10234 if (buf != NULL && varname != NULL && varp != NULL)
10235 {
10236 if (*varname == '&')
10237 {
10238 long numval;
10239 char_u *strval;
10240 int error = FALSE;
10241 aco_save_T aco;
10242
10243 /* set curbuf to be our buf, temporarily */
10244 aucmd_prepbuf(&aco, buf);
10245
10246 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010247 numval = (long)tv_get_number_chk(varp, &error);
10248 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 if (!error && strval != NULL)
10250 set_option_value(varname, numval, strval, OPT_LOCAL);
10251
10252 /* reset notion of buffer */
10253 aucmd_restbuf(&aco);
10254 }
10255 else
10256 {
10257 buf_T *save_curbuf = curbuf;
10258
Bram Moolenaar964b3742019-05-24 18:54:09 +020010259 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010260 if (bufvarname != NULL)
10261 {
10262 curbuf = buf;
10263 STRCPY(bufvarname, "b:");
10264 STRCPY(bufvarname + 2, varname);
10265 set_var(bufvarname, varp, TRUE);
10266 vim_free(bufvarname);
10267 curbuf = save_curbuf;
10268 }
10269 }
10270 }
10271}
10272
10273 static void
10274f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10275{
10276 dict_T *d;
10277 dictitem_T *di;
10278 char_u *csearch;
10279
10280 if (argvars[0].v_type != VAR_DICT)
10281 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010282 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010283 return;
10284 }
10285
10286 if ((d = argvars[0].vval.v_dict) != NULL)
10287 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010288 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289 if (csearch != NULL)
10290 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010291 if (enc_utf8)
10292 {
10293 int pcc[MAX_MCO];
10294 int c = utfc_ptr2char(csearch, pcc);
10295
10296 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10297 }
10298 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010299 set_last_csearch(PTR2CHAR(csearch),
10300 csearch, MB_PTR2LEN(csearch));
10301 }
10302
10303 di = dict_find(d, (char_u *)"forward", -1);
10304 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010305 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010306 ? FORWARD : BACKWARD);
10307
10308 di = dict_find(d, (char_u *)"until", -1);
10309 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010310 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010311 }
10312}
10313
10314/*
10315 * "setcmdpos()" function
10316 */
10317 static void
10318f_setcmdpos(typval_T *argvars, typval_T *rettv)
10319{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010320 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010321
10322 if (pos >= 0)
10323 rettv->vval.v_number = set_cmdline_pos(pos);
10324}
10325
10326/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010327 * "setenv()" function
10328 */
10329 static void
10330f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10331{
10332 char_u namebuf[NUMBUFLEN];
10333 char_u valbuf[NUMBUFLEN];
10334 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10335
10336 if (argvars[1].v_type == VAR_SPECIAL
10337 && argvars[1].vval.v_number == VVAL_NULL)
10338 vim_unsetenv(name);
10339 else
10340 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10341}
10342
10343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010344 * "setfperm({fname}, {mode})" function
10345 */
10346 static void
10347f_setfperm(typval_T *argvars, typval_T *rettv)
10348{
10349 char_u *fname;
10350 char_u modebuf[NUMBUFLEN];
10351 char_u *mode_str;
10352 int i;
10353 int mask;
10354 int mode = 0;
10355
10356 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010357 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010358 if (fname == NULL)
10359 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010360 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010361 if (mode_str == NULL)
10362 return;
10363 if (STRLEN(mode_str) != 9)
10364 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010365 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010366 return;
10367 }
10368
10369 mask = 1;
10370 for (i = 8; i >= 0; --i)
10371 {
10372 if (mode_str[i] != '-')
10373 mode |= mask;
10374 mask = mask << 1;
10375 }
10376 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10377}
10378
10379/*
10380 * "setline()" function
10381 */
10382 static void
10383f_setline(typval_T *argvars, typval_T *rettv)
10384{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010385 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010386
Bram Moolenaarca851592018-06-06 21:04:07 +020010387 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010388}
10389
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010390/*
10391 * Used by "setqflist()" and "setloclist()" functions
10392 */
10393 static void
10394set_qf_ll_list(
10395 win_T *wp UNUSED,
10396 typval_T *list_arg UNUSED,
10397 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010398 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399 typval_T *rettv)
10400{
10401#ifdef FEAT_QUICKFIX
10402 static char *e_invact = N_("E927: Invalid action: '%s'");
10403 char_u *act;
10404 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010405 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010406#endif
10407
10408 rettv->vval.v_number = -1;
10409
10410#ifdef FEAT_QUICKFIX
10411 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010412 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010413 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010414 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010415 else
10416 {
10417 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010418 dict_T *d = NULL;
10419 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010420
10421 if (action_arg->v_type == VAR_STRING)
10422 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010423 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010424 if (act == NULL)
10425 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010426 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10427 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010428 action = *act;
10429 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010430 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010431 }
10432 else if (action_arg->v_type == VAR_UNKNOWN)
10433 action = ' ';
10434 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010435 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436
Bram Moolenaard823fa92016-08-12 16:29:27 +020010437 if (action_arg->v_type != VAR_UNKNOWN
10438 && what_arg->v_type != VAR_UNKNOWN)
10439 {
10440 if (what_arg->v_type == VAR_DICT)
10441 d = what_arg->vval.v_dict;
10442 else
10443 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010444 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010445 valid_dict = FALSE;
10446 }
10447 }
10448
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010449 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010450 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010451 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10452 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010453 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010454 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010455 }
10456#endif
10457}
10458
10459/*
10460 * "setloclist()" function
10461 */
10462 static void
10463f_setloclist(typval_T *argvars, typval_T *rettv)
10464{
10465 win_T *win;
10466
10467 rettv->vval.v_number = -1;
10468
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010469 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010470 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010471 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010472}
10473
10474/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010475 * "setpos()" function
10476 */
10477 static void
10478f_setpos(typval_T *argvars, typval_T *rettv)
10479{
10480 pos_T pos;
10481 int fnum;
10482 char_u *name;
10483 colnr_T curswant = -1;
10484
10485 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010486 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010487 if (name != NULL)
10488 {
10489 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10490 {
10491 if (--pos.col < 0)
10492 pos.col = 0;
10493 if (name[0] == '.' && name[1] == NUL)
10494 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010495 /* set cursor; "fnum" is ignored */
10496 curwin->w_cursor = pos;
10497 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010498 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010499 curwin->w_curswant = curswant - 1;
10500 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010501 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010502 check_cursor();
10503 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010504 }
10505 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10506 {
10507 /* set mark */
10508 if (setmark_pos(name[1], &pos, fnum) == OK)
10509 rettv->vval.v_number = 0;
10510 }
10511 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010512 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010513 }
10514 }
10515}
10516
10517/*
10518 * "setqflist()" function
10519 */
10520 static void
10521f_setqflist(typval_T *argvars, typval_T *rettv)
10522{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010523 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010524}
10525
10526/*
10527 * "setreg()" function
10528 */
10529 static void
10530f_setreg(typval_T *argvars, typval_T *rettv)
10531{
10532 int regname;
10533 char_u *strregname;
10534 char_u *stropt;
10535 char_u *strval;
10536 int append;
10537 char_u yank_type;
10538 long block_len;
10539
10540 block_len = -1;
10541 yank_type = MAUTO;
10542 append = FALSE;
10543
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010544 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010545 rettv->vval.v_number = 1; /* FAIL is default */
10546
10547 if (strregname == NULL)
10548 return; /* type error; errmsg already given */
10549 regname = *strregname;
10550 if (regname == 0 || regname == '@')
10551 regname = '"';
10552
10553 if (argvars[2].v_type != VAR_UNKNOWN)
10554 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010555 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010556 if (stropt == NULL)
10557 return; /* type error */
10558 for (; *stropt != NUL; ++stropt)
10559 switch (*stropt)
10560 {
10561 case 'a': case 'A': /* append */
10562 append = TRUE;
10563 break;
10564 case 'v': case 'c': /* character-wise selection */
10565 yank_type = MCHAR;
10566 break;
10567 case 'V': case 'l': /* line-wise selection */
10568 yank_type = MLINE;
10569 break;
10570 case 'b': case Ctrl_V: /* block-wise selection */
10571 yank_type = MBLOCK;
10572 if (VIM_ISDIGIT(stropt[1]))
10573 {
10574 ++stropt;
10575 block_len = getdigits(&stropt) - 1;
10576 --stropt;
10577 }
10578 break;
10579 }
10580 }
10581
10582 if (argvars[1].v_type == VAR_LIST)
10583 {
10584 char_u **lstval;
10585 char_u **allocval;
10586 char_u buf[NUMBUFLEN];
10587 char_u **curval;
10588 char_u **curallocval;
10589 list_T *ll = argvars[1].vval.v_list;
10590 listitem_T *li;
10591 int len;
10592
10593 /* If the list is NULL handle like an empty list. */
10594 len = ll == NULL ? 0 : ll->lv_len;
10595
10596 /* First half: use for pointers to result lines; second half: use for
10597 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010598 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010599 if (lstval == NULL)
10600 return;
10601 curval = lstval;
10602 allocval = lstval + len + 2;
10603 curallocval = allocval;
10604
10605 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10606 li = li->li_next)
10607 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010608 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010609 if (strval == NULL)
10610 goto free_lstval;
10611 if (strval == buf)
10612 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010613 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010614 * overwrite the string. */
10615 strval = vim_strsave(buf);
10616 if (strval == NULL)
10617 goto free_lstval;
10618 *curallocval++ = strval;
10619 }
10620 *curval++ = strval;
10621 }
10622 *curval++ = NULL;
10623
10624 write_reg_contents_lst(regname, lstval, -1,
10625 append, yank_type, block_len);
10626free_lstval:
10627 while (curallocval > allocval)
10628 vim_free(*--curallocval);
10629 vim_free(lstval);
10630 }
10631 else
10632 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010633 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 if (strval == NULL)
10635 return;
10636 write_reg_contents_ex(regname, strval, -1,
10637 append, yank_type, block_len);
10638 }
10639 rettv->vval.v_number = 0;
10640}
10641
10642/*
10643 * "settabvar()" function
10644 */
10645 static void
10646f_settabvar(typval_T *argvars, typval_T *rettv)
10647{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648 tabpage_T *save_curtab;
10649 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010650 char_u *varname, *tabvarname;
10651 typval_T *varp;
10652
10653 rettv->vval.v_number = 0;
10654
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010655 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010656 return;
10657
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010658 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10659 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 varp = &argvars[2];
10661
Bram Moolenaar4033c552017-09-16 20:54:51 +020010662 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010663 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010664 save_curtab = curtab;
10665 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010666
Bram Moolenaar964b3742019-05-24 18:54:09 +020010667 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 if (tabvarname != NULL)
10669 {
10670 STRCPY(tabvarname, "t:");
10671 STRCPY(tabvarname + 2, varname);
10672 set_var(tabvarname, varp, TRUE);
10673 vim_free(tabvarname);
10674 }
10675
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010676 /* Restore current tabpage */
10677 if (valid_tabpage(save_curtab))
10678 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010679 }
10680}
10681
10682/*
10683 * "settabwinvar()" function
10684 */
10685 static void
10686f_settabwinvar(typval_T *argvars, typval_T *rettv)
10687{
10688 setwinvar(argvars, rettv, 1);
10689}
10690
10691/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010692 * "settagstack()" function
10693 */
10694 static void
10695f_settagstack(typval_T *argvars, typval_T *rettv)
10696{
10697 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10698 win_T *wp;
10699 dict_T *d;
10700 int action = 'r';
10701
10702 rettv->vval.v_number = -1;
10703
10704 // first argument: window number or id
10705 wp = find_win_by_nr_or_id(&argvars[0]);
10706 if (wp == NULL)
10707 return;
10708
10709 // second argument: dict with items to set in the tag stack
10710 if (argvars[1].v_type != VAR_DICT)
10711 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010712 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010713 return;
10714 }
10715 d = argvars[1].vval.v_dict;
10716 if (d == NULL)
10717 return;
10718
10719 // third argument: action - 'a' for append and 'r' for replace.
10720 // default is to replace the stack.
10721 if (argvars[2].v_type == VAR_UNKNOWN)
10722 action = 'r';
10723 else if (argvars[2].v_type == VAR_STRING)
10724 {
10725 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010726 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010727 if (actstr == NULL)
10728 return;
10729 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10730 action = *actstr;
10731 else
10732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010733 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010734 return;
10735 }
10736 }
10737 else
10738 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010739 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010740 return;
10741 }
10742
10743 if (set_tagstack(wp, d, action) == OK)
10744 rettv->vval.v_number = 0;
10745}
10746
10747/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010748 * "setwinvar()" function
10749 */
10750 static void
10751f_setwinvar(typval_T *argvars, typval_T *rettv)
10752{
10753 setwinvar(argvars, rettv, 0);
10754}
10755
10756#ifdef FEAT_CRYPT
10757/*
10758 * "sha256({string})" function
10759 */
10760 static void
10761f_sha256(typval_T *argvars, typval_T *rettv)
10762{
10763 char_u *p;
10764
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010765 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010766 rettv->vval.v_string = vim_strsave(
10767 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10768 rettv->v_type = VAR_STRING;
10769}
10770#endif /* FEAT_CRYPT */
10771
10772/*
10773 * "shellescape({string})" function
10774 */
10775 static void
10776f_shellescape(typval_T *argvars, typval_T *rettv)
10777{
Bram Moolenaar20615522017-06-05 18:46:26 +020010778 int do_special = non_zero_arg(&argvars[1]);
10779
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010780 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010781 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 rettv->v_type = VAR_STRING;
10783}
10784
10785/*
10786 * shiftwidth() function
10787 */
10788 static void
10789f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10790{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010791 rettv->vval.v_number = 0;
10792
10793 if (argvars[0].v_type != VAR_UNKNOWN)
10794 {
10795 long col;
10796
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010797 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010798 if (col < 0)
10799 return; // type error; errmsg already given
10800#ifdef FEAT_VARTABS
10801 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10802 return;
10803#endif
10804 }
10805
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010806 rettv->vval.v_number = get_sw_value(curbuf);
10807}
10808
10809/*
10810 * "simplify()" function
10811 */
10812 static void
10813f_simplify(typval_T *argvars, typval_T *rettv)
10814{
10815 char_u *p;
10816
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010817 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010818 rettv->vval.v_string = vim_strsave(p);
10819 simplify_filename(rettv->vval.v_string); /* simplify in place */
10820 rettv->v_type = VAR_STRING;
10821}
10822
10823#ifdef FEAT_FLOAT
10824/*
10825 * "sin()" function
10826 */
10827 static void
10828f_sin(typval_T *argvars, typval_T *rettv)
10829{
10830 float_T f = 0.0;
10831
10832 rettv->v_type = VAR_FLOAT;
10833 if (get_float_arg(argvars, &f) == OK)
10834 rettv->vval.v_float = sin(f);
10835 else
10836 rettv->vval.v_float = 0.0;
10837}
10838
10839/*
10840 * "sinh()" function
10841 */
10842 static void
10843f_sinh(typval_T *argvars, typval_T *rettv)
10844{
10845 float_T f = 0.0;
10846
10847 rettv->v_type = VAR_FLOAT;
10848 if (get_float_arg(argvars, &f) == OK)
10849 rettv->vval.v_float = sinh(f);
10850 else
10851 rettv->vval.v_float = 0.0;
10852}
10853#endif
10854
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010855/*
10856 * "soundfold({word})" function
10857 */
10858 static void
10859f_soundfold(typval_T *argvars, typval_T *rettv)
10860{
10861 char_u *s;
10862
10863 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010864 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010865#ifdef FEAT_SPELL
10866 rettv->vval.v_string = eval_soundfold(s);
10867#else
10868 rettv->vval.v_string = vim_strsave(s);
10869#endif
10870}
10871
10872/*
10873 * "spellbadword()" function
10874 */
10875 static void
10876f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10877{
10878 char_u *word = (char_u *)"";
10879 hlf_T attr = HLF_COUNT;
10880 int len = 0;
10881
10882 if (rettv_list_alloc(rettv) == FAIL)
10883 return;
10884
10885#ifdef FEAT_SPELL
10886 if (argvars[0].v_type == VAR_UNKNOWN)
10887 {
10888 /* Find the start and length of the badly spelled word. */
10889 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10890 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010891 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010892 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010893 curwin->w_set_curswant = TRUE;
10894 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010895 }
10896 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10897 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010898 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010899 int capcol = -1;
10900
10901 if (str != NULL)
10902 {
10903 /* Check the argument for spelling. */
10904 while (*str != NUL)
10905 {
10906 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10907 if (attr != HLF_COUNT)
10908 {
10909 word = str;
10910 break;
10911 }
10912 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010913 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010914 }
10915 }
10916 }
10917#endif
10918
10919 list_append_string(rettv->vval.v_list, word, len);
10920 list_append_string(rettv->vval.v_list, (char_u *)(
10921 attr == HLF_SPB ? "bad" :
10922 attr == HLF_SPR ? "rare" :
10923 attr == HLF_SPL ? "local" :
10924 attr == HLF_SPC ? "caps" :
10925 ""), -1);
10926}
10927
10928/*
10929 * "spellsuggest()" function
10930 */
10931 static void
10932f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10933{
10934#ifdef FEAT_SPELL
10935 char_u *str;
10936 int typeerr = FALSE;
10937 int maxcount;
10938 garray_T ga;
10939 int i;
10940 listitem_T *li;
10941 int need_capital = FALSE;
10942#endif
10943
10944 if (rettv_list_alloc(rettv) == FAIL)
10945 return;
10946
10947#ifdef FEAT_SPELL
10948 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10949 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010950 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010951 if (argvars[1].v_type != VAR_UNKNOWN)
10952 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010953 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010954 if (maxcount <= 0)
10955 return;
10956 if (argvars[2].v_type != VAR_UNKNOWN)
10957 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010958 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010959 if (typeerr)
10960 return;
10961 }
10962 }
10963 else
10964 maxcount = 25;
10965
10966 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10967
10968 for (i = 0; i < ga.ga_len; ++i)
10969 {
10970 str = ((char_u **)ga.ga_data)[i];
10971
10972 li = listitem_alloc();
10973 if (li == NULL)
10974 vim_free(str);
10975 else
10976 {
10977 li->li_tv.v_type = VAR_STRING;
10978 li->li_tv.v_lock = 0;
10979 li->li_tv.vval.v_string = str;
10980 list_append(rettv->vval.v_list, li);
10981 }
10982 }
10983 ga_clear(&ga);
10984 }
10985#endif
10986}
10987
10988 static void
10989f_split(typval_T *argvars, typval_T *rettv)
10990{
10991 char_u *str;
10992 char_u *end;
10993 char_u *pat = NULL;
10994 regmatch_T regmatch;
10995 char_u patbuf[NUMBUFLEN];
10996 char_u *save_cpo;
10997 int match;
10998 colnr_T col = 0;
10999 int keepempty = FALSE;
11000 int typeerr = FALSE;
11001
11002 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11003 save_cpo = p_cpo;
11004 p_cpo = (char_u *)"";
11005
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011006 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011007 if (argvars[1].v_type != VAR_UNKNOWN)
11008 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011009 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011010 if (pat == NULL)
11011 typeerr = TRUE;
11012 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011013 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011014 }
11015 if (pat == NULL || *pat == NUL)
11016 pat = (char_u *)"[\\x01- ]\\+";
11017
11018 if (rettv_list_alloc(rettv) == FAIL)
11019 return;
11020 if (typeerr)
11021 return;
11022
11023 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11024 if (regmatch.regprog != NULL)
11025 {
11026 regmatch.rm_ic = FALSE;
11027 while (*str != NUL || keepempty)
11028 {
11029 if (*str == NUL)
11030 match = FALSE; /* empty item at the end */
11031 else
11032 match = vim_regexec_nl(&regmatch, str, col);
11033 if (match)
11034 end = regmatch.startp[0];
11035 else
11036 end = str + STRLEN(str);
11037 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11038 && *str != NUL && match && end < regmatch.endp[0]))
11039 {
11040 if (list_append_string(rettv->vval.v_list, str,
11041 (int)(end - str)) == FAIL)
11042 break;
11043 }
11044 if (!match)
11045 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011046 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011047 if (regmatch.endp[0] > str)
11048 col = 0;
11049 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011050 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011051 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 str = regmatch.endp[0];
11053 }
11054
11055 vim_regfree(regmatch.regprog);
11056 }
11057
11058 p_cpo = save_cpo;
11059}
11060
11061#ifdef FEAT_FLOAT
11062/*
11063 * "sqrt()" function
11064 */
11065 static void
11066f_sqrt(typval_T *argvars, typval_T *rettv)
11067{
11068 float_T f = 0.0;
11069
11070 rettv->v_type = VAR_FLOAT;
11071 if (get_float_arg(argvars, &f) == OK)
11072 rettv->vval.v_float = sqrt(f);
11073 else
11074 rettv->vval.v_float = 0.0;
11075}
11076
11077/*
11078 * "str2float()" function
11079 */
11080 static void
11081f_str2float(typval_T *argvars, typval_T *rettv)
11082{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011083 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011084 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011085
Bram Moolenaar08243d22017-01-10 16:12:29 +010011086 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011087 p = skipwhite(p + 1);
11088 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011089 if (isneg)
11090 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011091 rettv->v_type = VAR_FLOAT;
11092}
11093#endif
11094
11095/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011096 * "str2list()" function
11097 */
11098 static void
11099f_str2list(typval_T *argvars, typval_T *rettv)
11100{
11101 char_u *p;
11102 int utf8 = FALSE;
11103
11104 if (rettv_list_alloc(rettv) == FAIL)
11105 return;
11106
11107 if (argvars[1].v_type != VAR_UNKNOWN)
11108 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11109
11110 p = tv_get_string(&argvars[0]);
11111
11112 if (has_mbyte || utf8)
11113 {
11114 int (*ptr2len)(char_u *);
11115 int (*ptr2char)(char_u *);
11116
11117 if (utf8 || enc_utf8)
11118 {
11119 ptr2len = utf_ptr2len;
11120 ptr2char = utf_ptr2char;
11121 }
11122 else
11123 {
11124 ptr2len = mb_ptr2len;
11125 ptr2char = mb_ptr2char;
11126 }
11127
11128 for ( ; *p != NUL; p += (*ptr2len)(p))
11129 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11130 }
11131 else
11132 for ( ; *p != NUL; ++p)
11133 list_append_number(rettv->vval.v_list, *p);
11134}
11135
11136/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011137 * "str2nr()" function
11138 */
11139 static void
11140f_str2nr(typval_T *argvars, typval_T *rettv)
11141{
11142 int base = 10;
11143 char_u *p;
11144 varnumber_T n;
11145 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011146 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011147
11148 if (argvars[1].v_type != VAR_UNKNOWN)
11149 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011150 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011151 if (base != 2 && base != 8 && base != 10 && base != 16)
11152 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011153 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154 return;
11155 }
11156 }
11157
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011158 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011159 isneg = (*p == '-');
11160 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011161 p = skipwhite(p + 1);
11162 switch (base)
11163 {
11164 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11165 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11166 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11167 default: what = 0;
11168 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011169 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11170 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011171 if (isneg)
11172 rettv->vval.v_number = -n;
11173 else
11174 rettv->vval.v_number = n;
11175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011176}
11177
11178#ifdef HAVE_STRFTIME
11179/*
11180 * "strftime({format}[, {time}])" function
11181 */
11182 static void
11183f_strftime(typval_T *argvars, typval_T *rettv)
11184{
11185 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011186 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011187 struct tm *curtime;
11188 time_t seconds;
11189 char_u *p;
11190
11191 rettv->v_type = VAR_STRING;
11192
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011193 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 if (argvars[1].v_type == VAR_UNKNOWN)
11195 seconds = time(NULL);
11196 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011197 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011198 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011199 /* MSVC returns NULL for an invalid value of seconds. */
11200 if (curtime == NULL)
11201 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11202 else
11203 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011204 vimconv_T conv;
11205 char_u *enc;
11206
11207 conv.vc_type = CONV_NONE;
11208 enc = enc_locale();
11209 convert_setup(&conv, p_enc, enc);
11210 if (conv.vc_type != CONV_NONE)
11211 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011212 if (p != NULL)
11213 (void)strftime((char *)result_buf, sizeof(result_buf),
11214 (char *)p, curtime);
11215 else
11216 result_buf[0] = NUL;
11217
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011218 if (conv.vc_type != CONV_NONE)
11219 vim_free(p);
11220 convert_setup(&conv, enc, p_enc);
11221 if (conv.vc_type != CONV_NONE)
11222 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11223 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011224 rettv->vval.v_string = vim_strsave(result_buf);
11225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011226 /* Release conversion descriptors */
11227 convert_setup(&conv, NULL, NULL);
11228 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229 }
11230}
11231#endif
11232
11233/*
11234 * "strgetchar()" function
11235 */
11236 static void
11237f_strgetchar(typval_T *argvars, typval_T *rettv)
11238{
11239 char_u *str;
11240 int len;
11241 int error = FALSE;
11242 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011243 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011244
11245 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011246 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011247 if (str == NULL)
11248 return;
11249 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011250 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011251 if (error)
11252 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253
Bram Moolenaar13505972019-01-24 15:04:48 +010011254 while (charidx >= 0 && byteidx < len)
11255 {
11256 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011257 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011258 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11259 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011260 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011261 --charidx;
11262 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011263 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011264}
11265
11266/*
11267 * "stridx()" function
11268 */
11269 static void
11270f_stridx(typval_T *argvars, typval_T *rettv)
11271{
11272 char_u buf[NUMBUFLEN];
11273 char_u *needle;
11274 char_u *haystack;
11275 char_u *save_haystack;
11276 char_u *pos;
11277 int start_idx;
11278
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011279 needle = tv_get_string_chk(&argvars[1]);
11280 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011281 rettv->vval.v_number = -1;
11282 if (needle == NULL || haystack == NULL)
11283 return; /* type error; errmsg already given */
11284
11285 if (argvars[2].v_type != VAR_UNKNOWN)
11286 {
11287 int error = FALSE;
11288
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011289 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011290 if (error || start_idx >= (int)STRLEN(haystack))
11291 return;
11292 if (start_idx >= 0)
11293 haystack += start_idx;
11294 }
11295
11296 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11297 if (pos != NULL)
11298 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11299}
11300
11301/*
11302 * "string()" function
11303 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011304 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011305f_string(typval_T *argvars, typval_T *rettv)
11306{
11307 char_u *tofree;
11308 char_u numbuf[NUMBUFLEN];
11309
11310 rettv->v_type = VAR_STRING;
11311 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11312 get_copyID());
11313 /* Make a copy if we have a value but it's not in allocated memory. */
11314 if (rettv->vval.v_string != NULL && tofree == NULL)
11315 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11316}
11317
11318/*
11319 * "strlen()" function
11320 */
11321 static void
11322f_strlen(typval_T *argvars, typval_T *rettv)
11323{
11324 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011325 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011326}
11327
11328/*
11329 * "strchars()" function
11330 */
11331 static void
11332f_strchars(typval_T *argvars, typval_T *rettv)
11333{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011334 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011335 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011336 varnumber_T len = 0;
11337 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011338
11339 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011340 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011341 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011342 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011343 else
11344 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011345 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11346 while (*s != NUL)
11347 {
11348 func_mb_ptr2char_adv(&s);
11349 ++len;
11350 }
11351 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011352 }
11353}
11354
11355/*
11356 * "strdisplaywidth()" function
11357 */
11358 static void
11359f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11360{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011361 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011362 int col = 0;
11363
11364 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011365 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011366
11367 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11368}
11369
11370/*
11371 * "strwidth()" function
11372 */
11373 static void
11374f_strwidth(typval_T *argvars, typval_T *rettv)
11375{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011376 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011377
Bram Moolenaar13505972019-01-24 15:04:48 +010011378 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011379}
11380
11381/*
11382 * "strcharpart()" function
11383 */
11384 static void
11385f_strcharpart(typval_T *argvars, typval_T *rettv)
11386{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011387 char_u *p;
11388 int nchar;
11389 int nbyte = 0;
11390 int charlen;
11391 int len = 0;
11392 int slen;
11393 int error = FALSE;
11394
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011395 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011396 slen = (int)STRLEN(p);
11397
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011398 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011399 if (!error)
11400 {
11401 if (nchar > 0)
11402 while (nchar > 0 && nbyte < slen)
11403 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011404 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011405 --nchar;
11406 }
11407 else
11408 nbyte = nchar;
11409 if (argvars[2].v_type != VAR_UNKNOWN)
11410 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011411 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011412 while (charlen > 0 && nbyte + len < slen)
11413 {
11414 int off = nbyte + len;
11415
11416 if (off < 0)
11417 len += 1;
11418 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011419 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011420 --charlen;
11421 }
11422 }
11423 else
11424 len = slen - nbyte; /* default: all bytes that are available. */
11425 }
11426
11427 /*
11428 * Only return the overlap between the specified part and the actual
11429 * string.
11430 */
11431 if (nbyte < 0)
11432 {
11433 len += nbyte;
11434 nbyte = 0;
11435 }
11436 else if (nbyte > slen)
11437 nbyte = slen;
11438 if (len < 0)
11439 len = 0;
11440 else if (nbyte + len > slen)
11441 len = slen - nbyte;
11442
11443 rettv->v_type = VAR_STRING;
11444 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011445}
11446
11447/*
11448 * "strpart()" function
11449 */
11450 static void
11451f_strpart(typval_T *argvars, typval_T *rettv)
11452{
11453 char_u *p;
11454 int n;
11455 int len;
11456 int slen;
11457 int error = FALSE;
11458
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011459 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011460 slen = (int)STRLEN(p);
11461
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011462 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011463 if (error)
11464 len = 0;
11465 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011466 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011467 else
11468 len = slen - n; /* default len: all bytes that are available. */
11469
11470 /*
11471 * Only return the overlap between the specified part and the actual
11472 * string.
11473 */
11474 if (n < 0)
11475 {
11476 len += n;
11477 n = 0;
11478 }
11479 else if (n > slen)
11480 n = slen;
11481 if (len < 0)
11482 len = 0;
11483 else if (n + len > slen)
11484 len = slen - n;
11485
11486 rettv->v_type = VAR_STRING;
11487 rettv->vval.v_string = vim_strnsave(p + n, len);
11488}
11489
11490/*
11491 * "strridx()" function
11492 */
11493 static void
11494f_strridx(typval_T *argvars, typval_T *rettv)
11495{
11496 char_u buf[NUMBUFLEN];
11497 char_u *needle;
11498 char_u *haystack;
11499 char_u *rest;
11500 char_u *lastmatch = NULL;
11501 int haystack_len, end_idx;
11502
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011503 needle = tv_get_string_chk(&argvars[1]);
11504 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011505
11506 rettv->vval.v_number = -1;
11507 if (needle == NULL || haystack == NULL)
11508 return; /* type error; errmsg already given */
11509
11510 haystack_len = (int)STRLEN(haystack);
11511 if (argvars[2].v_type != VAR_UNKNOWN)
11512 {
11513 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011514 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011515 if (end_idx < 0)
11516 return; /* can never find a match */
11517 }
11518 else
11519 end_idx = haystack_len;
11520
11521 if (*needle == NUL)
11522 {
11523 /* Empty string matches past the end. */
11524 lastmatch = haystack + end_idx;
11525 }
11526 else
11527 {
11528 for (rest = haystack; *rest != '\0'; ++rest)
11529 {
11530 rest = (char_u *)strstr((char *)rest, (char *)needle);
11531 if (rest == NULL || rest > haystack + end_idx)
11532 break;
11533 lastmatch = rest;
11534 }
11535 }
11536
11537 if (lastmatch == NULL)
11538 rettv->vval.v_number = -1;
11539 else
11540 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11541}
11542
11543/*
11544 * "strtrans()" function
11545 */
11546 static void
11547f_strtrans(typval_T *argvars, typval_T *rettv)
11548{
11549 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011550 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011551}
11552
11553/*
11554 * "submatch()" function
11555 */
11556 static void
11557f_submatch(typval_T *argvars, typval_T *rettv)
11558{
11559 int error = FALSE;
11560 int no;
11561 int retList = 0;
11562
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011563 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011564 if (error)
11565 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011566 if (no < 0 || no >= NSUBEXP)
11567 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011568 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011569 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011570 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011571 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011572 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011573 if (error)
11574 return;
11575
11576 if (retList == 0)
11577 {
11578 rettv->v_type = VAR_STRING;
11579 rettv->vval.v_string = reg_submatch(no);
11580 }
11581 else
11582 {
11583 rettv->v_type = VAR_LIST;
11584 rettv->vval.v_list = reg_submatch_list(no);
11585 }
11586}
11587
11588/*
11589 * "substitute()" function
11590 */
11591 static void
11592f_substitute(typval_T *argvars, typval_T *rettv)
11593{
11594 char_u patbuf[NUMBUFLEN];
11595 char_u subbuf[NUMBUFLEN];
11596 char_u flagsbuf[NUMBUFLEN];
11597
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011598 char_u *str = tv_get_string_chk(&argvars[0]);
11599 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011600 char_u *sub = NULL;
11601 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011602 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011603
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011604 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11605 expr = &argvars[2];
11606 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011607 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011609 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011610 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11611 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011612 rettv->vval.v_string = NULL;
11613 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011614 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011615}
11616
11617/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011618 * "swapinfo(swap_filename)" function
11619 */
11620 static void
11621f_swapinfo(typval_T *argvars, typval_T *rettv)
11622{
11623 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011624 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011625}
11626
11627/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011628 * "swapname(expr)" function
11629 */
11630 static void
11631f_swapname(typval_T *argvars, typval_T *rettv)
11632{
11633 buf_T *buf;
11634
11635 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011636 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011637 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11638 || buf->b_ml.ml_mfp->mf_fname == NULL)
11639 rettv->vval.v_string = NULL;
11640 else
11641 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11642}
11643
11644/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011645 * "synID(lnum, col, trans)" function
11646 */
11647 static void
11648f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11649{
11650 int id = 0;
11651#ifdef FEAT_SYN_HL
11652 linenr_T lnum;
11653 colnr_T col;
11654 int trans;
11655 int transerr = FALSE;
11656
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011657 lnum = tv_get_lnum(argvars); /* -1 on type error */
11658 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11659 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011660
11661 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11662 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11663 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11664#endif
11665
11666 rettv->vval.v_number = id;
11667}
11668
11669/*
11670 * "synIDattr(id, what [, mode])" function
11671 */
11672 static void
11673f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11674{
11675 char_u *p = NULL;
11676#ifdef FEAT_SYN_HL
11677 int id;
11678 char_u *what;
11679 char_u *mode;
11680 char_u modebuf[NUMBUFLEN];
11681 int modec;
11682
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011683 id = (int)tv_get_number(&argvars[0]);
11684 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011685 if (argvars[2].v_type != VAR_UNKNOWN)
11686 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011687 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011688 modec = TOLOWER_ASC(mode[0]);
11689 if (modec != 't' && modec != 'c' && modec != 'g')
11690 modec = 0; /* replace invalid with current */
11691 }
11692 else
11693 {
11694#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11695 if (USE_24BIT)
11696 modec = 'g';
11697 else
11698#endif
11699 if (t_colors > 1)
11700 modec = 'c';
11701 else
11702 modec = 't';
11703 }
11704
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011705 switch (TOLOWER_ASC(what[0]))
11706 {
11707 case 'b':
11708 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11709 p = highlight_color(id, what, modec);
11710 else /* bold */
11711 p = highlight_has_attr(id, HL_BOLD, modec);
11712 break;
11713
11714 case 'f': /* fg[#] or font */
11715 p = highlight_color(id, what, modec);
11716 break;
11717
11718 case 'i':
11719 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11720 p = highlight_has_attr(id, HL_INVERSE, modec);
11721 else /* italic */
11722 p = highlight_has_attr(id, HL_ITALIC, modec);
11723 break;
11724
11725 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011726 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011727 break;
11728
11729 case 'r': /* reverse */
11730 p = highlight_has_attr(id, HL_INVERSE, modec);
11731 break;
11732
11733 case 's':
11734 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11735 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011736 /* strikeout */
11737 else if (TOLOWER_ASC(what[1]) == 't' &&
11738 TOLOWER_ASC(what[2]) == 'r')
11739 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011740 else /* standout */
11741 p = highlight_has_attr(id, HL_STANDOUT, modec);
11742 break;
11743
11744 case 'u':
11745 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11746 /* underline */
11747 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11748 else
11749 /* undercurl */
11750 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11751 break;
11752 }
11753
11754 if (p != NULL)
11755 p = vim_strsave(p);
11756#endif
11757 rettv->v_type = VAR_STRING;
11758 rettv->vval.v_string = p;
11759}
11760
11761/*
11762 * "synIDtrans(id)" function
11763 */
11764 static void
11765f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11766{
11767 int id;
11768
11769#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011770 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011771
11772 if (id > 0)
11773 id = syn_get_final_id(id);
11774 else
11775#endif
11776 id = 0;
11777
11778 rettv->vval.v_number = id;
11779}
11780
11781/*
11782 * "synconcealed(lnum, col)" function
11783 */
11784 static void
11785f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11786{
11787#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11788 linenr_T lnum;
11789 colnr_T col;
11790 int syntax_flags = 0;
11791 int cchar;
11792 int matchid = 0;
11793 char_u str[NUMBUFLEN];
11794#endif
11795
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011796 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011797
11798#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011799 lnum = tv_get_lnum(argvars); /* -1 on type error */
11800 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801
11802 vim_memset(str, NUL, sizeof(str));
11803
11804 if (rettv_list_alloc(rettv) != FAIL)
11805 {
11806 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11807 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11808 && curwin->w_p_cole > 0)
11809 {
11810 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11811 syntax_flags = get_syntax_info(&matchid);
11812
11813 /* get the conceal character */
11814 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11815 {
11816 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011817 if (cchar == NUL && curwin->w_p_cole == 1)
11818 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011819 if (cchar != NUL)
11820 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011821 if (has_mbyte)
11822 (*mb_char2bytes)(cchar, str);
11823 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011824 str[0] = cchar;
11825 }
11826 }
11827 }
11828
11829 list_append_number(rettv->vval.v_list,
11830 (syntax_flags & HL_CONCEAL) != 0);
11831 /* -1 to auto-determine strlen */
11832 list_append_string(rettv->vval.v_list, str, -1);
11833 list_append_number(rettv->vval.v_list, matchid);
11834 }
11835#endif
11836}
11837
11838/*
11839 * "synstack(lnum, col)" function
11840 */
11841 static void
11842f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11843{
11844#ifdef FEAT_SYN_HL
11845 linenr_T lnum;
11846 colnr_T col;
11847 int i;
11848 int id;
11849#endif
11850
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011851 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011852
11853#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011854 lnum = tv_get_lnum(argvars); /* -1 on type error */
11855 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011856
11857 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11858 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11859 && rettv_list_alloc(rettv) != FAIL)
11860 {
11861 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11862 for (i = 0; ; ++i)
11863 {
11864 id = syn_get_stack_item(i);
11865 if (id < 0)
11866 break;
11867 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11868 break;
11869 }
11870 }
11871#endif
11872}
11873
11874 static void
11875get_cmd_output_as_rettv(
11876 typval_T *argvars,
11877 typval_T *rettv,
11878 int retlist)
11879{
11880 char_u *res = NULL;
11881 char_u *p;
11882 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011883 int err = FALSE;
11884 FILE *fd;
11885 list_T *list = NULL;
11886 int flags = SHELL_SILENT;
11887
11888 rettv->v_type = VAR_STRING;
11889 rettv->vval.v_string = NULL;
11890 if (check_restricted() || check_secure())
11891 goto errret;
11892
11893 if (argvars[1].v_type != VAR_UNKNOWN)
11894 {
11895 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011896 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011897 * command.
11898 */
11899 if ((infile = vim_tempname('i', TRUE)) == NULL)
11900 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011901 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011902 goto errret;
11903 }
11904
11905 fd = mch_fopen((char *)infile, WRITEBIN);
11906 if (fd == NULL)
11907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011908 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909 goto errret;
11910 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011911 if (argvars[1].v_type == VAR_NUMBER)
11912 {
11913 linenr_T lnum;
11914 buf_T *buf;
11915
11916 buf = buflist_findnr(argvars[1].vval.v_number);
11917 if (buf == NULL)
11918 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011919 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011920 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011921 goto errret;
11922 }
11923
11924 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11925 {
11926 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11927 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11928 {
11929 err = TRUE;
11930 break;
11931 }
11932 if (putc(NL, fd) == EOF)
11933 {
11934 err = TRUE;
11935 break;
11936 }
11937 }
11938 }
11939 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011940 {
11941 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11942 err = TRUE;
11943 }
11944 else
11945 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011946 size_t len;
11947 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011948
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011949 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011950 if (p == NULL)
11951 {
11952 fclose(fd);
11953 goto errret; /* type error; errmsg already given */
11954 }
11955 len = STRLEN(p);
11956 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11957 err = TRUE;
11958 }
11959 if (fclose(fd) != 0)
11960 err = TRUE;
11961 if (err)
11962 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011963 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011964 goto errret;
11965 }
11966 }
11967
11968 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11969 * echoes typeahead, that messes up the display. */
11970 if (!msg_silent)
11971 flags += SHELL_COOKED;
11972
11973 if (retlist)
11974 {
11975 int len;
11976 listitem_T *li;
11977 char_u *s = NULL;
11978 char_u *start;
11979 char_u *end;
11980 int i;
11981
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011982 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011983 if (res == NULL)
11984 goto errret;
11985
11986 list = list_alloc();
11987 if (list == NULL)
11988 goto errret;
11989
11990 for (i = 0; i < len; ++i)
11991 {
11992 start = res + i;
11993 while (i < len && res[i] != NL)
11994 ++i;
11995 end = res + i;
11996
Bram Moolenaar964b3742019-05-24 18:54:09 +020011997 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011998 if (s == NULL)
11999 goto errret;
12000
12001 for (p = s; start < end; ++p, ++start)
12002 *p = *start == NUL ? NL : *start;
12003 *p = NUL;
12004
12005 li = listitem_alloc();
12006 if (li == NULL)
12007 {
12008 vim_free(s);
12009 goto errret;
12010 }
12011 li->li_tv.v_type = VAR_STRING;
12012 li->li_tv.v_lock = 0;
12013 li->li_tv.vval.v_string = s;
12014 list_append(list, li);
12015 }
12016
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012017 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012018 list = NULL;
12019 }
12020 else
12021 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012022 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010012023#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012024 /* translate <CR><NL> into <NL> */
12025 if (res != NULL)
12026 {
12027 char_u *s, *d;
12028
12029 d = res;
12030 for (s = res; *s; ++s)
12031 {
12032 if (s[0] == CAR && s[1] == NL)
12033 ++s;
12034 *d++ = *s;
12035 }
12036 *d = NUL;
12037 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012038#endif
12039 rettv->vval.v_string = res;
12040 res = NULL;
12041 }
12042
12043errret:
12044 if (infile != NULL)
12045 {
12046 mch_remove(infile);
12047 vim_free(infile);
12048 }
12049 if (res != NULL)
12050 vim_free(res);
12051 if (list != NULL)
12052 list_free(list);
12053}
12054
12055/*
12056 * "system()" function
12057 */
12058 static void
12059f_system(typval_T *argvars, typval_T *rettv)
12060{
12061 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12062}
12063
12064/*
12065 * "systemlist()" function
12066 */
12067 static void
12068f_systemlist(typval_T *argvars, typval_T *rettv)
12069{
12070 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12071}
12072
12073/*
12074 * "tabpagebuflist()" function
12075 */
12076 static void
12077f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12078{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079 tabpage_T *tp;
12080 win_T *wp = NULL;
12081
12082 if (argvars[0].v_type == VAR_UNKNOWN)
12083 wp = firstwin;
12084 else
12085 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012086 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012087 if (tp != NULL)
12088 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12089 }
12090 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12091 {
12092 for (; wp != NULL; wp = wp->w_next)
12093 if (list_append_number(rettv->vval.v_list,
12094 wp->w_buffer->b_fnum) == FAIL)
12095 break;
12096 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012097}
12098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012099/*
12100 * "tabpagenr()" function
12101 */
12102 static void
12103f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12104{
12105 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012106 char_u *arg;
12107
12108 if (argvars[0].v_type != VAR_UNKNOWN)
12109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012110 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012111 nr = 0;
12112 if (arg != NULL)
12113 {
12114 if (STRCMP(arg, "$") == 0)
12115 nr = tabpage_index(NULL) - 1;
12116 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012117 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012118 }
12119 }
12120 else
12121 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012122 rettv->vval.v_number = nr;
12123}
12124
12125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012126/*
12127 * Common code for tabpagewinnr() and winnr().
12128 */
12129 static int
12130get_winnr(tabpage_T *tp, typval_T *argvar)
12131{
12132 win_T *twin;
12133 int nr = 1;
12134 win_T *wp;
12135 char_u *arg;
12136
12137 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12138 if (argvar->v_type != VAR_UNKNOWN)
12139 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012140 int invalid_arg = FALSE;
12141
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012142 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012143 if (arg == NULL)
12144 nr = 0; /* type error; errmsg already given */
12145 else if (STRCMP(arg, "$") == 0)
12146 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12147 else if (STRCMP(arg, "#") == 0)
12148 {
12149 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12150 if (twin == NULL)
12151 nr = 0;
12152 }
12153 else
12154 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012155 long count;
12156 char_u *endp;
12157
12158 // Extract the window count (if specified). e.g. winnr('3j')
12159 count = strtol((char *)arg, (char **)&endp, 10);
12160 if (count <= 0)
12161 count = 1; // if count is not specified, default to 1
12162 if (endp != NULL && *endp != '\0')
12163 {
12164 if (STRCMP(endp, "j") == 0)
12165 twin = win_vert_neighbor(tp, twin, FALSE, count);
12166 else if (STRCMP(endp, "k") == 0)
12167 twin = win_vert_neighbor(tp, twin, TRUE, count);
12168 else if (STRCMP(endp, "h") == 0)
12169 twin = win_horz_neighbor(tp, twin, TRUE, count);
12170 else if (STRCMP(endp, "l") == 0)
12171 twin = win_horz_neighbor(tp, twin, FALSE, count);
12172 else
12173 invalid_arg = TRUE;
12174 }
12175 else
12176 invalid_arg = TRUE;
12177 }
12178
12179 if (invalid_arg)
12180 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012181 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012182 nr = 0;
12183 }
12184 }
12185
12186 if (nr > 0)
12187 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12188 wp != twin; wp = wp->w_next)
12189 {
12190 if (wp == NULL)
12191 {
12192 /* didn't find it in this tabpage */
12193 nr = 0;
12194 break;
12195 }
12196 ++nr;
12197 }
12198 return nr;
12199}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012200
12201/*
12202 * "tabpagewinnr()" function
12203 */
12204 static void
12205f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12206{
12207 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012208 tabpage_T *tp;
12209
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012210 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012211 if (tp == NULL)
12212 nr = 0;
12213 else
12214 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012215 rettv->vval.v_number = nr;
12216}
12217
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012218/*
12219 * "tagfiles()" function
12220 */
12221 static void
12222f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12223{
12224 char_u *fname;
12225 tagname_T tn;
12226 int first;
12227
12228 if (rettv_list_alloc(rettv) == FAIL)
12229 return;
12230 fname = alloc(MAXPATHL);
12231 if (fname == NULL)
12232 return;
12233
12234 for (first = TRUE; ; first = FALSE)
12235 if (get_tagfname(&tn, first, fname) == FAIL
12236 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12237 break;
12238 tagname_free(&tn);
12239 vim_free(fname);
12240}
12241
12242/*
12243 * "taglist()" function
12244 */
12245 static void
12246f_taglist(typval_T *argvars, typval_T *rettv)
12247{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012248 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012249 char_u *tag_pattern;
12250
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012251 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012252
12253 rettv->vval.v_number = FALSE;
12254 if (*tag_pattern == NUL)
12255 return;
12256
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012257 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012258 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012259 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012260 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012261}
12262
12263/*
12264 * "tempname()" function
12265 */
12266 static void
12267f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12268{
12269 static int x = 'A';
12270
12271 rettv->v_type = VAR_STRING;
12272 rettv->vval.v_string = vim_tempname(x, FALSE);
12273
12274 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12275 * names. Skip 'I' and 'O', they are used for shell redirection. */
12276 do
12277 {
12278 if (x == 'Z')
12279 x = '0';
12280 else if (x == '9')
12281 x = 'A';
12282 else
12283 {
12284#ifdef EBCDIC
12285 if (x == 'I')
12286 x = 'J';
12287 else if (x == 'R')
12288 x = 'S';
12289 else
12290#endif
12291 ++x;
12292 }
12293 } while (x == 'I' || x == 'O');
12294}
12295
12296#ifdef FEAT_FLOAT
12297/*
12298 * "tan()" function
12299 */
12300 static void
12301f_tan(typval_T *argvars, typval_T *rettv)
12302{
12303 float_T f = 0.0;
12304
12305 rettv->v_type = VAR_FLOAT;
12306 if (get_float_arg(argvars, &f) == OK)
12307 rettv->vval.v_float = tan(f);
12308 else
12309 rettv->vval.v_float = 0.0;
12310}
12311
12312/*
12313 * "tanh()" function
12314 */
12315 static void
12316f_tanh(typval_T *argvars, typval_T *rettv)
12317{
12318 float_T f = 0.0;
12319
12320 rettv->v_type = VAR_FLOAT;
12321 if (get_float_arg(argvars, &f) == OK)
12322 rettv->vval.v_float = tanh(f);
12323 else
12324 rettv->vval.v_float = 0.0;
12325}
12326#endif
12327
12328/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012329 * Get a callback from "arg". It can be a Funcref or a function name.
12330 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012331 * "cb_name" is not allocated.
12332 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012333 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012334 callback_T
12335get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012337 callback_T res;
12338
12339 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012340 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12341 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012342 res.cb_partial = arg->vval.v_partial;
12343 ++res.cb_partial->pt_refcount;
12344 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012345 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012346 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012347 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012348 res.cb_partial = NULL;
12349 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12350 {
12351 // Note that we don't make a copy of the string.
12352 res.cb_name = arg->vval.v_string;
12353 func_ref(res.cb_name);
12354 }
12355 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12356 {
12357 res.cb_name = (char_u *)"";
12358 }
12359 else
12360 {
12361 emsg(_("E921: Invalid callback argument"));
12362 res.cb_name = NULL;
12363 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012364 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012365 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012366}
12367
12368/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012369 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012370 */
12371 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012372put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012373{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012374 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012375 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012376 tv->v_type = VAR_PARTIAL;
12377 tv->vval.v_partial = cb->cb_partial;
12378 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012379 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012380 else
12381 {
12382 tv->v_type = VAR_FUNC;
12383 tv->vval.v_string = vim_strsave(cb->cb_name);
12384 func_ref(cb->cb_name);
12385 }
12386}
12387
12388/*
12389 * Make a copy of "src" into "dest", allocating the function name if needed,
12390 * without incrementing the refcount.
12391 */
12392 void
12393set_callback(callback_T *dest, callback_T *src)
12394{
12395 if (src->cb_partial == NULL)
12396 {
12397 // just a function name, make a copy
12398 dest->cb_name = vim_strsave(src->cb_name);
12399 dest->cb_free_name = TRUE;
12400 }
12401 else
12402 {
12403 // cb_name is a pointer into cb_partial
12404 dest->cb_name = src->cb_name;
12405 dest->cb_free_name = FALSE;
12406 }
12407 dest->cb_partial = src->cb_partial;
12408}
12409
12410/*
12411 * Unref/free "callback" returned by get_callback() or set_callback().
12412 */
12413 void
12414free_callback(callback_T *callback)
12415{
12416 if (callback->cb_partial != NULL)
12417 {
12418 partial_unref(callback->cb_partial);
12419 callback->cb_partial = NULL;
12420 }
12421 else if (callback->cb_name != NULL)
12422 func_unref(callback->cb_name);
12423 if (callback->cb_free_name)
12424 {
12425 vim_free(callback->cb_name);
12426 callback->cb_free_name = FALSE;
12427 }
12428 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012429}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012430
12431#ifdef FEAT_TIMERS
12432/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012433 * "timer_info([timer])" function
12434 */
12435 static void
12436f_timer_info(typval_T *argvars, typval_T *rettv)
12437{
12438 timer_T *timer = NULL;
12439
12440 if (rettv_list_alloc(rettv) != OK)
12441 return;
12442 if (argvars[0].v_type != VAR_UNKNOWN)
12443 {
12444 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012445 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012446 else
12447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012448 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012449 if (timer != NULL)
12450 add_timer_info(rettv, timer);
12451 }
12452 }
12453 else
12454 add_timer_info_all(rettv);
12455}
12456
12457/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012458 * "timer_pause(timer, paused)" function
12459 */
12460 static void
12461f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12462{
12463 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012464 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012465
12466 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012467 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012468 else
12469 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012470 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012471 if (timer != NULL)
12472 timer->tr_paused = paused;
12473 }
12474}
12475
12476/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012477 * "timer_start(time, callback [, options])" function
12478 */
12479 static void
12480f_timer_start(typval_T *argvars, typval_T *rettv)
12481{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012482 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012483 timer_T *timer;
12484 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012485 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012486 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012487
Bram Moolenaar75537a92016-09-05 22:45:28 +020012488 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012489 if (check_secure())
12490 return;
12491 if (argvars[2].v_type != VAR_UNKNOWN)
12492 {
12493 if (argvars[2].v_type != VAR_DICT
12494 || (dict = argvars[2].vval.v_dict) == NULL)
12495 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012496 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012497 return;
12498 }
12499 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012500 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012501 }
12502
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012503 callback = get_callback(&argvars[1]);
12504 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012505 return;
12506
12507 timer = create_timer(msec, repeat);
12508 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012509 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012510 else
12511 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012512 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012513 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012514 }
12515}
12516
12517/*
12518 * "timer_stop(timer)" function
12519 */
12520 static void
12521f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12522{
12523 timer_T *timer;
12524
12525 if (argvars[0].v_type != VAR_NUMBER)
12526 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012527 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012528 return;
12529 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012530 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531 if (timer != NULL)
12532 stop_timer(timer);
12533}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012534
12535/*
12536 * "timer_stopall()" function
12537 */
12538 static void
12539f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12540{
12541 stop_all_timers();
12542}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012543#endif
12544
12545/*
12546 * "tolower(string)" function
12547 */
12548 static void
12549f_tolower(typval_T *argvars, typval_T *rettv)
12550{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012551 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012552 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012553}
12554
12555/*
12556 * "toupper(string)" function
12557 */
12558 static void
12559f_toupper(typval_T *argvars, typval_T *rettv)
12560{
12561 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012562 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012563}
12564
12565/*
12566 * "tr(string, fromstr, tostr)" function
12567 */
12568 static void
12569f_tr(typval_T *argvars, typval_T *rettv)
12570{
12571 char_u *in_str;
12572 char_u *fromstr;
12573 char_u *tostr;
12574 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575 int inlen;
12576 int fromlen;
12577 int tolen;
12578 int idx;
12579 char_u *cpstr;
12580 int cplen;
12581 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012582 char_u buf[NUMBUFLEN];
12583 char_u buf2[NUMBUFLEN];
12584 garray_T ga;
12585
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012586 in_str = tv_get_string(&argvars[0]);
12587 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12588 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589
12590 /* Default return value: empty string. */
12591 rettv->v_type = VAR_STRING;
12592 rettv->vval.v_string = NULL;
12593 if (fromstr == NULL || tostr == NULL)
12594 return; /* type error; errmsg already given */
12595 ga_init2(&ga, (int)sizeof(char), 80);
12596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012597 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012598 /* not multi-byte: fromstr and tostr must be the same length */
12599 if (STRLEN(fromstr) != STRLEN(tostr))
12600 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012601error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012602 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012603 ga_clear(&ga);
12604 return;
12605 }
12606
12607 /* fromstr and tostr have to contain the same number of chars */
12608 while (*in_str != NUL)
12609 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012610 if (has_mbyte)
12611 {
12612 inlen = (*mb_ptr2len)(in_str);
12613 cpstr = in_str;
12614 cplen = inlen;
12615 idx = 0;
12616 for (p = fromstr; *p != NUL; p += fromlen)
12617 {
12618 fromlen = (*mb_ptr2len)(p);
12619 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12620 {
12621 for (p = tostr; *p != NUL; p += tolen)
12622 {
12623 tolen = (*mb_ptr2len)(p);
12624 if (idx-- == 0)
12625 {
12626 cplen = tolen;
12627 cpstr = p;
12628 break;
12629 }
12630 }
12631 if (*p == NUL) /* tostr is shorter than fromstr */
12632 goto error;
12633 break;
12634 }
12635 ++idx;
12636 }
12637
12638 if (first && cpstr == in_str)
12639 {
12640 /* Check that fromstr and tostr have the same number of
12641 * (multi-byte) characters. Done only once when a character
12642 * of in_str doesn't appear in fromstr. */
12643 first = FALSE;
12644 for (p = tostr; *p != NUL; p += tolen)
12645 {
12646 tolen = (*mb_ptr2len)(p);
12647 --idx;
12648 }
12649 if (idx != 0)
12650 goto error;
12651 }
12652
12653 (void)ga_grow(&ga, cplen);
12654 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12655 ga.ga_len += cplen;
12656
12657 in_str += inlen;
12658 }
12659 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012660 {
12661 /* When not using multi-byte chars we can do it faster. */
12662 p = vim_strchr(fromstr, *in_str);
12663 if (p != NULL)
12664 ga_append(&ga, tostr[p - fromstr]);
12665 else
12666 ga_append(&ga, *in_str);
12667 ++in_str;
12668 }
12669 }
12670
12671 /* add a terminating NUL */
12672 (void)ga_grow(&ga, 1);
12673 ga_append(&ga, NUL);
12674
12675 rettv->vval.v_string = ga.ga_data;
12676}
12677
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012678/*
12679 * "trim({expr})" function
12680 */
12681 static void
12682f_trim(typval_T *argvars, typval_T *rettv)
12683{
12684 char_u buf1[NUMBUFLEN];
12685 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012686 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012687 char_u *mask = NULL;
12688 char_u *tail;
12689 char_u *prev;
12690 char_u *p;
12691 int c1;
12692
12693 rettv->v_type = VAR_STRING;
12694 if (head == NULL)
12695 {
12696 rettv->vval.v_string = NULL;
12697 return;
12698 }
12699
12700 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012701 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012702
12703 while (*head != NUL)
12704 {
12705 c1 = PTR2CHAR(head);
12706 if (mask == NULL)
12707 {
12708 if (c1 > ' ' && c1 != 0xa0)
12709 break;
12710 }
12711 else
12712 {
12713 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12714 if (c1 == PTR2CHAR(p))
12715 break;
12716 if (*p == NUL)
12717 break;
12718 }
12719 MB_PTR_ADV(head);
12720 }
12721
12722 for (tail = head + STRLEN(head); tail > head; tail = prev)
12723 {
12724 prev = tail;
12725 MB_PTR_BACK(head, prev);
12726 c1 = PTR2CHAR(prev);
12727 if (mask == NULL)
12728 {
12729 if (c1 > ' ' && c1 != 0xa0)
12730 break;
12731 }
12732 else
12733 {
12734 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12735 if (c1 == PTR2CHAR(p))
12736 break;
12737 if (*p == NUL)
12738 break;
12739 }
12740 }
12741 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12742}
12743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744#ifdef FEAT_FLOAT
12745/*
12746 * "trunc({float})" function
12747 */
12748 static void
12749f_trunc(typval_T *argvars, typval_T *rettv)
12750{
12751 float_T f = 0.0;
12752
12753 rettv->v_type = VAR_FLOAT;
12754 if (get_float_arg(argvars, &f) == OK)
12755 /* trunc() is not in C90, use floor() or ceil() instead. */
12756 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12757 else
12758 rettv->vval.v_float = 0.0;
12759}
12760#endif
12761
12762/*
12763 * "type(expr)" function
12764 */
12765 static void
12766f_type(typval_T *argvars, typval_T *rettv)
12767{
12768 int n = -1;
12769
12770 switch (argvars[0].v_type)
12771 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012772 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12773 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012774 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012775 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12776 case VAR_LIST: n = VAR_TYPE_LIST; break;
12777 case VAR_DICT: n = VAR_TYPE_DICT; break;
12778 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012779 case VAR_SPECIAL:
12780 if (argvars[0].vval.v_number == VVAL_FALSE
12781 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012782 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012784 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012785 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012786 case VAR_JOB: n = VAR_TYPE_JOB; break;
12787 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012788 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012790 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 n = -1;
12792 break;
12793 }
12794 rettv->vval.v_number = n;
12795}
12796
12797/*
12798 * "undofile(name)" function
12799 */
12800 static void
12801f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12802{
12803 rettv->v_type = VAR_STRING;
12804#ifdef FEAT_PERSISTENT_UNDO
12805 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012806 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807
12808 if (*fname == NUL)
12809 {
12810 /* If there is no file name there will be no undo file. */
12811 rettv->vval.v_string = NULL;
12812 }
12813 else
12814 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012815 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012816
12817 if (ffname != NULL)
12818 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12819 vim_free(ffname);
12820 }
12821 }
12822#else
12823 rettv->vval.v_string = NULL;
12824#endif
12825}
12826
12827/*
12828 * "undotree()" function
12829 */
12830 static void
12831f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12832{
12833 if (rettv_dict_alloc(rettv) == OK)
12834 {
12835 dict_T *dict = rettv->vval.v_dict;
12836 list_T *list;
12837
Bram Moolenaare0be1672018-07-08 16:50:37 +020012838 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12839 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12840 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12841 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12842 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12843 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012844
12845 list = list_alloc();
12846 if (list != NULL)
12847 {
12848 u_eval_tree(curbuf->b_u_oldhead, list);
12849 dict_add_list(dict, "entries", list);
12850 }
12851 }
12852}
12853
12854/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012855 * "virtcol(string)" function
12856 */
12857 static void
12858f_virtcol(typval_T *argvars, typval_T *rettv)
12859{
12860 colnr_T vcol = 0;
12861 pos_T *fp;
12862 int fnum = curbuf->b_fnum;
12863
12864 fp = var2fpos(&argvars[0], FALSE, &fnum);
12865 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12866 && fnum == curbuf->b_fnum)
12867 {
12868 getvvcol(curwin, fp, NULL, NULL, &vcol);
12869 ++vcol;
12870 }
12871
12872 rettv->vval.v_number = vcol;
12873}
12874
12875/*
12876 * "visualmode()" function
12877 */
12878 static void
12879f_visualmode(typval_T *argvars, typval_T *rettv)
12880{
12881 char_u str[2];
12882
12883 rettv->v_type = VAR_STRING;
12884 str[0] = curbuf->b_visual_mode_eval;
12885 str[1] = NUL;
12886 rettv->vval.v_string = vim_strsave(str);
12887
12888 /* A non-zero number or non-empty string argument: reset mode. */
12889 if (non_zero_arg(&argvars[0]))
12890 curbuf->b_visual_mode_eval = NUL;
12891}
12892
12893/*
12894 * "wildmenumode()" function
12895 */
12896 static void
12897f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12898{
12899#ifdef FEAT_WILDMENU
12900 if (wild_menu_showing)
12901 rettv->vval.v_number = 1;
12902#endif
12903}
12904
12905/*
12906 * "winbufnr(nr)" function
12907 */
12908 static void
12909f_winbufnr(typval_T *argvars, typval_T *rettv)
12910{
12911 win_T *wp;
12912
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012913 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012914 if (wp == NULL)
12915 rettv->vval.v_number = -1;
12916 else
12917 rettv->vval.v_number = wp->w_buffer->b_fnum;
12918}
12919
12920/*
12921 * "wincol()" function
12922 */
12923 static void
12924f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12925{
12926 validate_cursor();
12927 rettv->vval.v_number = curwin->w_wcol + 1;
12928}
12929
12930/*
12931 * "winheight(nr)" function
12932 */
12933 static void
12934f_winheight(typval_T *argvars, typval_T *rettv)
12935{
12936 win_T *wp;
12937
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012938 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012939 if (wp == NULL)
12940 rettv->vval.v_number = -1;
12941 else
12942 rettv->vval.v_number = wp->w_height;
12943}
12944
12945/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012946 * "winlayout()" function
12947 */
12948 static void
12949f_winlayout(typval_T *argvars, typval_T *rettv)
12950{
12951 tabpage_T *tp;
12952
12953 if (rettv_list_alloc(rettv) != OK)
12954 return;
12955
12956 if (argvars[0].v_type == VAR_UNKNOWN)
12957 tp = curtab;
12958 else
12959 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012960 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012961 if (tp == NULL)
12962 return;
12963 }
12964
12965 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12966}
12967
12968/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012969 * "winline()" function
12970 */
12971 static void
12972f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12973{
12974 validate_cursor();
12975 rettv->vval.v_number = curwin->w_wrow + 1;
12976}
12977
12978/*
12979 * "winnr()" function
12980 */
12981 static void
12982f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12983{
12984 int nr = 1;
12985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012986 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012987 rettv->vval.v_number = nr;
12988}
12989
12990/*
12991 * "winrestcmd()" function
12992 */
12993 static void
12994f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12995{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012996 win_T *wp;
12997 int winnr = 1;
12998 garray_T ga;
12999 char_u buf[50];
13000
13001 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013002 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013003 {
13004 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13005 ga_concat(&ga, buf);
13006 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13007 ga_concat(&ga, buf);
13008 ++winnr;
13009 }
13010 ga_append(&ga, NUL);
13011
13012 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013013 rettv->v_type = VAR_STRING;
13014}
13015
13016/*
13017 * "winrestview()" function
13018 */
13019 static void
13020f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13021{
13022 dict_T *dict;
13023
13024 if (argvars[0].v_type != VAR_DICT
13025 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013026 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013027 else
13028 {
13029 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013030 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013032 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013033 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013034 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013035 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13036 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013037 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013038 curwin->w_set_curswant = FALSE;
13039 }
13040
13041 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013042 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013043#ifdef FEAT_DIFF
13044 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013045 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013046#endif
13047 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013048 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013049 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013050 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013051
13052 check_cursor();
13053 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013054 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055 changed_window_setting();
13056
13057 if (curwin->w_topline <= 0)
13058 curwin->w_topline = 1;
13059 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13060 curwin->w_topline = curbuf->b_ml.ml_line_count;
13061#ifdef FEAT_DIFF
13062 check_topfill(curwin, TRUE);
13063#endif
13064 }
13065}
13066
13067/*
13068 * "winsaveview()" function
13069 */
13070 static void
13071f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13072{
13073 dict_T *dict;
13074
13075 if (rettv_dict_alloc(rettv) == FAIL)
13076 return;
13077 dict = rettv->vval.v_dict;
13078
Bram Moolenaare0be1672018-07-08 16:50:37 +020013079 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13080 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013081 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013082 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013083 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013084
Bram Moolenaare0be1672018-07-08 16:50:37 +020013085 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013086#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013087 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013088#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013089 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13090 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013091}
13092
13093/*
13094 * "winwidth(nr)" function
13095 */
13096 static void
13097f_winwidth(typval_T *argvars, typval_T *rettv)
13098{
13099 win_T *wp;
13100
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013101 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013102 if (wp == NULL)
13103 rettv->vval.v_number = -1;
13104 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013105 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013106}
13107
13108/*
13109 * "wordcount()" function
13110 */
13111 static void
13112f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13113{
13114 if (rettv_dict_alloc(rettv) == FAIL)
13115 return;
13116 cursor_pos_info(rettv->vval.v_dict);
13117}
13118
13119/*
13120 * "writefile()" function
13121 */
13122 static void
13123f_writefile(typval_T *argvars, typval_T *rettv)
13124{
13125 int binary = FALSE;
13126 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013127#ifdef HAVE_FSYNC
13128 int do_fsync = p_fs;
13129#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013130 char_u *fname;
13131 FILE *fd;
13132 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013133 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013134 list_T *list = NULL;
13135 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013136
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013137 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013138 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013139 return;
13140
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013141 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013142 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013143 list = argvars[0].vval.v_list;
13144 if (list == NULL)
13145 return;
13146 for (li = list->lv_first; li != NULL; li = li->li_next)
13147 if (tv_get_string_chk(&li->li_tv) == NULL)
13148 return;
13149 }
13150 else if (argvars[0].v_type == VAR_BLOB)
13151 {
13152 blob = argvars[0].vval.v_blob;
13153 if (blob == NULL)
13154 return;
13155 }
13156 else
13157 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013158 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013159 return;
13160 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013161
13162 if (argvars[2].v_type != VAR_UNKNOWN)
13163 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013164 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013165
13166 if (arg2 == NULL)
13167 return;
13168 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013169 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013170 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013171 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013172#ifdef HAVE_FSYNC
13173 if (vim_strchr(arg2, 's') != NULL)
13174 do_fsync = TRUE;
13175 else if (vim_strchr(arg2, 'S') != NULL)
13176 do_fsync = FALSE;
13177#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013178 }
13179
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013180 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013181 if (fname == NULL)
13182 return;
13183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013184 /* Always open the file in binary mode, library functions have a mind of
13185 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13187 append ? APPENDBIN : WRITEBIN)) == NULL)
13188 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013189 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013190 ret = -1;
13191 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013192 else if (blob)
13193 {
13194 if (write_blob(fd, blob) == FAIL)
13195 ret = -1;
13196#ifdef HAVE_FSYNC
13197 else if (do_fsync)
13198 // Ignore the error, the user wouldn't know what to do about it.
13199 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013200 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013201#endif
13202 fclose(fd);
13203 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013204 else
13205 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013206 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013207 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013208#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013209 else if (do_fsync)
13210 /* Ignore the error, the user wouldn't know what to do about it.
13211 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013212 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013213#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013214 fclose(fd);
13215 }
13216
13217 rettv->vval.v_number = ret;
13218}
13219
13220/*
13221 * "xor(expr, expr)" function
13222 */
13223 static void
13224f_xor(typval_T *argvars, typval_T *rettv)
13225{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013226 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13227 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013228}
13229
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013230#endif /* FEAT_EVAL */