blob: 4561f08a341392914fa72b5b6d3c840a2b52e128 [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 Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#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 +020038#ifdef FEAT_FLOAT
39static void f_asin(typval_T *argvars, typval_T *rettv);
40static void f_atan(typval_T *argvars, typval_T *rettv);
41static void f_atan2(typval_T *argvars, typval_T *rettv);
42#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020044static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010045static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010046# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010047static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010048# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010049#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_browse(typval_T *argvars, typval_T *rettv);
51static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020052static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020053static void f_bufexists(typval_T *argvars, typval_T *rettv);
54static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020055static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_bufloaded(typval_T *argvars, typval_T *rettv);
57static void f_bufname(typval_T *argvars, typval_T *rettv);
58static void f_bufnr(typval_T *argvars, typval_T *rettv);
59static void f_bufwinid(typval_T *argvars, typval_T *rettv);
60static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
61static void f_byte2line(typval_T *argvars, typval_T *rettv);
62static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
63static void f_byteidx(typval_T *argvars, typval_T *rettv);
64static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
65static void f_call(typval_T *argvars, typval_T *rettv);
66#ifdef FEAT_FLOAT
67static void f_ceil(typval_T *argvars, typval_T *rettv);
68#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_changenr(typval_T *argvars, typval_T *rettv);
70static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020071static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020074static void f_confirm(typval_T *argvars, typval_T *rettv);
75static void f_copy(typval_T *argvars, typval_T *rettv);
76#ifdef FEAT_FLOAT
77static void f_cos(typval_T *argvars, typval_T *rettv);
78static void f_cosh(typval_T *argvars, typval_T *rettv);
79#endif
80static void f_count(typval_T *argvars, typval_T *rettv);
81static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
82static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010083#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020084static void f_debugbreak(typval_T *argvars, typval_T *rettv);
85#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_deepcopy(typval_T *argvars, typval_T *rettv);
87static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020088static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_did_filetype(typval_T *argvars, typval_T *rettv);
90static void f_diff_filler(typval_T *argvars, typval_T *rettv);
91static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
92static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020093static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_escape(typval_T *argvars, typval_T *rettv);
95static void f_eval(typval_T *argvars, typval_T *rettv);
96static void f_eventhandler(typval_T *argvars, typval_T *rettv);
97static void f_executable(typval_T *argvars, typval_T *rettv);
98static void f_execute(typval_T *argvars, typval_T *rettv);
99static void f_exepath(typval_T *argvars, typval_T *rettv);
100static void f_exists(typval_T *argvars, typval_T *rettv);
101#ifdef FEAT_FLOAT
102static void f_exp(typval_T *argvars, typval_T *rettv);
103#endif
104static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200105static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_extend(typval_T *argvars, typval_T *rettv);
107static void f_feedkeys(typval_T *argvars, typval_T *rettv);
108static void f_filereadable(typval_T *argvars, typval_T *rettv);
109static void f_filewritable(typval_T *argvars, typval_T *rettv);
110static void f_filter(typval_T *argvars, typval_T *rettv);
111static void f_finddir(typval_T *argvars, typval_T *rettv);
112static void f_findfile(typval_T *argvars, typval_T *rettv);
113#ifdef FEAT_FLOAT
114static void f_float2nr(typval_T *argvars, typval_T *rettv);
115static void f_floor(typval_T *argvars, typval_T *rettv);
116static void f_fmod(typval_T *argvars, typval_T *rettv);
117#endif
118static void f_fnameescape(typval_T *argvars, typval_T *rettv);
119static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
120static void f_foldclosed(typval_T *argvars, typval_T *rettv);
121static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
122static void f_foldlevel(typval_T *argvars, typval_T *rettv);
123static void f_foldtext(typval_T *argvars, typval_T *rettv);
124static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
125static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200126static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_function(typval_T *argvars, typval_T *rettv);
128static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
129static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200130static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131static void f_getbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100132static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200133static void f_getchar(typval_T *argvars, typval_T *rettv);
134static void f_getcharmod(typval_T *argvars, typval_T *rettv);
135static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
136static void f_getcmdline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
138static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
139static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
140static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200141static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142static void f_getfontname(typval_T *argvars, typval_T *rettv);
143static void f_getfperm(typval_T *argvars, typval_T *rettv);
144static void f_getfsize(typval_T *argvars, typval_T *rettv);
145static void f_getftime(typval_T *argvars, typval_T *rettv);
146static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100147static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200148static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200149static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200150static void f_getpid(typval_T *argvars, typval_T *rettv);
151static void f_getcurpos(typval_T *argvars, typval_T *rettv);
152static void f_getpos(typval_T *argvars, typval_T *rettv);
153static void f_getqflist(typval_T *argvars, typval_T *rettv);
154static void f_getreg(typval_T *argvars, typval_T *rettv);
155static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200156static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100157static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200158static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100159static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200160static void f_getwinposx(typval_T *argvars, typval_T *rettv);
161static void f_getwinposy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_glob(typval_T *argvars, typval_T *rettv);
163static void f_globpath(typval_T *argvars, typval_T *rettv);
164static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
165static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200166static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
167static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_hlID(typval_T *argvars, typval_T *rettv);
169static void f_hlexists(typval_T *argvars, typval_T *rettv);
170static void f_hostname(typval_T *argvars, typval_T *rettv);
171static void f_iconv(typval_T *argvars, typval_T *rettv);
172static void f_indent(typval_T *argvars, typval_T *rettv);
173static void f_index(typval_T *argvars, typval_T *rettv);
174static void f_input(typval_T *argvars, typval_T *rettv);
175static void f_inputdialog(typval_T *argvars, typval_T *rettv);
176static void f_inputlist(typval_T *argvars, typval_T *rettv);
177static void f_inputrestore(typval_T *argvars, typval_T *rettv);
178static void f_inputsave(typval_T *argvars, typval_T *rettv);
179static void f_inputsecret(typval_T *argvars, typval_T *rettv);
180static void f_insert(typval_T *argvars, typval_T *rettv);
181static void f_invert(typval_T *argvars, typval_T *rettv);
182static void f_isdirectory(typval_T *argvars, typval_T *rettv);
183static void f_islocked(typval_T *argvars, typval_T *rettv);
184#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200185static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200186static void f_isnan(typval_T *argvars, typval_T *rettv);
187#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
189static void f_len(typval_T *argvars, typval_T *rettv);
190static void f_libcall(typval_T *argvars, typval_T *rettv);
191static void f_libcallnr(typval_T *argvars, typval_T *rettv);
192static void f_line(typval_T *argvars, typval_T *rettv);
193static void f_line2byte(typval_T *argvars, typval_T *rettv);
194static void f_lispindent(typval_T *argvars, typval_T *rettv);
195static void f_localtime(typval_T *argvars, typval_T *rettv);
196#ifdef FEAT_FLOAT
197static void f_log(typval_T *argvars, typval_T *rettv);
198static void f_log10(typval_T *argvars, typval_T *rettv);
199#endif
200#ifdef FEAT_LUA
201static void f_luaeval(typval_T *argvars, typval_T *rettv);
202#endif
203static void f_map(typval_T *argvars, typval_T *rettv);
204static void f_maparg(typval_T *argvars, typval_T *rettv);
205static void f_mapcheck(typval_T *argvars, typval_T *rettv);
206static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_matchend(typval_T *argvars, typval_T *rettv);
208static void f_matchlist(typval_T *argvars, typval_T *rettv);
209static void f_matchstr(typval_T *argvars, typval_T *rettv);
210static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
211static void f_max(typval_T *argvars, typval_T *rettv);
212static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214static void f_mode(typval_T *argvars, typval_T *rettv);
215#ifdef FEAT_MZSCHEME
216static void f_mzeval(typval_T *argvars, typval_T *rettv);
217#endif
218static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
219static void f_nr2char(typval_T *argvars, typval_T *rettv);
220static void f_or(typval_T *argvars, typval_T *rettv);
221static void f_pathshorten(typval_T *argvars, typval_T *rettv);
222#ifdef FEAT_PERL
223static void f_perleval(typval_T *argvars, typval_T *rettv);
224#endif
225#ifdef FEAT_FLOAT
226static void f_pow(typval_T *argvars, typval_T *rettv);
227#endif
228static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
229static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200230static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200231static void f_pumvisible(typval_T *argvars, typval_T *rettv);
232#ifdef FEAT_PYTHON3
233static void f_py3eval(typval_T *argvars, typval_T *rettv);
234#endif
235#ifdef FEAT_PYTHON
236static void f_pyeval(typval_T *argvars, typval_T *rettv);
237#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100238#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
239static void f_pyxeval(typval_T *argvars, typval_T *rettv);
240#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200242static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200243static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200244static void f_reg_executing(typval_T *argvars, typval_T *rettv);
245static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_reltime(typval_T *argvars, typval_T *rettv);
247#ifdef FEAT_FLOAT
248static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
249#endif
250static void f_reltimestr(typval_T *argvars, typval_T *rettv);
251static void f_remote_expr(typval_T *argvars, typval_T *rettv);
252static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
253static void f_remote_peek(typval_T *argvars, typval_T *rettv);
254static void f_remote_read(typval_T *argvars, typval_T *rettv);
255static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100256static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200257static void f_remove(typval_T *argvars, typval_T *rettv);
258static void f_rename(typval_T *argvars, typval_T *rettv);
259static void f_repeat(typval_T *argvars, typval_T *rettv);
260static void f_resolve(typval_T *argvars, typval_T *rettv);
261static void f_reverse(typval_T *argvars, typval_T *rettv);
262#ifdef FEAT_FLOAT
263static void f_round(typval_T *argvars, typval_T *rettv);
264#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100265#ifdef FEAT_RUBY
266static void f_rubyeval(typval_T *argvars, typval_T *rettv);
267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_screenattr(typval_T *argvars, typval_T *rettv);
269static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100270static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271static void f_screencol(typval_T *argvars, typval_T *rettv);
272static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100273static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200274static void f_search(typval_T *argvars, typval_T *rettv);
275static void f_searchdecl(typval_T *argvars, typval_T *rettv);
276static void f_searchpair(typval_T *argvars, typval_T *rettv);
277static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
278static void f_searchpos(typval_T *argvars, typval_T *rettv);
279static void f_server2client(typval_T *argvars, typval_T *rettv);
280static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200281static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200282static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
283static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200284static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200285static void f_setfperm(typval_T *argvars, typval_T *rettv);
286static void f_setline(typval_T *argvars, typval_T *rettv);
287static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288static void f_setpos(typval_T *argvars, typval_T *rettv);
289static void f_setqflist(typval_T *argvars, typval_T *rettv);
290static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100291static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200292#ifdef FEAT_CRYPT
293static void f_sha256(typval_T *argvars, typval_T *rettv);
294#endif /* FEAT_CRYPT */
295static void f_shellescape(typval_T *argvars, typval_T *rettv);
296static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
297static void f_simplify(typval_T *argvars, typval_T *rettv);
298#ifdef FEAT_FLOAT
299static void f_sin(typval_T *argvars, typval_T *rettv);
300static void f_sinh(typval_T *argvars, typval_T *rettv);
301#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_soundfold(typval_T *argvars, typval_T *rettv);
303static void f_spellbadword(typval_T *argvars, typval_T *rettv);
304static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
305static void f_split(typval_T *argvars, typval_T *rettv);
306#ifdef FEAT_FLOAT
307static void f_sqrt(typval_T *argvars, typval_T *rettv);
308static void f_str2float(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200310static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311static void f_str2nr(typval_T *argvars, typval_T *rettv);
312static void f_strchars(typval_T *argvars, typval_T *rettv);
313#ifdef HAVE_STRFTIME
314static void f_strftime(typval_T *argvars, typval_T *rettv);
315#endif
316static void f_strgetchar(typval_T *argvars, typval_T *rettv);
317static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318static void f_strlen(typval_T *argvars, typval_T *rettv);
319static void f_strcharpart(typval_T *argvars, typval_T *rettv);
320static void f_strpart(typval_T *argvars, typval_T *rettv);
321static void f_strridx(typval_T *argvars, typval_T *rettv);
322static void f_strtrans(typval_T *argvars, typval_T *rettv);
323static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
324static void f_strwidth(typval_T *argvars, typval_T *rettv);
325static void f_submatch(typval_T *argvars, typval_T *rettv);
326static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200327static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200328static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200329static void f_synID(typval_T *argvars, typval_T *rettv);
330static void f_synIDattr(typval_T *argvars, typval_T *rettv);
331static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
332static void f_synstack(typval_T *argvars, typval_T *rettv);
333static void f_synconcealed(typval_T *argvars, typval_T *rettv);
334static void f_system(typval_T *argvars, typval_T *rettv);
335static void f_systemlist(typval_T *argvars, typval_T *rettv);
336static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
337static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
338static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
339static void f_taglist(typval_T *argvars, typval_T *rettv);
340static void f_tagfiles(typval_T *argvars, typval_T *rettv);
341static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342#ifdef FEAT_FLOAT
343static void f_tan(typval_T *argvars, typval_T *rettv);
344static void f_tanh(typval_T *argvars, typval_T *rettv);
345#endif
346#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200347static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200348static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200349static void f_timer_start(typval_T *argvars, typval_T *rettv);
350static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200351static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352#endif
353static void f_tolower(typval_T *argvars, typval_T *rettv);
354static void f_toupper(typval_T *argvars, typval_T *rettv);
355static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100356static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357#ifdef FEAT_FLOAT
358static void f_trunc(typval_T *argvars, typval_T *rettv);
359#endif
360static void f_type(typval_T *argvars, typval_T *rettv);
361static void f_undofile(typval_T *argvars, typval_T *rettv);
362static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363static void f_virtcol(typval_T *argvars, typval_T *rettv);
364static void f_visualmode(typval_T *argvars, typval_T *rettv);
365static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200366static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200367static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
368static void f_win_getid(typval_T *argvars, typval_T *rettv);
369static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
370static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
371static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100372static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373static void f_winbufnr(typval_T *argvars, typval_T *rettv);
374static void f_wincol(typval_T *argvars, typval_T *rettv);
375static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200376static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200377static void f_winline(typval_T *argvars, typval_T *rettv);
378static void f_winnr(typval_T *argvars, typval_T *rettv);
379static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
380static void f_winrestview(typval_T *argvars, typval_T *rettv);
381static void f_winsaveview(typval_T *argvars, typval_T *rettv);
382static void f_winwidth(typval_T *argvars, typval_T *rettv);
383static void f_writefile(typval_T *argvars, typval_T *rettv);
384static void f_wordcount(typval_T *argvars, typval_T *rettv);
385static void f_xor(typval_T *argvars, typval_T *rettv);
386
387/*
388 * Array with names and number of arguments of all internal functions
389 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
390 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200391typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200392{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200393 char *f_name; // function name
394 char f_min_argc; // minimal number of arguments
395 char f_max_argc; // maximal number of arguments
396 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200398 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200399} funcentry_T;
400
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200401// values for f_argtype; zero means it cannot be used as a method
402#define FEARG_1 1 // base is the first argument
403#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200404#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200405#define FEARG_LAST 9 // base is the last argument
406
Bram Moolenaarac92e252019-08-03 21:58:38 +0200407static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408{
409#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200410 {"abs", 1, 1, FEARG_1, f_abs},
411 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200412#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200414 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200415 {"append", 2, 2, FEARG_LAST, f_append},
416 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
417 {"argc", 0, 1, 0, f_argc},
418 {"argidx", 0, 0, 0, f_argidx},
419 {"arglistid", 0, 2, 0, f_arglistid},
420 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200422 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200423#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200424 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200425 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200426 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200427 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200428 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
429 {"assert_false", 1, 2, FEARG_1, f_assert_false},
430 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
431 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200432 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200433 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200434 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200435 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200437 {"atan", 1, 1, FEARG_1, f_atan},
438 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100440#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200442 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100443# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200444 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100445# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100446#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"browse", 4, 4, 0, f_browse},
448 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200449 {"bufadd", 1, 1, FEARG_1, f_bufadd},
450 {"bufexists", 1, 1, FEARG_1, f_bufexists},
451 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200452 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
453 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200454 {"buflisted", 1, 1, FEARG_1, f_buflisted},
455 {"bufload", 1, 1, FEARG_1, f_bufload},
456 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200457 {"bufname", 0, 1, FEARG_1, f_bufname},
458 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200459 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
460 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200461 {"byte2line", 1, 1, FEARG_1, f_byte2line},
462 {"byteidx", 2, 2, FEARG_1, f_byteidx},
463 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
464 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200465#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200466 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467#endif
468#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200469 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
470 {"ch_close", 1, 1, FEARG_1, f_ch_close},
471 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
472 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
473 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
474 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
475 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
476 {"ch_info", 1, 1, FEARG_1, f_ch_info},
477 {"ch_log", 1, 2, FEARG_1, f_ch_log},
478 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
479 {"ch_open", 1, 2, FEARG_1, f_ch_open},
480 {"ch_read", 1, 2, FEARG_1, f_ch_read},
481 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
482 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
483 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
484 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
485 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
486 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200488 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200489 {"char2nr", 1, 2, FEARG_1, f_char2nr},
490 {"chdir", 1, 1, FEARG_1, f_chdir},
491 {"cindent", 1, 1, FEARG_1, f_cindent},
492 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
493 {"col", 1, 1, FEARG_1, f_col},
494 {"complete", 2, 2, FEARG_2, f_complete},
495 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200496 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200497 {"complete_info", 0, 1, FEARG_1, f_complete_info},
498 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200499 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200501 {"cos", 1, 1, FEARG_1, f_cos},
502 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200503#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"count", 2, 4, FEARG_1, f_count},
505 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200506 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100507#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200508 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200509#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200510 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
511 {"delete", 1, 2, FEARG_1, f_delete},
512 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200513 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200514 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
515 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200516 {"empty", 1, 1, FEARG_1, f_empty},
517 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200518 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200519 {"eval", 1, 1, FEARG_1, f_eval},
520 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200521 {"executable", 1, 1, FEARG_1, f_executable},
522 {"execute", 1, 2, FEARG_1, f_execute},
523 {"exepath", 1, 1, FEARG_1, f_exepath},
524 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200526 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200528 {"expand", 1, 3, FEARG_1, f_expand},
529 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200530 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200531 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
532 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
533 {"filereadable", 1, 1, FEARG_1, f_filereadable},
534 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200535 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200536 {"finddir", 1, 3, FEARG_1, f_finddir},
537 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200538#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200539 {"float2nr", 1, 1, FEARG_1, f_float2nr},
540 {"floor", 1, 1, FEARG_1, f_floor},
541 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200543 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
544 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
545 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
546 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
547 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200548 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200549 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200550 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200551 {"funcref", 1, 3, FEARG_1, f_funcref},
552 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200553 {"garbagecollect", 0, 1, 0, f_garbagecollect},
554 {"get", 2, 3, FEARG_1, f_get},
555 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200556 {"getbufline", 2, 3, FEARG_1, f_getbufline},
557 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
558 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200559 {"getchar", 0, 1, 0, f_getchar},
560 {"getcharmod", 0, 0, 0, f_getcharmod},
561 {"getcharsearch", 0, 0, 0, f_getcharsearch},
562 {"getcmdline", 0, 0, 0, f_getcmdline},
563 {"getcmdpos", 0, 0, 0, f_getcmdpos},
564 {"getcmdtype", 0, 0, 0, f_getcmdtype},
565 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200566 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200567 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200568 {"getcwd", 0, 2, FEARG_1, f_getcwd},
569 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200570 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200571 {"getfperm", 1, 1, FEARG_1, f_getfperm},
572 {"getfsize", 1, 1, FEARG_1, f_getfsize},
573 {"getftime", 1, 1, FEARG_1, f_getftime},
574 {"getftype", 1, 1, FEARG_1, f_getftype},
575 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
576 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200577 {"getloclist", 1, 2, 0, f_getloclist},
578 {"getmatches", 0, 1, 0, f_getmatches},
579 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200580 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200581 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200582 {"getreg", 0, 3, FEARG_1, f_getreg},
583 {"getregtype", 0, 1, FEARG_1, f_getregtype},
584 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
585 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
586 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200587 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
588 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
589 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200590 {"getwinposx", 0, 0, 0, f_getwinposx},
591 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200592 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
593 {"glob", 1, 4, FEARG_1, f_glob},
594 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
595 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200596 {"has", 1, 1, 0, f_has},
597 {"has_key", 2, 2, FEARG_1, f_has_key},
598 {"haslocaldir", 0, 2, 0, f_haslocaldir},
599 {"hasmapto", 1, 3, 0, f_hasmapto},
600 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
601 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
602 {"histadd", 2, 2, 0, f_histadd},
603 {"histdel", 1, 2, 0, f_histdel},
604 {"histget", 1, 2, 0, f_histget},
605 {"histnr", 1, 1, 0, f_histnr},
606 {"hlID", 1, 1, 0, f_hlID},
607 {"hlexists", 1, 1, 0, f_hlexists},
608 {"hostname", 0, 0, 0, f_hostname},
609 {"iconv", 3, 3, 0, f_iconv},
610 {"indent", 1, 1, 0, f_indent},
611 {"index", 2, 4, FEARG_1, f_index},
612 {"input", 1, 3, 0, f_input},
613 {"inputdialog", 1, 3, 0, f_inputdialog},
614 {"inputlist", 1, 1, 0, f_inputlist},
615 {"inputrestore", 0, 0, 0, f_inputrestore},
616 {"inputsave", 0, 0, 0, f_inputsave},
617 {"inputsecret", 1, 2, 0, f_inputsecret},
618 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200619 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200620 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200621#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200622 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200623#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200624 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200626 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200628 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200630 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
631 {"job_info", 0, 1, FEARG_1, f_job_info},
632 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
633 {"job_start", 1, 2, FEARG_1, f_job_start},
634 {"job_status", 1, 1, FEARG_1, f_job_status},
635 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200637 {"join", 1, 2, FEARG_1, f_join},
638 {"js_decode", 1, 1, 0, f_js_decode},
639 {"js_encode", 1, 1, 0, f_js_encode},
640 {"json_decode", 1, 1, 0, f_json_decode},
641 {"json_encode", 1, 1, 0, f_json_encode},
642 {"keys", 1, 1, FEARG_1, f_keys},
643 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
644 {"len", 1, 1, FEARG_1, f_len},
645 {"libcall", 3, 3, 0, f_libcall},
646 {"libcallnr", 3, 3, 0, f_libcallnr},
647 {"line", 1, 1, 0, f_line},
648 {"line2byte", 1, 1, 0, f_line2byte},
649 {"lispindent", 1, 1, 0, f_lispindent},
650 {"list2str", 1, 2, 0, f_list2str},
651 {"listener_add", 1, 2, 0, f_listener_add},
652 {"listener_flush", 0, 1, 0, f_listener_flush},
653 {"listener_remove", 1, 1, 0, f_listener_remove},
654 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200656 {"log", 1, 1, FEARG_1, f_log},
657 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#endif
659#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200660 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200662 {"map", 2, 2, FEARG_1, f_map},
663 {"maparg", 1, 4, 0, f_maparg},
664 {"mapcheck", 1, 3, 0, f_mapcheck},
665 {"match", 2, 4, 0, f_match},
666 {"matchadd", 2, 5, 0, f_matchadd},
667 {"matchaddpos", 2, 5, 0, f_matchaddpos},
668 {"matcharg", 1, 1, 0, f_matcharg},
669 {"matchdelete", 1, 2, 0, f_matchdelete},
670 {"matchend", 2, 4, 0, f_matchend},
671 {"matchlist", 2, 4, 0, f_matchlist},
672 {"matchstr", 2, 4, 0, f_matchstr},
673 {"matchstrpos", 2, 4, 0, f_matchstrpos},
674 {"max", 1, 1, FEARG_1, f_max},
675 {"min", 1, 1, FEARG_1, f_min},
676 {"mkdir", 1, 3, 0, f_mkdir},
677 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200678#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200679 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200681 {"nextnonblank", 1, 1, 0, f_nextnonblank},
682 {"nr2char", 1, 2, 0, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200683 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200684 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200686 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200688#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
690 {"popup_beval", 2, 2, 0, f_popup_beval},
691 {"popup_clear", 0, 0, 0, f_popup_clear},
692 {"popup_close", 1, 2, 0, f_popup_close},
693 {"popup_create", 2, 2, 0, f_popup_create},
694 {"popup_dialog", 2, 2, 0, f_popup_dialog},
695 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
696 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200697 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
698 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200699 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
700 {"popup_getpos", 1, 1, 0, f_popup_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200701 {"popup_hide", 1, 1, 0, f_popup_hide},
702 {"popup_locate", 2, 2, 0, f_popup_locate},
703 {"popup_menu", 2, 2, 0, f_popup_menu},
704 {"popup_move", 2, 2, 0, f_popup_move},
705 {"popup_notification", 2, 2, 0, f_popup_notification},
706 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
707 {"popup_settext", 2, 2, 0, f_popup_settext},
708 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200709#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200711 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200712#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200713 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200714 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200715#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200716 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
717 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
718 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200719#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100720#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200721 {"prop_add", 3, 3, 0, f_prop_add},
722 {"prop_clear", 1, 3, 0, f_prop_clear},
723 {"prop_list", 1, 2, 0, f_prop_list},
724 {"prop_remove", 1, 3, 0, f_prop_remove},
725 {"prop_type_add", 2, 2, 0, f_prop_type_add},
726 {"prop_type_change", 2, 2, 0, f_prop_type_change},
727 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
728 {"prop_type_get", 1, 2, 0, f_prop_type_get},
729 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100730#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200731 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200732 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200734 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#endif
736#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200737 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200738#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100739#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100741#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200742 {"range", 1, 3, 0, f_range},
743 {"readdir", 1, 2, 0, f_readdir},
744 {"readfile", 1, 3, 0, f_readfile},
745 {"reg_executing", 0, 0, 0, f_reg_executing},
746 {"reg_recording", 0, 0, 0, f_reg_recording},
747 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200748#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200749 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200750#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200751 {"reltimestr", 1, 1, 0, f_reltimestr},
752 {"remote_expr", 2, 4, 0, f_remote_expr},
753 {"remote_foreground", 1, 1, 0, f_remote_foreground},
754 {"remote_peek", 1, 2, 0, f_remote_peek},
755 {"remote_read", 1, 2, 0, f_remote_read},
756 {"remote_send", 2, 3, 0, f_remote_send},
757 {"remote_startserver", 1, 1, 0, f_remote_startserver},
758 {"remove", 2, 3, FEARG_1, f_remove},
759 {"rename", 2, 2, 0, f_rename},
760 {"repeat", 2, 2, FEARG_1, f_repeat},
761 {"resolve", 1, 1, 0, f_resolve},
762 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200764 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100766#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200767 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100768#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200769 {"screenattr", 2, 2, 0, f_screenattr},
770 {"screenchar", 2, 2, 0, f_screenchar},
771 {"screenchars", 2, 2, 0, f_screenchars},
772 {"screencol", 0, 0, 0, f_screencol},
773 {"screenpos", 3, 3, 0, f_screenpos},
774 {"screenrow", 0, 0, 0, f_screenrow},
775 {"screenstring", 2, 2, 0, f_screenstring},
776 {"search", 1, 4, 0, f_search},
777 {"searchdecl", 1, 3, 0, f_searchdecl},
778 {"searchpair", 3, 7, 0, f_searchpair},
779 {"searchpairpos", 3, 7, 0, f_searchpairpos},
780 {"searchpos", 1, 4, 0, f_searchpos},
781 {"server2client", 2, 2, 0, f_server2client},
782 {"serverlist", 0, 0, 0, f_serverlist},
783 {"setbufline", 3, 3, 0, f_setbufline},
784 {"setbufvar", 3, 3, 0, f_setbufvar},
785 {"setcharsearch", 1, 1, 0, f_setcharsearch},
786 {"setcmdpos", 1, 1, 0, f_setcmdpos},
787 {"setenv", 2, 2, 0, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200788 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200789 {"setline", 2, 2, 0, f_setline},
790 {"setloclist", 2, 4, 0, f_setloclist},
791 {"setmatches", 1, 2, 0, f_setmatches},
792 {"setpos", 2, 2, 0, f_setpos},
793 {"setqflist", 1, 3, 0, f_setqflist},
794 {"setreg", 2, 3, 0, f_setreg},
795 {"settabvar", 3, 3, 0, f_settabvar},
796 {"settabwinvar", 4, 4, 0, f_settabwinvar},
797 {"settagstack", 2, 3, 0, f_settagstack},
798 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200799#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200800 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200801#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200802 {"shellescape", 1, 2, 0, f_shellescape},
803 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100804#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"sign_define", 1, 2, 0, f_sign_define},
806 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
807 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
808 {"sign_jump", 3, 3, 0, f_sign_jump},
809 {"sign_place", 4, 5, 0, f_sign_place},
810 {"sign_placelist", 1, 1, 0, f_sign_placelist},
811 {"sign_undefine", 0, 1, 0, f_sign_undefine},
812 {"sign_unplace", 1, 2, 0, f_sign_unplace},
813 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100814#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200815 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200816#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200817 {"sin", 1, 1, FEARG_1, f_sin},
818 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200820 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200821#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200822 {"sound_clear", 0, 0, 0, f_sound_clear},
823 {"sound_playevent", 1, 2, 0, f_sound_playevent},
824 {"sound_playfile", 1, 2, 0, f_sound_playfile},
825 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200826#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200827 {"soundfold", 1, 1, 0, f_soundfold},
828 {"spellbadword", 0, 1, 0, f_spellbadword},
829 {"spellsuggest", 1, 3, 0, f_spellsuggest},
830 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200832 {"sqrt", 1, 1, FEARG_1, f_sqrt},
833 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200834#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200835 {"str2list", 1, 2, FEARG_1, f_str2list},
836 {"str2nr", 1, 2, 0, f_str2nr},
837 {"strcharpart", 2, 3, 0, f_strcharpart},
838 {"strchars", 1, 2, 0, f_strchars},
839 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200840#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200841 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200843 {"strgetchar", 2, 2, 0, f_strgetchar},
844 {"stridx", 2, 3, 0, f_stridx},
845 {"string", 1, 1, FEARG_1, f_string},
846 {"strlen", 1, 1, FEARG_1, f_strlen},
847 {"strpart", 2, 3, 0, f_strpart},
848 {"strridx", 2, 3, 0, f_strridx},
849 {"strtrans", 1, 1, FEARG_1, f_strtrans},
850 {"strwidth", 1, 1, FEARG_1, f_strwidth},
851 {"submatch", 1, 2, 0, f_submatch},
852 {"substitute", 4, 4, FEARG_1, f_substitute},
853 {"swapinfo", 1, 1, 0, f_swapinfo},
854 {"swapname", 1, 1, 0, f_swapname},
855 {"synID", 3, 3, 0, f_synID},
856 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
857 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
858 {"synconcealed", 2, 2, 0, f_synconcealed},
859 {"synstack", 2, 2, 0, f_synstack},
860 {"system", 1, 2, FEARG_1, f_system},
861 {"systemlist", 1, 2, FEARG_1, f_systemlist},
862 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
863 {"tabpagenr", 0, 1, 0, f_tabpagenr},
864 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
865 {"tagfiles", 0, 0, 0, f_tagfiles},
866 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200867#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200868 {"tan", 1, 1, FEARG_1, f_tan},
869 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200871 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200872#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200873 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
874 {"term_dumpload", 1, 2, 0, f_term_dumpload},
875 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
876 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200877# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200878 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200879# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200880 {"term_getattr", 2, 2, 0, f_term_getattr},
881 {"term_getcursor", 1, 1, 0, f_term_getcursor},
882 {"term_getjob", 1, 1, 0, f_term_getjob},
883 {"term_getline", 2, 2, 0, f_term_getline},
884 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
885 {"term_getsize", 1, 1, 0, f_term_getsize},
886 {"term_getstatus", 1, 1, 0, f_term_getstatus},
887 {"term_gettitle", 1, 1, 0, f_term_gettitle},
888 {"term_gettty", 1, 2, 0, f_term_gettty},
889 {"term_list", 0, 0, 0, f_term_list},
890 {"term_scrape", 2, 2, 0, f_term_scrape},
891 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200892# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200893 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200894# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200895 {"term_setkill", 2, 2, 0, f_term_setkill},
896 {"term_setrestore", 2, 2, 0, f_term_setrestore},
897 {"term_setsize", 3, 3, 0, f_term_setsize},
898 {"term_start", 1, 2, 0, f_term_start},
899 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200900#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200901 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
902 {"test_autochdir", 0, 0, 0, f_test_autochdir},
903 {"test_feedinput", 1, 1, 0, f_test_feedinput},
904 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
905 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
906 {"test_getvalue", 1, 1, 0, f_test_getvalue},
907 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
908 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200909#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200910 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200912 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200913#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200914 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200916 {"test_null_list", 0, 0, 0, f_test_null_list},
917 {"test_null_partial", 0, 0, 0, f_test_null_partial},
918 {"test_null_string", 0, 0, 0, f_test_null_string},
919 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
920 {"test_override", 2, 2, 0, f_test_override},
921 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200922#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200923 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200924#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200925#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200926 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200927#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200928 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 {"timer_info", 0, 1, 0, f_timer_info},
931 {"timer_pause", 2, 2, 0, f_timer_pause},
932 {"timer_start", 2, 3, 0, f_timer_start},
933 {"timer_stop", 1, 1, 0, f_timer_stop},
934 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200936 {"tolower", 1, 1, 0, f_tolower},
937 {"toupper", 1, 1, 0, f_toupper},
938 {"tr", 3, 3, 0, f_tr},
939 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200940#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200941 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200942#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200943 {"type", 1, 1, FEARG_1, f_type},
944 {"undofile", 1, 1, 0, f_undofile},
945 {"undotree", 0, 0, 0, f_undotree},
946 {"uniq", 1, 3, FEARG_1, f_uniq},
947 {"values", 1, 1, FEARG_1, f_values},
948 {"virtcol", 1, 1, 0, f_virtcol},
949 {"visualmode", 0, 1, 0, f_visualmode},
950 {"wildmenumode", 0, 0, 0, f_wildmenumode},
951 {"win_execute", 2, 3, 0, f_win_execute},
952 {"win_findbuf", 1, 1, 0, f_win_findbuf},
953 {"win_getid", 0, 2, 0, f_win_getid},
954 {"win_gotoid", 1, 1, 0, f_win_gotoid},
955 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
956 {"win_id2win", 1, 1, 0, f_win_id2win},
957 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200958 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200959 {"wincol", 0, 0, 0, f_wincol},
960 {"winheight", 1, 1, 0, f_winheight},
961 {"winlayout", 0, 1, 0, f_winlayout},
962 {"winline", 0, 0, 0, f_winline},
963 {"winnr", 0, 1, 0, f_winnr},
964 {"winrestcmd", 0, 0, 0, f_winrestcmd},
965 {"winrestview", 1, 1, 0, f_winrestview},
966 {"winsaveview", 0, 0, 0, f_winsaveview},
967 {"winwidth", 1, 1, 0, f_winwidth},
968 {"wordcount", 0, 0, 0, f_wordcount},
969 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200970 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200971};
972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973/*
974 * Function given to ExpandGeneric() to obtain the list of internal
975 * or user defined function names.
976 */
977 char_u *
978get_function_name(expand_T *xp, int idx)
979{
980 static int intidx = -1;
981 char_u *name;
982
983 if (idx == 0)
984 intidx = -1;
985 if (intidx < 0)
986 {
987 name = get_user_func_name(xp, idx);
988 if (name != NULL)
989 return name;
990 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200991 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200992 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200993 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200994 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200995 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200996 STRCAT(IObuff, ")");
997 return IObuff;
998 }
999
1000 return NULL;
1001}
1002
1003/*
1004 * Function given to ExpandGeneric() to obtain the list of internal or
1005 * user defined variable or function names.
1006 */
1007 char_u *
1008get_expr_name(expand_T *xp, int idx)
1009{
1010 static int intidx = -1;
1011 char_u *name;
1012
1013 if (idx == 0)
1014 intidx = -1;
1015 if (intidx < 0)
1016 {
1017 name = get_function_name(xp, idx);
1018 if (name != NULL)
1019 return name;
1020 }
1021 return get_user_var_name(xp, ++intidx);
1022}
1023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001024/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001025 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001026 * Return index, or -1 if not found
1027 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001028 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001029find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001030{
1031 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001032 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001033 int cmp;
1034 int x;
1035
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001036 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001037
1038 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001039 while (first <= last)
1040 {
1041 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001042 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001043 if (cmp < 0)
1044 last = x - 1;
1045 else if (cmp > 0)
1046 first = x + 1;
1047 else
1048 return x;
1049 }
1050 return -1;
1051}
1052
1053 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001054has_internal_func(char_u *name)
1055{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001056 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001057}
1058
1059 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001060call_internal_func(
1061 char_u *name,
1062 int argcount,
1063 typval_T *argvars,
1064 typval_T *rettv)
1065{
1066 int i;
1067
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001068 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001069 if (i < 0)
1070 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001071 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001072 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001073 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001074 return ERROR_TOOMANY;
1075 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001076 global_functions[i].f_func(argvars, rettv);
1077 return ERROR_NONE;
1078}
1079
1080/*
1081 * Invoke a method for base->method().
1082 */
1083 int
1084call_internal_method(
1085 char_u *name,
1086 int argcount,
1087 typval_T *argvars,
1088 typval_T *rettv,
1089 typval_T *basetv)
1090{
1091 int i;
1092 int fi;
1093 typval_T argv[MAX_FUNC_ARGS + 1];
1094
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001095 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001096 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001097 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001098 if (global_functions[fi].f_argtype == 0)
1099 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001100 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001102 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001103 return ERROR_TOOMANY;
1104
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001105 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001106 {
1107 // base value goes last
1108 for (i = 0; i < argcount; ++i)
1109 argv[i] = argvars[i];
1110 argv[argcount] = *basetv;
1111 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001112 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001113 {
1114 // base value goes second
1115 argv[0] = argvars[0];
1116 argv[1] = *basetv;
1117 for (i = 1; i < argcount; ++i)
1118 argv[i + 1] = argvars[i];
1119 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001120 else if (global_functions[fi].f_argtype == FEARG_3)
1121 {
1122 // base value goes third
1123 argv[0] = argvars[0];
1124 argv[1] = argvars[1];
1125 argv[2] = *basetv;
1126 for (i = 2; i < argcount; ++i)
1127 argv[i + 1] = argvars[i];
1128 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001129 else
1130 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001131 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001132 argv[0] = *basetv;
1133 for (i = 0; i < argcount; ++i)
1134 argv[i + 1] = argvars[i];
1135 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001136 argv[argcount + 1].v_type = VAR_UNKNOWN;
1137
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001138 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001139 return ERROR_NONE;
1140}
1141
1142/*
1143 * Return TRUE for a non-zero Number and a non-empty String.
1144 */
1145 static int
1146non_zero_arg(typval_T *argvars)
1147{
1148 return ((argvars[0].v_type == VAR_NUMBER
1149 && argvars[0].vval.v_number != 0)
1150 || (argvars[0].v_type == VAR_SPECIAL
1151 && argvars[0].vval.v_number == VVAL_TRUE)
1152 || (argvars[0].v_type == VAR_STRING
1153 && argvars[0].vval.v_string != NULL
1154 && *argvars[0].vval.v_string != NUL));
1155}
1156
1157/*
1158 * Get the lnum from the first argument.
1159 * Also accepts ".", "$", etc., but that only works for the current buffer.
1160 * Returns -1 on error.
1161 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001162 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001163tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001164{
1165 typval_T rettv;
1166 linenr_T lnum;
1167
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001168 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001169 if (lnum == 0) /* no valid number, try using line() */
1170 {
1171 rettv.v_type = VAR_NUMBER;
1172 f_line(argvars, &rettv);
1173 lnum = (linenr_T)rettv.vval.v_number;
1174 clear_tv(&rettv);
1175 }
1176 return lnum;
1177}
1178
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001179/*
1180 * Get the lnum from the first argument.
1181 * Also accepts "$", then "buf" is used.
1182 * Returns 0 on error.
1183 */
1184 static linenr_T
1185tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1186{
1187 if (argvars[0].v_type == VAR_STRING
1188 && argvars[0].vval.v_string != NULL
1189 && argvars[0].vval.v_string[0] == '$'
1190 && buf != NULL)
1191 return buf->b_ml.ml_line_count;
1192 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1193}
1194
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001195#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001196/*
1197 * Get the float value of "argvars[0]" into "f".
1198 * Returns FAIL when the argument is not a Number or Float.
1199 */
1200 static int
1201get_float_arg(typval_T *argvars, float_T *f)
1202{
1203 if (argvars[0].v_type == VAR_FLOAT)
1204 {
1205 *f = argvars[0].vval.v_float;
1206 return OK;
1207 }
1208 if (argvars[0].v_type == VAR_NUMBER)
1209 {
1210 *f = (float_T)argvars[0].vval.v_number;
1211 return OK;
1212 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001213 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001214 return FAIL;
1215}
1216
1217/*
1218 * "abs(expr)" function
1219 */
1220 static void
1221f_abs(typval_T *argvars, typval_T *rettv)
1222{
1223 if (argvars[0].v_type == VAR_FLOAT)
1224 {
1225 rettv->v_type = VAR_FLOAT;
1226 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1227 }
1228 else
1229 {
1230 varnumber_T n;
1231 int error = FALSE;
1232
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001233 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 if (error)
1235 rettv->vval.v_number = -1;
1236 else if (n > 0)
1237 rettv->vval.v_number = n;
1238 else
1239 rettv->vval.v_number = -n;
1240 }
1241}
1242
1243/*
1244 * "acos()" function
1245 */
1246 static void
1247f_acos(typval_T *argvars, typval_T *rettv)
1248{
1249 float_T f = 0.0;
1250
1251 rettv->v_type = VAR_FLOAT;
1252 if (get_float_arg(argvars, &f) == OK)
1253 rettv->vval.v_float = acos(f);
1254 else
1255 rettv->vval.v_float = 0.0;
1256}
1257#endif
1258
1259/*
1260 * "add(list, item)" function
1261 */
1262 static void
1263f_add(typval_T *argvars, typval_T *rettv)
1264{
1265 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001266 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267
1268 rettv->vval.v_number = 1; /* Default: Failed */
1269 if (argvars[0].v_type == VAR_LIST)
1270 {
1271 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001272 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001273 (char_u *)N_("add() argument"), TRUE)
1274 && list_append_tv(l, &argvars[1]) == OK)
1275 copy_tv(&argvars[0], rettv);
1276 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001277 else if (argvars[0].v_type == VAR_BLOB)
1278 {
1279 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001280 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001281 (char_u *)N_("add() argument"), TRUE))
1282 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001283 int error = FALSE;
1284 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1285
1286 if (!error)
1287 {
1288 ga_append(&b->bv_ga, (int)n);
1289 copy_tv(&argvars[0], rettv);
1290 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001291 }
1292 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001294 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295}
1296
1297/*
1298 * "and(expr, expr)" function
1299 */
1300 static void
1301f_and(typval_T *argvars, typval_T *rettv)
1302{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001303 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1304 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001305}
1306
1307/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001308 * If there is a window for "curbuf", make it the current window.
1309 */
1310 static void
1311find_win_for_curbuf(void)
1312{
1313 wininfo_T *wip;
1314
1315 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1316 {
1317 if (wip->wi_win != NULL)
1318 {
1319 curwin = wip->wi_win;
1320 break;
1321 }
1322 }
1323}
1324
1325/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001326 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001327 */
1328 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001329set_buffer_lines(
1330 buf_T *buf,
1331 linenr_T lnum_arg,
1332 int append,
1333 typval_T *lines,
1334 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335{
Bram Moolenaarca851592018-06-06 21:04:07 +02001336 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1337 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338 list_T *l = NULL;
1339 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001340 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001341 linenr_T append_lnum;
1342 buf_T *curbuf_save = NULL;
1343 win_T *curwin_save = NULL;
1344 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001345
Bram Moolenaarca851592018-06-06 21:04:07 +02001346 /* When using the current buffer ml_mfp will be set if needed. Useful when
1347 * setline() is used on startup. For other buffers the buffer must be
1348 * loaded. */
1349 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001351 rettv->vval.v_number = 1; /* FAIL */
1352 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353 }
1354
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001356 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001357 curbuf_save = curbuf;
1358 curwin_save = curwin;
1359 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001360 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001361 }
1362
1363 if (append)
1364 // appendbufline() uses the line number below which we insert
1365 append_lnum = lnum - 1;
1366 else
1367 // setbufline() uses the line number above which we insert, we only
1368 // append if it's below the last line
1369 append_lnum = curbuf->b_ml.ml_line_count;
1370
1371 if (lines->v_type == VAR_LIST)
1372 {
1373 l = lines->vval.v_list;
1374 li = l->lv_first;
1375 }
1376 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001377 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001378
1379 /* default result is zero == OK */
1380 for (;;)
1381 {
1382 if (l != NULL)
1383 {
1384 /* list argument, get next string */
1385 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001386 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001387 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001388 li = li->li_next;
1389 }
1390
Bram Moolenaarca851592018-06-06 21:04:07 +02001391 rettv->vval.v_number = 1; /* FAIL */
1392 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1393 break;
1394
1395 /* When coming here from Insert mode, sync undo, so that this can be
1396 * undone separately from what was previously inserted. */
1397 if (u_sync_once == 2)
1398 {
1399 u_sync_once = 1; /* notify that u_sync() was called */
1400 u_sync(TRUE);
1401 }
1402
1403 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1404 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001405 // Existing line, replace it.
1406 // Removes any existing text properties.
1407 if (u_savesub(lnum) == OK && ml_replace_len(
1408 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001409 {
1410 changed_bytes(lnum, 0);
1411 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1412 check_cursor_col();
1413 rettv->vval.v_number = 0; /* OK */
1414 }
1415 }
1416 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1417 {
1418 /* append the line */
1419 ++added;
1420 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1421 rettv->vval.v_number = 0; /* OK */
1422 }
1423
1424 if (l == NULL) /* only one string argument */
1425 break;
1426 ++lnum;
1427 }
1428
1429 if (added > 0)
1430 {
1431 win_T *wp;
1432 tabpage_T *tp;
1433
1434 appended_lines_mark(append_lnum, added);
Bram Moolenaard2007022019-08-27 21:56:06 +02001435
1436 // Only adjust the cursor for buffers other than the current, unless it
1437 // is the current window. For curbuf and other windows it has been
1438 // done in mark_adjust_internal().
Bram Moolenaarca851592018-06-06 21:04:07 +02001439 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaard2007022019-08-27 21:56:06 +02001440 if (wp->w_buffer == buf
1441 && (wp->w_buffer != curbuf || wp == curwin)
1442 && wp->w_cursor.lnum > append_lnum)
Bram Moolenaarca851592018-06-06 21:04:07 +02001443 wp->w_cursor.lnum += added;
1444 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001445 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001446 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001447
1448 if (!is_curbuf)
1449 {
1450 curbuf = curbuf_save;
1451 curwin = curwin_save;
1452 }
1453}
1454
1455/*
1456 * "append(lnum, string/list)" function
1457 */
1458 static void
1459f_append(typval_T *argvars, typval_T *rettv)
1460{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001461 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001462
1463 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1464}
1465
1466/*
1467 * "appendbufline(buf, lnum, string/list)" function
1468 */
1469 static void
1470f_appendbufline(typval_T *argvars, typval_T *rettv)
1471{
1472 linenr_T lnum;
1473 buf_T *buf;
1474
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001475 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001476 if (buf == NULL)
1477 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001478 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001480 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001481 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1482 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483}
1484
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485#ifdef FEAT_FLOAT
1486/*
1487 * "asin()" function
1488 */
1489 static void
1490f_asin(typval_T *argvars, typval_T *rettv)
1491{
1492 float_T f = 0.0;
1493
1494 rettv->v_type = VAR_FLOAT;
1495 if (get_float_arg(argvars, &f) == OK)
1496 rettv->vval.v_float = asin(f);
1497 else
1498 rettv->vval.v_float = 0.0;
1499}
1500
1501/*
1502 * "atan()" function
1503 */
1504 static void
1505f_atan(typval_T *argvars, typval_T *rettv)
1506{
1507 float_T f = 0.0;
1508
1509 rettv->v_type = VAR_FLOAT;
1510 if (get_float_arg(argvars, &f) == OK)
1511 rettv->vval.v_float = atan(f);
1512 else
1513 rettv->vval.v_float = 0.0;
1514}
1515
1516/*
1517 * "atan2()" function
1518 */
1519 static void
1520f_atan2(typval_T *argvars, typval_T *rettv)
1521{
1522 float_T fx = 0.0, fy = 0.0;
1523
1524 rettv->v_type = VAR_FLOAT;
1525 if (get_float_arg(argvars, &fx) == OK
1526 && get_float_arg(&argvars[1], &fy) == OK)
1527 rettv->vval.v_float = atan2(fx, fy);
1528 else
1529 rettv->vval.v_float = 0.0;
1530}
1531#endif
1532
1533/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001534 * "balloon_show()" function
1535 */
1536#ifdef FEAT_BEVAL
1537 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001538f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1539{
1540 rettv->v_type = VAR_STRING;
1541 if (balloonEval != NULL)
1542 {
1543 if (balloonEval->msg == NULL)
1544 rettv->vval.v_string = NULL;
1545 else
1546 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1547 }
1548}
1549
1550 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001551f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1552{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001553 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001554 {
1555 if (argvars[0].v_type == VAR_LIST
1556# ifdef FEAT_GUI
1557 && !gui.in_use
1558# endif
1559 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001560 {
1561 list_T *l = argvars[0].vval.v_list;
1562
1563 // empty list removes the balloon
1564 post_balloon(balloonEval, NULL,
1565 l == NULL || l->lv_len == 0 ? NULL : l);
1566 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001567 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001568 {
1569 char_u *mesg = tv_get_string_chk(&argvars[0]);
1570
1571 if (mesg != NULL)
1572 // empty string removes the balloon
1573 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1574 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001575 }
1576}
1577
Bram Moolenaar669a8282017-11-19 20:13:05 +01001578# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001579 static void
1580f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1581{
1582 if (rettv_list_alloc(rettv) == OK)
1583 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001584 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001585
1586 if (msg != NULL)
1587 {
1588 pumitem_T *array;
1589 int size = split_message(msg, &array);
1590 int i;
1591
1592 /* Skip the first and last item, they are always empty. */
1593 for (i = 1; i < size - 1; ++i)
1594 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001595 while (size > 0)
1596 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001597 vim_free(array);
1598 }
1599 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001600}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001601# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001602#endif
1603
1604/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605 * "browse(save, title, initdir, default)" function
1606 */
1607 static void
1608f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1609{
1610#ifdef FEAT_BROWSE
1611 int save;
1612 char_u *title;
1613 char_u *initdir;
1614 char_u *defname;
1615 char_u buf[NUMBUFLEN];
1616 char_u buf2[NUMBUFLEN];
1617 int error = FALSE;
1618
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001619 save = (int)tv_get_number_chk(&argvars[0], &error);
1620 title = tv_get_string_chk(&argvars[1]);
1621 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1622 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001623
1624 if (error || title == NULL || initdir == NULL || defname == NULL)
1625 rettv->vval.v_string = NULL;
1626 else
1627 rettv->vval.v_string =
1628 do_browse(save ? BROWSE_SAVE : 0,
1629 title, defname, NULL, initdir, NULL, curbuf);
1630#else
1631 rettv->vval.v_string = NULL;
1632#endif
1633 rettv->v_type = VAR_STRING;
1634}
1635
1636/*
1637 * "browsedir(title, initdir)" function
1638 */
1639 static void
1640f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1641{
1642#ifdef FEAT_BROWSE
1643 char_u *title;
1644 char_u *initdir;
1645 char_u buf[NUMBUFLEN];
1646
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001647 title = tv_get_string_chk(&argvars[0]);
1648 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649
1650 if (title == NULL || initdir == NULL)
1651 rettv->vval.v_string = NULL;
1652 else
1653 rettv->vval.v_string = do_browse(BROWSE_DIR,
1654 title, NULL, NULL, initdir, NULL, curbuf);
1655#else
1656 rettv->vval.v_string = NULL;
1657#endif
1658 rettv->v_type = VAR_STRING;
1659}
1660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661/*
1662 * Find a buffer by number or exact name.
1663 */
1664 static buf_T *
1665find_buffer(typval_T *avar)
1666{
1667 buf_T *buf = NULL;
1668
1669 if (avar->v_type == VAR_NUMBER)
1670 buf = buflist_findnr((int)avar->vval.v_number);
1671 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1672 {
1673 buf = buflist_findname_exp(avar->vval.v_string);
1674 if (buf == NULL)
1675 {
1676 /* No full path name match, try a match with a URL or a "nofile"
1677 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001678 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001679 if (buf->b_fname != NULL
1680 && (path_with_url(buf->b_fname)
1681#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001682 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683#endif
1684 )
1685 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1686 break;
1687 }
1688 }
1689 return buf;
1690}
1691
1692/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001693 * "bufadd(expr)" function
1694 */
1695 static void
1696f_bufadd(typval_T *argvars, typval_T *rettv)
1697{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001698 char_u *name = tv_get_string(&argvars[0]);
1699
1700 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001701}
1702
1703/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001704 * "bufexists(expr)" function
1705 */
1706 static void
1707f_bufexists(typval_T *argvars, typval_T *rettv)
1708{
1709 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1710}
1711
1712/*
1713 * "buflisted(expr)" function
1714 */
1715 static void
1716f_buflisted(typval_T *argvars, typval_T *rettv)
1717{
1718 buf_T *buf;
1719
1720 buf = find_buffer(&argvars[0]);
1721 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1722}
1723
1724/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001725 * "bufload(expr)" function
1726 */
1727 static void
1728f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1729{
1730 buf_T *buf = get_buf_arg(&argvars[0]);
1731
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001732 if (buf != NULL)
1733 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001734}
1735
1736/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001737 * "bufloaded(expr)" function
1738 */
1739 static void
1740f_bufloaded(typval_T *argvars, typval_T *rettv)
1741{
1742 buf_T *buf;
1743
1744 buf = find_buffer(&argvars[0]);
1745 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1746}
1747
1748 buf_T *
1749buflist_find_by_name(char_u *name, int curtab_only)
1750{
1751 int save_magic;
1752 char_u *save_cpo;
1753 buf_T *buf;
1754
1755 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1756 save_magic = p_magic;
1757 p_magic = TRUE;
1758 save_cpo = p_cpo;
1759 p_cpo = (char_u *)"";
1760
1761 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1762 TRUE, FALSE, curtab_only));
1763
1764 p_magic = save_magic;
1765 p_cpo = save_cpo;
1766 return buf;
1767}
1768
1769/*
1770 * Get buffer by number or pattern.
1771 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001772 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001773tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001774{
1775 char_u *name = tv->vval.v_string;
1776 buf_T *buf;
1777
1778 if (tv->v_type == VAR_NUMBER)
1779 return buflist_findnr((int)tv->vval.v_number);
1780 if (tv->v_type != VAR_STRING)
1781 return NULL;
1782 if (name == NULL || *name == NUL)
1783 return curbuf;
1784 if (name[0] == '$' && name[1] == NUL)
1785 return lastbuf;
1786
1787 buf = buflist_find_by_name(name, curtab_only);
1788
1789 /* If not found, try expanding the name, like done for bufexists(). */
1790 if (buf == NULL)
1791 buf = find_buffer(tv);
1792
1793 return buf;
1794}
1795
1796/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001797 * Get the buffer from "arg" and give an error and return NULL if it is not
1798 * valid.
1799 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001800 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001801get_buf_arg(typval_T *arg)
1802{
1803 buf_T *buf;
1804
1805 ++emsg_off;
1806 buf = tv_get_buf(arg, FALSE);
1807 --emsg_off;
1808 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001809 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001810 return buf;
1811}
1812
1813/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 * "bufname(expr)" function
1815 */
1816 static void
1817f_bufname(typval_T *argvars, typval_T *rettv)
1818{
1819 buf_T *buf;
1820
Bram Moolenaara8eee212019-08-24 22:14:58 +02001821 if (argvars[0].v_type == VAR_UNKNOWN)
1822 buf = curbuf;
1823 else
1824 {
1825 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1826 ++emsg_off;
1827 buf = tv_get_buf(&argvars[0], FALSE);
1828 --emsg_off;
1829 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 rettv->v_type = VAR_STRING;
1831 if (buf != NULL && buf->b_fname != NULL)
1832 rettv->vval.v_string = vim_strsave(buf->b_fname);
1833 else
1834 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835}
1836
1837/*
1838 * "bufnr(expr)" function
1839 */
1840 static void
1841f_bufnr(typval_T *argvars, typval_T *rettv)
1842{
1843 buf_T *buf;
1844 int error = FALSE;
1845 char_u *name;
1846
Bram Moolenaara8eee212019-08-24 22:14:58 +02001847 if (argvars[0].v_type == VAR_UNKNOWN)
1848 buf = curbuf;
1849 else
1850 {
1851 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1852 ++emsg_off;
1853 buf = tv_get_buf(&argvars[0], FALSE);
1854 --emsg_off;
1855 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001856
Bram Moolenaara8eee212019-08-24 22:14:58 +02001857 // If the buffer isn't found and the second argument is not zero create a
1858 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859 if (buf == NULL
1860 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001861 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001862 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001863 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001864 && !error)
1865 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1866
1867 if (buf != NULL)
1868 rettv->vval.v_number = buf->b_fnum;
1869 else
1870 rettv->vval.v_number = -1;
1871}
1872
1873 static void
1874buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1875{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001876 win_T *wp;
1877 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878 buf_T *buf;
1879
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001880 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001882 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001883 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884 {
1885 ++winnr;
1886 if (wp->w_buffer == buf)
1887 break;
1888 }
1889 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 --emsg_off;
1891}
1892
1893/*
1894 * "bufwinid(nr)" function
1895 */
1896 static void
1897f_bufwinid(typval_T *argvars, typval_T *rettv)
1898{
1899 buf_win_common(argvars, rettv, FALSE);
1900}
1901
1902/*
1903 * "bufwinnr(nr)" function
1904 */
1905 static void
1906f_bufwinnr(typval_T *argvars, typval_T *rettv)
1907{
1908 buf_win_common(argvars, rettv, TRUE);
1909}
1910
1911/*
1912 * "byte2line(byte)" function
1913 */
1914 static void
1915f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1916{
1917#ifndef FEAT_BYTEOFF
1918 rettv->vval.v_number = -1;
1919#else
1920 long boff = 0;
1921
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001922 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 if (boff < 0)
1924 rettv->vval.v_number = -1;
1925 else
1926 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1927 (linenr_T)0, &boff);
1928#endif
1929}
1930
1931 static void
1932byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1933{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001934 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 char_u *str;
1936 varnumber_T idx;
1937
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001938 str = tv_get_string_chk(&argvars[0]);
1939 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001940 rettv->vval.v_number = -1;
1941 if (str == NULL || idx < 0)
1942 return;
1943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001944 t = str;
1945 for ( ; idx > 0; idx--)
1946 {
1947 if (*t == NUL) /* EOL reached */
1948 return;
1949 if (enc_utf8 && comp)
1950 t += utf_ptr2len(t);
1951 else
1952 t += (*mb_ptr2len)(t);
1953 }
1954 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955}
1956
1957/*
1958 * "byteidx()" function
1959 */
1960 static void
1961f_byteidx(typval_T *argvars, typval_T *rettv)
1962{
1963 byteidx(argvars, rettv, FALSE);
1964}
1965
1966/*
1967 * "byteidxcomp()" function
1968 */
1969 static void
1970f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1971{
1972 byteidx(argvars, rettv, TRUE);
1973}
1974
1975/*
1976 * "call(func, arglist [, dict])" function
1977 */
1978 static void
1979f_call(typval_T *argvars, typval_T *rettv)
1980{
1981 char_u *func;
1982 partial_T *partial = NULL;
1983 dict_T *selfdict = NULL;
1984
1985 if (argvars[1].v_type != VAR_LIST)
1986 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001987 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 return;
1989 }
1990 if (argvars[1].vval.v_list == NULL)
1991 return;
1992
1993 if (argvars[0].v_type == VAR_FUNC)
1994 func = argvars[0].vval.v_string;
1995 else if (argvars[0].v_type == VAR_PARTIAL)
1996 {
1997 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001998 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 }
2000 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002001 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002 if (*func == NUL)
2003 return; /* type error or empty name */
2004
2005 if (argvars[2].v_type != VAR_UNKNOWN)
2006 {
2007 if (argvars[2].v_type != VAR_DICT)
2008 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002009 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 return;
2011 }
2012 selfdict = argvars[2].vval.v_dict;
2013 }
2014
2015 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2016}
2017
2018#ifdef FEAT_FLOAT
2019/*
2020 * "ceil({float})" function
2021 */
2022 static void
2023f_ceil(typval_T *argvars, typval_T *rettv)
2024{
2025 float_T f = 0.0;
2026
2027 rettv->v_type = VAR_FLOAT;
2028 if (get_float_arg(argvars, &f) == OK)
2029 rettv->vval.v_float = ceil(f);
2030 else
2031 rettv->vval.v_float = 0.0;
2032}
2033#endif
2034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035/*
2036 * "changenr()" function
2037 */
2038 static void
2039f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2040{
2041 rettv->vval.v_number = curbuf->b_u_seq_cur;
2042}
2043
2044/*
2045 * "char2nr(string)" function
2046 */
2047 static void
2048f_char2nr(typval_T *argvars, typval_T *rettv)
2049{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002050 if (has_mbyte)
2051 {
2052 int utf8 = 0;
2053
2054 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002055 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002056
2057 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002058 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002060 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 }
2062 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002063 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002064}
2065
2066/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002067 * "chdir(dir)" function
2068 */
2069 static void
2070f_chdir(typval_T *argvars, typval_T *rettv)
2071{
2072 char_u *cwd;
2073 cdscope_T scope = CDSCOPE_GLOBAL;
2074
2075 rettv->v_type = VAR_STRING;
2076 rettv->vval.v_string = NULL;
2077
2078 if (argvars[0].v_type != VAR_STRING)
2079 return;
2080
2081 // Return the current directory
2082 cwd = alloc(MAXPATHL);
2083 if (cwd != NULL)
2084 {
2085 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2086 {
2087#ifdef BACKSLASH_IN_FILENAME
2088 slash_adjust(cwd);
2089#endif
2090 rettv->vval.v_string = vim_strsave(cwd);
2091 }
2092 vim_free(cwd);
2093 }
2094
2095 if (curwin->w_localdir != NULL)
2096 scope = CDSCOPE_WINDOW;
2097 else if (curtab->tp_localdir != NULL)
2098 scope = CDSCOPE_TABPAGE;
2099
2100 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2101 // Directory change failed
2102 VIM_CLEAR(rettv->vval.v_string);
2103}
2104
2105/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106 * "cindent(lnum)" function
2107 */
2108 static void
2109f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2110{
2111#ifdef FEAT_CINDENT
2112 pos_T pos;
2113 linenr_T lnum;
2114
2115 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002116 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002117 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2118 {
2119 curwin->w_cursor.lnum = lnum;
2120 rettv->vval.v_number = get_c_indent();
2121 curwin->w_cursor = pos;
2122 }
2123 else
2124#endif
2125 rettv->vval.v_number = -1;
2126}
2127
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002128 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002129get_optional_window(typval_T *argvars, int idx)
2130{
2131 win_T *win = curwin;
2132
2133 if (argvars[idx].v_type != VAR_UNKNOWN)
2134 {
2135 win = find_win_by_nr_or_id(&argvars[idx]);
2136 if (win == NULL)
2137 {
2138 emsg(_(e_invalwindow));
2139 return NULL;
2140 }
2141 }
2142 return win;
2143}
2144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002145/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146 * "col(string)" function
2147 */
2148 static void
2149f_col(typval_T *argvars, typval_T *rettv)
2150{
2151 colnr_T col = 0;
2152 pos_T *fp;
2153 int fnum = curbuf->b_fnum;
2154
2155 fp = var2fpos(&argvars[0], FALSE, &fnum);
2156 if (fp != NULL && fnum == curbuf->b_fnum)
2157 {
2158 if (fp->col == MAXCOL)
2159 {
2160 /* '> can be MAXCOL, get the length of the line then */
2161 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2162 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2163 else
2164 col = MAXCOL;
2165 }
2166 else
2167 {
2168 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 /* col(".") when the cursor is on the NUL at the end of the line
2170 * because of "coladd" can be seen as an extra column. */
2171 if (virtual_active() && fp == &curwin->w_cursor)
2172 {
2173 char_u *p = ml_get_cursor();
2174
2175 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2176 curwin->w_virtcol - curwin->w_cursor.coladd))
2177 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178 int l;
2179
2180 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2181 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 }
2183 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184 }
2185 }
2186 rettv->vval.v_number = col;
2187}
2188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189/*
2190 * "confirm(message, buttons[, default [, type]])" function
2191 */
2192 static void
2193f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2194{
2195#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2196 char_u *message;
2197 char_u *buttons = NULL;
2198 char_u buf[NUMBUFLEN];
2199 char_u buf2[NUMBUFLEN];
2200 int def = 1;
2201 int type = VIM_GENERIC;
2202 char_u *typestr;
2203 int error = FALSE;
2204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002205 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 if (message == NULL)
2207 error = TRUE;
2208 if (argvars[1].v_type != VAR_UNKNOWN)
2209 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002210 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 if (buttons == NULL)
2212 error = TRUE;
2213 if (argvars[2].v_type != VAR_UNKNOWN)
2214 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002215 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 if (argvars[3].v_type != VAR_UNKNOWN)
2217 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002218 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219 if (typestr == NULL)
2220 error = TRUE;
2221 else
2222 {
2223 switch (TOUPPER_ASC(*typestr))
2224 {
2225 case 'E': type = VIM_ERROR; break;
2226 case 'Q': type = VIM_QUESTION; break;
2227 case 'I': type = VIM_INFO; break;
2228 case 'W': type = VIM_WARNING; break;
2229 case 'G': type = VIM_GENERIC; break;
2230 }
2231 }
2232 }
2233 }
2234 }
2235
2236 if (buttons == NULL || *buttons == NUL)
2237 buttons = (char_u *)_("&Ok");
2238
2239 if (!error)
2240 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2241 def, NULL, FALSE);
2242#endif
2243}
2244
2245/*
2246 * "copy()" function
2247 */
2248 static void
2249f_copy(typval_T *argvars, typval_T *rettv)
2250{
2251 item_copy(&argvars[0], rettv, FALSE, 0);
2252}
2253
2254#ifdef FEAT_FLOAT
2255/*
2256 * "cos()" function
2257 */
2258 static void
2259f_cos(typval_T *argvars, typval_T *rettv)
2260{
2261 float_T f = 0.0;
2262
2263 rettv->v_type = VAR_FLOAT;
2264 if (get_float_arg(argvars, &f) == OK)
2265 rettv->vval.v_float = cos(f);
2266 else
2267 rettv->vval.v_float = 0.0;
2268}
2269
2270/*
2271 * "cosh()" function
2272 */
2273 static void
2274f_cosh(typval_T *argvars, typval_T *rettv)
2275{
2276 float_T f = 0.0;
2277
2278 rettv->v_type = VAR_FLOAT;
2279 if (get_float_arg(argvars, &f) == OK)
2280 rettv->vval.v_float = cosh(f);
2281 else
2282 rettv->vval.v_float = 0.0;
2283}
2284#endif
2285
2286/*
2287 * "count()" function
2288 */
2289 static void
2290f_count(typval_T *argvars, typval_T *rettv)
2291{
2292 long n = 0;
2293 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002294 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295
Bram Moolenaar9966b212017-07-28 16:46:57 +02002296 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002297 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002298
2299 if (argvars[0].v_type == VAR_STRING)
2300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002301 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002302 char_u *p = argvars[0].vval.v_string;
2303 char_u *next;
2304
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002305 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002306 {
2307 if (ic)
2308 {
2309 size_t len = STRLEN(expr);
2310
2311 while (*p != NUL)
2312 {
2313 if (MB_STRNICMP(p, expr, len) == 0)
2314 {
2315 ++n;
2316 p += len;
2317 }
2318 else
2319 MB_PTR_ADV(p);
2320 }
2321 }
2322 else
2323 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2324 != NULL)
2325 {
2326 ++n;
2327 p = next + STRLEN(expr);
2328 }
2329 }
2330
2331 }
2332 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002333 {
2334 listitem_T *li;
2335 list_T *l;
2336 long idx;
2337
2338 if ((l = argvars[0].vval.v_list) != NULL)
2339 {
2340 li = l->lv_first;
2341 if (argvars[2].v_type != VAR_UNKNOWN)
2342 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 if (argvars[3].v_type != VAR_UNKNOWN)
2344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002345 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002346 if (!error)
2347 {
2348 li = list_find(l, idx);
2349 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002350 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351 }
2352 }
2353 if (error)
2354 li = NULL;
2355 }
2356
2357 for ( ; li != NULL; li = li->li_next)
2358 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2359 ++n;
2360 }
2361 }
2362 else if (argvars[0].v_type == VAR_DICT)
2363 {
2364 int todo;
2365 dict_T *d;
2366 hashitem_T *hi;
2367
2368 if ((d = argvars[0].vval.v_dict) != NULL)
2369 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 if (argvars[2].v_type != VAR_UNKNOWN)
2371 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002373 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002374 }
2375
2376 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2377 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2378 {
2379 if (!HASHITEM_EMPTY(hi))
2380 {
2381 --todo;
2382 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2383 ++n;
2384 }
2385 }
2386 }
2387 }
2388 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002389 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390 rettv->vval.v_number = n;
2391}
2392
2393/*
2394 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2395 *
2396 * Checks the existence of a cscope connection.
2397 */
2398 static void
2399f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2400{
2401#ifdef FEAT_CSCOPE
2402 int num = 0;
2403 char_u *dbpath = NULL;
2404 char_u *prepend = NULL;
2405 char_u buf[NUMBUFLEN];
2406
2407 if (argvars[0].v_type != VAR_UNKNOWN
2408 && argvars[1].v_type != VAR_UNKNOWN)
2409 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002410 num = (int)tv_get_number(&argvars[0]);
2411 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002412 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002413 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 }
2415
2416 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2417#endif
2418}
2419
2420/*
2421 * "cursor(lnum, col)" function, or
2422 * "cursor(list)"
2423 *
2424 * Moves the cursor to the specified line and column.
2425 * Returns 0 when the position could be set, -1 otherwise.
2426 */
2427 static void
2428f_cursor(typval_T *argvars, typval_T *rettv)
2429{
2430 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 int set_curswant = TRUE;
2433
2434 rettv->vval.v_number = -1;
2435 if (argvars[1].v_type == VAR_UNKNOWN)
2436 {
2437 pos_T pos;
2438 colnr_T curswant = -1;
2439
2440 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2441 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002442 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002443 return;
2444 }
2445 line = pos.lnum;
2446 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 if (curswant >= 0)
2449 {
2450 curwin->w_curswant = curswant - 1;
2451 set_curswant = FALSE;
2452 }
2453 }
2454 else
2455 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002456 line = tv_get_lnum(argvars);
2457 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002459 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002461 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462 return; /* type error; errmsg already given */
2463 if (line > 0)
2464 curwin->w_cursor.lnum = line;
2465 if (col > 0)
2466 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002468
2469 /* Make sure the cursor is in a valid position. */
2470 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 /* Correct cursor for multi-byte character. */
2472 if (has_mbyte)
2473 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474
2475 curwin->w_set_curswant = set_curswant;
2476 rettv->vval.v_number = 0;
2477}
2478
Bram Moolenaar4f974752019-02-17 17:44:42 +01002479#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002480/*
2481 * "debugbreak()" function
2482 */
2483 static void
2484f_debugbreak(typval_T *argvars, typval_T *rettv)
2485{
2486 int pid;
2487
2488 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002489 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002490 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002491 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002492 else
2493 {
2494 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2495
2496 if (hProcess != NULL)
2497 {
2498 DebugBreakProcess(hProcess);
2499 CloseHandle(hProcess);
2500 rettv->vval.v_number = OK;
2501 }
2502 }
2503}
2504#endif
2505
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506/*
2507 * "deepcopy()" function
2508 */
2509 static void
2510f_deepcopy(typval_T *argvars, typval_T *rettv)
2511{
2512 int noref = 0;
2513 int copyID;
2514
2515 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002516 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002518 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002519 else
2520 {
2521 copyID = get_copyID();
2522 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2523 }
2524}
2525
2526/*
2527 * "delete()" function
2528 */
2529 static void
2530f_delete(typval_T *argvars, typval_T *rettv)
2531{
2532 char_u nbuf[NUMBUFLEN];
2533 char_u *name;
2534 char_u *flags;
2535
2536 rettv->vval.v_number = -1;
2537 if (check_restricted() || check_secure())
2538 return;
2539
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002540 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 if (name == NULL || *name == NUL)
2542 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002543 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002544 return;
2545 }
2546
2547 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002548 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 else
2550 flags = (char_u *)"";
2551
2552 if (*flags == NUL)
2553 /* delete a file */
2554 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2555 else if (STRCMP(flags, "d") == 0)
2556 /* delete an empty directory */
2557 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2558 else if (STRCMP(flags, "rf") == 0)
2559 /* delete a directory recursively */
2560 rettv->vval.v_number = delete_recursive(name);
2561 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002562 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563}
2564
2565/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002566 * "deletebufline()" function
2567 */
2568 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002569f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002570{
2571 buf_T *buf;
2572 linenr_T first, last;
2573 linenr_T lnum;
2574 long count;
2575 int is_curbuf;
2576 buf_T *curbuf_save = NULL;
2577 win_T *curwin_save = NULL;
2578 tabpage_T *tp;
2579 win_T *wp;
2580
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002581 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002582 if (buf == NULL)
2583 {
2584 rettv->vval.v_number = 1; /* FAIL */
2585 return;
2586 }
2587 is_curbuf = buf == curbuf;
2588
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002589 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002590 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002591 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002592 else
2593 last = first;
2594
2595 if (buf->b_ml.ml_mfp == NULL || first < 1
2596 || first > buf->b_ml.ml_line_count || last < first)
2597 {
2598 rettv->vval.v_number = 1; /* FAIL */
2599 return;
2600 }
2601
2602 if (!is_curbuf)
2603 {
2604 curbuf_save = curbuf;
2605 curwin_save = curwin;
2606 curbuf = buf;
2607 find_win_for_curbuf();
2608 }
2609 if (last > curbuf->b_ml.ml_line_count)
2610 last = curbuf->b_ml.ml_line_count;
2611 count = last - first + 1;
2612
2613 // When coming here from Insert mode, sync undo, so that this can be
2614 // undone separately from what was previously inserted.
2615 if (u_sync_once == 2)
2616 {
2617 u_sync_once = 1; // notify that u_sync() was called
2618 u_sync(TRUE);
2619 }
2620
2621 if (u_save(first - 1, last + 1) == FAIL)
2622 {
2623 rettv->vval.v_number = 1; /* FAIL */
2624 return;
2625 }
2626
2627 for (lnum = first; lnum <= last; ++lnum)
2628 ml_delete(first, TRUE);
2629
2630 FOR_ALL_TAB_WINDOWS(tp, wp)
2631 if (wp->w_buffer == buf)
2632 {
2633 if (wp->w_cursor.lnum > last)
2634 wp->w_cursor.lnum -= count;
2635 else if (wp->w_cursor.lnum> first)
2636 wp->w_cursor.lnum = first;
2637 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2638 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2639 }
2640 check_cursor_col();
2641 deleted_lines_mark(first, count);
2642
2643 if (!is_curbuf)
2644 {
2645 curbuf = curbuf_save;
2646 curwin = curwin_save;
2647 }
2648}
2649
2650/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 * "did_filetype()" function
2652 */
2653 static void
2654f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2655{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002657}
2658
2659/*
2660 * "diff_filler()" function
2661 */
2662 static void
2663f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2664{
2665#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002666 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002667#endif
2668}
2669
2670/*
2671 * "diff_hlID()" function
2672 */
2673 static void
2674f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2675{
2676#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002677 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002678 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002679 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 static int fnum = 0;
2681 static int change_start = 0;
2682 static int change_end = 0;
2683 static hlf_T hlID = (hlf_T)0;
2684 int filler_lines;
2685 int col;
2686
2687 if (lnum < 0) /* ignore type error in {lnum} arg */
2688 lnum = 0;
2689 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002690 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 || fnum != curbuf->b_fnum)
2692 {
2693 /* New line, buffer, change: need to get the values. */
2694 filler_lines = diff_check(curwin, lnum);
2695 if (filler_lines < 0)
2696 {
2697 if (filler_lines == -1)
2698 {
2699 change_start = MAXCOL;
2700 change_end = -1;
2701 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2702 hlID = HLF_ADD; /* added line */
2703 else
2704 hlID = HLF_CHD; /* changed line */
2705 }
2706 else
2707 hlID = HLF_ADD; /* added line */
2708 }
2709 else
2710 hlID = (hlf_T)0;
2711 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002712 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 fnum = curbuf->b_fnum;
2714 }
2715
2716 if (hlID == HLF_CHD || hlID == HLF_TXD)
2717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 if (col >= change_start && col <= change_end)
2720 hlID = HLF_TXD; /* changed text */
2721 else
2722 hlID = HLF_CHD; /* changed line */
2723 }
2724 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2725#endif
2726}
2727
2728/*
2729 * "empty({expr})" function
2730 */
2731 static void
2732f_empty(typval_T *argvars, typval_T *rettv)
2733{
2734 int n = FALSE;
2735
2736 switch (argvars[0].v_type)
2737 {
2738 case VAR_STRING:
2739 case VAR_FUNC:
2740 n = argvars[0].vval.v_string == NULL
2741 || *argvars[0].vval.v_string == NUL;
2742 break;
2743 case VAR_PARTIAL:
2744 n = FALSE;
2745 break;
2746 case VAR_NUMBER:
2747 n = argvars[0].vval.v_number == 0;
2748 break;
2749 case VAR_FLOAT:
2750#ifdef FEAT_FLOAT
2751 n = argvars[0].vval.v_float == 0.0;
2752 break;
2753#endif
2754 case VAR_LIST:
2755 n = argvars[0].vval.v_list == NULL
2756 || argvars[0].vval.v_list->lv_first == NULL;
2757 break;
2758 case VAR_DICT:
2759 n = argvars[0].vval.v_dict == NULL
2760 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2761 break;
2762 case VAR_SPECIAL:
2763 n = argvars[0].vval.v_number != VVAL_TRUE;
2764 break;
2765
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002766 case VAR_BLOB:
2767 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002768 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2769 break;
2770
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002771 case VAR_JOB:
2772#ifdef FEAT_JOB_CHANNEL
2773 n = argvars[0].vval.v_job == NULL
2774 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2775 break;
2776#endif
2777 case VAR_CHANNEL:
2778#ifdef FEAT_JOB_CHANNEL
2779 n = argvars[0].vval.v_channel == NULL
2780 || !channel_is_open(argvars[0].vval.v_channel);
2781 break;
2782#endif
2783 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002784 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002785 n = TRUE;
2786 break;
2787 }
2788
2789 rettv->vval.v_number = n;
2790}
2791
2792/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002793 * "environ()" function
2794 */
2795 static void
2796f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2797{
2798#if !defined(AMIGA)
2799 int i = 0;
2800 char_u *entry, *value;
2801# ifdef MSWIN
2802 extern wchar_t **_wenviron;
2803# else
2804 extern char **environ;
2805# endif
2806
2807 if (rettv_dict_alloc(rettv) != OK)
2808 return;
2809
2810# ifdef MSWIN
2811 if (*_wenviron == NULL)
2812 return;
2813# else
2814 if (*environ == NULL)
2815 return;
2816# endif
2817
2818 for (i = 0; ; ++i)
2819 {
2820# ifdef MSWIN
2821 short_u *p;
2822
2823 if ((p = (short_u *)_wenviron[i]) == NULL)
2824 return;
2825 entry = utf16_to_enc(p, NULL);
2826# else
2827 if ((entry = (char_u *)environ[i]) == NULL)
2828 return;
2829 entry = vim_strsave(entry);
2830# endif
2831 if (entry == NULL) // out of memory
2832 return;
2833 if ((value = vim_strchr(entry, '=')) == NULL)
2834 {
2835 vim_free(entry);
2836 continue;
2837 }
2838 *value++ = NUL;
2839 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2840 vim_free(entry);
2841 }
2842#endif
2843}
2844
2845/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002846 * "escape({string}, {chars})" function
2847 */
2848 static void
2849f_escape(typval_T *argvars, typval_T *rettv)
2850{
2851 char_u buf[NUMBUFLEN];
2852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002853 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2854 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 rettv->v_type = VAR_STRING;
2856}
2857
2858/*
2859 * "eval()" function
2860 */
2861 static void
2862f_eval(typval_T *argvars, typval_T *rettv)
2863{
2864 char_u *s, *p;
2865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002866 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002867 if (s != NULL)
2868 s = skipwhite(s);
2869
2870 p = s;
2871 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2872 {
2873 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002874 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002875 need_clr_eos = FALSE;
2876 rettv->v_type = VAR_NUMBER;
2877 rettv->vval.v_number = 0;
2878 }
2879 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002880 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002881}
2882
2883/*
2884 * "eventhandler()" function
2885 */
2886 static void
2887f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2888{
2889 rettv->vval.v_number = vgetc_busy;
2890}
2891
2892/*
2893 * "executable()" function
2894 */
2895 static void
2896f_executable(typval_T *argvars, typval_T *rettv)
2897{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002898 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899
2900 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002901 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902}
2903
2904static garray_T redir_execute_ga;
2905
2906/*
2907 * Append "value[value_len]" to the execute() output.
2908 */
2909 void
2910execute_redir_str(char_u *value, int value_len)
2911{
2912 int len;
2913
2914 if (value_len == -1)
2915 len = (int)STRLEN(value); /* Append the entire string */
2916 else
2917 len = value_len; /* Append only "value_len" characters */
2918 if (ga_grow(&redir_execute_ga, len) == OK)
2919 {
2920 mch_memmove((char *)redir_execute_ga.ga_data
2921 + redir_execute_ga.ga_len, value, len);
2922 redir_execute_ga.ga_len += len;
2923 }
2924}
2925
2926/*
2927 * Get next line from a list.
2928 * Called by do_cmdline() to get the next line.
2929 * Returns allocated string, or NULL for end of function.
2930 */
2931
2932 static char_u *
2933get_list_line(
2934 int c UNUSED,
2935 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002936 int indent UNUSED,
2937 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002938{
2939 listitem_T **p = (listitem_T **)cookie;
2940 listitem_T *item = *p;
2941 char_u buf[NUMBUFLEN];
2942 char_u *s;
2943
2944 if (item == NULL)
2945 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002946 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 *p = item->li_next;
2948 return s == NULL ? NULL : vim_strsave(s);
2949}
2950
2951/*
2952 * "execute()" function
2953 */
2954 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002955execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956{
2957 char_u *cmd = NULL;
2958 list_T *list = NULL;
2959 int save_msg_silent = msg_silent;
2960 int save_emsg_silent = emsg_silent;
2961 int save_emsg_noredir = emsg_noredir;
2962 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002963 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002964 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002965 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002966 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002967
2968 rettv->vval.v_string = NULL;
2969 rettv->v_type = VAR_STRING;
2970
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002971 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002973 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002974 if (list == NULL || list->lv_first == NULL)
2975 /* empty list, no commands, empty output */
2976 return;
2977 ++list->lv_refcount;
2978 }
2979 else
2980 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002981 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002982 if (cmd == NULL)
2983 return;
2984 }
2985
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002986 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 {
2988 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002989 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002990
2991 if (s == NULL)
2992 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002993 if (*s == NUL)
2994 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002995 if (STRNCMP(s, "silent", 6) == 0)
2996 ++msg_silent;
2997 if (STRCMP(s, "silent!") == 0)
2998 {
2999 emsg_silent = TRUE;
3000 emsg_noredir = TRUE;
3001 }
3002 }
3003 else
3004 ++msg_silent;
3005
3006 if (redir_execute)
3007 save_ga = redir_execute_ga;
3008 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3009 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003010 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003011 if (!echo_output)
3012 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003013
3014 if (cmd != NULL)
3015 do_cmdline_cmd(cmd);
3016 else
3017 {
3018 listitem_T *item = list->lv_first;
3019
3020 do_cmdline(NULL, get_list_line, (void *)&item,
3021 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3022 --list->lv_refcount;
3023 }
3024
Bram Moolenaard297f352017-01-29 20:31:21 +01003025 /* Need to append a NUL to the result. */
3026 if (ga_grow(&redir_execute_ga, 1) == OK)
3027 {
3028 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3029 rettv->vval.v_string = redir_execute_ga.ga_data;
3030 }
3031 else
3032 {
3033 ga_clear(&redir_execute_ga);
3034 rettv->vval.v_string = NULL;
3035 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 msg_silent = save_msg_silent;
3037 emsg_silent = save_emsg_silent;
3038 emsg_noredir = save_emsg_noredir;
3039
3040 redir_execute = save_redir_execute;
3041 if (redir_execute)
3042 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003043 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003044
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003045 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003046 if (echo_output)
3047 // When not working silently: put it in column zero. A following
3048 // "echon" will overwrite the message, unavoidably.
3049 msg_col = 0;
3050 else
3051 // When working silently: Put it back where it was, since nothing
3052 // should have been written.
3053 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054}
3055
3056/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003057 * "execute()" function
3058 */
3059 static void
3060f_execute(typval_T *argvars, typval_T *rettv)
3061{
3062 execute_common(argvars, rettv, 0);
3063}
3064
3065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 * "exepath()" function
3067 */
3068 static void
3069f_exepath(typval_T *argvars, typval_T *rettv)
3070{
3071 char_u *p = NULL;
3072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003073 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003074 rettv->v_type = VAR_STRING;
3075 rettv->vval.v_string = p;
3076}
3077
3078/*
3079 * "exists()" function
3080 */
3081 static void
3082f_exists(typval_T *argvars, typval_T *rettv)
3083{
3084 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003085 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003087 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088 if (*p == '$') /* environment variable */
3089 {
3090 /* first try "normal" environment variables (fast) */
3091 if (mch_getenv(p + 1) != NULL)
3092 n = TRUE;
3093 else
3094 {
3095 /* try expanding things like $VIM and ${HOME} */
3096 p = expand_env_save(p);
3097 if (p != NULL && *p != '$')
3098 n = TRUE;
3099 vim_free(p);
3100 }
3101 }
3102 else if (*p == '&' || *p == '+') /* option */
3103 {
3104 n = (get_option_tv(&p, NULL, TRUE) == OK);
3105 if (*skipwhite(p) != NUL)
3106 n = FALSE; /* trailing garbage */
3107 }
3108 else if (*p == '*') /* internal or user defined function */
3109 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003110 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003111 }
3112 else if (*p == ':')
3113 {
3114 n = cmd_exists(p + 1);
3115 }
3116 else if (*p == '#')
3117 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003118 if (p[1] == '#')
3119 n = autocmd_supported(p + 2);
3120 else
3121 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 }
3123 else /* internal variable */
3124 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003125 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126 }
3127
3128 rettv->vval.v_number = n;
3129}
3130
3131#ifdef FEAT_FLOAT
3132/*
3133 * "exp()" function
3134 */
3135 static void
3136f_exp(typval_T *argvars, typval_T *rettv)
3137{
3138 float_T f = 0.0;
3139
3140 rettv->v_type = VAR_FLOAT;
3141 if (get_float_arg(argvars, &f) == OK)
3142 rettv->vval.v_float = exp(f);
3143 else
3144 rettv->vval.v_float = 0.0;
3145}
3146#endif
3147
3148/*
3149 * "expand()" function
3150 */
3151 static void
3152f_expand(typval_T *argvars, typval_T *rettv)
3153{
3154 char_u *s;
3155 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003156 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3158 expand_T xpc;
3159 int error = FALSE;
3160 char_u *result;
3161
3162 rettv->v_type = VAR_STRING;
3163 if (argvars[1].v_type != VAR_UNKNOWN
3164 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003165 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003166 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003167 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003168
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003169 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003170 if (*s == '%' || *s == '#' || *s == '<')
3171 {
3172 ++emsg_off;
3173 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3174 --emsg_off;
3175 if (rettv->v_type == VAR_LIST)
3176 {
3177 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3178 list_append_string(rettv->vval.v_list, result, -1);
3179 else
3180 vim_free(result);
3181 }
3182 else
3183 rettv->vval.v_string = result;
3184 }
3185 else
3186 {
3187 /* When the optional second argument is non-zero, don't remove matches
3188 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3189 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003190 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003191 options |= WILD_KEEP_ALL;
3192 if (!error)
3193 {
3194 ExpandInit(&xpc);
3195 xpc.xp_context = EXPAND_FILES;
3196 if (p_wic)
3197 options += WILD_ICASE;
3198 if (rettv->v_type == VAR_STRING)
3199 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3200 options, WILD_ALL);
3201 else if (rettv_list_alloc(rettv) != FAIL)
3202 {
3203 int i;
3204
3205 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3206 for (i = 0; i < xpc.xp_numfiles; i++)
3207 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3208 ExpandCleanup(&xpc);
3209 }
3210 }
3211 else
3212 rettv->vval.v_string = NULL;
3213 }
3214}
3215
3216/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003217 * "expandcmd()" function
3218 * Expand all the special characters in a command string.
3219 */
3220 static void
3221f_expandcmd(typval_T *argvars, typval_T *rettv)
3222{
3223 exarg_T eap;
3224 char_u *cmdstr;
3225 char *errormsg = NULL;
3226
3227 rettv->v_type = VAR_STRING;
3228 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3229
3230 memset(&eap, 0, sizeof(eap));
3231 eap.cmd = cmdstr;
3232 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003233 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003234 eap.usefilter = FALSE;
3235 eap.nextcmd = NULL;
3236 eap.cmdidx = CMD_USER;
3237
3238 expand_filename(&eap, &cmdstr, &errormsg);
3239 if (errormsg != NULL && *errormsg != NUL)
3240 emsg(errormsg);
3241
3242 rettv->vval.v_string = cmdstr;
3243}
3244
3245/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246 * "extend(list, list [, idx])" function
3247 * "extend(dict, dict [, action])" function
3248 */
3249 static void
3250f_extend(typval_T *argvars, typval_T *rettv)
3251{
3252 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3253
3254 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3255 {
3256 list_T *l1, *l2;
3257 listitem_T *item;
3258 long before;
3259 int error = FALSE;
3260
3261 l1 = argvars[0].vval.v_list;
3262 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003263 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264 && l2 != NULL)
3265 {
3266 if (argvars[2].v_type != VAR_UNKNOWN)
3267 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003268 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 if (error)
3270 return; /* type error; errmsg already given */
3271
3272 if (before == l1->lv_len)
3273 item = NULL;
3274 else
3275 {
3276 item = list_find(l1, before);
3277 if (item == NULL)
3278 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003279 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280 return;
3281 }
3282 }
3283 }
3284 else
3285 item = NULL;
3286 list_extend(l1, l2, item);
3287
3288 copy_tv(&argvars[0], rettv);
3289 }
3290 }
3291 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3292 {
3293 dict_T *d1, *d2;
3294 char_u *action;
3295 int i;
3296
3297 d1 = argvars[0].vval.v_dict;
3298 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003299 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003300 && d2 != NULL)
3301 {
3302 /* Check the third argument. */
3303 if (argvars[2].v_type != VAR_UNKNOWN)
3304 {
3305 static char *(av[]) = {"keep", "force", "error"};
3306
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003307 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 if (action == NULL)
3309 return; /* type error; errmsg already given */
3310 for (i = 0; i < 3; ++i)
3311 if (STRCMP(action, av[i]) == 0)
3312 break;
3313 if (i == 3)
3314 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003315 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316 return;
3317 }
3318 }
3319 else
3320 action = (char_u *)"force";
3321
3322 dict_extend(d1, d2, action);
3323
3324 copy_tv(&argvars[0], rettv);
3325 }
3326 }
3327 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003328 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329}
3330
3331/*
3332 * "feedkeys()" function
3333 */
3334 static void
3335f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3336{
3337 int remap = TRUE;
3338 int insert = FALSE;
3339 char_u *keys, *flags;
3340 char_u nbuf[NUMBUFLEN];
3341 int typed = FALSE;
3342 int execute = FALSE;
3343 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003344 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003345 char_u *keys_esc;
3346
3347 /* This is not allowed in the sandbox. If the commands would still be
3348 * executed in the sandbox it would be OK, but it probably happens later,
3349 * when "sandbox" is no longer set. */
3350 if (check_secure())
3351 return;
3352
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003353 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003354
3355 if (argvars[1].v_type != VAR_UNKNOWN)
3356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003357 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003358 for ( ; *flags != NUL; ++flags)
3359 {
3360 switch (*flags)
3361 {
3362 case 'n': remap = FALSE; break;
3363 case 'm': remap = TRUE; break;
3364 case 't': typed = TRUE; break;
3365 case 'i': insert = TRUE; break;
3366 case 'x': execute = TRUE; break;
3367 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003368 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369 }
3370 }
3371 }
3372
3373 if (*keys != NUL || execute)
3374 {
3375 /* Need to escape K_SPECIAL and CSI before putting the string in the
3376 * typeahead buffer. */
3377 keys_esc = vim_strsave_escape_csi(keys);
3378 if (keys_esc != NULL)
3379 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003380 if (lowlevel)
3381 {
3382#ifdef USE_INPUT_BUF
3383 add_to_input_buf(keys, (int)STRLEN(keys));
3384#else
3385 emsg(_("E980: lowlevel input not supported"));
3386#endif
3387 }
3388 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003389 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003390 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003392 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003393#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003394 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003395#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003396 )
3397 typebuf_was_filled = TRUE;
3398 }
3399 vim_free(keys_esc);
3400
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401 if (execute)
3402 {
3403 int save_msg_scroll = msg_scroll;
3404
3405 /* Avoid a 1 second delay when the keys start Insert mode. */
3406 msg_scroll = FALSE;
3407
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003408 if (!dangerous)
3409 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003410 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003411 if (!dangerous)
3412 --ex_normal_busy;
3413
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414 msg_scroll |= save_msg_scroll;
3415 }
3416 }
3417 }
3418}
3419
3420/*
3421 * "filereadable()" function
3422 */
3423 static void
3424f_filereadable(typval_T *argvars, typval_T *rettv)
3425{
3426 int fd;
3427 char_u *p;
3428 int n;
3429
3430#ifndef O_NONBLOCK
3431# define O_NONBLOCK 0
3432#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003433 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3435 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3436 {
3437 n = TRUE;
3438 close(fd);
3439 }
3440 else
3441 n = FALSE;
3442
3443 rettv->vval.v_number = n;
3444}
3445
3446/*
3447 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3448 * rights to write into.
3449 */
3450 static void
3451f_filewritable(typval_T *argvars, typval_T *rettv)
3452{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003453 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003454}
3455
3456 static void
3457findfilendir(
3458 typval_T *argvars UNUSED,
3459 typval_T *rettv,
3460 int find_what UNUSED)
3461{
3462#ifdef FEAT_SEARCHPATH
3463 char_u *fname;
3464 char_u *fresult = NULL;
3465 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3466 char_u *p;
3467 char_u pathbuf[NUMBUFLEN];
3468 int count = 1;
3469 int first = TRUE;
3470 int error = FALSE;
3471#endif
3472
3473 rettv->vval.v_string = NULL;
3474 rettv->v_type = VAR_STRING;
3475
3476#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003477 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478
3479 if (argvars[1].v_type != VAR_UNKNOWN)
3480 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003481 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482 if (p == NULL)
3483 error = TRUE;
3484 else
3485 {
3486 if (*p != NUL)
3487 path = p;
3488
3489 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003490 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003491 }
3492 }
3493
3494 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3495 error = TRUE;
3496
3497 if (*fname != NUL && !error)
3498 {
3499 do
3500 {
3501 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3502 vim_free(fresult);
3503 fresult = find_file_in_path_option(first ? fname : NULL,
3504 first ? (int)STRLEN(fname) : 0,
3505 0, first, path,
3506 find_what,
3507 curbuf->b_ffname,
3508 find_what == FINDFILE_DIR
3509 ? (char_u *)"" : curbuf->b_p_sua);
3510 first = FALSE;
3511
3512 if (fresult != NULL && rettv->v_type == VAR_LIST)
3513 list_append_string(rettv->vval.v_list, fresult, -1);
3514
3515 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3516 }
3517
3518 if (rettv->v_type == VAR_STRING)
3519 rettv->vval.v_string = fresult;
3520#endif
3521}
3522
3523/*
3524 * "filter()" function
3525 */
3526 static void
3527f_filter(typval_T *argvars, typval_T *rettv)
3528{
3529 filter_map(argvars, rettv, FALSE);
3530}
3531
3532/*
3533 * "finddir({fname}[, {path}[, {count}]])" function
3534 */
3535 static void
3536f_finddir(typval_T *argvars, typval_T *rettv)
3537{
3538 findfilendir(argvars, rettv, FINDFILE_DIR);
3539}
3540
3541/*
3542 * "findfile({fname}[, {path}[, {count}]])" function
3543 */
3544 static void
3545f_findfile(typval_T *argvars, typval_T *rettv)
3546{
3547 findfilendir(argvars, rettv, FINDFILE_FILE);
3548}
3549
3550#ifdef FEAT_FLOAT
3551/*
3552 * "float2nr({float})" function
3553 */
3554 static void
3555f_float2nr(typval_T *argvars, typval_T *rettv)
3556{
3557 float_T f = 0.0;
3558
3559 if (get_float_arg(argvars, &f) == OK)
3560 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003561 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003562 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003563 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003564 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565 else
3566 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567 }
3568}
3569
3570/*
3571 * "floor({float})" function
3572 */
3573 static void
3574f_floor(typval_T *argvars, typval_T *rettv)
3575{
3576 float_T f = 0.0;
3577
3578 rettv->v_type = VAR_FLOAT;
3579 if (get_float_arg(argvars, &f) == OK)
3580 rettv->vval.v_float = floor(f);
3581 else
3582 rettv->vval.v_float = 0.0;
3583}
3584
3585/*
3586 * "fmod()" function
3587 */
3588 static void
3589f_fmod(typval_T *argvars, typval_T *rettv)
3590{
3591 float_T fx = 0.0, fy = 0.0;
3592
3593 rettv->v_type = VAR_FLOAT;
3594 if (get_float_arg(argvars, &fx) == OK
3595 && get_float_arg(&argvars[1], &fy) == OK)
3596 rettv->vval.v_float = fmod(fx, fy);
3597 else
3598 rettv->vval.v_float = 0.0;
3599}
3600#endif
3601
3602/*
3603 * "fnameescape({string})" function
3604 */
3605 static void
3606f_fnameescape(typval_T *argvars, typval_T *rettv)
3607{
3608 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003609 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003610 rettv->v_type = VAR_STRING;
3611}
3612
3613/*
3614 * "fnamemodify({fname}, {mods})" function
3615 */
3616 static void
3617f_fnamemodify(typval_T *argvars, typval_T *rettv)
3618{
3619 char_u *fname;
3620 char_u *mods;
3621 int usedlen = 0;
3622 int len;
3623 char_u *fbuf = NULL;
3624 char_u buf[NUMBUFLEN];
3625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003626 fname = tv_get_string_chk(&argvars[0]);
3627 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628 if (fname == NULL || mods == NULL)
3629 fname = NULL;
3630 else
3631 {
3632 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003633 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 }
3635
3636 rettv->v_type = VAR_STRING;
3637 if (fname == NULL)
3638 rettv->vval.v_string = NULL;
3639 else
3640 rettv->vval.v_string = vim_strnsave(fname, len);
3641 vim_free(fbuf);
3642}
3643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644/*
3645 * "foldclosed()" function
3646 */
3647 static void
3648foldclosed_both(
3649 typval_T *argvars UNUSED,
3650 typval_T *rettv,
3651 int end UNUSED)
3652{
3653#ifdef FEAT_FOLDING
3654 linenr_T lnum;
3655 linenr_T first, last;
3656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003657 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3659 {
3660 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3661 {
3662 if (end)
3663 rettv->vval.v_number = (varnumber_T)last;
3664 else
3665 rettv->vval.v_number = (varnumber_T)first;
3666 return;
3667 }
3668 }
3669#endif
3670 rettv->vval.v_number = -1;
3671}
3672
3673/*
3674 * "foldclosed()" function
3675 */
3676 static void
3677f_foldclosed(typval_T *argvars, typval_T *rettv)
3678{
3679 foldclosed_both(argvars, rettv, FALSE);
3680}
3681
3682/*
3683 * "foldclosedend()" function
3684 */
3685 static void
3686f_foldclosedend(typval_T *argvars, typval_T *rettv)
3687{
3688 foldclosed_both(argvars, rettv, TRUE);
3689}
3690
3691/*
3692 * "foldlevel()" function
3693 */
3694 static void
3695f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3696{
3697#ifdef FEAT_FOLDING
3698 linenr_T lnum;
3699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003700 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003701 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3702 rettv->vval.v_number = foldLevel(lnum);
3703#endif
3704}
3705
3706/*
3707 * "foldtext()" function
3708 */
3709 static void
3710f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3711{
3712#ifdef FEAT_FOLDING
3713 linenr_T foldstart;
3714 linenr_T foldend;
3715 char_u *dashes;
3716 linenr_T lnum;
3717 char_u *s;
3718 char_u *r;
3719 int len;
3720 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003721 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722#endif
3723
3724 rettv->v_type = VAR_STRING;
3725 rettv->vval.v_string = NULL;
3726#ifdef FEAT_FOLDING
3727 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3728 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3729 dashes = get_vim_var_str(VV_FOLDDASHES);
3730 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3731 && dashes != NULL)
3732 {
3733 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003734 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735 if (!linewhite(lnum))
3736 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003737
3738 /* Find interesting text in this line. */
3739 s = skipwhite(ml_get(lnum));
3740 /* skip C comment-start */
3741 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3742 {
3743 s = skipwhite(s + 2);
3744 if (*skipwhite(s) == NUL
3745 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3746 {
3747 s = skipwhite(ml_get(lnum + 1));
3748 if (*s == '*')
3749 s = skipwhite(s + 1);
3750 }
3751 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003752 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003753 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003754 r = alloc(STRLEN(txt)
3755 + STRLEN(dashes) // for %s
3756 + 20 // for %3ld
3757 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003758 if (r != NULL)
3759 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003760 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 len = (int)STRLEN(r);
3762 STRCAT(r, s);
3763 /* remove 'foldmarker' and 'commentstring' */
3764 foldtext_cleanup(r + len);
3765 rettv->vval.v_string = r;
3766 }
3767 }
3768#endif
3769}
3770
3771/*
3772 * "foldtextresult(lnum)" function
3773 */
3774 static void
3775f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3776{
3777#ifdef FEAT_FOLDING
3778 linenr_T lnum;
3779 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003780 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 foldinfo_T foldinfo;
3782 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003783 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003784#endif
3785
3786 rettv->v_type = VAR_STRING;
3787 rettv->vval.v_string = NULL;
3788#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003789 if (entered)
3790 return; /* reject recursive use */
3791 entered = TRUE;
3792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003793 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794 /* treat illegal types and illegal string values for {lnum} the same */
3795 if (lnum < 0)
3796 lnum = 0;
3797 fold_count = foldedCount(curwin, lnum, &foldinfo);
3798 if (fold_count > 0)
3799 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003800 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3801 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003802 if (text == buf)
3803 text = vim_strsave(text);
3804 rettv->vval.v_string = text;
3805 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003806
3807 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808#endif
3809}
3810
3811/*
3812 * "foreground()" function
3813 */
3814 static void
3815f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3816{
3817#ifdef FEAT_GUI
3818 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003819 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003821 return;
3822 }
3823#endif
3824#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003825 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826#endif
3827}
3828
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003829 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003830common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831{
3832 char_u *s;
3833 char_u *name;
3834 int use_string = FALSE;
3835 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003836 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837
3838 if (argvars[0].v_type == VAR_FUNC)
3839 {
3840 /* function(MyFunc, [arg], dict) */
3841 s = argvars[0].vval.v_string;
3842 }
3843 else if (argvars[0].v_type == VAR_PARTIAL
3844 && argvars[0].vval.v_partial != NULL)
3845 {
3846 /* function(dict.MyFunc, [arg]) */
3847 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003848 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849 }
3850 else
3851 {
3852 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003853 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854 use_string = TRUE;
3855 }
3856
Bram Moolenaar843b8842016-08-21 14:36:15 +02003857 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003858 {
3859 name = s;
3860 trans_name = trans_function_name(&name, FALSE,
3861 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3862 if (*name != NUL)
3863 s = NULL;
3864 }
3865
Bram Moolenaar843b8842016-08-21 14:36:15 +02003866 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3867 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003868 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003869 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003870 else if (trans_name != NULL && (is_funcref
3871 ? find_func(trans_name) == NULL
3872 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003873 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003874 else
3875 {
3876 int dict_idx = 0;
3877 int arg_idx = 0;
3878 list_T *list = NULL;
3879
3880 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3881 {
3882 char sid_buf[25];
3883 int off = *s == 's' ? 2 : 5;
3884
3885 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3886 * also be called from another script. Using trans_function_name()
3887 * would also work, but some plugins depend on the name being
3888 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003889 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003890 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003891 if (name != NULL)
3892 {
3893 STRCPY(name, sid_buf);
3894 STRCAT(name, s + off);
3895 }
3896 }
3897 else
3898 name = vim_strsave(s);
3899
3900 if (argvars[1].v_type != VAR_UNKNOWN)
3901 {
3902 if (argvars[2].v_type != VAR_UNKNOWN)
3903 {
3904 /* function(name, [args], dict) */
3905 arg_idx = 1;
3906 dict_idx = 2;
3907 }
3908 else if (argvars[1].v_type == VAR_DICT)
3909 /* function(name, dict) */
3910 dict_idx = 1;
3911 else
3912 /* function(name, [args]) */
3913 arg_idx = 1;
3914 if (dict_idx > 0)
3915 {
3916 if (argvars[dict_idx].v_type != VAR_DICT)
3917 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003918 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003919 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003920 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 }
3922 if (argvars[dict_idx].vval.v_dict == NULL)
3923 dict_idx = 0;
3924 }
3925 if (arg_idx > 0)
3926 {
3927 if (argvars[arg_idx].v_type != VAR_LIST)
3928 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003929 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003930 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003931 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 }
3933 list = argvars[arg_idx].vval.v_list;
3934 if (list == NULL || list->lv_len == 0)
3935 arg_idx = 0;
3936 }
3937 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003938 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003940 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941
3942 /* result is a VAR_PARTIAL */
3943 if (pt == NULL)
3944 vim_free(name);
3945 else
3946 {
3947 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3948 {
3949 listitem_T *li;
3950 int i = 0;
3951 int arg_len = 0;
3952 int lv_len = 0;
3953
3954 if (arg_pt != NULL)
3955 arg_len = arg_pt->pt_argc;
3956 if (list != NULL)
3957 lv_len = list->lv_len;
3958 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003959 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 if (pt->pt_argv == NULL)
3961 {
3962 vim_free(pt);
3963 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003964 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003966 for (i = 0; i < arg_len; i++)
3967 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3968 if (lv_len > 0)
3969 for (li = list->lv_first; li != NULL;
3970 li = li->li_next)
3971 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972 }
3973
3974 /* For "function(dict.func, [], dict)" and "func" is a partial
3975 * use "dict". That is backwards compatible. */
3976 if (dict_idx > 0)
3977 {
3978 /* The dict is bound explicitly, pt_auto is FALSE. */
3979 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3980 ++pt->pt_dict->dv_refcount;
3981 }
3982 else if (arg_pt != NULL)
3983 {
3984 /* If the dict was bound automatically the result is also
3985 * bound automatically. */
3986 pt->pt_dict = arg_pt->pt_dict;
3987 pt->pt_auto = arg_pt->pt_auto;
3988 if (pt->pt_dict != NULL)
3989 ++pt->pt_dict->dv_refcount;
3990 }
3991
3992 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003993 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3994 {
3995 pt->pt_func = arg_pt->pt_func;
3996 func_ptr_ref(pt->pt_func);
3997 vim_free(name);
3998 }
3999 else if (is_funcref)
4000 {
4001 pt->pt_func = find_func(trans_name);
4002 func_ptr_ref(pt->pt_func);
4003 vim_free(name);
4004 }
4005 else
4006 {
4007 pt->pt_name = name;
4008 func_ref(name);
4009 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010 }
4011 rettv->v_type = VAR_PARTIAL;
4012 rettv->vval.v_partial = pt;
4013 }
4014 else
4015 {
4016 /* result is a VAR_FUNC */
4017 rettv->v_type = VAR_FUNC;
4018 rettv->vval.v_string = name;
4019 func_ref(name);
4020 }
4021 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004022theend:
4023 vim_free(trans_name);
4024}
4025
4026/*
4027 * "funcref()" function
4028 */
4029 static void
4030f_funcref(typval_T *argvars, typval_T *rettv)
4031{
4032 common_function(argvars, rettv, TRUE);
4033}
4034
4035/*
4036 * "function()" function
4037 */
4038 static void
4039f_function(typval_T *argvars, typval_T *rettv)
4040{
4041 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004042}
4043
4044/*
4045 * "garbagecollect()" function
4046 */
4047 static void
4048f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4049{
4050 /* This is postponed until we are back at the toplevel, because we may be
4051 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4052 want_garbage_collect = TRUE;
4053
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004054 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055 garbage_collect_at_exit = TRUE;
4056}
4057
4058/*
4059 * "get()" function
4060 */
4061 static void
4062f_get(typval_T *argvars, typval_T *rettv)
4063{
4064 listitem_T *li;
4065 list_T *l;
4066 dictitem_T *di;
4067 dict_T *d;
4068 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004069 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004071 if (argvars[0].v_type == VAR_BLOB)
4072 {
4073 int error = FALSE;
4074 int idx = tv_get_number_chk(&argvars[1], &error);
4075
4076 if (!error)
4077 {
4078 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004079 if (idx < 0)
4080 idx = blob_len(argvars[0].vval.v_blob) + idx;
4081 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4082 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004083 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004084 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004085 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004086 tv = rettv;
4087 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004088 }
4089 }
4090 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 {
4092 if ((l = argvars[0].vval.v_list) != NULL)
4093 {
4094 int error = FALSE;
4095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004096 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004097 if (!error && li != NULL)
4098 tv = &li->li_tv;
4099 }
4100 }
4101 else if (argvars[0].v_type == VAR_DICT)
4102 {
4103 if ((d = argvars[0].vval.v_dict) != NULL)
4104 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004105 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004106 if (di != NULL)
4107 tv = &di->di_tv;
4108 }
4109 }
4110 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4111 {
4112 partial_T *pt;
4113 partial_T fref_pt;
4114
4115 if (argvars[0].v_type == VAR_PARTIAL)
4116 pt = argvars[0].vval.v_partial;
4117 else
4118 {
4119 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4120 fref_pt.pt_name = argvars[0].vval.v_string;
4121 pt = &fref_pt;
4122 }
4123
4124 if (pt != NULL)
4125 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004126 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004127 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004128
4129 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4130 {
4131 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004132 n = partial_name(pt);
4133 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134 rettv->vval.v_string = NULL;
4135 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004136 {
4137 rettv->vval.v_string = vim_strsave(n);
4138 if (rettv->v_type == VAR_FUNC)
4139 func_ref(rettv->vval.v_string);
4140 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 }
4142 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004143 {
4144 what_is_dict = TRUE;
4145 if (pt->pt_dict != NULL)
4146 rettv_dict_set(rettv, pt->pt_dict);
4147 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 else if (STRCMP(what, "args") == 0)
4149 {
4150 rettv->v_type = VAR_LIST;
4151 if (rettv_list_alloc(rettv) == OK)
4152 {
4153 int i;
4154
4155 for (i = 0; i < pt->pt_argc; ++i)
4156 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4157 }
4158 }
4159 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004160 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004161
4162 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4163 // third argument
4164 if (!what_is_dict)
4165 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004166 }
4167 }
4168 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004169 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170
4171 if (tv == NULL)
4172 {
4173 if (argvars[2].v_type != VAR_UNKNOWN)
4174 copy_tv(&argvars[2], rettv);
4175 }
4176 else
4177 copy_tv(tv, rettv);
4178}
4179
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004180/*
4181 * Returns buffer options, variables and other attributes in a dictionary.
4182 */
4183 static dict_T *
4184get_buffer_info(buf_T *buf)
4185{
4186 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004187 tabpage_T *tp;
4188 win_T *wp;
4189 list_T *windows;
4190
4191 dict = dict_alloc();
4192 if (dict == NULL)
4193 return NULL;
4194
Bram Moolenaare0be1672018-07-08 16:50:37 +02004195 dict_add_number(dict, "bufnr", buf->b_fnum);
4196 dict_add_string(dict, "name", buf->b_ffname);
4197 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4198 : buflist_findlnum(buf));
4199 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4200 dict_add_number(dict, "listed", buf->b_p_bl);
4201 dict_add_number(dict, "changed", bufIsChanged(buf));
4202 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4203 dict_add_number(dict, "hidden",
4204 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004205
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004206 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004207 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004208
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004209 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004210 windows = list_alloc();
4211 if (windows != NULL)
4212 {
4213 FOR_ALL_TAB_WINDOWS(tp, wp)
4214 if (wp->w_buffer == buf)
4215 list_append_number(windows, (varnumber_T)wp->w_id);
4216 dict_add_list(dict, "windows", windows);
4217 }
4218
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004219#ifdef FEAT_TEXT_PROP
4220 // List of popup windows displaying this buffer
4221 windows = list_alloc();
4222 if (windows != NULL)
4223 {
4224 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4225 if (wp->w_buffer == buf)
4226 list_append_number(windows, (varnumber_T)wp->w_id);
4227 FOR_ALL_TABPAGES(tp)
4228 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4229 if (wp->w_buffer == buf)
4230 list_append_number(windows, (varnumber_T)wp->w_id);
4231
4232 dict_add_list(dict, "popups", windows);
4233 }
4234#endif
4235
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004236#ifdef FEAT_SIGNS
4237 if (buf->b_signlist != NULL)
4238 {
4239 /* List of signs placed in this buffer */
4240 list_T *signs = list_alloc();
4241 if (signs != NULL)
4242 {
4243 get_buffer_signs(buf, signs);
4244 dict_add_list(dict, "signs", signs);
4245 }
4246 }
4247#endif
4248
4249 return dict;
4250}
4251
4252/*
4253 * "getbufinfo()" function
4254 */
4255 static void
4256f_getbufinfo(typval_T *argvars, typval_T *rettv)
4257{
4258 buf_T *buf = NULL;
4259 buf_T *argbuf = NULL;
4260 dict_T *d;
4261 int filtered = FALSE;
4262 int sel_buflisted = FALSE;
4263 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004264 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004265
4266 if (rettv_list_alloc(rettv) != OK)
4267 return;
4268
4269 /* List of all the buffers or selected buffers */
4270 if (argvars[0].v_type == VAR_DICT)
4271 {
4272 dict_T *sel_d = argvars[0].vval.v_dict;
4273
4274 if (sel_d != NULL)
4275 {
4276 dictitem_T *di;
4277
4278 filtered = TRUE;
4279
4280 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004281 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004282 sel_buflisted = TRUE;
4283
4284 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004285 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004286 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004287
4288 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004289 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004290 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004291 }
4292 }
4293 else if (argvars[0].v_type != VAR_UNKNOWN)
4294 {
4295 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004296 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004297 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004298 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 --emsg_off;
4300 if (argbuf == NULL)
4301 return;
4302 }
4303
4304 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004305 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004306 {
4307 if (argbuf != NULL && argbuf != buf)
4308 continue;
4309 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004310 || (sel_buflisted && !buf->b_p_bl)
4311 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004312 continue;
4313
4314 d = get_buffer_info(buf);
4315 if (d != NULL)
4316 list_append_dict(rettv->vval.v_list, d);
4317 if (argbuf != NULL)
4318 return;
4319 }
4320}
4321
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004322/*
4323 * Get line or list of lines from buffer "buf" into "rettv".
4324 * Return a range (from start to end) of lines in rettv from the specified
4325 * buffer.
4326 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4327 */
4328 static void
4329get_buffer_lines(
4330 buf_T *buf,
4331 linenr_T start,
4332 linenr_T end,
4333 int retlist,
4334 typval_T *rettv)
4335{
4336 char_u *p;
4337
4338 rettv->v_type = VAR_STRING;
4339 rettv->vval.v_string = NULL;
4340 if (retlist && rettv_list_alloc(rettv) == FAIL)
4341 return;
4342
4343 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4344 return;
4345
4346 if (!retlist)
4347 {
4348 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4349 p = ml_get_buf(buf, start, FALSE);
4350 else
4351 p = (char_u *)"";
4352 rettv->vval.v_string = vim_strsave(p);
4353 }
4354 else
4355 {
4356 if (end < start)
4357 return;
4358
4359 if (start < 1)
4360 start = 1;
4361 if (end > buf->b_ml.ml_line_count)
4362 end = buf->b_ml.ml_line_count;
4363 while (start <= end)
4364 if (list_append_string(rettv->vval.v_list,
4365 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4366 break;
4367 }
4368}
4369
4370/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371 * "getbufline()" function
4372 */
4373 static void
4374f_getbufline(typval_T *argvars, typval_T *rettv)
4375{
4376 linenr_T lnum;
4377 linenr_T end;
4378 buf_T *buf;
4379
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004380 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004381 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004382 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004383 --emsg_off;
4384
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004385 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 if (argvars[2].v_type == VAR_UNKNOWN)
4387 end = lnum;
4388 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004389 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390
4391 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4392}
4393
4394/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004395 * "getchangelist()" function
4396 */
4397 static void
4398f_getchangelist(typval_T *argvars, typval_T *rettv)
4399{
4400#ifdef FEAT_JUMPLIST
4401 buf_T *buf;
4402 int i;
4403 list_T *l;
4404 dict_T *d;
4405#endif
4406
4407 if (rettv_list_alloc(rettv) != OK)
4408 return;
4409
4410#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02004411 if (argvars[0].v_type == VAR_UNKNOWN)
4412 buf = curbuf;
4413 else
4414 {
4415 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
4416 ++emsg_off;
4417 buf = tv_get_buf(&argvars[0], FALSE);
4418 --emsg_off;
4419 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004420 if (buf == NULL)
4421 return;
4422
4423 l = list_alloc();
4424 if (l == NULL)
4425 return;
4426
4427 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4428 return;
4429 /*
4430 * The current window change list index tracks only the position in the
4431 * current buffer change list. For other buffers, use the change list
4432 * length as the current index.
4433 */
4434 list_append_number(rettv->vval.v_list,
4435 (varnumber_T)((buf == curwin->w_buffer)
4436 ? curwin->w_changelistidx : buf->b_changelistlen));
4437
4438 for (i = 0; i < buf->b_changelistlen; ++i)
4439 {
4440 if (buf->b_changelist[i].lnum == 0)
4441 continue;
4442 if ((d = dict_alloc()) == NULL)
4443 return;
4444 if (list_append_dict(l, d) == FAIL)
4445 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004446 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4447 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004448 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004449 }
4450#endif
4451}
4452/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453 * "getchar()" function
4454 */
4455 static void
4456f_getchar(typval_T *argvars, typval_T *rettv)
4457{
4458 varnumber_T n;
4459 int error = FALSE;
4460
Bram Moolenaar84d93902018-09-11 20:10:20 +02004461#ifdef MESSAGE_QUEUE
4462 // vpeekc() used to check for messages, but that caused problems, invoking
4463 // a callback where it was not expected. Some plugins use getchar(1) in a
4464 // loop to await a message, therefore make sure we check for messages here.
4465 parse_queued_messages();
4466#endif
4467
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468 /* Position the cursor. Needed after a message that ends in a space. */
4469 windgoto(msg_row, msg_col);
4470
4471 ++no_mapping;
4472 ++allow_keys;
4473 for (;;)
4474 {
4475 if (argvars[0].v_type == VAR_UNKNOWN)
4476 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004477 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004478 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479 /* getchar(1): only check if char avail */
4480 n = vpeekc_any();
4481 else if (error || vpeekc_any() == NUL)
4482 /* illegal argument or getchar(0) and no char avail: return zero */
4483 n = 0;
4484 else
4485 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004486 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487
4488 if (n == K_IGNORE)
4489 continue;
4490 break;
4491 }
4492 --no_mapping;
4493 --allow_keys;
4494
4495 set_vim_var_nr(VV_MOUSE_WIN, 0);
4496 set_vim_var_nr(VV_MOUSE_WINID, 0);
4497 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4498 set_vim_var_nr(VV_MOUSE_COL, 0);
4499
4500 rettv->vval.v_number = n;
4501 if (IS_SPECIAL(n) || mod_mask != 0)
4502 {
4503 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4504 int i = 0;
4505
4506 /* Turn a special key into three bytes, plus modifier. */
4507 if (mod_mask != 0)
4508 {
4509 temp[i++] = K_SPECIAL;
4510 temp[i++] = KS_MODIFIER;
4511 temp[i++] = mod_mask;
4512 }
4513 if (IS_SPECIAL(n))
4514 {
4515 temp[i++] = K_SPECIAL;
4516 temp[i++] = K_SECOND(n);
4517 temp[i++] = K_THIRD(n);
4518 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 else if (has_mbyte)
4520 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521 else
4522 temp[i++] = n;
4523 temp[i++] = NUL;
4524 rettv->v_type = VAR_STRING;
4525 rettv->vval.v_string = vim_strsave(temp);
4526
4527#ifdef FEAT_MOUSE
4528 if (is_mouse_key(n))
4529 {
4530 int row = mouse_row;
4531 int col = mouse_col;
4532 win_T *win;
4533 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535 int winnr = 1;
4536
4537 if (row >= 0 && col >= 0)
4538 {
4539 /* Find the window at the mouse coordinates and compute the
4540 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004541 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004542 if (win == NULL)
4543 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004544 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004545# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004546 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004547 winnr = 0;
4548 else
4549# endif
4550 for (wp = firstwin; wp != win && wp != NULL;
4551 wp = wp->w_next)
4552 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4554 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4555 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4556 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4557 }
4558 }
4559#endif
4560 }
4561}
4562
4563/*
4564 * "getcharmod()" function
4565 */
4566 static void
4567f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4568{
4569 rettv->vval.v_number = mod_mask;
4570}
4571
4572/*
4573 * "getcharsearch()" function
4574 */
4575 static void
4576f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4577{
4578 if (rettv_dict_alloc(rettv) != FAIL)
4579 {
4580 dict_T *dict = rettv->vval.v_dict;
4581
Bram Moolenaare0be1672018-07-08 16:50:37 +02004582 dict_add_string(dict, "char", last_csearch());
4583 dict_add_number(dict, "forward", last_csearch_forward());
4584 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004585 }
4586}
4587
4588/*
4589 * "getcmdline()" function
4590 */
4591 static void
4592f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4593{
4594 rettv->v_type = VAR_STRING;
4595 rettv->vval.v_string = get_cmdline_str();
4596}
4597
4598/*
4599 * "getcmdpos()" function
4600 */
4601 static void
4602f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4603{
4604 rettv->vval.v_number = get_cmdline_pos() + 1;
4605}
4606
4607/*
4608 * "getcmdtype()" function
4609 */
4610 static void
4611f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4612{
4613 rettv->v_type = VAR_STRING;
4614 rettv->vval.v_string = alloc(2);
4615 if (rettv->vval.v_string != NULL)
4616 {
4617 rettv->vval.v_string[0] = get_cmdline_type();
4618 rettv->vval.v_string[1] = NUL;
4619 }
4620}
4621
4622/*
4623 * "getcmdwintype()" function
4624 */
4625 static void
4626f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4627{
4628 rettv->v_type = VAR_STRING;
4629 rettv->vval.v_string = NULL;
4630#ifdef FEAT_CMDWIN
4631 rettv->vval.v_string = alloc(2);
4632 if (rettv->vval.v_string != NULL)
4633 {
4634 rettv->vval.v_string[0] = cmdwin_type;
4635 rettv->vval.v_string[1] = NUL;
4636 }
4637#endif
4638}
4639
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640/*
4641 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004642 *
4643 * Return the current working directory of a window in a tab page.
4644 * First optional argument 'winnr' is the window number or -1 and the second
4645 * optional argument 'tabnr' is the tab page number.
4646 *
4647 * If no arguments are supplied, then return the directory of the current
4648 * window.
4649 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4650 * the specified window.
4651 * If 'winnr' is 0 then return the directory of the current window.
4652 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4653 * directory of the specified tab page. Otherwise return the directory of the
4654 * specified window in the specified tab page.
4655 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656 */
4657 static void
4658f_getcwd(typval_T *argvars, typval_T *rettv)
4659{
4660 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004661 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004662 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004663 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664
4665 rettv->v_type = VAR_STRING;
4666 rettv->vval.v_string = NULL;
4667
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004668 if (argvars[0].v_type == VAR_NUMBER
4669 && argvars[0].vval.v_number == -1
4670 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004671 global = TRUE;
4672 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004673 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004674
4675 if (wp != NULL && wp->w_localdir != NULL)
4676 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004677 else if (tp != NULL && tp->tp_localdir != NULL)
4678 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4679 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004681 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004682 rettv->vval.v_string = vim_strsave(globaldir);
4683 else
4684 {
4685 cwd = alloc(MAXPATHL);
4686 if (cwd != NULL)
4687 {
4688 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4689 rettv->vval.v_string = vim_strsave(cwd);
4690 vim_free(cwd);
4691 }
4692 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004694#ifdef BACKSLASH_IN_FILENAME
4695 if (rettv->vval.v_string != NULL)
4696 slash_adjust(rettv->vval.v_string);
4697#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004698}
4699
4700/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004701 * "getenv()" function
4702 */
4703 static void
4704f_getenv(typval_T *argvars, typval_T *rettv)
4705{
4706 int mustfree = FALSE;
4707 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4708
4709 if (p == NULL)
4710 {
4711 rettv->v_type = VAR_SPECIAL;
4712 rettv->vval.v_number = VVAL_NULL;
4713 return;
4714 }
4715 if (!mustfree)
4716 p = vim_strsave(p);
4717 rettv->vval.v_string = p;
4718 rettv->v_type = VAR_STRING;
4719}
4720
4721/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004722 * "getfontname()" function
4723 */
4724 static void
4725f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4726{
4727 rettv->v_type = VAR_STRING;
4728 rettv->vval.v_string = NULL;
4729#ifdef FEAT_GUI
4730 if (gui.in_use)
4731 {
4732 GuiFont font;
4733 char_u *name = NULL;
4734
4735 if (argvars[0].v_type == VAR_UNKNOWN)
4736 {
4737 /* Get the "Normal" font. Either the name saved by
4738 * hl_set_font_name() or from the font ID. */
4739 font = gui.norm_font;
4740 name = hl_get_font_name();
4741 }
4742 else
4743 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004744 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004745 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4746 return;
4747 font = gui_mch_get_font(name, FALSE);
4748 if (font == NOFONT)
4749 return; /* Invalid font name, return empty string. */
4750 }
4751 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4752 if (argvars[0].v_type != VAR_UNKNOWN)
4753 gui_mch_free_font(font);
4754 }
4755#endif
4756}
4757
4758/*
4759 * "getfperm({fname})" function
4760 */
4761 static void
4762f_getfperm(typval_T *argvars, typval_T *rettv)
4763{
4764 char_u *fname;
4765 stat_T st;
4766 char_u *perm = NULL;
4767 char_u flags[] = "rwx";
4768 int i;
4769
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004770 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004771
4772 rettv->v_type = VAR_STRING;
4773 if (mch_stat((char *)fname, &st) >= 0)
4774 {
4775 perm = vim_strsave((char_u *)"---------");
4776 if (perm != NULL)
4777 {
4778 for (i = 0; i < 9; i++)
4779 {
4780 if (st.st_mode & (1 << (8 - i)))
4781 perm[i] = flags[i % 3];
4782 }
4783 }
4784 }
4785 rettv->vval.v_string = perm;
4786}
4787
4788/*
4789 * "getfsize({fname})" function
4790 */
4791 static void
4792f_getfsize(typval_T *argvars, typval_T *rettv)
4793{
4794 char_u *fname;
4795 stat_T st;
4796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004797 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004798
4799 rettv->v_type = VAR_NUMBER;
4800
4801 if (mch_stat((char *)fname, &st) >= 0)
4802 {
4803 if (mch_isdir(fname))
4804 rettv->vval.v_number = 0;
4805 else
4806 {
4807 rettv->vval.v_number = (varnumber_T)st.st_size;
4808
4809 /* non-perfect check for overflow */
4810 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4811 rettv->vval.v_number = -2;
4812 }
4813 }
4814 else
4815 rettv->vval.v_number = -1;
4816}
4817
4818/*
4819 * "getftime({fname})" function
4820 */
4821 static void
4822f_getftime(typval_T *argvars, typval_T *rettv)
4823{
4824 char_u *fname;
4825 stat_T st;
4826
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004827 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828
4829 if (mch_stat((char *)fname, &st) >= 0)
4830 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4831 else
4832 rettv->vval.v_number = -1;
4833}
4834
4835/*
4836 * "getftype({fname})" function
4837 */
4838 static void
4839f_getftype(typval_T *argvars, typval_T *rettv)
4840{
4841 char_u *fname;
4842 stat_T st;
4843 char_u *type = NULL;
4844 char *t;
4845
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004846 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847
4848 rettv->v_type = VAR_STRING;
4849 if (mch_lstat((char *)fname, &st) >= 0)
4850 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851 if (S_ISREG(st.st_mode))
4852 t = "file";
4853 else if (S_ISDIR(st.st_mode))
4854 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004855 else if (S_ISLNK(st.st_mode))
4856 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 else if (S_ISBLK(st.st_mode))
4858 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 else if (S_ISCHR(st.st_mode))
4860 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 else if (S_ISFIFO(st.st_mode))
4862 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004864 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004865 else
4866 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 type = vim_strsave((char_u *)t);
4868 }
4869 rettv->vval.v_string = type;
4870}
4871
4872/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004873 * "getjumplist()" function
4874 */
4875 static void
4876f_getjumplist(typval_T *argvars, typval_T *rettv)
4877{
4878#ifdef FEAT_JUMPLIST
4879 win_T *wp;
4880 int i;
4881 list_T *l;
4882 dict_T *d;
4883#endif
4884
4885 if (rettv_list_alloc(rettv) != OK)
4886 return;
4887
4888#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004889 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004890 if (wp == NULL)
4891 return;
4892
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004893 cleanup_jumplist(wp, TRUE);
4894
Bram Moolenaar4f505882018-02-10 21:06:32 +01004895 l = list_alloc();
4896 if (l == NULL)
4897 return;
4898
4899 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4900 return;
4901 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4902
4903 for (i = 0; i < wp->w_jumplistlen; ++i)
4904 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004905 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4906 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004907 if ((d = dict_alloc()) == NULL)
4908 return;
4909 if (list_append_dict(l, d) == FAIL)
4910 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004911 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4912 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004913 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004914 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004915 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004916 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004917 }
4918#endif
4919}
4920
4921/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 * "getline(lnum, [end])" function
4923 */
4924 static void
4925f_getline(typval_T *argvars, typval_T *rettv)
4926{
4927 linenr_T lnum;
4928 linenr_T end;
4929 int retlist;
4930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004931 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932 if (argvars[1].v_type == VAR_UNKNOWN)
4933 {
4934 end = 0;
4935 retlist = FALSE;
4936 }
4937 else
4938 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004939 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940 retlist = TRUE;
4941 }
4942
4943 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4944}
4945
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004946#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004947 static void
4948get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4949{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004950 if (what_arg->v_type == VAR_UNKNOWN)
4951 {
4952 if (rettv_list_alloc(rettv) == OK)
4953 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004954 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004955 }
4956 else
4957 {
4958 if (rettv_dict_alloc(rettv) == OK)
4959 if (is_qf || (wp != NULL))
4960 {
4961 if (what_arg->v_type == VAR_DICT)
4962 {
4963 dict_T *d = what_arg->vval.v_dict;
4964
4965 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02004966 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004967 }
4968 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004969 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02004970 }
4971 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02004972}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004973#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02004974
4975/*
4976 * "getloclist()" function
4977 */
4978 static void
4979f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4980{
4981#ifdef FEAT_QUICKFIX
4982 win_T *wp;
4983
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02004984 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004985 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4986#endif
4987}
4988
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004989/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004990 * "getpid()" function
4991 */
4992 static void
4993f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4994{
4995 rettv->vval.v_number = mch_get_pid();
4996}
4997
4998 static void
4999getpos_both(
5000 typval_T *argvars,
5001 typval_T *rettv,
5002 int getcurpos)
5003{
5004 pos_T *fp;
5005 list_T *l;
5006 int fnum = -1;
5007
5008 if (rettv_list_alloc(rettv) == OK)
5009 {
5010 l = rettv->vval.v_list;
5011 if (getcurpos)
5012 fp = &curwin->w_cursor;
5013 else
5014 fp = var2fpos(&argvars[0], TRUE, &fnum);
5015 if (fnum != -1)
5016 list_append_number(l, (varnumber_T)fnum);
5017 else
5018 list_append_number(l, (varnumber_T)0);
5019 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5020 : (varnumber_T)0);
5021 list_append_number(l, (fp != NULL)
5022 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5023 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005024 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 (varnumber_T)0);
5026 if (getcurpos)
5027 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005028 int save_set_curswant = curwin->w_set_curswant;
5029 colnr_T save_curswant = curwin->w_curswant;
5030 colnr_T save_virtcol = curwin->w_virtcol;
5031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005032 update_curswant();
5033 list_append_number(l, curwin->w_curswant == MAXCOL ?
5034 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005035
5036 // Do not change "curswant", as it is unexpected that a get
5037 // function has a side effect.
5038 if (save_set_curswant)
5039 {
5040 curwin->w_set_curswant = save_set_curswant;
5041 curwin->w_curswant = save_curswant;
5042 curwin->w_virtcol = save_virtcol;
5043 curwin->w_valid &= ~VALID_VIRTCOL;
5044 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045 }
5046 }
5047 else
5048 rettv->vval.v_number = FALSE;
5049}
5050
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005051/*
5052 * "getcurpos()" function
5053 */
5054 static void
5055f_getcurpos(typval_T *argvars, typval_T *rettv)
5056{
5057 getpos_both(argvars, rettv, TRUE);
5058}
5059
5060/*
5061 * "getpos(string)" function
5062 */
5063 static void
5064f_getpos(typval_T *argvars, typval_T *rettv)
5065{
5066 getpos_both(argvars, rettv, FALSE);
5067}
5068
5069/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005070 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 */
5072 static void
5073f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5074{
5075#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005076 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077#endif
5078}
5079
5080/*
5081 * "getreg()" function
5082 */
5083 static void
5084f_getreg(typval_T *argvars, typval_T *rettv)
5085{
5086 char_u *strregname;
5087 int regname;
5088 int arg2 = FALSE;
5089 int return_list = FALSE;
5090 int error = FALSE;
5091
5092 if (argvars[0].v_type != VAR_UNKNOWN)
5093 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005094 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005095 error = strregname == NULL;
5096 if (argvars[1].v_type != VAR_UNKNOWN)
5097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005098 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005100 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 }
5102 }
5103 else
5104 strregname = get_vim_var_str(VV_REG);
5105
5106 if (error)
5107 return;
5108
5109 regname = (strregname == NULL ? '"' : *strregname);
5110 if (regname == 0)
5111 regname = '"';
5112
5113 if (return_list)
5114 {
5115 rettv->v_type = VAR_LIST;
5116 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5117 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5118 if (rettv->vval.v_list == NULL)
5119 (void)rettv_list_alloc(rettv);
5120 else
5121 ++rettv->vval.v_list->lv_refcount;
5122 }
5123 else
5124 {
5125 rettv->v_type = VAR_STRING;
5126 rettv->vval.v_string = get_reg_contents(regname,
5127 arg2 ? GREG_EXPR_SRC : 0);
5128 }
5129}
5130
5131/*
5132 * "getregtype()" function
5133 */
5134 static void
5135f_getregtype(typval_T *argvars, typval_T *rettv)
5136{
5137 char_u *strregname;
5138 int regname;
5139 char_u buf[NUMBUFLEN + 2];
5140 long reglen = 0;
5141
5142 if (argvars[0].v_type != VAR_UNKNOWN)
5143 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005144 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 if (strregname == NULL) /* type error; errmsg already given */
5146 {
5147 rettv->v_type = VAR_STRING;
5148 rettv->vval.v_string = NULL;
5149 return;
5150 }
5151 }
5152 else
5153 /* Default to v:register */
5154 strregname = get_vim_var_str(VV_REG);
5155
5156 regname = (strregname == NULL ? '"' : *strregname);
5157 if (regname == 0)
5158 regname = '"';
5159
5160 buf[0] = NUL;
5161 buf[1] = NUL;
5162 switch (get_reg_type(regname, &reglen))
5163 {
5164 case MLINE: buf[0] = 'V'; break;
5165 case MCHAR: buf[0] = 'v'; break;
5166 case MBLOCK:
5167 buf[0] = Ctrl_V;
5168 sprintf((char *)buf + 1, "%ld", reglen + 1);
5169 break;
5170 }
5171 rettv->v_type = VAR_STRING;
5172 rettv->vval.v_string = vim_strsave(buf);
5173}
5174
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005175/*
5176 * Returns information (variables, options, etc.) about a tab page
5177 * as a dictionary.
5178 */
5179 static dict_T *
5180get_tabpage_info(tabpage_T *tp, int tp_idx)
5181{
5182 win_T *wp;
5183 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005184 list_T *l;
5185
5186 dict = dict_alloc();
5187 if (dict == NULL)
5188 return NULL;
5189
Bram Moolenaare0be1672018-07-08 16:50:37 +02005190 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005191
5192 l = list_alloc();
5193 if (l != NULL)
5194 {
5195 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005196 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005197 list_append_number(l, (varnumber_T)wp->w_id);
5198 dict_add_list(dict, "windows", l);
5199 }
5200
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005201 /* Make a reference to tabpage variables */
5202 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005203
5204 return dict;
5205}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005206
5207/*
5208 * "gettabinfo()" function
5209 */
5210 static void
5211f_gettabinfo(typval_T *argvars, typval_T *rettv)
5212{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005213 tabpage_T *tp, *tparg = NULL;
5214 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005215 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005216
5217 if (rettv_list_alloc(rettv) != OK)
5218 return;
5219
5220 if (argvars[0].v_type != VAR_UNKNOWN)
5221 {
5222 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005223 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005224 if (tparg == NULL)
5225 return;
5226 }
5227
5228 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005229 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005230 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005231 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005232 if (tparg != NULL && tp != tparg)
5233 continue;
5234 d = get_tabpage_info(tp, tpnr);
5235 if (d != NULL)
5236 list_append_dict(rettv->vval.v_list, d);
5237 if (tparg != NULL)
5238 return;
5239 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005240}
5241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005243 * "gettagstack()" function
5244 */
5245 static void
5246f_gettagstack(typval_T *argvars, typval_T *rettv)
5247{
5248 win_T *wp = curwin; // default is current window
5249
5250 if (rettv_dict_alloc(rettv) != OK)
5251 return;
5252
5253 if (argvars[0].v_type != VAR_UNKNOWN)
5254 {
5255 wp = find_win_by_nr_or_id(&argvars[0]);
5256 if (wp == NULL)
5257 return;
5258 }
5259
5260 get_tagstack(wp, rettv->vval.v_dict);
5261}
5262
5263/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005264 * Returns information about a window as a dictionary.
5265 */
5266 static dict_T *
5267get_win_info(win_T *wp, short tpnr, short winnr)
5268{
5269 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005270
5271 dict = dict_alloc();
5272 if (dict == NULL)
5273 return NULL;
5274
Bram Moolenaare0be1672018-07-08 16:50:37 +02005275 dict_add_number(dict, "tabnr", tpnr);
5276 dict_add_number(dict, "winnr", winnr);
5277 dict_add_number(dict, "winid", wp->w_id);
5278 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005279 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005280 dict_add_number(dict, "topline", wp->w_topline);
5281 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005282#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005283 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005284#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005285 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005286 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005287 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005288
Bram Moolenaar69905d12017-08-13 18:14:47 +02005289#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005290 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005291#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005292#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005293 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5294 dict_add_number(dict, "loclist",
5295 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005296#endif
5297
Bram Moolenaar30567352016-08-27 21:25:44 +02005298 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005299 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005300
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005301 return dict;
5302}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005303
5304/*
5305 * "getwininfo()" function
5306 */
5307 static void
5308f_getwininfo(typval_T *argvars, typval_T *rettv)
5309{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005310 tabpage_T *tp;
5311 win_T *wp = NULL, *wparg = NULL;
5312 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005313 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005314
5315 if (rettv_list_alloc(rettv) != OK)
5316 return;
5317
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005318 if (argvars[0].v_type != VAR_UNKNOWN)
5319 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005320 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005321 if (wparg == NULL)
5322 return;
5323 }
5324
5325 /* Collect information about either all the windows across all the tab
5326 * pages or one particular window.
5327 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005328 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005329 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005330 tabnr++;
5331 winnr = 0;
5332 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005333 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005334 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005335 if (wparg != NULL && wp != wparg)
5336 continue;
5337 d = get_win_info(wp, tabnr, winnr);
5338 if (d != NULL)
5339 list_append_dict(rettv->vval.v_list, d);
5340 if (wparg != NULL)
5341 /* found information about a specific window */
5342 return;
5343 }
5344 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005345}
5346
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005347/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005348 * "win_execute()" function
5349 */
5350 static void
5351f_win_execute(typval_T *argvars, typval_T *rettv)
5352{
5353 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005354 tabpage_T *tp;
5355 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005356 win_T *save_curwin;
5357 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005358
Bram Moolenaar820680b2019-08-09 14:56:22 +02005359 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005360 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005361 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005362 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005363 check_cursor();
5364 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005365 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005366 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005367 }
5368}
5369
5370/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371 * "win_findbuf()" function
5372 */
5373 static void
5374f_win_findbuf(typval_T *argvars, typval_T *rettv)
5375{
5376 if (rettv_list_alloc(rettv) != FAIL)
5377 win_findbuf(argvars, rettv->vval.v_list);
5378}
5379
5380/*
5381 * "win_getid()" function
5382 */
5383 static void
5384f_win_getid(typval_T *argvars, typval_T *rettv)
5385{
5386 rettv->vval.v_number = win_getid(argvars);
5387}
5388
5389/*
5390 * "win_gotoid()" function
5391 */
5392 static void
5393f_win_gotoid(typval_T *argvars, typval_T *rettv)
5394{
5395 rettv->vval.v_number = win_gotoid(argvars);
5396}
5397
5398/*
5399 * "win_id2tabwin()" function
5400 */
5401 static void
5402f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5403{
5404 if (rettv_list_alloc(rettv) != FAIL)
5405 win_id2tabwin(argvars, rettv->vval.v_list);
5406}
5407
5408/*
5409 * "win_id2win()" function
5410 */
5411 static void
5412f_win_id2win(typval_T *argvars, typval_T *rettv)
5413{
5414 rettv->vval.v_number = win_id2win(argvars);
5415}
5416
5417/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005418 * "win_screenpos()" function
5419 */
5420 static void
5421f_win_screenpos(typval_T *argvars, typval_T *rettv)
5422{
5423 win_T *wp;
5424
5425 if (rettv_list_alloc(rettv) == FAIL)
5426 return;
5427
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005428 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005429 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5430 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5431}
5432
5433/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005434 * "getwinpos({timeout})" function
5435 */
5436 static void
5437f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5438{
5439 int x = -1;
5440 int y = -1;
5441
5442 if (rettv_list_alloc(rettv) == FAIL)
5443 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005444#if defined(FEAT_GUI) \
5445 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5446 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005447 {
5448 varnumber_T timeout = 100;
5449
5450 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005451 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005452
5453 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005454 }
5455#endif
5456 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5457 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5458}
5459
5460
5461/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005462 * "getwinposx()" function
5463 */
5464 static void
5465f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5466{
5467 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005468#if defined(FEAT_GUI) \
5469 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5470 || defined(MSWIN)
5471
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005472 {
5473 int x, y;
5474
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005475 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005476 rettv->vval.v_number = x;
5477 }
5478#endif
5479}
5480
5481/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482 * "getwinposy()" function
5483 */
5484 static void
5485f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5486{
5487 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005488#if defined(FEAT_GUI) \
5489 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5490 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 {
5492 int x, y;
5493
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005494 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005495 rettv->vval.v_number = y;
5496 }
5497#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005498}
5499
5500/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501 * "glob()" function
5502 */
5503 static void
5504f_glob(typval_T *argvars, typval_T *rettv)
5505{
5506 int options = WILD_SILENT|WILD_USE_NL;
5507 expand_T xpc;
5508 int error = FALSE;
5509
5510 /* When the optional second argument is non-zero, don't remove matches
5511 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5512 rettv->v_type = VAR_STRING;
5513 if (argvars[1].v_type != VAR_UNKNOWN)
5514 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005515 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 options |= WILD_KEEP_ALL;
5517 if (argvars[2].v_type != VAR_UNKNOWN)
5518 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005519 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005520 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005522 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005523 options |= WILD_ALLLINKS;
5524 }
5525 }
5526 if (!error)
5527 {
5528 ExpandInit(&xpc);
5529 xpc.xp_context = EXPAND_FILES;
5530 if (p_wic)
5531 options += WILD_ICASE;
5532 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005533 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534 NULL, options, WILD_ALL);
5535 else if (rettv_list_alloc(rettv) != FAIL)
5536 {
5537 int i;
5538
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005539 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005540 NULL, options, WILD_ALL_KEEP);
5541 for (i = 0; i < xpc.xp_numfiles; i++)
5542 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5543
5544 ExpandCleanup(&xpc);
5545 }
5546 }
5547 else
5548 rettv->vval.v_string = NULL;
5549}
5550
5551/*
5552 * "globpath()" function
5553 */
5554 static void
5555f_globpath(typval_T *argvars, typval_T *rettv)
5556{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005557 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005558 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005559 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560 int error = FALSE;
5561 garray_T ga;
5562 int i;
5563
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005564 // When the optional second argument is non-zero, don't remove matches
5565 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566 rettv->v_type = VAR_STRING;
5567 if (argvars[2].v_type != VAR_UNKNOWN)
5568 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005569 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005570 flags |= WILD_KEEP_ALL;
5571 if (argvars[3].v_type != VAR_UNKNOWN)
5572 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005573 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005574 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005575 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005576 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 flags |= WILD_ALLLINKS;
5578 }
5579 }
5580 if (file != NULL && !error)
5581 {
5582 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005583 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005584 if (rettv->v_type == VAR_STRING)
5585 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5586 else if (rettv_list_alloc(rettv) != FAIL)
5587 for (i = 0; i < ga.ga_len; ++i)
5588 list_append_string(rettv->vval.v_list,
5589 ((char_u **)(ga.ga_data))[i], -1);
5590 ga_clear_strings(&ga);
5591 }
5592 else
5593 rettv->vval.v_string = NULL;
5594}
5595
5596/*
5597 * "glob2regpat()" function
5598 */
5599 static void
5600f_glob2regpat(typval_T *argvars, typval_T *rettv)
5601{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005602 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005603
5604 rettv->v_type = VAR_STRING;
5605 rettv->vval.v_string = (pat == NULL)
5606 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5607}
5608
5609/* for VIM_VERSION_ defines */
5610#include "version.h"
5611
5612/*
5613 * "has()" function
5614 */
5615 static void
5616f_has(typval_T *argvars, typval_T *rettv)
5617{
5618 int i;
5619 char_u *name;
5620 int n = FALSE;
5621 static char *(has_list[]) =
5622 {
5623#ifdef AMIGA
5624 "amiga",
5625# ifdef FEAT_ARP
5626 "arp",
5627# endif
5628#endif
5629#ifdef __BEOS__
5630 "beos",
5631#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005632#if defined(BSD) && !defined(MACOS_X)
5633 "bsd",
5634#endif
5635#ifdef hpux
5636 "hpux",
5637#endif
5638#ifdef __linux__
5639 "linux",
5640#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005641#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005642 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5643 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005644# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005645 "macunix", /* Mac OS X, with the darwin feature */
5646 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005647# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648#endif
5649#ifdef __QNX__
5650 "qnx",
5651#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005652#ifdef SUN_SYSTEM
5653 "sun",
5654#else
5655 "moon",
5656#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657#ifdef UNIX
5658 "unix",
5659#endif
5660#ifdef VMS
5661 "vms",
5662#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005663#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005664 "win32",
5665#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005666#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667 "win32unix",
5668#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005669#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 "win64",
5671#endif
5672#ifdef EBCDIC
5673 "ebcdic",
5674#endif
5675#ifndef CASE_INSENSITIVE_FILENAME
5676 "fname_case",
5677#endif
5678#ifdef HAVE_ACL
5679 "acl",
5680#endif
5681#ifdef FEAT_ARABIC
5682 "arabic",
5683#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005684 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005685#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005686 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005687#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005688#ifdef FEAT_AUTOSERVERNAME
5689 "autoservername",
5690#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005691#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005692 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005693# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005694 "balloon_multiline",
5695# endif
5696#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005697#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005698 "balloon_eval_term",
5699#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5701 "builtin_terms",
5702# ifdef ALL_BUILTIN_TCAPS
5703 "all_builtin_terms",
5704# endif
5705#endif
5706#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005707 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708 || defined(FEAT_GUI_MOTIF))
5709 "browsefilter",
5710#endif
5711#ifdef FEAT_BYTEOFF
5712 "byte_offset",
5713#endif
5714#ifdef FEAT_JOB_CHANNEL
5715 "channel",
5716#endif
5717#ifdef FEAT_CINDENT
5718 "cindent",
5719#endif
5720#ifdef FEAT_CLIENTSERVER
5721 "clientserver",
5722#endif
5723#ifdef FEAT_CLIPBOARD
5724 "clipboard",
5725#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005726 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005727 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005728#ifdef FEAT_COMMENTS
5729 "comments",
5730#endif
5731#ifdef FEAT_CONCEAL
5732 "conceal",
5733#endif
5734#ifdef FEAT_CRYPT
5735 "cryptv",
5736 "crypt-blowfish",
5737 "crypt-blowfish2",
5738#endif
5739#ifdef FEAT_CSCOPE
5740 "cscope",
5741#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005742 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743#ifdef CURSOR_SHAPE
5744 "cursorshape",
5745#endif
5746#ifdef DEBUG
5747 "debug",
5748#endif
5749#ifdef FEAT_CON_DIALOG
5750 "dialog_con",
5751#endif
5752#ifdef FEAT_GUI_DIALOG
5753 "dialog_gui",
5754#endif
5755#ifdef FEAT_DIFF
5756 "diff",
5757#endif
5758#ifdef FEAT_DIGRAPHS
5759 "digraphs",
5760#endif
5761#ifdef FEAT_DIRECTX
5762 "directx",
5763#endif
5764#ifdef FEAT_DND
5765 "dnd",
5766#endif
5767#ifdef FEAT_EMACS_TAGS
5768 "emacs_tags",
5769#endif
5770 "eval", /* always present, of course! */
5771 "ex_extra", /* graduated feature */
5772#ifdef FEAT_SEARCH_EXTRA
5773 "extra_search",
5774#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775#ifdef FEAT_SEARCHPATH
5776 "file_in_path",
5777#endif
5778#ifdef FEAT_FILTERPIPE
5779 "filterpipe",
5780#endif
5781#ifdef FEAT_FIND_ID
5782 "find_in_path",
5783#endif
5784#ifdef FEAT_FLOAT
5785 "float",
5786#endif
5787#ifdef FEAT_FOLDING
5788 "folding",
5789#endif
5790#ifdef FEAT_FOOTER
5791 "footer",
5792#endif
5793#if !defined(USE_SYSTEM) && defined(UNIX)
5794 "fork",
5795#endif
5796#ifdef FEAT_GETTEXT
5797 "gettext",
5798#endif
5799#ifdef FEAT_GUI
5800 "gui",
5801#endif
5802#ifdef FEAT_GUI_ATHENA
5803# ifdef FEAT_GUI_NEXTAW
5804 "gui_neXtaw",
5805# else
5806 "gui_athena",
5807# endif
5808#endif
5809#ifdef FEAT_GUI_GTK
5810 "gui_gtk",
5811# ifdef USE_GTK3
5812 "gui_gtk3",
5813# else
5814 "gui_gtk2",
5815# endif
5816#endif
5817#ifdef FEAT_GUI_GNOME
5818 "gui_gnome",
5819#endif
5820#ifdef FEAT_GUI_MAC
5821 "gui_mac",
5822#endif
5823#ifdef FEAT_GUI_MOTIF
5824 "gui_motif",
5825#endif
5826#ifdef FEAT_GUI_PHOTON
5827 "gui_photon",
5828#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005829#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005830 "gui_win32",
5831#endif
5832#ifdef FEAT_HANGULIN
5833 "hangul_input",
5834#endif
5835#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5836 "iconv",
5837#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005838 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839#ifdef FEAT_JOB_CHANNEL
5840 "job",
5841#endif
5842#ifdef FEAT_JUMPLIST
5843 "jumplist",
5844#endif
5845#ifdef FEAT_KEYMAP
5846 "keymap",
5847#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005848 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849#ifdef FEAT_LANGMAP
5850 "langmap",
5851#endif
5852#ifdef FEAT_LIBCALL
5853 "libcall",
5854#endif
5855#ifdef FEAT_LINEBREAK
5856 "linebreak",
5857#endif
5858#ifdef FEAT_LISP
5859 "lispindent",
5860#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005861 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005862 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863#ifdef FEAT_LUA
5864# ifndef DYNAMIC_LUA
5865 "lua",
5866# endif
5867#endif
5868#ifdef FEAT_MENU
5869 "menu",
5870#endif
5871#ifdef FEAT_SESSION
5872 "mksession",
5873#endif
5874#ifdef FEAT_MODIFY_FNAME
5875 "modify_fname",
5876#endif
5877#ifdef FEAT_MOUSE
5878 "mouse",
5879#endif
5880#ifdef FEAT_MOUSESHAPE
5881 "mouseshape",
5882#endif
5883#if defined(UNIX) || defined(VMS)
5884# ifdef FEAT_MOUSE_DEC
5885 "mouse_dec",
5886# endif
5887# ifdef FEAT_MOUSE_GPM
5888 "mouse_gpm",
5889# endif
5890# ifdef FEAT_MOUSE_JSB
5891 "mouse_jsbterm",
5892# endif
5893# ifdef FEAT_MOUSE_NET
5894 "mouse_netterm",
5895# endif
5896# ifdef FEAT_MOUSE_PTERM
5897 "mouse_pterm",
5898# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01005899# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 "mouse_sgr",
5901# endif
5902# ifdef FEAT_SYSMOUSE
5903 "mouse_sysmouse",
5904# endif
5905# ifdef FEAT_MOUSE_URXVT
5906 "mouse_urxvt",
5907# endif
5908# ifdef FEAT_MOUSE_XTERM
5909 "mouse_xterm",
5910# endif
5911#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913#ifdef FEAT_MBYTE_IME
5914 "multi_byte_ime",
5915#endif
5916#ifdef FEAT_MULTI_LANG
5917 "multi_lang",
5918#endif
5919#ifdef FEAT_MZSCHEME
5920#ifndef DYNAMIC_MZSCHEME
5921 "mzscheme",
5922#endif
5923#endif
5924#ifdef FEAT_NUM64
5925 "num64",
5926#endif
5927#ifdef FEAT_OLE
5928 "ole",
5929#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02005930#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02005932#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005933#ifdef FEAT_PATH_EXTRA
5934 "path_extra",
5935#endif
5936#ifdef FEAT_PERL
5937#ifndef DYNAMIC_PERL
5938 "perl",
5939#endif
5940#endif
5941#ifdef FEAT_PERSISTENT_UNDO
5942 "persistent_undo",
5943#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005944#if defined(FEAT_PYTHON)
5945 "python_compiled",
5946# if defined(DYNAMIC_PYTHON)
5947 "python_dynamic",
5948# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005950 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005951# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005952#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005953#if defined(FEAT_PYTHON3)
5954 "python3_compiled",
5955# if defined(DYNAMIC_PYTHON3)
5956 "python3_dynamic",
5957# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005958 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005959 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005960# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005961#endif
5962#ifdef FEAT_POSTSCRIPT
5963 "postscript",
5964#endif
5965#ifdef FEAT_PRINTER
5966 "printer",
5967#endif
5968#ifdef FEAT_PROFILE
5969 "profile",
5970#endif
5971#ifdef FEAT_RELTIME
5972 "reltime",
5973#endif
5974#ifdef FEAT_QUICKFIX
5975 "quickfix",
5976#endif
5977#ifdef FEAT_RIGHTLEFT
5978 "rightleft",
5979#endif
5980#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5981 "ruby",
5982#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984#ifdef FEAT_CMDL_INFO
5985 "showcmd",
5986 "cmdline_info",
5987#endif
5988#ifdef FEAT_SIGNS
5989 "signs",
5990#endif
5991#ifdef FEAT_SMARTINDENT
5992 "smartindent",
5993#endif
5994#ifdef STARTUPTIME
5995 "startuptime",
5996#endif
5997#ifdef FEAT_STL_OPT
5998 "statusline",
5999#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000#ifdef FEAT_NETBEANS_INTG
6001 "netbeans_intg",
6002#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006003#ifdef FEAT_SOUND
6004 "sound",
6005#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006#ifdef FEAT_SPELL
6007 "spell",
6008#endif
6009#ifdef FEAT_SYN_HL
6010 "syntax",
6011#endif
6012#if defined(USE_SYSTEM) || !defined(UNIX)
6013 "system",
6014#endif
6015#ifdef FEAT_TAG_BINS
6016 "tag_binary",
6017#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018#ifdef FEAT_TCL
6019# ifndef DYNAMIC_TCL
6020 "tcl",
6021# endif
6022#endif
6023#ifdef FEAT_TERMGUICOLORS
6024 "termguicolors",
6025#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006026#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006027 "terminal",
6028#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006029#ifdef TERMINFO
6030 "terminfo",
6031#endif
6032#ifdef FEAT_TERMRESPONSE
6033 "termresponse",
6034#endif
6035#ifdef FEAT_TEXTOBJ
6036 "textobjects",
6037#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006038#ifdef FEAT_TEXT_PROP
6039 "textprop",
6040#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006041#ifdef HAVE_TGETENT
6042 "tgetent",
6043#endif
6044#ifdef FEAT_TIMERS
6045 "timers",
6046#endif
6047#ifdef FEAT_TITLE
6048 "title",
6049#endif
6050#ifdef FEAT_TOOLBAR
6051 "toolbar",
6052#endif
6053#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6054 "unnamedplus",
6055#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056 "user-commands", /* was accidentally included in 5.4 */
6057 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006058#ifdef FEAT_VARTABS
6059 "vartabs",
6060#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006061 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006062#ifdef FEAT_VIMINFO
6063 "viminfo",
6064#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006065 "vimscript-1",
6066 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006067 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006069 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006072#ifdef FEAT_VTP
6073 "vtp",
6074#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075#ifdef FEAT_WILDIGN
6076 "wildignore",
6077#endif
6078#ifdef FEAT_WILDMENU
6079 "wildmenu",
6080#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006082#ifdef FEAT_WAK
6083 "winaltkeys",
6084#endif
6085#ifdef FEAT_WRITEBACKUP
6086 "writebackup",
6087#endif
6088#ifdef FEAT_XIM
6089 "xim",
6090#endif
6091#ifdef FEAT_XFONTSET
6092 "xfontset",
6093#endif
6094#ifdef FEAT_XPM_W32
6095 "xpm",
6096 "xpm_w32", /* for backward compatibility */
6097#else
6098# if defined(HAVE_XPM)
6099 "xpm",
6100# endif
6101#endif
6102#ifdef USE_XSMP
6103 "xsmp",
6104#endif
6105#ifdef USE_XSMP_INTERACT
6106 "xsmp_interact",
6107#endif
6108#ifdef FEAT_XCLIPBOARD
6109 "xterm_clipboard",
6110#endif
6111#ifdef FEAT_XTERM_SAVE
6112 "xterm_save",
6113#endif
6114#if defined(UNIX) && defined(FEAT_X11)
6115 "X11",
6116#endif
6117 NULL
6118 };
6119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006120 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006121 for (i = 0; has_list[i] != NULL; ++i)
6122 if (STRICMP(name, has_list[i]) == 0)
6123 {
6124 n = TRUE;
6125 break;
6126 }
6127
6128 if (n == FALSE)
6129 {
6130 if (STRNICMP(name, "patch", 5) == 0)
6131 {
6132 if (name[5] == '-'
6133 && STRLEN(name) >= 11
6134 && vim_isdigit(name[6])
6135 && vim_isdigit(name[8])
6136 && vim_isdigit(name[10]))
6137 {
6138 int major = atoi((char *)name + 6);
6139 int minor = atoi((char *)name + 8);
6140
6141 /* Expect "patch-9.9.01234". */
6142 n = (major < VIM_VERSION_MAJOR
6143 || (major == VIM_VERSION_MAJOR
6144 && (minor < VIM_VERSION_MINOR
6145 || (minor == VIM_VERSION_MINOR
6146 && has_patch(atoi((char *)name + 10))))));
6147 }
6148 else
6149 n = has_patch(atoi((char *)name + 5));
6150 }
6151 else if (STRICMP(name, "vim_starting") == 0)
6152 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006153 else if (STRICMP(name, "ttyin") == 0)
6154 n = mch_input_isatty();
6155 else if (STRICMP(name, "ttyout") == 0)
6156 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157 else if (STRICMP(name, "multi_byte_encoding") == 0)
6158 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006159#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 else if (STRICMP(name, "balloon_multiline") == 0)
6161 n = multiline_balloon_available();
6162#endif
6163#ifdef DYNAMIC_TCL
6164 else if (STRICMP(name, "tcl") == 0)
6165 n = tcl_enabled(FALSE);
6166#endif
6167#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6168 else if (STRICMP(name, "iconv") == 0)
6169 n = iconv_enabled(FALSE);
6170#endif
6171#ifdef DYNAMIC_LUA
6172 else if (STRICMP(name, "lua") == 0)
6173 n = lua_enabled(FALSE);
6174#endif
6175#ifdef DYNAMIC_MZSCHEME
6176 else if (STRICMP(name, "mzscheme") == 0)
6177 n = mzscheme_enabled(FALSE);
6178#endif
6179#ifdef DYNAMIC_RUBY
6180 else if (STRICMP(name, "ruby") == 0)
6181 n = ruby_enabled(FALSE);
6182#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183#ifdef DYNAMIC_PYTHON
6184 else if (STRICMP(name, "python") == 0)
6185 n = python_enabled(FALSE);
6186#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187#ifdef DYNAMIC_PYTHON3
6188 else if (STRICMP(name, "python3") == 0)
6189 n = python3_enabled(FALSE);
6190#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006191#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6192 else if (STRICMP(name, "pythonx") == 0)
6193 {
6194# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6195 if (p_pyx == 0)
6196 n = python3_enabled(FALSE) || python_enabled(FALSE);
6197 else if (p_pyx == 3)
6198 n = python3_enabled(FALSE);
6199 else if (p_pyx == 2)
6200 n = python_enabled(FALSE);
6201# elif defined(DYNAMIC_PYTHON)
6202 n = python_enabled(FALSE);
6203# elif defined(DYNAMIC_PYTHON3)
6204 n = python3_enabled(FALSE);
6205# endif
6206 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006207#endif
6208#ifdef DYNAMIC_PERL
6209 else if (STRICMP(name, "perl") == 0)
6210 n = perl_enabled(FALSE);
6211#endif
6212#ifdef FEAT_GUI
6213 else if (STRICMP(name, "gui_running") == 0)
6214 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215# ifdef FEAT_BROWSE
6216 else if (STRICMP(name, "browse") == 0)
6217 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6218# endif
6219#endif
6220#ifdef FEAT_SYN_HL
6221 else if (STRICMP(name, "syntax_items") == 0)
6222 n = syntax_present(curwin);
6223#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006224#ifdef FEAT_VTP
6225 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006226 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227#endif
6228#ifdef FEAT_NETBEANS_INTG
6229 else if (STRICMP(name, "netbeans_enabled") == 0)
6230 n = netbeans_active();
6231#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006232#ifdef FEAT_MOUSE_GPM
6233 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6234 n = gpm_enabled();
6235#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006236#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006237 else if (STRICMP(name, "terminal") == 0)
6238 n = terminal_enabled();
6239#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006240#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006241 else if (STRICMP(name, "conpty") == 0)
6242 n = use_conpty();
6243#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006244#ifdef FEAT_CLIPBOARD
6245 else if (STRICMP(name, "clipboard_working") == 0)
6246 n = clip_star.available;
6247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006248 }
6249
6250 rettv->vval.v_number = n;
6251}
6252
6253/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254 * "haslocaldir()" function
6255 */
6256 static void
6257f_haslocaldir(typval_T *argvars, typval_T *rettv)
6258{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006259 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006260 win_T *wp = NULL;
6261
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006262 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6263
6264 // Check for window-local and tab-local directories
6265 if (wp != NULL && wp->w_localdir != NULL)
6266 rettv->vval.v_number = 1;
6267 else if (tp != NULL && tp->tp_localdir != NULL)
6268 rettv->vval.v_number = 2;
6269 else
6270 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006271}
6272
6273/*
6274 * "hasmapto()" function
6275 */
6276 static void
6277f_hasmapto(typval_T *argvars, typval_T *rettv)
6278{
6279 char_u *name;
6280 char_u *mode;
6281 char_u buf[NUMBUFLEN];
6282 int abbr = FALSE;
6283
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006284 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 if (argvars[1].v_type == VAR_UNKNOWN)
6286 mode = (char_u *)"nvo";
6287 else
6288 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006289 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006291 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006292 }
6293
6294 if (map_to_exists(name, mode, abbr))
6295 rettv->vval.v_number = TRUE;
6296 else
6297 rettv->vval.v_number = FALSE;
6298}
6299
6300/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006301 * "highlightID(name)" function
6302 */
6303 static void
6304f_hlID(typval_T *argvars, typval_T *rettv)
6305{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006306 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307}
6308
6309/*
6310 * "highlight_exists()" function
6311 */
6312 static void
6313f_hlexists(typval_T *argvars, typval_T *rettv)
6314{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006315 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006316}
6317
6318/*
6319 * "hostname()" function
6320 */
6321 static void
6322f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6323{
6324 char_u hostname[256];
6325
6326 mch_get_host_name(hostname, 256);
6327 rettv->v_type = VAR_STRING;
6328 rettv->vval.v_string = vim_strsave(hostname);
6329}
6330
6331/*
6332 * iconv() function
6333 */
6334 static void
6335f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6336{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 char_u buf1[NUMBUFLEN];
6338 char_u buf2[NUMBUFLEN];
6339 char_u *from, *to, *str;
6340 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341
6342 rettv->v_type = VAR_STRING;
6343 rettv->vval.v_string = NULL;
6344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006345 str = tv_get_string(&argvars[0]);
6346 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6347 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006348 vimconv.vc_type = CONV_NONE;
6349 convert_setup(&vimconv, from, to);
6350
6351 /* If the encodings are equal, no conversion needed. */
6352 if (vimconv.vc_type == CONV_NONE)
6353 rettv->vval.v_string = vim_strsave(str);
6354 else
6355 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6356
6357 convert_setup(&vimconv, NULL, NULL);
6358 vim_free(from);
6359 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360}
6361
6362/*
6363 * "indent()" function
6364 */
6365 static void
6366f_indent(typval_T *argvars, typval_T *rettv)
6367{
6368 linenr_T lnum;
6369
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006370 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006371 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6372 rettv->vval.v_number = get_indent_lnum(lnum);
6373 else
6374 rettv->vval.v_number = -1;
6375}
6376
6377/*
6378 * "index()" function
6379 */
6380 static void
6381f_index(typval_T *argvars, typval_T *rettv)
6382{
6383 list_T *l;
6384 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006385 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386 long idx = 0;
6387 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006388 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389
6390 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006391 if (argvars[0].v_type == VAR_BLOB)
6392 {
6393 typval_T tv;
6394 int start = 0;
6395
6396 if (argvars[2].v_type != VAR_UNKNOWN)
6397 {
6398 start = tv_get_number_chk(&argvars[2], &error);
6399 if (error)
6400 return;
6401 }
6402 b = argvars[0].vval.v_blob;
6403 if (b == NULL)
6404 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006405 if (start < 0)
6406 {
6407 start = blob_len(b) + start;
6408 if (start < 0)
6409 start = 0;
6410 }
6411
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006412 for (idx = start; idx < blob_len(b); ++idx)
6413 {
6414 tv.v_type = VAR_NUMBER;
6415 tv.vval.v_number = blob_get(b, idx);
6416 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6417 {
6418 rettv->vval.v_number = idx;
6419 return;
6420 }
6421 }
6422 return;
6423 }
6424 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006426 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427 return;
6428 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006429
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430 l = argvars[0].vval.v_list;
6431 if (l != NULL)
6432 {
6433 item = l->lv_first;
6434 if (argvars[2].v_type != VAR_UNKNOWN)
6435 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 /* Start at specified item. Use the cached index that list_find()
6437 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006438 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439 idx = l->lv_idx;
6440 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006441 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 if (error)
6443 item = NULL;
6444 }
6445
6446 for ( ; item != NULL; item = item->li_next, ++idx)
6447 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6448 {
6449 rettv->vval.v_number = idx;
6450 break;
6451 }
6452 }
6453}
6454
6455static int inputsecret_flag = 0;
6456
6457/*
6458 * "input()" function
6459 * Also handles inputsecret() when inputsecret is set.
6460 */
6461 static void
6462f_input(typval_T *argvars, typval_T *rettv)
6463{
6464 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6465}
6466
6467/*
6468 * "inputdialog()" function
6469 */
6470 static void
6471f_inputdialog(typval_T *argvars, typval_T *rettv)
6472{
6473#if defined(FEAT_GUI_TEXTDIALOG)
6474 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6475 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6476 {
6477 char_u *message;
6478 char_u buf[NUMBUFLEN];
6479 char_u *defstr = (char_u *)"";
6480
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006481 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006483 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6485 else
6486 IObuff[0] = NUL;
6487 if (message != NULL && defstr != NULL
6488 && do_dialog(VIM_QUESTION, NULL, message,
6489 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6490 rettv->vval.v_string = vim_strsave(IObuff);
6491 else
6492 {
6493 if (message != NULL && defstr != NULL
6494 && argvars[1].v_type != VAR_UNKNOWN
6495 && argvars[2].v_type != VAR_UNKNOWN)
6496 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006497 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006498 else
6499 rettv->vval.v_string = NULL;
6500 }
6501 rettv->v_type = VAR_STRING;
6502 }
6503 else
6504#endif
6505 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6506}
6507
6508/*
6509 * "inputlist()" function
6510 */
6511 static void
6512f_inputlist(typval_T *argvars, typval_T *rettv)
6513{
6514 listitem_T *li;
6515 int selected;
6516 int mouse_used;
6517
6518#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006519 /* While starting up, there is no place to enter text. When running tests
6520 * with --not-a-term we assume feedkeys() will be used. */
6521 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522 return;
6523#endif
6524 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6525 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006526 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527 return;
6528 }
6529
6530 msg_start();
6531 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6532 lines_left = Rows; /* avoid more prompt */
6533 msg_scroll = TRUE;
6534 msg_clr_eos();
6535
6536 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6537 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006538 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 msg_putchar('\n');
6540 }
6541
6542 /* Ask for choice. */
6543 selected = prompt_for_number(&mouse_used);
6544 if (mouse_used)
6545 selected -= lines_left;
6546
6547 rettv->vval.v_number = selected;
6548}
6549
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6551
6552/*
6553 * "inputrestore()" function
6554 */
6555 static void
6556f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6557{
6558 if (ga_userinput.ga_len > 0)
6559 {
6560 --ga_userinput.ga_len;
6561 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6562 + ga_userinput.ga_len);
6563 /* default return is zero == OK */
6564 }
6565 else if (p_verbose > 1)
6566 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006567 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 rettv->vval.v_number = 1; /* Failed */
6569 }
6570}
6571
6572/*
6573 * "inputsave()" function
6574 */
6575 static void
6576f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6577{
6578 /* Add an entry to the stack of typeahead storage. */
6579 if (ga_grow(&ga_userinput, 1) == OK)
6580 {
6581 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6582 + ga_userinput.ga_len);
6583 ++ga_userinput.ga_len;
6584 /* default return is zero == OK */
6585 }
6586 else
6587 rettv->vval.v_number = 1; /* Failed */
6588}
6589
6590/*
6591 * "inputsecret()" function
6592 */
6593 static void
6594f_inputsecret(typval_T *argvars, typval_T *rettv)
6595{
6596 ++cmdline_star;
6597 ++inputsecret_flag;
6598 f_input(argvars, rettv);
6599 --cmdline_star;
6600 --inputsecret_flag;
6601}
6602
6603/*
6604 * "insert()" function
6605 */
6606 static void
6607f_insert(typval_T *argvars, typval_T *rettv)
6608{
6609 long before = 0;
6610 listitem_T *item;
6611 list_T *l;
6612 int error = FALSE;
6613
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006614 if (argvars[0].v_type == VAR_BLOB)
6615 {
6616 int val, len;
6617 char_u *p;
6618
6619 len = blob_len(argvars[0].vval.v_blob);
6620 if (argvars[2].v_type != VAR_UNKNOWN)
6621 {
6622 before = (long)tv_get_number_chk(&argvars[2], &error);
6623 if (error)
6624 return; // type error; errmsg already given
6625 if (before < 0 || before > len)
6626 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006627 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006628 return;
6629 }
6630 }
6631 val = tv_get_number_chk(&argvars[1], &error);
6632 if (error)
6633 return;
6634 if (val < 0 || val > 255)
6635 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006636 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006637 return;
6638 }
6639
6640 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6641 return;
6642 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6643 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6644 *(p + before) = val;
6645 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6646
6647 copy_tv(&argvars[0], rettv);
6648 }
6649 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006650 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006651 else if ((l = argvars[0].vval.v_list) != NULL
6652 && !var_check_lock(l->lv_lock,
6653 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006654 {
6655 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006656 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 if (error)
6658 return; /* type error; errmsg already given */
6659
6660 if (before == l->lv_len)
6661 item = NULL;
6662 else
6663 {
6664 item = list_find(l, before);
6665 if (item == NULL)
6666 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006667 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006668 l = NULL;
6669 }
6670 }
6671 if (l != NULL)
6672 {
6673 list_insert_tv(l, &argvars[1], item);
6674 copy_tv(&argvars[0], rettv);
6675 }
6676 }
6677}
6678
6679/*
6680 * "invert(expr)" function
6681 */
6682 static void
6683f_invert(typval_T *argvars, typval_T *rettv)
6684{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006685 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686}
6687
6688/*
6689 * "isdirectory()" function
6690 */
6691 static void
6692f_isdirectory(typval_T *argvars, typval_T *rettv)
6693{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006694 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695}
6696
6697/*
6698 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6699 * or it refers to a List or Dictionary that is locked.
6700 */
6701 static int
6702tv_islocked(typval_T *tv)
6703{
6704 return (tv->v_lock & VAR_LOCKED)
6705 || (tv->v_type == VAR_LIST
6706 && tv->vval.v_list != NULL
6707 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6708 || (tv->v_type == VAR_DICT
6709 && tv->vval.v_dict != NULL
6710 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6711}
6712
6713/*
6714 * "islocked()" function
6715 */
6716 static void
6717f_islocked(typval_T *argvars, typval_T *rettv)
6718{
6719 lval_T lv;
6720 char_u *end;
6721 dictitem_T *di;
6722
6723 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006724 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006725 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 if (end != NULL && lv.ll_name != NULL)
6727 {
6728 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006729 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006730 else
6731 {
6732 if (lv.ll_tv == NULL)
6733 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006734 di = find_var(lv.ll_name, NULL, TRUE);
6735 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006736 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006737 /* Consider a variable locked when:
6738 * 1. the variable itself is locked
6739 * 2. the value of the variable is locked.
6740 * 3. the List or Dict value is locked.
6741 */
6742 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6743 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006744 }
6745 }
6746 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006747 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006748 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006749 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750 else if (lv.ll_list != NULL)
6751 /* List item. */
6752 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6753 else
6754 /* Dictionary item. */
6755 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6756 }
6757 }
6758
6759 clear_lval(&lv);
6760}
6761
6762#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6763/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006764 * "isinf()" function
6765 */
6766 static void
6767f_isinf(typval_T *argvars, typval_T *rettv)
6768{
6769 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6770 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6771}
6772
6773/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 * "isnan()" function
6775 */
6776 static void
6777f_isnan(typval_T *argvars, typval_T *rettv)
6778{
6779 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6780 && isnan(argvars[0].vval.v_float);
6781}
6782#endif
6783
6784/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785 * "last_buffer_nr()" function.
6786 */
6787 static void
6788f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6789{
6790 int n = 0;
6791 buf_T *buf;
6792
Bram Moolenaar29323592016-07-24 22:04:11 +02006793 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 if (n < buf->b_fnum)
6795 n = buf->b_fnum;
6796
6797 rettv->vval.v_number = n;
6798}
6799
6800/*
6801 * "len()" function
6802 */
6803 static void
6804f_len(typval_T *argvars, typval_T *rettv)
6805{
6806 switch (argvars[0].v_type)
6807 {
6808 case VAR_STRING:
6809 case VAR_NUMBER:
6810 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006813 case VAR_BLOB:
6814 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6815 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006816 case VAR_LIST:
6817 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6818 break;
6819 case VAR_DICT:
6820 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6821 break;
6822 case VAR_UNKNOWN:
6823 case VAR_SPECIAL:
6824 case VAR_FLOAT:
6825 case VAR_FUNC:
6826 case VAR_PARTIAL:
6827 case VAR_JOB:
6828 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006829 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830 break;
6831 }
6832}
6833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006835libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836{
6837#ifdef FEAT_LIBCALL
6838 char_u *string_in;
6839 char_u **string_result;
6840 int nr_result;
6841#endif
6842
6843 rettv->v_type = type;
6844 if (type != VAR_NUMBER)
6845 rettv->vval.v_string = NULL;
6846
6847 if (check_restricted() || check_secure())
6848 return;
6849
6850#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006851 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006852 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6853 {
6854 string_in = NULL;
6855 if (argvars[2].v_type == VAR_STRING)
6856 string_in = argvars[2].vval.v_string;
6857 if (type == VAR_NUMBER)
6858 string_result = NULL;
6859 else
6860 string_result = &rettv->vval.v_string;
6861 if (mch_libcall(argvars[0].vval.v_string,
6862 argvars[1].vval.v_string,
6863 string_in,
6864 argvars[2].vval.v_number,
6865 string_result,
6866 &nr_result) == OK
6867 && type == VAR_NUMBER)
6868 rettv->vval.v_number = nr_result;
6869 }
6870#endif
6871}
6872
6873/*
6874 * "libcall()" function
6875 */
6876 static void
6877f_libcall(typval_T *argvars, typval_T *rettv)
6878{
6879 libcall_common(argvars, rettv, VAR_STRING);
6880}
6881
6882/*
6883 * "libcallnr()" function
6884 */
6885 static void
6886f_libcallnr(typval_T *argvars, typval_T *rettv)
6887{
6888 libcall_common(argvars, rettv, VAR_NUMBER);
6889}
6890
6891/*
6892 * "line(string)" function
6893 */
6894 static void
6895f_line(typval_T *argvars, typval_T *rettv)
6896{
6897 linenr_T lnum = 0;
6898 pos_T *fp;
6899 int fnum;
6900
6901 fp = var2fpos(&argvars[0], TRUE, &fnum);
6902 if (fp != NULL)
6903 lnum = fp->lnum;
6904 rettv->vval.v_number = lnum;
6905}
6906
6907/*
6908 * "line2byte(lnum)" function
6909 */
6910 static void
6911f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6912{
6913#ifndef FEAT_BYTEOFF
6914 rettv->vval.v_number = -1;
6915#else
6916 linenr_T lnum;
6917
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006918 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6920 rettv->vval.v_number = -1;
6921 else
6922 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6923 if (rettv->vval.v_number >= 0)
6924 ++rettv->vval.v_number;
6925#endif
6926}
6927
6928/*
6929 * "lispindent(lnum)" function
6930 */
6931 static void
6932f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6933{
6934#ifdef FEAT_LISP
6935 pos_T pos;
6936 linenr_T lnum;
6937
6938 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006939 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6941 {
6942 curwin->w_cursor.lnum = lnum;
6943 rettv->vval.v_number = get_lisp_indent();
6944 curwin->w_cursor = pos;
6945 }
6946 else
6947#endif
6948 rettv->vval.v_number = -1;
6949}
6950
6951/*
6952 * "localtime()" function
6953 */
6954 static void
6955f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6956{
6957 rettv->vval.v_number = (varnumber_T)time(NULL);
6958}
6959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960#ifdef FEAT_FLOAT
6961/*
6962 * "log()" function
6963 */
6964 static void
6965f_log(typval_T *argvars, typval_T *rettv)
6966{
6967 float_T f = 0.0;
6968
6969 rettv->v_type = VAR_FLOAT;
6970 if (get_float_arg(argvars, &f) == OK)
6971 rettv->vval.v_float = log(f);
6972 else
6973 rettv->vval.v_float = 0.0;
6974}
6975
6976/*
6977 * "log10()" function
6978 */
6979 static void
6980f_log10(typval_T *argvars, typval_T *rettv)
6981{
6982 float_T f = 0.0;
6983
6984 rettv->v_type = VAR_FLOAT;
6985 if (get_float_arg(argvars, &f) == OK)
6986 rettv->vval.v_float = log10(f);
6987 else
6988 rettv->vval.v_float = 0.0;
6989}
6990#endif
6991
6992#ifdef FEAT_LUA
6993/*
6994 * "luaeval()" function
6995 */
6996 static void
6997f_luaeval(typval_T *argvars, typval_T *rettv)
6998{
6999 char_u *str;
7000 char_u buf[NUMBUFLEN];
7001
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007002 if (check_restricted() || check_secure())
7003 return;
7004
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007005 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007006 do_luaeval(str, argvars + 1, rettv);
7007}
7008#endif
7009
7010/*
7011 * "map()" function
7012 */
7013 static void
7014f_map(typval_T *argvars, typval_T *rettv)
7015{
7016 filter_map(argvars, rettv, TRUE);
7017}
7018
7019/*
7020 * "maparg()" function
7021 */
7022 static void
7023f_maparg(typval_T *argvars, typval_T *rettv)
7024{
7025 get_maparg(argvars, rettv, TRUE);
7026}
7027
7028/*
7029 * "mapcheck()" function
7030 */
7031 static void
7032f_mapcheck(typval_T *argvars, typval_T *rettv)
7033{
7034 get_maparg(argvars, rettv, FALSE);
7035}
7036
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007037typedef enum
7038{
7039 MATCH_END, /* matchend() */
7040 MATCH_MATCH, /* match() */
7041 MATCH_STR, /* matchstr() */
7042 MATCH_LIST, /* matchlist() */
7043 MATCH_POS /* matchstrpos() */
7044} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045
7046 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007047find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048{
7049 char_u *str = NULL;
7050 long len = 0;
7051 char_u *expr = NULL;
7052 char_u *pat;
7053 regmatch_T regmatch;
7054 char_u patbuf[NUMBUFLEN];
7055 char_u strbuf[NUMBUFLEN];
7056 char_u *save_cpo;
7057 long start = 0;
7058 long nth = 1;
7059 colnr_T startcol = 0;
7060 int match = 0;
7061 list_T *l = NULL;
7062 listitem_T *li = NULL;
7063 long idx = 0;
7064 char_u *tofree = NULL;
7065
7066 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7067 save_cpo = p_cpo;
7068 p_cpo = (char_u *)"";
7069
7070 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007071 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007073 /* type MATCH_LIST: return empty list when there are no matches.
7074 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 if (rettv_list_alloc(rettv) == FAIL)
7076 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007077 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078 && (list_append_string(rettv->vval.v_list,
7079 (char_u *)"", 0) == FAIL
7080 || list_append_number(rettv->vval.v_list,
7081 (varnumber_T)-1) == FAIL
7082 || list_append_number(rettv->vval.v_list,
7083 (varnumber_T)-1) == FAIL
7084 || list_append_number(rettv->vval.v_list,
7085 (varnumber_T)-1) == FAIL))
7086 {
7087 list_free(rettv->vval.v_list);
7088 rettv->vval.v_list = NULL;
7089 goto theend;
7090 }
7091 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007092 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007093 {
7094 rettv->v_type = VAR_STRING;
7095 rettv->vval.v_string = NULL;
7096 }
7097
7098 if (argvars[0].v_type == VAR_LIST)
7099 {
7100 if ((l = argvars[0].vval.v_list) == NULL)
7101 goto theend;
7102 li = l->lv_first;
7103 }
7104 else
7105 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007106 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 len = (long)STRLEN(str);
7108 }
7109
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007110 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007111 if (pat == NULL)
7112 goto theend;
7113
7114 if (argvars[2].v_type != VAR_UNKNOWN)
7115 {
7116 int error = FALSE;
7117
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007118 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 if (error)
7120 goto theend;
7121 if (l != NULL)
7122 {
7123 li = list_find(l, start);
7124 if (li == NULL)
7125 goto theend;
7126 idx = l->lv_idx; /* use the cached index */
7127 }
7128 else
7129 {
7130 if (start < 0)
7131 start = 0;
7132 if (start > len)
7133 goto theend;
7134 /* When "count" argument is there ignore matches before "start",
7135 * otherwise skip part of the string. Differs when pattern is "^"
7136 * or "\<". */
7137 if (argvars[3].v_type != VAR_UNKNOWN)
7138 startcol = start;
7139 else
7140 {
7141 str += start;
7142 len -= start;
7143 }
7144 }
7145
7146 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007147 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 if (error)
7149 goto theend;
7150 }
7151
7152 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7153 if (regmatch.regprog != NULL)
7154 {
7155 regmatch.rm_ic = p_ic;
7156
7157 for (;;)
7158 {
7159 if (l != NULL)
7160 {
7161 if (li == NULL)
7162 {
7163 match = FALSE;
7164 break;
7165 }
7166 vim_free(tofree);
7167 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7168 if (str == NULL)
7169 break;
7170 }
7171
7172 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7173
7174 if (match && --nth <= 0)
7175 break;
7176 if (l == NULL && !match)
7177 break;
7178
7179 /* Advance to just after the match. */
7180 if (l != NULL)
7181 {
7182 li = li->li_next;
7183 ++idx;
7184 }
7185 else
7186 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187 startcol = (colnr_T)(regmatch.startp[0]
7188 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007189 if (startcol > (colnr_T)len
7190 || str + startcol <= regmatch.startp[0])
7191 {
7192 match = FALSE;
7193 break;
7194 }
7195 }
7196 }
7197
7198 if (match)
7199 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007200 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201 {
7202 listitem_T *li1 = rettv->vval.v_list->lv_first;
7203 listitem_T *li2 = li1->li_next;
7204 listitem_T *li3 = li2->li_next;
7205 listitem_T *li4 = li3->li_next;
7206
7207 vim_free(li1->li_tv.vval.v_string);
7208 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7209 (int)(regmatch.endp[0] - regmatch.startp[0]));
7210 li3->li_tv.vval.v_number =
7211 (varnumber_T)(regmatch.startp[0] - expr);
7212 li4->li_tv.vval.v_number =
7213 (varnumber_T)(regmatch.endp[0] - expr);
7214 if (l != NULL)
7215 li2->li_tv.vval.v_number = (varnumber_T)idx;
7216 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007217 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218 {
7219 int i;
7220
7221 /* return list with matched string and submatches */
7222 for (i = 0; i < NSUBEXP; ++i)
7223 {
7224 if (regmatch.endp[i] == NULL)
7225 {
7226 if (list_append_string(rettv->vval.v_list,
7227 (char_u *)"", 0) == FAIL)
7228 break;
7229 }
7230 else if (list_append_string(rettv->vval.v_list,
7231 regmatch.startp[i],
7232 (int)(regmatch.endp[i] - regmatch.startp[i]))
7233 == FAIL)
7234 break;
7235 }
7236 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007237 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238 {
7239 /* return matched string */
7240 if (l != NULL)
7241 copy_tv(&li->li_tv, rettv);
7242 else
7243 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7244 (int)(regmatch.endp[0] - regmatch.startp[0]));
7245 }
7246 else if (l != NULL)
7247 rettv->vval.v_number = idx;
7248 else
7249 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007250 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 rettv->vval.v_number =
7252 (varnumber_T)(regmatch.startp[0] - str);
7253 else
7254 rettv->vval.v_number =
7255 (varnumber_T)(regmatch.endp[0] - str);
7256 rettv->vval.v_number += (varnumber_T)(str - expr);
7257 }
7258 }
7259 vim_regfree(regmatch.regprog);
7260 }
7261
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007262theend:
7263 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007264 /* matchstrpos() without a list: drop the second item. */
7265 listitem_remove(rettv->vval.v_list,
7266 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 vim_free(tofree);
7268 p_cpo = save_cpo;
7269}
7270
7271/*
7272 * "match()" function
7273 */
7274 static void
7275f_match(typval_T *argvars, typval_T *rettv)
7276{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007277 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278}
7279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007280/*
7281 * "matchend()" function
7282 */
7283 static void
7284f_matchend(typval_T *argvars, typval_T *rettv)
7285{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007286 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287}
7288
7289/*
7290 * "matchlist()" function
7291 */
7292 static void
7293f_matchlist(typval_T *argvars, typval_T *rettv)
7294{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007295 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296}
7297
7298/*
7299 * "matchstr()" function
7300 */
7301 static void
7302f_matchstr(typval_T *argvars, typval_T *rettv)
7303{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007304 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305}
7306
7307/*
7308 * "matchstrpos()" function
7309 */
7310 static void
7311f_matchstrpos(typval_T *argvars, typval_T *rettv)
7312{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007313 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007314}
7315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 static void
7317max_min(typval_T *argvars, typval_T *rettv, int domax)
7318{
7319 varnumber_T n = 0;
7320 varnumber_T i;
7321 int error = FALSE;
7322
7323 if (argvars[0].v_type == VAR_LIST)
7324 {
7325 list_T *l;
7326 listitem_T *li;
7327
7328 l = argvars[0].vval.v_list;
7329 if (l != NULL)
7330 {
7331 li = l->lv_first;
7332 if (li != NULL)
7333 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007334 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007335 for (;;)
7336 {
7337 li = li->li_next;
7338 if (li == NULL)
7339 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007340 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 if (domax ? i > n : i < n)
7342 n = i;
7343 }
7344 }
7345 }
7346 }
7347 else if (argvars[0].v_type == VAR_DICT)
7348 {
7349 dict_T *d;
7350 int first = TRUE;
7351 hashitem_T *hi;
7352 int todo;
7353
7354 d = argvars[0].vval.v_dict;
7355 if (d != NULL)
7356 {
7357 todo = (int)d->dv_hashtab.ht_used;
7358 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7359 {
7360 if (!HASHITEM_EMPTY(hi))
7361 {
7362 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007363 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 if (first)
7365 {
7366 n = i;
7367 first = FALSE;
7368 }
7369 else if (domax ? i > n : i < n)
7370 n = i;
7371 }
7372 }
7373 }
7374 }
7375 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007376 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 rettv->vval.v_number = error ? 0 : n;
7378}
7379
7380/*
7381 * "max()" function
7382 */
7383 static void
7384f_max(typval_T *argvars, typval_T *rettv)
7385{
7386 max_min(argvars, rettv, TRUE);
7387}
7388
7389/*
7390 * "min()" function
7391 */
7392 static void
7393f_min(typval_T *argvars, typval_T *rettv)
7394{
7395 max_min(argvars, rettv, FALSE);
7396}
7397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398/*
7399 * Create the directory in which "dir" is located, and higher levels when
7400 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007401 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007402 */
7403 static int
7404mkdir_recurse(char_u *dir, int prot)
7405{
7406 char_u *p;
7407 char_u *updir;
7408 int r = FAIL;
7409
7410 /* Get end of directory name in "dir".
7411 * We're done when it's "/" or "c:/". */
7412 p = gettail_sep(dir);
7413 if (p <= get_past_head(dir))
7414 return OK;
7415
7416 /* If the directory exists we're done. Otherwise: create it.*/
7417 updir = vim_strnsave(dir, (int)(p - dir));
7418 if (updir == NULL)
7419 return FAIL;
7420 if (mch_isdir(updir))
7421 r = OK;
7422 else if (mkdir_recurse(updir, prot) == OK)
7423 r = vim_mkdir_emsg(updir, prot);
7424 vim_free(updir);
7425 return r;
7426}
7427
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428/*
7429 * "mkdir()" function
7430 */
7431 static void
7432f_mkdir(typval_T *argvars, typval_T *rettv)
7433{
7434 char_u *dir;
7435 char_u buf[NUMBUFLEN];
7436 int prot = 0755;
7437
7438 rettv->vval.v_number = FAIL;
7439 if (check_restricted() || check_secure())
7440 return;
7441
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007442 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007443 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007444 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007446 if (*gettail(dir) == NUL)
7447 /* remove trailing slashes */
7448 *gettail_sep(dir) = NUL;
7449
7450 if (argvars[1].v_type != VAR_UNKNOWN)
7451 {
7452 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007454 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007455 if (prot == -1)
7456 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007457 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007458 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007459 {
7460 if (mch_isdir(dir))
7461 {
7462 /* With the "p" flag it's OK if the dir already exists. */
7463 rettv->vval.v_number = OK;
7464 return;
7465 }
7466 mkdir_recurse(dir, prot);
7467 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007468 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007469 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471
7472/*
7473 * "mode()" function
7474 */
7475 static void
7476f_mode(typval_T *argvars, typval_T *rettv)
7477{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007478 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007479
Bram Moolenaar612cc382018-07-29 15:34:26 +02007480 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007481
7482 if (time_for_testing == 93784)
7483 {
7484 /* Testing the two-character code. */
7485 buf[0] = 'x';
7486 buf[1] = '!';
7487 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007488#ifdef FEAT_TERMINAL
7489 else if (term_use_loop())
7490 buf[0] = 't';
7491#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 else if (VIsual_active)
7493 {
7494 if (VIsual_select)
7495 buf[0] = VIsual_mode + 's' - 'v';
7496 else
7497 buf[0] = VIsual_mode;
7498 }
7499 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7500 || State == CONFIRM)
7501 {
7502 buf[0] = 'r';
7503 if (State == ASKMORE)
7504 buf[1] = 'm';
7505 else if (State == CONFIRM)
7506 buf[1] = '?';
7507 }
7508 else if (State == EXTERNCMD)
7509 buf[0] = '!';
7510 else if (State & INSERT)
7511 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512 if (State & VREPLACE_FLAG)
7513 {
7514 buf[0] = 'R';
7515 buf[1] = 'v';
7516 }
7517 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007518 {
7519 if (State & REPLACE_FLAG)
7520 buf[0] = 'R';
7521 else
7522 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007523 if (ins_compl_active())
7524 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007525 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007526 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007527 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007529 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007530 {
7531 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007532 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007533 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007534 else if (exmode_active == EXMODE_NORMAL)
7535 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007536 }
7537 else
7538 {
7539 buf[0] = 'n';
7540 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007541 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007543 // to be able to detect force-linewise/blockwise/characterwise operations
7544 buf[2] = motion_force;
7545 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007546 else if (restart_edit == 'I' || restart_edit == 'R'
7547 || restart_edit == 'V')
7548 {
7549 buf[1] = 'i';
7550 buf[2] = restart_edit;
7551 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 }
7553
7554 /* Clear out the minor mode when the argument is not a non-zero number or
7555 * non-empty string. */
7556 if (!non_zero_arg(&argvars[0]))
7557 buf[1] = NUL;
7558
7559 rettv->vval.v_string = vim_strsave(buf);
7560 rettv->v_type = VAR_STRING;
7561}
7562
7563#if defined(FEAT_MZSCHEME) || defined(PROTO)
7564/*
7565 * "mzeval()" function
7566 */
7567 static void
7568f_mzeval(typval_T *argvars, typval_T *rettv)
7569{
7570 char_u *str;
7571 char_u buf[NUMBUFLEN];
7572
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007573 if (check_restricted() || check_secure())
7574 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007575 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007576 do_mzeval(str, rettv);
7577}
7578
7579 void
7580mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7581{
7582 typval_T argvars[3];
7583
7584 argvars[0].v_type = VAR_STRING;
7585 argvars[0].vval.v_string = name;
7586 copy_tv(args, &argvars[1]);
7587 argvars[2].v_type = VAR_UNKNOWN;
7588 f_call(argvars, rettv);
7589 clear_tv(&argvars[1]);
7590}
7591#endif
7592
7593/*
7594 * "nextnonblank()" function
7595 */
7596 static void
7597f_nextnonblank(typval_T *argvars, typval_T *rettv)
7598{
7599 linenr_T lnum;
7600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007601 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007602 {
7603 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7604 {
7605 lnum = 0;
7606 break;
7607 }
7608 if (*skipwhite(ml_get(lnum)) != NUL)
7609 break;
7610 }
7611 rettv->vval.v_number = lnum;
7612}
7613
7614/*
7615 * "nr2char()" function
7616 */
7617 static void
7618f_nr2char(typval_T *argvars, typval_T *rettv)
7619{
7620 char_u buf[NUMBUFLEN];
7621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622 if (has_mbyte)
7623 {
7624 int utf8 = 0;
7625
7626 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007627 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007629 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007631 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 }
7633 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007635 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007636 buf[1] = NUL;
7637 }
7638 rettv->v_type = VAR_STRING;
7639 rettv->vval.v_string = vim_strsave(buf);
7640}
7641
7642/*
7643 * "or(expr, expr)" function
7644 */
7645 static void
7646f_or(typval_T *argvars, typval_T *rettv)
7647{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007648 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7649 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650}
7651
7652/*
7653 * "pathshorten()" function
7654 */
7655 static void
7656f_pathshorten(typval_T *argvars, typval_T *rettv)
7657{
7658 char_u *p;
7659
7660 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007661 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662 if (p == NULL)
7663 rettv->vval.v_string = NULL;
7664 else
7665 {
7666 p = vim_strsave(p);
7667 rettv->vval.v_string = p;
7668 if (p != NULL)
7669 shorten_dir(p);
7670 }
7671}
7672
7673#ifdef FEAT_PERL
7674/*
7675 * "perleval()" function
7676 */
7677 static void
7678f_perleval(typval_T *argvars, typval_T *rettv)
7679{
7680 char_u *str;
7681 char_u buf[NUMBUFLEN];
7682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007683 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007684 do_perleval(str, rettv);
7685}
7686#endif
7687
7688#ifdef FEAT_FLOAT
7689/*
7690 * "pow()" function
7691 */
7692 static void
7693f_pow(typval_T *argvars, typval_T *rettv)
7694{
7695 float_T fx = 0.0, fy = 0.0;
7696
7697 rettv->v_type = VAR_FLOAT;
7698 if (get_float_arg(argvars, &fx) == OK
7699 && get_float_arg(&argvars[1], &fy) == OK)
7700 rettv->vval.v_float = pow(fx, fy);
7701 else
7702 rettv->vval.v_float = 0.0;
7703}
7704#endif
7705
7706/*
7707 * "prevnonblank()" function
7708 */
7709 static void
7710f_prevnonblank(typval_T *argvars, typval_T *rettv)
7711{
7712 linenr_T lnum;
7713
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007714 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007715 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7716 lnum = 0;
7717 else
7718 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7719 --lnum;
7720 rettv->vval.v_number = lnum;
7721}
7722
7723/* This dummy va_list is here because:
7724 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7725 * - locally in the function results in a "used before set" warning
7726 * - using va_start() to initialize it gives "function with fixed args" error */
7727static va_list ap;
7728
7729/*
7730 * "printf()" function
7731 */
7732 static void
7733f_printf(typval_T *argvars, typval_T *rettv)
7734{
7735 char_u buf[NUMBUFLEN];
7736 int len;
7737 char_u *s;
7738 int saved_did_emsg = did_emsg;
7739 char *fmt;
7740
7741 rettv->v_type = VAR_STRING;
7742 rettv->vval.v_string = NULL;
7743
7744 /* Get the required length, allocate the buffer and do it for real. */
7745 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007746 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007747 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 if (!did_emsg)
7749 {
7750 s = alloc(len + 1);
7751 if (s != NULL)
7752 {
7753 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007754 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7755 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 }
7757 }
7758 did_emsg |= saved_did_emsg;
7759}
7760
7761/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007762 * "pum_getpos()" function
7763 */
7764 static void
7765f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7766{
7767 if (rettv_dict_alloc(rettv) != OK)
7768 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007769 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007770}
7771
7772/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007773 * "pumvisible()" function
7774 */
7775 static void
7776f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7777{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 if (pum_visible())
7779 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780}
7781
7782#ifdef FEAT_PYTHON3
7783/*
7784 * "py3eval()" function
7785 */
7786 static void
7787f_py3eval(typval_T *argvars, typval_T *rettv)
7788{
7789 char_u *str;
7790 char_u buf[NUMBUFLEN];
7791
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007792 if (check_restricted() || check_secure())
7793 return;
7794
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007795 if (p_pyx == 0)
7796 p_pyx = 3;
7797
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007798 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799 do_py3eval(str, rettv);
7800}
7801#endif
7802
7803#ifdef FEAT_PYTHON
7804/*
7805 * "pyeval()" function
7806 */
7807 static void
7808f_pyeval(typval_T *argvars, typval_T *rettv)
7809{
7810 char_u *str;
7811 char_u buf[NUMBUFLEN];
7812
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007813 if (check_restricted() || check_secure())
7814 return;
7815
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007816 if (p_pyx == 0)
7817 p_pyx = 2;
7818
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007819 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007820 do_pyeval(str, rettv);
7821}
7822#endif
7823
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007824#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7825/*
7826 * "pyxeval()" function
7827 */
7828 static void
7829f_pyxeval(typval_T *argvars, typval_T *rettv)
7830{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007831 if (check_restricted() || check_secure())
7832 return;
7833
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007834# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7835 init_pyxversion();
7836 if (p_pyx == 2)
7837 f_pyeval(argvars, rettv);
7838 else
7839 f_py3eval(argvars, rettv);
7840# elif defined(FEAT_PYTHON)
7841 f_pyeval(argvars, rettv);
7842# elif defined(FEAT_PYTHON3)
7843 f_py3eval(argvars, rettv);
7844# endif
7845}
7846#endif
7847
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848/*
7849 * "range()" function
7850 */
7851 static void
7852f_range(typval_T *argvars, typval_T *rettv)
7853{
7854 varnumber_T start;
7855 varnumber_T end;
7856 varnumber_T stride = 1;
7857 varnumber_T i;
7858 int error = FALSE;
7859
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007860 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 if (argvars[1].v_type == VAR_UNKNOWN)
7862 {
7863 end = start - 1;
7864 start = 0;
7865 }
7866 else
7867 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007868 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007869 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007870 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 }
7872
7873 if (error)
7874 return; /* type error; errmsg already given */
7875 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007876 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007877 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007878 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007879 else
7880 {
7881 if (rettv_list_alloc(rettv) == OK)
7882 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7883 if (list_append_number(rettv->vval.v_list,
7884 (varnumber_T)i) == FAIL)
7885 break;
7886 }
7887}
7888
7889/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007890 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007891 */
7892 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007893readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007894{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007895 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007896 typval_T save_val;
7897 typval_T rettv;
7898 typval_T argv[2];
7899 int retval = 0;
7900 int error = FALSE;
7901
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007902 if (expr->v_type == VAR_UNKNOWN)
7903 return 1;
7904
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007905 prepare_vimvar(VV_VAL, &save_val);
7906 set_vim_var_string(VV_VAL, name, -1);
7907 argv[0].v_type = VAR_STRING;
7908 argv[0].vval.v_string = name;
7909
7910 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
7911 goto theend;
7912
7913 retval = tv_get_number_chk(&rettv, &error);
7914 if (error)
7915 retval = -1;
7916 clear_tv(&rettv);
7917
7918theend:
7919 set_vim_var_string(VV_VAL, NULL, 0);
7920 restore_vimvar(VV_VAL, &save_val);
7921 return retval;
7922}
7923
7924/*
7925 * "readdir()" function
7926 */
7927 static void
7928f_readdir(typval_T *argvars, typval_T *rettv)
7929{
7930 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007931 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007932 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007933 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007934 garray_T ga;
7935 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007936
7937 if (rettv_list_alloc(rettv) == FAIL)
7938 return;
7939 path = tv_get_string(&argvars[0]);
7940 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007941
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007942 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
7943 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007944 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007945 for (i = 0; i < ga.ga_len; i++)
7946 {
7947 p = ((char_u **)ga.ga_data)[i];
7948 list_append_string(rettv->vval.v_list, p, -1);
7949 }
7950 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02007951 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007952}
7953
7954/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 * "readfile()" function
7956 */
7957 static void
7958f_readfile(typval_T *argvars, typval_T *rettv)
7959{
7960 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007961 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962 int failed = FALSE;
7963 char_u *fname;
7964 FILE *fd;
7965 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
7966 int io_size = sizeof(buf);
7967 int readlen; /* size of last fread() */
7968 char_u *prev = NULL; /* previously read bytes, if any */
7969 long prevlen = 0; /* length of data in prev */
7970 long prevsize = 0; /* size of prev buffer */
7971 long maxline = MAXLNUM;
7972 long cnt = 0;
7973 char_u *p; /* position in buf */
7974 char_u *start; /* start of current line */
7975
7976 if (argvars[1].v_type != VAR_UNKNOWN)
7977 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007978 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007980 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
7981 blob = TRUE;
7982
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007984 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985 }
7986
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007987 if (blob)
7988 {
7989 if (rettv_blob_alloc(rettv) == FAIL)
7990 return;
7991 }
7992 else
7993 {
7994 if (rettv_list_alloc(rettv) == FAIL)
7995 return;
7996 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997
7998 /* Always open the file in binary mode, library functions have a mind of
7999 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008000 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8002 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008003 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 return;
8005 }
8006
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008007 if (blob)
8008 {
8009 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8010 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008011 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008012 blob_free(rettv->vval.v_blob);
8013 }
8014 fclose(fd);
8015 return;
8016 }
8017
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018 while (cnt < maxline || maxline < 0)
8019 {
8020 readlen = (int)fread(buf, 1, io_size, fd);
8021
8022 /* This for loop processes what was read, but is also entered at end
8023 * of file so that either:
8024 * - an incomplete line gets written
8025 * - a "binary" file gets an empty line at the end if it ends in a
8026 * newline. */
8027 for (p = buf, start = buf;
8028 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8029 ++p)
8030 {
8031 if (*p == '\n' || readlen <= 0)
8032 {
8033 listitem_T *li;
8034 char_u *s = NULL;
8035 long_u len = p - start;
8036
8037 /* Finished a line. Remove CRs before NL. */
8038 if (readlen > 0 && !binary)
8039 {
8040 while (len > 0 && start[len - 1] == '\r')
8041 --len;
8042 /* removal may cross back to the "prev" string */
8043 if (len == 0)
8044 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8045 --prevlen;
8046 }
8047 if (prevlen == 0)
8048 s = vim_strnsave(start, (int)len);
8049 else
8050 {
8051 /* Change "prev" buffer to be the right size. This way
8052 * the bytes are only copied once, and very long lines are
8053 * allocated only once. */
8054 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8055 {
8056 mch_memmove(s + prevlen, start, len);
8057 s[prevlen + len] = NUL;
8058 prev = NULL; /* the list will own the string */
8059 prevlen = prevsize = 0;
8060 }
8061 }
8062 if (s == NULL)
8063 {
8064 do_outofmem_msg((long_u) prevlen + len + 1);
8065 failed = TRUE;
8066 break;
8067 }
8068
8069 if ((li = listitem_alloc()) == NULL)
8070 {
8071 vim_free(s);
8072 failed = TRUE;
8073 break;
8074 }
8075 li->li_tv.v_type = VAR_STRING;
8076 li->li_tv.v_lock = 0;
8077 li->li_tv.vval.v_string = s;
8078 list_append(rettv->vval.v_list, li);
8079
8080 start = p + 1; /* step over newline */
8081 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8082 break;
8083 }
8084 else if (*p == NUL)
8085 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8087 * when finding the BF and check the previous two bytes. */
8088 else if (*p == 0xbf && enc_utf8 && !binary)
8089 {
8090 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8091 * + 1, these may be in the "prev" string. */
8092 char_u back1 = p >= buf + 1 ? p[-1]
8093 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8094 char_u back2 = p >= buf + 2 ? p[-2]
8095 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8096 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8097
8098 if (back2 == 0xef && back1 == 0xbb)
8099 {
8100 char_u *dest = p - 2;
8101
8102 /* Usually a BOM is at the beginning of a file, and so at
8103 * the beginning of a line; then we can just step over it.
8104 */
8105 if (start == dest)
8106 start = p + 1;
8107 else
8108 {
8109 /* have to shuffle buf to close gap */
8110 int adjust_prevlen = 0;
8111
8112 if (dest < buf)
8113 {
8114 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8115 dest = buf;
8116 }
8117 if (readlen > p - buf + 1)
8118 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8119 readlen -= 3 - adjust_prevlen;
8120 prevlen -= adjust_prevlen;
8121 p = dest - 1;
8122 }
8123 }
8124 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 } /* for */
8126
8127 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8128 break;
8129 if (start < p)
8130 {
8131 /* There's part of a line in buf, store it in "prev". */
8132 if (p - start + prevlen >= prevsize)
8133 {
8134 /* need bigger "prev" buffer */
8135 char_u *newprev;
8136
8137 /* A common use case is ordinary text files and "prev" gets a
8138 * fragment of a line, so the first allocation is made
8139 * small, to avoid repeatedly 'allocing' large and
8140 * 'reallocing' small. */
8141 if (prevsize == 0)
8142 prevsize = (long)(p - start);
8143 else
8144 {
8145 long grow50pc = (prevsize * 3) / 2;
8146 long growmin = (long)((p - start) * 2 + prevlen);
8147 prevsize = grow50pc > growmin ? grow50pc : growmin;
8148 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008149 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150 if (newprev == NULL)
8151 {
8152 do_outofmem_msg((long_u)prevsize);
8153 failed = TRUE;
8154 break;
8155 }
8156 prev = newprev;
8157 }
8158 /* Add the line part to end of "prev". */
8159 mch_memmove(prev + prevlen, start, p - start);
8160 prevlen += (long)(p - start);
8161 }
8162 } /* while */
8163
8164 /*
8165 * For a negative line count use only the lines at the end of the file,
8166 * free the rest.
8167 */
8168 if (!failed && maxline < 0)
8169 while (cnt > -maxline)
8170 {
8171 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8172 --cnt;
8173 }
8174
8175 if (failed)
8176 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008177 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008179 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180 }
8181
8182 vim_free(prev);
8183 fclose(fd);
8184}
8185
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008186 static void
8187return_register(int regname, typval_T *rettv)
8188{
8189 char_u buf[2] = {0, 0};
8190
8191 buf[0] = (char_u)regname;
8192 rettv->v_type = VAR_STRING;
8193 rettv->vval.v_string = vim_strsave(buf);
8194}
8195
8196/*
8197 * "reg_executing()" function
8198 */
8199 static void
8200f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8201{
8202 return_register(reg_executing, rettv);
8203}
8204
8205/*
8206 * "reg_recording()" function
8207 */
8208 static void
8209f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8210{
8211 return_register(reg_recording, rettv);
8212}
8213
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008214#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215/*
8216 * Convert a List to proftime_T.
8217 * Return FAIL when there is something wrong.
8218 */
8219 static int
8220list2proftime(typval_T *arg, proftime_T *tm)
8221{
8222 long n1, n2;
8223 int error = FALSE;
8224
8225 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8226 || arg->vval.v_list->lv_len != 2)
8227 return FAIL;
8228 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8229 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008230# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008231 tm->HighPart = n1;
8232 tm->LowPart = n2;
8233# else
8234 tm->tv_sec = n1;
8235 tm->tv_usec = n2;
8236# endif
8237 return error ? FAIL : OK;
8238}
8239#endif /* FEAT_RELTIME */
8240
8241/*
8242 * "reltime()" function
8243 */
8244 static void
8245f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8246{
8247#ifdef FEAT_RELTIME
8248 proftime_T res;
8249 proftime_T start;
8250
8251 if (argvars[0].v_type == VAR_UNKNOWN)
8252 {
8253 /* No arguments: get current time. */
8254 profile_start(&res);
8255 }
8256 else if (argvars[1].v_type == VAR_UNKNOWN)
8257 {
8258 if (list2proftime(&argvars[0], &res) == FAIL)
8259 return;
8260 profile_end(&res);
8261 }
8262 else
8263 {
8264 /* Two arguments: compute the difference. */
8265 if (list2proftime(&argvars[0], &start) == FAIL
8266 || list2proftime(&argvars[1], &res) == FAIL)
8267 return;
8268 profile_sub(&res, &start);
8269 }
8270
8271 if (rettv_list_alloc(rettv) == OK)
8272 {
8273 long n1, n2;
8274
Bram Moolenaar4f974752019-02-17 17:44:42 +01008275# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008276 n1 = res.HighPart;
8277 n2 = res.LowPart;
8278# else
8279 n1 = res.tv_sec;
8280 n2 = res.tv_usec;
8281# endif
8282 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8283 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8284 }
8285#endif
8286}
8287
8288#ifdef FEAT_FLOAT
8289/*
8290 * "reltimefloat()" function
8291 */
8292 static void
8293f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8294{
8295# ifdef FEAT_RELTIME
8296 proftime_T tm;
8297# endif
8298
8299 rettv->v_type = VAR_FLOAT;
8300 rettv->vval.v_float = 0;
8301# ifdef FEAT_RELTIME
8302 if (list2proftime(&argvars[0], &tm) == OK)
8303 rettv->vval.v_float = profile_float(&tm);
8304# endif
8305}
8306#endif
8307
8308/*
8309 * "reltimestr()" function
8310 */
8311 static void
8312f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8313{
8314#ifdef FEAT_RELTIME
8315 proftime_T tm;
8316#endif
8317
8318 rettv->v_type = VAR_STRING;
8319 rettv->vval.v_string = NULL;
8320#ifdef FEAT_RELTIME
8321 if (list2proftime(&argvars[0], &tm) == OK)
8322 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8323#endif
8324}
8325
8326#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008327 static void
8328make_connection(void)
8329{
8330 if (X_DISPLAY == NULL
8331# ifdef FEAT_GUI
8332 && !gui.in_use
8333# endif
8334 )
8335 {
8336 x_force_connect = TRUE;
8337 setup_term_clip();
8338 x_force_connect = FALSE;
8339 }
8340}
8341
8342 static int
8343check_connection(void)
8344{
8345 make_connection();
8346 if (X_DISPLAY == NULL)
8347 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008348 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008349 return FAIL;
8350 }
8351 return OK;
8352}
8353#endif
8354
8355#ifdef FEAT_CLIENTSERVER
8356 static void
8357remote_common(typval_T *argvars, typval_T *rettv, int expr)
8358{
8359 char_u *server_name;
8360 char_u *keys;
8361 char_u *r = NULL;
8362 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008363 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008364# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365 HWND w;
8366# else
8367 Window w;
8368# endif
8369
8370 if (check_restricted() || check_secure())
8371 return;
8372
8373# ifdef FEAT_X11
8374 if (check_connection() == FAIL)
8375 return;
8376# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008377 if (argvars[2].v_type != VAR_UNKNOWN
8378 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008379 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008380
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008381 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 if (server_name == NULL)
8383 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008384 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008385# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008386 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008388 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8389 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390# endif
8391 {
8392 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008393 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008394 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008395 vim_free(r);
8396 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008397 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008398 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008399 return;
8400 }
8401
8402 rettv->vval.v_string = r;
8403
8404 if (argvars[2].v_type != VAR_UNKNOWN)
8405 {
8406 dictitem_T v;
8407 char_u str[30];
8408 char_u *idvar;
8409
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008410 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008411 if (idvar != NULL && *idvar != NUL)
8412 {
8413 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8414 v.di_tv.v_type = VAR_STRING;
8415 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008417 vim_free(v.di_tv.vval.v_string);
8418 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008419 }
8420}
8421#endif
8422
8423/*
8424 * "remote_expr()" function
8425 */
8426 static void
8427f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8428{
8429 rettv->v_type = VAR_STRING;
8430 rettv->vval.v_string = NULL;
8431#ifdef FEAT_CLIENTSERVER
8432 remote_common(argvars, rettv, TRUE);
8433#endif
8434}
8435
8436/*
8437 * "remote_foreground()" function
8438 */
8439 static void
8440f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8441{
8442#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008443# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008444 /* On Win32 it's done in this application. */
8445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008446 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008447
8448 if (server_name != NULL)
8449 serverForeground(server_name);
8450 }
8451# else
8452 /* Send a foreground() expression to the server. */
8453 argvars[1].v_type = VAR_STRING;
8454 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8455 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008456 rettv->v_type = VAR_STRING;
8457 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458 remote_common(argvars, rettv, TRUE);
8459 vim_free(argvars[1].vval.v_string);
8460# endif
8461#endif
8462}
8463
8464 static void
8465f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8466{
8467#ifdef FEAT_CLIENTSERVER
8468 dictitem_T v;
8469 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008470# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 long_u n = 0;
8472# endif
8473 char_u *serverid;
8474
8475 if (check_restricted() || check_secure())
8476 {
8477 rettv->vval.v_number = -1;
8478 return;
8479 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008480 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008481 if (serverid == NULL)
8482 {
8483 rettv->vval.v_number = -1;
8484 return; /* type error; errmsg already given */
8485 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008486# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8488 if (n == 0)
8489 rettv->vval.v_number = -1;
8490 else
8491 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008492 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008493 rettv->vval.v_number = (s != NULL);
8494 }
8495# else
8496 if (check_connection() == FAIL)
8497 return;
8498
8499 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8500 serverStrToWin(serverid), &s);
8501# endif
8502
8503 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8504 {
8505 char_u *retvar;
8506
8507 v.di_tv.v_type = VAR_STRING;
8508 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008509 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008510 if (retvar != NULL)
8511 set_var(retvar, &v.di_tv, FALSE);
8512 vim_free(v.di_tv.vval.v_string);
8513 }
8514#else
8515 rettv->vval.v_number = -1;
8516#endif
8517}
8518
8519 static void
8520f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8521{
8522 char_u *r = NULL;
8523
8524#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008525 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008526
8527 if (serverid != NULL && !check_restricted() && !check_secure())
8528 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008529 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008530# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008531 /* The server's HWND is encoded in the 'id' parameter */
8532 long_u n = 0;
8533# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008534
8535 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008536 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008537
Bram Moolenaar4f974752019-02-17 17:44:42 +01008538# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008539 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8540 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008541 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542 if (r == NULL)
8543# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008544 if (check_connection() == FAIL
8545 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8546 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008548 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008549 }
8550#endif
8551 rettv->v_type = VAR_STRING;
8552 rettv->vval.v_string = r;
8553}
8554
8555/*
8556 * "remote_send()" function
8557 */
8558 static void
8559f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8560{
8561 rettv->v_type = VAR_STRING;
8562 rettv->vval.v_string = NULL;
8563#ifdef FEAT_CLIENTSERVER
8564 remote_common(argvars, rettv, FALSE);
8565#endif
8566}
8567
8568/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008569 * "remote_startserver()" function
8570 */
8571 static void
8572f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8573{
8574#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008575 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008576
8577 if (server == NULL)
8578 return; /* type error; errmsg already given */
8579 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008580 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008581 else
8582 {
8583# ifdef FEAT_X11
8584 if (check_connection() == OK)
8585 serverRegisterName(X_DISPLAY, server);
8586# else
8587 serverSetName(server);
8588# endif
8589 }
8590#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008591 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008592#endif
8593}
8594
8595/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 * "remove()" function
8597 */
8598 static void
8599f_remove(typval_T *argvars, typval_T *rettv)
8600{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8602
8603 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008604 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008605 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008606 blob_remove(argvars, rettv);
8607 else if (argvars[0].v_type == VAR_LIST)
8608 list_remove(argvars, rettv, arg_errmsg);
8609 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008610 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611}
8612
8613/*
8614 * "rename({from}, {to})" function
8615 */
8616 static void
8617f_rename(typval_T *argvars, typval_T *rettv)
8618{
8619 char_u buf[NUMBUFLEN];
8620
8621 if (check_restricted() || check_secure())
8622 rettv->vval.v_number = -1;
8623 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008624 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8625 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626}
8627
8628/*
8629 * "repeat()" function
8630 */
8631 static void
8632f_repeat(typval_T *argvars, typval_T *rettv)
8633{
8634 char_u *p;
8635 int n;
8636 int slen;
8637 int len;
8638 char_u *r;
8639 int i;
8640
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008641 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008642 if (argvars[0].v_type == VAR_LIST)
8643 {
8644 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8645 while (n-- > 0)
8646 if (list_extend(rettv->vval.v_list,
8647 argvars[0].vval.v_list, NULL) == FAIL)
8648 break;
8649 }
8650 else
8651 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008652 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008653 rettv->v_type = VAR_STRING;
8654 rettv->vval.v_string = NULL;
8655
8656 slen = (int)STRLEN(p);
8657 len = slen * n;
8658 if (len <= 0)
8659 return;
8660
8661 r = alloc(len + 1);
8662 if (r != NULL)
8663 {
8664 for (i = 0; i < n; i++)
8665 mch_memmove(r + i * slen, p, (size_t)slen);
8666 r[len] = NUL;
8667 }
8668
8669 rettv->vval.v_string = r;
8670 }
8671}
8672
8673/*
8674 * "resolve()" function
8675 */
8676 static void
8677f_resolve(typval_T *argvars, typval_T *rettv)
8678{
8679 char_u *p;
8680#ifdef HAVE_READLINK
8681 char_u *buf = NULL;
8682#endif
8683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008684 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008685#ifdef FEAT_SHORTCUT
8686 {
8687 char_u *v = NULL;
8688
Bram Moolenaardce1e892019-02-10 23:18:53 +01008689 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690 if (v != NULL)
8691 rettv->vval.v_string = v;
8692 else
8693 rettv->vval.v_string = vim_strsave(p);
8694 }
8695#else
8696# ifdef HAVE_READLINK
8697 {
8698 char_u *cpy;
8699 int len;
8700 char_u *remain = NULL;
8701 char_u *q;
8702 int is_relative_to_current = FALSE;
8703 int has_trailing_pathsep = FALSE;
8704 int limit = 100;
8705
8706 p = vim_strsave(p);
8707
8708 if (p[0] == '.' && (vim_ispathsep(p[1])
8709 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8710 is_relative_to_current = TRUE;
8711
8712 len = STRLEN(p);
8713 if (len > 0 && after_pathsep(p, p + len))
8714 {
8715 has_trailing_pathsep = TRUE;
8716 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8717 }
8718
8719 q = getnextcomp(p);
8720 if (*q != NUL)
8721 {
8722 /* Separate the first path component in "p", and keep the
8723 * remainder (beginning with the path separator). */
8724 remain = vim_strsave(q - 1);
8725 q[-1] = NUL;
8726 }
8727
8728 buf = alloc(MAXPATHL + 1);
8729 if (buf == NULL)
8730 goto fail;
8731
8732 for (;;)
8733 {
8734 for (;;)
8735 {
8736 len = readlink((char *)p, (char *)buf, MAXPATHL);
8737 if (len <= 0)
8738 break;
8739 buf[len] = NUL;
8740
8741 if (limit-- == 0)
8742 {
8743 vim_free(p);
8744 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008745 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 rettv->vval.v_string = NULL;
8747 goto fail;
8748 }
8749
8750 /* Ensure that the result will have a trailing path separator
8751 * if the argument has one. */
8752 if (remain == NULL && has_trailing_pathsep)
8753 add_pathsep(buf);
8754
8755 /* Separate the first path component in the link value and
8756 * concatenate the remainders. */
8757 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8758 if (*q != NUL)
8759 {
8760 if (remain == NULL)
8761 remain = vim_strsave(q - 1);
8762 else
8763 {
8764 cpy = concat_str(q - 1, remain);
8765 if (cpy != NULL)
8766 {
8767 vim_free(remain);
8768 remain = cpy;
8769 }
8770 }
8771 q[-1] = NUL;
8772 }
8773
8774 q = gettail(p);
8775 if (q > p && *q == NUL)
8776 {
8777 /* Ignore trailing path separator. */
8778 q[-1] = NUL;
8779 q = gettail(p);
8780 }
8781 if (q > p && !mch_isFullName(buf))
8782 {
8783 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008784 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 if (cpy != NULL)
8786 {
8787 STRCPY(cpy, p);
8788 STRCPY(gettail(cpy), buf);
8789 vim_free(p);
8790 p = cpy;
8791 }
8792 }
8793 else
8794 {
8795 vim_free(p);
8796 p = vim_strsave(buf);
8797 }
8798 }
8799
8800 if (remain == NULL)
8801 break;
8802
8803 /* Append the first path component of "remain" to "p". */
8804 q = getnextcomp(remain + 1);
8805 len = q - remain - (*q != NUL);
8806 cpy = vim_strnsave(p, STRLEN(p) + len);
8807 if (cpy != NULL)
8808 {
8809 STRNCAT(cpy, remain, len);
8810 vim_free(p);
8811 p = cpy;
8812 }
8813 /* Shorten "remain". */
8814 if (*q != NUL)
8815 STRMOVE(remain, q - 1);
8816 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008817 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008818 }
8819
8820 /* If the result is a relative path name, make it explicitly relative to
8821 * the current directory if and only if the argument had this form. */
8822 if (!vim_ispathsep(*p))
8823 {
8824 if (is_relative_to_current
8825 && *p != NUL
8826 && !(p[0] == '.'
8827 && (p[1] == NUL
8828 || vim_ispathsep(p[1])
8829 || (p[1] == '.'
8830 && (p[2] == NUL
8831 || vim_ispathsep(p[2]))))))
8832 {
8833 /* Prepend "./". */
8834 cpy = concat_str((char_u *)"./", p);
8835 if (cpy != NULL)
8836 {
8837 vim_free(p);
8838 p = cpy;
8839 }
8840 }
8841 else if (!is_relative_to_current)
8842 {
8843 /* Strip leading "./". */
8844 q = p;
8845 while (q[0] == '.' && vim_ispathsep(q[1]))
8846 q += 2;
8847 if (q > p)
8848 STRMOVE(p, p + 2);
8849 }
8850 }
8851
8852 /* Ensure that the result will have no trailing path separator
8853 * if the argument had none. But keep "/" or "//". */
8854 if (!has_trailing_pathsep)
8855 {
8856 q = p + STRLEN(p);
8857 if (after_pathsep(p, q))
8858 *gettail_sep(p) = NUL;
8859 }
8860
8861 rettv->vval.v_string = p;
8862 }
8863# else
8864 rettv->vval.v_string = vim_strsave(p);
8865# endif
8866#endif
8867
8868 simplify_filename(rettv->vval.v_string);
8869
8870#ifdef HAVE_READLINK
8871fail:
8872 vim_free(buf);
8873#endif
8874 rettv->v_type = VAR_STRING;
8875}
8876
8877/*
8878 * "reverse({list})" function
8879 */
8880 static void
8881f_reverse(typval_T *argvars, typval_T *rettv)
8882{
8883 list_T *l;
8884 listitem_T *li, *ni;
8885
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008886 if (argvars[0].v_type == VAR_BLOB)
8887 {
8888 blob_T *b = argvars[0].vval.v_blob;
8889 int i, len = blob_len(b);
8890
8891 for (i = 0; i < len / 2; i++)
8892 {
8893 int tmp = blob_get(b, i);
8894
8895 blob_set(b, i, blob_get(b, len - i - 1));
8896 blob_set(b, len - i - 1, tmp);
8897 }
8898 rettv_blob_set(rettv, b);
8899 return;
8900 }
8901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008903 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008904 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01008905 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008906 (char_u *)N_("reverse() argument"), TRUE))
8907 {
8908 li = l->lv_last;
8909 l->lv_first = l->lv_last = NULL;
8910 l->lv_len = 0;
8911 while (li != NULL)
8912 {
8913 ni = li->li_prev;
8914 list_append(l, li);
8915 li = ni;
8916 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008917 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008918 l->lv_idx = l->lv_len - l->lv_idx - 1;
8919 }
8920}
8921
8922#define SP_NOMOVE 0x01 /* don't move cursor */
8923#define SP_REPEAT 0x02 /* repeat to find outer pair */
8924#define SP_RETCOUNT 0x04 /* return matchcount */
8925#define SP_SETPCMARK 0x08 /* set previous context mark */
8926#define SP_START 0x10 /* accept match at start position */
8927#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
8928#define SP_END 0x40 /* leave cursor at end of match */
8929#define SP_COLUMN 0x80 /* start at cursor column */
8930
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008931/*
8932 * Get flags for a search function.
8933 * Possibly sets "p_ws".
8934 * Returns BACKWARD, FORWARD or zero (for an error).
8935 */
8936 static int
8937get_search_arg(typval_T *varp, int *flagsp)
8938{
8939 int dir = FORWARD;
8940 char_u *flags;
8941 char_u nbuf[NUMBUFLEN];
8942 int mask;
8943
8944 if (varp->v_type != VAR_UNKNOWN)
8945 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008946 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008947 if (flags == NULL)
8948 return 0; /* type error; errmsg already given */
8949 while (*flags != NUL)
8950 {
8951 switch (*flags)
8952 {
8953 case 'b': dir = BACKWARD; break;
8954 case 'w': p_ws = TRUE; break;
8955 case 'W': p_ws = FALSE; break;
8956 default: mask = 0;
8957 if (flagsp != NULL)
8958 switch (*flags)
8959 {
8960 case 'c': mask = SP_START; break;
8961 case 'e': mask = SP_END; break;
8962 case 'm': mask = SP_RETCOUNT; break;
8963 case 'n': mask = SP_NOMOVE; break;
8964 case 'p': mask = SP_SUBPAT; break;
8965 case 'r': mask = SP_REPEAT; break;
8966 case 's': mask = SP_SETPCMARK; break;
8967 case 'z': mask = SP_COLUMN; break;
8968 }
8969 if (mask == 0)
8970 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008971 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008972 dir = 0;
8973 }
8974 else
8975 *flagsp |= mask;
8976 }
8977 if (dir == 0)
8978 break;
8979 ++flags;
8980 }
8981 }
8982 return dir;
8983}
8984
8985/*
8986 * Shared by search() and searchpos() functions.
8987 */
8988 static int
8989search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8990{
8991 int flags;
8992 char_u *pat;
8993 pos_T pos;
8994 pos_T save_cursor;
8995 int save_p_ws = p_ws;
8996 int dir;
8997 int retval = 0; /* default: FAIL */
8998 long lnum_stop = 0;
8999 proftime_T tm;
9000#ifdef FEAT_RELTIME
9001 long time_limit = 0;
9002#endif
9003 int options = SEARCH_KEEP;
9004 int subpatnum;
9005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009006 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009007 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9008 if (dir == 0)
9009 goto theend;
9010 flags = *flagsp;
9011 if (flags & SP_START)
9012 options |= SEARCH_START;
9013 if (flags & SP_END)
9014 options |= SEARCH_END;
9015 if (flags & SP_COLUMN)
9016 options |= SEARCH_COL;
9017
9018 /* Optional arguments: line number to stop searching and timeout. */
9019 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009021 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022 if (lnum_stop < 0)
9023 goto theend;
9024#ifdef FEAT_RELTIME
9025 if (argvars[3].v_type != VAR_UNKNOWN)
9026 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009027 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009028 if (time_limit < 0)
9029 goto theend;
9030 }
9031#endif
9032 }
9033
9034#ifdef FEAT_RELTIME
9035 /* Set the time limit, if there is one. */
9036 profile_setlimit(time_limit, &tm);
9037#endif
9038
9039 /*
9040 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9041 * Check to make sure only those flags are set.
9042 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9043 * flags cannot be set. Check for that condition also.
9044 */
9045 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9046 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9047 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009048 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009049 goto theend;
9050 }
9051
9052 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009053 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009054 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009055 if (subpatnum != FAIL)
9056 {
9057 if (flags & SP_SUBPAT)
9058 retval = subpatnum;
9059 else
9060 retval = pos.lnum;
9061 if (flags & SP_SETPCMARK)
9062 setpcmark();
9063 curwin->w_cursor = pos;
9064 if (match_pos != NULL)
9065 {
9066 /* Store the match cursor position */
9067 match_pos->lnum = pos.lnum;
9068 match_pos->col = pos.col + 1;
9069 }
9070 /* "/$" will put the cursor after the end of the line, may need to
9071 * correct that here */
9072 check_cursor();
9073 }
9074
9075 /* If 'n' flag is used: restore cursor position. */
9076 if (flags & SP_NOMOVE)
9077 curwin->w_cursor = save_cursor;
9078 else
9079 curwin->w_set_curswant = TRUE;
9080theend:
9081 p_ws = save_p_ws;
9082
9083 return retval;
9084}
9085
9086#ifdef FEAT_FLOAT
9087
9088/*
9089 * round() is not in C90, use ceil() or floor() instead.
9090 */
9091 float_T
9092vim_round(float_T f)
9093{
9094 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9095}
9096
9097/*
9098 * "round({float})" function
9099 */
9100 static void
9101f_round(typval_T *argvars, typval_T *rettv)
9102{
9103 float_T f = 0.0;
9104
9105 rettv->v_type = VAR_FLOAT;
9106 if (get_float_arg(argvars, &f) == OK)
9107 rettv->vval.v_float = vim_round(f);
9108 else
9109 rettv->vval.v_float = 0.0;
9110}
9111#endif
9112
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009113#ifdef FEAT_RUBY
9114/*
9115 * "rubyeval()" function
9116 */
9117 static void
9118f_rubyeval(typval_T *argvars, typval_T *rettv)
9119{
9120 char_u *str;
9121 char_u buf[NUMBUFLEN];
9122
9123 str = tv_get_string_buf(&argvars[0], buf);
9124 do_rubyeval(str, rettv);
9125}
9126#endif
9127
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009128/*
9129 * "screenattr()" function
9130 */
9131 static void
9132f_screenattr(typval_T *argvars, typval_T *rettv)
9133{
9134 int row;
9135 int col;
9136 int c;
9137
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009138 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9139 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009140 if (row < 0 || row >= screen_Rows
9141 || col < 0 || col >= screen_Columns)
9142 c = -1;
9143 else
9144 c = ScreenAttrs[LineOffset[row] + col];
9145 rettv->vval.v_number = c;
9146}
9147
9148/*
9149 * "screenchar()" function
9150 */
9151 static void
9152f_screenchar(typval_T *argvars, typval_T *rettv)
9153{
9154 int row;
9155 int col;
9156 int off;
9157 int c;
9158
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009159 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9160 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009161 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009162 c = -1;
9163 else
9164 {
9165 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009166 if (enc_utf8 && ScreenLinesUC[off] != 0)
9167 c = ScreenLinesUC[off];
9168 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009169 c = ScreenLines[off];
9170 }
9171 rettv->vval.v_number = c;
9172}
9173
9174/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009175 * "screenchars()" function
9176 */
9177 static void
9178f_screenchars(typval_T *argvars, typval_T *rettv)
9179{
9180 int row;
9181 int col;
9182 int off;
9183 int c;
9184 int i;
9185
9186 if (rettv_list_alloc(rettv) == FAIL)
9187 return;
9188 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9189 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9190 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9191 return;
9192
9193 off = LineOffset[row] + col;
9194 if (enc_utf8 && ScreenLinesUC[off] != 0)
9195 c = ScreenLinesUC[off];
9196 else
9197 c = ScreenLines[off];
9198 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9199
9200 if (enc_utf8)
9201
9202 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9203 list_append_number(rettv->vval.v_list,
9204 (varnumber_T)ScreenLinesC[i][off]);
9205}
9206
9207/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009208 * "screencol()" function
9209 *
9210 * First column is 1 to be consistent with virtcol().
9211 */
9212 static void
9213f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9214{
9215 rettv->vval.v_number = screen_screencol() + 1;
9216}
9217
9218/*
9219 * "screenrow()" function
9220 */
9221 static void
9222f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9223{
9224 rettv->vval.v_number = screen_screenrow() + 1;
9225}
9226
9227/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009228 * "screenstring()" function
9229 */
9230 static void
9231f_screenstring(typval_T *argvars, typval_T *rettv)
9232{
9233 int row;
9234 int col;
9235 int off;
9236 int c;
9237 int i;
9238 char_u buf[MB_MAXBYTES + 1];
9239 int buflen = 0;
9240
9241 rettv->vval.v_string = NULL;
9242 rettv->v_type = VAR_STRING;
9243
9244 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9245 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9246 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9247 return;
9248
9249 off = LineOffset[row] + col;
9250 if (enc_utf8 && ScreenLinesUC[off] != 0)
9251 c = ScreenLinesUC[off];
9252 else
9253 c = ScreenLines[off];
9254 buflen += mb_char2bytes(c, buf);
9255
9256 if (enc_utf8)
9257 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9258 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9259
9260 buf[buflen] = NUL;
9261 rettv->vval.v_string = vim_strsave(buf);
9262}
9263
9264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009265 * "search()" function
9266 */
9267 static void
9268f_search(typval_T *argvars, typval_T *rettv)
9269{
9270 int flags = 0;
9271
9272 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9273}
9274
9275/*
9276 * "searchdecl()" function
9277 */
9278 static void
9279f_searchdecl(typval_T *argvars, typval_T *rettv)
9280{
9281 int locally = 1;
9282 int thisblock = 0;
9283 int error = FALSE;
9284 char_u *name;
9285
9286 rettv->vval.v_number = 1; /* default: FAIL */
9287
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009288 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009289 if (argvars[1].v_type != VAR_UNKNOWN)
9290 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009291 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009292 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009293 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009294 }
9295 if (!error && name != NULL)
9296 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9297 locally, thisblock, SEARCH_KEEP) == FAIL;
9298}
9299
9300/*
9301 * Used by searchpair() and searchpairpos()
9302 */
9303 static int
9304searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9305{
9306 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009307 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009308 int save_p_ws = p_ws;
9309 int dir;
9310 int flags = 0;
9311 char_u nbuf1[NUMBUFLEN];
9312 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009313 int retval = 0; /* default: FAIL */
9314 long lnum_stop = 0;
9315 long time_limit = 0;
9316
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009317 /* Get the three pattern arguments: start, middle, end. Will result in an
9318 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009319 spat = tv_get_string_chk(&argvars[0]);
9320 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9321 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009322 if (spat == NULL || mpat == NULL || epat == NULL)
9323 goto theend; /* type error */
9324
9325 /* Handle the optional fourth argument: flags */
9326 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9327 if (dir == 0)
9328 goto theend;
9329
9330 /* Don't accept SP_END or SP_SUBPAT.
9331 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9332 */
9333 if ((flags & (SP_END | SP_SUBPAT)) != 0
9334 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9335 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009336 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009337 goto theend;
9338 }
9339
9340 /* Using 'r' implies 'W', otherwise it doesn't work. */
9341 if (flags & SP_REPEAT)
9342 p_ws = FALSE;
9343
9344 /* Optional fifth argument: skip expression */
9345 if (argvars[3].v_type == VAR_UNKNOWN
9346 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009347 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009348 else
9349 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009350 skip = &argvars[4];
9351 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9352 && skip->v_type != VAR_STRING)
9353 {
9354 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009355 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009356 goto theend;
9357 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009358 if (argvars[5].v_type != VAR_UNKNOWN)
9359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009360 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009361 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009363 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009364 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009365 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009366#ifdef FEAT_RELTIME
9367 if (argvars[6].v_type != VAR_UNKNOWN)
9368 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009369 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009370 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009371 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009372 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009373 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009374 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009375 }
9376#endif
9377 }
9378 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379
9380 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9381 match_pos, lnum_stop, time_limit);
9382
9383theend:
9384 p_ws = save_p_ws;
9385
9386 return retval;
9387}
9388
9389/*
9390 * "searchpair()" function
9391 */
9392 static void
9393f_searchpair(typval_T *argvars, typval_T *rettv)
9394{
9395 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9396}
9397
9398/*
9399 * "searchpairpos()" function
9400 */
9401 static void
9402f_searchpairpos(typval_T *argvars, typval_T *rettv)
9403{
9404 pos_T match_pos;
9405 int lnum = 0;
9406 int col = 0;
9407
9408 if (rettv_list_alloc(rettv) == FAIL)
9409 return;
9410
9411 if (searchpair_cmn(argvars, &match_pos) > 0)
9412 {
9413 lnum = match_pos.lnum;
9414 col = match_pos.col;
9415 }
9416
9417 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9418 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9419}
9420
9421/*
9422 * Search for a start/middle/end thing.
9423 * Used by searchpair(), see its documentation for the details.
9424 * Returns 0 or -1 for no match,
9425 */
9426 long
9427do_searchpair(
9428 char_u *spat, /* start pattern */
9429 char_u *mpat, /* middle pattern */
9430 char_u *epat, /* end pattern */
9431 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009432 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009433 int flags, /* SP_SETPCMARK and other SP_ values */
9434 pos_T *match_pos,
9435 linenr_T lnum_stop, /* stop at this line if not zero */
9436 long time_limit UNUSED) /* stop after this many msec */
9437{
9438 char_u *save_cpo;
9439 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9440 long retval = 0;
9441 pos_T pos;
9442 pos_T firstpos;
9443 pos_T foundpos;
9444 pos_T save_cursor;
9445 pos_T save_pos;
9446 int n;
9447 int r;
9448 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009449 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009450 int err;
9451 int options = SEARCH_KEEP;
9452 proftime_T tm;
9453
9454 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9455 save_cpo = p_cpo;
9456 p_cpo = empty_option;
9457
9458#ifdef FEAT_RELTIME
9459 /* Set the time limit, if there is one. */
9460 profile_setlimit(time_limit, &tm);
9461#endif
9462
9463 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9464 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009465 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9466 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009467 if (pat2 == NULL || pat3 == NULL)
9468 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009469 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009470 if (*mpat == NUL)
9471 STRCPY(pat3, pat2);
9472 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009473 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009474 spat, epat, mpat);
9475 if (flags & SP_START)
9476 options |= SEARCH_START;
9477
Bram Moolenaar48570482017-10-30 21:48:41 +01009478 if (skip != NULL)
9479 {
9480 /* Empty string means to not use the skip expression. */
9481 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9482 use_skip = skip->vval.v_string != NULL
9483 && *skip->vval.v_string != NUL;
9484 }
9485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009486 save_cursor = curwin->w_cursor;
9487 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009488 CLEAR_POS(&firstpos);
9489 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009490 pat = pat3;
9491 for (;;)
9492 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009493 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009494 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009495 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009496 /* didn't find it or found the first match again: FAIL */
9497 break;
9498
9499 if (firstpos.lnum == 0)
9500 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009501 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009502 {
9503 /* Found the same position again. Can happen with a pattern that
9504 * has "\zs" at the end and searching backwards. Advance one
9505 * character and try again. */
9506 if (dir == BACKWARD)
9507 decl(&pos);
9508 else
9509 incl(&pos);
9510 }
9511 foundpos = pos;
9512
9513 /* clear the start flag to avoid getting stuck here */
9514 options &= ~SEARCH_START;
9515
9516 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009517 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009518 {
9519 save_pos = curwin->w_cursor;
9520 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009521 err = FALSE;
9522 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009523 curwin->w_cursor = save_pos;
9524 if (err)
9525 {
9526 /* Evaluating {skip} caused an error, break here. */
9527 curwin->w_cursor = save_cursor;
9528 retval = -1;
9529 break;
9530 }
9531 if (r)
9532 continue;
9533 }
9534
9535 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9536 {
9537 /* Found end when searching backwards or start when searching
9538 * forward: nested pair. */
9539 ++nest;
9540 pat = pat2; /* nested, don't search for middle */
9541 }
9542 else
9543 {
9544 /* Found end when searching forward or start when searching
9545 * backward: end of (nested) pair; or found middle in outer pair. */
9546 if (--nest == 1)
9547 pat = pat3; /* outer level, search for middle */
9548 }
9549
9550 if (nest == 0)
9551 {
9552 /* Found the match: return matchcount or line number. */
9553 if (flags & SP_RETCOUNT)
9554 ++retval;
9555 else
9556 retval = pos.lnum;
9557 if (flags & SP_SETPCMARK)
9558 setpcmark();
9559 curwin->w_cursor = pos;
9560 if (!(flags & SP_REPEAT))
9561 break;
9562 nest = 1; /* search for next unmatched */
9563 }
9564 }
9565
9566 if (match_pos != NULL)
9567 {
9568 /* Store the match cursor position */
9569 match_pos->lnum = curwin->w_cursor.lnum;
9570 match_pos->col = curwin->w_cursor.col + 1;
9571 }
9572
9573 /* If 'n' flag is used or search failed: restore cursor position. */
9574 if ((flags & SP_NOMOVE) || retval == 0)
9575 curwin->w_cursor = save_cursor;
9576
9577theend:
9578 vim_free(pat2);
9579 vim_free(pat3);
9580 if (p_cpo == empty_option)
9581 p_cpo = save_cpo;
9582 else
9583 /* Darn, evaluating the {skip} expression changed the value. */
9584 free_string_option(save_cpo);
9585
9586 return retval;
9587}
9588
9589/*
9590 * "searchpos()" function
9591 */
9592 static void
9593f_searchpos(typval_T *argvars, typval_T *rettv)
9594{
9595 pos_T match_pos;
9596 int lnum = 0;
9597 int col = 0;
9598 int n;
9599 int flags = 0;
9600
9601 if (rettv_list_alloc(rettv) == FAIL)
9602 return;
9603
9604 n = search_cmn(argvars, &match_pos, &flags);
9605 if (n > 0)
9606 {
9607 lnum = match_pos.lnum;
9608 col = match_pos.col;
9609 }
9610
9611 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9612 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9613 if (flags & SP_SUBPAT)
9614 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9615}
9616
9617 static void
9618f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9619{
9620#ifdef FEAT_CLIENTSERVER
9621 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009622 char_u *server = tv_get_string_chk(&argvars[0]);
9623 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009624
9625 rettv->vval.v_number = -1;
9626 if (server == NULL || reply == NULL)
9627 return;
9628 if (check_restricted() || check_secure())
9629 return;
9630# ifdef FEAT_X11
9631 if (check_connection() == FAIL)
9632 return;
9633# endif
9634
9635 if (serverSendReply(server, reply) < 0)
9636 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009637 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009638 return;
9639 }
9640 rettv->vval.v_number = 0;
9641#else
9642 rettv->vval.v_number = -1;
9643#endif
9644}
9645
9646 static void
9647f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9648{
9649 char_u *r = NULL;
9650
9651#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009652# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009653 r = serverGetVimNames();
9654# else
9655 make_connection();
9656 if (X_DISPLAY != NULL)
9657 r = serverGetVimNames(X_DISPLAY);
9658# endif
9659#endif
9660 rettv->v_type = VAR_STRING;
9661 rettv->vval.v_string = r;
9662}
9663
9664/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009665 * "setbufline()" function
9666 */
9667 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009668f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009669{
9670 linenr_T lnum;
9671 buf_T *buf;
9672
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009673 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009674 if (buf == NULL)
9675 rettv->vval.v_number = 1; /* FAIL */
9676 else
9677 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009678 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009679 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009680 }
9681}
9682
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009683 static void
9684f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9685{
9686 dict_T *d;
9687 dictitem_T *di;
9688 char_u *csearch;
9689
9690 if (argvars[0].v_type != VAR_DICT)
9691 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009692 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009693 return;
9694 }
9695
9696 if ((d = argvars[0].vval.v_dict) != NULL)
9697 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009698 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009699 if (csearch != NULL)
9700 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009701 if (enc_utf8)
9702 {
9703 int pcc[MAX_MCO];
9704 int c = utfc_ptr2char(csearch, pcc);
9705
9706 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9707 }
9708 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009709 set_last_csearch(PTR2CHAR(csearch),
9710 csearch, MB_PTR2LEN(csearch));
9711 }
9712
9713 di = dict_find(d, (char_u *)"forward", -1);
9714 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009715 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009716 ? FORWARD : BACKWARD);
9717
9718 di = dict_find(d, (char_u *)"until", -1);
9719 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009720 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009721 }
9722}
9723
9724/*
9725 * "setcmdpos()" function
9726 */
9727 static void
9728f_setcmdpos(typval_T *argvars, typval_T *rettv)
9729{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009730 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731
9732 if (pos >= 0)
9733 rettv->vval.v_number = set_cmdline_pos(pos);
9734}
9735
9736/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009737 * "setenv()" function
9738 */
9739 static void
9740f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9741{
9742 char_u namebuf[NUMBUFLEN];
9743 char_u valbuf[NUMBUFLEN];
9744 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9745
9746 if (argvars[1].v_type == VAR_SPECIAL
9747 && argvars[1].vval.v_number == VVAL_NULL)
9748 vim_unsetenv(name);
9749 else
9750 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9751}
9752
9753/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009754 * "setfperm({fname}, {mode})" function
9755 */
9756 static void
9757f_setfperm(typval_T *argvars, typval_T *rettv)
9758{
9759 char_u *fname;
9760 char_u modebuf[NUMBUFLEN];
9761 char_u *mode_str;
9762 int i;
9763 int mask;
9764 int mode = 0;
9765
9766 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009767 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009768 if (fname == NULL)
9769 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009770 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009771 if (mode_str == NULL)
9772 return;
9773 if (STRLEN(mode_str) != 9)
9774 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009775 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009776 return;
9777 }
9778
9779 mask = 1;
9780 for (i = 8; i >= 0; --i)
9781 {
9782 if (mode_str[i] != '-')
9783 mode |= mask;
9784 mask = mask << 1;
9785 }
9786 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9787}
9788
9789/*
9790 * "setline()" function
9791 */
9792 static void
9793f_setline(typval_T *argvars, typval_T *rettv)
9794{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009795 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009796
Bram Moolenaarca851592018-06-06 21:04:07 +02009797 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798}
9799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009800/*
9801 * Used by "setqflist()" and "setloclist()" functions
9802 */
9803 static void
9804set_qf_ll_list(
9805 win_T *wp UNUSED,
9806 typval_T *list_arg UNUSED,
9807 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009808 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 typval_T *rettv)
9810{
9811#ifdef FEAT_QUICKFIX
9812 static char *e_invact = N_("E927: Invalid action: '%s'");
9813 char_u *act;
9814 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009815 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009816#endif
9817
9818 rettv->vval.v_number = -1;
9819
9820#ifdef FEAT_QUICKFIX
9821 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009822 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009823 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009824 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 else
9826 {
9827 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +02009828 dict_T *d = NULL;
9829 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009830
9831 if (action_arg->v_type == VAR_STRING)
9832 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009833 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009834 if (act == NULL)
9835 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +02009836 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
9837 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009838 action = *act;
9839 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009840 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 }
9842 else if (action_arg->v_type == VAR_UNKNOWN)
9843 action = ' ';
9844 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009845 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009846
Bram Moolenaard823fa92016-08-12 16:29:27 +02009847 if (action_arg->v_type != VAR_UNKNOWN
9848 && what_arg->v_type != VAR_UNKNOWN)
9849 {
9850 if (what_arg->v_type == VAR_DICT)
9851 d = what_arg->vval.v_dict;
9852 else
9853 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009854 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02009855 valid_dict = FALSE;
9856 }
9857 }
9858
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009859 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +02009860 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009861 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
9862 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009863 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009864 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009865 }
9866#endif
9867}
9868
9869/*
9870 * "setloclist()" function
9871 */
9872 static void
9873f_setloclist(typval_T *argvars, typval_T *rettv)
9874{
9875 win_T *win;
9876
9877 rettv->vval.v_number = -1;
9878
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02009879 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +02009881 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009882}
9883
9884/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009885 * "setpos()" function
9886 */
9887 static void
9888f_setpos(typval_T *argvars, typval_T *rettv)
9889{
9890 pos_T pos;
9891 int fnum;
9892 char_u *name;
9893 colnr_T curswant = -1;
9894
9895 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009896 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009897 if (name != NULL)
9898 {
9899 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
9900 {
9901 if (--pos.col < 0)
9902 pos.col = 0;
9903 if (name[0] == '.' && name[1] == NUL)
9904 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009905 /* set cursor; "fnum" is ignored */
9906 curwin->w_cursor = pos;
9907 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009908 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009909 curwin->w_curswant = curswant - 1;
9910 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009911 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009912 check_cursor();
9913 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009914 }
9915 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
9916 {
9917 /* set mark */
9918 if (setmark_pos(name[1], &pos, fnum) == OK)
9919 rettv->vval.v_number = 0;
9920 }
9921 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009922 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009923 }
9924 }
9925}
9926
9927/*
9928 * "setqflist()" function
9929 */
9930 static void
9931f_setqflist(typval_T *argvars, typval_T *rettv)
9932{
Bram Moolenaard823fa92016-08-12 16:29:27 +02009933 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009934}
9935
9936/*
9937 * "setreg()" function
9938 */
9939 static void
9940f_setreg(typval_T *argvars, typval_T *rettv)
9941{
9942 int regname;
9943 char_u *strregname;
9944 char_u *stropt;
9945 char_u *strval;
9946 int append;
9947 char_u yank_type;
9948 long block_len;
9949
9950 block_len = -1;
9951 yank_type = MAUTO;
9952 append = FALSE;
9953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009954 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 rettv->vval.v_number = 1; /* FAIL is default */
9956
9957 if (strregname == NULL)
9958 return; /* type error; errmsg already given */
9959 regname = *strregname;
9960 if (regname == 0 || regname == '@')
9961 regname = '"';
9962
9963 if (argvars[2].v_type != VAR_UNKNOWN)
9964 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009965 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009966 if (stropt == NULL)
9967 return; /* type error */
9968 for (; *stropt != NUL; ++stropt)
9969 switch (*stropt)
9970 {
9971 case 'a': case 'A': /* append */
9972 append = TRUE;
9973 break;
9974 case 'v': case 'c': /* character-wise selection */
9975 yank_type = MCHAR;
9976 break;
9977 case 'V': case 'l': /* line-wise selection */
9978 yank_type = MLINE;
9979 break;
9980 case 'b': case Ctrl_V: /* block-wise selection */
9981 yank_type = MBLOCK;
9982 if (VIM_ISDIGIT(stropt[1]))
9983 {
9984 ++stropt;
9985 block_len = getdigits(&stropt) - 1;
9986 --stropt;
9987 }
9988 break;
9989 }
9990 }
9991
9992 if (argvars[1].v_type == VAR_LIST)
9993 {
9994 char_u **lstval;
9995 char_u **allocval;
9996 char_u buf[NUMBUFLEN];
9997 char_u **curval;
9998 char_u **curallocval;
9999 list_T *ll = argvars[1].vval.v_list;
10000 listitem_T *li;
10001 int len;
10002
10003 /* If the list is NULL handle like an empty list. */
10004 len = ll == NULL ? 0 : ll->lv_len;
10005
10006 /* First half: use for pointers to result lines; second half: use for
10007 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010008 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010009 if (lstval == NULL)
10010 return;
10011 curval = lstval;
10012 allocval = lstval + len + 2;
10013 curallocval = allocval;
10014
10015 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10016 li = li->li_next)
10017 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010018 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 if (strval == NULL)
10020 goto free_lstval;
10021 if (strval == buf)
10022 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010023 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010024 * overwrite the string. */
10025 strval = vim_strsave(buf);
10026 if (strval == NULL)
10027 goto free_lstval;
10028 *curallocval++ = strval;
10029 }
10030 *curval++ = strval;
10031 }
10032 *curval++ = NULL;
10033
10034 write_reg_contents_lst(regname, lstval, -1,
10035 append, yank_type, block_len);
10036free_lstval:
10037 while (curallocval > allocval)
10038 vim_free(*--curallocval);
10039 vim_free(lstval);
10040 }
10041 else
10042 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010043 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010044 if (strval == NULL)
10045 return;
10046 write_reg_contents_ex(regname, strval, -1,
10047 append, yank_type, block_len);
10048 }
10049 rettv->vval.v_number = 0;
10050}
10051
10052/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010053 * "settagstack()" function
10054 */
10055 static void
10056f_settagstack(typval_T *argvars, typval_T *rettv)
10057{
10058 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10059 win_T *wp;
10060 dict_T *d;
10061 int action = 'r';
10062
10063 rettv->vval.v_number = -1;
10064
10065 // first argument: window number or id
10066 wp = find_win_by_nr_or_id(&argvars[0]);
10067 if (wp == NULL)
10068 return;
10069
10070 // second argument: dict with items to set in the tag stack
10071 if (argvars[1].v_type != VAR_DICT)
10072 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010073 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010074 return;
10075 }
10076 d = argvars[1].vval.v_dict;
10077 if (d == NULL)
10078 return;
10079
10080 // third argument: action - 'a' for append and 'r' for replace.
10081 // default is to replace the stack.
10082 if (argvars[2].v_type == VAR_UNKNOWN)
10083 action = 'r';
10084 else if (argvars[2].v_type == VAR_STRING)
10085 {
10086 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010087 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010088 if (actstr == NULL)
10089 return;
10090 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10091 action = *actstr;
10092 else
10093 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010094 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010095 return;
10096 }
10097 }
10098 else
10099 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010100 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010101 return;
10102 }
10103
10104 if (set_tagstack(wp, d, action) == OK)
10105 rettv->vval.v_number = 0;
10106}
10107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010108#ifdef FEAT_CRYPT
10109/*
10110 * "sha256({string})" function
10111 */
10112 static void
10113f_sha256(typval_T *argvars, typval_T *rettv)
10114{
10115 char_u *p;
10116
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010117 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010118 rettv->vval.v_string = vim_strsave(
10119 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10120 rettv->v_type = VAR_STRING;
10121}
10122#endif /* FEAT_CRYPT */
10123
10124/*
10125 * "shellescape({string})" function
10126 */
10127 static void
10128f_shellescape(typval_T *argvars, typval_T *rettv)
10129{
Bram Moolenaar20615522017-06-05 18:46:26 +020010130 int do_special = non_zero_arg(&argvars[1]);
10131
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010132 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010133 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010134 rettv->v_type = VAR_STRING;
10135}
10136
10137/*
10138 * shiftwidth() function
10139 */
10140 static void
10141f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10142{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010143 rettv->vval.v_number = 0;
10144
10145 if (argvars[0].v_type != VAR_UNKNOWN)
10146 {
10147 long col;
10148
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010149 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010150 if (col < 0)
10151 return; // type error; errmsg already given
10152#ifdef FEAT_VARTABS
10153 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10154 return;
10155#endif
10156 }
10157
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010158 rettv->vval.v_number = get_sw_value(curbuf);
10159}
10160
10161/*
10162 * "simplify()" function
10163 */
10164 static void
10165f_simplify(typval_T *argvars, typval_T *rettv)
10166{
10167 char_u *p;
10168
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010169 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010170 rettv->vval.v_string = vim_strsave(p);
10171 simplify_filename(rettv->vval.v_string); /* simplify in place */
10172 rettv->v_type = VAR_STRING;
10173}
10174
10175#ifdef FEAT_FLOAT
10176/*
10177 * "sin()" function
10178 */
10179 static void
10180f_sin(typval_T *argvars, typval_T *rettv)
10181{
10182 float_T f = 0.0;
10183
10184 rettv->v_type = VAR_FLOAT;
10185 if (get_float_arg(argvars, &f) == OK)
10186 rettv->vval.v_float = sin(f);
10187 else
10188 rettv->vval.v_float = 0.0;
10189}
10190
10191/*
10192 * "sinh()" function
10193 */
10194 static void
10195f_sinh(typval_T *argvars, typval_T *rettv)
10196{
10197 float_T f = 0.0;
10198
10199 rettv->v_type = VAR_FLOAT;
10200 if (get_float_arg(argvars, &f) == OK)
10201 rettv->vval.v_float = sinh(f);
10202 else
10203 rettv->vval.v_float = 0.0;
10204}
10205#endif
10206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010207/*
10208 * "soundfold({word})" function
10209 */
10210 static void
10211f_soundfold(typval_T *argvars, typval_T *rettv)
10212{
10213 char_u *s;
10214
10215 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010216 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010217#ifdef FEAT_SPELL
10218 rettv->vval.v_string = eval_soundfold(s);
10219#else
10220 rettv->vval.v_string = vim_strsave(s);
10221#endif
10222}
10223
10224/*
10225 * "spellbadword()" function
10226 */
10227 static void
10228f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10229{
10230 char_u *word = (char_u *)"";
10231 hlf_T attr = HLF_COUNT;
10232 int len = 0;
10233
10234 if (rettv_list_alloc(rettv) == FAIL)
10235 return;
10236
10237#ifdef FEAT_SPELL
10238 if (argvars[0].v_type == VAR_UNKNOWN)
10239 {
10240 /* Find the start and length of the badly spelled word. */
10241 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10242 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010243 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010245 curwin->w_set_curswant = TRUE;
10246 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010247 }
10248 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10249 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010250 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010251 int capcol = -1;
10252
10253 if (str != NULL)
10254 {
10255 /* Check the argument for spelling. */
10256 while (*str != NUL)
10257 {
10258 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10259 if (attr != HLF_COUNT)
10260 {
10261 word = str;
10262 break;
10263 }
10264 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010265 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010266 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010267 }
10268 }
10269 }
10270#endif
10271
10272 list_append_string(rettv->vval.v_list, word, len);
10273 list_append_string(rettv->vval.v_list, (char_u *)(
10274 attr == HLF_SPB ? "bad" :
10275 attr == HLF_SPR ? "rare" :
10276 attr == HLF_SPL ? "local" :
10277 attr == HLF_SPC ? "caps" :
10278 ""), -1);
10279}
10280
10281/*
10282 * "spellsuggest()" function
10283 */
10284 static void
10285f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10286{
10287#ifdef FEAT_SPELL
10288 char_u *str;
10289 int typeerr = FALSE;
10290 int maxcount;
10291 garray_T ga;
10292 int i;
10293 listitem_T *li;
10294 int need_capital = FALSE;
10295#endif
10296
10297 if (rettv_list_alloc(rettv) == FAIL)
10298 return;
10299
10300#ifdef FEAT_SPELL
10301 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10302 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010303 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 if (argvars[1].v_type != VAR_UNKNOWN)
10305 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010306 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010307 if (maxcount <= 0)
10308 return;
10309 if (argvars[2].v_type != VAR_UNKNOWN)
10310 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010311 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010312 if (typeerr)
10313 return;
10314 }
10315 }
10316 else
10317 maxcount = 25;
10318
10319 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10320
10321 for (i = 0; i < ga.ga_len; ++i)
10322 {
10323 str = ((char_u **)ga.ga_data)[i];
10324
10325 li = listitem_alloc();
10326 if (li == NULL)
10327 vim_free(str);
10328 else
10329 {
10330 li->li_tv.v_type = VAR_STRING;
10331 li->li_tv.v_lock = 0;
10332 li->li_tv.vval.v_string = str;
10333 list_append(rettv->vval.v_list, li);
10334 }
10335 }
10336 ga_clear(&ga);
10337 }
10338#endif
10339}
10340
10341 static void
10342f_split(typval_T *argvars, typval_T *rettv)
10343{
10344 char_u *str;
10345 char_u *end;
10346 char_u *pat = NULL;
10347 regmatch_T regmatch;
10348 char_u patbuf[NUMBUFLEN];
10349 char_u *save_cpo;
10350 int match;
10351 colnr_T col = 0;
10352 int keepempty = FALSE;
10353 int typeerr = FALSE;
10354
10355 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10356 save_cpo = p_cpo;
10357 p_cpo = (char_u *)"";
10358
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010359 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010360 if (argvars[1].v_type != VAR_UNKNOWN)
10361 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010362 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010363 if (pat == NULL)
10364 typeerr = TRUE;
10365 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010366 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010367 }
10368 if (pat == NULL || *pat == NUL)
10369 pat = (char_u *)"[\\x01- ]\\+";
10370
10371 if (rettv_list_alloc(rettv) == FAIL)
10372 return;
10373 if (typeerr)
10374 return;
10375
10376 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10377 if (regmatch.regprog != NULL)
10378 {
10379 regmatch.rm_ic = FALSE;
10380 while (*str != NUL || keepempty)
10381 {
10382 if (*str == NUL)
10383 match = FALSE; /* empty item at the end */
10384 else
10385 match = vim_regexec_nl(&regmatch, str, col);
10386 if (match)
10387 end = regmatch.startp[0];
10388 else
10389 end = str + STRLEN(str);
10390 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10391 && *str != NUL && match && end < regmatch.endp[0]))
10392 {
10393 if (list_append_string(rettv->vval.v_list, str,
10394 (int)(end - str)) == FAIL)
10395 break;
10396 }
10397 if (!match)
10398 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010399 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400 if (regmatch.endp[0] > str)
10401 col = 0;
10402 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010403 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010404 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010405 str = regmatch.endp[0];
10406 }
10407
10408 vim_regfree(regmatch.regprog);
10409 }
10410
10411 p_cpo = save_cpo;
10412}
10413
10414#ifdef FEAT_FLOAT
10415/*
10416 * "sqrt()" function
10417 */
10418 static void
10419f_sqrt(typval_T *argvars, typval_T *rettv)
10420{
10421 float_T f = 0.0;
10422
10423 rettv->v_type = VAR_FLOAT;
10424 if (get_float_arg(argvars, &f) == OK)
10425 rettv->vval.v_float = sqrt(f);
10426 else
10427 rettv->vval.v_float = 0.0;
10428}
10429
10430/*
10431 * "str2float()" function
10432 */
10433 static void
10434f_str2float(typval_T *argvars, typval_T *rettv)
10435{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010436 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010437 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010438
Bram Moolenaar08243d22017-01-10 16:12:29 +010010439 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440 p = skipwhite(p + 1);
10441 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010442 if (isneg)
10443 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010444 rettv->v_type = VAR_FLOAT;
10445}
10446#endif
10447
10448/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010449 * "str2list()" function
10450 */
10451 static void
10452f_str2list(typval_T *argvars, typval_T *rettv)
10453{
10454 char_u *p;
10455 int utf8 = FALSE;
10456
10457 if (rettv_list_alloc(rettv) == FAIL)
10458 return;
10459
10460 if (argvars[1].v_type != VAR_UNKNOWN)
10461 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10462
10463 p = tv_get_string(&argvars[0]);
10464
10465 if (has_mbyte || utf8)
10466 {
10467 int (*ptr2len)(char_u *);
10468 int (*ptr2char)(char_u *);
10469
10470 if (utf8 || enc_utf8)
10471 {
10472 ptr2len = utf_ptr2len;
10473 ptr2char = utf_ptr2char;
10474 }
10475 else
10476 {
10477 ptr2len = mb_ptr2len;
10478 ptr2char = mb_ptr2char;
10479 }
10480
10481 for ( ; *p != NUL; p += (*ptr2len)(p))
10482 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10483 }
10484 else
10485 for ( ; *p != NUL; ++p)
10486 list_append_number(rettv->vval.v_list, *p);
10487}
10488
10489/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010490 * "str2nr()" function
10491 */
10492 static void
10493f_str2nr(typval_T *argvars, typval_T *rettv)
10494{
10495 int base = 10;
10496 char_u *p;
10497 varnumber_T n;
10498 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010499 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010500
10501 if (argvars[1].v_type != VAR_UNKNOWN)
10502 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010503 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010504 if (base != 2 && base != 8 && base != 10 && base != 16)
10505 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010506 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010507 return;
10508 }
10509 }
10510
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010511 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010512 isneg = (*p == '-');
10513 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010514 p = skipwhite(p + 1);
10515 switch (base)
10516 {
10517 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10518 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10519 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10520 default: what = 0;
10521 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010522 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10523 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010524 if (isneg)
10525 rettv->vval.v_number = -n;
10526 else
10527 rettv->vval.v_number = n;
10528
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010529}
10530
10531#ifdef HAVE_STRFTIME
10532/*
10533 * "strftime({format}[, {time}])" function
10534 */
10535 static void
10536f_strftime(typval_T *argvars, typval_T *rettv)
10537{
10538 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010539 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010540 struct tm *curtime;
10541 time_t seconds;
10542 char_u *p;
10543
10544 rettv->v_type = VAR_STRING;
10545
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010546 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010547 if (argvars[1].v_type == VAR_UNKNOWN)
10548 seconds = time(NULL);
10549 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010550 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010551 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010552 /* MSVC returns NULL for an invalid value of seconds. */
10553 if (curtime == NULL)
10554 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10555 else
10556 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010557 vimconv_T conv;
10558 char_u *enc;
10559
10560 conv.vc_type = CONV_NONE;
10561 enc = enc_locale();
10562 convert_setup(&conv, p_enc, enc);
10563 if (conv.vc_type != CONV_NONE)
10564 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010565 if (p != NULL)
10566 (void)strftime((char *)result_buf, sizeof(result_buf),
10567 (char *)p, curtime);
10568 else
10569 result_buf[0] = NUL;
10570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010571 if (conv.vc_type != CONV_NONE)
10572 vim_free(p);
10573 convert_setup(&conv, enc, p_enc);
10574 if (conv.vc_type != CONV_NONE)
10575 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10576 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010577 rettv->vval.v_string = vim_strsave(result_buf);
10578
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010579 /* Release conversion descriptors */
10580 convert_setup(&conv, NULL, NULL);
10581 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010582 }
10583}
10584#endif
10585
10586/*
10587 * "strgetchar()" function
10588 */
10589 static void
10590f_strgetchar(typval_T *argvars, typval_T *rettv)
10591{
10592 char_u *str;
10593 int len;
10594 int error = FALSE;
10595 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010596 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010597
10598 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010599 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010600 if (str == NULL)
10601 return;
10602 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010603 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010604 if (error)
10605 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010606
Bram Moolenaar13505972019-01-24 15:04:48 +010010607 while (charidx >= 0 && byteidx < len)
10608 {
10609 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010610 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010611 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10612 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010613 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010614 --charidx;
10615 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010616 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010617}
10618
10619/*
10620 * "stridx()" function
10621 */
10622 static void
10623f_stridx(typval_T *argvars, typval_T *rettv)
10624{
10625 char_u buf[NUMBUFLEN];
10626 char_u *needle;
10627 char_u *haystack;
10628 char_u *save_haystack;
10629 char_u *pos;
10630 int start_idx;
10631
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010632 needle = tv_get_string_chk(&argvars[1]);
10633 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 rettv->vval.v_number = -1;
10635 if (needle == NULL || haystack == NULL)
10636 return; /* type error; errmsg already given */
10637
10638 if (argvars[2].v_type != VAR_UNKNOWN)
10639 {
10640 int error = FALSE;
10641
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010642 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010643 if (error || start_idx >= (int)STRLEN(haystack))
10644 return;
10645 if (start_idx >= 0)
10646 haystack += start_idx;
10647 }
10648
10649 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10650 if (pos != NULL)
10651 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10652}
10653
10654/*
10655 * "string()" function
10656 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010657 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010658f_string(typval_T *argvars, typval_T *rettv)
10659{
10660 char_u *tofree;
10661 char_u numbuf[NUMBUFLEN];
10662
10663 rettv->v_type = VAR_STRING;
10664 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10665 get_copyID());
10666 /* Make a copy if we have a value but it's not in allocated memory. */
10667 if (rettv->vval.v_string != NULL && tofree == NULL)
10668 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10669}
10670
10671/*
10672 * "strlen()" function
10673 */
10674 static void
10675f_strlen(typval_T *argvars, typval_T *rettv)
10676{
10677 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010678 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010679}
10680
10681/*
10682 * "strchars()" function
10683 */
10684 static void
10685f_strchars(typval_T *argvars, typval_T *rettv)
10686{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010687 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010688 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010689 varnumber_T len = 0;
10690 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010691
10692 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010693 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010694 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010695 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010696 else
10697 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010698 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10699 while (*s != NUL)
10700 {
10701 func_mb_ptr2char_adv(&s);
10702 ++len;
10703 }
10704 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010705 }
10706}
10707
10708/*
10709 * "strdisplaywidth()" function
10710 */
10711 static void
10712f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10713{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010714 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010715 int col = 0;
10716
10717 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010718 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010719
10720 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10721}
10722
10723/*
10724 * "strwidth()" function
10725 */
10726 static void
10727f_strwidth(typval_T *argvars, typval_T *rettv)
10728{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010729 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010730
Bram Moolenaar13505972019-01-24 15:04:48 +010010731 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010732}
10733
10734/*
10735 * "strcharpart()" function
10736 */
10737 static void
10738f_strcharpart(typval_T *argvars, typval_T *rettv)
10739{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010740 char_u *p;
10741 int nchar;
10742 int nbyte = 0;
10743 int charlen;
10744 int len = 0;
10745 int slen;
10746 int error = FALSE;
10747
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010748 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010749 slen = (int)STRLEN(p);
10750
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010751 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010752 if (!error)
10753 {
10754 if (nchar > 0)
10755 while (nchar > 0 && nbyte < slen)
10756 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010757 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010758 --nchar;
10759 }
10760 else
10761 nbyte = nchar;
10762 if (argvars[2].v_type != VAR_UNKNOWN)
10763 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010764 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010765 while (charlen > 0 && nbyte + len < slen)
10766 {
10767 int off = nbyte + len;
10768
10769 if (off < 0)
10770 len += 1;
10771 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010772 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010773 --charlen;
10774 }
10775 }
10776 else
10777 len = slen - nbyte; /* default: all bytes that are available. */
10778 }
10779
10780 /*
10781 * Only return the overlap between the specified part and the actual
10782 * string.
10783 */
10784 if (nbyte < 0)
10785 {
10786 len += nbyte;
10787 nbyte = 0;
10788 }
10789 else if (nbyte > slen)
10790 nbyte = slen;
10791 if (len < 0)
10792 len = 0;
10793 else if (nbyte + len > slen)
10794 len = slen - nbyte;
10795
10796 rettv->v_type = VAR_STRING;
10797 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798}
10799
10800/*
10801 * "strpart()" function
10802 */
10803 static void
10804f_strpart(typval_T *argvars, typval_T *rettv)
10805{
10806 char_u *p;
10807 int n;
10808 int len;
10809 int slen;
10810 int error = FALSE;
10811
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010812 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010813 slen = (int)STRLEN(p);
10814
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010815 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010816 if (error)
10817 len = 0;
10818 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010819 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010820 else
10821 len = slen - n; /* default len: all bytes that are available. */
10822
10823 /*
10824 * Only return the overlap between the specified part and the actual
10825 * string.
10826 */
10827 if (n < 0)
10828 {
10829 len += n;
10830 n = 0;
10831 }
10832 else if (n > slen)
10833 n = slen;
10834 if (len < 0)
10835 len = 0;
10836 else if (n + len > slen)
10837 len = slen - n;
10838
10839 rettv->v_type = VAR_STRING;
10840 rettv->vval.v_string = vim_strnsave(p + n, len);
10841}
10842
10843/*
10844 * "strridx()" function
10845 */
10846 static void
10847f_strridx(typval_T *argvars, typval_T *rettv)
10848{
10849 char_u buf[NUMBUFLEN];
10850 char_u *needle;
10851 char_u *haystack;
10852 char_u *rest;
10853 char_u *lastmatch = NULL;
10854 int haystack_len, end_idx;
10855
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010856 needle = tv_get_string_chk(&argvars[1]);
10857 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010858
10859 rettv->vval.v_number = -1;
10860 if (needle == NULL || haystack == NULL)
10861 return; /* type error; errmsg already given */
10862
10863 haystack_len = (int)STRLEN(haystack);
10864 if (argvars[2].v_type != VAR_UNKNOWN)
10865 {
10866 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010867 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010868 if (end_idx < 0)
10869 return; /* can never find a match */
10870 }
10871 else
10872 end_idx = haystack_len;
10873
10874 if (*needle == NUL)
10875 {
10876 /* Empty string matches past the end. */
10877 lastmatch = haystack + end_idx;
10878 }
10879 else
10880 {
10881 for (rest = haystack; *rest != '\0'; ++rest)
10882 {
10883 rest = (char_u *)strstr((char *)rest, (char *)needle);
10884 if (rest == NULL || rest > haystack + end_idx)
10885 break;
10886 lastmatch = rest;
10887 }
10888 }
10889
10890 if (lastmatch == NULL)
10891 rettv->vval.v_number = -1;
10892 else
10893 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
10894}
10895
10896/*
10897 * "strtrans()" function
10898 */
10899 static void
10900f_strtrans(typval_T *argvars, typval_T *rettv)
10901{
10902 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010903 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010904}
10905
10906/*
10907 * "submatch()" function
10908 */
10909 static void
10910f_submatch(typval_T *argvars, typval_T *rettv)
10911{
10912 int error = FALSE;
10913 int no;
10914 int retList = 0;
10915
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010916 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010917 if (error)
10918 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020010919 if (no < 0 || no >= NSUBEXP)
10920 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010921 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010010922 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020010923 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010925 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926 if (error)
10927 return;
10928
10929 if (retList == 0)
10930 {
10931 rettv->v_type = VAR_STRING;
10932 rettv->vval.v_string = reg_submatch(no);
10933 }
10934 else
10935 {
10936 rettv->v_type = VAR_LIST;
10937 rettv->vval.v_list = reg_submatch_list(no);
10938 }
10939}
10940
10941/*
10942 * "substitute()" function
10943 */
10944 static void
10945f_substitute(typval_T *argvars, typval_T *rettv)
10946{
10947 char_u patbuf[NUMBUFLEN];
10948 char_u subbuf[NUMBUFLEN];
10949 char_u flagsbuf[NUMBUFLEN];
10950
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010951 char_u *str = tv_get_string_chk(&argvars[0]);
10952 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010953 char_u *sub = NULL;
10954 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010955 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010956
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010957 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
10958 expr = &argvars[2];
10959 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010960 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010962 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010963 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
10964 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010965 rettv->vval.v_string = NULL;
10966 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010967 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010968}
10969
10970/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020010971 * "swapinfo(swap_filename)" function
10972 */
10973 static void
10974f_swapinfo(typval_T *argvars, typval_T *rettv)
10975{
10976 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010977 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020010978}
10979
10980/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020010981 * "swapname(expr)" function
10982 */
10983 static void
10984f_swapname(typval_T *argvars, typval_T *rettv)
10985{
10986 buf_T *buf;
10987
10988 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010989 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020010990 if (buf == NULL || buf->b_ml.ml_mfp == NULL
10991 || buf->b_ml.ml_mfp->mf_fname == NULL)
10992 rettv->vval.v_string = NULL;
10993 else
10994 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
10995}
10996
10997/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010998 * "synID(lnum, col, trans)" function
10999 */
11000 static void
11001f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11002{
11003 int id = 0;
11004#ifdef FEAT_SYN_HL
11005 linenr_T lnum;
11006 colnr_T col;
11007 int trans;
11008 int transerr = FALSE;
11009
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011010 lnum = tv_get_lnum(argvars); /* -1 on type error */
11011 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11012 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011013
11014 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11015 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11016 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11017#endif
11018
11019 rettv->vval.v_number = id;
11020}
11021
11022/*
11023 * "synIDattr(id, what [, mode])" function
11024 */
11025 static void
11026f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11027{
11028 char_u *p = NULL;
11029#ifdef FEAT_SYN_HL
11030 int id;
11031 char_u *what;
11032 char_u *mode;
11033 char_u modebuf[NUMBUFLEN];
11034 int modec;
11035
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011036 id = (int)tv_get_number(&argvars[0]);
11037 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 if (argvars[2].v_type != VAR_UNKNOWN)
11039 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011040 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011041 modec = TOLOWER_ASC(mode[0]);
11042 if (modec != 't' && modec != 'c' && modec != 'g')
11043 modec = 0; /* replace invalid with current */
11044 }
11045 else
11046 {
11047#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11048 if (USE_24BIT)
11049 modec = 'g';
11050 else
11051#endif
11052 if (t_colors > 1)
11053 modec = 'c';
11054 else
11055 modec = 't';
11056 }
11057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011058 switch (TOLOWER_ASC(what[0]))
11059 {
11060 case 'b':
11061 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11062 p = highlight_color(id, what, modec);
11063 else /* bold */
11064 p = highlight_has_attr(id, HL_BOLD, modec);
11065 break;
11066
11067 case 'f': /* fg[#] or font */
11068 p = highlight_color(id, what, modec);
11069 break;
11070
11071 case 'i':
11072 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11073 p = highlight_has_attr(id, HL_INVERSE, modec);
11074 else /* italic */
11075 p = highlight_has_attr(id, HL_ITALIC, modec);
11076 break;
11077
11078 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011079 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 break;
11081
11082 case 'r': /* reverse */
11083 p = highlight_has_attr(id, HL_INVERSE, modec);
11084 break;
11085
11086 case 's':
11087 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11088 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011089 /* strikeout */
11090 else if (TOLOWER_ASC(what[1]) == 't' &&
11091 TOLOWER_ASC(what[2]) == 'r')
11092 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011093 else /* standout */
11094 p = highlight_has_attr(id, HL_STANDOUT, modec);
11095 break;
11096
11097 case 'u':
11098 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11099 /* underline */
11100 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11101 else
11102 /* undercurl */
11103 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11104 break;
11105 }
11106
11107 if (p != NULL)
11108 p = vim_strsave(p);
11109#endif
11110 rettv->v_type = VAR_STRING;
11111 rettv->vval.v_string = p;
11112}
11113
11114/*
11115 * "synIDtrans(id)" function
11116 */
11117 static void
11118f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11119{
11120 int id;
11121
11122#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011123 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011124
11125 if (id > 0)
11126 id = syn_get_final_id(id);
11127 else
11128#endif
11129 id = 0;
11130
11131 rettv->vval.v_number = id;
11132}
11133
11134/*
11135 * "synconcealed(lnum, col)" function
11136 */
11137 static void
11138f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11139{
11140#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11141 linenr_T lnum;
11142 colnr_T col;
11143 int syntax_flags = 0;
11144 int cchar;
11145 int matchid = 0;
11146 char_u str[NUMBUFLEN];
11147#endif
11148
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011149 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011150
11151#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011152 lnum = tv_get_lnum(argvars); /* -1 on type error */
11153 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154
11155 vim_memset(str, NUL, sizeof(str));
11156
11157 if (rettv_list_alloc(rettv) != FAIL)
11158 {
11159 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11160 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11161 && curwin->w_p_cole > 0)
11162 {
11163 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11164 syntax_flags = get_syntax_info(&matchid);
11165
11166 /* get the conceal character */
11167 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11168 {
11169 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011170 if (cchar == NUL && curwin->w_p_cole == 1)
11171 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011172 if (cchar != NUL)
11173 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011174 if (has_mbyte)
11175 (*mb_char2bytes)(cchar, str);
11176 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011177 str[0] = cchar;
11178 }
11179 }
11180 }
11181
11182 list_append_number(rettv->vval.v_list,
11183 (syntax_flags & HL_CONCEAL) != 0);
11184 /* -1 to auto-determine strlen */
11185 list_append_string(rettv->vval.v_list, str, -1);
11186 list_append_number(rettv->vval.v_list, matchid);
11187 }
11188#endif
11189}
11190
11191/*
11192 * "synstack(lnum, col)" function
11193 */
11194 static void
11195f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11196{
11197#ifdef FEAT_SYN_HL
11198 linenr_T lnum;
11199 colnr_T col;
11200 int i;
11201 int id;
11202#endif
11203
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011204 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205
11206#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011207 lnum = tv_get_lnum(argvars); /* -1 on type error */
11208 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011209
11210 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11211 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11212 && rettv_list_alloc(rettv) != FAIL)
11213 {
11214 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11215 for (i = 0; ; ++i)
11216 {
11217 id = syn_get_stack_item(i);
11218 if (id < 0)
11219 break;
11220 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11221 break;
11222 }
11223 }
11224#endif
11225}
11226
11227 static void
11228get_cmd_output_as_rettv(
11229 typval_T *argvars,
11230 typval_T *rettv,
11231 int retlist)
11232{
11233 char_u *res = NULL;
11234 char_u *p;
11235 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 int err = FALSE;
11237 FILE *fd;
11238 list_T *list = NULL;
11239 int flags = SHELL_SILENT;
11240
11241 rettv->v_type = VAR_STRING;
11242 rettv->vval.v_string = NULL;
11243 if (check_restricted() || check_secure())
11244 goto errret;
11245
11246 if (argvars[1].v_type != VAR_UNKNOWN)
11247 {
11248 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011249 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011250 * command.
11251 */
11252 if ((infile = vim_tempname('i', TRUE)) == NULL)
11253 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011254 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011255 goto errret;
11256 }
11257
11258 fd = mch_fopen((char *)infile, WRITEBIN);
11259 if (fd == NULL)
11260 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011261 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011262 goto errret;
11263 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011264 if (argvars[1].v_type == VAR_NUMBER)
11265 {
11266 linenr_T lnum;
11267 buf_T *buf;
11268
11269 buf = buflist_findnr(argvars[1].vval.v_number);
11270 if (buf == NULL)
11271 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011272 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011273 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011274 goto errret;
11275 }
11276
11277 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11278 {
11279 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11280 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11281 {
11282 err = TRUE;
11283 break;
11284 }
11285 if (putc(NL, fd) == EOF)
11286 {
11287 err = TRUE;
11288 break;
11289 }
11290 }
11291 }
11292 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011293 {
11294 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11295 err = TRUE;
11296 }
11297 else
11298 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011299 size_t len;
11300 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011301
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011302 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011303 if (p == NULL)
11304 {
11305 fclose(fd);
11306 goto errret; /* type error; errmsg already given */
11307 }
11308 len = STRLEN(p);
11309 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11310 err = TRUE;
11311 }
11312 if (fclose(fd) != 0)
11313 err = TRUE;
11314 if (err)
11315 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011316 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317 goto errret;
11318 }
11319 }
11320
11321 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11322 * echoes typeahead, that messes up the display. */
11323 if (!msg_silent)
11324 flags += SHELL_COOKED;
11325
11326 if (retlist)
11327 {
11328 int len;
11329 listitem_T *li;
11330 char_u *s = NULL;
11331 char_u *start;
11332 char_u *end;
11333 int i;
11334
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011335 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011336 if (res == NULL)
11337 goto errret;
11338
11339 list = list_alloc();
11340 if (list == NULL)
11341 goto errret;
11342
11343 for (i = 0; i < len; ++i)
11344 {
11345 start = res + i;
11346 while (i < len && res[i] != NL)
11347 ++i;
11348 end = res + i;
11349
Bram Moolenaar964b3742019-05-24 18:54:09 +020011350 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011351 if (s == NULL)
11352 goto errret;
11353
11354 for (p = s; start < end; ++p, ++start)
11355 *p = *start == NUL ? NL : *start;
11356 *p = NUL;
11357
11358 li = listitem_alloc();
11359 if (li == NULL)
11360 {
11361 vim_free(s);
11362 goto errret;
11363 }
11364 li->li_tv.v_type = VAR_STRING;
11365 li->li_tv.v_lock = 0;
11366 li->li_tv.vval.v_string = s;
11367 list_append(list, li);
11368 }
11369
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011370 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011371 list = NULL;
11372 }
11373 else
11374 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011375 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011376#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011377 /* translate <CR><NL> into <NL> */
11378 if (res != NULL)
11379 {
11380 char_u *s, *d;
11381
11382 d = res;
11383 for (s = res; *s; ++s)
11384 {
11385 if (s[0] == CAR && s[1] == NL)
11386 ++s;
11387 *d++ = *s;
11388 }
11389 *d = NUL;
11390 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011391#endif
11392 rettv->vval.v_string = res;
11393 res = NULL;
11394 }
11395
11396errret:
11397 if (infile != NULL)
11398 {
11399 mch_remove(infile);
11400 vim_free(infile);
11401 }
11402 if (res != NULL)
11403 vim_free(res);
11404 if (list != NULL)
11405 list_free(list);
11406}
11407
11408/*
11409 * "system()" function
11410 */
11411 static void
11412f_system(typval_T *argvars, typval_T *rettv)
11413{
11414 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11415}
11416
11417/*
11418 * "systemlist()" function
11419 */
11420 static void
11421f_systemlist(typval_T *argvars, typval_T *rettv)
11422{
11423 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11424}
11425
11426/*
11427 * "tabpagebuflist()" function
11428 */
11429 static void
11430f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11431{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011432 tabpage_T *tp;
11433 win_T *wp = NULL;
11434
11435 if (argvars[0].v_type == VAR_UNKNOWN)
11436 wp = firstwin;
11437 else
11438 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011439 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011440 if (tp != NULL)
11441 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11442 }
11443 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11444 {
11445 for (; wp != NULL; wp = wp->w_next)
11446 if (list_append_number(rettv->vval.v_list,
11447 wp->w_buffer->b_fnum) == FAIL)
11448 break;
11449 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011450}
11451
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011452/*
11453 * "tabpagenr()" function
11454 */
11455 static void
11456f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11457{
11458 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011459 char_u *arg;
11460
11461 if (argvars[0].v_type != VAR_UNKNOWN)
11462 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011463 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011464 nr = 0;
11465 if (arg != NULL)
11466 {
11467 if (STRCMP(arg, "$") == 0)
11468 nr = tabpage_index(NULL) - 1;
11469 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011470 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011471 }
11472 }
11473 else
11474 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011475 rettv->vval.v_number = nr;
11476}
11477
11478
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011479/*
11480 * Common code for tabpagewinnr() and winnr().
11481 */
11482 static int
11483get_winnr(tabpage_T *tp, typval_T *argvar)
11484{
11485 win_T *twin;
11486 int nr = 1;
11487 win_T *wp;
11488 char_u *arg;
11489
11490 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11491 if (argvar->v_type != VAR_UNKNOWN)
11492 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011493 int invalid_arg = FALSE;
11494
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011495 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011496 if (arg == NULL)
11497 nr = 0; /* type error; errmsg already given */
11498 else if (STRCMP(arg, "$") == 0)
11499 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11500 else if (STRCMP(arg, "#") == 0)
11501 {
11502 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11503 if (twin == NULL)
11504 nr = 0;
11505 }
11506 else
11507 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011508 long count;
11509 char_u *endp;
11510
11511 // Extract the window count (if specified). e.g. winnr('3j')
11512 count = strtol((char *)arg, (char **)&endp, 10);
11513 if (count <= 0)
11514 count = 1; // if count is not specified, default to 1
11515 if (endp != NULL && *endp != '\0')
11516 {
11517 if (STRCMP(endp, "j") == 0)
11518 twin = win_vert_neighbor(tp, twin, FALSE, count);
11519 else if (STRCMP(endp, "k") == 0)
11520 twin = win_vert_neighbor(tp, twin, TRUE, count);
11521 else if (STRCMP(endp, "h") == 0)
11522 twin = win_horz_neighbor(tp, twin, TRUE, count);
11523 else if (STRCMP(endp, "l") == 0)
11524 twin = win_horz_neighbor(tp, twin, FALSE, count);
11525 else
11526 invalid_arg = TRUE;
11527 }
11528 else
11529 invalid_arg = TRUE;
11530 }
11531
11532 if (invalid_arg)
11533 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011534 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011535 nr = 0;
11536 }
11537 }
11538
11539 if (nr > 0)
11540 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11541 wp != twin; wp = wp->w_next)
11542 {
11543 if (wp == NULL)
11544 {
11545 /* didn't find it in this tabpage */
11546 nr = 0;
11547 break;
11548 }
11549 ++nr;
11550 }
11551 return nr;
11552}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011553
11554/*
11555 * "tabpagewinnr()" function
11556 */
11557 static void
11558f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11559{
11560 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011561 tabpage_T *tp;
11562
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011563 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011564 if (tp == NULL)
11565 nr = 0;
11566 else
11567 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011568 rettv->vval.v_number = nr;
11569}
11570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011571/*
11572 * "tagfiles()" function
11573 */
11574 static void
11575f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11576{
11577 char_u *fname;
11578 tagname_T tn;
11579 int first;
11580
11581 if (rettv_list_alloc(rettv) == FAIL)
11582 return;
11583 fname = alloc(MAXPATHL);
11584 if (fname == NULL)
11585 return;
11586
11587 for (first = TRUE; ; first = FALSE)
11588 if (get_tagfname(&tn, first, fname) == FAIL
11589 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11590 break;
11591 tagname_free(&tn);
11592 vim_free(fname);
11593}
11594
11595/*
11596 * "taglist()" function
11597 */
11598 static void
11599f_taglist(typval_T *argvars, typval_T *rettv)
11600{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011601 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011602 char_u *tag_pattern;
11603
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011604 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011605
11606 rettv->vval.v_number = FALSE;
11607 if (*tag_pattern == NUL)
11608 return;
11609
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011610 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011611 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011612 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011613 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011614}
11615
11616/*
11617 * "tempname()" function
11618 */
11619 static void
11620f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11621{
11622 static int x = 'A';
11623
11624 rettv->v_type = VAR_STRING;
11625 rettv->vval.v_string = vim_tempname(x, FALSE);
11626
11627 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11628 * names. Skip 'I' and 'O', they are used for shell redirection. */
11629 do
11630 {
11631 if (x == 'Z')
11632 x = '0';
11633 else if (x == '9')
11634 x = 'A';
11635 else
11636 {
11637#ifdef EBCDIC
11638 if (x == 'I')
11639 x = 'J';
11640 else if (x == 'R')
11641 x = 'S';
11642 else
11643#endif
11644 ++x;
11645 }
11646 } while (x == 'I' || x == 'O');
11647}
11648
11649#ifdef FEAT_FLOAT
11650/*
11651 * "tan()" function
11652 */
11653 static void
11654f_tan(typval_T *argvars, typval_T *rettv)
11655{
11656 float_T f = 0.0;
11657
11658 rettv->v_type = VAR_FLOAT;
11659 if (get_float_arg(argvars, &f) == OK)
11660 rettv->vval.v_float = tan(f);
11661 else
11662 rettv->vval.v_float = 0.0;
11663}
11664
11665/*
11666 * "tanh()" function
11667 */
11668 static void
11669f_tanh(typval_T *argvars, typval_T *rettv)
11670{
11671 float_T f = 0.0;
11672
11673 rettv->v_type = VAR_FLOAT;
11674 if (get_float_arg(argvars, &f) == OK)
11675 rettv->vval.v_float = tanh(f);
11676 else
11677 rettv->vval.v_float = 0.0;
11678}
11679#endif
11680
11681/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011682 * Get a callback from "arg". It can be a Funcref or a function name.
11683 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011684 * "cb_name" is not allocated.
11685 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011686 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011687 callback_T
11688get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011689{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011690 callback_T res;
11691
11692 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011693 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11694 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011695 res.cb_partial = arg->vval.v_partial;
11696 ++res.cb_partial->pt_refcount;
11697 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011698 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011699 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011700 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011701 res.cb_partial = NULL;
11702 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11703 {
11704 // Note that we don't make a copy of the string.
11705 res.cb_name = arg->vval.v_string;
11706 func_ref(res.cb_name);
11707 }
11708 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11709 {
11710 res.cb_name = (char_u *)"";
11711 }
11712 else
11713 {
11714 emsg(_("E921: Invalid callback argument"));
11715 res.cb_name = NULL;
11716 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011717 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011718 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011719}
11720
11721/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011722 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011723 */
11724 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011725put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011726{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011727 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011728 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011729 tv->v_type = VAR_PARTIAL;
11730 tv->vval.v_partial = cb->cb_partial;
11731 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011732 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011733 else
11734 {
11735 tv->v_type = VAR_FUNC;
11736 tv->vval.v_string = vim_strsave(cb->cb_name);
11737 func_ref(cb->cb_name);
11738 }
11739}
11740
11741/*
11742 * Make a copy of "src" into "dest", allocating the function name if needed,
11743 * without incrementing the refcount.
11744 */
11745 void
11746set_callback(callback_T *dest, callback_T *src)
11747{
11748 if (src->cb_partial == NULL)
11749 {
11750 // just a function name, make a copy
11751 dest->cb_name = vim_strsave(src->cb_name);
11752 dest->cb_free_name = TRUE;
11753 }
11754 else
11755 {
11756 // cb_name is a pointer into cb_partial
11757 dest->cb_name = src->cb_name;
11758 dest->cb_free_name = FALSE;
11759 }
11760 dest->cb_partial = src->cb_partial;
11761}
11762
11763/*
11764 * Unref/free "callback" returned by get_callback() or set_callback().
11765 */
11766 void
11767free_callback(callback_T *callback)
11768{
11769 if (callback->cb_partial != NULL)
11770 {
11771 partial_unref(callback->cb_partial);
11772 callback->cb_partial = NULL;
11773 }
11774 else if (callback->cb_name != NULL)
11775 func_unref(callback->cb_name);
11776 if (callback->cb_free_name)
11777 {
11778 vim_free(callback->cb_name);
11779 callback->cb_free_name = FALSE;
11780 }
11781 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011782}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011783
11784#ifdef FEAT_TIMERS
11785/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011786 * "timer_info([timer])" function
11787 */
11788 static void
11789f_timer_info(typval_T *argvars, typval_T *rettv)
11790{
11791 timer_T *timer = NULL;
11792
11793 if (rettv_list_alloc(rettv) != OK)
11794 return;
11795 if (argvars[0].v_type != VAR_UNKNOWN)
11796 {
11797 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011798 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011799 else
11800 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011801 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011802 if (timer != NULL)
11803 add_timer_info(rettv, timer);
11804 }
11805 }
11806 else
11807 add_timer_info_all(rettv);
11808}
11809
11810/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011811 * "timer_pause(timer, paused)" function
11812 */
11813 static void
11814f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
11815{
11816 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011817 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011818
11819 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011820 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011821 else
11822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011823 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011824 if (timer != NULL)
11825 timer->tr_paused = paused;
11826 }
11827}
11828
11829/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011830 * "timer_start(time, callback [, options])" function
11831 */
11832 static void
11833f_timer_start(typval_T *argvars, typval_T *rettv)
11834{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011835 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020011836 timer_T *timer;
11837 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011838 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020011839 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011840
Bram Moolenaar75537a92016-09-05 22:45:28 +020011841 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011842 if (check_secure())
11843 return;
11844 if (argvars[2].v_type != VAR_UNKNOWN)
11845 {
11846 if (argvars[2].v_type != VAR_DICT
11847 || (dict = argvars[2].vval.v_dict) == NULL)
11848 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011849 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011850 return;
11851 }
11852 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010011853 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011854 }
11855
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011856 callback = get_callback(&argvars[1]);
11857 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020011858 return;
11859
11860 timer = create_timer(msec, repeat);
11861 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011862 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011863 else
11864 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011865 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020011866 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011867 }
11868}
11869
11870/*
11871 * "timer_stop(timer)" function
11872 */
11873 static void
11874f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
11875{
11876 timer_T *timer;
11877
11878 if (argvars[0].v_type != VAR_NUMBER)
11879 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011880 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011881 return;
11882 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011883 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011884 if (timer != NULL)
11885 stop_timer(timer);
11886}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011887
11888/*
11889 * "timer_stopall()" function
11890 */
11891 static void
11892f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11893{
11894 stop_all_timers();
11895}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011896#endif
11897
11898/*
11899 * "tolower(string)" function
11900 */
11901 static void
11902f_tolower(typval_T *argvars, typval_T *rettv)
11903{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011904 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011905 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011906}
11907
11908/*
11909 * "toupper(string)" function
11910 */
11911 static void
11912f_toupper(typval_T *argvars, typval_T *rettv)
11913{
11914 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011915 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011916}
11917
11918/*
11919 * "tr(string, fromstr, tostr)" function
11920 */
11921 static void
11922f_tr(typval_T *argvars, typval_T *rettv)
11923{
11924 char_u *in_str;
11925 char_u *fromstr;
11926 char_u *tostr;
11927 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011928 int inlen;
11929 int fromlen;
11930 int tolen;
11931 int idx;
11932 char_u *cpstr;
11933 int cplen;
11934 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011935 char_u buf[NUMBUFLEN];
11936 char_u buf2[NUMBUFLEN];
11937 garray_T ga;
11938
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011939 in_str = tv_get_string(&argvars[0]);
11940 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
11941 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011942
11943 /* Default return value: empty string. */
11944 rettv->v_type = VAR_STRING;
11945 rettv->vval.v_string = NULL;
11946 if (fromstr == NULL || tostr == NULL)
11947 return; /* type error; errmsg already given */
11948 ga_init2(&ga, (int)sizeof(char), 80);
11949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011950 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011951 /* not multi-byte: fromstr and tostr must be the same length */
11952 if (STRLEN(fromstr) != STRLEN(tostr))
11953 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011954error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011955 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011956 ga_clear(&ga);
11957 return;
11958 }
11959
11960 /* fromstr and tostr have to contain the same number of chars */
11961 while (*in_str != NUL)
11962 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011963 if (has_mbyte)
11964 {
11965 inlen = (*mb_ptr2len)(in_str);
11966 cpstr = in_str;
11967 cplen = inlen;
11968 idx = 0;
11969 for (p = fromstr; *p != NUL; p += fromlen)
11970 {
11971 fromlen = (*mb_ptr2len)(p);
11972 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
11973 {
11974 for (p = tostr; *p != NUL; p += tolen)
11975 {
11976 tolen = (*mb_ptr2len)(p);
11977 if (idx-- == 0)
11978 {
11979 cplen = tolen;
11980 cpstr = p;
11981 break;
11982 }
11983 }
11984 if (*p == NUL) /* tostr is shorter than fromstr */
11985 goto error;
11986 break;
11987 }
11988 ++idx;
11989 }
11990
11991 if (first && cpstr == in_str)
11992 {
11993 /* Check that fromstr and tostr have the same number of
11994 * (multi-byte) characters. Done only once when a character
11995 * of in_str doesn't appear in fromstr. */
11996 first = FALSE;
11997 for (p = tostr; *p != NUL; p += tolen)
11998 {
11999 tolen = (*mb_ptr2len)(p);
12000 --idx;
12001 }
12002 if (idx != 0)
12003 goto error;
12004 }
12005
12006 (void)ga_grow(&ga, cplen);
12007 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12008 ga.ga_len += cplen;
12009
12010 in_str += inlen;
12011 }
12012 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012013 {
12014 /* When not using multi-byte chars we can do it faster. */
12015 p = vim_strchr(fromstr, *in_str);
12016 if (p != NULL)
12017 ga_append(&ga, tostr[p - fromstr]);
12018 else
12019 ga_append(&ga, *in_str);
12020 ++in_str;
12021 }
12022 }
12023
12024 /* add a terminating NUL */
12025 (void)ga_grow(&ga, 1);
12026 ga_append(&ga, NUL);
12027
12028 rettv->vval.v_string = ga.ga_data;
12029}
12030
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012031/*
12032 * "trim({expr})" function
12033 */
12034 static void
12035f_trim(typval_T *argvars, typval_T *rettv)
12036{
12037 char_u buf1[NUMBUFLEN];
12038 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012039 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012040 char_u *mask = NULL;
12041 char_u *tail;
12042 char_u *prev;
12043 char_u *p;
12044 int c1;
12045
12046 rettv->v_type = VAR_STRING;
12047 if (head == NULL)
12048 {
12049 rettv->vval.v_string = NULL;
12050 return;
12051 }
12052
12053 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012054 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012055
12056 while (*head != NUL)
12057 {
12058 c1 = PTR2CHAR(head);
12059 if (mask == NULL)
12060 {
12061 if (c1 > ' ' && c1 != 0xa0)
12062 break;
12063 }
12064 else
12065 {
12066 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12067 if (c1 == PTR2CHAR(p))
12068 break;
12069 if (*p == NUL)
12070 break;
12071 }
12072 MB_PTR_ADV(head);
12073 }
12074
12075 for (tail = head + STRLEN(head); tail > head; tail = prev)
12076 {
12077 prev = tail;
12078 MB_PTR_BACK(head, prev);
12079 c1 = PTR2CHAR(prev);
12080 if (mask == NULL)
12081 {
12082 if (c1 > ' ' && c1 != 0xa0)
12083 break;
12084 }
12085 else
12086 {
12087 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12088 if (c1 == PTR2CHAR(p))
12089 break;
12090 if (*p == NUL)
12091 break;
12092 }
12093 }
12094 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12095}
12096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012097#ifdef FEAT_FLOAT
12098/*
12099 * "trunc({float})" function
12100 */
12101 static void
12102f_trunc(typval_T *argvars, typval_T *rettv)
12103{
12104 float_T f = 0.0;
12105
12106 rettv->v_type = VAR_FLOAT;
12107 if (get_float_arg(argvars, &f) == OK)
12108 /* trunc() is not in C90, use floor() or ceil() instead. */
12109 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12110 else
12111 rettv->vval.v_float = 0.0;
12112}
12113#endif
12114
12115/*
12116 * "type(expr)" function
12117 */
12118 static void
12119f_type(typval_T *argvars, typval_T *rettv)
12120{
12121 int n = -1;
12122
12123 switch (argvars[0].v_type)
12124 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012125 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12126 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012127 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012128 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12129 case VAR_LIST: n = VAR_TYPE_LIST; break;
12130 case VAR_DICT: n = VAR_TYPE_DICT; break;
12131 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012132 case VAR_SPECIAL:
12133 if (argvars[0].vval.v_number == VVAL_FALSE
12134 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012135 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012137 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012138 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012139 case VAR_JOB: n = VAR_TYPE_JOB; break;
12140 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012141 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012142 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012143 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012144 n = -1;
12145 break;
12146 }
12147 rettv->vval.v_number = n;
12148}
12149
12150/*
12151 * "undofile(name)" function
12152 */
12153 static void
12154f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12155{
12156 rettv->v_type = VAR_STRING;
12157#ifdef FEAT_PERSISTENT_UNDO
12158 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012159 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012160
12161 if (*fname == NUL)
12162 {
12163 /* If there is no file name there will be no undo file. */
12164 rettv->vval.v_string = NULL;
12165 }
12166 else
12167 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012168 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012169
12170 if (ffname != NULL)
12171 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12172 vim_free(ffname);
12173 }
12174 }
12175#else
12176 rettv->vval.v_string = NULL;
12177#endif
12178}
12179
12180/*
12181 * "undotree()" function
12182 */
12183 static void
12184f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12185{
12186 if (rettv_dict_alloc(rettv) == OK)
12187 {
12188 dict_T *dict = rettv->vval.v_dict;
12189 list_T *list;
12190
Bram Moolenaare0be1672018-07-08 16:50:37 +020012191 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12192 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12193 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12194 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12195 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12196 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012197
12198 list = list_alloc();
12199 if (list != NULL)
12200 {
12201 u_eval_tree(curbuf->b_u_oldhead, list);
12202 dict_add_list(dict, "entries", list);
12203 }
12204 }
12205}
12206
12207/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012208 * "virtcol(string)" function
12209 */
12210 static void
12211f_virtcol(typval_T *argvars, typval_T *rettv)
12212{
12213 colnr_T vcol = 0;
12214 pos_T *fp;
12215 int fnum = curbuf->b_fnum;
12216
12217 fp = var2fpos(&argvars[0], FALSE, &fnum);
12218 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12219 && fnum == curbuf->b_fnum)
12220 {
12221 getvvcol(curwin, fp, NULL, NULL, &vcol);
12222 ++vcol;
12223 }
12224
12225 rettv->vval.v_number = vcol;
12226}
12227
12228/*
12229 * "visualmode()" function
12230 */
12231 static void
12232f_visualmode(typval_T *argvars, typval_T *rettv)
12233{
12234 char_u str[2];
12235
12236 rettv->v_type = VAR_STRING;
12237 str[0] = curbuf->b_visual_mode_eval;
12238 str[1] = NUL;
12239 rettv->vval.v_string = vim_strsave(str);
12240
12241 /* A non-zero number or non-empty string argument: reset mode. */
12242 if (non_zero_arg(&argvars[0]))
12243 curbuf->b_visual_mode_eval = NUL;
12244}
12245
12246/*
12247 * "wildmenumode()" function
12248 */
12249 static void
12250f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12251{
12252#ifdef FEAT_WILDMENU
12253 if (wild_menu_showing)
12254 rettv->vval.v_number = 1;
12255#endif
12256}
12257
12258/*
12259 * "winbufnr(nr)" function
12260 */
12261 static void
12262f_winbufnr(typval_T *argvars, typval_T *rettv)
12263{
12264 win_T *wp;
12265
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012266 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012267 if (wp == NULL)
12268 rettv->vval.v_number = -1;
12269 else
12270 rettv->vval.v_number = wp->w_buffer->b_fnum;
12271}
12272
12273/*
12274 * "wincol()" function
12275 */
12276 static void
12277f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12278{
12279 validate_cursor();
12280 rettv->vval.v_number = curwin->w_wcol + 1;
12281}
12282
12283/*
12284 * "winheight(nr)" function
12285 */
12286 static void
12287f_winheight(typval_T *argvars, typval_T *rettv)
12288{
12289 win_T *wp;
12290
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012291 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012292 if (wp == NULL)
12293 rettv->vval.v_number = -1;
12294 else
12295 rettv->vval.v_number = wp->w_height;
12296}
12297
12298/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012299 * "winlayout()" function
12300 */
12301 static void
12302f_winlayout(typval_T *argvars, typval_T *rettv)
12303{
12304 tabpage_T *tp;
12305
12306 if (rettv_list_alloc(rettv) != OK)
12307 return;
12308
12309 if (argvars[0].v_type == VAR_UNKNOWN)
12310 tp = curtab;
12311 else
12312 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012313 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012314 if (tp == NULL)
12315 return;
12316 }
12317
12318 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12319}
12320
12321/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012322 * "winline()" function
12323 */
12324 static void
12325f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12326{
12327 validate_cursor();
12328 rettv->vval.v_number = curwin->w_wrow + 1;
12329}
12330
12331/*
12332 * "winnr()" function
12333 */
12334 static void
12335f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12336{
12337 int nr = 1;
12338
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012339 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012340 rettv->vval.v_number = nr;
12341}
12342
12343/*
12344 * "winrestcmd()" function
12345 */
12346 static void
12347f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12348{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012349 win_T *wp;
12350 int winnr = 1;
12351 garray_T ga;
12352 char_u buf[50];
12353
12354 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012355 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012356 {
12357 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12358 ga_concat(&ga, buf);
12359 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12360 ga_concat(&ga, buf);
12361 ++winnr;
12362 }
12363 ga_append(&ga, NUL);
12364
12365 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012366 rettv->v_type = VAR_STRING;
12367}
12368
12369/*
12370 * "winrestview()" function
12371 */
12372 static void
12373f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12374{
12375 dict_T *dict;
12376
12377 if (argvars[0].v_type != VAR_DICT
12378 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012379 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012380 else
12381 {
12382 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012383 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012384 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012385 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012386 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012387 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012388 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12389 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012390 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012391 curwin->w_set_curswant = FALSE;
12392 }
12393
12394 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012395 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012396#ifdef FEAT_DIFF
12397 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012398 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012399#endif
12400 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012401 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012402 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012403 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012404
12405 check_cursor();
12406 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012407 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012408 changed_window_setting();
12409
12410 if (curwin->w_topline <= 0)
12411 curwin->w_topline = 1;
12412 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12413 curwin->w_topline = curbuf->b_ml.ml_line_count;
12414#ifdef FEAT_DIFF
12415 check_topfill(curwin, TRUE);
12416#endif
12417 }
12418}
12419
12420/*
12421 * "winsaveview()" function
12422 */
12423 static void
12424f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12425{
12426 dict_T *dict;
12427
12428 if (rettv_dict_alloc(rettv) == FAIL)
12429 return;
12430 dict = rettv->vval.v_dict;
12431
Bram Moolenaare0be1672018-07-08 16:50:37 +020012432 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12433 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012434 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012435 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012436 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012437
Bram Moolenaare0be1672018-07-08 16:50:37 +020012438 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012439#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012440 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012441#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012442 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12443 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012444}
12445
12446/*
12447 * "winwidth(nr)" function
12448 */
12449 static void
12450f_winwidth(typval_T *argvars, typval_T *rettv)
12451{
12452 win_T *wp;
12453
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012454 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012455 if (wp == NULL)
12456 rettv->vval.v_number = -1;
12457 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012458 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459}
12460
12461/*
12462 * "wordcount()" function
12463 */
12464 static void
12465f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12466{
12467 if (rettv_dict_alloc(rettv) == FAIL)
12468 return;
12469 cursor_pos_info(rettv->vval.v_dict);
12470}
12471
12472/*
12473 * "writefile()" function
12474 */
12475 static void
12476f_writefile(typval_T *argvars, typval_T *rettv)
12477{
12478 int binary = FALSE;
12479 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012480#ifdef HAVE_FSYNC
12481 int do_fsync = p_fs;
12482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483 char_u *fname;
12484 FILE *fd;
12485 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012486 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012487 list_T *list = NULL;
12488 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012489
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012490 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012491 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012492 return;
12493
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012494 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012495 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012496 list = argvars[0].vval.v_list;
12497 if (list == NULL)
12498 return;
12499 for (li = list->lv_first; li != NULL; li = li->li_next)
12500 if (tv_get_string_chk(&li->li_tv) == NULL)
12501 return;
12502 }
12503 else if (argvars[0].v_type == VAR_BLOB)
12504 {
12505 blob = argvars[0].vval.v_blob;
12506 if (blob == NULL)
12507 return;
12508 }
12509 else
12510 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012511 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012512 return;
12513 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012514
12515 if (argvars[2].v_type != VAR_UNKNOWN)
12516 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012517 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012518
12519 if (arg2 == NULL)
12520 return;
12521 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012522 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012523 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012524 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012525#ifdef HAVE_FSYNC
12526 if (vim_strchr(arg2, 's') != NULL)
12527 do_fsync = TRUE;
12528 else if (vim_strchr(arg2, 'S') != NULL)
12529 do_fsync = FALSE;
12530#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531 }
12532
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012533 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012534 if (fname == NULL)
12535 return;
12536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012537 /* Always open the file in binary mode, library functions have a mind of
12538 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012539 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12540 append ? APPENDBIN : WRITEBIN)) == NULL)
12541 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012542 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012543 ret = -1;
12544 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012545 else if (blob)
12546 {
12547 if (write_blob(fd, blob) == FAIL)
12548 ret = -1;
12549#ifdef HAVE_FSYNC
12550 else if (do_fsync)
12551 // Ignore the error, the user wouldn't know what to do about it.
12552 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012553 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012554#endif
12555 fclose(fd);
12556 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012557 else
12558 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012559 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012560 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012561#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012562 else if (do_fsync)
12563 /* Ignore the error, the user wouldn't know what to do about it.
12564 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012565 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012566#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012567 fclose(fd);
12568 }
12569
12570 rettv->vval.v_number = ret;
12571}
12572
12573/*
12574 * "xor(expr, expr)" function
12575 */
12576 static void
12577f_xor(typval_T *argvars, typval_T *rettv)
12578{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012579 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12580 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012581}
12582
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012583#endif /* FEAT_EVAL */