blob: a2964286fc36f962e72b0f882878dbebb34334e0 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020024# include <time.h> /* for time_t */
25#endif
26
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010027static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020029
30#ifdef FEAT_FLOAT
31static void f_abs(typval_T *argvars, typval_T *rettv);
32static void f_acos(typval_T *argvars, typval_T *rettv);
33#endif
34static void f_add(typval_T *argvars, typval_T *rettv);
35static void f_and(typval_T *argvars, typval_T *rettv);
36static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020037static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +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);
132static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100133static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_getchar(typval_T *argvars, typval_T *rettv);
135static void f_getcharmod(typval_T *argvars, typval_T *rettv);
136static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
137static void f_getcmdline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
139static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
140static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
141static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200142static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143static void f_getfontname(typval_T *argvars, typval_T *rettv);
144static void f_getfperm(typval_T *argvars, typval_T *rettv);
145static void f_getfsize(typval_T *argvars, typval_T *rettv);
146static void f_getftime(typval_T *argvars, typval_T *rettv);
147static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100148static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200150static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200151static void f_getpid(typval_T *argvars, typval_T *rettv);
152static void f_getcurpos(typval_T *argvars, typval_T *rettv);
153static void f_getpos(typval_T *argvars, typval_T *rettv);
154static void f_getqflist(typval_T *argvars, typval_T *rettv);
155static void f_getreg(typval_T *argvars, typval_T *rettv);
156static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200157static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_gettabvar(typval_T *argvars, typval_T *rettv);
159static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100160static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200161static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100162static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_getwinposx(typval_T *argvars, typval_T *rettv);
164static void f_getwinposy(typval_T *argvars, typval_T *rettv);
165static void f_getwinvar(typval_T *argvars, typval_T *rettv);
166static void f_glob(typval_T *argvars, typval_T *rettv);
167static void f_globpath(typval_T *argvars, typval_T *rettv);
168static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
169static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
171static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_hlID(typval_T *argvars, typval_T *rettv);
173static void f_hlexists(typval_T *argvars, typval_T *rettv);
174static void f_hostname(typval_T *argvars, typval_T *rettv);
175static void f_iconv(typval_T *argvars, typval_T *rettv);
176static void f_indent(typval_T *argvars, typval_T *rettv);
177static void f_index(typval_T *argvars, typval_T *rettv);
178static void f_input(typval_T *argvars, typval_T *rettv);
179static void f_inputdialog(typval_T *argvars, typval_T *rettv);
180static void f_inputlist(typval_T *argvars, typval_T *rettv);
181static void f_inputrestore(typval_T *argvars, typval_T *rettv);
182static void f_inputsave(typval_T *argvars, typval_T *rettv);
183static void f_inputsecret(typval_T *argvars, typval_T *rettv);
184static void f_insert(typval_T *argvars, typval_T *rettv);
185static void f_invert(typval_T *argvars, typval_T *rettv);
186static void f_isdirectory(typval_T *argvars, typval_T *rettv);
187static void f_islocked(typval_T *argvars, typval_T *rettv);
188#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200189static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190static void f_isnan(typval_T *argvars, typval_T *rettv);
191#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
193static void f_len(typval_T *argvars, typval_T *rettv);
194static void f_libcall(typval_T *argvars, typval_T *rettv);
195static void f_libcallnr(typval_T *argvars, typval_T *rettv);
196static void f_line(typval_T *argvars, typval_T *rettv);
197static void f_line2byte(typval_T *argvars, typval_T *rettv);
198static void f_lispindent(typval_T *argvars, typval_T *rettv);
199static void f_localtime(typval_T *argvars, typval_T *rettv);
200#ifdef FEAT_FLOAT
201static void f_log(typval_T *argvars, typval_T *rettv);
202static void f_log10(typval_T *argvars, typval_T *rettv);
203#endif
204#ifdef FEAT_LUA
205static void f_luaeval(typval_T *argvars, typval_T *rettv);
206#endif
207static void f_map(typval_T *argvars, typval_T *rettv);
208static void f_maparg(typval_T *argvars, typval_T *rettv);
209static void f_mapcheck(typval_T *argvars, typval_T *rettv);
210static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_matchend(typval_T *argvars, typval_T *rettv);
212static void f_matchlist(typval_T *argvars, typval_T *rettv);
213static void f_matchstr(typval_T *argvars, typval_T *rettv);
214static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
215static void f_max(typval_T *argvars, typval_T *rettv);
216static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218static void f_mode(typval_T *argvars, typval_T *rettv);
219#ifdef FEAT_MZSCHEME
220static void f_mzeval(typval_T *argvars, typval_T *rettv);
221#endif
222static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
223static void f_nr2char(typval_T *argvars, typval_T *rettv);
224static void f_or(typval_T *argvars, typval_T *rettv);
225static void f_pathshorten(typval_T *argvars, typval_T *rettv);
226#ifdef FEAT_PERL
227static void f_perleval(typval_T *argvars, typval_T *rettv);
228#endif
229#ifdef FEAT_FLOAT
230static void f_pow(typval_T *argvars, typval_T *rettv);
231#endif
232static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
233static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200234static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_pumvisible(typval_T *argvars, typval_T *rettv);
236#ifdef FEAT_PYTHON3
237static void f_py3eval(typval_T *argvars, typval_T *rettv);
238#endif
239#ifdef FEAT_PYTHON
240static void f_pyeval(typval_T *argvars, typval_T *rettv);
241#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100242#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
243static void f_pyxeval(typval_T *argvars, typval_T *rettv);
244#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200246static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200248static void f_reg_executing(typval_T *argvars, typval_T *rettv);
249static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250static void f_reltime(typval_T *argvars, typval_T *rettv);
251#ifdef FEAT_FLOAT
252static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
253#endif
254static void f_reltimestr(typval_T *argvars, typval_T *rettv);
255static void f_remote_expr(typval_T *argvars, typval_T *rettv);
256static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
257static void f_remote_peek(typval_T *argvars, typval_T *rettv);
258static void f_remote_read(typval_T *argvars, typval_T *rettv);
259static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100260static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_remove(typval_T *argvars, typval_T *rettv);
262static void f_rename(typval_T *argvars, typval_T *rettv);
263static void f_repeat(typval_T *argvars, typval_T *rettv);
264static void f_resolve(typval_T *argvars, typval_T *rettv);
265static void f_reverse(typval_T *argvars, typval_T *rettv);
266#ifdef FEAT_FLOAT
267static void f_round(typval_T *argvars, typval_T *rettv);
268#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100269#ifdef FEAT_RUBY
270static void f_rubyeval(typval_T *argvars, typval_T *rettv);
271#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272static void f_screenattr(typval_T *argvars, typval_T *rettv);
273static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100274static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_screencol(typval_T *argvars, typval_T *rettv);
276static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100277static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200278static void f_search(typval_T *argvars, typval_T *rettv);
279static void f_searchdecl(typval_T *argvars, typval_T *rettv);
280static void f_searchpair(typval_T *argvars, typval_T *rettv);
281static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
282static void f_searchpos(typval_T *argvars, typval_T *rettv);
283static void f_server2client(typval_T *argvars, typval_T *rettv);
284static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200285static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200286static void f_setbufvar(typval_T *argvars, typval_T *rettv);
287static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
288static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200289static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290static void f_setfperm(typval_T *argvars, typval_T *rettv);
291static void f_setline(typval_T *argvars, typval_T *rettv);
292static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293static void f_setpos(typval_T *argvars, typval_T *rettv);
294static void f_setqflist(typval_T *argvars, typval_T *rettv);
295static void f_setreg(typval_T *argvars, typval_T *rettv);
296static void f_settabvar(typval_T *argvars, typval_T *rettv);
297static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100298static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_setwinvar(typval_T *argvars, typval_T *rettv);
300#ifdef FEAT_CRYPT
301static void f_sha256(typval_T *argvars, typval_T *rettv);
302#endif /* FEAT_CRYPT */
303static void f_shellescape(typval_T *argvars, typval_T *rettv);
304static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
305static void f_simplify(typval_T *argvars, typval_T *rettv);
306#ifdef FEAT_FLOAT
307static void f_sin(typval_T *argvars, typval_T *rettv);
308static void f_sinh(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310static void f_soundfold(typval_T *argvars, typval_T *rettv);
311static void f_spellbadword(typval_T *argvars, typval_T *rettv);
312static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
313static void f_split(typval_T *argvars, typval_T *rettv);
314#ifdef FEAT_FLOAT
315static void f_sqrt(typval_T *argvars, typval_T *rettv);
316static void f_str2float(typval_T *argvars, typval_T *rettv);
317#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200318static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319static void f_str2nr(typval_T *argvars, typval_T *rettv);
320static void f_strchars(typval_T *argvars, typval_T *rettv);
321#ifdef HAVE_STRFTIME
322static void f_strftime(typval_T *argvars, typval_T *rettv);
323#endif
324static void f_strgetchar(typval_T *argvars, typval_T *rettv);
325static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_strlen(typval_T *argvars, typval_T *rettv);
327static void f_strcharpart(typval_T *argvars, typval_T *rettv);
328static void f_strpart(typval_T *argvars, typval_T *rettv);
329static void f_strridx(typval_T *argvars, typval_T *rettv);
330static void f_strtrans(typval_T *argvars, typval_T *rettv);
331static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
332static void f_strwidth(typval_T *argvars, typval_T *rettv);
333static void f_submatch(typval_T *argvars, typval_T *rettv);
334static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200335static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200336static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337static void f_synID(typval_T *argvars, typval_T *rettv);
338static void f_synIDattr(typval_T *argvars, typval_T *rettv);
339static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
340static void f_synstack(typval_T *argvars, typval_T *rettv);
341static void f_synconcealed(typval_T *argvars, typval_T *rettv);
342static void f_system(typval_T *argvars, typval_T *rettv);
343static void f_systemlist(typval_T *argvars, typval_T *rettv);
344static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
345static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
346static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
347static void f_taglist(typval_T *argvars, typval_T *rettv);
348static void f_tagfiles(typval_T *argvars, typval_T *rettv);
349static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200350#ifdef FEAT_FLOAT
351static void f_tan(typval_T *argvars, typval_T *rettv);
352static void f_tanh(typval_T *argvars, typval_T *rettv);
353#endif
354#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200355static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200356static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357static void f_timer_start(typval_T *argvars, typval_T *rettv);
358static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200359static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200360#endif
361static void f_tolower(typval_T *argvars, typval_T *rettv);
362static void f_toupper(typval_T *argvars, typval_T *rettv);
363static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100364static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200365#ifdef FEAT_FLOAT
366static void f_trunc(typval_T *argvars, typval_T *rettv);
367#endif
368static void f_type(typval_T *argvars, typval_T *rettv);
369static void f_undofile(typval_T *argvars, typval_T *rettv);
370static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200371static void f_virtcol(typval_T *argvars, typval_T *rettv);
372static void f_visualmode(typval_T *argvars, typval_T *rettv);
373static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200374static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200375static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
376static void f_win_getid(typval_T *argvars, typval_T *rettv);
377static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
378static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
379static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100380static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381static void f_winbufnr(typval_T *argvars, typval_T *rettv);
382static void f_wincol(typval_T *argvars, typval_T *rettv);
383static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200384static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200385static void f_winline(typval_T *argvars, typval_T *rettv);
386static void f_winnr(typval_T *argvars, typval_T *rettv);
387static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
388static void f_winrestview(typval_T *argvars, typval_T *rettv);
389static void f_winsaveview(typval_T *argvars, typval_T *rettv);
390static void f_winwidth(typval_T *argvars, typval_T *rettv);
391static void f_writefile(typval_T *argvars, typval_T *rettv);
392static void f_wordcount(typval_T *argvars, typval_T *rettv);
393static void f_xor(typval_T *argvars, typval_T *rettv);
394
395/*
396 * Array with names and number of arguments of all internal functions
397 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
398 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200399typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200401 char *f_name; // function name
402 char f_min_argc; // minimal number of arguments
403 char f_max_argc; // maximal number of arguments
404 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200405 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200406 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200407} funcentry_T;
408
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200409// values for f_argtype; zero means it cannot be used as a method
410#define FEARG_1 1 // base is the first argument
411#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200412#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413#define FEARG_LAST 9 // base is the last argument
414
Bram Moolenaarac92e252019-08-03 21:58:38 +0200415static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416{
417#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200418 {"abs", 1, 1, FEARG_1, f_abs},
419 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200421 {"add", 2, 2, FEARG_1, f_add},
422 {"and", 2, 2, 0, f_and},
423 {"append", 2, 2, FEARG_LAST, f_append},
424 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
425 {"argc", 0, 1, 0, f_argc},
426 {"argidx", 0, 0, 0, f_argidx},
427 {"arglistid", 0, 2, 0, f_arglistid},
428 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200430 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200431#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200432 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
434 {"assert_equalfile", 2, 2, 0, f_assert_equalfile},
435 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200436 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
437 {"assert_false", 1, 2, FEARG_1, f_assert_false},
438 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
439 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200440 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200441 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200442 {"assert_report", 1, 1, 0, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200443 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200445 {"atan", 1, 1, FEARG_1, f_atan},
446 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100448#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200449 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
450 {"balloon_show", 1, 1, 0, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100451# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200452 {"balloon_split", 1, 1, 0, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100453# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100454#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"browse", 4, 4, 0, f_browse},
456 {"browsedir", 2, 2, 0, f_browsedir},
457 {"bufadd", 1, 1, 0, f_bufadd},
458 {"bufexists", 1, 1, 0, f_bufexists},
459 {"buffer_exists", 1, 1, 0, f_bufexists}, // obsolete
460 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
461 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
462 {"buflisted", 1, 1, 0, f_buflisted},
463 {"bufload", 1, 1, 0, f_bufload},
464 {"bufloaded", 1, 1, 0, f_bufloaded},
465 {"bufname", 1, 1, 0, f_bufname},
466 {"bufnr", 1, 2, 0, f_bufnr},
467 {"bufwinid", 1, 1, 0, f_bufwinid},
468 {"bufwinnr", 1, 1, 0, f_bufwinnr},
469 {"byte2line", 1, 1, 0, f_byte2line},
470 {"byteidx", 2, 2, 0, f_byteidx},
471 {"byteidxcomp", 2, 2, 0, f_byteidxcomp},
472 {"call", 2, 3, 0, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200474 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200475#endif
476#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200477 {"ch_canread", 1, 1, 0, f_ch_canread},
478 {"ch_close", 1, 1, 0, f_ch_close},
479 {"ch_close_in", 1, 1, 0, f_ch_close_in},
480 {"ch_evalexpr", 2, 3, 0, f_ch_evalexpr},
481 {"ch_evalraw", 2, 3, 0, f_ch_evalraw},
482 {"ch_getbufnr", 2, 2, 0, f_ch_getbufnr},
483 {"ch_getjob", 1, 1, 0, f_ch_getjob},
484 {"ch_info", 1, 1, 0, f_ch_info},
485 {"ch_log", 1, 2, 0, f_ch_log},
486 {"ch_logfile", 1, 2, 0, f_ch_logfile},
487 {"ch_open", 1, 2, 0, f_ch_open},
488 {"ch_read", 1, 2, 0, f_ch_read},
489 {"ch_readblob", 1, 2, 0, f_ch_readblob},
490 {"ch_readraw", 1, 2, 0, f_ch_readraw},
491 {"ch_sendexpr", 2, 3, 0, f_ch_sendexpr},
492 {"ch_sendraw", 2, 3, 0, f_ch_sendraw},
493 {"ch_setoptions", 2, 2, 0, f_ch_setoptions},
494 {"ch_status", 1, 2, 0, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200495#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200496 {"changenr", 0, 0, 0, f_changenr},
497 {"char2nr", 1, 2, 0, f_char2nr},
498 {"chdir", 1, 1, 0, f_chdir},
499 {"cindent", 1, 1, 0, f_cindent},
500 {"clearmatches", 0, 1, 0, f_clearmatches},
501 {"col", 1, 1, 0, f_col},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200502#if defined(FEAT_INS_EXPAND)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200503 {"complete", 2, 2, 0, f_complete},
504 {"complete_add", 1, 1, 0, f_complete_add},
505 {"complete_check", 0, 0, 0, f_complete_check},
506 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200508 {"confirm", 1, 4, 0, f_confirm},
509 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200510#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200511 {"cos", 1, 1, FEARG_1, f_cos},
512 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"count", 2, 4, FEARG_1, f_count},
515 {"cscope_connection",0,3, 0, f_cscope_connection},
516 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100517#ifdef MSWIN
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200518 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200519#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200520 {"deepcopy", 1, 2, 0, f_deepcopy},
521 {"delete", 1, 2, 0, f_delete},
522 {"deletebufline", 2, 3, 0, f_deletebufline},
523 {"did_filetype", 0, 0, 0, f_did_filetype},
524 {"diff_filler", 1, 1, 0, f_diff_filler},
525 {"diff_hlID", 2, 2, 0, f_diff_hlID},
526 {"empty", 1, 1, FEARG_1, f_empty},
527 {"environ", 0, 0, 0, f_environ},
528 {"escape", 2, 2, 0, f_escape},
529 {"eval", 1, 1, FEARG_1, f_eval},
530 {"eventhandler", 0, 0, 0, f_eventhandler},
531 {"executable", 1, 1, 0, f_executable},
532 {"execute", 1, 2, 0, f_execute},
533 {"exepath", 1, 1, 0, f_exepath},
534 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200536 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200538 {"expand", 1, 3, 0, f_expand},
539 {"expandcmd", 1, 1, 0, f_expandcmd},
540 {"extend", 2, 3, FEARG_1, f_extend},
541 {"feedkeys", 1, 2, 0, f_feedkeys},
542 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
543 {"filereadable", 1, 1, 0, f_filereadable},
544 {"filewritable", 1, 1, 0, f_filewritable},
545 {"filter", 2, 2, FEARG_1, f_filter},
546 {"finddir", 1, 3, 0, f_finddir},
547 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200548#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200549 {"float2nr", 1, 1, FEARG_1, f_float2nr},
550 {"floor", 1, 1, FEARG_1, f_floor},
551 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200553 {"fnameescape", 1, 1, 0, f_fnameescape},
554 {"fnamemodify", 2, 2, 0, f_fnamemodify},
555 {"foldclosed", 1, 1, 0, f_foldclosed},
556 {"foldclosedend", 1, 1, 0, f_foldclosedend},
557 {"foldlevel", 1, 1, 0, f_foldlevel},
558 {"foldtext", 0, 0, 0, f_foldtext},
559 {"foldtextresult", 1, 1, 0, f_foldtextresult},
560 {"foreground", 0, 0, 0, f_foreground},
561 {"funcref", 1, 3, 0, f_funcref},
562 {"function", 1, 3, 0, f_function},
563 {"garbagecollect", 0, 1, 0, f_garbagecollect},
564 {"get", 2, 3, FEARG_1, f_get},
565 {"getbufinfo", 0, 1, 0, f_getbufinfo},
566 {"getbufline", 2, 3, 0, f_getbufline},
567 {"getbufvar", 2, 3, 0, f_getbufvar},
568 {"getchangelist", 1, 1, 0, f_getchangelist},
569 {"getchar", 0, 1, 0, f_getchar},
570 {"getcharmod", 0, 0, 0, f_getcharmod},
571 {"getcharsearch", 0, 0, 0, f_getcharsearch},
572 {"getcmdline", 0, 0, 0, f_getcmdline},
573 {"getcmdpos", 0, 0, 0, f_getcmdpos},
574 {"getcmdtype", 0, 0, 0, f_getcmdtype},
575 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200576 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200577 {"getcurpos", 0, 0, 0, f_getcurpos},
578 {"getcwd", 0, 2, 0, f_getcwd},
579 {"getenv", 1, 1, 0, f_getenv},
580 {"getfontname", 0, 1, 0, f_getfontname},
581 {"getfperm", 1, 1, 0, f_getfperm},
582 {"getfsize", 1, 1, 0, f_getfsize},
583 {"getftime", 1, 1, 0, f_getftime},
584 {"getftype", 1, 1, 0, f_getftype},
585 {"getjumplist", 0, 2, 0, f_getjumplist},
586 {"getline", 1, 2, 0, f_getline},
587 {"getloclist", 1, 2, 0, f_getloclist},
588 {"getmatches", 0, 1, 0, f_getmatches},
589 {"getpid", 0, 0, 0, f_getpid},
590 {"getpos", 1, 1, 0, f_getpos},
591 {"getqflist", 0, 1, 0, f_getqflist},
592 {"getreg", 0, 3, 0, f_getreg},
593 {"getregtype", 0, 1, 0, f_getregtype},
594 {"gettabinfo", 0, 1, 0, f_gettabinfo},
595 {"gettabvar", 2, 3, 0, f_gettabvar},
596 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
597 {"gettagstack", 0, 1, 0, f_gettagstack},
598 {"getwininfo", 0, 1, 0, f_getwininfo},
599 {"getwinpos", 0, 1, 0, f_getwinpos},
600 {"getwinposx", 0, 0, 0, f_getwinposx},
601 {"getwinposy", 0, 0, 0, f_getwinposy},
602 {"getwinvar", 2, 3, 0, f_getwinvar},
603 {"glob", 1, 4, 0, f_glob},
604 {"glob2regpat", 1, 1, 0, f_glob2regpat},
605 {"globpath", 2, 5, 0, f_globpath},
606 {"has", 1, 1, 0, f_has},
607 {"has_key", 2, 2, FEARG_1, f_has_key},
608 {"haslocaldir", 0, 2, 0, f_haslocaldir},
609 {"hasmapto", 1, 3, 0, f_hasmapto},
610 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
611 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
612 {"histadd", 2, 2, 0, f_histadd},
613 {"histdel", 1, 2, 0, f_histdel},
614 {"histget", 1, 2, 0, f_histget},
615 {"histnr", 1, 1, 0, f_histnr},
616 {"hlID", 1, 1, 0, f_hlID},
617 {"hlexists", 1, 1, 0, f_hlexists},
618 {"hostname", 0, 0, 0, f_hostname},
619 {"iconv", 3, 3, 0, f_iconv},
620 {"indent", 1, 1, 0, f_indent},
621 {"index", 2, 4, FEARG_1, f_index},
622 {"input", 1, 3, 0, f_input},
623 {"inputdialog", 1, 3, 0, f_inputdialog},
624 {"inputlist", 1, 1, 0, f_inputlist},
625 {"inputrestore", 0, 0, 0, f_inputrestore},
626 {"inputsave", 0, 0, 0, f_inputsave},
627 {"inputsecret", 1, 2, 0, f_inputsecret},
628 {"insert", 2, 3, FEARG_1, f_insert},
629 {"invert", 1, 1, 0, f_invert},
630 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200631#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200632 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200633#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200634 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200636 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200638 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200639#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200640 {"job_getchannel", 1, 1, 0, f_job_getchannel},
641 {"job_info", 0, 1, 0, f_job_info},
642 {"job_setoptions", 2, 2, 0, f_job_setoptions},
643 {"job_start", 1, 2, 0, f_job_start},
644 {"job_status", 1, 1, 0, f_job_status},
645 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200647 {"join", 1, 2, FEARG_1, f_join},
648 {"js_decode", 1, 1, 0, f_js_decode},
649 {"js_encode", 1, 1, 0, f_js_encode},
650 {"json_decode", 1, 1, 0, f_json_decode},
651 {"json_encode", 1, 1, 0, f_json_encode},
652 {"keys", 1, 1, FEARG_1, f_keys},
653 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
654 {"len", 1, 1, FEARG_1, f_len},
655 {"libcall", 3, 3, 0, f_libcall},
656 {"libcallnr", 3, 3, 0, f_libcallnr},
657 {"line", 1, 1, 0, f_line},
658 {"line2byte", 1, 1, 0, f_line2byte},
659 {"lispindent", 1, 1, 0, f_lispindent},
660 {"list2str", 1, 2, 0, f_list2str},
661 {"listener_add", 1, 2, 0, f_listener_add},
662 {"listener_flush", 0, 1, 0, f_listener_flush},
663 {"listener_remove", 1, 1, 0, f_listener_remove},
664 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200666 {"log", 1, 1, FEARG_1, f_log},
667 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668#endif
669#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200670 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200672 {"map", 2, 2, FEARG_1, f_map},
673 {"maparg", 1, 4, 0, f_maparg},
674 {"mapcheck", 1, 3, 0, f_mapcheck},
675 {"match", 2, 4, 0, f_match},
676 {"matchadd", 2, 5, 0, f_matchadd},
677 {"matchaddpos", 2, 5, 0, f_matchaddpos},
678 {"matcharg", 1, 1, 0, f_matcharg},
679 {"matchdelete", 1, 2, 0, f_matchdelete},
680 {"matchend", 2, 4, 0, f_matchend},
681 {"matchlist", 2, 4, 0, f_matchlist},
682 {"matchstr", 2, 4, 0, f_matchstr},
683 {"matchstrpos", 2, 4, 0, f_matchstrpos},
684 {"max", 1, 1, FEARG_1, f_max},
685 {"min", 1, 1, FEARG_1, f_min},
686 {"mkdir", 1, 3, 0, f_mkdir},
687 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200690#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200691 {"nextnonblank", 1, 1, 0, f_nextnonblank},
692 {"nr2char", 1, 2, 0, f_nr2char},
693 {"or", 2, 2, 0, f_or},
694 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200696 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200698#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200699 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
700 {"popup_beval", 2, 2, 0, f_popup_beval},
701 {"popup_clear", 0, 0, 0, f_popup_clear},
702 {"popup_close", 1, 2, 0, f_popup_close},
703 {"popup_create", 2, 2, 0, f_popup_create},
704 {"popup_dialog", 2, 2, 0, f_popup_dialog},
705 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
706 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
707 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
708 {"popup_getpos", 1, 1, 0, f_popup_getpos},
709 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
710 {"popup_hide", 1, 1, 0, f_popup_hide},
711 {"popup_locate", 2, 2, 0, f_popup_locate},
712 {"popup_menu", 2, 2, 0, f_popup_menu},
713 {"popup_move", 2, 2, 0, f_popup_move},
714 {"popup_notification", 2, 2, 0, f_popup_notification},
715 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
716 {"popup_settext", 2, 2, 0, f_popup_settext},
717 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200718#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200719#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200720 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200721#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200722 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200723 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200724#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200725 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
726 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
727 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200728#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100729#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"prop_add", 3, 3, 0, f_prop_add},
731 {"prop_clear", 1, 3, 0, f_prop_clear},
732 {"prop_list", 1, 2, 0, f_prop_list},
733 {"prop_remove", 1, 3, 0, f_prop_remove},
734 {"prop_type_add", 2, 2, 0, f_prop_type_add},
735 {"prop_type_change", 2, 2, 0, f_prop_type_change},
736 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
737 {"prop_type_get", 1, 2, 0, f_prop_type_get},
738 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100739#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200740 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200741 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200743 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#endif
745#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200746 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100748#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200749 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100750#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200751 {"range", 1, 3, 0, f_range},
752 {"readdir", 1, 2, 0, f_readdir},
753 {"readfile", 1, 3, 0, f_readfile},
754 {"reg_executing", 0, 0, 0, f_reg_executing},
755 {"reg_recording", 0, 0, 0, f_reg_recording},
756 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200759#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"reltimestr", 1, 1, 0, f_reltimestr},
761 {"remote_expr", 2, 4, 0, f_remote_expr},
762 {"remote_foreground", 1, 1, 0, f_remote_foreground},
763 {"remote_peek", 1, 2, 0, f_remote_peek},
764 {"remote_read", 1, 2, 0, f_remote_read},
765 {"remote_send", 2, 3, 0, f_remote_send},
766 {"remote_startserver", 1, 1, 0, f_remote_startserver},
767 {"remove", 2, 3, FEARG_1, f_remove},
768 {"rename", 2, 2, 0, f_rename},
769 {"repeat", 2, 2, FEARG_1, f_repeat},
770 {"resolve", 1, 1, 0, f_resolve},
771 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200773 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200774#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100775#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200776 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100777#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200778 {"screenattr", 2, 2, 0, f_screenattr},
779 {"screenchar", 2, 2, 0, f_screenchar},
780 {"screenchars", 2, 2, 0, f_screenchars},
781 {"screencol", 0, 0, 0, f_screencol},
782 {"screenpos", 3, 3, 0, f_screenpos},
783 {"screenrow", 0, 0, 0, f_screenrow},
784 {"screenstring", 2, 2, 0, f_screenstring},
785 {"search", 1, 4, 0, f_search},
786 {"searchdecl", 1, 3, 0, f_searchdecl},
787 {"searchpair", 3, 7, 0, f_searchpair},
788 {"searchpairpos", 3, 7, 0, f_searchpairpos},
789 {"searchpos", 1, 4, 0, f_searchpos},
790 {"server2client", 2, 2, 0, f_server2client},
791 {"serverlist", 0, 0, 0, f_serverlist},
792 {"setbufline", 3, 3, 0, f_setbufline},
793 {"setbufvar", 3, 3, 0, f_setbufvar},
794 {"setcharsearch", 1, 1, 0, f_setcharsearch},
795 {"setcmdpos", 1, 1, 0, f_setcmdpos},
796 {"setenv", 2, 2, 0, f_setenv},
797 {"setfperm", 2, 2, 0, f_setfperm},
798 {"setline", 2, 2, 0, f_setline},
799 {"setloclist", 2, 4, 0, f_setloclist},
800 {"setmatches", 1, 2, 0, f_setmatches},
801 {"setpos", 2, 2, 0, f_setpos},
802 {"setqflist", 1, 3, 0, f_setqflist},
803 {"setreg", 2, 3, 0, f_setreg},
804 {"settabvar", 3, 3, 0, f_settabvar},
805 {"settabwinvar", 4, 4, 0, f_settabwinvar},
806 {"settagstack", 2, 3, 0, f_settagstack},
807 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200811 {"shellescape", 1, 2, 0, f_shellescape},
812 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100813#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200814 {"sign_define", 1, 2, 0, f_sign_define},
815 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
816 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
817 {"sign_jump", 3, 3, 0, f_sign_jump},
818 {"sign_place", 4, 5, 0, f_sign_place},
819 {"sign_placelist", 1, 1, 0, f_sign_placelist},
820 {"sign_undefine", 0, 1, 0, f_sign_undefine},
821 {"sign_unplace", 1, 2, 0, f_sign_unplace},
822 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100823#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200824 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200826 {"sin", 1, 1, FEARG_1, f_sin},
827 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200830#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200831 {"sound_clear", 0, 0, 0, f_sound_clear},
832 {"sound_playevent", 1, 2, 0, f_sound_playevent},
833 {"sound_playfile", 1, 2, 0, f_sound_playfile},
834 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200835#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200836 {"soundfold", 1, 1, 0, f_soundfold},
837 {"spellbadword", 0, 1, 0, f_spellbadword},
838 {"spellsuggest", 1, 3, 0, f_spellsuggest},
839 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200840#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200841 {"sqrt", 1, 1, FEARG_1, f_sqrt},
842 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200844 {"str2list", 1, 2, FEARG_1, f_str2list},
845 {"str2nr", 1, 2, 0, f_str2nr},
846 {"strcharpart", 2, 3, 0, f_strcharpart},
847 {"strchars", 1, 2, 0, f_strchars},
848 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200850 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200852 {"strgetchar", 2, 2, 0, f_strgetchar},
853 {"stridx", 2, 3, 0, f_stridx},
854 {"string", 1, 1, FEARG_1, f_string},
855 {"strlen", 1, 1, FEARG_1, f_strlen},
856 {"strpart", 2, 3, 0, f_strpart},
857 {"strridx", 2, 3, 0, f_strridx},
858 {"strtrans", 1, 1, FEARG_1, f_strtrans},
859 {"strwidth", 1, 1, FEARG_1, f_strwidth},
860 {"submatch", 1, 2, 0, f_submatch},
861 {"substitute", 4, 4, FEARG_1, f_substitute},
862 {"swapinfo", 1, 1, 0, f_swapinfo},
863 {"swapname", 1, 1, 0, f_swapname},
864 {"synID", 3, 3, 0, f_synID},
865 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
866 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
867 {"synconcealed", 2, 2, 0, f_synconcealed},
868 {"synstack", 2, 2, 0, f_synstack},
869 {"system", 1, 2, FEARG_1, f_system},
870 {"systemlist", 1, 2, FEARG_1, f_systemlist},
871 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
872 {"tabpagenr", 0, 1, 0, f_tabpagenr},
873 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
874 {"tagfiles", 0, 0, 0, f_tagfiles},
875 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200877 {"tan", 1, 1, FEARG_1, f_tan},
878 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200879#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200880 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200881#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200882 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
883 {"term_dumpload", 1, 2, 0, f_term_dumpload},
884 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
885 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200886# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200887 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200888# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200889 {"term_getattr", 2, 2, 0, f_term_getattr},
890 {"term_getcursor", 1, 1, 0, f_term_getcursor},
891 {"term_getjob", 1, 1, 0, f_term_getjob},
892 {"term_getline", 2, 2, 0, f_term_getline},
893 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
894 {"term_getsize", 1, 1, 0, f_term_getsize},
895 {"term_getstatus", 1, 1, 0, f_term_getstatus},
896 {"term_gettitle", 1, 1, 0, f_term_gettitle},
897 {"term_gettty", 1, 2, 0, f_term_gettty},
898 {"term_list", 0, 0, 0, f_term_list},
899 {"term_scrape", 2, 2, 0, f_term_scrape},
900 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200901# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200902 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200903# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200904 {"term_setkill", 2, 2, 0, f_term_setkill},
905 {"term_setrestore", 2, 2, 0, f_term_setrestore},
906 {"term_setsize", 3, 3, 0, f_term_setsize},
907 {"term_start", 1, 2, 0, f_term_start},
908 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200909#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200910 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
911 {"test_autochdir", 0, 0, 0, f_test_autochdir},
912 {"test_feedinput", 1, 1, 0, f_test_feedinput},
913 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
914 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
915 {"test_getvalue", 1, 1, 0, f_test_getvalue},
916 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
917 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200919 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200923 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200924#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200925 {"test_null_list", 0, 0, 0, f_test_null_list},
926 {"test_null_partial", 0, 0, 0, f_test_null_partial},
927 {"test_null_string", 0, 0, 0, f_test_null_string},
928 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
929 {"test_override", 2, 2, 0, f_test_override},
930 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200931#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200932 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200933#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200934#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200935 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200936#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200937 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200939 {"timer_info", 0, 1, 0, f_timer_info},
940 {"timer_pause", 2, 2, 0, f_timer_pause},
941 {"timer_start", 2, 3, 0, f_timer_start},
942 {"timer_stop", 1, 1, 0, f_timer_stop},
943 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200945 {"tolower", 1, 1, 0, f_tolower},
946 {"toupper", 1, 1, 0, f_toupper},
947 {"tr", 3, 3, 0, f_tr},
948 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200950 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 {"type", 1, 1, FEARG_1, f_type},
953 {"undofile", 1, 1, 0, f_undofile},
954 {"undotree", 0, 0, 0, f_undotree},
955 {"uniq", 1, 3, FEARG_1, f_uniq},
956 {"values", 1, 1, FEARG_1, f_values},
957 {"virtcol", 1, 1, 0, f_virtcol},
958 {"visualmode", 0, 1, 0, f_visualmode},
959 {"wildmenumode", 0, 0, 0, f_wildmenumode},
960 {"win_execute", 2, 3, 0, f_win_execute},
961 {"win_findbuf", 1, 1, 0, f_win_findbuf},
962 {"win_getid", 0, 2, 0, f_win_getid},
963 {"win_gotoid", 1, 1, 0, f_win_gotoid},
964 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
965 {"win_id2win", 1, 1, 0, f_win_id2win},
966 {"win_screenpos", 1, 1, 0, f_win_screenpos},
967 {"winbufnr", 1, 1, 0, f_winbufnr},
968 {"wincol", 0, 0, 0, f_wincol},
969 {"winheight", 1, 1, 0, f_winheight},
970 {"winlayout", 0, 1, 0, f_winlayout},
971 {"winline", 0, 0, 0, f_winline},
972 {"winnr", 0, 1, 0, f_winnr},
973 {"winrestcmd", 0, 0, 0, f_winrestcmd},
974 {"winrestview", 1, 1, 0, f_winrestview},
975 {"winsaveview", 0, 0, 0, f_winsaveview},
976 {"winwidth", 1, 1, 0, f_winwidth},
977 {"wordcount", 0, 0, 0, f_wordcount},
978 {"writefile", 2, 3, 0, f_writefile},
979 {"xor", 2, 2, 0, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200980};
981
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982/*
983 * Function given to ExpandGeneric() to obtain the list of internal
984 * or user defined function names.
985 */
986 char_u *
987get_function_name(expand_T *xp, int idx)
988{
989 static int intidx = -1;
990 char_u *name;
991
992 if (idx == 0)
993 intidx = -1;
994 if (intidx < 0)
995 {
996 name = get_user_func_name(xp, idx);
997 if (name != NULL)
998 return name;
999 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001000 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001001 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001002 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001003 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001004 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001005 STRCAT(IObuff, ")");
1006 return IObuff;
1007 }
1008
1009 return NULL;
1010}
1011
1012/*
1013 * Function given to ExpandGeneric() to obtain the list of internal or
1014 * user defined variable or function names.
1015 */
1016 char_u *
1017get_expr_name(expand_T *xp, int idx)
1018{
1019 static int intidx = -1;
1020 char_u *name;
1021
1022 if (idx == 0)
1023 intidx = -1;
1024 if (intidx < 0)
1025 {
1026 name = get_function_name(xp, idx);
1027 if (name != NULL)
1028 return name;
1029 }
1030 return get_user_var_name(xp, ++intidx);
1031}
1032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001033/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001034 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001035 * Return index, or -1 if not found
1036 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001037 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001038find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001039{
1040 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001041 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001042 int cmp;
1043 int x;
1044
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001045 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001046
1047 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048 while (first <= last)
1049 {
1050 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001051 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001052 if (cmp < 0)
1053 last = x - 1;
1054 else if (cmp > 0)
1055 first = x + 1;
1056 else
1057 return x;
1058 }
1059 return -1;
1060}
1061
1062 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001063has_internal_func(char_u *name)
1064{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001065 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001066}
1067
1068 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001069call_internal_func(
1070 char_u *name,
1071 int argcount,
1072 typval_T *argvars,
1073 typval_T *rettv)
1074{
1075 int i;
1076
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001077 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078 if (i < 0)
1079 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001080 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001082 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001083 return ERROR_TOOMANY;
1084 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001085 global_functions[i].f_func(argvars, rettv);
1086 return ERROR_NONE;
1087}
1088
1089/*
1090 * Invoke a method for base->method().
1091 */
1092 int
1093call_internal_method(
1094 char_u *name,
1095 int argcount,
1096 typval_T *argvars,
1097 typval_T *rettv,
1098 typval_T *basetv)
1099{
1100 int i;
1101 int fi;
1102 typval_T argv[MAX_FUNC_ARGS + 1];
1103
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001104 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001105 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001107 if (global_functions[fi].f_argtype == 0)
1108 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001109 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001110 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001111 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001112 return ERROR_TOOMANY;
1113
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001114 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001115 {
1116 // base value goes last
1117 for (i = 0; i < argcount; ++i)
1118 argv[i] = argvars[i];
1119 argv[argcount] = *basetv;
1120 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001121 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001122 {
1123 // base value goes second
1124 argv[0] = argvars[0];
1125 argv[1] = *basetv;
1126 for (i = 1; i < argcount; ++i)
1127 argv[i + 1] = argvars[i];
1128 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001129 else if (global_functions[fi].f_argtype == FEARG_3)
1130 {
1131 // base value goes third
1132 argv[0] = argvars[0];
1133 argv[1] = argvars[1];
1134 argv[2] = *basetv;
1135 for (i = 2; i < argcount; ++i)
1136 argv[i + 1] = argvars[i];
1137 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001138 else
1139 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001140 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001141 argv[0] = *basetv;
1142 for (i = 0; i < argcount; ++i)
1143 argv[i + 1] = argvars[i];
1144 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001145 argv[argcount + 1].v_type = VAR_UNKNOWN;
1146
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001147 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148 return ERROR_NONE;
1149}
1150
1151/*
1152 * Return TRUE for a non-zero Number and a non-empty String.
1153 */
1154 static int
1155non_zero_arg(typval_T *argvars)
1156{
1157 return ((argvars[0].v_type == VAR_NUMBER
1158 && argvars[0].vval.v_number != 0)
1159 || (argvars[0].v_type == VAR_SPECIAL
1160 && argvars[0].vval.v_number == VVAL_TRUE)
1161 || (argvars[0].v_type == VAR_STRING
1162 && argvars[0].vval.v_string != NULL
1163 && *argvars[0].vval.v_string != NUL));
1164}
1165
1166/*
1167 * Get the lnum from the first argument.
1168 * Also accepts ".", "$", etc., but that only works for the current buffer.
1169 * Returns -1 on error.
1170 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001171 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001172tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001173{
1174 typval_T rettv;
1175 linenr_T lnum;
1176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001177 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001178 if (lnum == 0) /* no valid number, try using line() */
1179 {
1180 rettv.v_type = VAR_NUMBER;
1181 f_line(argvars, &rettv);
1182 lnum = (linenr_T)rettv.vval.v_number;
1183 clear_tv(&rettv);
1184 }
1185 return lnum;
1186}
1187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001188/*
1189 * Get the lnum from the first argument.
1190 * Also accepts "$", then "buf" is used.
1191 * Returns 0 on error.
1192 */
1193 static linenr_T
1194tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1195{
1196 if (argvars[0].v_type == VAR_STRING
1197 && argvars[0].vval.v_string != NULL
1198 && argvars[0].vval.v_string[0] == '$'
1199 && buf != NULL)
1200 return buf->b_ml.ml_line_count;
1201 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1202}
1203
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001204#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001205/*
1206 * Get the float value of "argvars[0]" into "f".
1207 * Returns FAIL when the argument is not a Number or Float.
1208 */
1209 static int
1210get_float_arg(typval_T *argvars, float_T *f)
1211{
1212 if (argvars[0].v_type == VAR_FLOAT)
1213 {
1214 *f = argvars[0].vval.v_float;
1215 return OK;
1216 }
1217 if (argvars[0].v_type == VAR_NUMBER)
1218 {
1219 *f = (float_T)argvars[0].vval.v_number;
1220 return OK;
1221 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001222 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001223 return FAIL;
1224}
1225
1226/*
1227 * "abs(expr)" function
1228 */
1229 static void
1230f_abs(typval_T *argvars, typval_T *rettv)
1231{
1232 if (argvars[0].v_type == VAR_FLOAT)
1233 {
1234 rettv->v_type = VAR_FLOAT;
1235 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1236 }
1237 else
1238 {
1239 varnumber_T n;
1240 int error = FALSE;
1241
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001242 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001243 if (error)
1244 rettv->vval.v_number = -1;
1245 else if (n > 0)
1246 rettv->vval.v_number = n;
1247 else
1248 rettv->vval.v_number = -n;
1249 }
1250}
1251
1252/*
1253 * "acos()" function
1254 */
1255 static void
1256f_acos(typval_T *argvars, typval_T *rettv)
1257{
1258 float_T f = 0.0;
1259
1260 rettv->v_type = VAR_FLOAT;
1261 if (get_float_arg(argvars, &f) == OK)
1262 rettv->vval.v_float = acos(f);
1263 else
1264 rettv->vval.v_float = 0.0;
1265}
1266#endif
1267
1268/*
1269 * "add(list, item)" function
1270 */
1271 static void
1272f_add(typval_T *argvars, typval_T *rettv)
1273{
1274 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001275 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001276
1277 rettv->vval.v_number = 1; /* Default: Failed */
1278 if (argvars[0].v_type == VAR_LIST)
1279 {
1280 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001281 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282 (char_u *)N_("add() argument"), TRUE)
1283 && list_append_tv(l, &argvars[1]) == OK)
1284 copy_tv(&argvars[0], rettv);
1285 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001286 else if (argvars[0].v_type == VAR_BLOB)
1287 {
1288 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001289 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001290 (char_u *)N_("add() argument"), TRUE))
1291 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001292 int error = FALSE;
1293 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1294
1295 if (!error)
1296 {
1297 ga_append(&b->bv_ga, (int)n);
1298 copy_tv(&argvars[0], rettv);
1299 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001300 }
1301 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001303 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001304}
1305
1306/*
1307 * "and(expr, expr)" function
1308 */
1309 static void
1310f_and(typval_T *argvars, typval_T *rettv)
1311{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001312 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1313 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001314}
1315
1316/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001317 * If there is a window for "curbuf", make it the current window.
1318 */
1319 static void
1320find_win_for_curbuf(void)
1321{
1322 wininfo_T *wip;
1323
1324 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1325 {
1326 if (wip->wi_win != NULL)
1327 {
1328 curwin = wip->wi_win;
1329 break;
1330 }
1331 }
1332}
1333
1334/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001335 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001336 */
1337 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001338set_buffer_lines(
1339 buf_T *buf,
1340 linenr_T lnum_arg,
1341 int append,
1342 typval_T *lines,
1343 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344{
Bram Moolenaarca851592018-06-06 21:04:07 +02001345 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1346 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 list_T *l = NULL;
1348 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001350 linenr_T append_lnum;
1351 buf_T *curbuf_save = NULL;
1352 win_T *curwin_save = NULL;
1353 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001354
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 /* When using the current buffer ml_mfp will be set if needed. Useful when
1356 * setline() is used on startup. For other buffers the buffer must be
1357 * loaded. */
1358 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001360 rettv->vval.v_number = 1; /* FAIL */
1361 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 }
1363
Bram Moolenaarca851592018-06-06 21:04:07 +02001364 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001366 curbuf_save = curbuf;
1367 curwin_save = curwin;
1368 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001369 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001370 }
1371
1372 if (append)
1373 // appendbufline() uses the line number below which we insert
1374 append_lnum = lnum - 1;
1375 else
1376 // setbufline() uses the line number above which we insert, we only
1377 // append if it's below the last line
1378 append_lnum = curbuf->b_ml.ml_line_count;
1379
1380 if (lines->v_type == VAR_LIST)
1381 {
1382 l = lines->vval.v_list;
1383 li = l->lv_first;
1384 }
1385 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001386 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001387
1388 /* default result is zero == OK */
1389 for (;;)
1390 {
1391 if (l != NULL)
1392 {
1393 /* list argument, get next string */
1394 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001395 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001396 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001397 li = li->li_next;
1398 }
1399
Bram Moolenaarca851592018-06-06 21:04:07 +02001400 rettv->vval.v_number = 1; /* FAIL */
1401 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1402 break;
1403
1404 /* When coming here from Insert mode, sync undo, so that this can be
1405 * undone separately from what was previously inserted. */
1406 if (u_sync_once == 2)
1407 {
1408 u_sync_once = 1; /* notify that u_sync() was called */
1409 u_sync(TRUE);
1410 }
1411
1412 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1413 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001414 // Existing line, replace it.
1415 // Removes any existing text properties.
1416 if (u_savesub(lnum) == OK && ml_replace_len(
1417 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001418 {
1419 changed_bytes(lnum, 0);
1420 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1421 check_cursor_col();
1422 rettv->vval.v_number = 0; /* OK */
1423 }
1424 }
1425 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1426 {
1427 /* append the line */
1428 ++added;
1429 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1430 rettv->vval.v_number = 0; /* OK */
1431 }
1432
1433 if (l == NULL) /* only one string argument */
1434 break;
1435 ++lnum;
1436 }
1437
1438 if (added > 0)
1439 {
1440 win_T *wp;
1441 tabpage_T *tp;
1442
1443 appended_lines_mark(append_lnum, added);
1444 FOR_ALL_TAB_WINDOWS(tp, wp)
1445 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1446 wp->w_cursor.lnum += added;
1447 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001448 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001449 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001450
1451 if (!is_curbuf)
1452 {
1453 curbuf = curbuf_save;
1454 curwin = curwin_save;
1455 }
1456}
1457
1458/*
1459 * "append(lnum, string/list)" function
1460 */
1461 static void
1462f_append(typval_T *argvars, typval_T *rettv)
1463{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001464 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001465
1466 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1467}
1468
1469/*
1470 * "appendbufline(buf, lnum, string/list)" function
1471 */
1472 static void
1473f_appendbufline(typval_T *argvars, typval_T *rettv)
1474{
1475 linenr_T lnum;
1476 buf_T *buf;
1477
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001478 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001479 if (buf == NULL)
1480 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001481 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001483 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001484 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1485 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486}
1487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488#ifdef FEAT_FLOAT
1489/*
1490 * "asin()" function
1491 */
1492 static void
1493f_asin(typval_T *argvars, typval_T *rettv)
1494{
1495 float_T f = 0.0;
1496
1497 rettv->v_type = VAR_FLOAT;
1498 if (get_float_arg(argvars, &f) == OK)
1499 rettv->vval.v_float = asin(f);
1500 else
1501 rettv->vval.v_float = 0.0;
1502}
1503
1504/*
1505 * "atan()" function
1506 */
1507 static void
1508f_atan(typval_T *argvars, typval_T *rettv)
1509{
1510 float_T f = 0.0;
1511
1512 rettv->v_type = VAR_FLOAT;
1513 if (get_float_arg(argvars, &f) == OK)
1514 rettv->vval.v_float = atan(f);
1515 else
1516 rettv->vval.v_float = 0.0;
1517}
1518
1519/*
1520 * "atan2()" function
1521 */
1522 static void
1523f_atan2(typval_T *argvars, typval_T *rettv)
1524{
1525 float_T fx = 0.0, fy = 0.0;
1526
1527 rettv->v_type = VAR_FLOAT;
1528 if (get_float_arg(argvars, &fx) == OK
1529 && get_float_arg(&argvars[1], &fy) == OK)
1530 rettv->vval.v_float = atan2(fx, fy);
1531 else
1532 rettv->vval.v_float = 0.0;
1533}
1534#endif
1535
1536/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001537 * "balloon_show()" function
1538 */
1539#ifdef FEAT_BEVAL
1540 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001541f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1542{
1543 rettv->v_type = VAR_STRING;
1544 if (balloonEval != NULL)
1545 {
1546 if (balloonEval->msg == NULL)
1547 rettv->vval.v_string = NULL;
1548 else
1549 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1550 }
1551}
1552
1553 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001554f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1555{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001556 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001557 {
1558 if (argvars[0].v_type == VAR_LIST
1559# ifdef FEAT_GUI
1560 && !gui.in_use
1561# endif
1562 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001563 {
1564 list_T *l = argvars[0].vval.v_list;
1565
1566 // empty list removes the balloon
1567 post_balloon(balloonEval, NULL,
1568 l == NULL || l->lv_len == 0 ? NULL : l);
1569 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001570 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001571 {
1572 char_u *mesg = tv_get_string_chk(&argvars[0]);
1573
1574 if (mesg != NULL)
1575 // empty string removes the balloon
1576 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1577 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001578 }
1579}
1580
Bram Moolenaar669a8282017-11-19 20:13:05 +01001581# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001582 static void
1583f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1584{
1585 if (rettv_list_alloc(rettv) == OK)
1586 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001587 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001588
1589 if (msg != NULL)
1590 {
1591 pumitem_T *array;
1592 int size = split_message(msg, &array);
1593 int i;
1594
1595 /* Skip the first and last item, they are always empty. */
1596 for (i = 1; i < size - 1; ++i)
1597 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001598 while (size > 0)
1599 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001600 vim_free(array);
1601 }
1602 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001603}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001604# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001605#endif
1606
1607/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608 * "browse(save, title, initdir, default)" function
1609 */
1610 static void
1611f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1612{
1613#ifdef FEAT_BROWSE
1614 int save;
1615 char_u *title;
1616 char_u *initdir;
1617 char_u *defname;
1618 char_u buf[NUMBUFLEN];
1619 char_u buf2[NUMBUFLEN];
1620 int error = FALSE;
1621
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001622 save = (int)tv_get_number_chk(&argvars[0], &error);
1623 title = tv_get_string_chk(&argvars[1]);
1624 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1625 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626
1627 if (error || title == NULL || initdir == NULL || defname == NULL)
1628 rettv->vval.v_string = NULL;
1629 else
1630 rettv->vval.v_string =
1631 do_browse(save ? BROWSE_SAVE : 0,
1632 title, defname, NULL, initdir, NULL, curbuf);
1633#else
1634 rettv->vval.v_string = NULL;
1635#endif
1636 rettv->v_type = VAR_STRING;
1637}
1638
1639/*
1640 * "browsedir(title, initdir)" function
1641 */
1642 static void
1643f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1644{
1645#ifdef FEAT_BROWSE
1646 char_u *title;
1647 char_u *initdir;
1648 char_u buf[NUMBUFLEN];
1649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001650 title = tv_get_string_chk(&argvars[0]);
1651 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652
1653 if (title == NULL || initdir == NULL)
1654 rettv->vval.v_string = NULL;
1655 else
1656 rettv->vval.v_string = do_browse(BROWSE_DIR,
1657 title, NULL, NULL, initdir, NULL, curbuf);
1658#else
1659 rettv->vval.v_string = NULL;
1660#endif
1661 rettv->v_type = VAR_STRING;
1662}
1663
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001664/*
1665 * Find a buffer by number or exact name.
1666 */
1667 static buf_T *
1668find_buffer(typval_T *avar)
1669{
1670 buf_T *buf = NULL;
1671
1672 if (avar->v_type == VAR_NUMBER)
1673 buf = buflist_findnr((int)avar->vval.v_number);
1674 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1675 {
1676 buf = buflist_findname_exp(avar->vval.v_string);
1677 if (buf == NULL)
1678 {
1679 /* No full path name match, try a match with a URL or a "nofile"
1680 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001681 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001682 if (buf->b_fname != NULL
1683 && (path_with_url(buf->b_fname)
1684#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001685 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686#endif
1687 )
1688 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1689 break;
1690 }
1691 }
1692 return buf;
1693}
1694
1695/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001696 * "bufadd(expr)" function
1697 */
1698 static void
1699f_bufadd(typval_T *argvars, typval_T *rettv)
1700{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001701 char_u *name = tv_get_string(&argvars[0]);
1702
1703 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001704}
1705
1706/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 * "bufexists(expr)" function
1708 */
1709 static void
1710f_bufexists(typval_T *argvars, typval_T *rettv)
1711{
1712 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1713}
1714
1715/*
1716 * "buflisted(expr)" function
1717 */
1718 static void
1719f_buflisted(typval_T *argvars, typval_T *rettv)
1720{
1721 buf_T *buf;
1722
1723 buf = find_buffer(&argvars[0]);
1724 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1725}
1726
1727/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001728 * "bufload(expr)" function
1729 */
1730 static void
1731f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1732{
1733 buf_T *buf = get_buf_arg(&argvars[0]);
1734
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001735 if (buf != NULL)
1736 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001737}
1738
1739/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740 * "bufloaded(expr)" function
1741 */
1742 static void
1743f_bufloaded(typval_T *argvars, typval_T *rettv)
1744{
1745 buf_T *buf;
1746
1747 buf = find_buffer(&argvars[0]);
1748 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1749}
1750
1751 buf_T *
1752buflist_find_by_name(char_u *name, int curtab_only)
1753{
1754 int save_magic;
1755 char_u *save_cpo;
1756 buf_T *buf;
1757
1758 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1759 save_magic = p_magic;
1760 p_magic = TRUE;
1761 save_cpo = p_cpo;
1762 p_cpo = (char_u *)"";
1763
1764 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1765 TRUE, FALSE, curtab_only));
1766
1767 p_magic = save_magic;
1768 p_cpo = save_cpo;
1769 return buf;
1770}
1771
1772/*
1773 * Get buffer by number or pattern.
1774 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001775 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001776tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001777{
1778 char_u *name = tv->vval.v_string;
1779 buf_T *buf;
1780
1781 if (tv->v_type == VAR_NUMBER)
1782 return buflist_findnr((int)tv->vval.v_number);
1783 if (tv->v_type != VAR_STRING)
1784 return NULL;
1785 if (name == NULL || *name == NUL)
1786 return curbuf;
1787 if (name[0] == '$' && name[1] == NUL)
1788 return lastbuf;
1789
1790 buf = buflist_find_by_name(name, curtab_only);
1791
1792 /* If not found, try expanding the name, like done for bufexists(). */
1793 if (buf == NULL)
1794 buf = find_buffer(tv);
1795
1796 return buf;
1797}
1798
1799/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001800 * Get the buffer from "arg" and give an error and return NULL if it is not
1801 * valid.
1802 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001803 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001804get_buf_arg(typval_T *arg)
1805{
1806 buf_T *buf;
1807
1808 ++emsg_off;
1809 buf = tv_get_buf(arg, FALSE);
1810 --emsg_off;
1811 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001812 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001813 return buf;
1814}
1815
1816/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 * "bufname(expr)" function
1818 */
1819 static void
1820f_bufname(typval_T *argvars, typval_T *rettv)
1821{
1822 buf_T *buf;
1823
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001824 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001826 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001827 rettv->v_type = VAR_STRING;
1828 if (buf != NULL && buf->b_fname != NULL)
1829 rettv->vval.v_string = vim_strsave(buf->b_fname);
1830 else
1831 rettv->vval.v_string = NULL;
1832 --emsg_off;
1833}
1834
1835/*
1836 * "bufnr(expr)" function
1837 */
1838 static void
1839f_bufnr(typval_T *argvars, typval_T *rettv)
1840{
1841 buf_T *buf;
1842 int error = FALSE;
1843 char_u *name;
1844
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001845 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001847 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001848 --emsg_off;
1849
1850 /* If the buffer isn't found and the second argument is not zero create a
1851 * new buffer. */
1852 if (buf == NULL
1853 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001854 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001856 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001857 && !error)
1858 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1859
1860 if (buf != NULL)
1861 rettv->vval.v_number = buf->b_fnum;
1862 else
1863 rettv->vval.v_number = -1;
1864}
1865
1866 static void
1867buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1868{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001869 win_T *wp;
1870 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001871 buf_T *buf;
1872
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001873 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001874 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001875 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001876 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001877 {
1878 ++winnr;
1879 if (wp->w_buffer == buf)
1880 break;
1881 }
1882 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883 --emsg_off;
1884}
1885
1886/*
1887 * "bufwinid(nr)" function
1888 */
1889 static void
1890f_bufwinid(typval_T *argvars, typval_T *rettv)
1891{
1892 buf_win_common(argvars, rettv, FALSE);
1893}
1894
1895/*
1896 * "bufwinnr(nr)" function
1897 */
1898 static void
1899f_bufwinnr(typval_T *argvars, typval_T *rettv)
1900{
1901 buf_win_common(argvars, rettv, TRUE);
1902}
1903
1904/*
1905 * "byte2line(byte)" function
1906 */
1907 static void
1908f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1909{
1910#ifndef FEAT_BYTEOFF
1911 rettv->vval.v_number = -1;
1912#else
1913 long boff = 0;
1914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001915 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916 if (boff < 0)
1917 rettv->vval.v_number = -1;
1918 else
1919 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1920 (linenr_T)0, &boff);
1921#endif
1922}
1923
1924 static void
1925byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1926{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 char_u *str;
1929 varnumber_T idx;
1930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001931 str = tv_get_string_chk(&argvars[0]);
1932 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001933 rettv->vval.v_number = -1;
1934 if (str == NULL || idx < 0)
1935 return;
1936
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937 t = str;
1938 for ( ; idx > 0; idx--)
1939 {
1940 if (*t == NUL) /* EOL reached */
1941 return;
1942 if (enc_utf8 && comp)
1943 t += utf_ptr2len(t);
1944 else
1945 t += (*mb_ptr2len)(t);
1946 }
1947 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001948}
1949
1950/*
1951 * "byteidx()" function
1952 */
1953 static void
1954f_byteidx(typval_T *argvars, typval_T *rettv)
1955{
1956 byteidx(argvars, rettv, FALSE);
1957}
1958
1959/*
1960 * "byteidxcomp()" function
1961 */
1962 static void
1963f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1964{
1965 byteidx(argvars, rettv, TRUE);
1966}
1967
1968/*
1969 * "call(func, arglist [, dict])" function
1970 */
1971 static void
1972f_call(typval_T *argvars, typval_T *rettv)
1973{
1974 char_u *func;
1975 partial_T *partial = NULL;
1976 dict_T *selfdict = NULL;
1977
1978 if (argvars[1].v_type != VAR_LIST)
1979 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001980 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001981 return;
1982 }
1983 if (argvars[1].vval.v_list == NULL)
1984 return;
1985
1986 if (argvars[0].v_type == VAR_FUNC)
1987 func = argvars[0].vval.v_string;
1988 else if (argvars[0].v_type == VAR_PARTIAL)
1989 {
1990 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001991 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001992 }
1993 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001994 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 if (*func == NUL)
1996 return; /* type error or empty name */
1997
1998 if (argvars[2].v_type != VAR_UNKNOWN)
1999 {
2000 if (argvars[2].v_type != VAR_DICT)
2001 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002002 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002003 return;
2004 }
2005 selfdict = argvars[2].vval.v_dict;
2006 }
2007
2008 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2009}
2010
2011#ifdef FEAT_FLOAT
2012/*
2013 * "ceil({float})" function
2014 */
2015 static void
2016f_ceil(typval_T *argvars, typval_T *rettv)
2017{
2018 float_T f = 0.0;
2019
2020 rettv->v_type = VAR_FLOAT;
2021 if (get_float_arg(argvars, &f) == OK)
2022 rettv->vval.v_float = ceil(f);
2023 else
2024 rettv->vval.v_float = 0.0;
2025}
2026#endif
2027
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002028/*
2029 * "changenr()" function
2030 */
2031 static void
2032f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2033{
2034 rettv->vval.v_number = curbuf->b_u_seq_cur;
2035}
2036
2037/*
2038 * "char2nr(string)" function
2039 */
2040 static void
2041f_char2nr(typval_T *argvars, typval_T *rettv)
2042{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002043 if (has_mbyte)
2044 {
2045 int utf8 = 0;
2046
2047 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002048 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049
2050 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002051 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002053 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002054 }
2055 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002056 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002057}
2058
2059/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002060 * "chdir(dir)" function
2061 */
2062 static void
2063f_chdir(typval_T *argvars, typval_T *rettv)
2064{
2065 char_u *cwd;
2066 cdscope_T scope = CDSCOPE_GLOBAL;
2067
2068 rettv->v_type = VAR_STRING;
2069 rettv->vval.v_string = NULL;
2070
2071 if (argvars[0].v_type != VAR_STRING)
2072 return;
2073
2074 // Return the current directory
2075 cwd = alloc(MAXPATHL);
2076 if (cwd != NULL)
2077 {
2078 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2079 {
2080#ifdef BACKSLASH_IN_FILENAME
2081 slash_adjust(cwd);
2082#endif
2083 rettv->vval.v_string = vim_strsave(cwd);
2084 }
2085 vim_free(cwd);
2086 }
2087
2088 if (curwin->w_localdir != NULL)
2089 scope = CDSCOPE_WINDOW;
2090 else if (curtab->tp_localdir != NULL)
2091 scope = CDSCOPE_TABPAGE;
2092
2093 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2094 // Directory change failed
2095 VIM_CLEAR(rettv->vval.v_string);
2096}
2097
2098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 * "cindent(lnum)" function
2100 */
2101 static void
2102f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2103{
2104#ifdef FEAT_CINDENT
2105 pos_T pos;
2106 linenr_T lnum;
2107
2108 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002109 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2111 {
2112 curwin->w_cursor.lnum = lnum;
2113 rettv->vval.v_number = get_c_indent();
2114 curwin->w_cursor = pos;
2115 }
2116 else
2117#endif
2118 rettv->vval.v_number = -1;
2119}
2120
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002121 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002122get_optional_window(typval_T *argvars, int idx)
2123{
2124 win_T *win = curwin;
2125
2126 if (argvars[idx].v_type != VAR_UNKNOWN)
2127 {
2128 win = find_win_by_nr_or_id(&argvars[idx]);
2129 if (win == NULL)
2130 {
2131 emsg(_(e_invalwindow));
2132 return NULL;
2133 }
2134 }
2135 return win;
2136}
2137
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002139 * "col(string)" function
2140 */
2141 static void
2142f_col(typval_T *argvars, typval_T *rettv)
2143{
2144 colnr_T col = 0;
2145 pos_T *fp;
2146 int fnum = curbuf->b_fnum;
2147
2148 fp = var2fpos(&argvars[0], FALSE, &fnum);
2149 if (fp != NULL && fnum == curbuf->b_fnum)
2150 {
2151 if (fp->col == MAXCOL)
2152 {
2153 /* '> can be MAXCOL, get the length of the line then */
2154 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2155 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2156 else
2157 col = MAXCOL;
2158 }
2159 else
2160 {
2161 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 /* col(".") when the cursor is on the NUL at the end of the line
2163 * because of "coladd" can be seen as an extra column. */
2164 if (virtual_active() && fp == &curwin->w_cursor)
2165 {
2166 char_u *p = ml_get_cursor();
2167
2168 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2169 curwin->w_virtcol - curwin->w_cursor.coladd))
2170 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 int l;
2172
2173 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2174 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 }
2176 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 }
2178 }
2179 rettv->vval.v_number = col;
2180}
2181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182/*
2183 * "confirm(message, buttons[, default [, type]])" function
2184 */
2185 static void
2186f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2187{
2188#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2189 char_u *message;
2190 char_u *buttons = NULL;
2191 char_u buf[NUMBUFLEN];
2192 char_u buf2[NUMBUFLEN];
2193 int def = 1;
2194 int type = VIM_GENERIC;
2195 char_u *typestr;
2196 int error = FALSE;
2197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002198 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002199 if (message == NULL)
2200 error = TRUE;
2201 if (argvars[1].v_type != VAR_UNKNOWN)
2202 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002203 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204 if (buttons == NULL)
2205 error = TRUE;
2206 if (argvars[2].v_type != VAR_UNKNOWN)
2207 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002208 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209 if (argvars[3].v_type != VAR_UNKNOWN)
2210 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002211 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 if (typestr == NULL)
2213 error = TRUE;
2214 else
2215 {
2216 switch (TOUPPER_ASC(*typestr))
2217 {
2218 case 'E': type = VIM_ERROR; break;
2219 case 'Q': type = VIM_QUESTION; break;
2220 case 'I': type = VIM_INFO; break;
2221 case 'W': type = VIM_WARNING; break;
2222 case 'G': type = VIM_GENERIC; break;
2223 }
2224 }
2225 }
2226 }
2227 }
2228
2229 if (buttons == NULL || *buttons == NUL)
2230 buttons = (char_u *)_("&Ok");
2231
2232 if (!error)
2233 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2234 def, NULL, FALSE);
2235#endif
2236}
2237
2238/*
2239 * "copy()" function
2240 */
2241 static void
2242f_copy(typval_T *argvars, typval_T *rettv)
2243{
2244 item_copy(&argvars[0], rettv, FALSE, 0);
2245}
2246
2247#ifdef FEAT_FLOAT
2248/*
2249 * "cos()" function
2250 */
2251 static void
2252f_cos(typval_T *argvars, typval_T *rettv)
2253{
2254 float_T f = 0.0;
2255
2256 rettv->v_type = VAR_FLOAT;
2257 if (get_float_arg(argvars, &f) == OK)
2258 rettv->vval.v_float = cos(f);
2259 else
2260 rettv->vval.v_float = 0.0;
2261}
2262
2263/*
2264 * "cosh()" function
2265 */
2266 static void
2267f_cosh(typval_T *argvars, typval_T *rettv)
2268{
2269 float_T f = 0.0;
2270
2271 rettv->v_type = VAR_FLOAT;
2272 if (get_float_arg(argvars, &f) == OK)
2273 rettv->vval.v_float = cosh(f);
2274 else
2275 rettv->vval.v_float = 0.0;
2276}
2277#endif
2278
2279/*
2280 * "count()" function
2281 */
2282 static void
2283f_count(typval_T *argvars, typval_T *rettv)
2284{
2285 long n = 0;
2286 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002287 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288
Bram Moolenaar9966b212017-07-28 16:46:57 +02002289 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002290 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002291
2292 if (argvars[0].v_type == VAR_STRING)
2293 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002294 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002295 char_u *p = argvars[0].vval.v_string;
2296 char_u *next;
2297
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002298 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002299 {
2300 if (ic)
2301 {
2302 size_t len = STRLEN(expr);
2303
2304 while (*p != NUL)
2305 {
2306 if (MB_STRNICMP(p, expr, len) == 0)
2307 {
2308 ++n;
2309 p += len;
2310 }
2311 else
2312 MB_PTR_ADV(p);
2313 }
2314 }
2315 else
2316 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2317 != NULL)
2318 {
2319 ++n;
2320 p = next + STRLEN(expr);
2321 }
2322 }
2323
2324 }
2325 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002326 {
2327 listitem_T *li;
2328 list_T *l;
2329 long idx;
2330
2331 if ((l = argvars[0].vval.v_list) != NULL)
2332 {
2333 li = l->lv_first;
2334 if (argvars[2].v_type != VAR_UNKNOWN)
2335 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336 if (argvars[3].v_type != VAR_UNKNOWN)
2337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002338 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002339 if (!error)
2340 {
2341 li = list_find(l, idx);
2342 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002343 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344 }
2345 }
2346 if (error)
2347 li = NULL;
2348 }
2349
2350 for ( ; li != NULL; li = li->li_next)
2351 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2352 ++n;
2353 }
2354 }
2355 else if (argvars[0].v_type == VAR_DICT)
2356 {
2357 int todo;
2358 dict_T *d;
2359 hashitem_T *hi;
2360
2361 if ((d = argvars[0].vval.v_dict) != NULL)
2362 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 if (argvars[2].v_type != VAR_UNKNOWN)
2364 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002366 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 }
2368
2369 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2370 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2371 {
2372 if (!HASHITEM_EMPTY(hi))
2373 {
2374 --todo;
2375 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2376 ++n;
2377 }
2378 }
2379 }
2380 }
2381 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002382 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002383 rettv->vval.v_number = n;
2384}
2385
2386/*
2387 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2388 *
2389 * Checks the existence of a cscope connection.
2390 */
2391 static void
2392f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2393{
2394#ifdef FEAT_CSCOPE
2395 int num = 0;
2396 char_u *dbpath = NULL;
2397 char_u *prepend = NULL;
2398 char_u buf[NUMBUFLEN];
2399
2400 if (argvars[0].v_type != VAR_UNKNOWN
2401 && argvars[1].v_type != VAR_UNKNOWN)
2402 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002403 num = (int)tv_get_number(&argvars[0]);
2404 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002406 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407 }
2408
2409 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2410#endif
2411}
2412
2413/*
2414 * "cursor(lnum, col)" function, or
2415 * "cursor(list)"
2416 *
2417 * Moves the cursor to the specified line and column.
2418 * Returns 0 when the position could be set, -1 otherwise.
2419 */
2420 static void
2421f_cursor(typval_T *argvars, typval_T *rettv)
2422{
2423 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425 int set_curswant = TRUE;
2426
2427 rettv->vval.v_number = -1;
2428 if (argvars[1].v_type == VAR_UNKNOWN)
2429 {
2430 pos_T pos;
2431 colnr_T curswant = -1;
2432
2433 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2434 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002435 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 return;
2437 }
2438 line = pos.lnum;
2439 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002441 if (curswant >= 0)
2442 {
2443 curwin->w_curswant = curswant - 1;
2444 set_curswant = FALSE;
2445 }
2446 }
2447 else
2448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 line = tv_get_lnum(argvars);
2450 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002452 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002454 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455 return; /* type error; errmsg already given */
2456 if (line > 0)
2457 curwin->w_cursor.lnum = line;
2458 if (col > 0)
2459 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461
2462 /* Make sure the cursor is in a valid position. */
2463 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 /* Correct cursor for multi-byte character. */
2465 if (has_mbyte)
2466 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467
2468 curwin->w_set_curswant = set_curswant;
2469 rettv->vval.v_number = 0;
2470}
2471
Bram Moolenaar4f974752019-02-17 17:44:42 +01002472#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002473/*
2474 * "debugbreak()" function
2475 */
2476 static void
2477f_debugbreak(typval_T *argvars, typval_T *rettv)
2478{
2479 int pid;
2480
2481 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002482 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002483 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002484 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002485 else
2486 {
2487 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2488
2489 if (hProcess != NULL)
2490 {
2491 DebugBreakProcess(hProcess);
2492 CloseHandle(hProcess);
2493 rettv->vval.v_number = OK;
2494 }
2495 }
2496}
2497#endif
2498
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002499/*
2500 * "deepcopy()" function
2501 */
2502 static void
2503f_deepcopy(typval_T *argvars, typval_T *rettv)
2504{
2505 int noref = 0;
2506 int copyID;
2507
2508 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002509 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002510 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002511 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512 else
2513 {
2514 copyID = get_copyID();
2515 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2516 }
2517}
2518
2519/*
2520 * "delete()" function
2521 */
2522 static void
2523f_delete(typval_T *argvars, typval_T *rettv)
2524{
2525 char_u nbuf[NUMBUFLEN];
2526 char_u *name;
2527 char_u *flags;
2528
2529 rettv->vval.v_number = -1;
2530 if (check_restricted() || check_secure())
2531 return;
2532
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002533 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002534 if (name == NULL || *name == NUL)
2535 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002536 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 return;
2538 }
2539
2540 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002541 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002542 else
2543 flags = (char_u *)"";
2544
2545 if (*flags == NUL)
2546 /* delete a file */
2547 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2548 else if (STRCMP(flags, "d") == 0)
2549 /* delete an empty directory */
2550 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2551 else if (STRCMP(flags, "rf") == 0)
2552 /* delete a directory recursively */
2553 rettv->vval.v_number = delete_recursive(name);
2554 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002555 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002556}
2557
2558/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002559 * "deletebufline()" function
2560 */
2561 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002562f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002563{
2564 buf_T *buf;
2565 linenr_T first, last;
2566 linenr_T lnum;
2567 long count;
2568 int is_curbuf;
2569 buf_T *curbuf_save = NULL;
2570 win_T *curwin_save = NULL;
2571 tabpage_T *tp;
2572 win_T *wp;
2573
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002574 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002575 if (buf == NULL)
2576 {
2577 rettv->vval.v_number = 1; /* FAIL */
2578 return;
2579 }
2580 is_curbuf = buf == curbuf;
2581
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002582 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002583 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002584 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002585 else
2586 last = first;
2587
2588 if (buf->b_ml.ml_mfp == NULL || first < 1
2589 || first > buf->b_ml.ml_line_count || last < first)
2590 {
2591 rettv->vval.v_number = 1; /* FAIL */
2592 return;
2593 }
2594
2595 if (!is_curbuf)
2596 {
2597 curbuf_save = curbuf;
2598 curwin_save = curwin;
2599 curbuf = buf;
2600 find_win_for_curbuf();
2601 }
2602 if (last > curbuf->b_ml.ml_line_count)
2603 last = curbuf->b_ml.ml_line_count;
2604 count = last - first + 1;
2605
2606 // When coming here from Insert mode, sync undo, so that this can be
2607 // undone separately from what was previously inserted.
2608 if (u_sync_once == 2)
2609 {
2610 u_sync_once = 1; // notify that u_sync() was called
2611 u_sync(TRUE);
2612 }
2613
2614 if (u_save(first - 1, last + 1) == FAIL)
2615 {
2616 rettv->vval.v_number = 1; /* FAIL */
2617 return;
2618 }
2619
2620 for (lnum = first; lnum <= last; ++lnum)
2621 ml_delete(first, TRUE);
2622
2623 FOR_ALL_TAB_WINDOWS(tp, wp)
2624 if (wp->w_buffer == buf)
2625 {
2626 if (wp->w_cursor.lnum > last)
2627 wp->w_cursor.lnum -= count;
2628 else if (wp->w_cursor.lnum> first)
2629 wp->w_cursor.lnum = first;
2630 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2631 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2632 }
2633 check_cursor_col();
2634 deleted_lines_mark(first, count);
2635
2636 if (!is_curbuf)
2637 {
2638 curbuf = curbuf_save;
2639 curwin = curwin_save;
2640 }
2641}
2642
2643/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002644 * "did_filetype()" function
2645 */
2646 static void
2647f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2648{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002649 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002650}
2651
2652/*
2653 * "diff_filler()" function
2654 */
2655 static void
2656f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2657{
2658#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002659 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660#endif
2661}
2662
2663/*
2664 * "diff_hlID()" function
2665 */
2666 static void
2667f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2668{
2669#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002670 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002672 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002673 static int fnum = 0;
2674 static int change_start = 0;
2675 static int change_end = 0;
2676 static hlf_T hlID = (hlf_T)0;
2677 int filler_lines;
2678 int col;
2679
2680 if (lnum < 0) /* ignore type error in {lnum} arg */
2681 lnum = 0;
2682 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002683 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002684 || fnum != curbuf->b_fnum)
2685 {
2686 /* New line, buffer, change: need to get the values. */
2687 filler_lines = diff_check(curwin, lnum);
2688 if (filler_lines < 0)
2689 {
2690 if (filler_lines == -1)
2691 {
2692 change_start = MAXCOL;
2693 change_end = -1;
2694 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2695 hlID = HLF_ADD; /* added line */
2696 else
2697 hlID = HLF_CHD; /* changed line */
2698 }
2699 else
2700 hlID = HLF_ADD; /* added line */
2701 }
2702 else
2703 hlID = (hlf_T)0;
2704 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002705 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 fnum = curbuf->b_fnum;
2707 }
2708
2709 if (hlID == HLF_CHD || hlID == HLF_TXD)
2710 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002711 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002712 if (col >= change_start && col <= change_end)
2713 hlID = HLF_TXD; /* changed text */
2714 else
2715 hlID = HLF_CHD; /* changed line */
2716 }
2717 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2718#endif
2719}
2720
2721/*
2722 * "empty({expr})" function
2723 */
2724 static void
2725f_empty(typval_T *argvars, typval_T *rettv)
2726{
2727 int n = FALSE;
2728
2729 switch (argvars[0].v_type)
2730 {
2731 case VAR_STRING:
2732 case VAR_FUNC:
2733 n = argvars[0].vval.v_string == NULL
2734 || *argvars[0].vval.v_string == NUL;
2735 break;
2736 case VAR_PARTIAL:
2737 n = FALSE;
2738 break;
2739 case VAR_NUMBER:
2740 n = argvars[0].vval.v_number == 0;
2741 break;
2742 case VAR_FLOAT:
2743#ifdef FEAT_FLOAT
2744 n = argvars[0].vval.v_float == 0.0;
2745 break;
2746#endif
2747 case VAR_LIST:
2748 n = argvars[0].vval.v_list == NULL
2749 || argvars[0].vval.v_list->lv_first == NULL;
2750 break;
2751 case VAR_DICT:
2752 n = argvars[0].vval.v_dict == NULL
2753 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2754 break;
2755 case VAR_SPECIAL:
2756 n = argvars[0].vval.v_number != VVAL_TRUE;
2757 break;
2758
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002759 case VAR_BLOB:
2760 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002761 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2762 break;
2763
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002764 case VAR_JOB:
2765#ifdef FEAT_JOB_CHANNEL
2766 n = argvars[0].vval.v_job == NULL
2767 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2768 break;
2769#endif
2770 case VAR_CHANNEL:
2771#ifdef FEAT_JOB_CHANNEL
2772 n = argvars[0].vval.v_channel == NULL
2773 || !channel_is_open(argvars[0].vval.v_channel);
2774 break;
2775#endif
2776 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002777 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 n = TRUE;
2779 break;
2780 }
2781
2782 rettv->vval.v_number = n;
2783}
2784
2785/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002786 * "environ()" function
2787 */
2788 static void
2789f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2790{
2791#if !defined(AMIGA)
2792 int i = 0;
2793 char_u *entry, *value;
2794# ifdef MSWIN
2795 extern wchar_t **_wenviron;
2796# else
2797 extern char **environ;
2798# endif
2799
2800 if (rettv_dict_alloc(rettv) != OK)
2801 return;
2802
2803# ifdef MSWIN
2804 if (*_wenviron == NULL)
2805 return;
2806# else
2807 if (*environ == NULL)
2808 return;
2809# endif
2810
2811 for (i = 0; ; ++i)
2812 {
2813# ifdef MSWIN
2814 short_u *p;
2815
2816 if ((p = (short_u *)_wenviron[i]) == NULL)
2817 return;
2818 entry = utf16_to_enc(p, NULL);
2819# else
2820 if ((entry = (char_u *)environ[i]) == NULL)
2821 return;
2822 entry = vim_strsave(entry);
2823# endif
2824 if (entry == NULL) // out of memory
2825 return;
2826 if ((value = vim_strchr(entry, '=')) == NULL)
2827 {
2828 vim_free(entry);
2829 continue;
2830 }
2831 *value++ = NUL;
2832 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2833 vim_free(entry);
2834 }
2835#endif
2836}
2837
2838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002839 * "escape({string}, {chars})" function
2840 */
2841 static void
2842f_escape(typval_T *argvars, typval_T *rettv)
2843{
2844 char_u buf[NUMBUFLEN];
2845
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002846 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2847 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 rettv->v_type = VAR_STRING;
2849}
2850
2851/*
2852 * "eval()" function
2853 */
2854 static void
2855f_eval(typval_T *argvars, typval_T *rettv)
2856{
2857 char_u *s, *p;
2858
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002859 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 if (s != NULL)
2861 s = skipwhite(s);
2862
2863 p = s;
2864 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2865 {
2866 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002867 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002868 need_clr_eos = FALSE;
2869 rettv->v_type = VAR_NUMBER;
2870 rettv->vval.v_number = 0;
2871 }
2872 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002873 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874}
2875
2876/*
2877 * "eventhandler()" function
2878 */
2879 static void
2880f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2881{
2882 rettv->vval.v_number = vgetc_busy;
2883}
2884
2885/*
2886 * "executable()" function
2887 */
2888 static void
2889f_executable(typval_T *argvars, typval_T *rettv)
2890{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002891 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892
2893 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002894 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895}
2896
2897static garray_T redir_execute_ga;
2898
2899/*
2900 * Append "value[value_len]" to the execute() output.
2901 */
2902 void
2903execute_redir_str(char_u *value, int value_len)
2904{
2905 int len;
2906
2907 if (value_len == -1)
2908 len = (int)STRLEN(value); /* Append the entire string */
2909 else
2910 len = value_len; /* Append only "value_len" characters */
2911 if (ga_grow(&redir_execute_ga, len) == OK)
2912 {
2913 mch_memmove((char *)redir_execute_ga.ga_data
2914 + redir_execute_ga.ga_len, value, len);
2915 redir_execute_ga.ga_len += len;
2916 }
2917}
2918
2919/*
2920 * Get next line from a list.
2921 * Called by do_cmdline() to get the next line.
2922 * Returns allocated string, or NULL for end of function.
2923 */
2924
2925 static char_u *
2926get_list_line(
2927 int c UNUSED,
2928 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002929 int indent UNUSED,
2930 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002931{
2932 listitem_T **p = (listitem_T **)cookie;
2933 listitem_T *item = *p;
2934 char_u buf[NUMBUFLEN];
2935 char_u *s;
2936
2937 if (item == NULL)
2938 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002939 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 *p = item->li_next;
2941 return s == NULL ? NULL : vim_strsave(s);
2942}
2943
2944/*
2945 * "execute()" function
2946 */
2947 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002948execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949{
2950 char_u *cmd = NULL;
2951 list_T *list = NULL;
2952 int save_msg_silent = msg_silent;
2953 int save_emsg_silent = emsg_silent;
2954 int save_emsg_noredir = emsg_noredir;
2955 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002956 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002958 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002959 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960
2961 rettv->vval.v_string = NULL;
2962 rettv->v_type = VAR_STRING;
2963
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002964 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002965 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002966 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002967 if (list == NULL || list->lv_first == NULL)
2968 /* empty list, no commands, empty output */
2969 return;
2970 ++list->lv_refcount;
2971 }
2972 else
2973 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002974 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975 if (cmd == NULL)
2976 return;
2977 }
2978
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002979 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002980 {
2981 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002982 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002983
2984 if (s == NULL)
2985 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002986 if (*s == NUL)
2987 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002988 if (STRNCMP(s, "silent", 6) == 0)
2989 ++msg_silent;
2990 if (STRCMP(s, "silent!") == 0)
2991 {
2992 emsg_silent = TRUE;
2993 emsg_noredir = TRUE;
2994 }
2995 }
2996 else
2997 ++msg_silent;
2998
2999 if (redir_execute)
3000 save_ga = redir_execute_ga;
3001 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3002 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003003 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003004 if (!echo_output)
3005 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006
3007 if (cmd != NULL)
3008 do_cmdline_cmd(cmd);
3009 else
3010 {
3011 listitem_T *item = list->lv_first;
3012
3013 do_cmdline(NULL, get_list_line, (void *)&item,
3014 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3015 --list->lv_refcount;
3016 }
3017
Bram Moolenaard297f352017-01-29 20:31:21 +01003018 /* Need to append a NUL to the result. */
3019 if (ga_grow(&redir_execute_ga, 1) == OK)
3020 {
3021 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3022 rettv->vval.v_string = redir_execute_ga.ga_data;
3023 }
3024 else
3025 {
3026 ga_clear(&redir_execute_ga);
3027 rettv->vval.v_string = NULL;
3028 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029 msg_silent = save_msg_silent;
3030 emsg_silent = save_emsg_silent;
3031 emsg_noredir = save_emsg_noredir;
3032
3033 redir_execute = save_redir_execute;
3034 if (redir_execute)
3035 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003036 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003037
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003038 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003039 if (echo_output)
3040 // When not working silently: put it in column zero. A following
3041 // "echon" will overwrite the message, unavoidably.
3042 msg_col = 0;
3043 else
3044 // When working silently: Put it back where it was, since nothing
3045 // should have been written.
3046 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003047}
3048
3049/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003050 * "execute()" function
3051 */
3052 static void
3053f_execute(typval_T *argvars, typval_T *rettv)
3054{
3055 execute_common(argvars, rettv, 0);
3056}
3057
3058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 * "exepath()" function
3060 */
3061 static void
3062f_exepath(typval_T *argvars, typval_T *rettv)
3063{
3064 char_u *p = NULL;
3065
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003066 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003067 rettv->v_type = VAR_STRING;
3068 rettv->vval.v_string = p;
3069}
3070
3071/*
3072 * "exists()" function
3073 */
3074 static void
3075f_exists(typval_T *argvars, typval_T *rettv)
3076{
3077 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003080 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081 if (*p == '$') /* environment variable */
3082 {
3083 /* first try "normal" environment variables (fast) */
3084 if (mch_getenv(p + 1) != NULL)
3085 n = TRUE;
3086 else
3087 {
3088 /* try expanding things like $VIM and ${HOME} */
3089 p = expand_env_save(p);
3090 if (p != NULL && *p != '$')
3091 n = TRUE;
3092 vim_free(p);
3093 }
3094 }
3095 else if (*p == '&' || *p == '+') /* option */
3096 {
3097 n = (get_option_tv(&p, NULL, TRUE) == OK);
3098 if (*skipwhite(p) != NUL)
3099 n = FALSE; /* trailing garbage */
3100 }
3101 else if (*p == '*') /* internal or user defined function */
3102 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003103 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003104 }
3105 else if (*p == ':')
3106 {
3107 n = cmd_exists(p + 1);
3108 }
3109 else if (*p == '#')
3110 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003111 if (p[1] == '#')
3112 n = autocmd_supported(p + 2);
3113 else
3114 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003115 }
3116 else /* internal variable */
3117 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003118 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003119 }
3120
3121 rettv->vval.v_number = n;
3122}
3123
3124#ifdef FEAT_FLOAT
3125/*
3126 * "exp()" function
3127 */
3128 static void
3129f_exp(typval_T *argvars, typval_T *rettv)
3130{
3131 float_T f = 0.0;
3132
3133 rettv->v_type = VAR_FLOAT;
3134 if (get_float_arg(argvars, &f) == OK)
3135 rettv->vval.v_float = exp(f);
3136 else
3137 rettv->vval.v_float = 0.0;
3138}
3139#endif
3140
3141/*
3142 * "expand()" function
3143 */
3144 static void
3145f_expand(typval_T *argvars, typval_T *rettv)
3146{
3147 char_u *s;
3148 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003149 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3151 expand_T xpc;
3152 int error = FALSE;
3153 char_u *result;
3154
3155 rettv->v_type = VAR_STRING;
3156 if (argvars[1].v_type != VAR_UNKNOWN
3157 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003158 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003160 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003161
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003162 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003163 if (*s == '%' || *s == '#' || *s == '<')
3164 {
3165 ++emsg_off;
3166 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3167 --emsg_off;
3168 if (rettv->v_type == VAR_LIST)
3169 {
3170 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3171 list_append_string(rettv->vval.v_list, result, -1);
3172 else
3173 vim_free(result);
3174 }
3175 else
3176 rettv->vval.v_string = result;
3177 }
3178 else
3179 {
3180 /* When the optional second argument is non-zero, don't remove matches
3181 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3182 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003183 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003184 options |= WILD_KEEP_ALL;
3185 if (!error)
3186 {
3187 ExpandInit(&xpc);
3188 xpc.xp_context = EXPAND_FILES;
3189 if (p_wic)
3190 options += WILD_ICASE;
3191 if (rettv->v_type == VAR_STRING)
3192 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3193 options, WILD_ALL);
3194 else if (rettv_list_alloc(rettv) != FAIL)
3195 {
3196 int i;
3197
3198 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3199 for (i = 0; i < xpc.xp_numfiles; i++)
3200 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3201 ExpandCleanup(&xpc);
3202 }
3203 }
3204 else
3205 rettv->vval.v_string = NULL;
3206 }
3207}
3208
3209/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003210 * "expandcmd()" function
3211 * Expand all the special characters in a command string.
3212 */
3213 static void
3214f_expandcmd(typval_T *argvars, typval_T *rettv)
3215{
3216 exarg_T eap;
3217 char_u *cmdstr;
3218 char *errormsg = NULL;
3219
3220 rettv->v_type = VAR_STRING;
3221 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3222
3223 memset(&eap, 0, sizeof(eap));
3224 eap.cmd = cmdstr;
3225 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003226 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003227 eap.usefilter = FALSE;
3228 eap.nextcmd = NULL;
3229 eap.cmdidx = CMD_USER;
3230
3231 expand_filename(&eap, &cmdstr, &errormsg);
3232 if (errormsg != NULL && *errormsg != NUL)
3233 emsg(errormsg);
3234
3235 rettv->vval.v_string = cmdstr;
3236}
3237
3238/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239 * "extend(list, list [, idx])" function
3240 * "extend(dict, dict [, action])" function
3241 */
3242 static void
3243f_extend(typval_T *argvars, typval_T *rettv)
3244{
3245 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3246
3247 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3248 {
3249 list_T *l1, *l2;
3250 listitem_T *item;
3251 long before;
3252 int error = FALSE;
3253
3254 l1 = argvars[0].vval.v_list;
3255 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003256 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 && l2 != NULL)
3258 {
3259 if (argvars[2].v_type != VAR_UNKNOWN)
3260 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003261 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262 if (error)
3263 return; /* type error; errmsg already given */
3264
3265 if (before == l1->lv_len)
3266 item = NULL;
3267 else
3268 {
3269 item = list_find(l1, before);
3270 if (item == NULL)
3271 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003272 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273 return;
3274 }
3275 }
3276 }
3277 else
3278 item = NULL;
3279 list_extend(l1, l2, item);
3280
3281 copy_tv(&argvars[0], rettv);
3282 }
3283 }
3284 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3285 {
3286 dict_T *d1, *d2;
3287 char_u *action;
3288 int i;
3289
3290 d1 = argvars[0].vval.v_dict;
3291 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003292 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293 && d2 != NULL)
3294 {
3295 /* Check the third argument. */
3296 if (argvars[2].v_type != VAR_UNKNOWN)
3297 {
3298 static char *(av[]) = {"keep", "force", "error"};
3299
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003300 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 if (action == NULL)
3302 return; /* type error; errmsg already given */
3303 for (i = 0; i < 3; ++i)
3304 if (STRCMP(action, av[i]) == 0)
3305 break;
3306 if (i == 3)
3307 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003308 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003309 return;
3310 }
3311 }
3312 else
3313 action = (char_u *)"force";
3314
3315 dict_extend(d1, d2, action);
3316
3317 copy_tv(&argvars[0], rettv);
3318 }
3319 }
3320 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003321 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322}
3323
3324/*
3325 * "feedkeys()" function
3326 */
3327 static void
3328f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3329{
3330 int remap = TRUE;
3331 int insert = FALSE;
3332 char_u *keys, *flags;
3333 char_u nbuf[NUMBUFLEN];
3334 int typed = FALSE;
3335 int execute = FALSE;
3336 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003337 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003338 char_u *keys_esc;
3339
3340 /* This is not allowed in the sandbox. If the commands would still be
3341 * executed in the sandbox it would be OK, but it probably happens later,
3342 * when "sandbox" is no longer set. */
3343 if (check_secure())
3344 return;
3345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003346 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003347
3348 if (argvars[1].v_type != VAR_UNKNOWN)
3349 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003350 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003351 for ( ; *flags != NUL; ++flags)
3352 {
3353 switch (*flags)
3354 {
3355 case 'n': remap = FALSE; break;
3356 case 'm': remap = TRUE; break;
3357 case 't': typed = TRUE; break;
3358 case 'i': insert = TRUE; break;
3359 case 'x': execute = TRUE; break;
3360 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003361 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362 }
3363 }
3364 }
3365
3366 if (*keys != NUL || execute)
3367 {
3368 /* Need to escape K_SPECIAL and CSI before putting the string in the
3369 * typeahead buffer. */
3370 keys_esc = vim_strsave_escape_csi(keys);
3371 if (keys_esc != NULL)
3372 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003373 if (lowlevel)
3374 {
3375#ifdef USE_INPUT_BUF
3376 add_to_input_buf(keys, (int)STRLEN(keys));
3377#else
3378 emsg(_("E980: lowlevel input not supported"));
3379#endif
3380 }
3381 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003382 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003383 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003384 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003385 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003386#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003387 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003388#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003389 )
3390 typebuf_was_filled = TRUE;
3391 }
3392 vim_free(keys_esc);
3393
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003394 if (execute)
3395 {
3396 int save_msg_scroll = msg_scroll;
3397
3398 /* Avoid a 1 second delay when the keys start Insert mode. */
3399 msg_scroll = FALSE;
3400
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003401 if (!dangerous)
3402 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003403 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003404 if (!dangerous)
3405 --ex_normal_busy;
3406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407 msg_scroll |= save_msg_scroll;
3408 }
3409 }
3410 }
3411}
3412
3413/*
3414 * "filereadable()" function
3415 */
3416 static void
3417f_filereadable(typval_T *argvars, typval_T *rettv)
3418{
3419 int fd;
3420 char_u *p;
3421 int n;
3422
3423#ifndef O_NONBLOCK
3424# define O_NONBLOCK 0
3425#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003426 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3428 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3429 {
3430 n = TRUE;
3431 close(fd);
3432 }
3433 else
3434 n = FALSE;
3435
3436 rettv->vval.v_number = n;
3437}
3438
3439/*
3440 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3441 * rights to write into.
3442 */
3443 static void
3444f_filewritable(typval_T *argvars, typval_T *rettv)
3445{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003446 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003447}
3448
3449 static void
3450findfilendir(
3451 typval_T *argvars UNUSED,
3452 typval_T *rettv,
3453 int find_what UNUSED)
3454{
3455#ifdef FEAT_SEARCHPATH
3456 char_u *fname;
3457 char_u *fresult = NULL;
3458 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3459 char_u *p;
3460 char_u pathbuf[NUMBUFLEN];
3461 int count = 1;
3462 int first = TRUE;
3463 int error = FALSE;
3464#endif
3465
3466 rettv->vval.v_string = NULL;
3467 rettv->v_type = VAR_STRING;
3468
3469#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003470 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471
3472 if (argvars[1].v_type != VAR_UNKNOWN)
3473 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003474 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475 if (p == NULL)
3476 error = TRUE;
3477 else
3478 {
3479 if (*p != NUL)
3480 path = p;
3481
3482 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003483 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484 }
3485 }
3486
3487 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3488 error = TRUE;
3489
3490 if (*fname != NUL && !error)
3491 {
3492 do
3493 {
3494 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3495 vim_free(fresult);
3496 fresult = find_file_in_path_option(first ? fname : NULL,
3497 first ? (int)STRLEN(fname) : 0,
3498 0, first, path,
3499 find_what,
3500 curbuf->b_ffname,
3501 find_what == FINDFILE_DIR
3502 ? (char_u *)"" : curbuf->b_p_sua);
3503 first = FALSE;
3504
3505 if (fresult != NULL && rettv->v_type == VAR_LIST)
3506 list_append_string(rettv->vval.v_list, fresult, -1);
3507
3508 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3509 }
3510
3511 if (rettv->v_type == VAR_STRING)
3512 rettv->vval.v_string = fresult;
3513#endif
3514}
3515
3516/*
3517 * "filter()" function
3518 */
3519 static void
3520f_filter(typval_T *argvars, typval_T *rettv)
3521{
3522 filter_map(argvars, rettv, FALSE);
3523}
3524
3525/*
3526 * "finddir({fname}[, {path}[, {count}]])" function
3527 */
3528 static void
3529f_finddir(typval_T *argvars, typval_T *rettv)
3530{
3531 findfilendir(argvars, rettv, FINDFILE_DIR);
3532}
3533
3534/*
3535 * "findfile({fname}[, {path}[, {count}]])" function
3536 */
3537 static void
3538f_findfile(typval_T *argvars, typval_T *rettv)
3539{
3540 findfilendir(argvars, rettv, FINDFILE_FILE);
3541}
3542
3543#ifdef FEAT_FLOAT
3544/*
3545 * "float2nr({float})" function
3546 */
3547 static void
3548f_float2nr(typval_T *argvars, typval_T *rettv)
3549{
3550 float_T f = 0.0;
3551
3552 if (get_float_arg(argvars, &f) == OK)
3553 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003554 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003555 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003556 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003557 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003558 else
3559 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003560 }
3561}
3562
3563/*
3564 * "floor({float})" function
3565 */
3566 static void
3567f_floor(typval_T *argvars, typval_T *rettv)
3568{
3569 float_T f = 0.0;
3570
3571 rettv->v_type = VAR_FLOAT;
3572 if (get_float_arg(argvars, &f) == OK)
3573 rettv->vval.v_float = floor(f);
3574 else
3575 rettv->vval.v_float = 0.0;
3576}
3577
3578/*
3579 * "fmod()" function
3580 */
3581 static void
3582f_fmod(typval_T *argvars, typval_T *rettv)
3583{
3584 float_T fx = 0.0, fy = 0.0;
3585
3586 rettv->v_type = VAR_FLOAT;
3587 if (get_float_arg(argvars, &fx) == OK
3588 && get_float_arg(&argvars[1], &fy) == OK)
3589 rettv->vval.v_float = fmod(fx, fy);
3590 else
3591 rettv->vval.v_float = 0.0;
3592}
3593#endif
3594
3595/*
3596 * "fnameescape({string})" function
3597 */
3598 static void
3599f_fnameescape(typval_T *argvars, typval_T *rettv)
3600{
3601 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003602 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 rettv->v_type = VAR_STRING;
3604}
3605
3606/*
3607 * "fnamemodify({fname}, {mods})" function
3608 */
3609 static void
3610f_fnamemodify(typval_T *argvars, typval_T *rettv)
3611{
3612 char_u *fname;
3613 char_u *mods;
3614 int usedlen = 0;
3615 int len;
3616 char_u *fbuf = NULL;
3617 char_u buf[NUMBUFLEN];
3618
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003619 fname = tv_get_string_chk(&argvars[0]);
3620 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621 if (fname == NULL || mods == NULL)
3622 fname = NULL;
3623 else
3624 {
3625 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003626 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 }
3628
3629 rettv->v_type = VAR_STRING;
3630 if (fname == NULL)
3631 rettv->vval.v_string = NULL;
3632 else
3633 rettv->vval.v_string = vim_strnsave(fname, len);
3634 vim_free(fbuf);
3635}
3636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637/*
3638 * "foldclosed()" function
3639 */
3640 static void
3641foldclosed_both(
3642 typval_T *argvars UNUSED,
3643 typval_T *rettv,
3644 int end UNUSED)
3645{
3646#ifdef FEAT_FOLDING
3647 linenr_T lnum;
3648 linenr_T first, last;
3649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003650 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3652 {
3653 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3654 {
3655 if (end)
3656 rettv->vval.v_number = (varnumber_T)last;
3657 else
3658 rettv->vval.v_number = (varnumber_T)first;
3659 return;
3660 }
3661 }
3662#endif
3663 rettv->vval.v_number = -1;
3664}
3665
3666/*
3667 * "foldclosed()" function
3668 */
3669 static void
3670f_foldclosed(typval_T *argvars, typval_T *rettv)
3671{
3672 foldclosed_both(argvars, rettv, FALSE);
3673}
3674
3675/*
3676 * "foldclosedend()" function
3677 */
3678 static void
3679f_foldclosedend(typval_T *argvars, typval_T *rettv)
3680{
3681 foldclosed_both(argvars, rettv, TRUE);
3682}
3683
3684/*
3685 * "foldlevel()" function
3686 */
3687 static void
3688f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3689{
3690#ifdef FEAT_FOLDING
3691 linenr_T lnum;
3692
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003693 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3695 rettv->vval.v_number = foldLevel(lnum);
3696#endif
3697}
3698
3699/*
3700 * "foldtext()" function
3701 */
3702 static void
3703f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3704{
3705#ifdef FEAT_FOLDING
3706 linenr_T foldstart;
3707 linenr_T foldend;
3708 char_u *dashes;
3709 linenr_T lnum;
3710 char_u *s;
3711 char_u *r;
3712 int len;
3713 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003714 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715#endif
3716
3717 rettv->v_type = VAR_STRING;
3718 rettv->vval.v_string = NULL;
3719#ifdef FEAT_FOLDING
3720 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3721 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3722 dashes = get_vim_var_str(VV_FOLDDASHES);
3723 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3724 && dashes != NULL)
3725 {
3726 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003727 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728 if (!linewhite(lnum))
3729 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003730
3731 /* Find interesting text in this line. */
3732 s = skipwhite(ml_get(lnum));
3733 /* skip C comment-start */
3734 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3735 {
3736 s = skipwhite(s + 2);
3737 if (*skipwhite(s) == NUL
3738 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3739 {
3740 s = skipwhite(ml_get(lnum + 1));
3741 if (*s == '*')
3742 s = skipwhite(s + 1);
3743 }
3744 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003745 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003746 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003747 r = alloc(STRLEN(txt)
3748 + STRLEN(dashes) // for %s
3749 + 20 // for %3ld
3750 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003751 if (r != NULL)
3752 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003753 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754 len = (int)STRLEN(r);
3755 STRCAT(r, s);
3756 /* remove 'foldmarker' and 'commentstring' */
3757 foldtext_cleanup(r + len);
3758 rettv->vval.v_string = r;
3759 }
3760 }
3761#endif
3762}
3763
3764/*
3765 * "foldtextresult(lnum)" function
3766 */
3767 static void
3768f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3769{
3770#ifdef FEAT_FOLDING
3771 linenr_T lnum;
3772 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003773 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003774 foldinfo_T foldinfo;
3775 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003776 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777#endif
3778
3779 rettv->v_type = VAR_STRING;
3780 rettv->vval.v_string = NULL;
3781#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003782 if (entered)
3783 return; /* reject recursive use */
3784 entered = TRUE;
3785
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003786 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787 /* treat illegal types and illegal string values for {lnum} the same */
3788 if (lnum < 0)
3789 lnum = 0;
3790 fold_count = foldedCount(curwin, lnum, &foldinfo);
3791 if (fold_count > 0)
3792 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003793 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3794 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795 if (text == buf)
3796 text = vim_strsave(text);
3797 rettv->vval.v_string = text;
3798 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003799
3800 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003801#endif
3802}
3803
3804/*
3805 * "foreground()" function
3806 */
3807 static void
3808f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3809{
3810#ifdef FEAT_GUI
3811 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003812 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003814 return;
3815 }
3816#endif
3817#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003819#endif
3820}
3821
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003823common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003824{
3825 char_u *s;
3826 char_u *name;
3827 int use_string = FALSE;
3828 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003829 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003830
3831 if (argvars[0].v_type == VAR_FUNC)
3832 {
3833 /* function(MyFunc, [arg], dict) */
3834 s = argvars[0].vval.v_string;
3835 }
3836 else if (argvars[0].v_type == VAR_PARTIAL
3837 && argvars[0].vval.v_partial != NULL)
3838 {
3839 /* function(dict.MyFunc, [arg]) */
3840 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003841 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003842 }
3843 else
3844 {
3845 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003846 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847 use_string = TRUE;
3848 }
3849
Bram Moolenaar843b8842016-08-21 14:36:15 +02003850 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003851 {
3852 name = s;
3853 trans_name = trans_function_name(&name, FALSE,
3854 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3855 if (*name != NUL)
3856 s = NULL;
3857 }
3858
Bram Moolenaar843b8842016-08-21 14:36:15 +02003859 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3860 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003861 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003863 else if (trans_name != NULL && (is_funcref
3864 ? find_func(trans_name) == NULL
3865 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003866 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003867 else
3868 {
3869 int dict_idx = 0;
3870 int arg_idx = 0;
3871 list_T *list = NULL;
3872
3873 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3874 {
3875 char sid_buf[25];
3876 int off = *s == 's' ? 2 : 5;
3877
3878 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3879 * also be called from another script. Using trans_function_name()
3880 * would also work, but some plugins depend on the name being
3881 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003882 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003883 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003884 if (name != NULL)
3885 {
3886 STRCPY(name, sid_buf);
3887 STRCAT(name, s + off);
3888 }
3889 }
3890 else
3891 name = vim_strsave(s);
3892
3893 if (argvars[1].v_type != VAR_UNKNOWN)
3894 {
3895 if (argvars[2].v_type != VAR_UNKNOWN)
3896 {
3897 /* function(name, [args], dict) */
3898 arg_idx = 1;
3899 dict_idx = 2;
3900 }
3901 else if (argvars[1].v_type == VAR_DICT)
3902 /* function(name, dict) */
3903 dict_idx = 1;
3904 else
3905 /* function(name, [args]) */
3906 arg_idx = 1;
3907 if (dict_idx > 0)
3908 {
3909 if (argvars[dict_idx].v_type != VAR_DICT)
3910 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003911 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003913 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914 }
3915 if (argvars[dict_idx].vval.v_dict == NULL)
3916 dict_idx = 0;
3917 }
3918 if (arg_idx > 0)
3919 {
3920 if (argvars[arg_idx].v_type != VAR_LIST)
3921 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003922 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003924 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925 }
3926 list = argvars[arg_idx].vval.v_list;
3927 if (list == NULL || list->lv_len == 0)
3928 arg_idx = 0;
3929 }
3930 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003931 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003933 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934
3935 /* result is a VAR_PARTIAL */
3936 if (pt == NULL)
3937 vim_free(name);
3938 else
3939 {
3940 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3941 {
3942 listitem_T *li;
3943 int i = 0;
3944 int arg_len = 0;
3945 int lv_len = 0;
3946
3947 if (arg_pt != NULL)
3948 arg_len = arg_pt->pt_argc;
3949 if (list != NULL)
3950 lv_len = list->lv_len;
3951 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003952 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953 if (pt->pt_argv == NULL)
3954 {
3955 vim_free(pt);
3956 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003957 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003959 for (i = 0; i < arg_len; i++)
3960 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3961 if (lv_len > 0)
3962 for (li = list->lv_first; li != NULL;
3963 li = li->li_next)
3964 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965 }
3966
3967 /* For "function(dict.func, [], dict)" and "func" is a partial
3968 * use "dict". That is backwards compatible. */
3969 if (dict_idx > 0)
3970 {
3971 /* The dict is bound explicitly, pt_auto is FALSE. */
3972 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3973 ++pt->pt_dict->dv_refcount;
3974 }
3975 else if (arg_pt != NULL)
3976 {
3977 /* If the dict was bound automatically the result is also
3978 * bound automatically. */
3979 pt->pt_dict = arg_pt->pt_dict;
3980 pt->pt_auto = arg_pt->pt_auto;
3981 if (pt->pt_dict != NULL)
3982 ++pt->pt_dict->dv_refcount;
3983 }
3984
3985 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003986 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3987 {
3988 pt->pt_func = arg_pt->pt_func;
3989 func_ptr_ref(pt->pt_func);
3990 vim_free(name);
3991 }
3992 else if (is_funcref)
3993 {
3994 pt->pt_func = find_func(trans_name);
3995 func_ptr_ref(pt->pt_func);
3996 vim_free(name);
3997 }
3998 else
3999 {
4000 pt->pt_name = name;
4001 func_ref(name);
4002 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004003 }
4004 rettv->v_type = VAR_PARTIAL;
4005 rettv->vval.v_partial = pt;
4006 }
4007 else
4008 {
4009 /* result is a VAR_FUNC */
4010 rettv->v_type = VAR_FUNC;
4011 rettv->vval.v_string = name;
4012 func_ref(name);
4013 }
4014 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004015theend:
4016 vim_free(trans_name);
4017}
4018
4019/*
4020 * "funcref()" function
4021 */
4022 static void
4023f_funcref(typval_T *argvars, typval_T *rettv)
4024{
4025 common_function(argvars, rettv, TRUE);
4026}
4027
4028/*
4029 * "function()" function
4030 */
4031 static void
4032f_function(typval_T *argvars, typval_T *rettv)
4033{
4034 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035}
4036
4037/*
4038 * "garbagecollect()" function
4039 */
4040 static void
4041f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4042{
4043 /* This is postponed until we are back at the toplevel, because we may be
4044 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4045 want_garbage_collect = TRUE;
4046
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004047 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048 garbage_collect_at_exit = TRUE;
4049}
4050
4051/*
4052 * "get()" function
4053 */
4054 static void
4055f_get(typval_T *argvars, typval_T *rettv)
4056{
4057 listitem_T *li;
4058 list_T *l;
4059 dictitem_T *di;
4060 dict_T *d;
4061 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004062 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004064 if (argvars[0].v_type == VAR_BLOB)
4065 {
4066 int error = FALSE;
4067 int idx = tv_get_number_chk(&argvars[1], &error);
4068
4069 if (!error)
4070 {
4071 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004072 if (idx < 0)
4073 idx = blob_len(argvars[0].vval.v_blob) + idx;
4074 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4075 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004076 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004077 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004078 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004079 tv = rettv;
4080 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004081 }
4082 }
4083 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 {
4085 if ((l = argvars[0].vval.v_list) != NULL)
4086 {
4087 int error = FALSE;
4088
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004089 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004090 if (!error && li != NULL)
4091 tv = &li->li_tv;
4092 }
4093 }
4094 else if (argvars[0].v_type == VAR_DICT)
4095 {
4096 if ((d = argvars[0].vval.v_dict) != NULL)
4097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004098 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 if (di != NULL)
4100 tv = &di->di_tv;
4101 }
4102 }
4103 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4104 {
4105 partial_T *pt;
4106 partial_T fref_pt;
4107
4108 if (argvars[0].v_type == VAR_PARTIAL)
4109 pt = argvars[0].vval.v_partial;
4110 else
4111 {
4112 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4113 fref_pt.pt_name = argvars[0].vval.v_string;
4114 pt = &fref_pt;
4115 }
4116
4117 if (pt != NULL)
4118 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004119 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004120 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004121
4122 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4123 {
4124 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004125 n = partial_name(pt);
4126 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004127 rettv->vval.v_string = NULL;
4128 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004129 {
4130 rettv->vval.v_string = vim_strsave(n);
4131 if (rettv->v_type == VAR_FUNC)
4132 func_ref(rettv->vval.v_string);
4133 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134 }
4135 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004136 {
4137 what_is_dict = TRUE;
4138 if (pt->pt_dict != NULL)
4139 rettv_dict_set(rettv, pt->pt_dict);
4140 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 else if (STRCMP(what, "args") == 0)
4142 {
4143 rettv->v_type = VAR_LIST;
4144 if (rettv_list_alloc(rettv) == OK)
4145 {
4146 int i;
4147
4148 for (i = 0; i < pt->pt_argc; ++i)
4149 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4150 }
4151 }
4152 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004153 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004154
4155 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4156 // third argument
4157 if (!what_is_dict)
4158 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004159 }
4160 }
4161 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004162 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163
4164 if (tv == NULL)
4165 {
4166 if (argvars[2].v_type != VAR_UNKNOWN)
4167 copy_tv(&argvars[2], rettv);
4168 }
4169 else
4170 copy_tv(tv, rettv);
4171}
4172
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004173/*
4174 * Returns buffer options, variables and other attributes in a dictionary.
4175 */
4176 static dict_T *
4177get_buffer_info(buf_T *buf)
4178{
4179 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004180 tabpage_T *tp;
4181 win_T *wp;
4182 list_T *windows;
4183
4184 dict = dict_alloc();
4185 if (dict == NULL)
4186 return NULL;
4187
Bram Moolenaare0be1672018-07-08 16:50:37 +02004188 dict_add_number(dict, "bufnr", buf->b_fnum);
4189 dict_add_string(dict, "name", buf->b_ffname);
4190 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4191 : buflist_findlnum(buf));
4192 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4193 dict_add_number(dict, "listed", buf->b_p_bl);
4194 dict_add_number(dict, "changed", bufIsChanged(buf));
4195 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4196 dict_add_number(dict, "hidden",
4197 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004198
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004199 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004200 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004201
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004202 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004203 windows = list_alloc();
4204 if (windows != NULL)
4205 {
4206 FOR_ALL_TAB_WINDOWS(tp, wp)
4207 if (wp->w_buffer == buf)
4208 list_append_number(windows, (varnumber_T)wp->w_id);
4209 dict_add_list(dict, "windows", windows);
4210 }
4211
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004212#ifdef FEAT_TEXT_PROP
4213 // List of popup windows displaying this buffer
4214 windows = list_alloc();
4215 if (windows != NULL)
4216 {
4217 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4218 if (wp->w_buffer == buf)
4219 list_append_number(windows, (varnumber_T)wp->w_id);
4220 FOR_ALL_TABPAGES(tp)
4221 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4222 if (wp->w_buffer == buf)
4223 list_append_number(windows, (varnumber_T)wp->w_id);
4224
4225 dict_add_list(dict, "popups", windows);
4226 }
4227#endif
4228
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004229#ifdef FEAT_SIGNS
4230 if (buf->b_signlist != NULL)
4231 {
4232 /* List of signs placed in this buffer */
4233 list_T *signs = list_alloc();
4234 if (signs != NULL)
4235 {
4236 get_buffer_signs(buf, signs);
4237 dict_add_list(dict, "signs", signs);
4238 }
4239 }
4240#endif
4241
4242 return dict;
4243}
4244
4245/*
4246 * "getbufinfo()" function
4247 */
4248 static void
4249f_getbufinfo(typval_T *argvars, typval_T *rettv)
4250{
4251 buf_T *buf = NULL;
4252 buf_T *argbuf = NULL;
4253 dict_T *d;
4254 int filtered = FALSE;
4255 int sel_buflisted = FALSE;
4256 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004257 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004258
4259 if (rettv_list_alloc(rettv) != OK)
4260 return;
4261
4262 /* List of all the buffers or selected buffers */
4263 if (argvars[0].v_type == VAR_DICT)
4264 {
4265 dict_T *sel_d = argvars[0].vval.v_dict;
4266
4267 if (sel_d != NULL)
4268 {
4269 dictitem_T *di;
4270
4271 filtered = TRUE;
4272
4273 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004274 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004275 sel_buflisted = TRUE;
4276
4277 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004278 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004279 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004280
4281 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004282 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004283 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004284 }
4285 }
4286 else if (argvars[0].v_type != VAR_UNKNOWN)
4287 {
4288 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004289 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004290 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004291 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004292 --emsg_off;
4293 if (argbuf == NULL)
4294 return;
4295 }
4296
4297 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004298 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 {
4300 if (argbuf != NULL && argbuf != buf)
4301 continue;
4302 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004303 || (sel_buflisted && !buf->b_p_bl)
4304 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004305 continue;
4306
4307 d = get_buffer_info(buf);
4308 if (d != NULL)
4309 list_append_dict(rettv->vval.v_list, d);
4310 if (argbuf != NULL)
4311 return;
4312 }
4313}
4314
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315/*
4316 * Get line or list of lines from buffer "buf" into "rettv".
4317 * Return a range (from start to end) of lines in rettv from the specified
4318 * buffer.
4319 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4320 */
4321 static void
4322get_buffer_lines(
4323 buf_T *buf,
4324 linenr_T start,
4325 linenr_T end,
4326 int retlist,
4327 typval_T *rettv)
4328{
4329 char_u *p;
4330
4331 rettv->v_type = VAR_STRING;
4332 rettv->vval.v_string = NULL;
4333 if (retlist && rettv_list_alloc(rettv) == FAIL)
4334 return;
4335
4336 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4337 return;
4338
4339 if (!retlist)
4340 {
4341 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4342 p = ml_get_buf(buf, start, FALSE);
4343 else
4344 p = (char_u *)"";
4345 rettv->vval.v_string = vim_strsave(p);
4346 }
4347 else
4348 {
4349 if (end < start)
4350 return;
4351
4352 if (start < 1)
4353 start = 1;
4354 if (end > buf->b_ml.ml_line_count)
4355 end = buf->b_ml.ml_line_count;
4356 while (start <= end)
4357 if (list_append_string(rettv->vval.v_list,
4358 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4359 break;
4360 }
4361}
4362
4363/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004364 * "getbufline()" function
4365 */
4366 static void
4367f_getbufline(typval_T *argvars, typval_T *rettv)
4368{
4369 linenr_T lnum;
4370 linenr_T end;
4371 buf_T *buf;
4372
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004373 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004375 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004376 --emsg_off;
4377
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004378 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 if (argvars[2].v_type == VAR_UNKNOWN)
4380 end = lnum;
4381 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004382 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004383
4384 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4385}
4386
4387/*
4388 * "getbufvar()" function
4389 */
4390 static void
4391f_getbufvar(typval_T *argvars, typval_T *rettv)
4392{
4393 buf_T *buf;
4394 buf_T *save_curbuf;
4395 char_u *varname;
4396 dictitem_T *v;
4397 int done = FALSE;
4398
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004399 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4400 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004401 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004402 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004403
4404 rettv->v_type = VAR_STRING;
4405 rettv->vval.v_string = NULL;
4406
4407 if (buf != NULL && varname != NULL)
4408 {
4409 /* set curbuf to be our buf, temporarily */
4410 save_curbuf = curbuf;
4411 curbuf = buf;
4412
Bram Moolenaar30567352016-08-27 21:25:44 +02004413 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004414 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004415 if (varname[1] == NUL)
4416 {
4417 /* get all buffer-local options in a dict */
4418 dict_T *opts = get_winbuf_options(TRUE);
4419
4420 if (opts != NULL)
4421 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004422 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004423 done = TRUE;
4424 }
4425 }
4426 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4427 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004428 done = TRUE;
4429 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004430 else
4431 {
4432 /* Look up the variable. */
4433 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4434 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4435 'b', varname, FALSE);
4436 if (v != NULL)
4437 {
4438 copy_tv(&v->di_tv, rettv);
4439 done = TRUE;
4440 }
4441 }
4442
4443 /* restore previous notion of curbuf */
4444 curbuf = save_curbuf;
4445 }
4446
4447 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4448 /* use the default value */
4449 copy_tv(&argvars[2], rettv);
4450
4451 --emsg_off;
4452}
4453
4454/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004455 * "getchangelist()" function
4456 */
4457 static void
4458f_getchangelist(typval_T *argvars, typval_T *rettv)
4459{
4460#ifdef FEAT_JUMPLIST
4461 buf_T *buf;
4462 int i;
4463 list_T *l;
4464 dict_T *d;
4465#endif
4466
4467 if (rettv_list_alloc(rettv) != OK)
4468 return;
4469
4470#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004471 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004472 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004473 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004474 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004475 if (buf == NULL)
4476 return;
4477
4478 l = list_alloc();
4479 if (l == NULL)
4480 return;
4481
4482 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4483 return;
4484 /*
4485 * The current window change list index tracks only the position in the
4486 * current buffer change list. For other buffers, use the change list
4487 * length as the current index.
4488 */
4489 list_append_number(rettv->vval.v_list,
4490 (varnumber_T)((buf == curwin->w_buffer)
4491 ? curwin->w_changelistidx : buf->b_changelistlen));
4492
4493 for (i = 0; i < buf->b_changelistlen; ++i)
4494 {
4495 if (buf->b_changelist[i].lnum == 0)
4496 continue;
4497 if ((d = dict_alloc()) == NULL)
4498 return;
4499 if (list_append_dict(l, d) == FAIL)
4500 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004501 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4502 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004503 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004504 }
4505#endif
4506}
4507/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004508 * "getchar()" function
4509 */
4510 static void
4511f_getchar(typval_T *argvars, typval_T *rettv)
4512{
4513 varnumber_T n;
4514 int error = FALSE;
4515
Bram Moolenaar84d93902018-09-11 20:10:20 +02004516#ifdef MESSAGE_QUEUE
4517 // vpeekc() used to check for messages, but that caused problems, invoking
4518 // a callback where it was not expected. Some plugins use getchar(1) in a
4519 // loop to await a message, therefore make sure we check for messages here.
4520 parse_queued_messages();
4521#endif
4522
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004523 /* Position the cursor. Needed after a message that ends in a space. */
4524 windgoto(msg_row, msg_col);
4525
4526 ++no_mapping;
4527 ++allow_keys;
4528 for (;;)
4529 {
4530 if (argvars[0].v_type == VAR_UNKNOWN)
4531 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004532 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004533 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 /* getchar(1): only check if char avail */
4535 n = vpeekc_any();
4536 else if (error || vpeekc_any() == NUL)
4537 /* illegal argument or getchar(0) and no char avail: return zero */
4538 n = 0;
4539 else
4540 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004541 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004542
4543 if (n == K_IGNORE)
4544 continue;
4545 break;
4546 }
4547 --no_mapping;
4548 --allow_keys;
4549
4550 set_vim_var_nr(VV_MOUSE_WIN, 0);
4551 set_vim_var_nr(VV_MOUSE_WINID, 0);
4552 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4553 set_vim_var_nr(VV_MOUSE_COL, 0);
4554
4555 rettv->vval.v_number = n;
4556 if (IS_SPECIAL(n) || mod_mask != 0)
4557 {
4558 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4559 int i = 0;
4560
4561 /* Turn a special key into three bytes, plus modifier. */
4562 if (mod_mask != 0)
4563 {
4564 temp[i++] = K_SPECIAL;
4565 temp[i++] = KS_MODIFIER;
4566 temp[i++] = mod_mask;
4567 }
4568 if (IS_SPECIAL(n))
4569 {
4570 temp[i++] = K_SPECIAL;
4571 temp[i++] = K_SECOND(n);
4572 temp[i++] = K_THIRD(n);
4573 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574 else if (has_mbyte)
4575 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004576 else
4577 temp[i++] = n;
4578 temp[i++] = NUL;
4579 rettv->v_type = VAR_STRING;
4580 rettv->vval.v_string = vim_strsave(temp);
4581
4582#ifdef FEAT_MOUSE
4583 if (is_mouse_key(n))
4584 {
4585 int row = mouse_row;
4586 int col = mouse_col;
4587 win_T *win;
4588 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004589 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590 int winnr = 1;
4591
4592 if (row >= 0 && col >= 0)
4593 {
4594 /* Find the window at the mouse coordinates and compute the
4595 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004596 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004597 if (win == NULL)
4598 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004599 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004600# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004601 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004602 winnr = 0;
4603 else
4604# endif
4605 for (wp = firstwin; wp != win && wp != NULL;
4606 wp = wp->w_next)
4607 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004608 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4609 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4610 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4611 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4612 }
4613 }
4614#endif
4615 }
4616}
4617
4618/*
4619 * "getcharmod()" function
4620 */
4621 static void
4622f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4623{
4624 rettv->vval.v_number = mod_mask;
4625}
4626
4627/*
4628 * "getcharsearch()" function
4629 */
4630 static void
4631f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4632{
4633 if (rettv_dict_alloc(rettv) != FAIL)
4634 {
4635 dict_T *dict = rettv->vval.v_dict;
4636
Bram Moolenaare0be1672018-07-08 16:50:37 +02004637 dict_add_string(dict, "char", last_csearch());
4638 dict_add_number(dict, "forward", last_csearch_forward());
4639 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640 }
4641}
4642
4643/*
4644 * "getcmdline()" function
4645 */
4646 static void
4647f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4648{
4649 rettv->v_type = VAR_STRING;
4650 rettv->vval.v_string = get_cmdline_str();
4651}
4652
4653/*
4654 * "getcmdpos()" function
4655 */
4656 static void
4657f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4658{
4659 rettv->vval.v_number = get_cmdline_pos() + 1;
4660}
4661
4662/*
4663 * "getcmdtype()" function
4664 */
4665 static void
4666f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4667{
4668 rettv->v_type = VAR_STRING;
4669 rettv->vval.v_string = alloc(2);
4670 if (rettv->vval.v_string != NULL)
4671 {
4672 rettv->vval.v_string[0] = get_cmdline_type();
4673 rettv->vval.v_string[1] = NUL;
4674 }
4675}
4676
4677/*
4678 * "getcmdwintype()" function
4679 */
4680 static void
4681f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4682{
4683 rettv->v_type = VAR_STRING;
4684 rettv->vval.v_string = NULL;
4685#ifdef FEAT_CMDWIN
4686 rettv->vval.v_string = alloc(2);
4687 if (rettv->vval.v_string != NULL)
4688 {
4689 rettv->vval.v_string[0] = cmdwin_type;
4690 rettv->vval.v_string[1] = NUL;
4691 }
4692#endif
4693}
4694
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695/*
4696 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004697 *
4698 * Return the current working directory of a window in a tab page.
4699 * First optional argument 'winnr' is the window number or -1 and the second
4700 * optional argument 'tabnr' is the tab page number.
4701 *
4702 * If no arguments are supplied, then return the directory of the current
4703 * window.
4704 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4705 * the specified window.
4706 * If 'winnr' is 0 then return the directory of the current window.
4707 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4708 * directory of the specified tab page. Otherwise return the directory of the
4709 * specified window in the specified tab page.
4710 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004711 */
4712 static void
4713f_getcwd(typval_T *argvars, typval_T *rettv)
4714{
4715 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004716 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004718 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719
4720 rettv->v_type = VAR_STRING;
4721 rettv->vval.v_string = NULL;
4722
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004723 if (argvars[0].v_type == VAR_NUMBER
4724 && argvars[0].vval.v_number == -1
4725 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004726 global = TRUE;
4727 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004728 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004729
4730 if (wp != NULL && wp->w_localdir != NULL)
4731 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004732 else if (tp != NULL && tp->tp_localdir != NULL)
4733 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4734 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004736 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 rettv->vval.v_string = vim_strsave(globaldir);
4738 else
4739 {
4740 cwd = alloc(MAXPATHL);
4741 if (cwd != NULL)
4742 {
4743 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4744 rettv->vval.v_string = vim_strsave(cwd);
4745 vim_free(cwd);
4746 }
4747 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004749#ifdef BACKSLASH_IN_FILENAME
4750 if (rettv->vval.v_string != NULL)
4751 slash_adjust(rettv->vval.v_string);
4752#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004753}
4754
4755/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004756 * "getenv()" function
4757 */
4758 static void
4759f_getenv(typval_T *argvars, typval_T *rettv)
4760{
4761 int mustfree = FALSE;
4762 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4763
4764 if (p == NULL)
4765 {
4766 rettv->v_type = VAR_SPECIAL;
4767 rettv->vval.v_number = VVAL_NULL;
4768 return;
4769 }
4770 if (!mustfree)
4771 p = vim_strsave(p);
4772 rettv->vval.v_string = p;
4773 rettv->v_type = VAR_STRING;
4774}
4775
4776/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004777 * "getfontname()" function
4778 */
4779 static void
4780f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4781{
4782 rettv->v_type = VAR_STRING;
4783 rettv->vval.v_string = NULL;
4784#ifdef FEAT_GUI
4785 if (gui.in_use)
4786 {
4787 GuiFont font;
4788 char_u *name = NULL;
4789
4790 if (argvars[0].v_type == VAR_UNKNOWN)
4791 {
4792 /* Get the "Normal" font. Either the name saved by
4793 * hl_set_font_name() or from the font ID. */
4794 font = gui.norm_font;
4795 name = hl_get_font_name();
4796 }
4797 else
4798 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004799 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4801 return;
4802 font = gui_mch_get_font(name, FALSE);
4803 if (font == NOFONT)
4804 return; /* Invalid font name, return empty string. */
4805 }
4806 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4807 if (argvars[0].v_type != VAR_UNKNOWN)
4808 gui_mch_free_font(font);
4809 }
4810#endif
4811}
4812
4813/*
4814 * "getfperm({fname})" function
4815 */
4816 static void
4817f_getfperm(typval_T *argvars, typval_T *rettv)
4818{
4819 char_u *fname;
4820 stat_T st;
4821 char_u *perm = NULL;
4822 char_u flags[] = "rwx";
4823 int i;
4824
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004825 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826
4827 rettv->v_type = VAR_STRING;
4828 if (mch_stat((char *)fname, &st) >= 0)
4829 {
4830 perm = vim_strsave((char_u *)"---------");
4831 if (perm != NULL)
4832 {
4833 for (i = 0; i < 9; i++)
4834 {
4835 if (st.st_mode & (1 << (8 - i)))
4836 perm[i] = flags[i % 3];
4837 }
4838 }
4839 }
4840 rettv->vval.v_string = perm;
4841}
4842
4843/*
4844 * "getfsize({fname})" function
4845 */
4846 static void
4847f_getfsize(typval_T *argvars, typval_T *rettv)
4848{
4849 char_u *fname;
4850 stat_T st;
4851
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004852 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853
4854 rettv->v_type = VAR_NUMBER;
4855
4856 if (mch_stat((char *)fname, &st) >= 0)
4857 {
4858 if (mch_isdir(fname))
4859 rettv->vval.v_number = 0;
4860 else
4861 {
4862 rettv->vval.v_number = (varnumber_T)st.st_size;
4863
4864 /* non-perfect check for overflow */
4865 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4866 rettv->vval.v_number = -2;
4867 }
4868 }
4869 else
4870 rettv->vval.v_number = -1;
4871}
4872
4873/*
4874 * "getftime({fname})" function
4875 */
4876 static void
4877f_getftime(typval_T *argvars, typval_T *rettv)
4878{
4879 char_u *fname;
4880 stat_T st;
4881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004882 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004883
4884 if (mch_stat((char *)fname, &st) >= 0)
4885 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4886 else
4887 rettv->vval.v_number = -1;
4888}
4889
4890/*
4891 * "getftype({fname})" function
4892 */
4893 static void
4894f_getftype(typval_T *argvars, typval_T *rettv)
4895{
4896 char_u *fname;
4897 stat_T st;
4898 char_u *type = NULL;
4899 char *t;
4900
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004901 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004902
4903 rettv->v_type = VAR_STRING;
4904 if (mch_lstat((char *)fname, &st) >= 0)
4905 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906 if (S_ISREG(st.st_mode))
4907 t = "file";
4908 else if (S_ISDIR(st.st_mode))
4909 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 else if (S_ISLNK(st.st_mode))
4911 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 else if (S_ISBLK(st.st_mode))
4913 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004914 else if (S_ISCHR(st.st_mode))
4915 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916 else if (S_ISFIFO(st.st_mode))
4917 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004918 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004919 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920 else
4921 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 type = vim_strsave((char_u *)t);
4923 }
4924 rettv->vval.v_string = type;
4925}
4926
4927/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004928 * "getjumplist()" function
4929 */
4930 static void
4931f_getjumplist(typval_T *argvars, typval_T *rettv)
4932{
4933#ifdef FEAT_JUMPLIST
4934 win_T *wp;
4935 int i;
4936 list_T *l;
4937 dict_T *d;
4938#endif
4939
4940 if (rettv_list_alloc(rettv) != OK)
4941 return;
4942
4943#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004944 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004945 if (wp == NULL)
4946 return;
4947
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004948 cleanup_jumplist(wp, TRUE);
4949
Bram Moolenaar4f505882018-02-10 21:06:32 +01004950 l = list_alloc();
4951 if (l == NULL)
4952 return;
4953
4954 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4955 return;
4956 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4957
4958 for (i = 0; i < wp->w_jumplistlen; ++i)
4959 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004960 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4961 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004962 if ((d = dict_alloc()) == NULL)
4963 return;
4964 if (list_append_dict(l, d) == FAIL)
4965 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004966 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4967 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004968 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004969 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004970 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004971 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004972 }
4973#endif
4974}
4975
4976/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004977 * "getline(lnum, [end])" function
4978 */
4979 static void
4980f_getline(typval_T *argvars, typval_T *rettv)
4981{
4982 linenr_T lnum;
4983 linenr_T end;
4984 int retlist;
4985
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004986 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004987 if (argvars[1].v_type == VAR_UNKNOWN)
4988 {
4989 end = 0;
4990 retlist = FALSE;
4991 }
4992 else
4993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004994 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004995 retlist = TRUE;
4996 }
4997
4998 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4999}
5000
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005001#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005002 static void
5003get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5004{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005005 if (what_arg->v_type == VAR_UNKNOWN)
5006 {
5007 if (rettv_list_alloc(rettv) == OK)
5008 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005009 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005010 }
5011 else
5012 {
5013 if (rettv_dict_alloc(rettv) == OK)
5014 if (is_qf || (wp != NULL))
5015 {
5016 if (what_arg->v_type == VAR_DICT)
5017 {
5018 dict_T *d = what_arg->vval.v_dict;
5019
5020 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005021 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005022 }
5023 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005024 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005025 }
5026 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005027}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005028#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005029
5030/*
5031 * "getloclist()" function
5032 */
5033 static void
5034f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5035{
5036#ifdef FEAT_QUICKFIX
5037 win_T *wp;
5038
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005039 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005040 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5041#endif
5042}
5043
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045 * "getpid()" function
5046 */
5047 static void
5048f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5049{
5050 rettv->vval.v_number = mch_get_pid();
5051}
5052
5053 static void
5054getpos_both(
5055 typval_T *argvars,
5056 typval_T *rettv,
5057 int getcurpos)
5058{
5059 pos_T *fp;
5060 list_T *l;
5061 int fnum = -1;
5062
5063 if (rettv_list_alloc(rettv) == OK)
5064 {
5065 l = rettv->vval.v_list;
5066 if (getcurpos)
5067 fp = &curwin->w_cursor;
5068 else
5069 fp = var2fpos(&argvars[0], TRUE, &fnum);
5070 if (fnum != -1)
5071 list_append_number(l, (varnumber_T)fnum);
5072 else
5073 list_append_number(l, (varnumber_T)0);
5074 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5075 : (varnumber_T)0);
5076 list_append_number(l, (fp != NULL)
5077 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5078 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005079 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080 (varnumber_T)0);
5081 if (getcurpos)
5082 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005083 int save_set_curswant = curwin->w_set_curswant;
5084 colnr_T save_curswant = curwin->w_curswant;
5085 colnr_T save_virtcol = curwin->w_virtcol;
5086
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005087 update_curswant();
5088 list_append_number(l, curwin->w_curswant == MAXCOL ?
5089 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005090
5091 // Do not change "curswant", as it is unexpected that a get
5092 // function has a side effect.
5093 if (save_set_curswant)
5094 {
5095 curwin->w_set_curswant = save_set_curswant;
5096 curwin->w_curswant = save_curswant;
5097 curwin->w_virtcol = save_virtcol;
5098 curwin->w_valid &= ~VALID_VIRTCOL;
5099 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005100 }
5101 }
5102 else
5103 rettv->vval.v_number = FALSE;
5104}
5105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106/*
5107 * "getcurpos()" function
5108 */
5109 static void
5110f_getcurpos(typval_T *argvars, typval_T *rettv)
5111{
5112 getpos_both(argvars, rettv, TRUE);
5113}
5114
5115/*
5116 * "getpos(string)" function
5117 */
5118 static void
5119f_getpos(typval_T *argvars, typval_T *rettv)
5120{
5121 getpos_both(argvars, rettv, FALSE);
5122}
5123
5124/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005125 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126 */
5127 static void
5128f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5129{
5130#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005131 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005132#endif
5133}
5134
5135/*
5136 * "getreg()" function
5137 */
5138 static void
5139f_getreg(typval_T *argvars, typval_T *rettv)
5140{
5141 char_u *strregname;
5142 int regname;
5143 int arg2 = FALSE;
5144 int return_list = FALSE;
5145 int error = FALSE;
5146
5147 if (argvars[0].v_type != VAR_UNKNOWN)
5148 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005149 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005150 error = strregname == NULL;
5151 if (argvars[1].v_type != VAR_UNKNOWN)
5152 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005153 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005155 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005156 }
5157 }
5158 else
5159 strregname = get_vim_var_str(VV_REG);
5160
5161 if (error)
5162 return;
5163
5164 regname = (strregname == NULL ? '"' : *strregname);
5165 if (regname == 0)
5166 regname = '"';
5167
5168 if (return_list)
5169 {
5170 rettv->v_type = VAR_LIST;
5171 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5172 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5173 if (rettv->vval.v_list == NULL)
5174 (void)rettv_list_alloc(rettv);
5175 else
5176 ++rettv->vval.v_list->lv_refcount;
5177 }
5178 else
5179 {
5180 rettv->v_type = VAR_STRING;
5181 rettv->vval.v_string = get_reg_contents(regname,
5182 arg2 ? GREG_EXPR_SRC : 0);
5183 }
5184}
5185
5186/*
5187 * "getregtype()" function
5188 */
5189 static void
5190f_getregtype(typval_T *argvars, typval_T *rettv)
5191{
5192 char_u *strregname;
5193 int regname;
5194 char_u buf[NUMBUFLEN + 2];
5195 long reglen = 0;
5196
5197 if (argvars[0].v_type != VAR_UNKNOWN)
5198 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005199 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005200 if (strregname == NULL) /* type error; errmsg already given */
5201 {
5202 rettv->v_type = VAR_STRING;
5203 rettv->vval.v_string = NULL;
5204 return;
5205 }
5206 }
5207 else
5208 /* Default to v:register */
5209 strregname = get_vim_var_str(VV_REG);
5210
5211 regname = (strregname == NULL ? '"' : *strregname);
5212 if (regname == 0)
5213 regname = '"';
5214
5215 buf[0] = NUL;
5216 buf[1] = NUL;
5217 switch (get_reg_type(regname, &reglen))
5218 {
5219 case MLINE: buf[0] = 'V'; break;
5220 case MCHAR: buf[0] = 'v'; break;
5221 case MBLOCK:
5222 buf[0] = Ctrl_V;
5223 sprintf((char *)buf + 1, "%ld", reglen + 1);
5224 break;
5225 }
5226 rettv->v_type = VAR_STRING;
5227 rettv->vval.v_string = vim_strsave(buf);
5228}
5229
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005230/*
5231 * Returns information (variables, options, etc.) about a tab page
5232 * as a dictionary.
5233 */
5234 static dict_T *
5235get_tabpage_info(tabpage_T *tp, int tp_idx)
5236{
5237 win_T *wp;
5238 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005239 list_T *l;
5240
5241 dict = dict_alloc();
5242 if (dict == NULL)
5243 return NULL;
5244
Bram Moolenaare0be1672018-07-08 16:50:37 +02005245 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005246
5247 l = list_alloc();
5248 if (l != NULL)
5249 {
5250 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005251 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005252 list_append_number(l, (varnumber_T)wp->w_id);
5253 dict_add_list(dict, "windows", l);
5254 }
5255
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005256 /* Make a reference to tabpage variables */
5257 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005258
5259 return dict;
5260}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005261
5262/*
5263 * "gettabinfo()" function
5264 */
5265 static void
5266f_gettabinfo(typval_T *argvars, typval_T *rettv)
5267{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005268 tabpage_T *tp, *tparg = NULL;
5269 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005270 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005271
5272 if (rettv_list_alloc(rettv) != OK)
5273 return;
5274
5275 if (argvars[0].v_type != VAR_UNKNOWN)
5276 {
5277 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005278 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005279 if (tparg == NULL)
5280 return;
5281 }
5282
5283 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005284 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005285 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005286 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005287 if (tparg != NULL && tp != tparg)
5288 continue;
5289 d = get_tabpage_info(tp, tpnr);
5290 if (d != NULL)
5291 list_append_dict(rettv->vval.v_list, d);
5292 if (tparg != NULL)
5293 return;
5294 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005295}
5296
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005297/*
5298 * "gettabvar()" function
5299 */
5300 static void
5301f_gettabvar(typval_T *argvars, typval_T *rettv)
5302{
5303 win_T *oldcurwin;
5304 tabpage_T *tp, *oldtabpage;
5305 dictitem_T *v;
5306 char_u *varname;
5307 int done = FALSE;
5308
5309 rettv->v_type = VAR_STRING;
5310 rettv->vval.v_string = NULL;
5311
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005312 varname = tv_get_string_chk(&argvars[1]);
5313 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005314 if (tp != NULL && varname != NULL)
5315 {
5316 /* Set tp to be our tabpage, temporarily. Also set the window to the
5317 * first window in the tabpage, otherwise the window is not valid. */
5318 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005319 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5320 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005321 {
5322 /* look up the variable */
5323 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5324 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5325 if (v != NULL)
5326 {
5327 copy_tv(&v->di_tv, rettv);
5328 done = TRUE;
5329 }
5330 }
5331
5332 /* restore previous notion of curwin */
5333 restore_win(oldcurwin, oldtabpage, TRUE);
5334 }
5335
5336 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5337 copy_tv(&argvars[2], rettv);
5338}
5339
5340/*
5341 * "gettabwinvar()" function
5342 */
5343 static void
5344f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5345{
5346 getwinvar(argvars, rettv, 1);
5347}
5348
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005349/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005350 * "gettagstack()" function
5351 */
5352 static void
5353f_gettagstack(typval_T *argvars, typval_T *rettv)
5354{
5355 win_T *wp = curwin; // default is current window
5356
5357 if (rettv_dict_alloc(rettv) != OK)
5358 return;
5359
5360 if (argvars[0].v_type != VAR_UNKNOWN)
5361 {
5362 wp = find_win_by_nr_or_id(&argvars[0]);
5363 if (wp == NULL)
5364 return;
5365 }
5366
5367 get_tagstack(wp, rettv->vval.v_dict);
5368}
5369
5370/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005371 * Returns information about a window as a dictionary.
5372 */
5373 static dict_T *
5374get_win_info(win_T *wp, short tpnr, short winnr)
5375{
5376 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005377
5378 dict = dict_alloc();
5379 if (dict == NULL)
5380 return NULL;
5381
Bram Moolenaare0be1672018-07-08 16:50:37 +02005382 dict_add_number(dict, "tabnr", tpnr);
5383 dict_add_number(dict, "winnr", winnr);
5384 dict_add_number(dict, "winid", wp->w_id);
5385 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005386 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005387 dict_add_number(dict, "topline", wp->w_topline);
5388 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005389#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005390 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005391#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005392 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005393 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005394 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005395
Bram Moolenaar69905d12017-08-13 18:14:47 +02005396#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005397 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005398#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005399#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005400 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5401 dict_add_number(dict, "loclist",
5402 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005403#endif
5404
Bram Moolenaar30567352016-08-27 21:25:44 +02005405 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005406 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005407
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005408 return dict;
5409}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005410
5411/*
5412 * "getwininfo()" function
5413 */
5414 static void
5415f_getwininfo(typval_T *argvars, typval_T *rettv)
5416{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005417 tabpage_T *tp;
5418 win_T *wp = NULL, *wparg = NULL;
5419 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005420 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005421
5422 if (rettv_list_alloc(rettv) != OK)
5423 return;
5424
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005425 if (argvars[0].v_type != VAR_UNKNOWN)
5426 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005427 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005428 if (wparg == NULL)
5429 return;
5430 }
5431
5432 /* Collect information about either all the windows across all the tab
5433 * pages or one particular window.
5434 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005435 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005436 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005437 tabnr++;
5438 winnr = 0;
5439 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005440 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005441 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005442 if (wparg != NULL && wp != wparg)
5443 continue;
5444 d = get_win_info(wp, tabnr, winnr);
5445 if (d != NULL)
5446 list_append_dict(rettv->vval.v_list, d);
5447 if (wparg != NULL)
5448 /* found information about a specific window */
5449 return;
5450 }
5451 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005452}
5453
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005454/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005455 * "win_execute()" function
5456 */
5457 static void
5458f_win_execute(typval_T *argvars, typval_T *rettv)
5459{
5460 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005461 tabpage_T *tp;
5462 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005463 win_T *save_curwin;
5464 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005465
Bram Moolenaar820680b2019-08-09 14:56:22 +02005466 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005467 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005468 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005469 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005470 check_cursor();
5471 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005472 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005473 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005474 }
5475}
5476
5477/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005478 * "win_findbuf()" function
5479 */
5480 static void
5481f_win_findbuf(typval_T *argvars, typval_T *rettv)
5482{
5483 if (rettv_list_alloc(rettv) != FAIL)
5484 win_findbuf(argvars, rettv->vval.v_list);
5485}
5486
5487/*
5488 * "win_getid()" function
5489 */
5490 static void
5491f_win_getid(typval_T *argvars, typval_T *rettv)
5492{
5493 rettv->vval.v_number = win_getid(argvars);
5494}
5495
5496/*
5497 * "win_gotoid()" function
5498 */
5499 static void
5500f_win_gotoid(typval_T *argvars, typval_T *rettv)
5501{
5502 rettv->vval.v_number = win_gotoid(argvars);
5503}
5504
5505/*
5506 * "win_id2tabwin()" function
5507 */
5508 static void
5509f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5510{
5511 if (rettv_list_alloc(rettv) != FAIL)
5512 win_id2tabwin(argvars, rettv->vval.v_list);
5513}
5514
5515/*
5516 * "win_id2win()" function
5517 */
5518 static void
5519f_win_id2win(typval_T *argvars, typval_T *rettv)
5520{
5521 rettv->vval.v_number = win_id2win(argvars);
5522}
5523
5524/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005525 * "win_screenpos()" function
5526 */
5527 static void
5528f_win_screenpos(typval_T *argvars, typval_T *rettv)
5529{
5530 win_T *wp;
5531
5532 if (rettv_list_alloc(rettv) == FAIL)
5533 return;
5534
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005535 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005536 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5537 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5538}
5539
5540/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005541 * "getwinpos({timeout})" function
5542 */
5543 static void
5544f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5545{
5546 int x = -1;
5547 int y = -1;
5548
5549 if (rettv_list_alloc(rettv) == FAIL)
5550 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005551#if defined(FEAT_GUI) \
5552 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5553 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005554 {
5555 varnumber_T timeout = 100;
5556
5557 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005558 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005559
5560 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005561 }
5562#endif
5563 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5564 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5565}
5566
5567
5568/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005569 * "getwinposx()" function
5570 */
5571 static void
5572f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5573{
5574 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005575#if defined(FEAT_GUI) \
5576 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5577 || defined(MSWIN)
5578
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005579 {
5580 int x, y;
5581
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005582 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005583 rettv->vval.v_number = x;
5584 }
5585#endif
5586}
5587
5588/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005589 * "getwinposy()" function
5590 */
5591 static void
5592f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5593{
5594 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005595#if defined(FEAT_GUI) \
5596 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5597 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 {
5599 int x, y;
5600
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005601 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005602 rettv->vval.v_number = y;
5603 }
5604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605}
5606
5607/*
5608 * "getwinvar()" function
5609 */
5610 static void
5611f_getwinvar(typval_T *argvars, typval_T *rettv)
5612{
5613 getwinvar(argvars, rettv, 0);
5614}
5615
5616/*
5617 * "glob()" function
5618 */
5619 static void
5620f_glob(typval_T *argvars, typval_T *rettv)
5621{
5622 int options = WILD_SILENT|WILD_USE_NL;
5623 expand_T xpc;
5624 int error = FALSE;
5625
5626 /* When the optional second argument is non-zero, don't remove matches
5627 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5628 rettv->v_type = VAR_STRING;
5629 if (argvars[1].v_type != VAR_UNKNOWN)
5630 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005631 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632 options |= WILD_KEEP_ALL;
5633 if (argvars[2].v_type != VAR_UNKNOWN)
5634 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005635 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005636 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005638 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639 options |= WILD_ALLLINKS;
5640 }
5641 }
5642 if (!error)
5643 {
5644 ExpandInit(&xpc);
5645 xpc.xp_context = EXPAND_FILES;
5646 if (p_wic)
5647 options += WILD_ICASE;
5648 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005649 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005650 NULL, options, WILD_ALL);
5651 else if (rettv_list_alloc(rettv) != FAIL)
5652 {
5653 int i;
5654
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005655 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005656 NULL, options, WILD_ALL_KEEP);
5657 for (i = 0; i < xpc.xp_numfiles; i++)
5658 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5659
5660 ExpandCleanup(&xpc);
5661 }
5662 }
5663 else
5664 rettv->vval.v_string = NULL;
5665}
5666
5667/*
5668 * "globpath()" function
5669 */
5670 static void
5671f_globpath(typval_T *argvars, typval_T *rettv)
5672{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005673 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005674 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005675 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676 int error = FALSE;
5677 garray_T ga;
5678 int i;
5679
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005680 // When the optional second argument is non-zero, don't remove matches
5681 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005682 rettv->v_type = VAR_STRING;
5683 if (argvars[2].v_type != VAR_UNKNOWN)
5684 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005685 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005686 flags |= WILD_KEEP_ALL;
5687 if (argvars[3].v_type != VAR_UNKNOWN)
5688 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005689 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005690 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005692 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005693 flags |= WILD_ALLLINKS;
5694 }
5695 }
5696 if (file != NULL && !error)
5697 {
5698 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005699 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700 if (rettv->v_type == VAR_STRING)
5701 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5702 else if (rettv_list_alloc(rettv) != FAIL)
5703 for (i = 0; i < ga.ga_len; ++i)
5704 list_append_string(rettv->vval.v_list,
5705 ((char_u **)(ga.ga_data))[i], -1);
5706 ga_clear_strings(&ga);
5707 }
5708 else
5709 rettv->vval.v_string = NULL;
5710}
5711
5712/*
5713 * "glob2regpat()" function
5714 */
5715 static void
5716f_glob2regpat(typval_T *argvars, typval_T *rettv)
5717{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005718 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005719
5720 rettv->v_type = VAR_STRING;
5721 rettv->vval.v_string = (pat == NULL)
5722 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5723}
5724
5725/* for VIM_VERSION_ defines */
5726#include "version.h"
5727
5728/*
5729 * "has()" function
5730 */
5731 static void
5732f_has(typval_T *argvars, typval_T *rettv)
5733{
5734 int i;
5735 char_u *name;
5736 int n = FALSE;
5737 static char *(has_list[]) =
5738 {
5739#ifdef AMIGA
5740 "amiga",
5741# ifdef FEAT_ARP
5742 "arp",
5743# endif
5744#endif
5745#ifdef __BEOS__
5746 "beos",
5747#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005748#if defined(BSD) && !defined(MACOS_X)
5749 "bsd",
5750#endif
5751#ifdef hpux
5752 "hpux",
5753#endif
5754#ifdef __linux__
5755 "linux",
5756#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005757#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005758 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5759 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005760# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005761 "macunix", /* Mac OS X, with the darwin feature */
5762 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005763# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005764#endif
5765#ifdef __QNX__
5766 "qnx",
5767#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005768#ifdef SUN_SYSTEM
5769 "sun",
5770#else
5771 "moon",
5772#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773#ifdef UNIX
5774 "unix",
5775#endif
5776#ifdef VMS
5777 "vms",
5778#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005779#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005780 "win32",
5781#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005782#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 "win32unix",
5784#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005785#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786 "win64",
5787#endif
5788#ifdef EBCDIC
5789 "ebcdic",
5790#endif
5791#ifndef CASE_INSENSITIVE_FILENAME
5792 "fname_case",
5793#endif
5794#ifdef HAVE_ACL
5795 "acl",
5796#endif
5797#ifdef FEAT_ARABIC
5798 "arabic",
5799#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005800 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005801#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005802 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005803#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005804#ifdef FEAT_AUTOSERVERNAME
5805 "autoservername",
5806#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005807#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005809# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005810 "balloon_multiline",
5811# endif
5812#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005813#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005814 "balloon_eval_term",
5815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005816#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5817 "builtin_terms",
5818# ifdef ALL_BUILTIN_TCAPS
5819 "all_builtin_terms",
5820# endif
5821#endif
5822#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005823 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005824 || defined(FEAT_GUI_MOTIF))
5825 "browsefilter",
5826#endif
5827#ifdef FEAT_BYTEOFF
5828 "byte_offset",
5829#endif
5830#ifdef FEAT_JOB_CHANNEL
5831 "channel",
5832#endif
5833#ifdef FEAT_CINDENT
5834 "cindent",
5835#endif
5836#ifdef FEAT_CLIENTSERVER
5837 "clientserver",
5838#endif
5839#ifdef FEAT_CLIPBOARD
5840 "clipboard",
5841#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005843 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005844#ifdef FEAT_COMMENTS
5845 "comments",
5846#endif
5847#ifdef FEAT_CONCEAL
5848 "conceal",
5849#endif
5850#ifdef FEAT_CRYPT
5851 "cryptv",
5852 "crypt-blowfish",
5853 "crypt-blowfish2",
5854#endif
5855#ifdef FEAT_CSCOPE
5856 "cscope",
5857#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005859#ifdef CURSOR_SHAPE
5860 "cursorshape",
5861#endif
5862#ifdef DEBUG
5863 "debug",
5864#endif
5865#ifdef FEAT_CON_DIALOG
5866 "dialog_con",
5867#endif
5868#ifdef FEAT_GUI_DIALOG
5869 "dialog_gui",
5870#endif
5871#ifdef FEAT_DIFF
5872 "diff",
5873#endif
5874#ifdef FEAT_DIGRAPHS
5875 "digraphs",
5876#endif
5877#ifdef FEAT_DIRECTX
5878 "directx",
5879#endif
5880#ifdef FEAT_DND
5881 "dnd",
5882#endif
5883#ifdef FEAT_EMACS_TAGS
5884 "emacs_tags",
5885#endif
5886 "eval", /* always present, of course! */
5887 "ex_extra", /* graduated feature */
5888#ifdef FEAT_SEARCH_EXTRA
5889 "extra_search",
5890#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005891#ifdef FEAT_SEARCHPATH
5892 "file_in_path",
5893#endif
5894#ifdef FEAT_FILTERPIPE
5895 "filterpipe",
5896#endif
5897#ifdef FEAT_FIND_ID
5898 "find_in_path",
5899#endif
5900#ifdef FEAT_FLOAT
5901 "float",
5902#endif
5903#ifdef FEAT_FOLDING
5904 "folding",
5905#endif
5906#ifdef FEAT_FOOTER
5907 "footer",
5908#endif
5909#if !defined(USE_SYSTEM) && defined(UNIX)
5910 "fork",
5911#endif
5912#ifdef FEAT_GETTEXT
5913 "gettext",
5914#endif
5915#ifdef FEAT_GUI
5916 "gui",
5917#endif
5918#ifdef FEAT_GUI_ATHENA
5919# ifdef FEAT_GUI_NEXTAW
5920 "gui_neXtaw",
5921# else
5922 "gui_athena",
5923# endif
5924#endif
5925#ifdef FEAT_GUI_GTK
5926 "gui_gtk",
5927# ifdef USE_GTK3
5928 "gui_gtk3",
5929# else
5930 "gui_gtk2",
5931# endif
5932#endif
5933#ifdef FEAT_GUI_GNOME
5934 "gui_gnome",
5935#endif
5936#ifdef FEAT_GUI_MAC
5937 "gui_mac",
5938#endif
5939#ifdef FEAT_GUI_MOTIF
5940 "gui_motif",
5941#endif
5942#ifdef FEAT_GUI_PHOTON
5943 "gui_photon",
5944#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005945#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005946 "gui_win32",
5947#endif
5948#ifdef FEAT_HANGULIN
5949 "hangul_input",
5950#endif
5951#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5952 "iconv",
5953#endif
5954#ifdef FEAT_INS_EXPAND
5955 "insert_expand",
5956#endif
5957#ifdef FEAT_JOB_CHANNEL
5958 "job",
5959#endif
5960#ifdef FEAT_JUMPLIST
5961 "jumplist",
5962#endif
5963#ifdef FEAT_KEYMAP
5964 "keymap",
5965#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005966 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005967#ifdef FEAT_LANGMAP
5968 "langmap",
5969#endif
5970#ifdef FEAT_LIBCALL
5971 "libcall",
5972#endif
5973#ifdef FEAT_LINEBREAK
5974 "linebreak",
5975#endif
5976#ifdef FEAT_LISP
5977 "lispindent",
5978#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981#ifdef FEAT_LUA
5982# ifndef DYNAMIC_LUA
5983 "lua",
5984# endif
5985#endif
5986#ifdef FEAT_MENU
5987 "menu",
5988#endif
5989#ifdef FEAT_SESSION
5990 "mksession",
5991#endif
5992#ifdef FEAT_MODIFY_FNAME
5993 "modify_fname",
5994#endif
5995#ifdef FEAT_MOUSE
5996 "mouse",
5997#endif
5998#ifdef FEAT_MOUSESHAPE
5999 "mouseshape",
6000#endif
6001#if defined(UNIX) || defined(VMS)
6002# ifdef FEAT_MOUSE_DEC
6003 "mouse_dec",
6004# endif
6005# ifdef FEAT_MOUSE_GPM
6006 "mouse_gpm",
6007# endif
6008# ifdef FEAT_MOUSE_JSB
6009 "mouse_jsbterm",
6010# endif
6011# ifdef FEAT_MOUSE_NET
6012 "mouse_netterm",
6013# endif
6014# ifdef FEAT_MOUSE_PTERM
6015 "mouse_pterm",
6016# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006017# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 "mouse_sgr",
6019# endif
6020# ifdef FEAT_SYSMOUSE
6021 "mouse_sysmouse",
6022# endif
6023# ifdef FEAT_MOUSE_URXVT
6024 "mouse_urxvt",
6025# endif
6026# ifdef FEAT_MOUSE_XTERM
6027 "mouse_xterm",
6028# endif
6029#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031#ifdef FEAT_MBYTE_IME
6032 "multi_byte_ime",
6033#endif
6034#ifdef FEAT_MULTI_LANG
6035 "multi_lang",
6036#endif
6037#ifdef FEAT_MZSCHEME
6038#ifndef DYNAMIC_MZSCHEME
6039 "mzscheme",
6040#endif
6041#endif
6042#ifdef FEAT_NUM64
6043 "num64",
6044#endif
6045#ifdef FEAT_OLE
6046 "ole",
6047#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006048#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006049 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006050#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051#ifdef FEAT_PATH_EXTRA
6052 "path_extra",
6053#endif
6054#ifdef FEAT_PERL
6055#ifndef DYNAMIC_PERL
6056 "perl",
6057#endif
6058#endif
6059#ifdef FEAT_PERSISTENT_UNDO
6060 "persistent_undo",
6061#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006062#if defined(FEAT_PYTHON)
6063 "python_compiled",
6064# if defined(DYNAMIC_PYTHON)
6065 "python_dynamic",
6066# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006068 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006069# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006071#if defined(FEAT_PYTHON3)
6072 "python3_compiled",
6073# if defined(DYNAMIC_PYTHON3)
6074 "python3_dynamic",
6075# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006077 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006078# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006079#endif
6080#ifdef FEAT_POSTSCRIPT
6081 "postscript",
6082#endif
6083#ifdef FEAT_PRINTER
6084 "printer",
6085#endif
6086#ifdef FEAT_PROFILE
6087 "profile",
6088#endif
6089#ifdef FEAT_RELTIME
6090 "reltime",
6091#endif
6092#ifdef FEAT_QUICKFIX
6093 "quickfix",
6094#endif
6095#ifdef FEAT_RIGHTLEFT
6096 "rightleft",
6097#endif
6098#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6099 "ruby",
6100#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006101 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102#ifdef FEAT_CMDL_INFO
6103 "showcmd",
6104 "cmdline_info",
6105#endif
6106#ifdef FEAT_SIGNS
6107 "signs",
6108#endif
6109#ifdef FEAT_SMARTINDENT
6110 "smartindent",
6111#endif
6112#ifdef STARTUPTIME
6113 "startuptime",
6114#endif
6115#ifdef FEAT_STL_OPT
6116 "statusline",
6117#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006118#ifdef FEAT_NETBEANS_INTG
6119 "netbeans_intg",
6120#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006121#ifdef FEAT_SOUND
6122 "sound",
6123#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006124#ifdef FEAT_SPELL
6125 "spell",
6126#endif
6127#ifdef FEAT_SYN_HL
6128 "syntax",
6129#endif
6130#if defined(USE_SYSTEM) || !defined(UNIX)
6131 "system",
6132#endif
6133#ifdef FEAT_TAG_BINS
6134 "tag_binary",
6135#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006136#ifdef FEAT_TCL
6137# ifndef DYNAMIC_TCL
6138 "tcl",
6139# endif
6140#endif
6141#ifdef FEAT_TERMGUICOLORS
6142 "termguicolors",
6143#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006144#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006145 "terminal",
6146#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147#ifdef TERMINFO
6148 "terminfo",
6149#endif
6150#ifdef FEAT_TERMRESPONSE
6151 "termresponse",
6152#endif
6153#ifdef FEAT_TEXTOBJ
6154 "textobjects",
6155#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006156#ifdef FEAT_TEXT_PROP
6157 "textprop",
6158#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006159#ifdef HAVE_TGETENT
6160 "tgetent",
6161#endif
6162#ifdef FEAT_TIMERS
6163 "timers",
6164#endif
6165#ifdef FEAT_TITLE
6166 "title",
6167#endif
6168#ifdef FEAT_TOOLBAR
6169 "toolbar",
6170#endif
6171#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6172 "unnamedplus",
6173#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174 "user-commands", /* was accidentally included in 5.4 */
6175 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006176#ifdef FEAT_VARTABS
6177 "vartabs",
6178#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006179 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180#ifdef FEAT_VIMINFO
6181 "viminfo",
6182#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006183 "vimscript-1",
6184 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006185 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006190#ifdef FEAT_VTP
6191 "vtp",
6192#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193#ifdef FEAT_WILDIGN
6194 "wildignore",
6195#endif
6196#ifdef FEAT_WILDMENU
6197 "wildmenu",
6198#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006199 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006200#ifdef FEAT_WAK
6201 "winaltkeys",
6202#endif
6203#ifdef FEAT_WRITEBACKUP
6204 "writebackup",
6205#endif
6206#ifdef FEAT_XIM
6207 "xim",
6208#endif
6209#ifdef FEAT_XFONTSET
6210 "xfontset",
6211#endif
6212#ifdef FEAT_XPM_W32
6213 "xpm",
6214 "xpm_w32", /* for backward compatibility */
6215#else
6216# if defined(HAVE_XPM)
6217 "xpm",
6218# endif
6219#endif
6220#ifdef USE_XSMP
6221 "xsmp",
6222#endif
6223#ifdef USE_XSMP_INTERACT
6224 "xsmp_interact",
6225#endif
6226#ifdef FEAT_XCLIPBOARD
6227 "xterm_clipboard",
6228#endif
6229#ifdef FEAT_XTERM_SAVE
6230 "xterm_save",
6231#endif
6232#if defined(UNIX) && defined(FEAT_X11)
6233 "X11",
6234#endif
6235 NULL
6236 };
6237
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006238 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 for (i = 0; has_list[i] != NULL; ++i)
6240 if (STRICMP(name, has_list[i]) == 0)
6241 {
6242 n = TRUE;
6243 break;
6244 }
6245
6246 if (n == FALSE)
6247 {
6248 if (STRNICMP(name, "patch", 5) == 0)
6249 {
6250 if (name[5] == '-'
6251 && STRLEN(name) >= 11
6252 && vim_isdigit(name[6])
6253 && vim_isdigit(name[8])
6254 && vim_isdigit(name[10]))
6255 {
6256 int major = atoi((char *)name + 6);
6257 int minor = atoi((char *)name + 8);
6258
6259 /* Expect "patch-9.9.01234". */
6260 n = (major < VIM_VERSION_MAJOR
6261 || (major == VIM_VERSION_MAJOR
6262 && (minor < VIM_VERSION_MINOR
6263 || (minor == VIM_VERSION_MINOR
6264 && has_patch(atoi((char *)name + 10))))));
6265 }
6266 else
6267 n = has_patch(atoi((char *)name + 5));
6268 }
6269 else if (STRICMP(name, "vim_starting") == 0)
6270 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006271 else if (STRICMP(name, "ttyin") == 0)
6272 n = mch_input_isatty();
6273 else if (STRICMP(name, "ttyout") == 0)
6274 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275 else if (STRICMP(name, "multi_byte_encoding") == 0)
6276 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006277#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278 else if (STRICMP(name, "balloon_multiline") == 0)
6279 n = multiline_balloon_available();
6280#endif
6281#ifdef DYNAMIC_TCL
6282 else if (STRICMP(name, "tcl") == 0)
6283 n = tcl_enabled(FALSE);
6284#endif
6285#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6286 else if (STRICMP(name, "iconv") == 0)
6287 n = iconv_enabled(FALSE);
6288#endif
6289#ifdef DYNAMIC_LUA
6290 else if (STRICMP(name, "lua") == 0)
6291 n = lua_enabled(FALSE);
6292#endif
6293#ifdef DYNAMIC_MZSCHEME
6294 else if (STRICMP(name, "mzscheme") == 0)
6295 n = mzscheme_enabled(FALSE);
6296#endif
6297#ifdef DYNAMIC_RUBY
6298 else if (STRICMP(name, "ruby") == 0)
6299 n = ruby_enabled(FALSE);
6300#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006301#ifdef DYNAMIC_PYTHON
6302 else if (STRICMP(name, "python") == 0)
6303 n = python_enabled(FALSE);
6304#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305#ifdef DYNAMIC_PYTHON3
6306 else if (STRICMP(name, "python3") == 0)
6307 n = python3_enabled(FALSE);
6308#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006309#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6310 else if (STRICMP(name, "pythonx") == 0)
6311 {
6312# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6313 if (p_pyx == 0)
6314 n = python3_enabled(FALSE) || python_enabled(FALSE);
6315 else if (p_pyx == 3)
6316 n = python3_enabled(FALSE);
6317 else if (p_pyx == 2)
6318 n = python_enabled(FALSE);
6319# elif defined(DYNAMIC_PYTHON)
6320 n = python_enabled(FALSE);
6321# elif defined(DYNAMIC_PYTHON3)
6322 n = python3_enabled(FALSE);
6323# endif
6324 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325#endif
6326#ifdef DYNAMIC_PERL
6327 else if (STRICMP(name, "perl") == 0)
6328 n = perl_enabled(FALSE);
6329#endif
6330#ifdef FEAT_GUI
6331 else if (STRICMP(name, "gui_running") == 0)
6332 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333# ifdef FEAT_BROWSE
6334 else if (STRICMP(name, "browse") == 0)
6335 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6336# endif
6337#endif
6338#ifdef FEAT_SYN_HL
6339 else if (STRICMP(name, "syntax_items") == 0)
6340 n = syntax_present(curwin);
6341#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006342#ifdef FEAT_VTP
6343 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006344 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345#endif
6346#ifdef FEAT_NETBEANS_INTG
6347 else if (STRICMP(name, "netbeans_enabled") == 0)
6348 n = netbeans_active();
6349#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006350#ifdef FEAT_MOUSE_GPM
6351 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6352 n = gpm_enabled();
6353#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006354#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006355 else if (STRICMP(name, "terminal") == 0)
6356 n = terminal_enabled();
6357#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006358#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006359 else if (STRICMP(name, "conpty") == 0)
6360 n = use_conpty();
6361#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006362#ifdef FEAT_CLIPBOARD
6363 else if (STRICMP(name, "clipboard_working") == 0)
6364 n = clip_star.available;
6365#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366 }
6367
6368 rettv->vval.v_number = n;
6369}
6370
6371/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 * "haslocaldir()" function
6373 */
6374 static void
6375f_haslocaldir(typval_T *argvars, typval_T *rettv)
6376{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006377 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006378 win_T *wp = NULL;
6379
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006380 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6381
6382 // Check for window-local and tab-local directories
6383 if (wp != NULL && wp->w_localdir != NULL)
6384 rettv->vval.v_number = 1;
6385 else if (tp != NULL && tp->tp_localdir != NULL)
6386 rettv->vval.v_number = 2;
6387 else
6388 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389}
6390
6391/*
6392 * "hasmapto()" function
6393 */
6394 static void
6395f_hasmapto(typval_T *argvars, typval_T *rettv)
6396{
6397 char_u *name;
6398 char_u *mode;
6399 char_u buf[NUMBUFLEN];
6400 int abbr = FALSE;
6401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006402 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403 if (argvars[1].v_type == VAR_UNKNOWN)
6404 mode = (char_u *)"nvo";
6405 else
6406 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006407 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006409 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 }
6411
6412 if (map_to_exists(name, mode, abbr))
6413 rettv->vval.v_number = TRUE;
6414 else
6415 rettv->vval.v_number = FALSE;
6416}
6417
6418/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006419 * "highlightID(name)" function
6420 */
6421 static void
6422f_hlID(typval_T *argvars, typval_T *rettv)
6423{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006424 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425}
6426
6427/*
6428 * "highlight_exists()" function
6429 */
6430 static void
6431f_hlexists(typval_T *argvars, typval_T *rettv)
6432{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006433 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006434}
6435
6436/*
6437 * "hostname()" function
6438 */
6439 static void
6440f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6441{
6442 char_u hostname[256];
6443
6444 mch_get_host_name(hostname, 256);
6445 rettv->v_type = VAR_STRING;
6446 rettv->vval.v_string = vim_strsave(hostname);
6447}
6448
6449/*
6450 * iconv() function
6451 */
6452 static void
6453f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6454{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006455 char_u buf1[NUMBUFLEN];
6456 char_u buf2[NUMBUFLEN];
6457 char_u *from, *to, *str;
6458 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459
6460 rettv->v_type = VAR_STRING;
6461 rettv->vval.v_string = NULL;
6462
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006463 str = tv_get_string(&argvars[0]);
6464 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6465 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 vimconv.vc_type = CONV_NONE;
6467 convert_setup(&vimconv, from, to);
6468
6469 /* If the encodings are equal, no conversion needed. */
6470 if (vimconv.vc_type == CONV_NONE)
6471 rettv->vval.v_string = vim_strsave(str);
6472 else
6473 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6474
6475 convert_setup(&vimconv, NULL, NULL);
6476 vim_free(from);
6477 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478}
6479
6480/*
6481 * "indent()" function
6482 */
6483 static void
6484f_indent(typval_T *argvars, typval_T *rettv)
6485{
6486 linenr_T lnum;
6487
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006488 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6490 rettv->vval.v_number = get_indent_lnum(lnum);
6491 else
6492 rettv->vval.v_number = -1;
6493}
6494
6495/*
6496 * "index()" function
6497 */
6498 static void
6499f_index(typval_T *argvars, typval_T *rettv)
6500{
6501 list_T *l;
6502 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006503 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 long idx = 0;
6505 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006506 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507
6508 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006509 if (argvars[0].v_type == VAR_BLOB)
6510 {
6511 typval_T tv;
6512 int start = 0;
6513
6514 if (argvars[2].v_type != VAR_UNKNOWN)
6515 {
6516 start = tv_get_number_chk(&argvars[2], &error);
6517 if (error)
6518 return;
6519 }
6520 b = argvars[0].vval.v_blob;
6521 if (b == NULL)
6522 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006523 if (start < 0)
6524 {
6525 start = blob_len(b) + start;
6526 if (start < 0)
6527 start = 0;
6528 }
6529
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006530 for (idx = start; idx < blob_len(b); ++idx)
6531 {
6532 tv.v_type = VAR_NUMBER;
6533 tv.vval.v_number = blob_get(b, idx);
6534 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6535 {
6536 rettv->vval.v_number = idx;
6537 return;
6538 }
6539 }
6540 return;
6541 }
6542 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006544 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006545 return;
6546 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006547
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548 l = argvars[0].vval.v_list;
6549 if (l != NULL)
6550 {
6551 item = l->lv_first;
6552 if (argvars[2].v_type != VAR_UNKNOWN)
6553 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554 /* Start at specified item. Use the cached index that list_find()
6555 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006556 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557 idx = l->lv_idx;
6558 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006559 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 if (error)
6561 item = NULL;
6562 }
6563
6564 for ( ; item != NULL; item = item->li_next, ++idx)
6565 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6566 {
6567 rettv->vval.v_number = idx;
6568 break;
6569 }
6570 }
6571}
6572
6573static int inputsecret_flag = 0;
6574
6575/*
6576 * "input()" function
6577 * Also handles inputsecret() when inputsecret is set.
6578 */
6579 static void
6580f_input(typval_T *argvars, typval_T *rettv)
6581{
6582 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6583}
6584
6585/*
6586 * "inputdialog()" function
6587 */
6588 static void
6589f_inputdialog(typval_T *argvars, typval_T *rettv)
6590{
6591#if defined(FEAT_GUI_TEXTDIALOG)
6592 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6593 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6594 {
6595 char_u *message;
6596 char_u buf[NUMBUFLEN];
6597 char_u *defstr = (char_u *)"";
6598
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006599 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006601 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6603 else
6604 IObuff[0] = NUL;
6605 if (message != NULL && defstr != NULL
6606 && do_dialog(VIM_QUESTION, NULL, message,
6607 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6608 rettv->vval.v_string = vim_strsave(IObuff);
6609 else
6610 {
6611 if (message != NULL && defstr != NULL
6612 && argvars[1].v_type != VAR_UNKNOWN
6613 && argvars[2].v_type != VAR_UNKNOWN)
6614 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006615 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 else
6617 rettv->vval.v_string = NULL;
6618 }
6619 rettv->v_type = VAR_STRING;
6620 }
6621 else
6622#endif
6623 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6624}
6625
6626/*
6627 * "inputlist()" function
6628 */
6629 static void
6630f_inputlist(typval_T *argvars, typval_T *rettv)
6631{
6632 listitem_T *li;
6633 int selected;
6634 int mouse_used;
6635
6636#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006637 /* While starting up, there is no place to enter text. When running tests
6638 * with --not-a-term we assume feedkeys() will be used. */
6639 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 return;
6641#endif
6642 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6643 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006644 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 return;
6646 }
6647
6648 msg_start();
6649 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6650 lines_left = Rows; /* avoid more prompt */
6651 msg_scroll = TRUE;
6652 msg_clr_eos();
6653
6654 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6655 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006656 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 msg_putchar('\n');
6658 }
6659
6660 /* Ask for choice. */
6661 selected = prompt_for_number(&mouse_used);
6662 if (mouse_used)
6663 selected -= lines_left;
6664
6665 rettv->vval.v_number = selected;
6666}
6667
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006668static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6669
6670/*
6671 * "inputrestore()" function
6672 */
6673 static void
6674f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6675{
6676 if (ga_userinput.ga_len > 0)
6677 {
6678 --ga_userinput.ga_len;
6679 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6680 + ga_userinput.ga_len);
6681 /* default return is zero == OK */
6682 }
6683 else if (p_verbose > 1)
6684 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006685 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 rettv->vval.v_number = 1; /* Failed */
6687 }
6688}
6689
6690/*
6691 * "inputsave()" function
6692 */
6693 static void
6694f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6695{
6696 /* Add an entry to the stack of typeahead storage. */
6697 if (ga_grow(&ga_userinput, 1) == OK)
6698 {
6699 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6700 + ga_userinput.ga_len);
6701 ++ga_userinput.ga_len;
6702 /* default return is zero == OK */
6703 }
6704 else
6705 rettv->vval.v_number = 1; /* Failed */
6706}
6707
6708/*
6709 * "inputsecret()" function
6710 */
6711 static void
6712f_inputsecret(typval_T *argvars, typval_T *rettv)
6713{
6714 ++cmdline_star;
6715 ++inputsecret_flag;
6716 f_input(argvars, rettv);
6717 --cmdline_star;
6718 --inputsecret_flag;
6719}
6720
6721/*
6722 * "insert()" function
6723 */
6724 static void
6725f_insert(typval_T *argvars, typval_T *rettv)
6726{
6727 long before = 0;
6728 listitem_T *item;
6729 list_T *l;
6730 int error = FALSE;
6731
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006732 if (argvars[0].v_type == VAR_BLOB)
6733 {
6734 int val, len;
6735 char_u *p;
6736
6737 len = blob_len(argvars[0].vval.v_blob);
6738 if (argvars[2].v_type != VAR_UNKNOWN)
6739 {
6740 before = (long)tv_get_number_chk(&argvars[2], &error);
6741 if (error)
6742 return; // type error; errmsg already given
6743 if (before < 0 || before > len)
6744 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006745 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006746 return;
6747 }
6748 }
6749 val = tv_get_number_chk(&argvars[1], &error);
6750 if (error)
6751 return;
6752 if (val < 0 || val > 255)
6753 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006754 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006755 return;
6756 }
6757
6758 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6759 return;
6760 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6761 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6762 *(p + before) = val;
6763 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6764
6765 copy_tv(&argvars[0], rettv);
6766 }
6767 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006768 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006769 else if ((l = argvars[0].vval.v_list) != NULL
6770 && !var_check_lock(l->lv_lock,
6771 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006772 {
6773 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006774 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 if (error)
6776 return; /* type error; errmsg already given */
6777
6778 if (before == l->lv_len)
6779 item = NULL;
6780 else
6781 {
6782 item = list_find(l, before);
6783 if (item == NULL)
6784 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006785 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006786 l = NULL;
6787 }
6788 }
6789 if (l != NULL)
6790 {
6791 list_insert_tv(l, &argvars[1], item);
6792 copy_tv(&argvars[0], rettv);
6793 }
6794 }
6795}
6796
6797/*
6798 * "invert(expr)" function
6799 */
6800 static void
6801f_invert(typval_T *argvars, typval_T *rettv)
6802{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006803 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804}
6805
6806/*
6807 * "isdirectory()" function
6808 */
6809 static void
6810f_isdirectory(typval_T *argvars, typval_T *rettv)
6811{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813}
6814
6815/*
6816 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6817 * or it refers to a List or Dictionary that is locked.
6818 */
6819 static int
6820tv_islocked(typval_T *tv)
6821{
6822 return (tv->v_lock & VAR_LOCKED)
6823 || (tv->v_type == VAR_LIST
6824 && tv->vval.v_list != NULL
6825 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6826 || (tv->v_type == VAR_DICT
6827 && tv->vval.v_dict != NULL
6828 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6829}
6830
6831/*
6832 * "islocked()" function
6833 */
6834 static void
6835f_islocked(typval_T *argvars, typval_T *rettv)
6836{
6837 lval_T lv;
6838 char_u *end;
6839 dictitem_T *di;
6840
6841 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006842 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006843 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006844 if (end != NULL && lv.ll_name != NULL)
6845 {
6846 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006847 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848 else
6849 {
6850 if (lv.ll_tv == NULL)
6851 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006852 di = find_var(lv.ll_name, NULL, TRUE);
6853 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006854 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006855 /* Consider a variable locked when:
6856 * 1. the variable itself is locked
6857 * 2. the value of the variable is locked.
6858 * 3. the List or Dict value is locked.
6859 */
6860 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6861 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 }
6863 }
6864 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006865 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006867 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 else if (lv.ll_list != NULL)
6869 /* List item. */
6870 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6871 else
6872 /* Dictionary item. */
6873 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6874 }
6875 }
6876
6877 clear_lval(&lv);
6878}
6879
6880#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6881/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006882 * "isinf()" function
6883 */
6884 static void
6885f_isinf(typval_T *argvars, typval_T *rettv)
6886{
6887 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6888 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6889}
6890
6891/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 * "isnan()" function
6893 */
6894 static void
6895f_isnan(typval_T *argvars, typval_T *rettv)
6896{
6897 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6898 && isnan(argvars[0].vval.v_float);
6899}
6900#endif
6901
6902/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006903 * "last_buffer_nr()" function.
6904 */
6905 static void
6906f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6907{
6908 int n = 0;
6909 buf_T *buf;
6910
Bram Moolenaar29323592016-07-24 22:04:11 +02006911 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006912 if (n < buf->b_fnum)
6913 n = buf->b_fnum;
6914
6915 rettv->vval.v_number = n;
6916}
6917
6918/*
6919 * "len()" function
6920 */
6921 static void
6922f_len(typval_T *argvars, typval_T *rettv)
6923{
6924 switch (argvars[0].v_type)
6925 {
6926 case VAR_STRING:
6927 case VAR_NUMBER:
6928 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006929 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006931 case VAR_BLOB:
6932 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6933 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 case VAR_LIST:
6935 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6936 break;
6937 case VAR_DICT:
6938 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6939 break;
6940 case VAR_UNKNOWN:
6941 case VAR_SPECIAL:
6942 case VAR_FLOAT:
6943 case VAR_FUNC:
6944 case VAR_PARTIAL:
6945 case VAR_JOB:
6946 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006947 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 break;
6949 }
6950}
6951
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006953libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954{
6955#ifdef FEAT_LIBCALL
6956 char_u *string_in;
6957 char_u **string_result;
6958 int nr_result;
6959#endif
6960
6961 rettv->v_type = type;
6962 if (type != VAR_NUMBER)
6963 rettv->vval.v_string = NULL;
6964
6965 if (check_restricted() || check_secure())
6966 return;
6967
6968#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006969 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6971 {
6972 string_in = NULL;
6973 if (argvars[2].v_type == VAR_STRING)
6974 string_in = argvars[2].vval.v_string;
6975 if (type == VAR_NUMBER)
6976 string_result = NULL;
6977 else
6978 string_result = &rettv->vval.v_string;
6979 if (mch_libcall(argvars[0].vval.v_string,
6980 argvars[1].vval.v_string,
6981 string_in,
6982 argvars[2].vval.v_number,
6983 string_result,
6984 &nr_result) == OK
6985 && type == VAR_NUMBER)
6986 rettv->vval.v_number = nr_result;
6987 }
6988#endif
6989}
6990
6991/*
6992 * "libcall()" function
6993 */
6994 static void
6995f_libcall(typval_T *argvars, typval_T *rettv)
6996{
6997 libcall_common(argvars, rettv, VAR_STRING);
6998}
6999
7000/*
7001 * "libcallnr()" function
7002 */
7003 static void
7004f_libcallnr(typval_T *argvars, typval_T *rettv)
7005{
7006 libcall_common(argvars, rettv, VAR_NUMBER);
7007}
7008
7009/*
7010 * "line(string)" function
7011 */
7012 static void
7013f_line(typval_T *argvars, typval_T *rettv)
7014{
7015 linenr_T lnum = 0;
7016 pos_T *fp;
7017 int fnum;
7018
7019 fp = var2fpos(&argvars[0], TRUE, &fnum);
7020 if (fp != NULL)
7021 lnum = fp->lnum;
7022 rettv->vval.v_number = lnum;
7023}
7024
7025/*
7026 * "line2byte(lnum)" function
7027 */
7028 static void
7029f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7030{
7031#ifndef FEAT_BYTEOFF
7032 rettv->vval.v_number = -1;
7033#else
7034 linenr_T lnum;
7035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007036 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7038 rettv->vval.v_number = -1;
7039 else
7040 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7041 if (rettv->vval.v_number >= 0)
7042 ++rettv->vval.v_number;
7043#endif
7044}
7045
7046/*
7047 * "lispindent(lnum)" function
7048 */
7049 static void
7050f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7051{
7052#ifdef FEAT_LISP
7053 pos_T pos;
7054 linenr_T lnum;
7055
7056 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007057 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7059 {
7060 curwin->w_cursor.lnum = lnum;
7061 rettv->vval.v_number = get_lisp_indent();
7062 curwin->w_cursor = pos;
7063 }
7064 else
7065#endif
7066 rettv->vval.v_number = -1;
7067}
7068
7069/*
7070 * "localtime()" function
7071 */
7072 static void
7073f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7074{
7075 rettv->vval.v_number = (varnumber_T)time(NULL);
7076}
7077
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078#ifdef FEAT_FLOAT
7079/*
7080 * "log()" function
7081 */
7082 static void
7083f_log(typval_T *argvars, typval_T *rettv)
7084{
7085 float_T f = 0.0;
7086
7087 rettv->v_type = VAR_FLOAT;
7088 if (get_float_arg(argvars, &f) == OK)
7089 rettv->vval.v_float = log(f);
7090 else
7091 rettv->vval.v_float = 0.0;
7092}
7093
7094/*
7095 * "log10()" function
7096 */
7097 static void
7098f_log10(typval_T *argvars, typval_T *rettv)
7099{
7100 float_T f = 0.0;
7101
7102 rettv->v_type = VAR_FLOAT;
7103 if (get_float_arg(argvars, &f) == OK)
7104 rettv->vval.v_float = log10(f);
7105 else
7106 rettv->vval.v_float = 0.0;
7107}
7108#endif
7109
7110#ifdef FEAT_LUA
7111/*
7112 * "luaeval()" function
7113 */
7114 static void
7115f_luaeval(typval_T *argvars, typval_T *rettv)
7116{
7117 char_u *str;
7118 char_u buf[NUMBUFLEN];
7119
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007120 if (check_restricted() || check_secure())
7121 return;
7122
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007123 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 do_luaeval(str, argvars + 1, rettv);
7125}
7126#endif
7127
7128/*
7129 * "map()" function
7130 */
7131 static void
7132f_map(typval_T *argvars, typval_T *rettv)
7133{
7134 filter_map(argvars, rettv, TRUE);
7135}
7136
7137/*
7138 * "maparg()" function
7139 */
7140 static void
7141f_maparg(typval_T *argvars, typval_T *rettv)
7142{
7143 get_maparg(argvars, rettv, TRUE);
7144}
7145
7146/*
7147 * "mapcheck()" function
7148 */
7149 static void
7150f_mapcheck(typval_T *argvars, typval_T *rettv)
7151{
7152 get_maparg(argvars, rettv, FALSE);
7153}
7154
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007155typedef enum
7156{
7157 MATCH_END, /* matchend() */
7158 MATCH_MATCH, /* match() */
7159 MATCH_STR, /* matchstr() */
7160 MATCH_LIST, /* matchlist() */
7161 MATCH_POS /* matchstrpos() */
7162} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007163
7164 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007165find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166{
7167 char_u *str = NULL;
7168 long len = 0;
7169 char_u *expr = NULL;
7170 char_u *pat;
7171 regmatch_T regmatch;
7172 char_u patbuf[NUMBUFLEN];
7173 char_u strbuf[NUMBUFLEN];
7174 char_u *save_cpo;
7175 long start = 0;
7176 long nth = 1;
7177 colnr_T startcol = 0;
7178 int match = 0;
7179 list_T *l = NULL;
7180 listitem_T *li = NULL;
7181 long idx = 0;
7182 char_u *tofree = NULL;
7183
7184 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7185 save_cpo = p_cpo;
7186 p_cpo = (char_u *)"";
7187
7188 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007189 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007190 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007191 /* type MATCH_LIST: return empty list when there are no matches.
7192 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 if (rettv_list_alloc(rettv) == FAIL)
7194 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007195 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 && (list_append_string(rettv->vval.v_list,
7197 (char_u *)"", 0) == FAIL
7198 || list_append_number(rettv->vval.v_list,
7199 (varnumber_T)-1) == FAIL
7200 || list_append_number(rettv->vval.v_list,
7201 (varnumber_T)-1) == FAIL
7202 || list_append_number(rettv->vval.v_list,
7203 (varnumber_T)-1) == FAIL))
7204 {
7205 list_free(rettv->vval.v_list);
7206 rettv->vval.v_list = NULL;
7207 goto theend;
7208 }
7209 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007210 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007211 {
7212 rettv->v_type = VAR_STRING;
7213 rettv->vval.v_string = NULL;
7214 }
7215
7216 if (argvars[0].v_type == VAR_LIST)
7217 {
7218 if ((l = argvars[0].vval.v_list) == NULL)
7219 goto theend;
7220 li = l->lv_first;
7221 }
7222 else
7223 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007224 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007225 len = (long)STRLEN(str);
7226 }
7227
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007228 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 if (pat == NULL)
7230 goto theend;
7231
7232 if (argvars[2].v_type != VAR_UNKNOWN)
7233 {
7234 int error = FALSE;
7235
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007236 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237 if (error)
7238 goto theend;
7239 if (l != NULL)
7240 {
7241 li = list_find(l, start);
7242 if (li == NULL)
7243 goto theend;
7244 idx = l->lv_idx; /* use the cached index */
7245 }
7246 else
7247 {
7248 if (start < 0)
7249 start = 0;
7250 if (start > len)
7251 goto theend;
7252 /* When "count" argument is there ignore matches before "start",
7253 * otherwise skip part of the string. Differs when pattern is "^"
7254 * or "\<". */
7255 if (argvars[3].v_type != VAR_UNKNOWN)
7256 startcol = start;
7257 else
7258 {
7259 str += start;
7260 len -= start;
7261 }
7262 }
7263
7264 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007265 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 if (error)
7267 goto theend;
7268 }
7269
7270 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7271 if (regmatch.regprog != NULL)
7272 {
7273 regmatch.rm_ic = p_ic;
7274
7275 for (;;)
7276 {
7277 if (l != NULL)
7278 {
7279 if (li == NULL)
7280 {
7281 match = FALSE;
7282 break;
7283 }
7284 vim_free(tofree);
7285 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7286 if (str == NULL)
7287 break;
7288 }
7289
7290 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7291
7292 if (match && --nth <= 0)
7293 break;
7294 if (l == NULL && !match)
7295 break;
7296
7297 /* Advance to just after the match. */
7298 if (l != NULL)
7299 {
7300 li = li->li_next;
7301 ++idx;
7302 }
7303 else
7304 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305 startcol = (colnr_T)(regmatch.startp[0]
7306 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007307 if (startcol > (colnr_T)len
7308 || str + startcol <= regmatch.startp[0])
7309 {
7310 match = FALSE;
7311 break;
7312 }
7313 }
7314 }
7315
7316 if (match)
7317 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007318 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 {
7320 listitem_T *li1 = rettv->vval.v_list->lv_first;
7321 listitem_T *li2 = li1->li_next;
7322 listitem_T *li3 = li2->li_next;
7323 listitem_T *li4 = li3->li_next;
7324
7325 vim_free(li1->li_tv.vval.v_string);
7326 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7327 (int)(regmatch.endp[0] - regmatch.startp[0]));
7328 li3->li_tv.vval.v_number =
7329 (varnumber_T)(regmatch.startp[0] - expr);
7330 li4->li_tv.vval.v_number =
7331 (varnumber_T)(regmatch.endp[0] - expr);
7332 if (l != NULL)
7333 li2->li_tv.vval.v_number = (varnumber_T)idx;
7334 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007335 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 {
7337 int i;
7338
7339 /* return list with matched string and submatches */
7340 for (i = 0; i < NSUBEXP; ++i)
7341 {
7342 if (regmatch.endp[i] == NULL)
7343 {
7344 if (list_append_string(rettv->vval.v_list,
7345 (char_u *)"", 0) == FAIL)
7346 break;
7347 }
7348 else if (list_append_string(rettv->vval.v_list,
7349 regmatch.startp[i],
7350 (int)(regmatch.endp[i] - regmatch.startp[i]))
7351 == FAIL)
7352 break;
7353 }
7354 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007355 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 {
7357 /* return matched string */
7358 if (l != NULL)
7359 copy_tv(&li->li_tv, rettv);
7360 else
7361 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7362 (int)(regmatch.endp[0] - regmatch.startp[0]));
7363 }
7364 else if (l != NULL)
7365 rettv->vval.v_number = idx;
7366 else
7367 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007368 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369 rettv->vval.v_number =
7370 (varnumber_T)(regmatch.startp[0] - str);
7371 else
7372 rettv->vval.v_number =
7373 (varnumber_T)(regmatch.endp[0] - str);
7374 rettv->vval.v_number += (varnumber_T)(str - expr);
7375 }
7376 }
7377 vim_regfree(regmatch.regprog);
7378 }
7379
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007380theend:
7381 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 /* matchstrpos() without a list: drop the second item. */
7383 listitem_remove(rettv->vval.v_list,
7384 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385 vim_free(tofree);
7386 p_cpo = save_cpo;
7387}
7388
7389/*
7390 * "match()" function
7391 */
7392 static void
7393f_match(typval_T *argvars, typval_T *rettv)
7394{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007395 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396}
7397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398/*
7399 * "matchend()" function
7400 */
7401 static void
7402f_matchend(typval_T *argvars, typval_T *rettv)
7403{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007404 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405}
7406
7407/*
7408 * "matchlist()" function
7409 */
7410 static void
7411f_matchlist(typval_T *argvars, typval_T *rettv)
7412{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007413 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007414}
7415
7416/*
7417 * "matchstr()" function
7418 */
7419 static void
7420f_matchstr(typval_T *argvars, typval_T *rettv)
7421{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007422 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423}
7424
7425/*
7426 * "matchstrpos()" function
7427 */
7428 static void
7429f_matchstrpos(typval_T *argvars, typval_T *rettv)
7430{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007431 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432}
7433
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 static void
7435max_min(typval_T *argvars, typval_T *rettv, int domax)
7436{
7437 varnumber_T n = 0;
7438 varnumber_T i;
7439 int error = FALSE;
7440
7441 if (argvars[0].v_type == VAR_LIST)
7442 {
7443 list_T *l;
7444 listitem_T *li;
7445
7446 l = argvars[0].vval.v_list;
7447 if (l != NULL)
7448 {
7449 li = l->lv_first;
7450 if (li != NULL)
7451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007452 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 for (;;)
7454 {
7455 li = li->li_next;
7456 if (li == NULL)
7457 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007458 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459 if (domax ? i > n : i < n)
7460 n = i;
7461 }
7462 }
7463 }
7464 }
7465 else if (argvars[0].v_type == VAR_DICT)
7466 {
7467 dict_T *d;
7468 int first = TRUE;
7469 hashitem_T *hi;
7470 int todo;
7471
7472 d = argvars[0].vval.v_dict;
7473 if (d != NULL)
7474 {
7475 todo = (int)d->dv_hashtab.ht_used;
7476 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7477 {
7478 if (!HASHITEM_EMPTY(hi))
7479 {
7480 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007481 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007482 if (first)
7483 {
7484 n = i;
7485 first = FALSE;
7486 }
7487 else if (domax ? i > n : i < n)
7488 n = i;
7489 }
7490 }
7491 }
7492 }
7493 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007494 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 rettv->vval.v_number = error ? 0 : n;
7496}
7497
7498/*
7499 * "max()" function
7500 */
7501 static void
7502f_max(typval_T *argvars, typval_T *rettv)
7503{
7504 max_min(argvars, rettv, TRUE);
7505}
7506
7507/*
7508 * "min()" function
7509 */
7510 static void
7511f_min(typval_T *argvars, typval_T *rettv)
7512{
7513 max_min(argvars, rettv, FALSE);
7514}
7515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516/*
7517 * Create the directory in which "dir" is located, and higher levels when
7518 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007519 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007520 */
7521 static int
7522mkdir_recurse(char_u *dir, int prot)
7523{
7524 char_u *p;
7525 char_u *updir;
7526 int r = FAIL;
7527
7528 /* Get end of directory name in "dir".
7529 * We're done when it's "/" or "c:/". */
7530 p = gettail_sep(dir);
7531 if (p <= get_past_head(dir))
7532 return OK;
7533
7534 /* If the directory exists we're done. Otherwise: create it.*/
7535 updir = vim_strnsave(dir, (int)(p - dir));
7536 if (updir == NULL)
7537 return FAIL;
7538 if (mch_isdir(updir))
7539 r = OK;
7540 else if (mkdir_recurse(updir, prot) == OK)
7541 r = vim_mkdir_emsg(updir, prot);
7542 vim_free(updir);
7543 return r;
7544}
7545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546/*
7547 * "mkdir()" function
7548 */
7549 static void
7550f_mkdir(typval_T *argvars, typval_T *rettv)
7551{
7552 char_u *dir;
7553 char_u buf[NUMBUFLEN];
7554 int prot = 0755;
7555
7556 rettv->vval.v_number = FAIL;
7557 if (check_restricted() || check_secure())
7558 return;
7559
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007560 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007562 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007563
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007564 if (*gettail(dir) == NUL)
7565 /* remove trailing slashes */
7566 *gettail_sep(dir) = NUL;
7567
7568 if (argvars[1].v_type != VAR_UNKNOWN)
7569 {
7570 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007571 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007572 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007573 if (prot == -1)
7574 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007577 {
7578 if (mch_isdir(dir))
7579 {
7580 /* With the "p" flag it's OK if the dir already exists. */
7581 rettv->vval.v_number = OK;
7582 return;
7583 }
7584 mkdir_recurse(dir, prot);
7585 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007587 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007589
7590/*
7591 * "mode()" function
7592 */
7593 static void
7594f_mode(typval_T *argvars, typval_T *rettv)
7595{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007596 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597
Bram Moolenaar612cc382018-07-29 15:34:26 +02007598 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007599
7600 if (time_for_testing == 93784)
7601 {
7602 /* Testing the two-character code. */
7603 buf[0] = 'x';
7604 buf[1] = '!';
7605 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007606#ifdef FEAT_TERMINAL
7607 else if (term_use_loop())
7608 buf[0] = 't';
7609#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 else if (VIsual_active)
7611 {
7612 if (VIsual_select)
7613 buf[0] = VIsual_mode + 's' - 'v';
7614 else
7615 buf[0] = VIsual_mode;
7616 }
7617 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7618 || State == CONFIRM)
7619 {
7620 buf[0] = 'r';
7621 if (State == ASKMORE)
7622 buf[1] = 'm';
7623 else if (State == CONFIRM)
7624 buf[1] = '?';
7625 }
7626 else if (State == EXTERNCMD)
7627 buf[0] = '!';
7628 else if (State & INSERT)
7629 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 if (State & VREPLACE_FLAG)
7631 {
7632 buf[0] = 'R';
7633 buf[1] = 'v';
7634 }
7635 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007636 {
7637 if (State & REPLACE_FLAG)
7638 buf[0] = 'R';
7639 else
7640 buf[0] = 'i';
7641#ifdef FEAT_INS_EXPAND
7642 if (ins_compl_active())
7643 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007644 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007645 buf[1] = 'x';
7646#endif
7647 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007649 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 {
7651 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007652 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007654 else if (exmode_active == EXMODE_NORMAL)
7655 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007656 }
7657 else
7658 {
7659 buf[0] = 'n';
7660 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007661 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007663 // to be able to detect force-linewise/blockwise/characterwise operations
7664 buf[2] = motion_force;
7665 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007666 else if (restart_edit == 'I' || restart_edit == 'R'
7667 || restart_edit == 'V')
7668 {
7669 buf[1] = 'i';
7670 buf[2] = restart_edit;
7671 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 }
7673
7674 /* Clear out the minor mode when the argument is not a non-zero number or
7675 * non-empty string. */
7676 if (!non_zero_arg(&argvars[0]))
7677 buf[1] = NUL;
7678
7679 rettv->vval.v_string = vim_strsave(buf);
7680 rettv->v_type = VAR_STRING;
7681}
7682
7683#if defined(FEAT_MZSCHEME) || defined(PROTO)
7684/*
7685 * "mzeval()" function
7686 */
7687 static void
7688f_mzeval(typval_T *argvars, typval_T *rettv)
7689{
7690 char_u *str;
7691 char_u buf[NUMBUFLEN];
7692
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007693 if (check_restricted() || check_secure())
7694 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007695 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007696 do_mzeval(str, rettv);
7697}
7698
7699 void
7700mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7701{
7702 typval_T argvars[3];
7703
7704 argvars[0].v_type = VAR_STRING;
7705 argvars[0].vval.v_string = name;
7706 copy_tv(args, &argvars[1]);
7707 argvars[2].v_type = VAR_UNKNOWN;
7708 f_call(argvars, rettv);
7709 clear_tv(&argvars[1]);
7710}
7711#endif
7712
7713/*
7714 * "nextnonblank()" function
7715 */
7716 static void
7717f_nextnonblank(typval_T *argvars, typval_T *rettv)
7718{
7719 linenr_T lnum;
7720
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007721 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 {
7723 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7724 {
7725 lnum = 0;
7726 break;
7727 }
7728 if (*skipwhite(ml_get(lnum)) != NUL)
7729 break;
7730 }
7731 rettv->vval.v_number = lnum;
7732}
7733
7734/*
7735 * "nr2char()" function
7736 */
7737 static void
7738f_nr2char(typval_T *argvars, typval_T *rettv)
7739{
7740 char_u buf[NUMBUFLEN];
7741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007742 if (has_mbyte)
7743 {
7744 int utf8 = 0;
7745
7746 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007747 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007749 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007751 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007752 }
7753 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007755 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 buf[1] = NUL;
7757 }
7758 rettv->v_type = VAR_STRING;
7759 rettv->vval.v_string = vim_strsave(buf);
7760}
7761
7762/*
7763 * "or(expr, expr)" function
7764 */
7765 static void
7766f_or(typval_T *argvars, typval_T *rettv)
7767{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007768 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7769 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770}
7771
7772/*
7773 * "pathshorten()" function
7774 */
7775 static void
7776f_pathshorten(typval_T *argvars, typval_T *rettv)
7777{
7778 char_u *p;
7779
7780 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007781 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782 if (p == NULL)
7783 rettv->vval.v_string = NULL;
7784 else
7785 {
7786 p = vim_strsave(p);
7787 rettv->vval.v_string = p;
7788 if (p != NULL)
7789 shorten_dir(p);
7790 }
7791}
7792
7793#ifdef FEAT_PERL
7794/*
7795 * "perleval()" function
7796 */
7797 static void
7798f_perleval(typval_T *argvars, typval_T *rettv)
7799{
7800 char_u *str;
7801 char_u buf[NUMBUFLEN];
7802
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007803 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 do_perleval(str, rettv);
7805}
7806#endif
7807
7808#ifdef FEAT_FLOAT
7809/*
7810 * "pow()" function
7811 */
7812 static void
7813f_pow(typval_T *argvars, typval_T *rettv)
7814{
7815 float_T fx = 0.0, fy = 0.0;
7816
7817 rettv->v_type = VAR_FLOAT;
7818 if (get_float_arg(argvars, &fx) == OK
7819 && get_float_arg(&argvars[1], &fy) == OK)
7820 rettv->vval.v_float = pow(fx, fy);
7821 else
7822 rettv->vval.v_float = 0.0;
7823}
7824#endif
7825
7826/*
7827 * "prevnonblank()" function
7828 */
7829 static void
7830f_prevnonblank(typval_T *argvars, typval_T *rettv)
7831{
7832 linenr_T lnum;
7833
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007834 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7836 lnum = 0;
7837 else
7838 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7839 --lnum;
7840 rettv->vval.v_number = lnum;
7841}
7842
7843/* This dummy va_list is here because:
7844 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7845 * - locally in the function results in a "used before set" warning
7846 * - using va_start() to initialize it gives "function with fixed args" error */
7847static va_list ap;
7848
7849/*
7850 * "printf()" function
7851 */
7852 static void
7853f_printf(typval_T *argvars, typval_T *rettv)
7854{
7855 char_u buf[NUMBUFLEN];
7856 int len;
7857 char_u *s;
7858 int saved_did_emsg = did_emsg;
7859 char *fmt;
7860
7861 rettv->v_type = VAR_STRING;
7862 rettv->vval.v_string = NULL;
7863
7864 /* Get the required length, allocate the buffer and do it for real. */
7865 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007866 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007867 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 if (!did_emsg)
7869 {
7870 s = alloc(len + 1);
7871 if (s != NULL)
7872 {
7873 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007874 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7875 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 }
7877 }
7878 did_emsg |= saved_did_emsg;
7879}
7880
7881/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007882 * "pum_getpos()" function
7883 */
7884 static void
7885f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7886{
7887 if (rettv_dict_alloc(rettv) != OK)
7888 return;
7889#ifdef FEAT_INS_EXPAND
7890 pum_set_event_info(rettv->vval.v_dict);
7891#endif
7892}
7893
7894/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895 * "pumvisible()" function
7896 */
7897 static void
7898f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7899{
7900#ifdef FEAT_INS_EXPAND
7901 if (pum_visible())
7902 rettv->vval.v_number = 1;
7903#endif
7904}
7905
7906#ifdef FEAT_PYTHON3
7907/*
7908 * "py3eval()" function
7909 */
7910 static void
7911f_py3eval(typval_T *argvars, typval_T *rettv)
7912{
7913 char_u *str;
7914 char_u buf[NUMBUFLEN];
7915
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007916 if (check_restricted() || check_secure())
7917 return;
7918
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007919 if (p_pyx == 0)
7920 p_pyx = 3;
7921
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007922 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 do_py3eval(str, rettv);
7924}
7925#endif
7926
7927#ifdef FEAT_PYTHON
7928/*
7929 * "pyeval()" function
7930 */
7931 static void
7932f_pyeval(typval_T *argvars, typval_T *rettv)
7933{
7934 char_u *str;
7935 char_u buf[NUMBUFLEN];
7936
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007937 if (check_restricted() || check_secure())
7938 return;
7939
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007940 if (p_pyx == 0)
7941 p_pyx = 2;
7942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007943 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944 do_pyeval(str, rettv);
7945}
7946#endif
7947
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007948#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7949/*
7950 * "pyxeval()" function
7951 */
7952 static void
7953f_pyxeval(typval_T *argvars, typval_T *rettv)
7954{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007955 if (check_restricted() || check_secure())
7956 return;
7957
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007958# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7959 init_pyxversion();
7960 if (p_pyx == 2)
7961 f_pyeval(argvars, rettv);
7962 else
7963 f_py3eval(argvars, rettv);
7964# elif defined(FEAT_PYTHON)
7965 f_pyeval(argvars, rettv);
7966# elif defined(FEAT_PYTHON3)
7967 f_py3eval(argvars, rettv);
7968# endif
7969}
7970#endif
7971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972/*
7973 * "range()" function
7974 */
7975 static void
7976f_range(typval_T *argvars, typval_T *rettv)
7977{
7978 varnumber_T start;
7979 varnumber_T end;
7980 varnumber_T stride = 1;
7981 varnumber_T i;
7982 int error = FALSE;
7983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007984 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985 if (argvars[1].v_type == VAR_UNKNOWN)
7986 {
7987 end = start - 1;
7988 start = 0;
7989 }
7990 else
7991 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007992 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007994 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 }
7996
7997 if (error)
7998 return; /* type error; errmsg already given */
7999 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008000 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008002 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 else
8004 {
8005 if (rettv_list_alloc(rettv) == OK)
8006 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8007 if (list_append_number(rettv->vval.v_list,
8008 (varnumber_T)i) == FAIL)
8009 break;
8010 }
8011}
8012
8013/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008014 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008015 */
8016 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008017readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008018{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008019 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008020 typval_T save_val;
8021 typval_T rettv;
8022 typval_T argv[2];
8023 int retval = 0;
8024 int error = FALSE;
8025
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008026 if (expr->v_type == VAR_UNKNOWN)
8027 return 1;
8028
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008029 prepare_vimvar(VV_VAL, &save_val);
8030 set_vim_var_string(VV_VAL, name, -1);
8031 argv[0].v_type = VAR_STRING;
8032 argv[0].vval.v_string = name;
8033
8034 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8035 goto theend;
8036
8037 retval = tv_get_number_chk(&rettv, &error);
8038 if (error)
8039 retval = -1;
8040 clear_tv(&rettv);
8041
8042theend:
8043 set_vim_var_string(VV_VAL, NULL, 0);
8044 restore_vimvar(VV_VAL, &save_val);
8045 return retval;
8046}
8047
8048/*
8049 * "readdir()" function
8050 */
8051 static void
8052f_readdir(typval_T *argvars, typval_T *rettv)
8053{
8054 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008055 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008056 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008057 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008058 garray_T ga;
8059 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008060
8061 if (rettv_list_alloc(rettv) == FAIL)
8062 return;
8063 path = tv_get_string(&argvars[0]);
8064 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008065
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008066 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8067 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008068 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008069 for (i = 0; i < ga.ga_len; i++)
8070 {
8071 p = ((char_u **)ga.ga_data)[i];
8072 list_append_string(rettv->vval.v_list, p, -1);
8073 }
8074 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008075 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008076}
8077
8078/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 * "readfile()" function
8080 */
8081 static void
8082f_readfile(typval_T *argvars, typval_T *rettv)
8083{
8084 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008085 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 int failed = FALSE;
8087 char_u *fname;
8088 FILE *fd;
8089 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8090 int io_size = sizeof(buf);
8091 int readlen; /* size of last fread() */
8092 char_u *prev = NULL; /* previously read bytes, if any */
8093 long prevlen = 0; /* length of data in prev */
8094 long prevsize = 0; /* size of prev buffer */
8095 long maxline = MAXLNUM;
8096 long cnt = 0;
8097 char_u *p; /* position in buf */
8098 char_u *start; /* start of current line */
8099
8100 if (argvars[1].v_type != VAR_UNKNOWN)
8101 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008102 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008104 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8105 blob = TRUE;
8106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008107 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008108 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008109 }
8110
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008111 if (blob)
8112 {
8113 if (rettv_blob_alloc(rettv) == FAIL)
8114 return;
8115 }
8116 else
8117 {
8118 if (rettv_list_alloc(rettv) == FAIL)
8119 return;
8120 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008121
8122 /* Always open the file in binary mode, library functions have a mind of
8123 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008124 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8126 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008127 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 return;
8129 }
8130
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008131 if (blob)
8132 {
8133 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8134 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008135 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008136 blob_free(rettv->vval.v_blob);
8137 }
8138 fclose(fd);
8139 return;
8140 }
8141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142 while (cnt < maxline || maxline < 0)
8143 {
8144 readlen = (int)fread(buf, 1, io_size, fd);
8145
8146 /* This for loop processes what was read, but is also entered at end
8147 * of file so that either:
8148 * - an incomplete line gets written
8149 * - a "binary" file gets an empty line at the end if it ends in a
8150 * newline. */
8151 for (p = buf, start = buf;
8152 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8153 ++p)
8154 {
8155 if (*p == '\n' || readlen <= 0)
8156 {
8157 listitem_T *li;
8158 char_u *s = NULL;
8159 long_u len = p - start;
8160
8161 /* Finished a line. Remove CRs before NL. */
8162 if (readlen > 0 && !binary)
8163 {
8164 while (len > 0 && start[len - 1] == '\r')
8165 --len;
8166 /* removal may cross back to the "prev" string */
8167 if (len == 0)
8168 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8169 --prevlen;
8170 }
8171 if (prevlen == 0)
8172 s = vim_strnsave(start, (int)len);
8173 else
8174 {
8175 /* Change "prev" buffer to be the right size. This way
8176 * the bytes are only copied once, and very long lines are
8177 * allocated only once. */
8178 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8179 {
8180 mch_memmove(s + prevlen, start, len);
8181 s[prevlen + len] = NUL;
8182 prev = NULL; /* the list will own the string */
8183 prevlen = prevsize = 0;
8184 }
8185 }
8186 if (s == NULL)
8187 {
8188 do_outofmem_msg((long_u) prevlen + len + 1);
8189 failed = TRUE;
8190 break;
8191 }
8192
8193 if ((li = listitem_alloc()) == NULL)
8194 {
8195 vim_free(s);
8196 failed = TRUE;
8197 break;
8198 }
8199 li->li_tv.v_type = VAR_STRING;
8200 li->li_tv.v_lock = 0;
8201 li->li_tv.vval.v_string = s;
8202 list_append(rettv->vval.v_list, li);
8203
8204 start = p + 1; /* step over newline */
8205 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8206 break;
8207 }
8208 else if (*p == NUL)
8209 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008210 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8211 * when finding the BF and check the previous two bytes. */
8212 else if (*p == 0xbf && enc_utf8 && !binary)
8213 {
8214 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8215 * + 1, these may be in the "prev" string. */
8216 char_u back1 = p >= buf + 1 ? p[-1]
8217 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8218 char_u back2 = p >= buf + 2 ? p[-2]
8219 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8220 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8221
8222 if (back2 == 0xef && back1 == 0xbb)
8223 {
8224 char_u *dest = p - 2;
8225
8226 /* Usually a BOM is at the beginning of a file, and so at
8227 * the beginning of a line; then we can just step over it.
8228 */
8229 if (start == dest)
8230 start = p + 1;
8231 else
8232 {
8233 /* have to shuffle buf to close gap */
8234 int adjust_prevlen = 0;
8235
8236 if (dest < buf)
8237 {
8238 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8239 dest = buf;
8240 }
8241 if (readlen > p - buf + 1)
8242 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8243 readlen -= 3 - adjust_prevlen;
8244 prevlen -= adjust_prevlen;
8245 p = dest - 1;
8246 }
8247 }
8248 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008249 } /* for */
8250
8251 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8252 break;
8253 if (start < p)
8254 {
8255 /* There's part of a line in buf, store it in "prev". */
8256 if (p - start + prevlen >= prevsize)
8257 {
8258 /* need bigger "prev" buffer */
8259 char_u *newprev;
8260
8261 /* A common use case is ordinary text files and "prev" gets a
8262 * fragment of a line, so the first allocation is made
8263 * small, to avoid repeatedly 'allocing' large and
8264 * 'reallocing' small. */
8265 if (prevsize == 0)
8266 prevsize = (long)(p - start);
8267 else
8268 {
8269 long grow50pc = (prevsize * 3) / 2;
8270 long growmin = (long)((p - start) * 2 + prevlen);
8271 prevsize = grow50pc > growmin ? grow50pc : growmin;
8272 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008273 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008274 if (newprev == NULL)
8275 {
8276 do_outofmem_msg((long_u)prevsize);
8277 failed = TRUE;
8278 break;
8279 }
8280 prev = newprev;
8281 }
8282 /* Add the line part to end of "prev". */
8283 mch_memmove(prev + prevlen, start, p - start);
8284 prevlen += (long)(p - start);
8285 }
8286 } /* while */
8287
8288 /*
8289 * For a negative line count use only the lines at the end of the file,
8290 * free the rest.
8291 */
8292 if (!failed && maxline < 0)
8293 while (cnt > -maxline)
8294 {
8295 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8296 --cnt;
8297 }
8298
8299 if (failed)
8300 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008301 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008303 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304 }
8305
8306 vim_free(prev);
8307 fclose(fd);
8308}
8309
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008310 static void
8311return_register(int regname, typval_T *rettv)
8312{
8313 char_u buf[2] = {0, 0};
8314
8315 buf[0] = (char_u)regname;
8316 rettv->v_type = VAR_STRING;
8317 rettv->vval.v_string = vim_strsave(buf);
8318}
8319
8320/*
8321 * "reg_executing()" function
8322 */
8323 static void
8324f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8325{
8326 return_register(reg_executing, rettv);
8327}
8328
8329/*
8330 * "reg_recording()" function
8331 */
8332 static void
8333f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8334{
8335 return_register(reg_recording, rettv);
8336}
8337
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339/*
8340 * Convert a List to proftime_T.
8341 * Return FAIL when there is something wrong.
8342 */
8343 static int
8344list2proftime(typval_T *arg, proftime_T *tm)
8345{
8346 long n1, n2;
8347 int error = FALSE;
8348
8349 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8350 || arg->vval.v_list->lv_len != 2)
8351 return FAIL;
8352 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8353 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008354# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 tm->HighPart = n1;
8356 tm->LowPart = n2;
8357# else
8358 tm->tv_sec = n1;
8359 tm->tv_usec = n2;
8360# endif
8361 return error ? FAIL : OK;
8362}
8363#endif /* FEAT_RELTIME */
8364
8365/*
8366 * "reltime()" function
8367 */
8368 static void
8369f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8370{
8371#ifdef FEAT_RELTIME
8372 proftime_T res;
8373 proftime_T start;
8374
8375 if (argvars[0].v_type == VAR_UNKNOWN)
8376 {
8377 /* No arguments: get current time. */
8378 profile_start(&res);
8379 }
8380 else if (argvars[1].v_type == VAR_UNKNOWN)
8381 {
8382 if (list2proftime(&argvars[0], &res) == FAIL)
8383 return;
8384 profile_end(&res);
8385 }
8386 else
8387 {
8388 /* Two arguments: compute the difference. */
8389 if (list2proftime(&argvars[0], &start) == FAIL
8390 || list2proftime(&argvars[1], &res) == FAIL)
8391 return;
8392 profile_sub(&res, &start);
8393 }
8394
8395 if (rettv_list_alloc(rettv) == OK)
8396 {
8397 long n1, n2;
8398
Bram Moolenaar4f974752019-02-17 17:44:42 +01008399# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008400 n1 = res.HighPart;
8401 n2 = res.LowPart;
8402# else
8403 n1 = res.tv_sec;
8404 n2 = res.tv_usec;
8405# endif
8406 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8407 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8408 }
8409#endif
8410}
8411
8412#ifdef FEAT_FLOAT
8413/*
8414 * "reltimefloat()" function
8415 */
8416 static void
8417f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8418{
8419# ifdef FEAT_RELTIME
8420 proftime_T tm;
8421# endif
8422
8423 rettv->v_type = VAR_FLOAT;
8424 rettv->vval.v_float = 0;
8425# ifdef FEAT_RELTIME
8426 if (list2proftime(&argvars[0], &tm) == OK)
8427 rettv->vval.v_float = profile_float(&tm);
8428# endif
8429}
8430#endif
8431
8432/*
8433 * "reltimestr()" function
8434 */
8435 static void
8436f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8437{
8438#ifdef FEAT_RELTIME
8439 proftime_T tm;
8440#endif
8441
8442 rettv->v_type = VAR_STRING;
8443 rettv->vval.v_string = NULL;
8444#ifdef FEAT_RELTIME
8445 if (list2proftime(&argvars[0], &tm) == OK)
8446 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8447#endif
8448}
8449
8450#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008451 static void
8452make_connection(void)
8453{
8454 if (X_DISPLAY == NULL
8455# ifdef FEAT_GUI
8456 && !gui.in_use
8457# endif
8458 )
8459 {
8460 x_force_connect = TRUE;
8461 setup_term_clip();
8462 x_force_connect = FALSE;
8463 }
8464}
8465
8466 static int
8467check_connection(void)
8468{
8469 make_connection();
8470 if (X_DISPLAY == NULL)
8471 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008472 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008473 return FAIL;
8474 }
8475 return OK;
8476}
8477#endif
8478
8479#ifdef FEAT_CLIENTSERVER
8480 static void
8481remote_common(typval_T *argvars, typval_T *rettv, int expr)
8482{
8483 char_u *server_name;
8484 char_u *keys;
8485 char_u *r = NULL;
8486 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008487 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008488# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008489 HWND w;
8490# else
8491 Window w;
8492# endif
8493
8494 if (check_restricted() || check_secure())
8495 return;
8496
8497# ifdef FEAT_X11
8498 if (check_connection() == FAIL)
8499 return;
8500# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008501 if (argvars[2].v_type != VAR_UNKNOWN
8502 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008503 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008504
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008505 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008506 if (server_name == NULL)
8507 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008508 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008509# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008510 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008511# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008512 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8513 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008514# endif
8515 {
8516 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008517 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008518 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008519 vim_free(r);
8520 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008521 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008522 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 return;
8524 }
8525
8526 rettv->vval.v_string = r;
8527
8528 if (argvars[2].v_type != VAR_UNKNOWN)
8529 {
8530 dictitem_T v;
8531 char_u str[30];
8532 char_u *idvar;
8533
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008534 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008535 if (idvar != NULL && *idvar != NUL)
8536 {
8537 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8538 v.di_tv.v_type = VAR_STRING;
8539 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008541 vim_free(v.di_tv.vval.v_string);
8542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 }
8544}
8545#endif
8546
8547/*
8548 * "remote_expr()" function
8549 */
8550 static void
8551f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8552{
8553 rettv->v_type = VAR_STRING;
8554 rettv->vval.v_string = NULL;
8555#ifdef FEAT_CLIENTSERVER
8556 remote_common(argvars, rettv, TRUE);
8557#endif
8558}
8559
8560/*
8561 * "remote_foreground()" function
8562 */
8563 static void
8564f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8565{
8566#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008567# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008568 /* On Win32 it's done in this application. */
8569 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008570 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008571
8572 if (server_name != NULL)
8573 serverForeground(server_name);
8574 }
8575# else
8576 /* Send a foreground() expression to the server. */
8577 argvars[1].v_type = VAR_STRING;
8578 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8579 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008580 rettv->v_type = VAR_STRING;
8581 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008582 remote_common(argvars, rettv, TRUE);
8583 vim_free(argvars[1].vval.v_string);
8584# endif
8585#endif
8586}
8587
8588 static void
8589f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8590{
8591#ifdef FEAT_CLIENTSERVER
8592 dictitem_T v;
8593 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008594# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595 long_u n = 0;
8596# endif
8597 char_u *serverid;
8598
8599 if (check_restricted() || check_secure())
8600 {
8601 rettv->vval.v_number = -1;
8602 return;
8603 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008604 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008605 if (serverid == NULL)
8606 {
8607 rettv->vval.v_number = -1;
8608 return; /* type error; errmsg already given */
8609 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008610# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8612 if (n == 0)
8613 rettv->vval.v_number = -1;
8614 else
8615 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008616 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008617 rettv->vval.v_number = (s != NULL);
8618 }
8619# else
8620 if (check_connection() == FAIL)
8621 return;
8622
8623 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8624 serverStrToWin(serverid), &s);
8625# endif
8626
8627 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8628 {
8629 char_u *retvar;
8630
8631 v.di_tv.v_type = VAR_STRING;
8632 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008633 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 if (retvar != NULL)
8635 set_var(retvar, &v.di_tv, FALSE);
8636 vim_free(v.di_tv.vval.v_string);
8637 }
8638#else
8639 rettv->vval.v_number = -1;
8640#endif
8641}
8642
8643 static void
8644f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8645{
8646 char_u *r = NULL;
8647
8648#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008649 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650
8651 if (serverid != NULL && !check_restricted() && !check_secure())
8652 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008653 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008654# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008655 /* The server's HWND is encoded in the 'id' parameter */
8656 long_u n = 0;
8657# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008658
8659 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008660 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008661
Bram Moolenaar4f974752019-02-17 17:44:42 +01008662# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8664 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008665 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008666 if (r == NULL)
8667# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008668 if (check_connection() == FAIL
8669 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8670 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008672 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008673 }
8674#endif
8675 rettv->v_type = VAR_STRING;
8676 rettv->vval.v_string = r;
8677}
8678
8679/*
8680 * "remote_send()" function
8681 */
8682 static void
8683f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8684{
8685 rettv->v_type = VAR_STRING;
8686 rettv->vval.v_string = NULL;
8687#ifdef FEAT_CLIENTSERVER
8688 remote_common(argvars, rettv, FALSE);
8689#endif
8690}
8691
8692/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008693 * "remote_startserver()" function
8694 */
8695 static void
8696f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8697{
8698#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008699 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008700
8701 if (server == NULL)
8702 return; /* type error; errmsg already given */
8703 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008704 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008705 else
8706 {
8707# ifdef FEAT_X11
8708 if (check_connection() == OK)
8709 serverRegisterName(X_DISPLAY, server);
8710# else
8711 serverSetName(server);
8712# endif
8713 }
8714#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008715 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008716#endif
8717}
8718
8719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 * "remove()" function
8721 */
8722 static void
8723f_remove(typval_T *argvars, typval_T *rettv)
8724{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8726
8727 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008728 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008729 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008730 blob_remove(argvars, rettv);
8731 else if (argvars[0].v_type == VAR_LIST)
8732 list_remove(argvars, rettv, arg_errmsg);
8733 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008734 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008735}
8736
8737/*
8738 * "rename({from}, {to})" function
8739 */
8740 static void
8741f_rename(typval_T *argvars, typval_T *rettv)
8742{
8743 char_u buf[NUMBUFLEN];
8744
8745 if (check_restricted() || check_secure())
8746 rettv->vval.v_number = -1;
8747 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008748 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8749 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008750}
8751
8752/*
8753 * "repeat()" function
8754 */
8755 static void
8756f_repeat(typval_T *argvars, typval_T *rettv)
8757{
8758 char_u *p;
8759 int n;
8760 int slen;
8761 int len;
8762 char_u *r;
8763 int i;
8764
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008765 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008766 if (argvars[0].v_type == VAR_LIST)
8767 {
8768 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8769 while (n-- > 0)
8770 if (list_extend(rettv->vval.v_list,
8771 argvars[0].vval.v_list, NULL) == FAIL)
8772 break;
8773 }
8774 else
8775 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008776 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008777 rettv->v_type = VAR_STRING;
8778 rettv->vval.v_string = NULL;
8779
8780 slen = (int)STRLEN(p);
8781 len = slen * n;
8782 if (len <= 0)
8783 return;
8784
8785 r = alloc(len + 1);
8786 if (r != NULL)
8787 {
8788 for (i = 0; i < n; i++)
8789 mch_memmove(r + i * slen, p, (size_t)slen);
8790 r[len] = NUL;
8791 }
8792
8793 rettv->vval.v_string = r;
8794 }
8795}
8796
8797/*
8798 * "resolve()" function
8799 */
8800 static void
8801f_resolve(typval_T *argvars, typval_T *rettv)
8802{
8803 char_u *p;
8804#ifdef HAVE_READLINK
8805 char_u *buf = NULL;
8806#endif
8807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008808 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008809#ifdef FEAT_SHORTCUT
8810 {
8811 char_u *v = NULL;
8812
Bram Moolenaardce1e892019-02-10 23:18:53 +01008813 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008814 if (v != NULL)
8815 rettv->vval.v_string = v;
8816 else
8817 rettv->vval.v_string = vim_strsave(p);
8818 }
8819#else
8820# ifdef HAVE_READLINK
8821 {
8822 char_u *cpy;
8823 int len;
8824 char_u *remain = NULL;
8825 char_u *q;
8826 int is_relative_to_current = FALSE;
8827 int has_trailing_pathsep = FALSE;
8828 int limit = 100;
8829
8830 p = vim_strsave(p);
8831
8832 if (p[0] == '.' && (vim_ispathsep(p[1])
8833 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8834 is_relative_to_current = TRUE;
8835
8836 len = STRLEN(p);
8837 if (len > 0 && after_pathsep(p, p + len))
8838 {
8839 has_trailing_pathsep = TRUE;
8840 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8841 }
8842
8843 q = getnextcomp(p);
8844 if (*q != NUL)
8845 {
8846 /* Separate the first path component in "p", and keep the
8847 * remainder (beginning with the path separator). */
8848 remain = vim_strsave(q - 1);
8849 q[-1] = NUL;
8850 }
8851
8852 buf = alloc(MAXPATHL + 1);
8853 if (buf == NULL)
8854 goto fail;
8855
8856 for (;;)
8857 {
8858 for (;;)
8859 {
8860 len = readlink((char *)p, (char *)buf, MAXPATHL);
8861 if (len <= 0)
8862 break;
8863 buf[len] = NUL;
8864
8865 if (limit-- == 0)
8866 {
8867 vim_free(p);
8868 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008869 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870 rettv->vval.v_string = NULL;
8871 goto fail;
8872 }
8873
8874 /* Ensure that the result will have a trailing path separator
8875 * if the argument has one. */
8876 if (remain == NULL && has_trailing_pathsep)
8877 add_pathsep(buf);
8878
8879 /* Separate the first path component in the link value and
8880 * concatenate the remainders. */
8881 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8882 if (*q != NUL)
8883 {
8884 if (remain == NULL)
8885 remain = vim_strsave(q - 1);
8886 else
8887 {
8888 cpy = concat_str(q - 1, remain);
8889 if (cpy != NULL)
8890 {
8891 vim_free(remain);
8892 remain = cpy;
8893 }
8894 }
8895 q[-1] = NUL;
8896 }
8897
8898 q = gettail(p);
8899 if (q > p && *q == NUL)
8900 {
8901 /* Ignore trailing path separator. */
8902 q[-1] = NUL;
8903 q = gettail(p);
8904 }
8905 if (q > p && !mch_isFullName(buf))
8906 {
8907 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008908 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008909 if (cpy != NULL)
8910 {
8911 STRCPY(cpy, p);
8912 STRCPY(gettail(cpy), buf);
8913 vim_free(p);
8914 p = cpy;
8915 }
8916 }
8917 else
8918 {
8919 vim_free(p);
8920 p = vim_strsave(buf);
8921 }
8922 }
8923
8924 if (remain == NULL)
8925 break;
8926
8927 /* Append the first path component of "remain" to "p". */
8928 q = getnextcomp(remain + 1);
8929 len = q - remain - (*q != NUL);
8930 cpy = vim_strnsave(p, STRLEN(p) + len);
8931 if (cpy != NULL)
8932 {
8933 STRNCAT(cpy, remain, len);
8934 vim_free(p);
8935 p = cpy;
8936 }
8937 /* Shorten "remain". */
8938 if (*q != NUL)
8939 STRMOVE(remain, q - 1);
8940 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008941 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 }
8943
8944 /* If the result is a relative path name, make it explicitly relative to
8945 * the current directory if and only if the argument had this form. */
8946 if (!vim_ispathsep(*p))
8947 {
8948 if (is_relative_to_current
8949 && *p != NUL
8950 && !(p[0] == '.'
8951 && (p[1] == NUL
8952 || vim_ispathsep(p[1])
8953 || (p[1] == '.'
8954 && (p[2] == NUL
8955 || vim_ispathsep(p[2]))))))
8956 {
8957 /* Prepend "./". */
8958 cpy = concat_str((char_u *)"./", p);
8959 if (cpy != NULL)
8960 {
8961 vim_free(p);
8962 p = cpy;
8963 }
8964 }
8965 else if (!is_relative_to_current)
8966 {
8967 /* Strip leading "./". */
8968 q = p;
8969 while (q[0] == '.' && vim_ispathsep(q[1]))
8970 q += 2;
8971 if (q > p)
8972 STRMOVE(p, p + 2);
8973 }
8974 }
8975
8976 /* Ensure that the result will have no trailing path separator
8977 * if the argument had none. But keep "/" or "//". */
8978 if (!has_trailing_pathsep)
8979 {
8980 q = p + STRLEN(p);
8981 if (after_pathsep(p, q))
8982 *gettail_sep(p) = NUL;
8983 }
8984
8985 rettv->vval.v_string = p;
8986 }
8987# else
8988 rettv->vval.v_string = vim_strsave(p);
8989# endif
8990#endif
8991
8992 simplify_filename(rettv->vval.v_string);
8993
8994#ifdef HAVE_READLINK
8995fail:
8996 vim_free(buf);
8997#endif
8998 rettv->v_type = VAR_STRING;
8999}
9000
9001/*
9002 * "reverse({list})" function
9003 */
9004 static void
9005f_reverse(typval_T *argvars, typval_T *rettv)
9006{
9007 list_T *l;
9008 listitem_T *li, *ni;
9009
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009010 if (argvars[0].v_type == VAR_BLOB)
9011 {
9012 blob_T *b = argvars[0].vval.v_blob;
9013 int i, len = blob_len(b);
9014
9015 for (i = 0; i < len / 2; i++)
9016 {
9017 int tmp = blob_get(b, i);
9018
9019 blob_set(b, i, blob_get(b, len - i - 1));
9020 blob_set(b, len - i - 1, tmp);
9021 }
9022 rettv_blob_set(rettv, b);
9023 return;
9024 }
9025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009027 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009028 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009029 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009030 (char_u *)N_("reverse() argument"), TRUE))
9031 {
9032 li = l->lv_last;
9033 l->lv_first = l->lv_last = NULL;
9034 l->lv_len = 0;
9035 while (li != NULL)
9036 {
9037 ni = li->li_prev;
9038 list_append(l, li);
9039 li = ni;
9040 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009041 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042 l->lv_idx = l->lv_len - l->lv_idx - 1;
9043 }
9044}
9045
9046#define SP_NOMOVE 0x01 /* don't move cursor */
9047#define SP_REPEAT 0x02 /* repeat to find outer pair */
9048#define SP_RETCOUNT 0x04 /* return matchcount */
9049#define SP_SETPCMARK 0x08 /* set previous context mark */
9050#define SP_START 0x10 /* accept match at start position */
9051#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9052#define SP_END 0x40 /* leave cursor at end of match */
9053#define SP_COLUMN 0x80 /* start at cursor column */
9054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009055/*
9056 * Get flags for a search function.
9057 * Possibly sets "p_ws".
9058 * Returns BACKWARD, FORWARD or zero (for an error).
9059 */
9060 static int
9061get_search_arg(typval_T *varp, int *flagsp)
9062{
9063 int dir = FORWARD;
9064 char_u *flags;
9065 char_u nbuf[NUMBUFLEN];
9066 int mask;
9067
9068 if (varp->v_type != VAR_UNKNOWN)
9069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009070 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009071 if (flags == NULL)
9072 return 0; /* type error; errmsg already given */
9073 while (*flags != NUL)
9074 {
9075 switch (*flags)
9076 {
9077 case 'b': dir = BACKWARD; break;
9078 case 'w': p_ws = TRUE; break;
9079 case 'W': p_ws = FALSE; break;
9080 default: mask = 0;
9081 if (flagsp != NULL)
9082 switch (*flags)
9083 {
9084 case 'c': mask = SP_START; break;
9085 case 'e': mask = SP_END; break;
9086 case 'm': mask = SP_RETCOUNT; break;
9087 case 'n': mask = SP_NOMOVE; break;
9088 case 'p': mask = SP_SUBPAT; break;
9089 case 'r': mask = SP_REPEAT; break;
9090 case 's': mask = SP_SETPCMARK; break;
9091 case 'z': mask = SP_COLUMN; break;
9092 }
9093 if (mask == 0)
9094 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009095 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009096 dir = 0;
9097 }
9098 else
9099 *flagsp |= mask;
9100 }
9101 if (dir == 0)
9102 break;
9103 ++flags;
9104 }
9105 }
9106 return dir;
9107}
9108
9109/*
9110 * Shared by search() and searchpos() functions.
9111 */
9112 static int
9113search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9114{
9115 int flags;
9116 char_u *pat;
9117 pos_T pos;
9118 pos_T save_cursor;
9119 int save_p_ws = p_ws;
9120 int dir;
9121 int retval = 0; /* default: FAIL */
9122 long lnum_stop = 0;
9123 proftime_T tm;
9124#ifdef FEAT_RELTIME
9125 long time_limit = 0;
9126#endif
9127 int options = SEARCH_KEEP;
9128 int subpatnum;
9129
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009130 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009131 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9132 if (dir == 0)
9133 goto theend;
9134 flags = *flagsp;
9135 if (flags & SP_START)
9136 options |= SEARCH_START;
9137 if (flags & SP_END)
9138 options |= SEARCH_END;
9139 if (flags & SP_COLUMN)
9140 options |= SEARCH_COL;
9141
9142 /* Optional arguments: line number to stop searching and timeout. */
9143 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9144 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009145 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 if (lnum_stop < 0)
9147 goto theend;
9148#ifdef FEAT_RELTIME
9149 if (argvars[3].v_type != VAR_UNKNOWN)
9150 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009151 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009152 if (time_limit < 0)
9153 goto theend;
9154 }
9155#endif
9156 }
9157
9158#ifdef FEAT_RELTIME
9159 /* Set the time limit, if there is one. */
9160 profile_setlimit(time_limit, &tm);
9161#endif
9162
9163 /*
9164 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9165 * Check to make sure only those flags are set.
9166 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9167 * flags cannot be set. Check for that condition also.
9168 */
9169 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9170 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9171 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009172 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009173 goto theend;
9174 }
9175
9176 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009177 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009178 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009179 if (subpatnum != FAIL)
9180 {
9181 if (flags & SP_SUBPAT)
9182 retval = subpatnum;
9183 else
9184 retval = pos.lnum;
9185 if (flags & SP_SETPCMARK)
9186 setpcmark();
9187 curwin->w_cursor = pos;
9188 if (match_pos != NULL)
9189 {
9190 /* Store the match cursor position */
9191 match_pos->lnum = pos.lnum;
9192 match_pos->col = pos.col + 1;
9193 }
9194 /* "/$" will put the cursor after the end of the line, may need to
9195 * correct that here */
9196 check_cursor();
9197 }
9198
9199 /* If 'n' flag is used: restore cursor position. */
9200 if (flags & SP_NOMOVE)
9201 curwin->w_cursor = save_cursor;
9202 else
9203 curwin->w_set_curswant = TRUE;
9204theend:
9205 p_ws = save_p_ws;
9206
9207 return retval;
9208}
9209
9210#ifdef FEAT_FLOAT
9211
9212/*
9213 * round() is not in C90, use ceil() or floor() instead.
9214 */
9215 float_T
9216vim_round(float_T f)
9217{
9218 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9219}
9220
9221/*
9222 * "round({float})" function
9223 */
9224 static void
9225f_round(typval_T *argvars, typval_T *rettv)
9226{
9227 float_T f = 0.0;
9228
9229 rettv->v_type = VAR_FLOAT;
9230 if (get_float_arg(argvars, &f) == OK)
9231 rettv->vval.v_float = vim_round(f);
9232 else
9233 rettv->vval.v_float = 0.0;
9234}
9235#endif
9236
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009237#ifdef FEAT_RUBY
9238/*
9239 * "rubyeval()" function
9240 */
9241 static void
9242f_rubyeval(typval_T *argvars, typval_T *rettv)
9243{
9244 char_u *str;
9245 char_u buf[NUMBUFLEN];
9246
9247 str = tv_get_string_buf(&argvars[0], buf);
9248 do_rubyeval(str, rettv);
9249}
9250#endif
9251
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009252/*
9253 * "screenattr()" function
9254 */
9255 static void
9256f_screenattr(typval_T *argvars, typval_T *rettv)
9257{
9258 int row;
9259 int col;
9260 int c;
9261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009262 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9263 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009264 if (row < 0 || row >= screen_Rows
9265 || col < 0 || col >= screen_Columns)
9266 c = -1;
9267 else
9268 c = ScreenAttrs[LineOffset[row] + col];
9269 rettv->vval.v_number = c;
9270}
9271
9272/*
9273 * "screenchar()" function
9274 */
9275 static void
9276f_screenchar(typval_T *argvars, typval_T *rettv)
9277{
9278 int row;
9279 int col;
9280 int off;
9281 int c;
9282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009283 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9284 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009285 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009286 c = -1;
9287 else
9288 {
9289 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009290 if (enc_utf8 && ScreenLinesUC[off] != 0)
9291 c = ScreenLinesUC[off];
9292 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009293 c = ScreenLines[off];
9294 }
9295 rettv->vval.v_number = c;
9296}
9297
9298/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009299 * "screenchars()" function
9300 */
9301 static void
9302f_screenchars(typval_T *argvars, typval_T *rettv)
9303{
9304 int row;
9305 int col;
9306 int off;
9307 int c;
9308 int i;
9309
9310 if (rettv_list_alloc(rettv) == FAIL)
9311 return;
9312 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9313 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9314 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9315 return;
9316
9317 off = LineOffset[row] + col;
9318 if (enc_utf8 && ScreenLinesUC[off] != 0)
9319 c = ScreenLinesUC[off];
9320 else
9321 c = ScreenLines[off];
9322 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9323
9324 if (enc_utf8)
9325
9326 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9327 list_append_number(rettv->vval.v_list,
9328 (varnumber_T)ScreenLinesC[i][off]);
9329}
9330
9331/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009332 * "screencol()" function
9333 *
9334 * First column is 1 to be consistent with virtcol().
9335 */
9336 static void
9337f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9338{
9339 rettv->vval.v_number = screen_screencol() + 1;
9340}
9341
9342/*
9343 * "screenrow()" function
9344 */
9345 static void
9346f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9347{
9348 rettv->vval.v_number = screen_screenrow() + 1;
9349}
9350
9351/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009352 * "screenstring()" function
9353 */
9354 static void
9355f_screenstring(typval_T *argvars, typval_T *rettv)
9356{
9357 int row;
9358 int col;
9359 int off;
9360 int c;
9361 int i;
9362 char_u buf[MB_MAXBYTES + 1];
9363 int buflen = 0;
9364
9365 rettv->vval.v_string = NULL;
9366 rettv->v_type = VAR_STRING;
9367
9368 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9369 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9370 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9371 return;
9372
9373 off = LineOffset[row] + col;
9374 if (enc_utf8 && ScreenLinesUC[off] != 0)
9375 c = ScreenLinesUC[off];
9376 else
9377 c = ScreenLines[off];
9378 buflen += mb_char2bytes(c, buf);
9379
9380 if (enc_utf8)
9381 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9382 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9383
9384 buf[buflen] = NUL;
9385 rettv->vval.v_string = vim_strsave(buf);
9386}
9387
9388/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009389 * "search()" function
9390 */
9391 static void
9392f_search(typval_T *argvars, typval_T *rettv)
9393{
9394 int flags = 0;
9395
9396 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9397}
9398
9399/*
9400 * "searchdecl()" function
9401 */
9402 static void
9403f_searchdecl(typval_T *argvars, typval_T *rettv)
9404{
9405 int locally = 1;
9406 int thisblock = 0;
9407 int error = FALSE;
9408 char_u *name;
9409
9410 rettv->vval.v_number = 1; /* default: FAIL */
9411
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009412 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009413 if (argvars[1].v_type != VAR_UNKNOWN)
9414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009415 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009416 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009417 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009418 }
9419 if (!error && name != NULL)
9420 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9421 locally, thisblock, SEARCH_KEEP) == FAIL;
9422}
9423
9424/*
9425 * Used by searchpair() and searchpairpos()
9426 */
9427 static int
9428searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9429{
9430 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009431 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009432 int save_p_ws = p_ws;
9433 int dir;
9434 int flags = 0;
9435 char_u nbuf1[NUMBUFLEN];
9436 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009437 int retval = 0; /* default: FAIL */
9438 long lnum_stop = 0;
9439 long time_limit = 0;
9440
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009441 /* Get the three pattern arguments: start, middle, end. Will result in an
9442 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009443 spat = tv_get_string_chk(&argvars[0]);
9444 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9445 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009446 if (spat == NULL || mpat == NULL || epat == NULL)
9447 goto theend; /* type error */
9448
9449 /* Handle the optional fourth argument: flags */
9450 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9451 if (dir == 0)
9452 goto theend;
9453
9454 /* Don't accept SP_END or SP_SUBPAT.
9455 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9456 */
9457 if ((flags & (SP_END | SP_SUBPAT)) != 0
9458 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9459 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009460 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009461 goto theend;
9462 }
9463
9464 /* Using 'r' implies 'W', otherwise it doesn't work. */
9465 if (flags & SP_REPEAT)
9466 p_ws = FALSE;
9467
9468 /* Optional fifth argument: skip expression */
9469 if (argvars[3].v_type == VAR_UNKNOWN
9470 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009471 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009472 else
9473 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009474 skip = &argvars[4];
9475 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9476 && skip->v_type != VAR_STRING)
9477 {
9478 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009479 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009480 goto theend;
9481 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009482 if (argvars[5].v_type != VAR_UNKNOWN)
9483 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009486 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009487 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009488 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009489 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009490#ifdef FEAT_RELTIME
9491 if (argvars[6].v_type != VAR_UNKNOWN)
9492 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009493 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009494 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009495 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009496 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009497 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009498 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009499 }
9500#endif
9501 }
9502 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009503
9504 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9505 match_pos, lnum_stop, time_limit);
9506
9507theend:
9508 p_ws = save_p_ws;
9509
9510 return retval;
9511}
9512
9513/*
9514 * "searchpair()" function
9515 */
9516 static void
9517f_searchpair(typval_T *argvars, typval_T *rettv)
9518{
9519 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9520}
9521
9522/*
9523 * "searchpairpos()" function
9524 */
9525 static void
9526f_searchpairpos(typval_T *argvars, typval_T *rettv)
9527{
9528 pos_T match_pos;
9529 int lnum = 0;
9530 int col = 0;
9531
9532 if (rettv_list_alloc(rettv) == FAIL)
9533 return;
9534
9535 if (searchpair_cmn(argvars, &match_pos) > 0)
9536 {
9537 lnum = match_pos.lnum;
9538 col = match_pos.col;
9539 }
9540
9541 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9542 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9543}
9544
9545/*
9546 * Search for a start/middle/end thing.
9547 * Used by searchpair(), see its documentation for the details.
9548 * Returns 0 or -1 for no match,
9549 */
9550 long
9551do_searchpair(
9552 char_u *spat, /* start pattern */
9553 char_u *mpat, /* middle pattern */
9554 char_u *epat, /* end pattern */
9555 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009556 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009557 int flags, /* SP_SETPCMARK and other SP_ values */
9558 pos_T *match_pos,
9559 linenr_T lnum_stop, /* stop at this line if not zero */
9560 long time_limit UNUSED) /* stop after this many msec */
9561{
9562 char_u *save_cpo;
9563 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9564 long retval = 0;
9565 pos_T pos;
9566 pos_T firstpos;
9567 pos_T foundpos;
9568 pos_T save_cursor;
9569 pos_T save_pos;
9570 int n;
9571 int r;
9572 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009573 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009574 int err;
9575 int options = SEARCH_KEEP;
9576 proftime_T tm;
9577
9578 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9579 save_cpo = p_cpo;
9580 p_cpo = empty_option;
9581
9582#ifdef FEAT_RELTIME
9583 /* Set the time limit, if there is one. */
9584 profile_setlimit(time_limit, &tm);
9585#endif
9586
9587 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9588 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009589 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9590 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009591 if (pat2 == NULL || pat3 == NULL)
9592 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009593 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009594 if (*mpat == NUL)
9595 STRCPY(pat3, pat2);
9596 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009597 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009598 spat, epat, mpat);
9599 if (flags & SP_START)
9600 options |= SEARCH_START;
9601
Bram Moolenaar48570482017-10-30 21:48:41 +01009602 if (skip != NULL)
9603 {
9604 /* Empty string means to not use the skip expression. */
9605 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9606 use_skip = skip->vval.v_string != NULL
9607 && *skip->vval.v_string != NUL;
9608 }
9609
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009610 save_cursor = curwin->w_cursor;
9611 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009612 CLEAR_POS(&firstpos);
9613 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009614 pat = pat3;
9615 for (;;)
9616 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009617 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009618 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009619 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009620 /* didn't find it or found the first match again: FAIL */
9621 break;
9622
9623 if (firstpos.lnum == 0)
9624 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009625 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009626 {
9627 /* Found the same position again. Can happen with a pattern that
9628 * has "\zs" at the end and searching backwards. Advance one
9629 * character and try again. */
9630 if (dir == BACKWARD)
9631 decl(&pos);
9632 else
9633 incl(&pos);
9634 }
9635 foundpos = pos;
9636
9637 /* clear the start flag to avoid getting stuck here */
9638 options &= ~SEARCH_START;
9639
9640 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009641 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642 {
9643 save_pos = curwin->w_cursor;
9644 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009645 err = FALSE;
9646 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647 curwin->w_cursor = save_pos;
9648 if (err)
9649 {
9650 /* Evaluating {skip} caused an error, break here. */
9651 curwin->w_cursor = save_cursor;
9652 retval = -1;
9653 break;
9654 }
9655 if (r)
9656 continue;
9657 }
9658
9659 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9660 {
9661 /* Found end when searching backwards or start when searching
9662 * forward: nested pair. */
9663 ++nest;
9664 pat = pat2; /* nested, don't search for middle */
9665 }
9666 else
9667 {
9668 /* Found end when searching forward or start when searching
9669 * backward: end of (nested) pair; or found middle in outer pair. */
9670 if (--nest == 1)
9671 pat = pat3; /* outer level, search for middle */
9672 }
9673
9674 if (nest == 0)
9675 {
9676 /* Found the match: return matchcount or line number. */
9677 if (flags & SP_RETCOUNT)
9678 ++retval;
9679 else
9680 retval = pos.lnum;
9681 if (flags & SP_SETPCMARK)
9682 setpcmark();
9683 curwin->w_cursor = pos;
9684 if (!(flags & SP_REPEAT))
9685 break;
9686 nest = 1; /* search for next unmatched */
9687 }
9688 }
9689
9690 if (match_pos != NULL)
9691 {
9692 /* Store the match cursor position */
9693 match_pos->lnum = curwin->w_cursor.lnum;
9694 match_pos->col = curwin->w_cursor.col + 1;
9695 }
9696
9697 /* If 'n' flag is used or search failed: restore cursor position. */
9698 if ((flags & SP_NOMOVE) || retval == 0)
9699 curwin->w_cursor = save_cursor;
9700
9701theend:
9702 vim_free(pat2);
9703 vim_free(pat3);
9704 if (p_cpo == empty_option)
9705 p_cpo = save_cpo;
9706 else
9707 /* Darn, evaluating the {skip} expression changed the value. */
9708 free_string_option(save_cpo);
9709
9710 return retval;
9711}
9712
9713/*
9714 * "searchpos()" function
9715 */
9716 static void
9717f_searchpos(typval_T *argvars, typval_T *rettv)
9718{
9719 pos_T match_pos;
9720 int lnum = 0;
9721 int col = 0;
9722 int n;
9723 int flags = 0;
9724
9725 if (rettv_list_alloc(rettv) == FAIL)
9726 return;
9727
9728 n = search_cmn(argvars, &match_pos, &flags);
9729 if (n > 0)
9730 {
9731 lnum = match_pos.lnum;
9732 col = match_pos.col;
9733 }
9734
9735 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9736 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9737 if (flags & SP_SUBPAT)
9738 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9739}
9740
9741 static void
9742f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9743{
9744#ifdef FEAT_CLIENTSERVER
9745 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009746 char_u *server = tv_get_string_chk(&argvars[0]);
9747 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009748
9749 rettv->vval.v_number = -1;
9750 if (server == NULL || reply == NULL)
9751 return;
9752 if (check_restricted() || check_secure())
9753 return;
9754# ifdef FEAT_X11
9755 if (check_connection() == FAIL)
9756 return;
9757# endif
9758
9759 if (serverSendReply(server, reply) < 0)
9760 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009761 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009762 return;
9763 }
9764 rettv->vval.v_number = 0;
9765#else
9766 rettv->vval.v_number = -1;
9767#endif
9768}
9769
9770 static void
9771f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9772{
9773 char_u *r = NULL;
9774
9775#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009776# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009777 r = serverGetVimNames();
9778# else
9779 make_connection();
9780 if (X_DISPLAY != NULL)
9781 r = serverGetVimNames(X_DISPLAY);
9782# endif
9783#endif
9784 rettv->v_type = VAR_STRING;
9785 rettv->vval.v_string = r;
9786}
9787
9788/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009789 * "setbufline()" function
9790 */
9791 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009792f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009793{
9794 linenr_T lnum;
9795 buf_T *buf;
9796
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009797 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009798 if (buf == NULL)
9799 rettv->vval.v_number = 1; /* FAIL */
9800 else
9801 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009802 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009803 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009804 }
9805}
9806
9807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009808 * "setbufvar()" function
9809 */
9810 static void
9811f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9812{
9813 buf_T *buf;
9814 char_u *varname, *bufvarname;
9815 typval_T *varp;
9816 char_u nbuf[NUMBUFLEN];
9817
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009818 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009819 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009820 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
9821 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009822 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009823 varp = &argvars[2];
9824
9825 if (buf != NULL && varname != NULL && varp != NULL)
9826 {
9827 if (*varname == '&')
9828 {
9829 long numval;
9830 char_u *strval;
9831 int error = FALSE;
9832 aco_save_T aco;
9833
9834 /* set curbuf to be our buf, temporarily */
9835 aucmd_prepbuf(&aco, buf);
9836
9837 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009838 numval = (long)tv_get_number_chk(varp, &error);
9839 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009840 if (!error && strval != NULL)
9841 set_option_value(varname, numval, strval, OPT_LOCAL);
9842
9843 /* reset notion of buffer */
9844 aucmd_restbuf(&aco);
9845 }
9846 else
9847 {
9848 buf_T *save_curbuf = curbuf;
9849
Bram Moolenaar964b3742019-05-24 18:54:09 +02009850 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009851 if (bufvarname != NULL)
9852 {
9853 curbuf = buf;
9854 STRCPY(bufvarname, "b:");
9855 STRCPY(bufvarname + 2, varname);
9856 set_var(bufvarname, varp, TRUE);
9857 vim_free(bufvarname);
9858 curbuf = save_curbuf;
9859 }
9860 }
9861 }
9862}
9863
9864 static void
9865f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9866{
9867 dict_T *d;
9868 dictitem_T *di;
9869 char_u *csearch;
9870
9871 if (argvars[0].v_type != VAR_DICT)
9872 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009873 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009874 return;
9875 }
9876
9877 if ((d = argvars[0].vval.v_dict) != NULL)
9878 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009879 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880 if (csearch != NULL)
9881 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009882 if (enc_utf8)
9883 {
9884 int pcc[MAX_MCO];
9885 int c = utfc_ptr2char(csearch, pcc);
9886
9887 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9888 }
9889 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009890 set_last_csearch(PTR2CHAR(csearch),
9891 csearch, MB_PTR2LEN(csearch));
9892 }
9893
9894 di = dict_find(d, (char_u *)"forward", -1);
9895 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009896 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009897 ? FORWARD : BACKWARD);
9898
9899 di = dict_find(d, (char_u *)"until", -1);
9900 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009901 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009902 }
9903}
9904
9905/*
9906 * "setcmdpos()" function
9907 */
9908 static void
9909f_setcmdpos(typval_T *argvars, typval_T *rettv)
9910{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009911 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009912
9913 if (pos >= 0)
9914 rettv->vval.v_number = set_cmdline_pos(pos);
9915}
9916
9917/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009918 * "setenv()" function
9919 */
9920 static void
9921f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9922{
9923 char_u namebuf[NUMBUFLEN];
9924 char_u valbuf[NUMBUFLEN];
9925 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9926
9927 if (argvars[1].v_type == VAR_SPECIAL
9928 && argvars[1].vval.v_number == VVAL_NULL)
9929 vim_unsetenv(name);
9930 else
9931 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9932}
9933
9934/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009935 * "setfperm({fname}, {mode})" function
9936 */
9937 static void
9938f_setfperm(typval_T *argvars, typval_T *rettv)
9939{
9940 char_u *fname;
9941 char_u modebuf[NUMBUFLEN];
9942 char_u *mode_str;
9943 int i;
9944 int mask;
9945 int mode = 0;
9946
9947 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009948 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009949 if (fname == NULL)
9950 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009951 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009952 if (mode_str == NULL)
9953 return;
9954 if (STRLEN(mode_str) != 9)
9955 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009956 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009957 return;
9958 }
9959
9960 mask = 1;
9961 for (i = 8; i >= 0; --i)
9962 {
9963 if (mode_str[i] != '-')
9964 mode |= mask;
9965 mask = mask << 1;
9966 }
9967 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9968}
9969
9970/*
9971 * "setline()" function
9972 */
9973 static void
9974f_setline(typval_T *argvars, typval_T *rettv)
9975{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009976 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009977
Bram Moolenaarca851592018-06-06 21:04:07 +02009978 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009979}
9980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009981/*
9982 * Used by "setqflist()" and "setloclist()" functions
9983 */
9984 static void
9985set_qf_ll_list(
9986 win_T *wp UNUSED,
9987 typval_T *list_arg UNUSED,
9988 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009989 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009990 typval_T *rettv)
9991{
9992#ifdef FEAT_QUICKFIX
9993 static char *e_invact = N_("E927: Invalid action: '%s'");
9994 char_u *act;
9995 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009996 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009997#endif
9998
9999 rettv->vval.v_number = -1;
10000
10001#ifdef FEAT_QUICKFIX
10002 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010003 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010004 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010005 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010006 else
10007 {
10008 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010009 dict_T *d = NULL;
10010 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010011
10012 if (action_arg->v_type == VAR_STRING)
10013 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010014 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010015 if (act == NULL)
10016 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010017 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10018 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 action = *act;
10020 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010021 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010022 }
10023 else if (action_arg->v_type == VAR_UNKNOWN)
10024 action = ' ';
10025 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010026 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010027
Bram Moolenaard823fa92016-08-12 16:29:27 +020010028 if (action_arg->v_type != VAR_UNKNOWN
10029 && what_arg->v_type != VAR_UNKNOWN)
10030 {
10031 if (what_arg->v_type == VAR_DICT)
10032 d = what_arg->vval.v_dict;
10033 else
10034 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010035 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010036 valid_dict = FALSE;
10037 }
10038 }
10039
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010040 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010041 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010042 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10043 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010044 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010045 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010046 }
10047#endif
10048}
10049
10050/*
10051 * "setloclist()" function
10052 */
10053 static void
10054f_setloclist(typval_T *argvars, typval_T *rettv)
10055{
10056 win_T *win;
10057
10058 rettv->vval.v_number = -1;
10059
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010060 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010061 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010062 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010063}
10064
10065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010066 * "setpos()" function
10067 */
10068 static void
10069f_setpos(typval_T *argvars, typval_T *rettv)
10070{
10071 pos_T pos;
10072 int fnum;
10073 char_u *name;
10074 colnr_T curswant = -1;
10075
10076 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010077 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010078 if (name != NULL)
10079 {
10080 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10081 {
10082 if (--pos.col < 0)
10083 pos.col = 0;
10084 if (name[0] == '.' && name[1] == NUL)
10085 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010086 /* set cursor; "fnum" is ignored */
10087 curwin->w_cursor = pos;
10088 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010089 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010090 curwin->w_curswant = curswant - 1;
10091 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010092 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010093 check_cursor();
10094 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010095 }
10096 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10097 {
10098 /* set mark */
10099 if (setmark_pos(name[1], &pos, fnum) == OK)
10100 rettv->vval.v_number = 0;
10101 }
10102 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010103 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010104 }
10105 }
10106}
10107
10108/*
10109 * "setqflist()" function
10110 */
10111 static void
10112f_setqflist(typval_T *argvars, typval_T *rettv)
10113{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010114 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010115}
10116
10117/*
10118 * "setreg()" function
10119 */
10120 static void
10121f_setreg(typval_T *argvars, typval_T *rettv)
10122{
10123 int regname;
10124 char_u *strregname;
10125 char_u *stropt;
10126 char_u *strval;
10127 int append;
10128 char_u yank_type;
10129 long block_len;
10130
10131 block_len = -1;
10132 yank_type = MAUTO;
10133 append = FALSE;
10134
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010135 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010136 rettv->vval.v_number = 1; /* FAIL is default */
10137
10138 if (strregname == NULL)
10139 return; /* type error; errmsg already given */
10140 regname = *strregname;
10141 if (regname == 0 || regname == '@')
10142 regname = '"';
10143
10144 if (argvars[2].v_type != VAR_UNKNOWN)
10145 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010146 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010147 if (stropt == NULL)
10148 return; /* type error */
10149 for (; *stropt != NUL; ++stropt)
10150 switch (*stropt)
10151 {
10152 case 'a': case 'A': /* append */
10153 append = TRUE;
10154 break;
10155 case 'v': case 'c': /* character-wise selection */
10156 yank_type = MCHAR;
10157 break;
10158 case 'V': case 'l': /* line-wise selection */
10159 yank_type = MLINE;
10160 break;
10161 case 'b': case Ctrl_V: /* block-wise selection */
10162 yank_type = MBLOCK;
10163 if (VIM_ISDIGIT(stropt[1]))
10164 {
10165 ++stropt;
10166 block_len = getdigits(&stropt) - 1;
10167 --stropt;
10168 }
10169 break;
10170 }
10171 }
10172
10173 if (argvars[1].v_type == VAR_LIST)
10174 {
10175 char_u **lstval;
10176 char_u **allocval;
10177 char_u buf[NUMBUFLEN];
10178 char_u **curval;
10179 char_u **curallocval;
10180 list_T *ll = argvars[1].vval.v_list;
10181 listitem_T *li;
10182 int len;
10183
10184 /* If the list is NULL handle like an empty list. */
10185 len = ll == NULL ? 0 : ll->lv_len;
10186
10187 /* First half: use for pointers to result lines; second half: use for
10188 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010189 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 if (lstval == NULL)
10191 return;
10192 curval = lstval;
10193 allocval = lstval + len + 2;
10194 curallocval = allocval;
10195
10196 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10197 li = li->li_next)
10198 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010199 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010200 if (strval == NULL)
10201 goto free_lstval;
10202 if (strval == buf)
10203 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010204 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010205 * overwrite the string. */
10206 strval = vim_strsave(buf);
10207 if (strval == NULL)
10208 goto free_lstval;
10209 *curallocval++ = strval;
10210 }
10211 *curval++ = strval;
10212 }
10213 *curval++ = NULL;
10214
10215 write_reg_contents_lst(regname, lstval, -1,
10216 append, yank_type, block_len);
10217free_lstval:
10218 while (curallocval > allocval)
10219 vim_free(*--curallocval);
10220 vim_free(lstval);
10221 }
10222 else
10223 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010224 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 if (strval == NULL)
10226 return;
10227 write_reg_contents_ex(regname, strval, -1,
10228 append, yank_type, block_len);
10229 }
10230 rettv->vval.v_number = 0;
10231}
10232
10233/*
10234 * "settabvar()" function
10235 */
10236 static void
10237f_settabvar(typval_T *argvars, typval_T *rettv)
10238{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010239 tabpage_T *save_curtab;
10240 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010241 char_u *varname, *tabvarname;
10242 typval_T *varp;
10243
10244 rettv->vval.v_number = 0;
10245
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010246 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010247 return;
10248
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010249 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10250 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010251 varp = &argvars[2];
10252
Bram Moolenaar4033c552017-09-16 20:54:51 +020010253 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010255 save_curtab = curtab;
10256 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010257
Bram Moolenaar964b3742019-05-24 18:54:09 +020010258 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259 if (tabvarname != NULL)
10260 {
10261 STRCPY(tabvarname, "t:");
10262 STRCPY(tabvarname + 2, varname);
10263 set_var(tabvarname, varp, TRUE);
10264 vim_free(tabvarname);
10265 }
10266
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010267 /* Restore current tabpage */
10268 if (valid_tabpage(save_curtab))
10269 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010270 }
10271}
10272
10273/*
10274 * "settabwinvar()" function
10275 */
10276 static void
10277f_settabwinvar(typval_T *argvars, typval_T *rettv)
10278{
10279 setwinvar(argvars, rettv, 1);
10280}
10281
10282/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010283 * "settagstack()" function
10284 */
10285 static void
10286f_settagstack(typval_T *argvars, typval_T *rettv)
10287{
10288 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10289 win_T *wp;
10290 dict_T *d;
10291 int action = 'r';
10292
10293 rettv->vval.v_number = -1;
10294
10295 // first argument: window number or id
10296 wp = find_win_by_nr_or_id(&argvars[0]);
10297 if (wp == NULL)
10298 return;
10299
10300 // second argument: dict with items to set in the tag stack
10301 if (argvars[1].v_type != VAR_DICT)
10302 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010303 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010304 return;
10305 }
10306 d = argvars[1].vval.v_dict;
10307 if (d == NULL)
10308 return;
10309
10310 // third argument: action - 'a' for append and 'r' for replace.
10311 // default is to replace the stack.
10312 if (argvars[2].v_type == VAR_UNKNOWN)
10313 action = 'r';
10314 else if (argvars[2].v_type == VAR_STRING)
10315 {
10316 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010317 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010318 if (actstr == NULL)
10319 return;
10320 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10321 action = *actstr;
10322 else
10323 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010324 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010325 return;
10326 }
10327 }
10328 else
10329 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010330 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010331 return;
10332 }
10333
10334 if (set_tagstack(wp, d, action) == OK)
10335 rettv->vval.v_number = 0;
10336}
10337
10338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010339 * "setwinvar()" function
10340 */
10341 static void
10342f_setwinvar(typval_T *argvars, typval_T *rettv)
10343{
10344 setwinvar(argvars, rettv, 0);
10345}
10346
10347#ifdef FEAT_CRYPT
10348/*
10349 * "sha256({string})" function
10350 */
10351 static void
10352f_sha256(typval_T *argvars, typval_T *rettv)
10353{
10354 char_u *p;
10355
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010356 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010357 rettv->vval.v_string = vim_strsave(
10358 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10359 rettv->v_type = VAR_STRING;
10360}
10361#endif /* FEAT_CRYPT */
10362
10363/*
10364 * "shellescape({string})" function
10365 */
10366 static void
10367f_shellescape(typval_T *argvars, typval_T *rettv)
10368{
Bram Moolenaar20615522017-06-05 18:46:26 +020010369 int do_special = non_zero_arg(&argvars[1]);
10370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010371 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010372 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010373 rettv->v_type = VAR_STRING;
10374}
10375
10376/*
10377 * shiftwidth() function
10378 */
10379 static void
10380f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10381{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010382 rettv->vval.v_number = 0;
10383
10384 if (argvars[0].v_type != VAR_UNKNOWN)
10385 {
10386 long col;
10387
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010388 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010389 if (col < 0)
10390 return; // type error; errmsg already given
10391#ifdef FEAT_VARTABS
10392 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10393 return;
10394#endif
10395 }
10396
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010397 rettv->vval.v_number = get_sw_value(curbuf);
10398}
10399
10400/*
10401 * "simplify()" function
10402 */
10403 static void
10404f_simplify(typval_T *argvars, typval_T *rettv)
10405{
10406 char_u *p;
10407
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010408 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010409 rettv->vval.v_string = vim_strsave(p);
10410 simplify_filename(rettv->vval.v_string); /* simplify in place */
10411 rettv->v_type = VAR_STRING;
10412}
10413
10414#ifdef FEAT_FLOAT
10415/*
10416 * "sin()" function
10417 */
10418 static void
10419f_sin(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 = sin(f);
10426 else
10427 rettv->vval.v_float = 0.0;
10428}
10429
10430/*
10431 * "sinh()" function
10432 */
10433 static void
10434f_sinh(typval_T *argvars, typval_T *rettv)
10435{
10436 float_T f = 0.0;
10437
10438 rettv->v_type = VAR_FLOAT;
10439 if (get_float_arg(argvars, &f) == OK)
10440 rettv->vval.v_float = sinh(f);
10441 else
10442 rettv->vval.v_float = 0.0;
10443}
10444#endif
10445
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010446/*
10447 * "soundfold({word})" function
10448 */
10449 static void
10450f_soundfold(typval_T *argvars, typval_T *rettv)
10451{
10452 char_u *s;
10453
10454 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010455 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010456#ifdef FEAT_SPELL
10457 rettv->vval.v_string = eval_soundfold(s);
10458#else
10459 rettv->vval.v_string = vim_strsave(s);
10460#endif
10461}
10462
10463/*
10464 * "spellbadword()" function
10465 */
10466 static void
10467f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10468{
10469 char_u *word = (char_u *)"";
10470 hlf_T attr = HLF_COUNT;
10471 int len = 0;
10472
10473 if (rettv_list_alloc(rettv) == FAIL)
10474 return;
10475
10476#ifdef FEAT_SPELL
10477 if (argvars[0].v_type == VAR_UNKNOWN)
10478 {
10479 /* Find the start and length of the badly spelled word. */
10480 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10481 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010482 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010483 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010484 curwin->w_set_curswant = TRUE;
10485 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010486 }
10487 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10488 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010489 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010490 int capcol = -1;
10491
10492 if (str != NULL)
10493 {
10494 /* Check the argument for spelling. */
10495 while (*str != NUL)
10496 {
10497 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10498 if (attr != HLF_COUNT)
10499 {
10500 word = str;
10501 break;
10502 }
10503 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010504 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010505 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010506 }
10507 }
10508 }
10509#endif
10510
10511 list_append_string(rettv->vval.v_list, word, len);
10512 list_append_string(rettv->vval.v_list, (char_u *)(
10513 attr == HLF_SPB ? "bad" :
10514 attr == HLF_SPR ? "rare" :
10515 attr == HLF_SPL ? "local" :
10516 attr == HLF_SPC ? "caps" :
10517 ""), -1);
10518}
10519
10520/*
10521 * "spellsuggest()" function
10522 */
10523 static void
10524f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10525{
10526#ifdef FEAT_SPELL
10527 char_u *str;
10528 int typeerr = FALSE;
10529 int maxcount;
10530 garray_T ga;
10531 int i;
10532 listitem_T *li;
10533 int need_capital = FALSE;
10534#endif
10535
10536 if (rettv_list_alloc(rettv) == FAIL)
10537 return;
10538
10539#ifdef FEAT_SPELL
10540 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010542 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010543 if (argvars[1].v_type != VAR_UNKNOWN)
10544 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010545 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010546 if (maxcount <= 0)
10547 return;
10548 if (argvars[2].v_type != VAR_UNKNOWN)
10549 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010550 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010551 if (typeerr)
10552 return;
10553 }
10554 }
10555 else
10556 maxcount = 25;
10557
10558 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10559
10560 for (i = 0; i < ga.ga_len; ++i)
10561 {
10562 str = ((char_u **)ga.ga_data)[i];
10563
10564 li = listitem_alloc();
10565 if (li == NULL)
10566 vim_free(str);
10567 else
10568 {
10569 li->li_tv.v_type = VAR_STRING;
10570 li->li_tv.v_lock = 0;
10571 li->li_tv.vval.v_string = str;
10572 list_append(rettv->vval.v_list, li);
10573 }
10574 }
10575 ga_clear(&ga);
10576 }
10577#endif
10578}
10579
10580 static void
10581f_split(typval_T *argvars, typval_T *rettv)
10582{
10583 char_u *str;
10584 char_u *end;
10585 char_u *pat = NULL;
10586 regmatch_T regmatch;
10587 char_u patbuf[NUMBUFLEN];
10588 char_u *save_cpo;
10589 int match;
10590 colnr_T col = 0;
10591 int keepempty = FALSE;
10592 int typeerr = FALSE;
10593
10594 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10595 save_cpo = p_cpo;
10596 p_cpo = (char_u *)"";
10597
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010598 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010599 if (argvars[1].v_type != VAR_UNKNOWN)
10600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010601 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010602 if (pat == NULL)
10603 typeerr = TRUE;
10604 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010605 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010606 }
10607 if (pat == NULL || *pat == NUL)
10608 pat = (char_u *)"[\\x01- ]\\+";
10609
10610 if (rettv_list_alloc(rettv) == FAIL)
10611 return;
10612 if (typeerr)
10613 return;
10614
10615 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10616 if (regmatch.regprog != NULL)
10617 {
10618 regmatch.rm_ic = FALSE;
10619 while (*str != NUL || keepempty)
10620 {
10621 if (*str == NUL)
10622 match = FALSE; /* empty item at the end */
10623 else
10624 match = vim_regexec_nl(&regmatch, str, col);
10625 if (match)
10626 end = regmatch.startp[0];
10627 else
10628 end = str + STRLEN(str);
10629 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10630 && *str != NUL && match && end < regmatch.endp[0]))
10631 {
10632 if (list_append_string(rettv->vval.v_list, str,
10633 (int)(end - str)) == FAIL)
10634 break;
10635 }
10636 if (!match)
10637 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010638 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639 if (regmatch.endp[0] > str)
10640 col = 0;
10641 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010642 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010643 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 str = regmatch.endp[0];
10645 }
10646
10647 vim_regfree(regmatch.regprog);
10648 }
10649
10650 p_cpo = save_cpo;
10651}
10652
10653#ifdef FEAT_FLOAT
10654/*
10655 * "sqrt()" function
10656 */
10657 static void
10658f_sqrt(typval_T *argvars, typval_T *rettv)
10659{
10660 float_T f = 0.0;
10661
10662 rettv->v_type = VAR_FLOAT;
10663 if (get_float_arg(argvars, &f) == OK)
10664 rettv->vval.v_float = sqrt(f);
10665 else
10666 rettv->vval.v_float = 0.0;
10667}
10668
10669/*
10670 * "str2float()" function
10671 */
10672 static void
10673f_str2float(typval_T *argvars, typval_T *rettv)
10674{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010675 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010676 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010677
Bram Moolenaar08243d22017-01-10 16:12:29 +010010678 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010679 p = skipwhite(p + 1);
10680 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010681 if (isneg)
10682 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010683 rettv->v_type = VAR_FLOAT;
10684}
10685#endif
10686
10687/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010688 * "str2list()" function
10689 */
10690 static void
10691f_str2list(typval_T *argvars, typval_T *rettv)
10692{
10693 char_u *p;
10694 int utf8 = FALSE;
10695
10696 if (rettv_list_alloc(rettv) == FAIL)
10697 return;
10698
10699 if (argvars[1].v_type != VAR_UNKNOWN)
10700 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10701
10702 p = tv_get_string(&argvars[0]);
10703
10704 if (has_mbyte || utf8)
10705 {
10706 int (*ptr2len)(char_u *);
10707 int (*ptr2char)(char_u *);
10708
10709 if (utf8 || enc_utf8)
10710 {
10711 ptr2len = utf_ptr2len;
10712 ptr2char = utf_ptr2char;
10713 }
10714 else
10715 {
10716 ptr2len = mb_ptr2len;
10717 ptr2char = mb_ptr2char;
10718 }
10719
10720 for ( ; *p != NUL; p += (*ptr2len)(p))
10721 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10722 }
10723 else
10724 for ( ; *p != NUL; ++p)
10725 list_append_number(rettv->vval.v_list, *p);
10726}
10727
10728/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010729 * "str2nr()" function
10730 */
10731 static void
10732f_str2nr(typval_T *argvars, typval_T *rettv)
10733{
10734 int base = 10;
10735 char_u *p;
10736 varnumber_T n;
10737 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010738 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010739
10740 if (argvars[1].v_type != VAR_UNKNOWN)
10741 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010742 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010743 if (base != 2 && base != 8 && base != 10 && base != 16)
10744 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010745 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010746 return;
10747 }
10748 }
10749
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010750 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010751 isneg = (*p == '-');
10752 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010753 p = skipwhite(p + 1);
10754 switch (base)
10755 {
10756 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10757 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10758 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10759 default: what = 0;
10760 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010761 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10762 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010763 if (isneg)
10764 rettv->vval.v_number = -n;
10765 else
10766 rettv->vval.v_number = n;
10767
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010768}
10769
10770#ifdef HAVE_STRFTIME
10771/*
10772 * "strftime({format}[, {time}])" function
10773 */
10774 static void
10775f_strftime(typval_T *argvars, typval_T *rettv)
10776{
10777 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010778 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010779 struct tm *curtime;
10780 time_t seconds;
10781 char_u *p;
10782
10783 rettv->v_type = VAR_STRING;
10784
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010785 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010786 if (argvars[1].v_type == VAR_UNKNOWN)
10787 seconds = time(NULL);
10788 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010789 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010790 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010791 /* MSVC returns NULL for an invalid value of seconds. */
10792 if (curtime == NULL)
10793 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10794 else
10795 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010796 vimconv_T conv;
10797 char_u *enc;
10798
10799 conv.vc_type = CONV_NONE;
10800 enc = enc_locale();
10801 convert_setup(&conv, p_enc, enc);
10802 if (conv.vc_type != CONV_NONE)
10803 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010804 if (p != NULL)
10805 (void)strftime((char *)result_buf, sizeof(result_buf),
10806 (char *)p, curtime);
10807 else
10808 result_buf[0] = NUL;
10809
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010810 if (conv.vc_type != CONV_NONE)
10811 vim_free(p);
10812 convert_setup(&conv, enc, p_enc);
10813 if (conv.vc_type != CONV_NONE)
10814 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10815 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010816 rettv->vval.v_string = vim_strsave(result_buf);
10817
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010818 /* Release conversion descriptors */
10819 convert_setup(&conv, NULL, NULL);
10820 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010821 }
10822}
10823#endif
10824
10825/*
10826 * "strgetchar()" function
10827 */
10828 static void
10829f_strgetchar(typval_T *argvars, typval_T *rettv)
10830{
10831 char_u *str;
10832 int len;
10833 int error = FALSE;
10834 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010835 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010836
10837 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010838 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010839 if (str == NULL)
10840 return;
10841 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010842 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010843 if (error)
10844 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010845
Bram Moolenaar13505972019-01-24 15:04:48 +010010846 while (charidx >= 0 && byteidx < len)
10847 {
10848 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010849 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010850 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10851 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010852 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010853 --charidx;
10854 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010855 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010856}
10857
10858/*
10859 * "stridx()" function
10860 */
10861 static void
10862f_stridx(typval_T *argvars, typval_T *rettv)
10863{
10864 char_u buf[NUMBUFLEN];
10865 char_u *needle;
10866 char_u *haystack;
10867 char_u *save_haystack;
10868 char_u *pos;
10869 int start_idx;
10870
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010871 needle = tv_get_string_chk(&argvars[1]);
10872 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010873 rettv->vval.v_number = -1;
10874 if (needle == NULL || haystack == NULL)
10875 return; /* type error; errmsg already given */
10876
10877 if (argvars[2].v_type != VAR_UNKNOWN)
10878 {
10879 int error = FALSE;
10880
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010881 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010882 if (error || start_idx >= (int)STRLEN(haystack))
10883 return;
10884 if (start_idx >= 0)
10885 haystack += start_idx;
10886 }
10887
10888 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10889 if (pos != NULL)
10890 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10891}
10892
10893/*
10894 * "string()" function
10895 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010896 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010897f_string(typval_T *argvars, typval_T *rettv)
10898{
10899 char_u *tofree;
10900 char_u numbuf[NUMBUFLEN];
10901
10902 rettv->v_type = VAR_STRING;
10903 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10904 get_copyID());
10905 /* Make a copy if we have a value but it's not in allocated memory. */
10906 if (rettv->vval.v_string != NULL && tofree == NULL)
10907 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10908}
10909
10910/*
10911 * "strlen()" function
10912 */
10913 static void
10914f_strlen(typval_T *argvars, typval_T *rettv)
10915{
10916 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010917 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010918}
10919
10920/*
10921 * "strchars()" function
10922 */
10923 static void
10924f_strchars(typval_T *argvars, typval_T *rettv)
10925{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010926 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 varnumber_T len = 0;
10929 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010930
10931 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010932 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010933 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010934 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010935 else
10936 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010937 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10938 while (*s != NUL)
10939 {
10940 func_mb_ptr2char_adv(&s);
10941 ++len;
10942 }
10943 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010944 }
10945}
10946
10947/*
10948 * "strdisplaywidth()" function
10949 */
10950 static void
10951f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10952{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010953 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010954 int col = 0;
10955
10956 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010957 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010958
10959 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10960}
10961
10962/*
10963 * "strwidth()" function
10964 */
10965 static void
10966f_strwidth(typval_T *argvars, typval_T *rettv)
10967{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010968 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969
Bram Moolenaar13505972019-01-24 15:04:48 +010010970 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010971}
10972
10973/*
10974 * "strcharpart()" function
10975 */
10976 static void
10977f_strcharpart(typval_T *argvars, typval_T *rettv)
10978{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 char_u *p;
10980 int nchar;
10981 int nbyte = 0;
10982 int charlen;
10983 int len = 0;
10984 int slen;
10985 int error = FALSE;
10986
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010987 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010988 slen = (int)STRLEN(p);
10989
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010990 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010991 if (!error)
10992 {
10993 if (nchar > 0)
10994 while (nchar > 0 && nbyte < slen)
10995 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010996 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 --nchar;
10998 }
10999 else
11000 nbyte = nchar;
11001 if (argvars[2].v_type != VAR_UNKNOWN)
11002 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011003 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011004 while (charlen > 0 && nbyte + len < slen)
11005 {
11006 int off = nbyte + len;
11007
11008 if (off < 0)
11009 len += 1;
11010 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011011 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011012 --charlen;
11013 }
11014 }
11015 else
11016 len = slen - nbyte; /* default: all bytes that are available. */
11017 }
11018
11019 /*
11020 * Only return the overlap between the specified part and the actual
11021 * string.
11022 */
11023 if (nbyte < 0)
11024 {
11025 len += nbyte;
11026 nbyte = 0;
11027 }
11028 else if (nbyte > slen)
11029 nbyte = slen;
11030 if (len < 0)
11031 len = 0;
11032 else if (nbyte + len > slen)
11033 len = slen - nbyte;
11034
11035 rettv->v_type = VAR_STRING;
11036 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011037}
11038
11039/*
11040 * "strpart()" function
11041 */
11042 static void
11043f_strpart(typval_T *argvars, typval_T *rettv)
11044{
11045 char_u *p;
11046 int n;
11047 int len;
11048 int slen;
11049 int error = FALSE;
11050
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011051 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 slen = (int)STRLEN(p);
11053
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011054 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011055 if (error)
11056 len = 0;
11057 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011058 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 else
11060 len = slen - n; /* default len: all bytes that are available. */
11061
11062 /*
11063 * Only return the overlap between the specified part and the actual
11064 * string.
11065 */
11066 if (n < 0)
11067 {
11068 len += n;
11069 n = 0;
11070 }
11071 else if (n > slen)
11072 n = slen;
11073 if (len < 0)
11074 len = 0;
11075 else if (n + len > slen)
11076 len = slen - n;
11077
11078 rettv->v_type = VAR_STRING;
11079 rettv->vval.v_string = vim_strnsave(p + n, len);
11080}
11081
11082/*
11083 * "strridx()" function
11084 */
11085 static void
11086f_strridx(typval_T *argvars, typval_T *rettv)
11087{
11088 char_u buf[NUMBUFLEN];
11089 char_u *needle;
11090 char_u *haystack;
11091 char_u *rest;
11092 char_u *lastmatch = NULL;
11093 int haystack_len, end_idx;
11094
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011095 needle = tv_get_string_chk(&argvars[1]);
11096 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011097
11098 rettv->vval.v_number = -1;
11099 if (needle == NULL || haystack == NULL)
11100 return; /* type error; errmsg already given */
11101
11102 haystack_len = (int)STRLEN(haystack);
11103 if (argvars[2].v_type != VAR_UNKNOWN)
11104 {
11105 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011106 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011107 if (end_idx < 0)
11108 return; /* can never find a match */
11109 }
11110 else
11111 end_idx = haystack_len;
11112
11113 if (*needle == NUL)
11114 {
11115 /* Empty string matches past the end. */
11116 lastmatch = haystack + end_idx;
11117 }
11118 else
11119 {
11120 for (rest = haystack; *rest != '\0'; ++rest)
11121 {
11122 rest = (char_u *)strstr((char *)rest, (char *)needle);
11123 if (rest == NULL || rest > haystack + end_idx)
11124 break;
11125 lastmatch = rest;
11126 }
11127 }
11128
11129 if (lastmatch == NULL)
11130 rettv->vval.v_number = -1;
11131 else
11132 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11133}
11134
11135/*
11136 * "strtrans()" function
11137 */
11138 static void
11139f_strtrans(typval_T *argvars, typval_T *rettv)
11140{
11141 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011142 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011143}
11144
11145/*
11146 * "submatch()" function
11147 */
11148 static void
11149f_submatch(typval_T *argvars, typval_T *rettv)
11150{
11151 int error = FALSE;
11152 int no;
11153 int retList = 0;
11154
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011155 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011156 if (error)
11157 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011158 if (no < 0 || no >= NSUBEXP)
11159 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011160 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011161 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011162 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011163 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011164 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011165 if (error)
11166 return;
11167
11168 if (retList == 0)
11169 {
11170 rettv->v_type = VAR_STRING;
11171 rettv->vval.v_string = reg_submatch(no);
11172 }
11173 else
11174 {
11175 rettv->v_type = VAR_LIST;
11176 rettv->vval.v_list = reg_submatch_list(no);
11177 }
11178}
11179
11180/*
11181 * "substitute()" function
11182 */
11183 static void
11184f_substitute(typval_T *argvars, typval_T *rettv)
11185{
11186 char_u patbuf[NUMBUFLEN];
11187 char_u subbuf[NUMBUFLEN];
11188 char_u flagsbuf[NUMBUFLEN];
11189
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011190 char_u *str = tv_get_string_chk(&argvars[0]);
11191 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011192 char_u *sub = NULL;
11193 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011194 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011195
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011196 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11197 expr = &argvars[2];
11198 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011199 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011200
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011201 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011202 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11203 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011204 rettv->vval.v_string = NULL;
11205 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011206 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011207}
11208
11209/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011210 * "swapinfo(swap_filename)" function
11211 */
11212 static void
11213f_swapinfo(typval_T *argvars, typval_T *rettv)
11214{
11215 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011216 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011217}
11218
11219/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011220 * "swapname(expr)" function
11221 */
11222 static void
11223f_swapname(typval_T *argvars, typval_T *rettv)
11224{
11225 buf_T *buf;
11226
11227 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011228 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011229 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11230 || buf->b_ml.ml_mfp->mf_fname == NULL)
11231 rettv->vval.v_string = NULL;
11232 else
11233 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11234}
11235
11236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011237 * "synID(lnum, col, trans)" function
11238 */
11239 static void
11240f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11241{
11242 int id = 0;
11243#ifdef FEAT_SYN_HL
11244 linenr_T lnum;
11245 colnr_T col;
11246 int trans;
11247 int transerr = FALSE;
11248
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011249 lnum = tv_get_lnum(argvars); /* -1 on type error */
11250 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11251 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011252
11253 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11254 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11255 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11256#endif
11257
11258 rettv->vval.v_number = id;
11259}
11260
11261/*
11262 * "synIDattr(id, what [, mode])" function
11263 */
11264 static void
11265f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11266{
11267 char_u *p = NULL;
11268#ifdef FEAT_SYN_HL
11269 int id;
11270 char_u *what;
11271 char_u *mode;
11272 char_u modebuf[NUMBUFLEN];
11273 int modec;
11274
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011275 id = (int)tv_get_number(&argvars[0]);
11276 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011277 if (argvars[2].v_type != VAR_UNKNOWN)
11278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011279 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011280 modec = TOLOWER_ASC(mode[0]);
11281 if (modec != 't' && modec != 'c' && modec != 'g')
11282 modec = 0; /* replace invalid with current */
11283 }
11284 else
11285 {
11286#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11287 if (USE_24BIT)
11288 modec = 'g';
11289 else
11290#endif
11291 if (t_colors > 1)
11292 modec = 'c';
11293 else
11294 modec = 't';
11295 }
11296
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011297 switch (TOLOWER_ASC(what[0]))
11298 {
11299 case 'b':
11300 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11301 p = highlight_color(id, what, modec);
11302 else /* bold */
11303 p = highlight_has_attr(id, HL_BOLD, modec);
11304 break;
11305
11306 case 'f': /* fg[#] or font */
11307 p = highlight_color(id, what, modec);
11308 break;
11309
11310 case 'i':
11311 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11312 p = highlight_has_attr(id, HL_INVERSE, modec);
11313 else /* italic */
11314 p = highlight_has_attr(id, HL_ITALIC, modec);
11315 break;
11316
11317 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011318 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011319 break;
11320
11321 case 'r': /* reverse */
11322 p = highlight_has_attr(id, HL_INVERSE, modec);
11323 break;
11324
11325 case 's':
11326 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11327 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011328 /* strikeout */
11329 else if (TOLOWER_ASC(what[1]) == 't' &&
11330 TOLOWER_ASC(what[2]) == 'r')
11331 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011332 else /* standout */
11333 p = highlight_has_attr(id, HL_STANDOUT, modec);
11334 break;
11335
11336 case 'u':
11337 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11338 /* underline */
11339 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11340 else
11341 /* undercurl */
11342 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11343 break;
11344 }
11345
11346 if (p != NULL)
11347 p = vim_strsave(p);
11348#endif
11349 rettv->v_type = VAR_STRING;
11350 rettv->vval.v_string = p;
11351}
11352
11353/*
11354 * "synIDtrans(id)" function
11355 */
11356 static void
11357f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11358{
11359 int id;
11360
11361#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011362 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011363
11364 if (id > 0)
11365 id = syn_get_final_id(id);
11366 else
11367#endif
11368 id = 0;
11369
11370 rettv->vval.v_number = id;
11371}
11372
11373/*
11374 * "synconcealed(lnum, col)" function
11375 */
11376 static void
11377f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11378{
11379#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11380 linenr_T lnum;
11381 colnr_T col;
11382 int syntax_flags = 0;
11383 int cchar;
11384 int matchid = 0;
11385 char_u str[NUMBUFLEN];
11386#endif
11387
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011388 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011389
11390#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011391 lnum = tv_get_lnum(argvars); /* -1 on type error */
11392 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011393
11394 vim_memset(str, NUL, sizeof(str));
11395
11396 if (rettv_list_alloc(rettv) != FAIL)
11397 {
11398 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11399 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11400 && curwin->w_p_cole > 0)
11401 {
11402 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11403 syntax_flags = get_syntax_info(&matchid);
11404
11405 /* get the conceal character */
11406 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11407 {
11408 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011409 if (cchar == NUL && curwin->w_p_cole == 1)
11410 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011411 if (cchar != NUL)
11412 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011413 if (has_mbyte)
11414 (*mb_char2bytes)(cchar, str);
11415 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011416 str[0] = cchar;
11417 }
11418 }
11419 }
11420
11421 list_append_number(rettv->vval.v_list,
11422 (syntax_flags & HL_CONCEAL) != 0);
11423 /* -1 to auto-determine strlen */
11424 list_append_string(rettv->vval.v_list, str, -1);
11425 list_append_number(rettv->vval.v_list, matchid);
11426 }
11427#endif
11428}
11429
11430/*
11431 * "synstack(lnum, col)" function
11432 */
11433 static void
11434f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11435{
11436#ifdef FEAT_SYN_HL
11437 linenr_T lnum;
11438 colnr_T col;
11439 int i;
11440 int id;
11441#endif
11442
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011443 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011444
11445#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011446 lnum = tv_get_lnum(argvars); /* -1 on type error */
11447 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011448
11449 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11450 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11451 && rettv_list_alloc(rettv) != FAIL)
11452 {
11453 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11454 for (i = 0; ; ++i)
11455 {
11456 id = syn_get_stack_item(i);
11457 if (id < 0)
11458 break;
11459 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11460 break;
11461 }
11462 }
11463#endif
11464}
11465
11466 static void
11467get_cmd_output_as_rettv(
11468 typval_T *argvars,
11469 typval_T *rettv,
11470 int retlist)
11471{
11472 char_u *res = NULL;
11473 char_u *p;
11474 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011475 int err = FALSE;
11476 FILE *fd;
11477 list_T *list = NULL;
11478 int flags = SHELL_SILENT;
11479
11480 rettv->v_type = VAR_STRING;
11481 rettv->vval.v_string = NULL;
11482 if (check_restricted() || check_secure())
11483 goto errret;
11484
11485 if (argvars[1].v_type != VAR_UNKNOWN)
11486 {
11487 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011488 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011489 * command.
11490 */
11491 if ((infile = vim_tempname('i', TRUE)) == NULL)
11492 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011493 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011494 goto errret;
11495 }
11496
11497 fd = mch_fopen((char *)infile, WRITEBIN);
11498 if (fd == NULL)
11499 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011500 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011501 goto errret;
11502 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011503 if (argvars[1].v_type == VAR_NUMBER)
11504 {
11505 linenr_T lnum;
11506 buf_T *buf;
11507
11508 buf = buflist_findnr(argvars[1].vval.v_number);
11509 if (buf == NULL)
11510 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011511 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011512 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011513 goto errret;
11514 }
11515
11516 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11517 {
11518 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11519 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11520 {
11521 err = TRUE;
11522 break;
11523 }
11524 if (putc(NL, fd) == EOF)
11525 {
11526 err = TRUE;
11527 break;
11528 }
11529 }
11530 }
11531 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011532 {
11533 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11534 err = TRUE;
11535 }
11536 else
11537 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011538 size_t len;
11539 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011540
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011541 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011542 if (p == NULL)
11543 {
11544 fclose(fd);
11545 goto errret; /* type error; errmsg already given */
11546 }
11547 len = STRLEN(p);
11548 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11549 err = TRUE;
11550 }
11551 if (fclose(fd) != 0)
11552 err = TRUE;
11553 if (err)
11554 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011555 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011556 goto errret;
11557 }
11558 }
11559
11560 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11561 * echoes typeahead, that messes up the display. */
11562 if (!msg_silent)
11563 flags += SHELL_COOKED;
11564
11565 if (retlist)
11566 {
11567 int len;
11568 listitem_T *li;
11569 char_u *s = NULL;
11570 char_u *start;
11571 char_u *end;
11572 int i;
11573
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011574 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011575 if (res == NULL)
11576 goto errret;
11577
11578 list = list_alloc();
11579 if (list == NULL)
11580 goto errret;
11581
11582 for (i = 0; i < len; ++i)
11583 {
11584 start = res + i;
11585 while (i < len && res[i] != NL)
11586 ++i;
11587 end = res + i;
11588
Bram Moolenaar964b3742019-05-24 18:54:09 +020011589 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011590 if (s == NULL)
11591 goto errret;
11592
11593 for (p = s; start < end; ++p, ++start)
11594 *p = *start == NUL ? NL : *start;
11595 *p = NUL;
11596
11597 li = listitem_alloc();
11598 if (li == NULL)
11599 {
11600 vim_free(s);
11601 goto errret;
11602 }
11603 li->li_tv.v_type = VAR_STRING;
11604 li->li_tv.v_lock = 0;
11605 li->li_tv.vval.v_string = s;
11606 list_append(list, li);
11607 }
11608
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011609 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011610 list = NULL;
11611 }
11612 else
11613 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011614 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011615#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011616 /* translate <CR><NL> into <NL> */
11617 if (res != NULL)
11618 {
11619 char_u *s, *d;
11620
11621 d = res;
11622 for (s = res; *s; ++s)
11623 {
11624 if (s[0] == CAR && s[1] == NL)
11625 ++s;
11626 *d++ = *s;
11627 }
11628 *d = NUL;
11629 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011630#endif
11631 rettv->vval.v_string = res;
11632 res = NULL;
11633 }
11634
11635errret:
11636 if (infile != NULL)
11637 {
11638 mch_remove(infile);
11639 vim_free(infile);
11640 }
11641 if (res != NULL)
11642 vim_free(res);
11643 if (list != NULL)
11644 list_free(list);
11645}
11646
11647/*
11648 * "system()" function
11649 */
11650 static void
11651f_system(typval_T *argvars, typval_T *rettv)
11652{
11653 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11654}
11655
11656/*
11657 * "systemlist()" function
11658 */
11659 static void
11660f_systemlist(typval_T *argvars, typval_T *rettv)
11661{
11662 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11663}
11664
11665/*
11666 * "tabpagebuflist()" function
11667 */
11668 static void
11669f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11670{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011671 tabpage_T *tp;
11672 win_T *wp = NULL;
11673
11674 if (argvars[0].v_type == VAR_UNKNOWN)
11675 wp = firstwin;
11676 else
11677 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011678 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679 if (tp != NULL)
11680 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11681 }
11682 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11683 {
11684 for (; wp != NULL; wp = wp->w_next)
11685 if (list_append_number(rettv->vval.v_list,
11686 wp->w_buffer->b_fnum) == FAIL)
11687 break;
11688 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011689}
11690
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011691/*
11692 * "tabpagenr()" function
11693 */
11694 static void
11695f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11696{
11697 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011698 char_u *arg;
11699
11700 if (argvars[0].v_type != VAR_UNKNOWN)
11701 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011702 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011703 nr = 0;
11704 if (arg != NULL)
11705 {
11706 if (STRCMP(arg, "$") == 0)
11707 nr = tabpage_index(NULL) - 1;
11708 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011709 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011710 }
11711 }
11712 else
11713 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011714 rettv->vval.v_number = nr;
11715}
11716
11717
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011718/*
11719 * Common code for tabpagewinnr() and winnr().
11720 */
11721 static int
11722get_winnr(tabpage_T *tp, typval_T *argvar)
11723{
11724 win_T *twin;
11725 int nr = 1;
11726 win_T *wp;
11727 char_u *arg;
11728
11729 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11730 if (argvar->v_type != VAR_UNKNOWN)
11731 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011732 int invalid_arg = FALSE;
11733
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011734 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011735 if (arg == NULL)
11736 nr = 0; /* type error; errmsg already given */
11737 else if (STRCMP(arg, "$") == 0)
11738 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11739 else if (STRCMP(arg, "#") == 0)
11740 {
11741 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11742 if (twin == NULL)
11743 nr = 0;
11744 }
11745 else
11746 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011747 long count;
11748 char_u *endp;
11749
11750 // Extract the window count (if specified). e.g. winnr('3j')
11751 count = strtol((char *)arg, (char **)&endp, 10);
11752 if (count <= 0)
11753 count = 1; // if count is not specified, default to 1
11754 if (endp != NULL && *endp != '\0')
11755 {
11756 if (STRCMP(endp, "j") == 0)
11757 twin = win_vert_neighbor(tp, twin, FALSE, count);
11758 else if (STRCMP(endp, "k") == 0)
11759 twin = win_vert_neighbor(tp, twin, TRUE, count);
11760 else if (STRCMP(endp, "h") == 0)
11761 twin = win_horz_neighbor(tp, twin, TRUE, count);
11762 else if (STRCMP(endp, "l") == 0)
11763 twin = win_horz_neighbor(tp, twin, FALSE, count);
11764 else
11765 invalid_arg = TRUE;
11766 }
11767 else
11768 invalid_arg = TRUE;
11769 }
11770
11771 if (invalid_arg)
11772 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011773 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011774 nr = 0;
11775 }
11776 }
11777
11778 if (nr > 0)
11779 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11780 wp != twin; wp = wp->w_next)
11781 {
11782 if (wp == NULL)
11783 {
11784 /* didn't find it in this tabpage */
11785 nr = 0;
11786 break;
11787 }
11788 ++nr;
11789 }
11790 return nr;
11791}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011792
11793/*
11794 * "tabpagewinnr()" function
11795 */
11796 static void
11797f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11798{
11799 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800 tabpage_T *tp;
11801
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011802 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011803 if (tp == NULL)
11804 nr = 0;
11805 else
11806 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011807 rettv->vval.v_number = nr;
11808}
11809
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011810/*
11811 * "tagfiles()" function
11812 */
11813 static void
11814f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11815{
11816 char_u *fname;
11817 tagname_T tn;
11818 int first;
11819
11820 if (rettv_list_alloc(rettv) == FAIL)
11821 return;
11822 fname = alloc(MAXPATHL);
11823 if (fname == NULL)
11824 return;
11825
11826 for (first = TRUE; ; first = FALSE)
11827 if (get_tagfname(&tn, first, fname) == FAIL
11828 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11829 break;
11830 tagname_free(&tn);
11831 vim_free(fname);
11832}
11833
11834/*
11835 * "taglist()" function
11836 */
11837 static void
11838f_taglist(typval_T *argvars, typval_T *rettv)
11839{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011840 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011841 char_u *tag_pattern;
11842
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011843 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011844
11845 rettv->vval.v_number = FALSE;
11846 if (*tag_pattern == NUL)
11847 return;
11848
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011849 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011850 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011851 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011852 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011853}
11854
11855/*
11856 * "tempname()" function
11857 */
11858 static void
11859f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11860{
11861 static int x = 'A';
11862
11863 rettv->v_type = VAR_STRING;
11864 rettv->vval.v_string = vim_tempname(x, FALSE);
11865
11866 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11867 * names. Skip 'I' and 'O', they are used for shell redirection. */
11868 do
11869 {
11870 if (x == 'Z')
11871 x = '0';
11872 else if (x == '9')
11873 x = 'A';
11874 else
11875 {
11876#ifdef EBCDIC
11877 if (x == 'I')
11878 x = 'J';
11879 else if (x == 'R')
11880 x = 'S';
11881 else
11882#endif
11883 ++x;
11884 }
11885 } while (x == 'I' || x == 'O');
11886}
11887
11888#ifdef FEAT_FLOAT
11889/*
11890 * "tan()" function
11891 */
11892 static void
11893f_tan(typval_T *argvars, typval_T *rettv)
11894{
11895 float_T f = 0.0;
11896
11897 rettv->v_type = VAR_FLOAT;
11898 if (get_float_arg(argvars, &f) == OK)
11899 rettv->vval.v_float = tan(f);
11900 else
11901 rettv->vval.v_float = 0.0;
11902}
11903
11904/*
11905 * "tanh()" function
11906 */
11907 static void
11908f_tanh(typval_T *argvars, typval_T *rettv)
11909{
11910 float_T f = 0.0;
11911
11912 rettv->v_type = VAR_FLOAT;
11913 if (get_float_arg(argvars, &f) == OK)
11914 rettv->vval.v_float = tanh(f);
11915 else
11916 rettv->vval.v_float = 0.0;
11917}
11918#endif
11919
11920/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011921 * Get a callback from "arg". It can be a Funcref or a function name.
11922 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011923 * "cb_name" is not allocated.
11924 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011925 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011926 callback_T
11927get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011928{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011929 callback_T res;
11930
11931 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011932 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11933 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011934 res.cb_partial = arg->vval.v_partial;
11935 ++res.cb_partial->pt_refcount;
11936 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011937 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011938 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011939 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011940 res.cb_partial = NULL;
11941 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11942 {
11943 // Note that we don't make a copy of the string.
11944 res.cb_name = arg->vval.v_string;
11945 func_ref(res.cb_name);
11946 }
11947 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11948 {
11949 res.cb_name = (char_u *)"";
11950 }
11951 else
11952 {
11953 emsg(_("E921: Invalid callback argument"));
11954 res.cb_name = NULL;
11955 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011956 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011957 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011958}
11959
11960/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011961 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011962 */
11963 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011964put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011965{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011966 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011967 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011968 tv->v_type = VAR_PARTIAL;
11969 tv->vval.v_partial = cb->cb_partial;
11970 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011971 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011972 else
11973 {
11974 tv->v_type = VAR_FUNC;
11975 tv->vval.v_string = vim_strsave(cb->cb_name);
11976 func_ref(cb->cb_name);
11977 }
11978}
11979
11980/*
11981 * Make a copy of "src" into "dest", allocating the function name if needed,
11982 * without incrementing the refcount.
11983 */
11984 void
11985set_callback(callback_T *dest, callback_T *src)
11986{
11987 if (src->cb_partial == NULL)
11988 {
11989 // just a function name, make a copy
11990 dest->cb_name = vim_strsave(src->cb_name);
11991 dest->cb_free_name = TRUE;
11992 }
11993 else
11994 {
11995 // cb_name is a pointer into cb_partial
11996 dest->cb_name = src->cb_name;
11997 dest->cb_free_name = FALSE;
11998 }
11999 dest->cb_partial = src->cb_partial;
12000}
12001
12002/*
12003 * Unref/free "callback" returned by get_callback() or set_callback().
12004 */
12005 void
12006free_callback(callback_T *callback)
12007{
12008 if (callback->cb_partial != NULL)
12009 {
12010 partial_unref(callback->cb_partial);
12011 callback->cb_partial = NULL;
12012 }
12013 else if (callback->cb_name != NULL)
12014 func_unref(callback->cb_name);
12015 if (callback->cb_free_name)
12016 {
12017 vim_free(callback->cb_name);
12018 callback->cb_free_name = FALSE;
12019 }
12020 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012021}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012022
12023#ifdef FEAT_TIMERS
12024/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012025 * "timer_info([timer])" function
12026 */
12027 static void
12028f_timer_info(typval_T *argvars, typval_T *rettv)
12029{
12030 timer_T *timer = NULL;
12031
12032 if (rettv_list_alloc(rettv) != OK)
12033 return;
12034 if (argvars[0].v_type != VAR_UNKNOWN)
12035 {
12036 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012037 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012038 else
12039 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012040 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012041 if (timer != NULL)
12042 add_timer_info(rettv, timer);
12043 }
12044 }
12045 else
12046 add_timer_info_all(rettv);
12047}
12048
12049/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012050 * "timer_pause(timer, paused)" function
12051 */
12052 static void
12053f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12054{
12055 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012056 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012057
12058 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012059 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012060 else
12061 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012062 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012063 if (timer != NULL)
12064 timer->tr_paused = paused;
12065 }
12066}
12067
12068/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012069 * "timer_start(time, callback [, options])" function
12070 */
12071 static void
12072f_timer_start(typval_T *argvars, typval_T *rettv)
12073{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012074 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012075 timer_T *timer;
12076 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012077 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012078 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079
Bram Moolenaar75537a92016-09-05 22:45:28 +020012080 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012081 if (check_secure())
12082 return;
12083 if (argvars[2].v_type != VAR_UNKNOWN)
12084 {
12085 if (argvars[2].v_type != VAR_DICT
12086 || (dict = argvars[2].vval.v_dict) == NULL)
12087 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012088 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012089 return;
12090 }
12091 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012092 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012093 }
12094
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012095 callback = get_callback(&argvars[1]);
12096 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012097 return;
12098
12099 timer = create_timer(msec, repeat);
12100 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012101 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102 else
12103 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012104 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012105 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012106 }
12107}
12108
12109/*
12110 * "timer_stop(timer)" function
12111 */
12112 static void
12113f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12114{
12115 timer_T *timer;
12116
12117 if (argvars[0].v_type != VAR_NUMBER)
12118 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012119 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012120 return;
12121 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012122 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012123 if (timer != NULL)
12124 stop_timer(timer);
12125}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012126
12127/*
12128 * "timer_stopall()" function
12129 */
12130 static void
12131f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12132{
12133 stop_all_timers();
12134}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012135#endif
12136
12137/*
12138 * "tolower(string)" function
12139 */
12140 static void
12141f_tolower(typval_T *argvars, typval_T *rettv)
12142{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012143 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012144 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012145}
12146
12147/*
12148 * "toupper(string)" function
12149 */
12150 static void
12151f_toupper(typval_T *argvars, typval_T *rettv)
12152{
12153 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012154 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012155}
12156
12157/*
12158 * "tr(string, fromstr, tostr)" function
12159 */
12160 static void
12161f_tr(typval_T *argvars, typval_T *rettv)
12162{
12163 char_u *in_str;
12164 char_u *fromstr;
12165 char_u *tostr;
12166 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012167 int inlen;
12168 int fromlen;
12169 int tolen;
12170 int idx;
12171 char_u *cpstr;
12172 int cplen;
12173 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012174 char_u buf[NUMBUFLEN];
12175 char_u buf2[NUMBUFLEN];
12176 garray_T ga;
12177
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012178 in_str = tv_get_string(&argvars[0]);
12179 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12180 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012181
12182 /* Default return value: empty string. */
12183 rettv->v_type = VAR_STRING;
12184 rettv->vval.v_string = NULL;
12185 if (fromstr == NULL || tostr == NULL)
12186 return; /* type error; errmsg already given */
12187 ga_init2(&ga, (int)sizeof(char), 80);
12188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012189 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190 /* not multi-byte: fromstr and tostr must be the same length */
12191 if (STRLEN(fromstr) != STRLEN(tostr))
12192 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012193error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012194 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012195 ga_clear(&ga);
12196 return;
12197 }
12198
12199 /* fromstr and tostr have to contain the same number of chars */
12200 while (*in_str != NUL)
12201 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012202 if (has_mbyte)
12203 {
12204 inlen = (*mb_ptr2len)(in_str);
12205 cpstr = in_str;
12206 cplen = inlen;
12207 idx = 0;
12208 for (p = fromstr; *p != NUL; p += fromlen)
12209 {
12210 fromlen = (*mb_ptr2len)(p);
12211 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12212 {
12213 for (p = tostr; *p != NUL; p += tolen)
12214 {
12215 tolen = (*mb_ptr2len)(p);
12216 if (idx-- == 0)
12217 {
12218 cplen = tolen;
12219 cpstr = p;
12220 break;
12221 }
12222 }
12223 if (*p == NUL) /* tostr is shorter than fromstr */
12224 goto error;
12225 break;
12226 }
12227 ++idx;
12228 }
12229
12230 if (first && cpstr == in_str)
12231 {
12232 /* Check that fromstr and tostr have the same number of
12233 * (multi-byte) characters. Done only once when a character
12234 * of in_str doesn't appear in fromstr. */
12235 first = FALSE;
12236 for (p = tostr; *p != NUL; p += tolen)
12237 {
12238 tolen = (*mb_ptr2len)(p);
12239 --idx;
12240 }
12241 if (idx != 0)
12242 goto error;
12243 }
12244
12245 (void)ga_grow(&ga, cplen);
12246 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12247 ga.ga_len += cplen;
12248
12249 in_str += inlen;
12250 }
12251 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012252 {
12253 /* When not using multi-byte chars we can do it faster. */
12254 p = vim_strchr(fromstr, *in_str);
12255 if (p != NULL)
12256 ga_append(&ga, tostr[p - fromstr]);
12257 else
12258 ga_append(&ga, *in_str);
12259 ++in_str;
12260 }
12261 }
12262
12263 /* add a terminating NUL */
12264 (void)ga_grow(&ga, 1);
12265 ga_append(&ga, NUL);
12266
12267 rettv->vval.v_string = ga.ga_data;
12268}
12269
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012270/*
12271 * "trim({expr})" function
12272 */
12273 static void
12274f_trim(typval_T *argvars, typval_T *rettv)
12275{
12276 char_u buf1[NUMBUFLEN];
12277 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012278 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012279 char_u *mask = NULL;
12280 char_u *tail;
12281 char_u *prev;
12282 char_u *p;
12283 int c1;
12284
12285 rettv->v_type = VAR_STRING;
12286 if (head == NULL)
12287 {
12288 rettv->vval.v_string = NULL;
12289 return;
12290 }
12291
12292 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012293 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012294
12295 while (*head != NUL)
12296 {
12297 c1 = PTR2CHAR(head);
12298 if (mask == NULL)
12299 {
12300 if (c1 > ' ' && c1 != 0xa0)
12301 break;
12302 }
12303 else
12304 {
12305 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12306 if (c1 == PTR2CHAR(p))
12307 break;
12308 if (*p == NUL)
12309 break;
12310 }
12311 MB_PTR_ADV(head);
12312 }
12313
12314 for (tail = head + STRLEN(head); tail > head; tail = prev)
12315 {
12316 prev = tail;
12317 MB_PTR_BACK(head, prev);
12318 c1 = PTR2CHAR(prev);
12319 if (mask == NULL)
12320 {
12321 if (c1 > ' ' && c1 != 0xa0)
12322 break;
12323 }
12324 else
12325 {
12326 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12327 if (c1 == PTR2CHAR(p))
12328 break;
12329 if (*p == NUL)
12330 break;
12331 }
12332 }
12333 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12334}
12335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336#ifdef FEAT_FLOAT
12337/*
12338 * "trunc({float})" function
12339 */
12340 static void
12341f_trunc(typval_T *argvars, typval_T *rettv)
12342{
12343 float_T f = 0.0;
12344
12345 rettv->v_type = VAR_FLOAT;
12346 if (get_float_arg(argvars, &f) == OK)
12347 /* trunc() is not in C90, use floor() or ceil() instead. */
12348 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12349 else
12350 rettv->vval.v_float = 0.0;
12351}
12352#endif
12353
12354/*
12355 * "type(expr)" function
12356 */
12357 static void
12358f_type(typval_T *argvars, typval_T *rettv)
12359{
12360 int n = -1;
12361
12362 switch (argvars[0].v_type)
12363 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012364 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12365 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012366 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012367 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12368 case VAR_LIST: n = VAR_TYPE_LIST; break;
12369 case VAR_DICT: n = VAR_TYPE_DICT; break;
12370 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012371 case VAR_SPECIAL:
12372 if (argvars[0].vval.v_number == VVAL_FALSE
12373 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012374 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012375 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012376 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012377 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012378 case VAR_JOB: n = VAR_TYPE_JOB; break;
12379 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012380 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012381 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012382 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012383 n = -1;
12384 break;
12385 }
12386 rettv->vval.v_number = n;
12387}
12388
12389/*
12390 * "undofile(name)" function
12391 */
12392 static void
12393f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12394{
12395 rettv->v_type = VAR_STRING;
12396#ifdef FEAT_PERSISTENT_UNDO
12397 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012398 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012399
12400 if (*fname == NUL)
12401 {
12402 /* If there is no file name there will be no undo file. */
12403 rettv->vval.v_string = NULL;
12404 }
12405 else
12406 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012407 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012408
12409 if (ffname != NULL)
12410 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12411 vim_free(ffname);
12412 }
12413 }
12414#else
12415 rettv->vval.v_string = NULL;
12416#endif
12417}
12418
12419/*
12420 * "undotree()" function
12421 */
12422 static void
12423f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12424{
12425 if (rettv_dict_alloc(rettv) == OK)
12426 {
12427 dict_T *dict = rettv->vval.v_dict;
12428 list_T *list;
12429
Bram Moolenaare0be1672018-07-08 16:50:37 +020012430 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12431 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12432 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12433 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12434 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12435 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012436
12437 list = list_alloc();
12438 if (list != NULL)
12439 {
12440 u_eval_tree(curbuf->b_u_oldhead, list);
12441 dict_add_list(dict, "entries", list);
12442 }
12443 }
12444}
12445
12446/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012447 * "virtcol(string)" function
12448 */
12449 static void
12450f_virtcol(typval_T *argvars, typval_T *rettv)
12451{
12452 colnr_T vcol = 0;
12453 pos_T *fp;
12454 int fnum = curbuf->b_fnum;
12455
12456 fp = var2fpos(&argvars[0], FALSE, &fnum);
12457 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12458 && fnum == curbuf->b_fnum)
12459 {
12460 getvvcol(curwin, fp, NULL, NULL, &vcol);
12461 ++vcol;
12462 }
12463
12464 rettv->vval.v_number = vcol;
12465}
12466
12467/*
12468 * "visualmode()" function
12469 */
12470 static void
12471f_visualmode(typval_T *argvars, typval_T *rettv)
12472{
12473 char_u str[2];
12474
12475 rettv->v_type = VAR_STRING;
12476 str[0] = curbuf->b_visual_mode_eval;
12477 str[1] = NUL;
12478 rettv->vval.v_string = vim_strsave(str);
12479
12480 /* A non-zero number or non-empty string argument: reset mode. */
12481 if (non_zero_arg(&argvars[0]))
12482 curbuf->b_visual_mode_eval = NUL;
12483}
12484
12485/*
12486 * "wildmenumode()" function
12487 */
12488 static void
12489f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12490{
12491#ifdef FEAT_WILDMENU
12492 if (wild_menu_showing)
12493 rettv->vval.v_number = 1;
12494#endif
12495}
12496
12497/*
12498 * "winbufnr(nr)" function
12499 */
12500 static void
12501f_winbufnr(typval_T *argvars, typval_T *rettv)
12502{
12503 win_T *wp;
12504
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012505 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012506 if (wp == NULL)
12507 rettv->vval.v_number = -1;
12508 else
12509 rettv->vval.v_number = wp->w_buffer->b_fnum;
12510}
12511
12512/*
12513 * "wincol()" function
12514 */
12515 static void
12516f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12517{
12518 validate_cursor();
12519 rettv->vval.v_number = curwin->w_wcol + 1;
12520}
12521
12522/*
12523 * "winheight(nr)" function
12524 */
12525 static void
12526f_winheight(typval_T *argvars, typval_T *rettv)
12527{
12528 win_T *wp;
12529
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012530 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531 if (wp == NULL)
12532 rettv->vval.v_number = -1;
12533 else
12534 rettv->vval.v_number = wp->w_height;
12535}
12536
12537/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012538 * "winlayout()" function
12539 */
12540 static void
12541f_winlayout(typval_T *argvars, typval_T *rettv)
12542{
12543 tabpage_T *tp;
12544
12545 if (rettv_list_alloc(rettv) != OK)
12546 return;
12547
12548 if (argvars[0].v_type == VAR_UNKNOWN)
12549 tp = curtab;
12550 else
12551 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012552 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012553 if (tp == NULL)
12554 return;
12555 }
12556
12557 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12558}
12559
12560/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012561 * "winline()" function
12562 */
12563 static void
12564f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12565{
12566 validate_cursor();
12567 rettv->vval.v_number = curwin->w_wrow + 1;
12568}
12569
12570/*
12571 * "winnr()" function
12572 */
12573 static void
12574f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12575{
12576 int nr = 1;
12577
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012578 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 rettv->vval.v_number = nr;
12580}
12581
12582/*
12583 * "winrestcmd()" function
12584 */
12585 static void
12586f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12587{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012588 win_T *wp;
12589 int winnr = 1;
12590 garray_T ga;
12591 char_u buf[50];
12592
12593 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012594 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012595 {
12596 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12597 ga_concat(&ga, buf);
12598 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12599 ga_concat(&ga, buf);
12600 ++winnr;
12601 }
12602 ga_append(&ga, NUL);
12603
12604 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012605 rettv->v_type = VAR_STRING;
12606}
12607
12608/*
12609 * "winrestview()" function
12610 */
12611 static void
12612f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12613{
12614 dict_T *dict;
12615
12616 if (argvars[0].v_type != VAR_DICT
12617 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012618 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012619 else
12620 {
12621 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012622 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012624 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012625 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012626 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012627 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12628 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012629 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 curwin->w_set_curswant = FALSE;
12631 }
12632
12633 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012634 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012635#ifdef FEAT_DIFF
12636 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012637 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012638#endif
12639 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012640 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012641 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012642 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643
12644 check_cursor();
12645 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012646 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012647 changed_window_setting();
12648
12649 if (curwin->w_topline <= 0)
12650 curwin->w_topline = 1;
12651 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12652 curwin->w_topline = curbuf->b_ml.ml_line_count;
12653#ifdef FEAT_DIFF
12654 check_topfill(curwin, TRUE);
12655#endif
12656 }
12657}
12658
12659/*
12660 * "winsaveview()" function
12661 */
12662 static void
12663f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12664{
12665 dict_T *dict;
12666
12667 if (rettv_dict_alloc(rettv) == FAIL)
12668 return;
12669 dict = rettv->vval.v_dict;
12670
Bram Moolenaare0be1672018-07-08 16:50:37 +020012671 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12672 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012673 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012674 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012675 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012676
Bram Moolenaare0be1672018-07-08 16:50:37 +020012677 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012678#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012679 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012680#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012681 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12682 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012683}
12684
12685/*
12686 * "winwidth(nr)" function
12687 */
12688 static void
12689f_winwidth(typval_T *argvars, typval_T *rettv)
12690{
12691 win_T *wp;
12692
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012693 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012694 if (wp == NULL)
12695 rettv->vval.v_number = -1;
12696 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012697 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012698}
12699
12700/*
12701 * "wordcount()" function
12702 */
12703 static void
12704f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12705{
12706 if (rettv_dict_alloc(rettv) == FAIL)
12707 return;
12708 cursor_pos_info(rettv->vval.v_dict);
12709}
12710
12711/*
12712 * "writefile()" function
12713 */
12714 static void
12715f_writefile(typval_T *argvars, typval_T *rettv)
12716{
12717 int binary = FALSE;
12718 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012719#ifdef HAVE_FSYNC
12720 int do_fsync = p_fs;
12721#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012722 char_u *fname;
12723 FILE *fd;
12724 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012725 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012726 list_T *list = NULL;
12727 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012728
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012729 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012730 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012731 return;
12732
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012733 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012734 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012735 list = argvars[0].vval.v_list;
12736 if (list == NULL)
12737 return;
12738 for (li = list->lv_first; li != NULL; li = li->li_next)
12739 if (tv_get_string_chk(&li->li_tv) == NULL)
12740 return;
12741 }
12742 else if (argvars[0].v_type == VAR_BLOB)
12743 {
12744 blob = argvars[0].vval.v_blob;
12745 if (blob == NULL)
12746 return;
12747 }
12748 else
12749 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012750 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751 return;
12752 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012753
12754 if (argvars[2].v_type != VAR_UNKNOWN)
12755 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012756 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012757
12758 if (arg2 == NULL)
12759 return;
12760 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012762 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012763 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012764#ifdef HAVE_FSYNC
12765 if (vim_strchr(arg2, 's') != NULL)
12766 do_fsync = TRUE;
12767 else if (vim_strchr(arg2, 'S') != NULL)
12768 do_fsync = FALSE;
12769#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012770 }
12771
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012772 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012773 if (fname == NULL)
12774 return;
12775
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012776 /* Always open the file in binary mode, library functions have a mind of
12777 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012778 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12779 append ? APPENDBIN : WRITEBIN)) == NULL)
12780 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012781 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012782 ret = -1;
12783 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012784 else if (blob)
12785 {
12786 if (write_blob(fd, blob) == FAIL)
12787 ret = -1;
12788#ifdef HAVE_FSYNC
12789 else if (do_fsync)
12790 // Ignore the error, the user wouldn't know what to do about it.
12791 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012792 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012793#endif
12794 fclose(fd);
12795 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012796 else
12797 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012798 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012799 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012800#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012801 else if (do_fsync)
12802 /* Ignore the error, the user wouldn't know what to do about it.
12803 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012804 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012805#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806 fclose(fd);
12807 }
12808
12809 rettv->vval.v_number = ret;
12810}
12811
12812/*
12813 * "xor(expr, expr)" function
12814 */
12815 static void
12816f_xor(typval_T *argvars, typval_T *rettv)
12817{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012818 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12819 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012820}
12821
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822#endif /* FEAT_EVAL */